Arduino, шаговый двигатель 28-BYJ48 и драйвер ULN2003
Шаговый двигатель - это мотор, который управляется несколькими электромагнитными катушками.
На центральном валу - роторе - расположены магниты. В зависимости от от того, есть ток на катушках, которые находятся вокруг вала, или нет, создаются магнитные поля, которые притягивают или отталкивают магниты на роторе. В результате вал шагового двигателя вращается.
Подобная конструкция позволяет реализовать очень точное управление углом поворота ротора шагового двигателя относительно катушек - статора. Можно выделить два основных типа шаговых моторов: униполярные и биполярные шаговые двигатели.
В данной статье мы рассмотрим работу униполярного шагового двигателя 28-BYJ48 с драйвером ULN2003.


Униполярные шаговые двигатели имеют пять или шесть контактов для подключения и четыре электромагнитные катушки в корпусе (если быть более точными, то две катушки, разделенные на четыре). Центральные контакты катушек соединены вместе и используются для подачи питания на двигатель. Эти шаговые моторы называются униполярными, потому-что питание всегда подается на один из этих полюсов.
Спецификация и драйвер шагового двигателя
Существуют разные модели драйверов (контроллеров) шаговых двигателей. Среди них можно выделить самые популярные в DIY разработках на базе Arduino: L293, ULN2003, A3967SLB.
Как правило, шаговый двигатель 28-BYJ48 используют в паре с драйвером ULN2003.
Спецификацию шагового двигателя 28-BYJ48 на английском языке вы можете скачать здесь. Краткие выдержки основных технических характеристик приведены ниже:
- Напряжение питания: 5 В (постоянный ток);
- Количество фаз: 4;
- Количество шагов: 64;
- Угол поврота на один шаг: 5.625 градуса
- Частота: 100 Герц;
- Частота холостого хода по часовой стрелке: > 600 Герц;
- Частота холостого хода против часовой стрелки: > 1000 Герц;
- Крутящий момент > 34.3 миллиньютон на метр;
- Сопротивление вращению: 600-1200 грамм на сантиметр;
- Класс элетробезопасности: A;
Внешний вид и схемы подключения ULN2003 приведены на изображениях ниже



Примечание. Если вы захотите использовать плату L293 вместо ULN2003, красный контакт подключать не надо.

