Управление шаговым двигателем через mx1805

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
Пробую освоить управление шаговым двигателем, но вместо вращения вал двигателя немного дребезжит и остаётся на месте. Можете подсказать в чем ошибки в скетче? Драйвера шагового двигателя пока нет, но т.к. есть драйвер управления коллекторным мотором на основе MX1805, то решил через него осваивать пока. Знаю что у Алекса есть библиотека, но делаю для понимания работы. У движка обмотки проверены.


C++:
#include <Arduino.h>

#define pause 3000     // задержка между шагами (мкс)
int8_t pins[] = {3, 4, 5, 6};  // драйвер (IN1 - A+, IN2 - A-, IN3 - B+, IN4 - B-)
int feedAmount = 1000;

// выключаем ток на мотор
void disableMotor() {
  for (byte i = 0; i < 4; i++) digitalWrite(pins[i], 0);
}

// Состояние пинов на каждом шаге  {IN1, IN2, IN3, IN4}
int8_t t1[]={0,1,1,0};
int8_t t2[]={1,0,1,0};
int8_t t3[]={0,1,0,1};
int8_t t4[]={0,1,0,1};

void step1(){
  for(byte i = 0; i < 4; i++) {
  digitalWrite(pins[i],t1[i]);
  delayMicroseconds(pause);
}
}

void step2(){
  for(byte i = 0; i < 4; i++) {
  digitalWrite(pins[i],t2[i]);
  delayMicroseconds(pause);
}
}

void step3(){
  for(byte i = 0; i < 4; i++) {
  digitalWrite(pins[i],t3[i]);
  delayMicroseconds(pause);
}
}

void step4(){
  for(byte i = 0; i < 4; i++) {
  digitalWrite(pins[i],t4[i]);
  delayMicroseconds(pause);
}
}


void setup() {
  for (byte i = 0; i < 4; i++) pinMode(pins[i], OUTPUT); 
}

void loop() {
  step1();
  step2();
  step3();
  step4();
}
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
611
145
в чем ошибки в скетче?
На вскидку, первое, почему в шагах 3 и 4 устанавливаются одинаковые уровни?
C++:
int8_t t3[]={0,1,0,1};
int8_t t4[]={0,1,0,1};
И второе, что за мотор? Может задержка в 3 мс между шагами мало для него?
 
  • Лойс +1
Реакции: Старик Похабыч

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
@viktor1703,
Что то ошибся, должно быть:
int8_t t3[]={1,0,0,1};
int8_t t4[]={0,1,0,1};
Про паузу тоже не подумал. Сегодня попробую. Спасибо за наводку.
ШД - китай, NEMA17

Логика подразумеваю такая как показал на рисунке
Красная и синяя линии - токи в обмотках ШД.
IN - входы драйвера MX1805, на них поступают управляющие сигналы, обозначил 0 и 1.

1676177420519.png
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
611
145
Может ещё не правильная фазировка быть. Если увеличение задержки не поможет, то попробуй поменять местами два провода одной из обмоток.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,301
Москва
Провода определить очень просто даже без прибора: берешь 2 провода и соединяешь их между собой. Пробуешь крутить вал мотора, если крутиться с усилием по сравнению с разомкнутыми проводами, то это одна катушка, если без - разные, меняй один из проводов.
 

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
Спасибо всем. Все заработало!

Столкнулся с ещё проблемой. Не понимаю как сделать работу программы без блокировки МК, т.к. при работе шагового двигателя МК на нажатие кнопки не реагирует, ток потребления составляет 0,7А. Пробовал такой же прерывистый режим реализовать на библиотеке GStepper, GStepper2, т.к. там нет блокирования работы МК и опрос кнопок происходит нормально, все заработало, но ток потребления у ШД выше и составляет 1,7А - мх1805 сильно греется, хотя скорость вращения примерно одинаковая.
Прерывистый режим ШД:
#include <Arduino.h>
#include <EncButton.h>
#define BTN_PIN 2           // кнопка
#define FEED_SPEED 3000     // задержка между шагами мотора (мкс)
#define STEPS_FRW 5        // шаги вперёд
#define STEPS_BKW 4        // шаги назад
const byte drvPins[] = {3, 4, 5, 6};  // драйвер (фазаА1, фазаА2, фазаВ1, фазаВ2)
int timer_feed = micros();
byte flagStart = false;

EncButton <EB_TICK, BTN_PIN> btn;
int feedAmount = 1000;


