Шаговый мотор NEMA 17, серии 17HS4402 + драйвер A4988 + Arduino NANO.

Тема статьи: 
Электронные поделки и механизмы

Управление шаговым двигателем с помощью платы Arduino.

В данной статье мы продолжаем разбираться с темой шаговых двигателей. В прошлый раз мы подключили к плате Arduino NANO небольшой моторчик 28BYJ-48 (5V). Сегодня мы будем делать то же самое, но с другим мотором - NEMA 17, серии 17HS4402 и другим драйвером - A4988.

ArduinoShagovMotor_NEMA17_01.jpg

Шаговый мотор NEMA 17 — это биполярный двигатель с высоким крутящим моментом. Может поворачиваться на заданное число шагов. За один шаг совершает оборот на 1,8°, соответственно полный оборот на 360° осуществляет за 200 шагов.
Биполярный двигатель имеет две обмотки, по одной в каждой фазе, которая для изменения направления магнитного поля переполюсовывается драйвером. Соответственно, от мотора отходят четыре провода.

ArduinoShagovMotor_NEMA17_02.jpg

Такой мотор широко применяется в станках ЧПУ, 3D принтерах, сканерах и т. д.
Управляться он будет с помощью платы Arduino NANO.

ArduinoShagovMotor_NEMA17_03.jpg

ArduinoShagovMotor_NEMA17_04.jpg

Эта плата способна выдавать напряжение 5V, тогда как мотор работает от большего напряжения. Мы выбрали блок питания 12V. Так что нам понадобится дополнительный модуль — драйвер, способный управлять более высоким напряжением через маломощные импульсы Arduino. Для этого отлично подходит драйвер А4988.

ArduinoShagovMotor_NEMA17_05.jpg

Драйвер шагового двигателя А4988.

Плата создана на базе микросхемы A4988 компании Allegro - драйвера биполярного шагового двигателя. Особенностями A4988 являются регулируемый ток, защита от перегрузки и перегрева, драйвер также имеет пять вариантов микрошага (вплоть до 1/16-шага). Он работает от напряжения 8 - 35 В и может обеспечить ток до 1 А на фазу без радиатора и дополнительного охлаждения (дополнительное охлаждение необходимо при подаче тока в 2 A на каждую обмотку).

Характеристики:

Модель: A4988;
напряжения питания: от 8 до 35 В;
возможность установки шага: от 1 до 1/16 от максимального шага;
напряжение логики: 3-5.5 В;
защита от перегрева;
максимальный ток на фазу: 1 А без радиатора, 2 А с радиатором;
расстояние между рядами ножек: 12 мм;
размер платы: 20 х 15 мм;
габариты драйвера: 20 х 15 х 10 мм;
габариты радиатора: 9 х 5 х 9 мм;
вес с радиатором: 3 г;
без радиатора: 2 г.

Для работы с драйвером необходимо питание логического уровня (3 - 5,5 В), подаваемое на выводы VDD и GND, а также питание двигателя (8 - 35 В) на выводы VMOT и GND. Плата очень уязвима для скачков напряжения, особенно если питающие провода длиннее нескольких сантиметров. Если эти скачки превысят максимально допустимое значение (35 В для A4988) ,то плата может сгореть. Одним из способов защиты платы от подобных скачков является установка большого (не меньше 47 мкФ) электролитического конденсатора между выводом питания (VMOT) и землёй близко к плате.
Соединение или разъединение шагового двигателя при включённом драйвере может привести к поломке двигателя!
Выбранный мотор совершает 200 шагов за полный оборот на 360°, что соответствует 1,8° на шаг. Микрошаговый драйвер, такой как A4988 позволяет увеличить разрешение за счёт возможности управления промежуточными шагами. Например, управление мотором в режиме четверти шага даст двигателю с величиной 200-шагов-за-оборот уже 800 микрошагов при использовании разных уровней тока.
Разрешение (размер шага) задаётся комбинациями переключателей на входах (MS1, MS2, и MS3).

MS1 MS2 MS3 Разрешение микрошага
Низкий Низкий Низкий Полный шаг
Высокий Низкий Низкий 1/2 шага
Низкий Высокий Низкий 1/4 шага
Высокий Высокий Низкий 1/8 шага
Высокий Высокий Высокий 1/16 шага

ArduinoShagovMotor_NEMA17_06.jpg

Каждый импульс на входе STEP соответствует одному микрошагу двигателя, направление вращения которого зависит от сигнала на выводе DIRECTION. Выводы STEP и DIRECTION не подтянуты к какому-либо конкретному внутреннему напряжению, поэтому их не стоит оставлять плавающими при создании приложений. Если вы просто хотите вращать двигатель в одном направлении, можно соединить DIR непосредственно с VCC или GND. Чип имеет три различных входа для управления состоянием питания: RESET, SLEEP и ENABLE. Вывод RESET плавает, если его не нужно использовать, то следует подключить его к соседнему контакту SLEEP на печатной плате, чтобы подать на него высокий уровень и включить плату.

