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

student99

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

DAK

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

student99

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

DAK

★★★✩✩✩✩
8 Окт 2020
517
138
@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
138
И библиотеки есть примеры, там есть метод 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
 

rastaman29

★✩✩✩✩✩✩
15 Ноя 2019
163
28
Может кто подскажет, мне просто надо крутить по первой кнопке в одну сторону, по второй в другую? Я вообще плохо разбираюсь. Вот такой код написал, не работает. Что не так? Плата 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();
}
 
Изменено:

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
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
574
Для более эффективной работы в прерывании лучше использовать gyverstepper2, об этом в той же статье написано
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
574
Если нормально написать опрос энкодера без while - прерывания для мотора будут не нужны. Почему энкодер ломается из за прерываний мотора - вопрос, возможно где то не хватает volatile или опять же запрета прерываний
 
  • Лойс +1
Реакции: Epszit

j0ker

✩✩✩✩✩✩✩
31 Май 2023
3
0
Есть CNC Shield v3, DRV8825, NEMA17. Пытаюсь крутить моторчик с помощью библиотеки GyverStepper. Но крутится только в одну сторону, менял setSpeed(-2000), вставлял reverse() - ничего не помогает. Почему так?

C++:
#include <GyverStepper.h>

GStepper<STEPPER4WIRE> stepper(200, 2, 5);

void setup() {
  pinMode( 8 ,OUTPUT);          // ВАЖНО !!!!!
  digitalWrite(8, LOW);         // иначе не будет работать

  stepper.setMaxSpeed(5000);
  stepper.setRunMode(KEEP_SPEED);
  stepper.setSpeed(2000);
}

void loop() {
    stepper.tick();
}
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
660
156
Сигналы/питание-"земля" доходят до драйвера? Может какая дорожка в обрыве. А, может быть и такое, как было на моей плате, были закорочены дорожки. По питанию моторов, при первом включении выгорел предохранитель и какие-то, уже не помню, к одному из четырех драйверов сигнальные. Пришлось резать одну и воспользоваться МГТФом.
 

j0ker

✩✩✩✩✩✩✩
31 Май 2023
3
0
Написал простенький скетч, без использования библиотеки GyverStepper - всё работает, крутится туда-сюда.
Непонятно.
Может у кого есть работающий скетч для CNC Shield v3 с GyverStepper, а то библиотека хорошая и удобная.

C++:
const int StepX = 2;
const int DirX = 5;

void setup() {
  pinMode(StepX,OUTPUT);
  pinMode(DirX,OUTPUT);
 
  pinMode( 8 ,OUTPUT);
  digitalWrite(8, LOW);
 
}
 
void loop() {
 digitalWrite(DirX, HIGH); // set direction, HIGH for clockwise, LOW for anticlockwise
 
 for(int x = 0; x < 200; x++) { // loop for 200 steps
  digitalWrite(StepX,HIGH);
  delayMicroseconds(500);
  digitalWrite(StepX,LOW);
  delayMicroseconds(500);
 }
delay(1000); // delay for 1 second
    
 digitalWrite(DirX, LOW); // set direction, HIGH for clockwise, LOW for anticlockwise

    for(int x = 0; x < 200; x++) { // loop for 200 steps
  digitalWrite(StepX,HIGH);
  delayMicroseconds(500);
  digitalWrite(StepX,LOW);
  delayMicroseconds(500);
 }
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,703
474
@j0ker, драйвер 8825 условно 2-х проводной. Следовательно, вместо
GStepper<STEPPER4WIRE> stepper(200, 2, 5);
нужно указать
GStepper<STEPPER2WIRE> stepper(200, 2, 5);
И будет вам счастье.;)
Читайте внимательно описание вот здесь , раздел "Документация GStepper" - Инициализация.
 
  • Лойс +1
Реакции: j0ker

j0ker

✩✩✩✩✩✩✩
31 Май 2023
3
0
И правда, как я раньше не заметил. Большое спасибо. Теперь всё работает.
 

Vitaliy_K

✩✩✩✩✩✩✩
31 Мар 2022
3
0
Здравствуйте. GStepper2 <STEPPER4WIRE> stepper (2048, 5, 3, 4, 2); 5, 3, 4, 2 – данные порты берутся с Ардуино нано. Подключил модуль PCF8575. Мне нужно подключить порты с модуля PCF8575, а не с ардуино в GStepper2 <STEPPER4WIRE> stepper (2048, PCF8575.5, PCF8575.3, PCF8575.4, PCF8575.2) (пример); Как правильно это сделать, ПОДСКАЖИТЕ.
 

VAF

✩✩✩✩✩✩✩
15 Июл 2023
50
1
Москва
Помогите понять особенности мотора 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

Dima89

✩✩✩✩✩✩✩
27 Июл 2023
3
0
Подскажите как передать в конструктор класса объект GStepper?
Таким способом не получается ошибка:
Compilation error: no matching function for call to ‘GStepper2<(GS_driverType)0>::GStepper2()’

C++:
#include "GyverStepper2.h"

class My {
  public:
    My(GStepper2<STEPPER2WIRE> stepper ){
      _stepper =  stepper;
    }
    private:
     GStepper2<STEPPER2WIRE> _stepper;
  };
 

vortigont

★★★★★★✩
24 Апр 2020
1,021
542
Saint-Petersburg, Russia
Подскажите как передать в конструктор класса объект GStepper?
эта фраза не имеет смысла. Попробуйте еще раз.

в простейшем случае как-то так:

C++:
#include "GyverStepper2.h"

template <GS_driverType D>
class My : public GStepper2<D> {
  public:
    My(uint16_t steps) : GStepper2<D>(steps) {
      //do something
    }
    private:
     //GStepper2<STEPPER2WIRE> _stepper; это не надо
};
 

KovAlex

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

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