Gyver Stepper, вопросы по библиотеке

BLOCKHEAD

✩✩✩✩✩✩✩
6 Окт 2021
3
0
@Lumenjer, такая конструкция работает, спасибо.
Условие у меня было не в loop, а в таком цикле:
C++:
         for (long target : targets) {
              stepper.setTarget(target);
                  while (stepper.getCurrent() != target) {
Можете объяснить, в чем была ошибка? Выходит, что программа задавала скорость второму мотору при каждом шаге первого и тем самым перегружала его? А эта штука с булевыми переменными эту проблему решает?
 

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
@BLOCKHEAD, Я стараюсь отталкиваться от принципа, что нет смысла дергать методы\функции\параметры если что-то в них не поменялось. Но как-то на скорую руку тоже проверял работу двух шаговиков, и когда задавал скорость второму, которая зависела от скорости первого то тоже не захотело работать как надо. Подкинул флаги и начал вызывать смену скорости намного реже - заработало.
В дебри библиотеки лезть не хотелось, чтобы разбираться, почему так происходит. Может баг, а может так задумано
 
  • Лойс +1
Реакции: BLOCKHEAD

InterestedStudent

✩✩✩✩✩✩✩
23 Сен 2021
3
0
Очень понравилась данная библиотека.

Можно ли использовать ее компоненты (части, разумеется с указанием автора) для написания своего кода?

Мне бы хотелось использовать прерывания для генерации сигнала STEP.
 

bort707

★★★★★★✩
21 Сен 2020
2,902
863
Мне бы хотелось использовать прерывания для генерации сигнала STEP.
вы думаете, если автор использовал прерывания, то другим уже нельзя?:)

но лучше не "брать части", а разобраться в коде и написать свое по аналогии.
 
  • Лойс +1
Реакции: Lumenjer

InterestedStudent

✩✩✩✩✩✩✩
23 Сен 2021
3
0
вы думаете, если автор использовал прерывания, то другим уже нельзя?:)
Нет :).

Меня интересует разгон-ускорение (методы planner(), smoothSpeedPlanner()), а так же подсчет шагов (лишь некоторые приемы).

Есть желание сделать генерацию шагов на прерываниях таймера (для драйвера шагового двигателя который понимает STEP\DIR), чтобы контролер сам изменял состояния вывода, без необходимости вызывать метод tick.
 

bort707

★★★★★★✩
21 Сен 2020
2,902
863
@InterestedStudent, при постоянной скорости именно так все и делают. Но разгон-торможение при этом усложняются.
 

InterestedStudent

✩✩✩✩✩✩✩
23 Сен 2021
3
0
Мне нужна и постоянная скорость (с режимом ускорения, торможения), для одно из двигателей и подсчет шагов для другого (с режимом ускорения, торможения).

Поэтому и хочу воспользоваться частями уже готового решения.
 

IvGor

✩✩✩✩✩✩✩
21 Апр 2021
8
0
Друзья, можете помочь? Пишу маленький скетч по движению шагового двигателя. Но при настройке скорости вращения регулировка происходит плавно только до определенного предела, потом резкий скачок. В качестве платы Arduino Nano.

C++:
// 1- Двагем мотором с заданной скоростью до первого концевика и останавливаем.
// 2- По нажатию кнопки запускаем программу движения от вехнего концевика до нижнего с возможностью настроййки скорости движения
// 3- При нажатии кнопки происходит остановки двигателя, при повторном нажатии запуск.
// 4- Программа работает до выключения питания. Скорость меняет переменный резистор.
//Версия 2.1


#define DRIVER_STEP_TIME 3
#include "GyverStepper.h"
#include "GyverButton.h"
GStepper< STEPPER2WIRE> stepper(6400, 3, 2, 4);
GButton butt_start(12);
GButton butt_up(7);
GButton butt_down(8);
bool stoped = true;


void setup(){
  stepper.setAccelerationDeg(5000);
  stepper.autoPower(true);
    pinMode(7, INPUT_PULLUP);//--------Кнопка UP
    pinMode(12, INPUT_PULLUP);//--------Кнопка START
    
 

//========= ДВИЖЕНИЕ ДО НАЧАЛЬНОЙ ТОЧКИ ==============================
    
    stepper.setRunMode(KEEP_SPEED);
    stepper.setSpeedDeg(-100);// --------Медленно крутимся Вверх до концевика

  while(digitalRead(7)) {//---------------До нажатия кнопки UP 
    stepper.tick();

    }
  stepper.stop();
//=====================================================================


  butt_start.setDebounce(4);     
  butt_up.setDebounce(4);
  butt_down.setDebounce(4);


}


void loop() {
int mnoj = 1;
int speed = 20000;

pinMode(10, OUTPUT);
butt_start.tick();
butt_up.tick();
butt_down.tick();



if (butt_start.isClick()) {
 
  if(stepper.getState())
  {
    stepper.brake();
    stoped = true;
  }
    else
    {
      stoped = false;
      stepper.setSpeed(speed - analogRead(0)*19, 5000);
      stepper.tick();
    }
  }
//-----------------Концевики ------------------------------
  else if (butt_down.isPress() && !stoped){
  digitalWrite(10, HIGH);
  stepper.disable();
  stepper.stop();
  stepper.reverse(true);
  stepper.setSpeed(speed - analogRead(0)*19, 5000);
  }
  //------------Нижний концевик ---------------------------
  else if (butt_up.isPress() && !stoped) {
  digitalWrite(10, LOW);
  stepper.disable();
  stepper.stop();
  stepper.reverse(false);
  stepper.setSpeed(speed - analogRead(0)*19, 5000);
  }
//---------------------------------------------------------
 

  if (!stoped){
      static uint32_t tmr2;
        if (millis() - tmr2 > 50) {
        tmr2 = millis();
      stepper.setSpeed(speed - analogRead(0)*19, 5000);
    }
  }
  stepper.tick();
}
 

hiteker75

✩✩✩✩✩✩✩
18 Авг 2019
26
1
Друзья, можете помочь? Пишу маленький скетч по движению шагового двигателя. Но при настройке скорости вращения регулировка происходит плавно только до определенного предела, потом резкий скачок. В качестве платы Arduino Nano.
А почему именно эту библиотеку юзаете?
Не проще на AccelStepper ?
Вроде нет проблем с разгоном
 

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

★★★★★★★
14 Авг 2019
4,197
1,282
Москва
А чего тут думать ? тут смотреть надо.
Вот эту часть выводите в монитор порта и смотрите как изменяется при скачке
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
567
@hiteker75, AccelStepper сжирает в десятки раз больше процессорного времени на участке разгона
 

rastaman29

★✩✩✩✩✩✩
15 Ноя 2019
45
16
Может кто подскажет, мне просто надо крутить по первой кнопке в одну сторону, по второй в другую? Я вообще плохо разбираюсь. Вот такой код написал, не работает. Что не так? Плата NODEMCU.
C++:
#include "GyverStepper.h"
#include "GyverButton.h"
GStepper< STEPPER2WIRE> stepper(200, 14, 12);
GButton butt1(5);
GButton butt2(4);

void setup(){
  stepper.setRunMode(KEEP_SPEED);
  stepper.setAccelerationDeg(1000);
  pinMode(2, OUTPUT);        // Enable
  digitalWrite(2, LOW);
  butt1.setDirection(NORM_OPEN);
  butt1.setDebounce(4);
  butt2.setDebounce(4);
}

void loop() {

butt1.tick();
butt2.tick();
stepper.tick();

if (butt1.isHold()) {
  digitalWrite(2, HIGH);      //Включение мотора Enable
  stepper.setSpeed(1000);

  }

if (butt1.isRelease()) {
  digitalWrite(2, LOW);       //Выключение мотора Enable
  }
stepper.tick();
}
 
Изменено:

VAF

✩✩✩✩✩✩✩
15 Июл 2023
20
0
Москва
Помогите понять особенности мотора 28BYJ-48. Пытался использовать Stepper.h, AccelStepper.h, GyverStepper2.h и столкнулся со многими непонятками, связанными с выбором скоростей и др. параметров. Лучший вариант был "жужжит, но не крутится". Написал свой скетч без библиотек (приложен). Все работает и в по шаговом и полушаговом режимах, в обе стороны. Но с разной ценой шага, против часовой движется, кажется, медленней и на меньший угол в отношении 280/360. Как это убрать? Или это дефект мотора.
Интересно также зачем в GyverStepper2 менять порядок пинов, При использовании первого примера1 из https://kit.alexgyver.ru/tutorials/stepmotor/ при порядке пинов (1, 3, 2, 4) крутится только по часовой, при (4, 2, 3, 1) только против часовой.
 

Вложения

  • 1.3 KB Просмотры: 0

KovAlex

✩✩✩✩✩✩✩
9 Фев 2022
25
0
Всем добрый день!
Требуется помощь зала..
Пишу контроллер поворотки антенны для работы через спутники на Arduino Nano.
Два вот таких моторчика (один вращает по азимуту, второй - элевация). Два драйвера А4988.
За основу взят GyverStepper2 вариант с таймером.
С одним ШД(азимут) проблем не возникло, всё работает согласно задачи.
Споткнулся на подключении второго ШД. Не понимаю, как в этом случае юзать таймер..
Реально ли вообще это - использовать ОДИН таймер для управления двумя двигателями?
Наверное, можно просто передавать в обработчик прерывания таймера попеременно активный обработчик для каждого двигателя.
Но! Задача предусматривает два варианта управления:
1. ручной, энкодером
2. авто с компа (программа Orbitron).
С одним двигателем сейчас работают успешно оба варианта.

Что посоветуете?
 

KovAlex

✩✩✩✩✩✩✩
9 Фев 2022
25
0
В самом простом виде в прерывании таймера вызывать тики обоих шаговых моторов.
Гм.. Не въехал..
Вот мой обработчик прерывания движка азимута
Код:
ISR(TIMER1_COMPA_vect) {
  bool flag_break = false;
  int32_t check = 0;
  // здесь происходит движение мотора
  // если мотор должен двигаться (true) - ставим новый период таймеру
  if (a_stepper.tickManual()) setPeriod(a_stepper.getPeriod());
  else stopTimer();
  // если нет - останавливаем таймер
  if (stat_hal != digitalRead(AZ_HAL_PIN)) flag_hal = true; // проверка на то, что двигатель действительно крутится (датчик холла)
  check = a_stepper.getCurrent() - start_pos;

  if (abs(check)>41 && flag_hal == false) {  // если мотор не крутится, делаем стоп и записываем текущую позицию в EEPROM
          stopTimer();
          a_stepper.brake();
          a_stepper.setCurrent(a_stepper.getCurrent() -(a_stepper.dir*abs(check)));
          flag_break = true;
          flag_error = true;        
  } else {
    flag_error = false;
  }
 
 
  if (a_stepper.ready() || flag_break == true)
  {
    a_stepper.disable();
    digitalWrite(LED_PIN , LOW);
    cur_pos = a_stepper.pos;
    flag = 0;
    WriteBackup();  // запись текущей позиции в EEPROM
  }
}
Я правильно вас понял, что можно сделать вот так - строки
Код:
if (a_stepper.tickManual()) setPeriod(a_stepper.getPeriod());
  else stopTimer()
заменить на
Код:
if (a_stepper.tickManual())  // stepper azimut
{
   setPeriod(a_stepper.getPeriod()); 
  }
else if (e_stepper.tickManual())  // stepper elevation
{
   setPeriod(e_stepper.getPeriod()); 
}
else 
{
  stopTimer();
}
Как к этому отнесётся таймер, если к нему прилетят ОБА тика ОДНОВРЕМЕННО?
Или во время движения двигателя азимута, прилетит тик старта двигателя элевации.
 
Изменено:

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

★★★★★★★
14 Авг 2019
4,197
1,282
Москва
Таймер останавливать не надо. Пусть всегда идет.
Я могу путать, давно не следил за этой библиотекой, но в самом тике есть проверка надо дергать мотором или нет, т.е. условно можно сдлеть так:
C++:
ISR(TIMER1_COMPA_vect) {  
a_stepper.tick();
b_stepper.tick();
}
Тут надо разделить понятия таймер и тики мотора - это два независимых процесса, так во всяком случае раньше было, как сейчас я не знаю, так что вполне могу ошибаться.
Попробую объяснить.
Как было раньше: тик мотора должен вызываться как можно чаще. Сама функция тика следит за временем и если с момента последнего тика проходило достаточно времени до следующего тика, то выполнялся степ мотора, если нет, то просто выход из функции. Там же, внутри , реализованы были ускорения и торможения. Т.е. если грубо тик говорит объекту мотора "дерни пин степ, если надо" и все.
Тоже самое будет для другого мотора - они будут одновременно обрабатывать свои моторы, и независимо друг от друга.
Тут еще надо понимать, что если мотор на полном шаге может дергать пином степ 1000 раз, в сек, то вызывать функцию тика 1000 раз в сек будет мало, т.к. при это не будет плавности разгона и торможение (скорости будут примерно такие 1000 раз в се, 500 раз в сек, т.к. на второй тик будет рано еще дергать степ, а на второй как раз, а это и будет 500 раз в сек.) а вот если дергать 5000 раз в сек, то будет уже что то приличное.

Да, совершенно верно, можно менять время срабатывания таймера, но тогда это и будет работать только с 1 мотором, под второй надо будет запускать отдельный таймер, что для ардуины расточительно, такое можно сделать с стм - там таймеров жопой ешь .
 

KovAlex

✩✩✩✩✩✩✩
9 Фев 2022
25
0
@Старик Похабыч,
Я правильно понимаю, что на одном таймере управлять двумя ШД не получится?
И какое же тогда решение может быть?
 

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

★★★★★★★
14 Авг 2019
4,197
1,282
Москва
Если для управления ускорением и торможением мотора менять длительность таймера, то да, будет 1 тайме - 1 мотор.
Если просто дергать тик мотора, а ускорение и торможение повесить на библиотеку мотра, то можно подключить больше 1 мотора, 2, 3, точно потянет.
 

KovAlex

✩✩✩✩✩✩✩
9 Фев 2022
25
0
Если просто дергать тик мотора,
А где это делать? В обработчике прерывания таймера, как вы предлагали выше, или где-то в loop?
И где и как тогда реализовать отслеживание сигнала с датчика холла? Вернее - с двух датчиков.
Это принципиально, т.к. датчика положения выходного вала мотора у меня нет.
Азимут и элевация тупо запоминаются в EEPROM.
а ускорение и торможение повесить на библиотеку мотра,
А это как реализовать? И чем сиё может грозить? Потери плавности движения не будет?

P.S. А может всё-таки возможно как-то выкрутиться в "моём" варианте? Как-то сделать "очередь" для моторов.
Мне не принципиально иметь одновременное вращение обоих моторов. Несколько секунд могу и подождать.

P.P.S. Случаем, вы не про этот вариант из примеров библиотеки говорите? -
Код:
// крутим мотор туда-сюда плавно с ускорением
// для синхронного многоосевого движения используй встроенный планировщик траекторий
// папка с примерами Planner и Planner2

#include "GyverStepper.h"
// подключим три мотора
// у первого и второго управление EN не подключаем
GStepper stepper1(100, 2, 3);
GStepper stepper2(100, 4, 5);
GStepper stepper3(100, 6, 7, 8);

void setup() {
  // мотор 1 просто вращается
  stepper1.setRunMode(KEEP_SPEED);
  stepper1.setSpeed(300);

  // мотор 2 будет делать sweep по проверке tick
  stepper2.setRunMode(FOLLOW_POS);
  stepper2.setMaxSpeed(1000);
  stepper2.setAcceleration(300);

  // мотор 3 будет перемещаться на случайную позицию
  stepper3.setRunMode(FOLLOW_POS);
  stepper3.setMaxSpeed(1000);
  stepper3.setAcceleration(300);
  stepper3.autoPower(true);
  stepper3.enable();
}

void loop() {
  // первый мотор
  stepper1.tick();
 
  // второй крутим туды-сюды (-1000, 1000)
  if (!stepper2.tick()) {
    static bool dir;
    dir = !dir;
    stepper2.setTarget(dir ? -1000 : 1000);
  }

  // третий по таймеру
  // будет отключаться при остановке
  stepper3.tick();
  static uint32_t tmr;
  if (millis() - tmr > 5000) {   // каждые 5 секунд
    tmr = millis();
    stepper3.setTarget(random(0, 2000));  // рандом 0-2000
  }
}
Да, и ещё - может мне стОит прикрутить в свой проект что-то из GPlanner2?
Правда, пока не вкуриваю, что вообще такое "многоосевой станок" и похож ли он на мой "станок". :)
 

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