Схема соединения.

ArduinoShagovMotor_NEMA17_07.jpg

Мы использовали вот такой блок питания (12V).

ArduinoShagovMotor_NEMA17_08.jpg

Для удобства подключения к плате Arduino UNO, мы использовали собственноручно сделанную деталь. Пластиковый корпус напечатан на 3D принтере, к нему приклеены контакты.

ArduinoShagovMotor_NEMA17_09.jpg

ArduinoShagovMotor_NEMA17_10.jpg

Также, использовали такой набор проводов, у части из них с одного конца контакт, с другого штырёк, у других контакты с обоих сторон.

ArduinoShagovMotor_NEMA17_11.jpg

Соединяем всё согласно схеме.

ArduinoShagovMotor_NEMA17_12.jpg

ArduinoShagovMotor_NEMA17_13.jpg

ArduinoShagovMotor_NEMA17_14.jpg

Потом открываем среду разработки программ для Arduino и пишем программу, вращающую мотор сначала в одну сторону на 360°, потом в другую.

/*Программа для вращения шагового мотора NEMA 17, серии 17HS4402 + драйвер A4988. Сначала мотор совершает полный оборот в одну сторону, потом в другую*/
/*целочисленная константа, хранящая номер цифрового контакта Arduino, который подаёт сигнал Step на драйвер. Каждый импульс от этого контакта — это перемещение мотора на один шаг*/

const int pinStep = 5;

/*целочисленная константа, хранящая номер цифрового контакта Arduino, который подаёт сигнал Direction на драйвер. Наличие импульса - мотор вращается в одну сторону, отсутствие - в другую*/
const int pinDir = 4;

//временная задержка между шагами мотора в мс
const int move_delay = 3;

//шагов на полный оборот
const int steps_rotate_360 = 200;

/*Функция, в которой происходит инициализация всех переменных программы*/
void setup()
{
/*задаём контактам Step и Direction режим вывода, то есть они выдают напряжение*/
  pinMode(pinStep, OUTPUT);
  pinMode(pinDir, OUTPUT);
//устанавливаем начальный режим
  digitalWrite(pinStep, HIGH);
  digitalWrite(pinDir, LOW);
}

/*Функция-цикл в которой задаётся поведение программы*/
void loop()
{
//устанавливаем направление вращения
  digitalWrite(pinDir, HIGH);

  for(int i = 0; i < steps_rotate_360; i++)
  {
    digitalWrite(pinStep, HIGH);
    delay(move_delay);
    digitalWrite(pinStep, LOW);
    delay(move_delay);
  }

  delay(move_delay*10);

//устанавливаем направление вращения обратное
  digitalWrite(pinDir, LOW);

  for(int i = 0; i < steps_rotate_360; i++)
  {
    digitalWrite(pinStep, HIGH);
    delay(move_delay);
    digitalWrite(pinStep, LOW);
    delay(move_delay);
  }

  delay(move_delay*10);
}

Если мы хотим, чтобы мотор просто постоянно вращался в ту или иную сторону, то можно подключить контакт драйвера DIRECTION к земле (вращение по часовой стрелке) или питанию (против часовой) и залить в Arduino такую простенькую программу:

/*Программа для вращения шагового мотора NEMA 17, серии 17HS4402 + драйвер A4988. Программа приводит мотор в движение.
По-умолчанию вращение происходит по часовой стрелке, так как на контакт DIRECTION драйвера подключён к земле. Если его подключить к питанию 5V, то
мотор вращается против часовой стрелки*/
/*целочисленная константа, хранящая номер цифрового контакта Arduino, который подаёт сигнал Step на драйвер. Каждый импульс от этого контакта — это перемещение мотора на один шаг*/

const int pinStep = 5;

//временная задержка между шагами мотора в мс
const int move_delay = 3;

/*Функция, в которой происходит инициализация всех переменных программы*/
void setup()
{
/*задаём контакту Step режим вывода, то есть он выдают напряжение*/
  pinMode(pinStep, OUTPUT);
//устанавливаем начальный режим
  digitalWrite(pinStep, LOW);
}

/*Функция-цикл в которой задаётся поведение программы*/
void loop()
{
/*через заданную задержку происходит перемещение мотора на один шаг*/
  digitalWrite(pinStep, HIGH);
  delay(move_delay);
  digitalWrite(pinStep, LOW);
  delay(move_delay);
}

Всё это мы рассматривали шаговый режим мотора, то есть 200 шагов за полный оборот. Но, как уже было описано, мотор может работать, в 1/2, 1/4, 1/8, 1/16 шаговых режимах, в зависимости от того, какая комбинация сигналов подаётся на контакты драйвера MS1, MS2, MS3.
Давайте с этим потренируемся, подключим эти три контакта к плате Arduino, согласно схеме, и зальём код программы.

ArduinoShagovMotor_NEMA17_15.jpg

Код программы, которая демонстрирует все пять режимов работы мотора, вращая мотор в одну и другую сторону на 200 шагов в каждом из этих режимов.

/*Программа для вращения шагового мотора NEMA 17, серии 17HS4402 + драйвер A4988. В программе попеременно сменяются режимы шага: полношаговый, 1/2, 1/4, 1/8, 1/16 шага, при каждом из них мотор совершает оборот на 200 шагов в одну сторону, потом в другую*/
/*целочисленная константа, хранящая номер цифрового контакта Arduino, который подаёт сигнал Step на драйвер. Каждый импульс от этого контакта — это перемещение мотора на один шаг*/

const int pinStep = 5;

/*целочисленная константа, хранящая номер цифрового контакта Arduino, который подаёт сигнал Direction на драйвер. Наличие импульса - мотор вращается в одну сторону, отсутствие - в другую*/
const int pinDir = 4;

//временная задержка между шагами мотора в мс
const int move_delay = 3;

//шагов на полный оборот
const int steps_rotate_360 = 200;

/*контакты на драйвере, задающие режим шага мотора - MS1, MS2, MS3*/
int StepModePins[3] = {8, 7, 6};

//размер массива StepModePins
const int StepModePinsCount = 3;

/*Массив, хранящий состояния контактов MS1, MS2, MS3 драйвера, при которых задаются разные режимы вращения: полношаговый, 1/2, 1/4, 1/8, 1/16я шага*/
bool StepMode[5][3] = {
  { 0, 0, 0},
  { 1, 0, 0},
  { 0, 1, 0},
  { 1, 1, 0},
  { 1, 1, 1} };

//размер массива StepMode
const int StepModeSize = 5;

/*Функция, в которой происходит инициализация всех переменных программы*/
void setup()
{
/*задаём контактам Step и Direction режим вывода, то есть они выдают напряжение*/
  pinMode(pinStep, OUTPUT);
  pinMode(pinDir, OUTPUT);

  for(int i = 0; i < StepModePinsCount; i++)
  {
    pinMode(StepModePins[i], OUTPUT);
  }

//устанавливаем начальный режим
  digitalWrite(pinStep, HIGH);
  digitalWrite(pinDir, LOW);
}

/*Функция-цикл в которой задаётся поведение программы*/
void loop()
{
  for(int i = 0; i < StepModeSize; i++)
  {
    for(int j = 0; j < StepModePinsCount; j++)
    {
      digitalWrite(StepModePins[j], StepMode[i][j] == 1 ? HIGH : LOW);
    }

//вращаем мотор в одну сторону, затем в другую
    MakeRoundRotation();
  }
}

/*функция, в которой мотор совершает 200 шагов в одном направлении, затем 200 в обратном*/
void MakeRoundRotation()
{
//устанавливаем направление вращения
  digitalWrite(pinDir, HIGH);

  for(int i = 0; i < steps_rotate_360; i++)
  {
    digitalWrite(pinStep, HIGH);
    delay(move_delay);
    digitalWrite(pinStep, LOW);
    delay(move_delay);
  }

  delay(move_delay*10);

//устанавливаем направление вращения обратное
  digitalWrite(pinDir, LOW);

  for(int i = 0; i < steps_rotate_360; i++)
  {
    digitalWrite(pinStep, HIGH);
    delay(move_delay);
    digitalWrite(pinStep, LOW);
    delay(move_delay);
  }

  delay(move_delay*10);
}

Ну, и последнее, что нам осталось добавить в схему, так это внешнее управление. Как и в предыдущей статье добавим кнопку, задающую направление вращения и переменный резистор (потенциометр), который будет менять скорость вращения. Скоростей же у нас будет только 5, по количеству возможных режимов шага для мотора.

Дополняем схему новыми элементами.

ArduinoShagovMotor_NEMA17_16.jpg

Для подключения кнопок воспользуемся такими проводочками.

ArduinoShagovMotor_NEMA17_17.jpg

ArduinoShagovMotor_NEMA17_18.jpg

ArduinoShagovMotor_NEMA17_19.jpg

Код программы.

