GyverStepper. Обсуждение библиотеки

DAER

✩✩✩✩✩✩✩
17 Дек 2021
21
0
@Старик Похабыч,

попробовал ради тренировки изобразить в коде

C++:
volatile boolean F_START; //логический флаг стартовой инициации
volatile boolean F_KONC_A; //концевик А
volatile boolean F_KONC_В; //концевик В
long distance=0; //обьявили переменную дистанции и присвоили ей 0

void Initial_positionA() {   //ФУНКЦИЯ ОБРАБОТКИ ПРЕРЫВАНИЯ концевик A
  if (millis() - debounce >= 200 && digitalRead(2)) {
    debounce = millis();
    F_KONC_A = 1;
    }
}
void Initial_positionB() {   //ФУНКЦИЯ ОБРАБОТКИ ПРЕРЫВАНИЯ концевик B
  if (millis() - debounce >= 200 && digitalRead(2)) {
    debounce = millis();
    F_KONC_B = 1;
    }
}



void setup() {
F_KONC_A=0;
F_KONC_В=0;
F_START=1;

attachInterrupt(0, Initial_positionA, RISING); //ОБЪЯВЛЕНИЕ ПРЕРЫВАНИЯ А
attachInterrupt(1, Initial_positionB, RISING); //ОБЪЯВЛЕНИЕ ПРЕРЫВАНИЯ B


if (!stepper1.tick() && F_START==1 ){//Если флаг СТАРТ поднят
   stepper1.setRunMode(KEEP_SPEED); //Режим поддержания скорости. Просто едем, пока не нажмём концевик А.
   stepper1.setMaxSpeed(maxspd/2); //С маленькой скоростью
      }
     
       if (F_KONC_A ==1 && F_START==1 &&F_KONC_B==0) //Нажали концевик А, едем к концевику В
        stepper1.brake(); //РЕЗКО тормозим, чтобы не сломать концевик
        stepper1.reverse(); //Инвертируем направление вращения
        stepper1.setMaxSpeed(maxspd/2); //С маленькой скоростью
        stepper1.setCurrent(0);//обнуляем координаты
             
    }
       if (F_KONC_A ==1 && F_START==1 &&F_KONC_B==1) //Нажали концевик В
        stepper1.brake(); //РЕЗКО тормозим, чтобы не сломать концевик
        distance=stepper1.getCurrent(); //Получаем координату и записываем её в переменную distance
        stepper1.setRunMode(FOLLOW_POS);//Устанавливаем режим следования к цели
        stepper1.reverse(); //Инвертируем направление вращения
        stepper1.setMaxSpeed(maxspd/2); //С маленькой скоростью
        stepper1.setTarget(distance/2, Relative);//Устанавливаем координату цели. После остановки она сбросится в 0.
        F_KONC_A=0;
        F_KONC_В=0;
        F_START=0;
             
    }
   
Void loop (){

static bool dir = true;
    if (!stepper1.tick()) {  //Начинаем работать вперёд-назад
      stepper1.setMaxSpeed(maxspd);
        stepper1.setTarget(dir ? worksteps : -worksteps, RELATIVE);
        dir = !dir;
    }


}
 

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

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
Самое главное не написал: получилось ? Вроде не должно работать...
Смотрю код. есть ошибки.

C++:
volatile boolean F_START = 1; //логический флаг стартовой инициации
volatile boolean F_KONC_A = 0; //концевик А
volatile boolean F_KONC_В = 0; //концевик В
long distance = 0; //обьявили переменную дистанции и присвоили ей 0

void Initial_positionA() {   //ФУНКЦИЯ ОБРАБОТКИ ПРЕРЫВАНИЯ концевик A
  if (millis() - debounce >= 200 && digitalRead(2)) {
    debounce = millis();
    F_KONC_A = 1;
  }
}
void Initial_positionB() {   //ФУНКЦИЯ ОБРАБОТКИ ПРЕРЫВАНИЯ концевик B
  if (millis() - debounce >= 200 && digitalRead(2)) {
    debounce = millis();
    F_KONC_B = 1;
  }
}


void setup() {
  attachInterrupt(0, Initial_positionA, RISING); //ОБЪЯВЛЕНИЕ ПРЕРЫВАНИЯ А
  attachInterrupt(1, Initial_positionB, RISING); //ОБЪЯВЛЕНИЕ ПРЕРЫВАНИЯ B

  // в начале F_START всегда 1, это раз. stepper1.tick() - проверять не имеет смысла в setup - итог условие тут не нужно!
  //f (!stepper1.tick() && F_START==1 ){//Если флаг СТАРТ поднят
  stepper1.setRunMode(KEEP_SPEED); //Режим поддержания скорости. Просто едем, пока не нажмём концевик А.
  stepper1.setMaxSpeed(maxspd / 2); //С маленькой скоростью
  //}
  // это не будет работать!
  //if (F_KONC_A == 1 && F_START == 1 && F_KONC_B == 0) //Нажали концевик А, едем к концевику В, и лишние условия ни к чему.
  /*
       Тут не имеет смысла проверять  tick - он всегда будет true т.к. у нас движение с пост. скоростью, а не до места.
       Значит проверяем только на нажатие концевика:
      проверять надо так:
  */
  while (!F_KONC_A) stepper1.tick();



  stepper1.brake(); //РЕЗКО тормозим, чтобы не сломать концевик // тут не резко тормозим, а отменяем движение. Да его и не будет дальше, т.к. движение идет через tick, а его уже нет.
  stepper1.setCurrent(0);//обнуляем координаты // это делаем сразу.
  stepper1.reverse(); //Инвертируем направление вращения
  stepper1.setMaxSpeed(maxspd / 2); //С маленькой скоростью

  while (!F_KONC_B) stepper1.tick();

  // if (F_KONC_A == 1 && F_START == 1 && F_KONC_B == 1) //Нажали концевик В

  stepper1.brake(); //РЕЗКО тормозим, чтобы не сломать концевик
  distance = stepper1.getCurrent(); //Получаем координату и записываем её в переменную distance
  stepper1.setRunMode(FOLLOW_POS);//Устанавливаем режим следования к цели
  stepper1.reverse(); //Инвертируем направление вращения
  stepper1.setMaxSpeed(maxspd / 2); //С маленькой скоростью
  stepper1.setTarget(distance / 2, Relative); //Устанавливаем координату цели. После остановки она сбросится в 0.
  F_KONC_A = 0;
  F_KONC_В = 0;
  F_START = 0;

}

Void loop () {

  static bool dir = true;
  if (!stepper1.tick()) {  //Начинаем работать вперёд-назад
    stepper1.setMaxSpeed(maxspd);
    stepper1.setTarget(dir ? worksteps : -worksteps, RELATIVE);
    dir = !dir;
  }


}

Внес кое какие изменения, так работать должно , если ничего не упустил :)

Но есть замечания:
1) Если изначально перепутано направление движения, то снос концевика гарантирован. Ну вернее упор в него.
2) Я на тестовые концевики повесил конденсатор на 0.1мкф, и включил подтяжку PULLUP для данного пина, получил отлично работающую RC цепочку, для гашения дребезга.


Буду продолжать тут:
Т.к. движения симметричные , все происходит относительно середины , то собственно пофиг где будет 0, а где нет. И значение 2-го концевика тоже пофиг, будет оно со знаком + или со знаком -, главное взять переменную ЗНАКОВУЮ.
Тогда на оба пина с концевиками делаем ОДНУ функцию прерывания, которая будет возводить флаг , когда упремся в любой из концевиков.
И тогда код получается такой
0) Устанавливаем нужную скорость, 1 раз%
stepper1.setMaxSpeed(maxspd / 2);
1) Даигаемся в любую сторону, пока не упремся:
F_KONС=0; // на всякий скидываем состояние, если до этого был упор в концевик
while (!F_KONС) stepper1.tick();
2) Делаем место нулем:
stepper1.setCurrent(0);//обнуляем координаты // это делаем сразу.
3) меняем направление:
stepper1.reverse(); //Инвертируем направление вращения
4) Двигаемся пока не упремся:
F_KONС=0; // скидываем состояние, если до этого был упор в концевик
while (!F_KONС) stepper1.tick();
5) Запоминаем положение:
distance = stepper1.getCurrent(); //Получаем координату и записываем её в переменную distance
6) Запускаем движение к середине:
7) Возвращаем направление:
stepper1.reverse(); //Инвертируем направление вращения
stepper1.setTarget(distance / 2, Relative); //Устанавливаем координату цели. После остановки она сбросится в 0.

Вид общего прерывания при условии, что запаян конденсатор и сделано PULLUP.
1640113320950.png
C++:
void Initial_position() {   
    F_KONC= 1;  
}
Да, т.к. прерыания rising -, т.е. по возрастанию, а INPUT_PULLUP притягивает пин к лог. 1, то подключать концевик надо одним концом (COMNON) к земле, а втроым , тем, что NC (NORMAL CLOSE, нормально замкнутый) к пину.
 
Изменено:
  • Лойс +1
Реакции: DAER

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
@DAER, setup() выполняется один раз при включении устройства, далее будет пофиг, какие концевики сработали, а какие нет.

И void loop() с маленькой надо
 

DAER

✩✩✩✩✩✩✩
17 Дек 2021
21
0
Ну так и задумано один раз инициализация и измерение рабочего хода.

У меня пины подтянуты к земле резисторами на 10к. Ну и программно на всякий случай. А концевик подаёт на каждый +.
Без программного устранения дребезг есть. Возможно, из за того, то 2 и 3 пин это прерывания, опрашиваются очень часто.

ЕСТЬ ВОПРОСЫ
1. Если мотор в режиме keep_sped остановился приехал в точку, остановился и двинулся обратно. Что происходит с координатой? Она не обнуляется в момент остановки?

2. В конструкциях
if...
if...
if...

ecли режим мотора (поддерж. скорости) задан в первом иф, он распространяется на все нижележащие? Если в
сетап или раньше был указан другой режим (следования к координате)?
 

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

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
Координата не обнуляется. При движении в одну сторону координата просто увеличивается на 1, в другую уменьшается.

if тут не будет работать - написал вроде выше. Почему ? Потому что по условию if все что подходит выполниться 1 раз и все. А это значит мотор выполни только 1 шаг. И все. Он не будет двигаться, При условии while все что подходит под условие будет работать постоянно пока условие выполняется, до 1-го нарушения. Потом переход далее.

Режим работы мотора сохраняется до тех пор, пока его дальше не изменить.
 
  • Лойс +1
Реакции: DAER

DAER

✩✩✩✩✩✩✩
17 Дек 2021
21
0
см. комментарии

C++:
void setup() {
...
stepper1.setRunMode(FOLLOW_POS); //РЕЖИМ СЛЕДОВАНИЯ К ПОЗИЦИИ
...

}

void loop() {

    ...

    if (F_KONC_A ==1 && F_TIME==1){
        stepper1.brake();
        stepper1.setRunMode(KEEP_SPEED); //Установили режим поддержания скорости
        stepper1.setMaxSpeed(maxspd/2);
        ...
     
    }
     if (F_KONC_B ==1 && F_TIME==1){
                                   //ВОТ ТУТ КАКОЙ БУДЕТ РЕЖИМ МОТОРА???
         stepper1.brake();
        stepper1.setMaxSpeed(maxspd/2);
       ....
    }
}
 

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

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
Вот тут не обязательно! Неизвестно какой концевик (условие) сработает раньше.
Вот эти 2 строки:
C++:
        stepper1.setRunMode(KEEP_SPEED); //Установили режим поддержания скорости
        stepper1.setMaxSpeed(maxspd/2);
]
Нужно делать в setup
А в условиях оставить только stepper1.brake(); и добавить смену направления.
Но логика все равно как то хромает. Я уже перестал понимать что происходит. Изначально было больше осмысленности.
Резюмируя:
У мотора есть некоторые настройки по умолчанию - когда он объявляется в коде уже есть некоторые значения для скорости, для типа движения и т.д.
Если их поменять, например скорость для постоянного движения, то изменение будет сохранено до тех пор, пока не будет другого изменения.
Это касается в данном примере типа движения KEEP_SPEED и выставленной максимальной скорости maxspd/2.
Оставить так можно - ошибки не будет. Вопрос зачем ?

И еще подумал про вчерашний код
В конце идет перемещение используя worksteps , диапазон получился 2*worksteps.
worksteps= (dist*roundstps)/shkiv;
Но при этом теоретически может оказаться ситуация, что worksteps будет больше половины всей дистанции. Тогда он будет тупо лупить по концевиками.
Значит дополнительно надо вычислить максимально возможное значение worksteps и если вычисленное по формуле будет превышать максимальное, то взять именно максимально. Тут очень удобна функция min() которая вернет минимальное значение из 2-х.
 
Изменено:
  • Лойс +1
Реакции: DAER

DAER

✩✩✩✩✩✩✩
17 Дек 2021
21
0
...Я уже перестал понимать что происходит. Изначально было больше осмысленности.
Есть готовый скетч, и он работает. Вот прямо сейчас :) Но есть некоторые для меня непонятные вопросы. Можно на них и забить (ведь работает же), но в этот раз мне хочется понять в этих строчках абсолютно всё! Особенно, еслим учесть, что строчек-то немного. Так что спасибо за помощь :)

В конце идет перемещение используя worksteps , диапазон получился 2*worksteps.
worksteps= (dist*roundstps)/shkiv;
Но при этом теоретически может оказаться ситуация, что worksteps будет больше половины всей дистанции.
Нет. Сейчас у меня между концевиками 75 мм. Рабочий ход - 40 мм ( 40 вперёд, остановка, 40 назад). (тут немного убого сделано, лучше, видимо абсолютная дистанция). roundstps нужен, чтобы удобно было менять деление шага.

А общее резюме - удивительно насколько не совпадает мозг (логика) новичка с тем, что как написано в учебниках, уроках и пр.

ЗЫ: это неудивительно. Возьмите школьный курс иностранного. Учебники, методички, всё утверждено... Столько лет, а что в итоге?

кстати, вот он. Я добавил таймер 10 минут работы 10 минут отдых. Но мне не нравится, что я в каждом IF пишу F_TIME==1
Я понимаю, что IF срабатывает один раз, но из-за того что всё это хозяйство помещено в loop я постоянно путаюсь.


C++:
#include <GyverStepper.h>

//****НАСТРАИВАЕМ РАБОТУ
int dist = 40; //рабочий ход мм
int cycles = 15; //количество циклов в минуту
int center = 35; //расстояние от концевика до центра мм
uint32_t timer_run = 10; //время работы мин.
uint32_t timer_pause = 10; //время паузы мин.


long stp = 64; //деление шага
int shkiv = 32; //мм за один оборот мотора


//*****ВЫЧИСЛЕНИЯ
long roundstps = stp*200; //чилсо шагов на оборот в полном шаге
long worksteps= (dist*roundstps)/shkiv; //шагов в рабочем ходе в одну сторону
long centersteps=(center*roundstps)/shkiv; //шагов от концевика до центра
long spd; //скорость движение шаг/с
long maxspd =(dist*2*cycles*roundstps)/60/shkiv; //мкс скорость движение шаг/с
long accel =maxspd*2; //ускорение движение шаг/с*с
uint32_t timer_rum_millis = timer_run*60000;
uint32_t timer_pause_millis = timer_pause*60000;

GStepper< STEPPER2WIRE> stepper1(roundstps, 12, 10, 4);

//*****ФЛАГИ
volatile boolean F_KONC_A; //Флаг концевика А возле мотора
volatile boolean F_KONC_B; //флаг концевика В дальний
volatile boolean F_START; //логический флаг иници
volatile boolean F_TIME; //флаг таймера работы/паузы
uint32_t tmr; //переменная хранения времени

volatile uint32_t debounce;
void Initial_positionA() {   //ФУНКЦИЯ ОБРАБОТКИ ПРЕРЫВАНИЯ концевик A
  if (millis() - debounce >= 200 && digitalRead(2)) {
    debounce = millis();
    F_KONC_A = 1;
    F_START = 1;
    }
}
void Initial_positionB() {   //ФУНКЦИЯ ОБРАБОТКИ ПРЕРЫВАНИЯ концевик B
  if (millis() - debounce >= 200 && digitalRead(3)) {
    debounce = millis();
    F_KONC_B = 1;
    }
}
//****SETUP***************

void setup() {
F_TIME=1;
F_KONC_A=0;
F_KONC_B=0;
F_START=0;

pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
digitalWrite(2, LOW);
digitalWrite(3, LOW);
attachInterrupt(0, Initial_positionA, RISING); //ОБЪЯВЛЕНИЕ ПРЕРЫВАНИЯ А
attachInterrupt(1, Initial_positionB, RISING); //ОБЪЯВЛЕНИЕ ПРЕРЫВАНИЯ B


stepper1.setRunMode(FOLLOW_POS);
stepper1.setMaxSpeed(maxspd);
stepper1.setAcceleration(accel);


Serial.begin(9600);
Serial.println("Hello World!"); // отправить
Serial.println(worksteps);        // дистанция в шагах
Serial.println(maxspd);       // скорость
Serial.println(accel); // ускорение
Serial.println(roundstps); //шагов в одном обороте
Serial.println(centersteps); //шагов до центра

}

void loop() {

if (millis() - tmr >= (F_TIME ? timer_rum_millis : timer_pause_millis)) {
    tmr = millis();
    F_TIME = !F_TIME;
}

if (!stepper1.tick() && F_START==0 && F_TIME==1 ){//Если флаг СТАРТ поднят
   stepper1.setMaxSpeed(maxspd/2);
   stepper1.setTarget(centersteps*2, RELATIVE);//Едем ДАЛЕКОоо вперёд. Костыль такой.
      }
static bool dir = true;
    if (!stepper1.tick()&& F_TIME==1) {  //Начинаем работать вперёд-назад
      stepper1.setMaxSpeed(maxspd);
        stepper1.setTarget(dir ? worksteps : -worksteps, RELATIVE);
        dir = !dir;
    }
    if (F_KONC_A ==1 && F_TIME==1){ //если флаг А поднят
        stepper1.brake(); //РЕЗКО тормозим, чтобы не сломать концевик
        stepper1.setMaxSpeed(maxspd/2);
        stepper1.setTarget(-centersteps-(worksteps/3), RELATIVE); //Едем в центр
        F_KONC_A = 0; //Флаг А снова готов к труду и обороне
     
    }
     if (F_KONC_B ==1 && F_TIME==1){ //если флаг В поднят
        stepper1.brake(); //опять же тормозим резко
        stepper1.setMaxSpeed(maxspd/2);
        stepper1.setTarget(centersteps-(worksteps/2), RELATIVE); //Тут едем в центр но немного ближе, т.к. следующий шаг туда же
        F_KONC_B = 0;//Опускаем флаг В
       
    }
}
 

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

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
А не надо так писать.
C++:
void loop() {
  // тут все хорошо!
  if (millis() - tmr >= (F_TIME ? timer_rum_millis : timer_pause_millis)) {
    tmr = millis();
    F_TIME = !F_TIME;
  }


  // если работаем то делаем все, что внутри:
  if (F_TIME == 1) {
    if (!stepper1.tick()) {  //Начинаем работать вперёд-назад
      stepper1.setMaxSpeed(maxspd);
      stepper1.setTarget(dir ? worksteps : -worksteps, RELATIVE);
      dir = !dir;
    }


    ...
  }
}
Там где ... дописать остальные проверки. Только понимаю, что условие F_TIME == 1 уже выполнено.
 
  • Лойс +1
Реакции: DAER

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Использую gyverstepper Почему то если просто в loop засунуть обновление скорости мотора оно не работает
C++:
ISR(TIMER2_A) { //прерывание по таймеру 2А
MainSt.tick(); //тикаем
}

void loop() {
bus.poll(modbus_array,1);       //Used to receive or write value from Master
if (modbus_array[0] ==0) {
                              MainSt.brake();
                              } else {
                                      MainSt.setSpeed(modbus_array[0]); //обновляем скорость
                                      }
}
А вот если обновлять скорость с задержкой 100 мс например, мотор все отрабатывает.
но для меня задержка в 100 мс критична, что не так с обновлением скорости сразу после принятия по rs485?

C++:
ISR(TIMER2_A) { //прерывание по таймеру 2А
MainSt.tick(); //тикаем
}

void loop() {
bus.poll(modbus_array,1);       //Used to receive or write value from Master
if(millis() - LEDTimer > 100) {
LEDTimer = millis();
if (modbus_array[0] ==0) {
                              MainSt.brake();
                              } else {
                                      MainSt.setSpeed(modbus_array[0]); //обновляем скорость
                                      }
}}
 

poty

★★★★★★✩
19 Фев 2020
3,117
919
Очевидно, скорость меняете чаще, чем срабатывает прерывание. Внутри loop нужно проверять, изменилось ли что-нибудь с момента последнего приёма и изменять скорость только тогда, когда изменилось.
Единица в bus.poll - правильна? Принимается 1 байт?
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
она точно не меняется чаще. пид выдает новую скорость не чаще чем 400 мс.
 

poty

★★★★★★✩
19 Фев 2020
3,117
919
Так Вы проверьте, сколько раз выполняется цикл за одну секунду. Тогда будет всё понятно.
 

student99

✩✩✩✩✩✩✩
31 Авг 2022
3
0
Всем доброго здравия! Не могу разобраться с библиотекой управления шаговым двигателем. Библиотека
GyverStepper. С Ардуинкой это моё первое знакомство. Задача вроде бы простая, при нажатии кнопки провернуть вал мотора на оборот при отпускании повернуть вал в исходное состояние. Мотор Нема 34 драйвер Степ-Дир. Спасибо всем откликнувшимся.
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
Думаю Вам лучше начать с изучения уроков по программированию
Как минимум почитать описание библиотеки для управления шаговым мотором
Ну и библиотека для подключения кнопки
 

student99

✩✩✩✩✩✩✩
31 Авг 2022
3
0
Спасибо, читал и читаю всё это. Но вот с шаговиком "завис".
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@student99, В чём именно проблема?
На этапе инициализации?
У вас хоть получилось сделать хоть какое то количество шагов?

Хоть код кинте, на котором Вы зависли.
 

student99

✩✩✩✩✩✩✩
31 Авг 2022
3
0
Оформи код соответствующим тэгом
#include "GyverStepper2.h"
GStepper2< STEPPER2WIRE> stepper(400, 2, 5);
const int buttonPin = 3;


void setup()
{
stepper.setMaxSpeed(1200);
stepper.setAcceleration(1000);
pinMode (buttonPin, INPUT_PULLUP);
}

void loop() {

if (!digitalRead(buttonPin))
{
stepper. setSpeed (400);
stepper.tick();
}

}

Сейчас, по нажатию кнопки мотор крутится, но не пойму как сделать, что-бы крутил на определённые шаги.
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
И библиотеки есть примеры, там есть метод SetTarget. Не поленитесь посмотреть примеры,
Логика работы

  • setTarget()/setTargetDeg() отправляет мотор на указанную позицию
  • Движение происходит в tick(), который нужно опрашивать постоянно. Либо в tickManual, который нужно вызывать с периодом, полученным из getPeriod() и пересчитывать на каждом шаге
  • tick() вернёт true, если мотор крутится
  • ready() однократно вернёт true, если мотор доехал до цели и остановился
  • Во время движения к цели можно вызвать pause(), тогда мотор доедет до точки и остановится, ready() не вернёт true
  • Во время движения к цели можно вызвать stop(), тогда мотор затормозит с заданным ускорением, ready() не вернёт true
  • Во время движения к цели можно вызвать brake(), тогда мотор остановится, ready() не вернёт true
  • После остановки можно вызвать resume(), мотор продолжит движение к цели
  • Постоянное вращение задаётся setSpeed()/setSpeedDeg(). Остановиться можно резко - stop() или brake()
  • Скорость и ускорение можно задать в любое время, но применяются они после остановки мотора!

Немного неправильно организована программа
У тебя должен тик постоянно в лупе крутится,
При нажатии кнопки должно быть вращение, а при отпускании кнопки должен быть stop

По факту setspeed надо один раз только вызвать... Твой код работает, потомучто ты неправильно сделал, если тик выдергнуть из условия, то при нажатии на кнопку мотор поедет и уже не остановыится.
Ну и было бы правильно только один раз вызывать setspeed, используй библиотеку с кнопками
Подключи кнопку и обрабатывай события. Если кнопка была нажата, то включаем мотор, если кнопку отпустили - стопим.
Начни с этого.
 
Изменено:
  • Лойс +1
Реакции: student99

vovaself

✩✩✩✩✩✩✩
24 Июл 2019
6
0
Добрый день


Я уже полтора года работаю на библиотеке GyverStepper версия 1.4. и успешно
Попытался сделать upgrade на последнюю версию. Полный балаган при том же скетче Ардуино
Что не так ?

Когда сделал обновление на последнюю версию, при том же самом скетче ШД начинает крутиться в противоположную сторону, рывками и нестабильно или почти не крутится хотя есть звук что он пытается что-то делать.
Пришлось вернуться к версии 1.4
 

Epszit

✩✩✩✩✩✩✩
17 Май 2023
3
0
Доброго времени суток, есть задача суть которой заключается в сравнении виртуальных шагов шагового двигателя(nema14 например) и реальных получая их с энкодера, чтобы достаточно точно выявлять нагрузку на вал и определять пропуски шагов. Я управляю шаговым двигателем при помощи библиотеки GyverStepper, как раз при помощи нее я и могу получить абсолютную виртуальную позицию (в шагах) с помощью метода stepper.pos() , также я использую энкодер as 5600 с разрешением 12 байт. В классе as56 я получаю инкрементную позицию энкодера по i2c (вызывая метод readTwoBytes(_raw_ang_hi)) и в этом же классе преобразую инкрементную позицию энкодера в абсолютную). Ну и в функции serial_print я вывожу в два столбца эту самую посчитанную абсолютную позицию с энкодера и виртуальную позицию с гивера. Скоростью и положением шаговика я управляю в функции loop, значение скорости с последовательного порта передается в переменную val, далее если она не равна нулю то шаговик начинает ехать при этом абсолютные позиции с энкодера и с библиотеки сбрасываются в ноль.
Теперь к сути проблемы, если при работе этой библиотеки использовать i2c, то программа начинает глючить, эта тема обсуждалась в комментариях этой библиотеки (https://alexgyver.ru/gyverstepper/ третий коммент) на что Алекс посоветовал вызывать метод stepper.tick() в прерывании таймера (это метод который дает команду шаговику (шагать), что я и сделал (строка 130). Но после вывода в порт нескольких значении(обычно это от 600 до 2000) всё зависает, данные в порт перестают отправляться, на команду полной остановки он не реагирует и так далее.
Буду очень благодарен если кто то поможет разобраться с этой проблемой, если позицию с энкодера не считывать, то все работает нормально. Пробовал считывать позицию с аналогового пина не используя i2c, но там слишком большие помехи, даже если подтянуть к земле через 10кОм. Возможно есть уже готовое решение этой задачи, или идеи как реализовать ее иначе (если смотреть нагрузку по потребляемому току, то из за стартового скачка потребления первые несколько значении нагрузки получаются не корректные). Код в стадии написания, так что есть не используемые переменные итд. Спасибо.
encoder+gyver:
#include "AS5600.h"
#include "Wire.h"
#include "GyverStepper2.h"
GStepper2<STEPPER2WIRE> stepper(3200, 4, 0, 2);

AS5600 as5600;   //  use default Wire

bool i2c_print = true;
bool is_Running = false;
static uint32_t lastTime = 0;
char sym;
int32_t val;
int32_t i2c_pos;
int32_t stepp_pos = 0;
int32_t final_pos;
int32_t prev_stepp_pos = 0;
int8_t d = 1;

//Настраиваем адреса и регистры для чтения данных с энкодера по I2C
// Взято отсюда https://russianblogs.com/article/31803346353/
int _ang_hi = 0x0E; // ANGLE
int _ang_lo = 0x0F;
int _raw_ang_hi = 0x0C; //RAW ANGLE
int _raw_ang_lo = 0x0D;
int _ams5600_Address = 0x36;

bool callibration_performance = true;
bool callibration_bool = false;
int32_t value_cal[4096];

hw_timer_t *My_timer = NULL; //для прерываний

class AS56{ //класс в котором происходит чтение данных по i2c с энкодера и преобразуется в абсолютное значение

  public:
    int AS56_adress = 0;
    int counter_sym = 0;
    int abs_pos = 0;  //
    int prev_retVal = 0; //Предыдущий азимут энкодера
    int zero_pos = 0;
    int retVal = 0; //Текущий азимут энкодера
    bool is_Reversed = false;

  public:




    AS56(int AS56_adress){
      this -> AS56_adress = AS56_adress;
    }


    void reset_Abs_pos(){
      int a = this -> readTwoBytes(_raw_ang_hi);
      this -> abs_pos = 0;
      this -> prev_retVal = 0;
      this -> zero_pos = a;
      this -> counter_sym = 0;
    }

    void revolutions( int coner){
      if ((coner - this -> prev_retVal) > 1000 && is_Running ){
        this -> counter_sym --;}
      if ((coner - this -> prev_retVal) < -1000 && is_Running ){
        this -> counter_sym ++;
        }


       
        this -> prev_retVal = coner;
    }

     
   
    int32_t abs_Pos(){
      int a = this -> readTwoBytes(_raw_ang_hi)- this-> zero_pos;
     
      this -> revolutions(a);
     
      uint32_t d =  this -> counter_sym*4096 + a;
      this ->  abs_pos = d;
   
 

      return (d);
    }
   
    int readOneByte(int adress, int val) // Чтение одного байта по I2C
    {
      int retVal = -1;
      Wire.beginTransmission (_ams5600_Address); // начало передачи
      Wire.write (adress); // адрес, который вы должны прочитать
      Wire.endTransmission();
      Wire.requestFrom (_ams5600_Address, 1); // Получить данные из 5600
      while(!Wire.available ());
      retVal = Wire.read (); // чтение данных
      Serial.print("retVal ");
      Serial.println(retVal);
      this->retVal = retVal;
      return retVal;
    }

   word readTwoBytes(int adress){ // Чтение двух байтов по I2C
     int retVal = -1;
     Wire.beginTransmission (_ams5600_Address); // начало передачи
     Wire.write (adress); // адрес, который вы должны прочитать
     Wire.endTransmission();
     Wire.requestFrom (_ams5600_Address, 2); // Получить данные из 5600
     while(!Wire.available ()); // ожидание автобусной остановки I2C (заканчивается передачей)
     word high = Wire.read();
     high = high << 8;
     int low = Wire.read();    // принять байт как символ
     retVal = high | low ; // чтение данных
     if (!is_Reversed){
       retVal = 4095 - retVal;
     }
     return retVal;
  }

   
  void reverse_Dir(bool i)
  {
    this->is_Reversed = !i;
  }
};

AS56 encod = AS56(783);

void IRAM_ATTR onTimer(){
  if (i2c_print == true) {
    is_Running = stepper.tick();
  }

}

void setup() {
  Serial.begin(57600);
  Serial.setTimeout(20);

  My_timer = timerBegin(0, 80, true); //для прерываний
  timerAttachInterrupt(My_timer, &onTimer, true);
  timerAlarmWrite(My_timer, 100, true);
  timerAlarmEnable(My_timer); //Just Enable

  Wire.begin();//для энкодера
  Serial.println([B]FILE[/B]);
  Serial.print("AS5600_LIB_VERSION: ");
  Serial.println(AS5600_LIB_VERSION);
  as5600.begin(4);  //  set direction pin.
  as5600.setDirection(AS5600_CLOCK_WISE);  // default, just be explicit.
  Serial.println(as5600.getAddress());
  int b = as5600.isConnected();
  Serial.print("Connect: ");
  Serial.println(b);

  stepper.autoPower(true); //сетап для Gyvera
  stepper.setAcceleration(1000);

}

  void serial_print(){

    lastTime = millis();
    i2c_pos =  encod.abs_Pos()*(0.78123);     //RawAngle //as5600.getCumulativePosition(); readOneByte(_raw_ang_hi);
    stepp_pos = -stepper.pos;

    Serial.print(stepp_pos); //виртуальная позиция гГивера
    Serial.println("\t");
    Serial.print(i2c_pos); //позиция энкодера
    Serial.print("\t");

   
  }

void loop() {  
    if (Serial.available() > 0) {
      sym = Serial.read();  
      if (sym == 's') {
        String ch = Serial.readString();
        String n = ch.substring(1);
        val = n.toInt();
        if(val > 0) d = 1;
        else if (val < 0) d = -1;
        if (val ==0) {
е          stepper.stop();
        }else{
          encod.reset_Abs_pos();
          stepper.reset();
          stepper.setAcceleration(500);
          stepper.setTarget(3200*d);
//          if (callibration_performance == true) { //
//            stepper.setMaxSpeed(100);
//            stepper.setTarget(-9999999);
//          }
        }  
      }
    }
  stepp_pos = stepper.pos;

  if (val > 1000){
    if (millis() - lastTime >= 4 && is_Running) serial_print();
  }
  else{
    if (prev_stepp_pos != stepp_pos && is_Running) serial_print();
  }
   

}
1684313773555.png