★★★★★★★
14 Авг 2019
4,197
1,282
Москва
1) Пример похож на то что я описывал. В нем вместо прерывания по таймеру сам цикл loop , пустой цикл может крутиться с частотой 200кГц.

2) Датчики холла я бы считывал по прерыванию на пинах 2 и 3 (аппаратно)

3) Если одновременное движение двух моторов не требуется, то можно и поочередно делать движение моторов. Будет что то типа этого в прервании:
если положение мотора 1 не соотв движению то
{
шевелить мотором номер 1 с нужным ускорением
}
иначе
{
если положение мотора 2 не соотв движению то
{
шевелить мотором номер 2 с нужным ускорением
}
}
 

KovAlex

✩✩✩✩✩✩✩
9 Фев 2022
25
0
1) Пример похож на то что я описывал. В нем вместо прерывания по таймеру сам цикл loop , пустой цикл может крутиться с частотой 200кГц.
Увы, loop совсем не пустой.. В нём кнопки, энкодер, дисплей, serial для приёма данных от Orbitron.
Сильно сомневаюсь, что всё это не будет тормозить движки..
2) Датчики холла я бы считывал по прерыванию на пинах 2 и 3 (аппаратно)
И тут "в пролёте".. На этих пинах энкодер на EncButton. Датчики холла на A0-A1. "Цифровых" пинов не хватило на всё..
Даже D6-D7 задействованы для прерывания компаратора (сохранение позиции при аварийном отключении питания при движении моторов).
3) Если одновременное движение двух моторов не требуется, то можно и поочередно делать движение моторов. Будет что то типа этого в прервании:
если положение мотора 1 не соотв движению то
{
шевелить мотором номер 1 с нужным ускорением
}
иначе
{
если положение мотора 2 не соотв движению то
{
шевелить мотором номер 2 с нужным ускорением
}
}
Чёт плохо воспринимается на родном языке.. :)
Это вот так? -
Код:
if (a_stepper.tickManual())
{
    setPeriod(a_stepper.getPeriod());
}
else
{
    if (e_stepper.tickManual())  setPeriod(e_stepper.getPeriod());
}
Даже лучше, наверное, вот так -
Код:
 if (a_stepper.tickManual()) 
  { 
    setPeriod(a_stepper.getPeriod());
  }
  else if (e_stepper.tickManual()) 
  {
    setPeriod(e_stepper.getPeriod());
  }
  else 
  {
    stopTimer();
  }
 

KovAlex

✩✩✩✩✩✩✩
9 Фев 2022
25
0
Упс... Забыл один интересный момент.
Если во время движения мотора азимута прилетит старт на мотор элевации, то попав в прерывание этот "старт" тупо погибнет..
Ну и наоборот тоже самое..
Надо изобретать какой-то "буфер" для хранения "отложенных стартов"..
 

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

★★★★★★★
14 Авг 2019
4,197
1,282
Москва
Так то прерывания можно повесить на любые пины, но обработка их будет чуть сложнее, чем аттачинтеррапт - они будут вызываться только на изменение состояния пина. Если считывать датчик холла в прерывании по таймеру , то можно потерять в скорости перемещения. Но не думаю, что тут очень важно незначительное снижение скорости.

Буфер не сильно должен быть большой. Есть направление азимута и склонение. При получении новой команды сразу записывать нужное направление в моторы. Тогда при попадании в прерывание будет мгновенное переключение на мотор азимута . а по выполнении на мотор склонения. Но не будет плавной остановки - вот этот момент надо продумать. Т.е. если пришло новое положение, а какой то мотор работает, то надо сначала его остановить, а уже потом задавать новые направления.
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
20
0
Москва
Если вы используете двухядерную плату, то наиболее простое решение разделить моторы по ядрам. Я так резделил шаговый мотор и Енкодер. Все получилось. Для системы с раздельным управление двух независимых объектов - это логично.