image

Всем привет.

Я думаю что вы, если работали с arduino+nema 17, знаете, что запустить несколько двигателей одновременно бывает очень затруднительно.

Есть разные способы решения этой проблемы, самый простой, пожалуй — использование библиотеки NemaStepper. Библиотека упрощает данную задачу во много раз, главное преимущество — она не останавливает выполнение программы. Устанавливается она также, как и все остальные библиотеки. Распространяется по MIT лицензии.

Ну что, давайте приступим. И начнем мы с подключения.

Мы будем использовать Simple Nema 17 с алиэкспресса за 500 рублей, драйвер L298N и arduino uno. Вот они:

image

image

image

  • В примере я буду показывать четыре подключенных драйвера к ардуине, хотя буду использовать только один.
  • В интернете есть много туториалов по подключению Nema 17, поэтому я не буду подробно расписывать это здесь.

Итак, подключаем мотор к драйверу:

image

image

Библиотека является объектно — ориентированной. Давайте рассмотрим пример включения одного мотора:

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)


  1. reticular
    24.08.2019 17:48
    +1

    спасибо огромное за статью!
    только печально видеть, что вы используете драйвер L298N :(
    есть же специально разработанные драйвера типа A4988
    их преимущество в том, что они держат заданный ток в обмотках мотора
    а в вашем случае моторы будут перегреваться


    1. romanetz_omsk
      25.08.2019 04:18

      А недостаток в том, что A4988 перегрузки не держат в силу размера корпуса.


  1. pvvv
    24.08.2019 17:51
    +2

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


  1. TheCalligrapher
    24.08.2019 18:06

    Ну то есть похоже что библиотека NemaStepper является простейшей тонкой оболочкой для реализации типичной ардуиновской кооперативной многозадачности для управления степперами.


    Это нормально, но меня удивила ваша фраза "Когда я искал решение моей проблемы, единственной подходящей библиотекой оказалась она". Это звучит примерно как "я искал, как увеличить переменную на 1, и перепробовав несколько, нашел только библиотеку Increment". У всех естественно возникнет вопрос: а чем вам простое ++i не подошло? Вот так же и здесь: зачем было искать библиотеку для кооперативного управления степпер-моторами (особенно если это потребовало усилий), когда это, мягко говоря, элементарное действие?


    1. acodered
      24.08.2019 23:09

      Просто покрутить один мотор влево-вправо, действительно, тривиально. С учетом, что библиотека так и так требует вызова Step() для каждого из моторов в отдельности, проще было переключать самостоятельно.

      А вообще, управление несколькими моторами может оказаться неожиданно сложной задачей.
      Навскидку:

      Заголовок спойлера
      — направление DIR нужно выставлять заранее, за несколько микросекунд до STEP/PUL
      — STEP должен быть определенной, одинаковой, длины. Нельзя просто в цикле или прерывании его переключать 1 / 0, плюс к этому драйвер может ловить шаг по переднему или заднему фронту
      — нужно гарантировать равномерность шагов (и равномерность ускорения). Если на простом Arduino это и решается просто, то уже на более сложном окружении ESP32 приходится идти на хитрые трюки, чтобы обеспечить равномерность. И это на 80 мегагерцах!
      — шаги нужно выдавать одновременно на несколько моторов. На самом деле одновременно, а не по очереди. Нельзя делать смелые предположения, «а пусть один мотор запаздывает на несколько микросекунд от остальных».
      — на «другом конце» может оказаться вообще не шаговый драйвер, а PID контроллер, например.


      1. FGV
        25.08.2019 14:43

        то уже на более сложном окружении ESP32 приходится идти на хитрые трюки


        ага, хитрые трюки заключаются в использовании периферии.


        1. acodered
          25.08.2019 23:09

          reports 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


          1. FGV
            26.08.2019 05:48

            but when it came to the parts that needed precise timing things got tricky

            Беда в том что почти все адуриновские библиотеки работают с внешним миром через программный ногодрыг. Для авр которая больше ничего кроме кручения двигателей не делает это вполне допустимо.
            Для есп32 такой фокус уже не прокатывает. Однако у есп32 есть довольно богатая периферия, для которой точно выдержать тайминги импульсов никаких проблем не составляет. Для этого надо только почитать даташит и подумать :)


  1. Serge78rus
    24.08.2019 20:07

    Зачем такие жуткие манипуляции со строками

          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];
          }
    
    если класс String имеет функцию substring()?

    Так же зачем в цепочке из множества if() в случае нахождения совпадения команды проверять и остальные варианты, заведомо не совпадающие?


  1. IronHead
    26.08.2019 09:26

    Для тех, кто захочет поиграть с шаговыми двигателями — не советую идти по пути автора.
    Для этих целей есть более современные решения, основанные на step/dir драйверах.
    A4988, DRV8825, TB6560 и пр.
    В них есть ограничение тока, поэтому драйвер не превратится в барбекю + заметно проще и дешевле конструкция.


    1. anunknowperson Автор
      26.08.2019 17:42

      Ну, по мне так, l298n будет использовать попроще чем вышеперечисленные драйверы.


      1. FGV
        26.08.2019 19:19

        Ну, по мне так, l298n будет использовать попроще чем вышеперечисленные драйверы.

        чем проще то? для A4988 достаточно двух проволок — DIR (направление) и STEP (шаг), для 298n надо четыре минимум.


        1. anunknowperson Автор
          27.08.2019 07:01

          Ну, кому как


          1. IronHead
            27.08.2019 09:15

            Два провода для A4988, поддержка биполярных шаговых двигателей (это где 4 провода, а не 6), встроенный контроль тока (чтобы не пожечь двигатель и сам драйвер). В общем все то, чего не хватает дубовой l298n из прошлого века.


            1. TheCalligrapher
              28.08.2019 01:30

              В l298n есть много неэффективностей. Но не ясно при чем здесь биполярные двигатели. l298n прекрасно поддерживает биполярные двигатели.