ARDUINO Управление шаговым двигателем (поворотное устройство)

Allonks

✩✩✩✩✩✩✩
9 Авг 2022
5
0
Добрый день! Помогите разобраться, делаю поворотное устройство на шаговом двигателе ШД57 + редуктор (1/25)
С простыми поворотами и с кручением туда-сюда, все хорошо, но вот не как не могу отладить патрулирование... есть 23 точки, к каждой нужно подъехать остановиться на 2 минуты и поехать к следующей.
Все работает без цикла For, но вот в нем почему-то не отправляются данные на двигатель
вот скетч

C++:
/* управление

!lдвижение по часовой стрелке

w - влево  на X градусов

e - вправо на X градусов

y - режим патруля

s - остановить y

p - узнать положение в градусах

m -

72000 шагов = полный круг (360*)

200 шагов = 1 градус

*/

#include <GyverStepper.h>

GStepper<STEPPER4WIRE> stepper(1600, 5, 3, 4, 2);

unsigned long last_time;

  long mass1[22] = {0, 5, 9, 13, 17, 21, 24, 29, 32, 89, 92, 97, 99, 124, 132, 136, 139, 143, 146, 149, 151, 153};  // массив с координатами

  long mass2[22]; // массив с преобразованием координат в шаги

  long v; // хранение координаты

  int  a; // выбор режима

  int  val; // временно не нужно

  char ch; // ввод в консоль

  int n1; // для первого таймера

  int n2; // для второго таймера

void setup() {

  Serial.begin(9600);  //

  stepper.setRunMode(FOLLOW_POS);

  // установка макс. скорости в шагах/сек

  stepper.setMaxSpeed(200);  // в рабочем режиме вернуть на 50

  // установка ускорения в шагах/сек/сек

  stepper.setAcceleration(200);

   a = 1;

    for (int i = 0; i < 21; i++) {   //преобразую координаты в шаги

    mass2[i] = mass1[i] * 200;

     Serial.println(mass2[i]);

  }
}

void loop()
{
  stepper.tick();

  if (a<2) {  // работа в ручном режиме

   char ch = Serial.read();

if (ch == 'w') // влево на +1 градусов

{
  stepper.setTargetDeg(-200, RELATIVE);
}

if (ch == 'e')  // вправо на -1 градусов

{
  stepper.setTargetDeg(200, RELATIVE);
}

if (ch == 'o') // вернуться в 0

{
  stepper.setTargetDeg(0);
}

if (ch == 'p') // узнать положение

{
  Serial.println(stepper.getCurrent()/888);
}

if (ch == 'z') a = 3; // переход в режим патруля

  }

else {

  stepper.tick();

  Serial.println (" 1 "); // тут тест входа  в Z

v = stepper.getCurrent()/888; // Определение координаты

for (int j = 1; j < 21; j++){ // цикл поворота вправо

  stepper.tick();

  Serial.println ("2"); // тест входа в for

  last_time = millis();

do {                         // таймер пока что установлен на 5 секунд

  if (millis() - last_time > 5000) {
    Serial.println("3"); // тест выхода в таймер
    n1 = 1;
  }
    else {
      Serial.println("4"); // жду конца таймера
    n1 = 0;
  }
} while (n1 != 1);

stepper.setTargetDeg(mass2[j]); // даю координаты двигателю (но почему то игнорируется и никуда не едет

Serial.println("5"); // срабатывает

  while (mass2[j] != v) { // жду пока мотор повернет до заданного направления
   Serial.println("mass2");
    Serial.println(mass2[j]);
    Serial.println("v");
    Serial.println(v);
      v = stepper.getCurrent()/888;
    v = v*200;  // умножаю на 200, что бы число было в формате масс2
  }
  Serial.println("7");
}
for (int k = 21; k > -1; k = k-1){ //тоже самое в обратную сторону (чутка отличается потому что тестирую, но в любом случае никак не работает
  stepper.tick();
last_time = millis();
  do {
  if (millis() - last_time > 5000) {
   n2 = 1;
  }
  else {
    n2 = 0;
  }
}  while (n2 != 1);
  stepper.setTargetDeg( mass2[k]);
   do {
    v = stepper.getCurrent()/888;
     v = v*200;
    } while (mass2[k] < v);
  }

char ch = Serial.read(); // стоп, выход из цикла с патрулём
  if (ch == 's') a = 1;
    }
}
 
Изменено:

Allonks

✩✩✩✩✩✩✩
9 Авг 2022
5
0
Вчера поэкспериментировал и выяснил, что stepper.setTargetDeg() и stepper.setTarget() вообще в циклах не запускаются, никто не знает почему так?
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
611
145
C++:
stepper.setMaxSpeed(200);
а не много это будет для мотора с 72000 шагов на 1 оборот? 200 шагов на 1градус х 200 градусов в секунду = 40000 шагов для поворота на 200 градусов за 1 секунду. Ты точно уверен, что моторчик, а может и ардуино, переваривает такую частоту? И очень много лишних движений: зачем переводить из одного массива в другой? потом при чтении позиций таять расчеты. Можно же сразу указать 72000 шагов на 1 оборот, а не 1600 (????) и потом танцы с бубном. В цикле задаешь позицию в градусах и не дожидаясь пока он туда дойдет (tick()) выполняет дальше программу.
 
Изменено:

Allonks

✩✩✩✩✩✩✩
9 Авг 2022
5
0
@viktor1703, stepper.setMaxSpeed() - это же шаги в секунду, а не градусы в секунду. Тут все работает хорошо, даже при больших числах, в режиме кручения "туда - сюда" из базового примера и при выставление позиции в ручном режиме, которые на "w" "e" "o" у меня

1600 шагов выставляются же исходя из возможностей драйвера насколько я понимаю, а не мотора

В цикле задаю позицию в шагах, которую беру из mass2. В mass2 градусы переведены в шаги

про (tick()) не очень понял, если не сложно объясните пожалуйста подробнее
 
Изменено:

viktor1703

★★★✩✩✩✩
9 Дек 2021
611
145
А вот этот участок
C++:
last_time = millis();

do {                         // таймер пока что установлен на 5 секунд

  if (millis() - last_time > 5000) {
    Serial.println("3"); // тест выхода в таймер
    n1 = 1;
  }
    else {
      Serial.println("4"); // жду конца таймера
    n1 = 0;
  }
} while (n1 != 1);
что выполняет кроме срания "4" в терминалв течение 5 секунд? deley(5000) не заменит его?
Дальше
C++:
while (mass2[j] != v) { // жду пока мотор повернет до заданного направления
   Serial.println("mass2");
    Serial.println(mass2[j]);
    Serial.println("v");
    Serial.println(v);
      v = stepper.getCurrent()/888;
    v = v*200;  // умножаю на 200, что бы число было в формате масс2
  }
получаешь координаты, потом делишь на 888(?),а потом умножаешь на 200. И сравниваешь с mass2?
 
Изменено:

Allonks

✩✩✩✩✩✩✩
9 Авг 2022
5
0
@viktor1703, заменит, но я исходил из советов, что всегда стоит избегать deley(), поэтому таймер сделал таким, когда программа будет отлажена режим удержания позиции будет составлять от 2 минут

спамит 4 он для понимания того где сейчас находиться программа, в будущем все Serial.println() с цифрами в циклах будут убраны
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
611
145
@viktor1703, стоит избегать deley(), поэтому таймер сделал таким

спамит 4 он для понимания
В твоём случае твой таймер = delay(), одинаково зависает на 5 секунд. Смотри выше мой пост, я там добавил ещё вопросов
 

Allonks

✩✩✩✩✩✩✩
9 Авг 2022
5
0
@viktor1703, stepper.getCurrent()/888 - дает координату в градусах ( почему именно 888 не знаю, вычислил исходя из данных компорта, отправлял команду сделать 1 шаг, запрашивал Serial.println( stepper.getCurrent()) и получалось 888)

в массиве mass2 записаны координаты в шагах, в V из stepper.getCurrent()/888 приходят градусы поэтому, что бы сравнивались одни величины умножаю на 200

while (mass2[j] != v) в целом это ожидание пока двигатель повернется на нужный угол, что бы For не уходил дальше пока не достигнута первая точка

главная проблема которую я не понимаю, почему stepper.setTargetDeg() и stepper.setTarget() не работают внутри циклов
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
611
145
Я вот не понимаю для кого писались документация к библиотеке, с примерами? Нет бы сначала изучить, потренироваться на простых действиях, понять как оно работает. Нет же будем городить огород. Зачем тебе читать позицию, делить,умножать,сравнивать? Алекс для кого придумал tick()?
 

Вложения

  • Лойс +1
Реакции: poty

poty

★★★★★★✩
19 Фев 2020
3,227
939

@Allonks, потому что эти команды лишь устанавливают таргет. Реальное движение осуществляется в tick().
 

Romashchandr

✩✩✩✩✩✩✩
19 Июл 2022
19
0
а можете обьяснить что означает фраза "tick() нужно вызывать как можно чаще" .
в каждой второй строке писать?
или после каждого установления цели?
или еще как то?
 

poty

★★★★★★✩
19 Фев 2020
3,227
939
Прочитайте первую выдержку из поста @viktor1703, там есть команда, которая позволяет Вам оценить необходимую частоту (или период) вызова tick(). Как Вы будете добиваться этого - на Вашей совести. Можно в каждой второй строке писать, можно длительность loop ограничить заданным периодом, можно в прерывании вызывать по таймеру...
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
611
145
@Romashchandr, ну вот смотри, есть у тебя
C++:
while (mass2[j] != v) { // жду пока мотор повернет до заданного направления
   Serial.println("mass2");
    Serial.println(mass2[j]);
    Serial.println("v");
    Serial.println(v);
      v = stepper.getCurrent()/888;
    v = v*200;  // умножаю на 200, что бы число было в формате масс2
  }
то есть, ждёшь пока мотор дойдет до нужной точки, фактически вешаешь МК. Тогда правильнее будет
C++:
while (tick){}
 

poty

★★★★★★✩
19 Фев 2020
3,227
939
ШД57, если я правильно понял, имеет 1,8 градуса/шаг, с учётом редуктора - 0,072 градуса на шаг. Т.е., получается что полный оборот составляет 5000 полных шагов (в инициализации указано 1600). Выбрано именно управление полным шагом ("STEPPER4WIRE управляет мотором в полношаговом режиме (выше скорость и момент) "). Это - первое несоответствие.
Далее - нужно убрать все пересчёты! getCurrent возвращает именно позицию в шагах, нужно ориентироваться исключительно на шаги!
Скорость двигателя выбрана 200 шагов/секунду. Не знаю, какой параметр выдаст getMinPeriod, но никак не больше 1/200 секунды = 5мс. Думаю, для надёжности нужно скорость увеличить раза в 2, т.е., вызывать tick() раз в 2,5мс. А теперь посмотрим, что напихано в while (mass2[j] != v):
  • вывод не менее 16 символов (128бит) со скоростью 9600бит/сек = 13,33мс:
  • выполнение функции getCurrent, деление, умножение, сравнение - я оцениваю ещё в 30мкс.
Итого - 13,36мс. Т.е. то, что происходит в цикле занимает больше чем в 5 раз времени, чем требуется для вызова tick(). Надо увеличивать скорость serial хотя бы, если не убирать нафиг из цикла лишний дебаг.