/*Программа для вращения шагового мотора NEMA 17, серии 17HS4402 + драйвер A4988. В схему включены кнопка с 3мя положениями (I, II, среднее — выключено) и потенциометр. Кнопка регулирует направление вращения мотора, а данные с потенциометра показывают какой из пяти режимов шага мотора включить (полношаговый, 1/2, 1/4, 1/8, 1/16 шага)*/
/*целочисленная константа, хранящая номер цифрового контакта Arduino, который подаёт сигнал Step на драйвер. Каждый импульс от этого контакта — это перемещение мотора на один шаг*/

const int pinStep = 5;

/*целочисленная константа, хранящая номер цифрового контакта Arduino, который подаёт сигнал Direction на драйвер. Наличие импульса - мотор вращается в одну сторону, отсутствие - в другую*/
const int pinDir = 4;

/*Контакты от двух положений кнопки - цифровые*/
const int ButtonOn1 = 9;
const int ButtonOn2 = 10;

/*Контакт регистрирующий значение потенциометра - аналоговый*/
const int PotenciomData = 1;

//временная задержка между шагами мотора в мс
const int move_delay = 3;

/*целочисленная константа, показывающая временную задержку между считыванием состояния кнопки и потенциометра*/
const int CheckButtonDelay = 15;

/*Целочисленная переменная показывающая, сколько прошло времени и не пора ли считывать состояние кнопки*/
int CurrentButtonDelay = 0;

/*контакты на драйвере, задающие режим шага мотора - MS1, MS2, MS3*/
int StepModePins[3] = {8, 7, 6};

//размер массива StepModePins
const int StepModePinsCount = 3;

//состояние кнопки включено-выключено
int ButtonState = 0;

//направление вращения согласно кнопке I - 1, II - 0
int ButtonDirection = 0;

/*Массив, хранящий состояния контактов MS1, MS2, MS3 драйвера, при которых задаются разные режимы вращения: полношаговый, 1/2, 1/4, 1/8, 1/16я шага*/
bool StepMode[5][3] = {
  { 0, 0, 0},
  { 1, 0, 0},
  { 0, 1, 0},
  { 1, 1, 0},
  { 1, 1, 1} };

//размер массива StepMode
const int StepModeSize = 5;

//текущий индекс массива StepMode
int StepModeIndex = 0;

/*Функция, в которой происходит инициализация всех переменных программы*/
void setup()
{
/*задаём контактам Step и Direction режим вывода, то есть они выдают напряжение*/
  pinMode(pinStep, OUTPUT);
  pinMode(pinDir, OUTPUT);

  for(int i = 0; i < StepModePinsCount; i++)
  {
    pinMode(StepModePins[i], OUTPUT);
  }

/*контакты от кнопки и потенциометра устанавливаем в режим входных*/
  pinMode(ButtonOn1, INPUT);
  pinMode(ButtonOn2, INPUT);
  pinMode(PotenciomData, INPUT);

//устанавливаем начальный режим
  digitalWrite(pinStep, LOW);
  digitalWrite(pinDir, LOW);
}

/*Функция-цикл в которой задаётся поведение программы*/
void loop()
{
  if(CurrentButtonDelay >= CheckButtonDelay)
  {
    CheckButtonState();
    CurrentButtonDelay = 0;
  }

  if(ButtonState == 1)
  {
    MakeMotorStep();
  }

  delay(move_delay);
  CurrentButtonDelay += move_delay;
}

//функция, в которой совершается один шаг мотора
void MakeMotorStep()
{
  digitalWrite(pinStep, HIGH);
  digitalWrite(pinStep, LOW);
}

/*функция, в которой проверяется текущее состояние кнопки и потенциометра*/
void CheckButtonState()
{
  int CurrentButtonState = 0, CurrentButtonDirection = 0, CurrentStepModeIndex = 0;

  bool readbuttonparam = digitalRead(ButtonOn1);

  if(readbuttonparam)
  {
    CurrentButtonState = 1;
    CurrentButtonDirection = 1;
  }

  readbuttonparam = digitalRead(ButtonOn2);

  if(readbuttonparam)
  {
    CurrentButtonState = 1;
    CurrentButtonDirection = 0;
  }

  if(ButtonState != CurrentButtonState)
  {
    ButtonState = CurrentButtonState;
  }

  if(ButtonDirection != CurrentButtonDirection)
  {
    ButtonDirection = CurrentButtonDirection;
    digitalWrite(pinDir, ButtonDirection);
  }

  CurrentStepModeIndex = map(analogRead(PotenciomData), 0, 1023, 0, StepModeSize-1);
  if(StepModeIndex != CurrentStepModeIndex)
  {
    StepModeIndex = CurrentStepModeIndex;
    for(int i = 0; i < StepModePinsCount; i++)
    {
      digitalWrite(StepModePins[i], StepMode[StepModeIndex][i]);
    }
  }
}