Необходимые компоненты
Вам понадобятся:
- Микроконтроллер Arduino.
- Шаговый двигатель BYJ48 5В.
- Драйвер шагового двигателя ULN2003.
- Коннекторы.
- Источник питания 5v - необязательно.
Скетч для Arduino
В Arduino IDE есть встроенная библиотека для управления шаговыми двигателями. После подключения шагового двигателя, ULN2003 и Arduino, вы можете загрузить скетч из категории Examples и ...
На этом этапе возникают определенные нюансы:
У этого двигателя передаточное отношение 1:64, а угол поворота 5.625, то есть у него 4096 шагов.
Шаг = Количество шагов на один поворот * передаточное отношение.
Шаги= (360/5.625)*64"Передаточное отношение" = 64 * 64 =4096. Это значение надо учесть в скетче Arduino.
А вот угол поворота для шаговых двигателей от adafruit равен 7.5 градусов, а передаточное отношение 1:16, так что количество шагов за 1 полный оборот вала равно:
Шаги за один оборот = 360 / 7.5 = 48.
Шаги = 48 * 16 = 768
То есть, это значение меняется в зависимости от двигателя, который вы используете. Поэтому проверяйте даташит для калибровки и корректной работы вашего шагового двигателя.
Модуль драйвера шагового двигателя ULN2003 подключается к Arduino контактами IN1 - IN4 к D8 - D11 соответственно.
Для подачи питания на ваш мотор, рекомендуется использовать внешний источник питания 5V с силой тока 500mA минимум. Не питайте двигатель непосредственно от контакта 5V на плате Arduino.
Проблема направления вращения в библиотеке и как ее исправить
Когда вы загрузите скетч на Arduino, шаговый двигатель будет вращаться в одном направлении с помощью функции:
step(steps);
То есть, вам надо указать в параметрах количество шагов для поворота ротора вала.
По идее, указав положительное или отрицательное значение, вы можете управлять направлением вращения. Если ваш шаговый двигать так и работает, то можете не читать дальше.
Но если шаговый двигатель вращается в том же направлении вне зависимости от знака, то надо внести изменения в библиотеку Arduino. В следующем разделе приведен код, используя который вы можете управлять направлением вращения.
Измененный код для Arduino
Окончательная версия скетча для шагового двигателя:
/* Скетч для шагового двигателя BYJ48
Схема подключения: IN1 >> D8 IN2 >> D9 IN3 >> D10 IN4 >> D11 VCC ... 5V.
Лучше использовать внешний источник питания Gnd
Автор кода: Mohannad Rawashdeh
Детали на русском языке: /arduino-shagovii-motor-28-BYJ48-draiver-ULN2003
Англоязычный вариант: http://www.instructables.com/member/Mohannad+Rawashdeh/ 28/9/2013 */
#define IN1 8
#define IN2 9
#define IN3 10
#define IN4 11
int Steps = 0;
boolean Direction = true;
unsigned long last_time;
unsigned long currentMillis ;
int steps_left=4095;
long time;
void setup()
{
Serial.begin(115200);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// delay(1000);
}
void loop()
{
while(steps_left>0){
currentMillis = micros();
if(currentMillis-last_time>=1000){
stepper(1);
time=time+micros()-last_time;
last_time=micros();
steps_left--;
}
}
Serial.println(time);
Serial.println("Wait...!");
delay(2000);
Direction=!Direction;
steps_left=4095;
}
void stepper(int xw){
for (int x=0;x<xw;x++){
switch(Steps){
case 0:
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
break;
case 1:
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, HIGH);
break;
case 2:
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
break;
case 3:
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
break;
case 4:
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
break;
case 5:
digitalWrite(IN1, HIGH);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
break;
case 6:
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
break;
case 7:
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
break;
default:
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
break;
}
SetDirection();
}
}
void SetDirection(){
if(Direction==1){ Steps++;}
if(Direction==0){ Steps--; }
if(Steps>7){Steps=0;}
if(Steps<0){Steps=7; }
}
Видео работающего мотора приведено ниже:
Но есть и более интересный вариант - написать собственную библиотеку для шагового двигателя
Собственная библиотека для корректной работы 28BYJ-48 с ULN2003
Как уже было указано выше, стандартная библиотека Arduino для работы с шаговыми двигателями отрабатывает некорректно в связке с мотором 28BYJ-48 и драйвером ULN2003. При этом, эта модель двигателя и драйвер ULN2003 - качественная бюджетная связка для ваших проектов на Arduino.
Пример кода, рассмотренный выше, неплохой, но было бы хорошо организовать собственную отдельную библиотеку для работы с шаговым двигателем 28BYJ-48 и Arduino. Решение, представленное ниже, предполагает базовое понимание C++ и понимания принципов работы шаговых двигателей.
Шаг 1. Создаем файл StepperMotor.h
Начнем с написания класса StepperMotor.
Создайте файл с названием StepperMotor.h и скопируйте следующий код:
#ifndef Stepper_h
#define Stepper_h
class StepperMotor {
public:
StepperMotor(int In1, int In2, int In3, int In4); // конструктор, который устанавливает inputs
void setStepDuration(int duration); // Функция для установки длительности шага
void step(int noOfSteps); // Делаем указанное количество шагов. + для одного направления и - для другого
int duration; // длительность шага в мс
int inputPins[4]; // номера input пинов
};
#endif
Даже если вы не сильны в C++, объявление класса говорит само за себя.
Шаг2. Создаем файл StepperMotor.cpp
Теперь давайте напишем интерфейс класса.
Создайте файл с названием StepperMotor.cpp вставьте в него код, представленный ниже.
#include <Arduino.h>
#include <StepperMotor.h>
StepperMotor::StepperMotor(int In1, int In2, int In3, int In4){
// Записываем номера пинов в массив inputPins
this->inputPins[0] = In1;
this->inputPins[1] = In2;
this->inputPins[2] = In3;
this->inputPins[3] = In4;
// Проходим в цикле по массиву inputPins, устанавливая каждый из них в режим Output
for (int inputCount = 0; inputCount < 4; inputCount++){
pinMode(this->inputPins[inputCount], OUTPUT);
}
duration = 50;
}
void StepperMotor::setStepDuration(int duration){
this->duration = duration;
}
void StepperMotor::step(int noOfSteps){
/*
* в данном 2D массиве хранится последовательность, которая
* используется для поворота. В строках хранится шаг,
* а в столбцах - текущий input пин
*/
bool sequence[][4] = {{LOW, LOW, LOW, HIGH},
{LOW, LOW, HIGH, HIGH},
{LOW, LOW, HIGH, LOW},
{LOW, HIGH, HIGH, LOW},
{LOW, HIGH, LOW, LOW},
{HIGH, HIGH, LOW, LOW},
{HIGH, LOW, LOW, LOW},
{HIGH, LOW, LOW, HIGH}};
int factor = abs(noOfSteps) / noOfSteps; // Если noOfSteps со знаком +, factor = 1. Если noOfSteps со знаком -, factor = -1
noOfSteps = abs(noOfSteps); // Если noOfSteps был отрицательным, делаем его позитивным для дальнейших операций
/*
* В цикле ниже обрабатываем массив sequence
* указанное количество раз
*/
for(int sequenceNum = 0; sequenceNum <= noOfSteps/8; sequenceNum++){
for(int position = 0; (position < 8) && (position < (noOfSteps - sequenceNum*8)); position++){
delay(duration);
for(int inputCount = 0; inputCount < 4; inputCount++){
digitalWrite(this->inputPins[inputCount], sequence[(int)(3.5-(3.5*factor)+(factor*position))][inputCount]);
}
}
}
}
Давайте посмотрим на конструктор на строчке 4. Мы начинаем с того, что добавляем выбранные пользователем пины в массив inputinputPins в строчках 6-9. В результате мы получаем простой и интуитивно понятный доступ к номерам пинов в дальнейшем коде.
В 12 строке мы пробегаемся по массиву inputinputPins и устанавливаем для каждого режим OUTPUT.
В 15 строке мы устанавливаем длительность шага по-умолчанию равной 15 мс.
В 18 строчке у нас функция-сеттер для установки длительности шага.
Теперь давайте рассмотрим метод step. Этот метод дает возможность шаговому двигателю делать переданное методу количество шагов.
В 28 строчке мы объявляем частоту вращения с использованием 2-х мерного массива. Строки представляют шаг, столбцы - выходящие пины.
В 37 строчке рассчитывается значение переменной factor, которое равно +1 или -1 в зависимости от знака, который мы передали при указании шагов. Это значение используется для определения направления перебора массива, то есть, в результате, для изменения направления вращения.
В 38 строчке мы присваем noOfSteps переменной позитивное значение.
В 44 строке мы запускаем цикл, который будет отрабатывать для каждой последовательности оборотов, то есть в начале каждого 8-го щага.
В 45 строке мы запускаем второй цикл, который пробегается по строкам в нашем массиве.
В 46 строчке мы устанавливаем задержку в соответствии со спецификацией.
В 47 строке мы пробегаемся по номерам пинов.
В 48 строке мы передаем цифровой сигнал на текущий номер пина.
Если переменная factor отрицательная, в 48-й строчке кода строки массива обрабатываются в противоположном порядке, то есть с низу вверх.
Доступ к библиотеке для шагового двигателя из Arduino IDE
Нам осталось добавить созданные файлы в папку библиотек Arduino IDE и мы сможем импортировать ее в любой наш проект.
Перейдите в папку:
C:\Program Files (x86)\Arduino\libraries
И создайте папку под названием StepperMotor.
Переместите созданные файлы .h и .cpp в созданную папку.
Теперь вы можете импортировать библиотеку в IDE (sketch > import library... > StepperMotor) с помощью директивы