Всем привет.
Я думаю что вы, если работали с arduino+nema 17, знаете, что запустить несколько двигателей одновременно бывает очень затруднительно.
Есть разные способы решения этой проблемы, самый простой, пожалуй — использование библиотеки NemaStepper. Библиотека упрощает данную задачу во много раз, главное преимущество — она не останавливает выполнение программы. Устанавливается она также, как и все остальные библиотеки. Распространяется по MIT лицензии.
Ну что, давайте приступим. И начнем мы с подключения.
Мы будем использовать Simple Nema 17 с алиэкспресса за 500 рублей, драйвер L298N и arduino uno. Вот они:
- В примере я буду показывать четыре подключенных драйвера к ардуине, хотя буду использовать только один.
- В интернете есть много туториалов по подключению Nema 17, поэтому я не буду подробно расписывать это здесь.
Итак, подключаем мотор к драйверу:
Библиотека является объектно — ориентированной. Давайте рассмотрим пример включения одного мотора:
NemaStepper Stepper1(2, 3, 4, 5, 200, 10, false);
void Setup(){
Stepper1.SetStepCount(100); //Запускаем вращение на 100 оборотов
}
void Update(){
Stepper1.Step(); //Обновляем вращение
}
О всех методах библиотеки можно узнать из файлов исходного кода библиотеки (в шапке библиотеки есть описание).
*Подробнее о коде в примере.
А теперь переходим к примеру.
В библиотеке есть встроенный пример (на данный момент он там один), который позволяет управлять сразу тремя моторами с Serial.
Данный пример принимает на порт команды, указанные ниже.
Давайте его разберем.
Начнем с шапки — подключения библиотек:
//This file - example of NemaStepper library.
#include "NemaStepper.h"
String inString;
bool IsStepperEnabled = false;
Далее объявляются три мотора, со следующими параметрами:
1. Первый пин
2. Второй пин
3. Третий пин
4. Четвертый пин
5. Количество шагов за оборот — у большинства моторов Nema 17 это 200.
6. Стартовая скорость
7. Значение указывающее, нужно ли удерживать вал после остановки (при true драйверы превращаются в барбекю)
NemaStepper Stepper1(2, 3, 4, 5, 200, 10, false);
NemaStepper Stepper2(6, 7, 8, 9, 200, 10, false);
NemaStepper Stepper3(10, 11, 12, 13, 200, 10, false);
Далее инициализация порта:
void setup() {
Serial.begin(9600);
}
Затем, ВАЖНО! В главном цикле нужно обновлять положение двигателей командой Step()
void loop() {
if (IsStepperEnabled == true){
Stepper1.Step();
Stepper2.Step();
Stepper3.Step();
}
GetCommandFromSerial();
}
Далее следует подпрограмма, которая получает данные с порта, включает/выключает моторы, задает скорость, тормоза, вращение.
void GetCommandFromSerial() {
if (Serial.available() > 0) { //если есть доступные данные
int inChar = Serial.read();
if (inChar == '/') {
String command = ((String)inString[0] + (String)inString[1] + (String)inString[2]);
String param;
int len = inString.length();
for (int i = 3; i < len; i++) {
param = (String)param + (String)inString[i];
}
if (command == "MV1") {
Stepper1.SetStepCount(param.toInt());
Serial.println(param.toInt());
}
if (command == "MV2") {
Stepper2.SetStepCount(param.toInt());
Serial.println(param.toInt());
}
if (command == "MV3") {
Stepper3.SetStepCount(param.toInt());
Serial.println(param.toInt());
}
if (command == "SS1") {
Stepper1.SetSpeed(param.toInt());
Serial.println(param.toInt());
}
if (command == "SS2") {
Stepper2.SetSpeed(param.toInt());
Serial.println(param.toInt());
}
if (command == "SS3") {
Stepper3.SetSpeed(param.toInt());
Serial.println(param.toInt());
}
if (command == "SB1") {
Stepper1.SetBrakes(param.toInt());
Serial.println(param.toInt());
}
if (command == "SB2") {
Stepper2.SetBrakes(param.toInt());
Serial.println(param.toInt());
}
if (command == "SB3") {
Stepper3.SetBrakes(param.toInt());
Serial.println(param.toInt());
}
if (command == "EMS") {
IsStepperEnabled = true;
Serial.println(param.toInt());
}
if (command == "DMS") {
IsStepperEnabled = false;
Serial.println(param.toInt());
}
inString = "";
} else {
inString += (char)inChar;
}
}
}
И так, давайте попробуем загрузить ее в плату.
Загрузили?
Тогда заходим в монитор порта и вводим команды из кода.
Каждая команда заканчивается символом /.
Первые три символа — название команды.
То, что между названием и / — параметры.
Давайте включим моторы командой «EMS/» (Enable MotorS).
Затем укажем мотору 1 скорость 60 командой «SS160/» (Set Speed), где 60 — скорость.
И наконец, включим первый мотор командой «MV1100/», (MoVe) где 100 — количество оборотов.
Все работает. Ура.
Тоже самое с остальными моторами.
Ну и где взять библиотеку.
Библиотеку можно скачать, отблагодарив создателя, по ссылке, указав ей реальную цену:
Get NemaStepper
Спасибо за прочтение, надеюсь вам помогла моя статья.
Когда я искал решение моей проблемы, единственной подходящей библиотекой оказалась она.
Комментарии (15)
pvvv
24.08.2019 17:51+2Неправильно ты, дядя Фёдор, платы крепишь, гвоздь надо в самый центр ардуины забивать, так держаться лучше будет.
TheCalligrapher
24.08.2019 18:06Ну то есть похоже что библиотека NemaStepper является простейшей тонкой оболочкой для реализации типичной ардуиновской кооперативной многозадачности для управления степперами.
Это нормально, но меня удивила ваша фраза "Когда я искал решение моей проблемы, единственной подходящей библиотекой оказалась она". Это звучит примерно как "я искал, как увеличить переменную на 1, и перепробовав несколько, нашел только библиотеку Increment". У всех естественно возникнет вопрос: а чем вам простое
++i
не подошло? Вот так же и здесь: зачем было искать библиотеку для кооперативного управления степпер-моторами (особенно если это потребовало усилий), когда это, мягко говоря, элементарное действие?acodered
24.08.2019 23:09Просто покрутить один мотор влево-вправо, действительно, тривиально. С учетом, что библиотека так и так требует вызова Step() для каждого из моторов в отдельности, проще было переключать самостоятельно.
А вообще, управление несколькими моторами может оказаться неожиданно сложной задачей.
Навскидку:
Заголовок спойлера— направление DIR нужно выставлять заранее, за несколько микросекунд до STEP/PUL
— STEP должен быть определенной, одинаковой, длины. Нельзя просто в цикле или прерывании его переключать 1 / 0, плюс к этому драйвер может ловить шаг по переднему или заднему фронту
— нужно гарантировать равномерность шагов (и равномерность ускорения). Если на простом Arduino это и решается просто, то уже на более сложном окружении ESP32 приходится идти на хитрые трюки, чтобы обеспечить равномерность. И это на 80 мегагерцах!
— шаги нужно выдавать одновременно на несколько моторов. На самом деле одновременно, а не по очереди. Нельзя делать смелые предположения, «а пусть один мотор запаздывает на несколько микросекунд от остальных».
— на «другом конце» может оказаться вообще не шаговый драйвер, а PID контроллер, например.FGV
25.08.2019 14:43то уже на более сложном окружении ESP32 приходится идти на хитрые трюки
ага, хитрые трюки заключаются в использовании периферии.acodered
25.08.2019 23:09reports that porting the code over to the ESP32 wasn’t terrible, but it wasn’t exactly a walk in the park either. The bulk of the code went by without too much trouble, but when it came to the parts that needed precise timing things got tricky
FGV
26.08.2019 05:48but when it came to the parts that needed precise timing things got tricky
Беда в том что почти все адуриновские библиотеки работают с внешним миром через программный ногодрыг. Для авр которая больше ничего кроме кручения двигателей не делает это вполне допустимо.
Для есп32 такой фокус уже не прокатывает. Однако у есп32 есть довольно богатая периферия, для которой точно выдержать тайминги импульсов никаких проблем не составляет. Для этого надо только почитать даташит и подумать :)
Serge78rus
24.08.2019 20:07Зачем такие жуткие манипуляции со строками
если класс String имеет функцию substring()?String command = ((String)inString[0] + (String)inString[1] + (String)inString[2]); String param; int len = inString.length(); for (int i = 3; i < len; i++) { param = (String)param + (String)inString[i]; }
Так же зачем в цепочке из множества if() в случае нахождения совпадения команды проверять и остальные варианты, заведомо не совпадающие?
IronHead
26.08.2019 09:26Для тех, кто захочет поиграть с шаговыми двигателями — не советую идти по пути автора.
Для этих целей есть более современные решения, основанные на step/dir драйверах.
A4988, DRV8825, TB6560 и пр.
В них есть ограничение тока, поэтому драйвер не превратится в барбекю + заметно проще и дешевле конструкция.anunknowperson Автор
26.08.2019 17:42Ну, по мне так, l298n будет использовать попроще чем вышеперечисленные драйверы.
FGV
26.08.2019 19:19Ну, по мне так, l298n будет использовать попроще чем вышеперечисленные драйверы.
чем проще то? для A4988 достаточно двух проволок — DIR (направление) и STEP (шаг), для 298n надо четыре минимум.anunknowperson Автор
27.08.2019 07:01Ну, кому как
IronHead
27.08.2019 09:15Два провода для A4988, поддержка биполярных шаговых двигателей (это где 4 провода, а не 6), встроенный контроль тока (чтобы не пожечь двигатель и сам драйвер). В общем все то, чего не хватает дубовой l298n из прошлого века.
TheCalligrapher
28.08.2019 01:30В l298n есть много неэффективностей. Но не ясно при чем здесь биполярные двигатели. l298n прекрасно поддерживает биполярные двигатели.
reticular
спасибо огромное за статью!
только печально видеть, что вы используете драйвер L298N :(
есть же специально разработанные драйвера типа A4988
их преимущество в том, что они держат заданный ток в обмотках мотора
а в вашем случае моторы будут перегреваться
romanetz_omsk
А недостаток в том, что A4988 перегрузки не держат в силу размера корпуса.