const byte steps[] = {0b0110, 0b1010, 0b1001, 0b0101};
void runMotor(int8_t dir) {
  static byte step = 0;
  for (byte i = 0; i < 4; i++) digitalWrite(drvPins[i], bitRead(steps[step & 0b11], i));
    delayMicroseconds(FEED_SPEED);
            step += dir;
}
// выключаем ток на мотор
void disableMotor() {
  for (byte i = 0; i < 4; i++) digitalWrite(drvPins[i], 0);
}
void oneRev() {
  for (int i = 0; i < STEPS_BKW; i++) runMotor(1);
  for (int i = 0; i < STEPS_FRW; i++) runMotor(-1);
}
void feed() {
  for (int i = 0; i < feedAmount; i++) oneRev();
  disableMotor();
}
void setup() {
  for (byte i = 0; i < 4; i++) pinMode(drvPins[i], OUTPUT);   // пины выходы
}
void loop() {
   btn.tick();
  if (flagStart && btn.click()) disableMotor();
  if (!flagStart &&btn.click())   feed();
}
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,301
Москва
Ну для того что бы сделать неблокирующим надо понять что блокирует. Это значит понять на какую операцию в цикле уходит максимум времени.
Тут даже запускать ничего не надо - блокирует все feed()
Т.е. идет цикл от 0 до feedAmount, т.е. до 1000, внутри которого запускается еще 2 циклы, от до 5 и до 4, что эквивалентно одному циклу до 9, Далее запускается функция runMotor, которая в результате будет запушена 1000*(5+4)=9000 раз, в которой тоже есть цикл до 4. А внутри цикла стоит , но быстрый и задержка 3000 мкс , или 3 миллисекунды. И что в итоге ? 9000*3=27 000 мс или 27 секунд ваша плата будет в ауте. С таким опросом кнопка просто не будет работать.
Как один из вариантов , самый простой , но и самый неправильный. Сделать тик кнопик и ее опрос на отмену работы в самом узком месте , рядом вот с этой строкой (19): delayMicroseconds(FEED_SPEED);
Что сделать правильнее:
За один цикл loop вызывать функцию поворота мотором, но выполнять ее только если прошел нужный интервал времени. Но тут есть тоже подводные камни: если Вы потом добавите еще какую функцию тяжелую, то мотор будет дергаться, из за неравномерности шагов.
Более правильно делать шаги мотором используя прерывания по таймеру. а в цикле только опрос кнопки с тиком, который кстати тоже можно делать по таймеру.Главное что бы интервала таймера хватило на все.
А можно кнопку повесить на отдельные прерывания.
 

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
@Старик Похабыч,спасибо! С прерываниями пока много непонятного, почитал есть ещё накладки и как понял что часть библиотек может заглючить, серва например использует 1-й таймер. Может в коде с библиотекой gstepper что то не так написал, что ток потребления такой большой? Код прикладываю, если есть возможность посмотрите пожалуйста.
Есть ли вероятность, что при управлении через драйвер A4988 ток будет меньше?

C++:
#include <Arduino.h>
#include <GyverStepper2.h>
#include <EncButton.h>
#include <GyverHX711.h> // https://vk.com/wall-97877471_783540
#include <LiquidCrystal_I2C.h>

#define _LCD_TYPE 1  // для работы с I2C дисплеями
#include <LCD_1602_RUS_ALL.h>
LCD_1602_RUS lcd(0x3F, 16, 2);

#include <TimerMs.h>
TimerMs tmr(2000, 1, 0);

#define BTN_PIN_START 2
#define BTN_PIN_1 7
#define BTN_PIN_2 8
#define BTN_PIN_3 9


GStepper2<STEPPER4WIRE> stepper(2048, 3, 4, 5, 6);
EncButton <EB_TICK, BTN_PIN_START> btn1;
EncButton <EB_TICK, BTN_PIN_1> btn2;
EncButton <EB_TICK, BTN_PIN_2> btn3;
EncButton <EB_TICK, BTN_PIN_3> btn4;

GyverHX711 sensor(10, 11, HX_GAIN128_A);
float unts = 0.035274;
uint32_t units = 0;
uint32_t ounces = 0;

byte flagStart = false;
int8_t forward = 26;
int8_t backward = -25;
byte flagForward = true;
byte flagBackward = false;
uint16_t pause = 3000;
uint16_t pause_ves = 100;

void driga(){
   static uint32_t timer = 0;

   if(flagForward && (micros() - timer >= pause)) {
    timer = micros();
    flagForward = !flagForward;
    flagBackward = !flagBackward;
   stepper.setSpeedDeg(forward);         
   }

   if(flagBackward  && (micros() - timer >= pause)){
    timer = micros();
    flagForward = !flagForward;
    flagBackward = !flagBackward;
   stepper.setSpeedDeg(backward);
   }
}

void weihgt(){
  static uint32_t timer = 0;
  if (sensor.available() && (millis() - timer >= pause_ves)) {
     timer = millis();
for(int i = 0;i < 50; i ++) units =+ sensor.read();   // усредняем показания 
  units = units / 50;                                               
  ounces = units * unts;                                    // переводим унции в граммы           
    lcd.setCursor(0, 0);
    lcd.print("Вес, грамм   ");
    lcd.setCursor(0, 4);
    lcd.print(ounces,1);
  }
}

void setup() {
  // Serial.begin(9600);
    delay(500);
  sensor.tare();    // калибровка нуля
    lcd.init();
  lcd.backlight();
  tmr.setPeriodMode();
}

void loop() {
  btn1.tick();   // дополнительный опрос таймаутов и коллбэков в loop
  btn2.tick();   // дополнительный опрос таймаутов и коллбэков в loop
  btn3.tick();   // дополнительный опрос таймаутов и коллбэков в loop
  btn4.tick();   // дополнительный опрос таймаутов и коллбэков в loop
  if(flagStart && btn1.click()) {
   flagStart = false;
   stepper.disable();
  }
  if(!flagStart && btn1.click()) flagStart = true;
  if(flagStart) {
    driga();
    stepper.tick();
  }
  if(btn2.click()) {
    forward = 26;
    backward = -24;
  }
    if(btn3.click()) {
    sensor.tare();    // калибровка нуля
  }
    weihgt();

    if(btn4.click()) {
      lcd.clear();
  }
if (tmr.tick()) lcd.clear();
}
 
Изменено: