Производительная библиотека для управления шаговыми моторами с Arduino
- Поддержка 4х пинового (шаг и полушаг) и STEP-DIR драйверов
 - Автоматическое отключение питания при достижении цели
 - Режимы работы:
- Вращение с заданной скоростью. Плавный разгон и торможение с ускорением
 - Следование к позиции с ускорением и ограничением скорости
 - Следование к позиции с заданной скоростью (без ускорения)
 
 - Быстрый алгоритм управления шагами
 - Поддержка "виртуальных" драйверов
 - Встроенный многоосевой планировщик траекторий
 
Совместима со всеми Arduino платформами (используются Arduino-функции)
К библиотеке есть расширенная документация
- Установка
 - StepperCore
 - GyverStepper
 - GyverStepper2
 - GyverPlanner
 - GyverPlanner2
 - Версии
 - Баги и обратная связь
 
Библиотека содержит набор инструментов для разных сценариев работы с шаговыми моторами
- StepperCore.h [класс Stepper]: ядро всех остальных классов, умеет быстро щёлкать пинами (AVR) и делать один шаг для настроенного типа драйвера. Поддерживает 4 фазы шаг/полушаг, а также step-dir драйверы.
 - GyverStepper.h [класс GStepper]: основная тяжёлая библиотека, много настроек. Движение одного мотора с ускорением к заданной позиции или вращение с заданной скоростью. Не очень оптимальная работа в прерывании таймера.
 - GyverStepper2.h [класс GStepper2]: новая облегченная версия GyverStepper, практически полностью с ней совместима. Более оптимальный целочисленный гибридный алгоритм движения с ускорением, лёгкий вес. Оптимизировано для работы в прерывании таймера.
 - GyverPlanner.h [класс GPlanner]: многоосевой планировщик траектории, движение с ускорением (2 порядок). Остановка в каждой точке. Оптимальная работа в прерывании таймера.
 - GyverPlanner2.h [класс GPlanner2]: многоосевой планировщик траектории, движение с ускорением (2 порядок). Планирование скорости на маршруте, оптимальное движение по точкам. Оптимальная работа в прерывании таймера.
 
- Библиотеку можно найти по названию GyverStepper и установить через менеджер библиотек в:
- Arduino IDE
 - Arduino IDE v2
 - PlatformIO
 
 - Скачать библиотеку .zip архивом для ручной установки:
- Распаковать и положить в C:\Program Files (x86)\Arduino\libraries (Windows x64)
 - Распаковать и положить в C:\Program Files\Arduino\libraries (Windows x32)
 - Распаковать и положить в Документы/Arduino/libraries/
 - (Arduino IDE) автоматическая установка из .zip: Скетч/Подключить библиотеку/Добавить .ZIP библиотеку… и указать скачанный архив
 
 - Читай более подробную инструкцию по установке библиотек здесь
 
- Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи
 - Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить"
 - Вручную: удалить папку со старой версией, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам!
 
Ядро библиотеки для управления шаговыми моторами:
- 4 фазные и STEP DIR драйверы
 - Поддержка пина EN
 - Виртуальный драйвер
 - Быстрый алгоритм IO для AVR
 
РАЗВЕРНУТЬ
Stepper<STEPPER2WIRE> stepper(step, dir);						// драйвер step-dir
Stepper<STEPPER2WIRE> stepper(step, dir, en);					// драйвер step-dir + пин enable
Stepper<STEPPER4WIRE> stepper(pin1, pin2, pin3, pin4);			// драйвер 4 пин
Stepper<STEPPER4WIRE> stepper(pin1, pin2, pin3, pin4, en);		// драйвер 4 пин + enable
Stepper<STEPPER4WIRE_HALF> stepper(pin1, pin2, pin3, pin4);		// драйвер 4 пин полушаг
Stepper<STEPPER4WIRE_HALF> stepper(pin1, pin2, pin3, pin4, en);	// драйвер 4 пин полушаг + enable
Stepper<STEPPER2WIRE, STEPPER_VIRTUAL> stepper;					// виртуальный драйвер step-dir
Stepper<STEPPER4WIRE, STEPPER_VIRTUAL> stepper;					// виртуальный драйвер 4 пинvoid step();                                // сделать шаг
void invertEn(bool val);                    // инвертировать поведение EN пина
void reverse(bool val);                     // инвертировать направление мотора
void disable();                             // отключить питание и EN
void enable();                              // включить питание и EN
void power(bool);                           // переключить питание
void attachStep(void (*handler)(uint8_t));  // подключить обработчик шага
void attachPower(void (*handler)(bool));    // подключить обработчик питания
int32_t pos;                                // текущая позиция в шагах
int8_t dir;                                 // направление (1, -1)Остальные примеры смотри в examples!
#include <StepperCore.h>
Stepper<STEPPER2WIRE> stepper(2, 3);
void setup() {
  stepper.dir = 1;  // или -1
  stepper.pos = 0;  // доступ к позиции
}
void loop() {
  // крутим вручную
  stepper.step();   // сделать шаг
  delay(10);
}- GStepper2 гораздо легче и сильнее оптимизирована
 - GStepper2 больше предназначена для движения по точкам траектории, но "следящий" режим в ней также работает
 - GStepper2 оптимизирована для работы в прерывании таймера
 - GStepper2 использует плавный алгоритм движения мотора по умолчанию
 - GStepper2 скорее всего будет чуть больше нагружать микроконтроллер во время работы, чем GStepper. Но гораздо меньше, чем GStepper в режиме SMOOTH_ALGORITHM
 
- Быстрый алгоритм (по умолчанию): в библиотеке заведено два таймера: таймер шагов (разный период) и таймер планировщика (10-30 миллисекунд). По таймеру планировщика производится перерасчёт траектории и вычисляется направление движения и текущая необходимая скорость. Из этой скорости получается новый период для таймера шагов.
 - Плавный алгоритм (настройка SMOOTH_ALGORITHM): работает один таймер шагов, на каждом шаге производится перерасчёт скорости движения и времени до следующего шага.
 
- Плавный профиль (по умолчанию): здесь используется алгоритм плавного движения SMOOTH_ALGORITHM как в GStepper, но оптимизирован и ускорен в 2-3 раза. Все тяжёлые вычисления траектории производятся при задании новой целевой позиции в setTarget. Далее по таймеру шагов мотор шагает и быстро вычисляет новое время следующего шага. Это позволяет тратить минимум времени в прерывании таймера, если оно используется.
 - Быстрый профиль (настройка GS_FAST_PROFILE): всё то же самое, но в таймере шагов происходит не вычисление, а выбор периода из заранее посчитанной таблицы, что позволяет двигаться с ускорением вплоть до скоростей 30000 шагов в секунду.
 
Библиотека для управления шаговыми моторами с Arduino
- Поддержка 4х пинового (шаг и полушаг) и STEP-DIR драйверов
 - Автоматическое отключение питания при достижении цели
 - Режимы работы:
- Вращение с заданной скоростью. Плавный разгон и торможение с ускорением
 - Следование к позиции с ускорением и ограничением скорости
 - Следование к позиции с заданной скоростью (без ускорения)
 
 
РАЗВЕРНУТЬ
// steps - шагов на один оборот вала (для расчётов с градусами)
// step, dir, pin1, pin2, pin3, pin4 - любые GPIO
// en - пин отключения драйвера, любой GPIO
GStepper<STEPPER2WIRE> stepper(steps, step, dir);                   // драйвер step-dir
GStepper<STEPPER2WIRE> stepper(steps, step, dir, en);               // драйвер step-dir + пин enable
GStepper<STEPPER4WIRE> stepper(steps, pin1, pin2, pin3, pin4);      // драйвер 4 пин
GStepper<STEPPER4WIRE> stepper(steps, pin1, pin2, pin3, pin4, en);  // драйвер 4 пин + enable
GStepper<STEPPER4WIRE_HALF> stepper(steps, pin1, pin2, pin3, pin4);     // драйвер 4 пин полушаг
GStepper<STEPPER4WIRE_HALF> stepper(steps, pin1, pin2, pin3, pin4, en); // драйвер 4 пин полушаг + enable
GStepper<STEPPER4WIRE, STEPPER_VIRTUAL> stepper(2048);                  // виртуальный драйвер, указать только количество шагов// Примечание: далее по тексту под "по умолчанию" имеется в виду "даже если не вызывать функцию"
// Здесь происходит движение мотора, вызывать как можно чаще!
// Имеет встроенный таймер
// Возвращает true, если мотор движется к цели или крутится по KEEP_SPEED
bool tick();
// Возвращает то же самое, что tick, т.е. крутится мотор или нет
bool getState();
// Инвертировать направление мотора - true (по умолч. false)
void reverse(bool dir);
// инвертировать поведение EN пина - true (по умолч. false)
void invertEn(bool rev);
// Установка режима работы, mode:
// FOLLOW_POS - следование к позиции setTarget(...)
// KEEP_SPEED - удержание скорости setSpeed(...)
void setRunMode(GS_runMode mode);
// Установка текущей позиции мотора в шагах и градусах
void setCurrent(long pos);
void setCurrentDeg(float pos);
// Чтение текущей позиции мотора в шагах и градусах
long getCurrent();
float getCurrentDeg();
// установка целевой позиции в шагах и градусах (для режима FOLLOW_POS)
// type - ABSOLUTE или RELATIVE, по умолчанию стоит ABSOLUTE
void setTarget(long pos);
void setTarget(long pos, GS_posType type);
void setTargetDeg(float pos);
void setTargetDeg(float pos, GS_posType type);
// Получение целевой позиции в шагах и градусах
long getTarget();
float getTargetDeg();
// Установка максимальной скорости (по модулю) в шагах/секунду и градусах/секунду (для режима FOLLOW_POS)
// по умолч. 300
void setMaxSpeed(float speed);
void setMaxSpeedDeg(float speed);
// Установка ускорения в шагах и градусах в секунду (для режима FOLLOW_POS).
// При значении 0 ускорение отключается и мотор работает
// по профилю постоянной максимальной скорости setMaxSpeed().
// По умолч. 300
void setAcceleration(int accel);
void setAccelerationDeg(float accel);
// Автоотключение EN при достижении позиции - true (по умолч. false)
void autoPower(bool mode);
// Плавная остановка с заданным ускорением
void stop();
// Жёсткая остановка
void brake();
// Жёсткая остановка + сброс позиции в 0 (для концевиков)
void reset();
// Установка целевой скорости в шагах/секунду и градусах/секунду (для режима KEEP_SPEED)
void setSpeed(float speed);
void setSpeedDeg(float speed);
// Получение целевой скорости в шагах/секунду и градусах/секунду (для режима KEEP_SPEED)
float getSpeed();
float getSpeedDeg();
// Включить мотор (пин EN)
void enable();
// Выключить мотор (пин EN)
void disable();
// Возвращает минимальный период тика мотора в микросекундах при настроенной setMaxSpeed() скорости.
// Можно использовать для настройки прерываний таймера, в обработчике которого будет лежать tick() (см. пример timerISR)
uint16_t getMinPeriod();
// Текущий период "тика" для отладки и всего такого
uint16_t stepTime;
// подключить внешний обработчик для шага и переключения питания
void attachStep(handler)
void attachPower(handler)Остальные примеры смотри в examples!
#include <GyverStepper.h>
GStepper<STEPPER4WIRE> stepper(2048, 5, 3, 4, 2);
void setup() {
  Serial.begin(115200);
  // режим поддержания скорости
  stepper.setRunMode(KEEP_SPEED);
  // можно установить скорость
  stepper.setSpeed(120);    // в шагах/сек
  stepper.setSpeedDeg(80);  // в градусах/сек
  // режим следования к целевй позиции
  stepper.setRunMode(FOLLOW_POS);
  // можно установить позицию
  stepper.setTarget(-2024);    // в шагах
  stepper.setTargetDeg(-360);  // в градусах
  // установка макс. скорости в градусах/сек
  stepper.setMaxSpeedDeg(400);
  // установка макс. скорости в шагах/сек
  stepper.setMaxSpeed(400);
  // установка ускорения в градусах/сек/сек
  stepper.setAccelerationDeg(300);
  // установка ускорения в шагах/сек/сек
  stepper.setAcceleration(300);
  // отключать мотор при достижении цели
  stepper.autoPower(true);
  // включить мотор (если указан пин en)
  stepper.enable();
}
void loop() {
  // просто крутим туды-сюды
  if (!stepper.tick()) {
    static bool dir;
    dir = !dir;
    stepper.setTarget(dir ? -1024 : 1024);
  }
}Облегчённая GyverStepper
- Легче на несколько кБ, всё целочисленное
 - Повышенная точность позиционирования
 - Более эффективный гибридный алгоритм движения
 - Движение к цели с ускорением
 - Вращение со скоростью
 - Макс. скорость:
- Обычный режим: 37000 шаг/с на полной, 18000 шаг/с на разгоне
 - Быстрый профиль: 37000 шаг/с на полной, 37000 шаг/с на разгоне
 
 - Оптимизировано для работы по прерыванию таймера
 - Наследует StepperCore
 
- setTarget()/setTargetDeg() отправляет мотор на указанную позицию
 - Движение происходит в tick(), который нужно опрашивать постоянно. Либо в tickManual, который нужно вызывать с периодом, полученным из getPeriod() и пересчитывать на каждом шаге
 - tick() вернёт true, если мотор крутится
 - ready() однократно вернёт true, если мотор доехал до цели и остановился
 - Во время движения к цели можно вызвать pause(), тогда мотор доедет до точки и остановится, ready() не вернёт true
 - Во время движения к цели можно вызвать stop(), тогда мотор затормозит с заданным ускорением, ready() не вернёт true
 - Во время движения к цели можно вызвать brake(), тогда мотор остановится, ready() не вернёт true
 - После остановки можно вызвать resume(), мотор продолжит движение к цели
 - Постоянное вращение задаётся setSpeed()/setSpeedDeg(). Остановиться можно резко - stop() или brake()
 - Скорость и ускорение можно задать в любое время, но применяются они после остановки мотора!
 
РАЗВЕРНУТЬ
GStepper2<STEPPER2WIRE> stepper(шаговНаОборот, step, dir);                          // драйвер step-dir
GStepper2<STEPPER2WIRE> stepper(шаговНаОборот, step, dir, en);                      // драйвер step-dir + пин enable
GStepper2<STEPPER4WIRE> stepper(шаговНаОборот, pin1, pin2, pin3, pin4);             // драйвер 4 пин
GStepper2<STEPPER4WIRE> stepper(шаговНаОборот, pin1, pin2, pin3, pin4, en);         // драйвер 4 пин + enable
GStepper2<STEPPER4WIRE_HALF> stepper(шаговНаОборот, pin1, pin2, pin3, pin4);        // драйвер 4 пин полушаг
GStepper2<STEPPER4WIRE_HALF> stepper(шаговНаОборот, pin1, pin2, pin3, pin4, en);    // драйвер 4 пин полушаг + enable
GStepper2<STEPPER2WIRE, STEPPER_VIRTUAL> stepper;    // виртуальный драйвер step-dir
GStepper2<STEPPER4WIRE, STEPPER_VIRTUAL> stepper;    // виртуальный драйвер 4 пин// === наследуется из Stepper ====
void step();                                // сделать шаг
void invertEn(bool val);                    // инвертировать поведение EN пина
void reverse(bool val);                     // инвертировать направление мотора
void disable();                             // отключить питание и EN
void enable();                              // включить питание и EN
void attachStep(void (*handler)(uint8_t));  // подключить обработчик шага
void attachPower(void (*handler)(bool));    // подключить обработчик питания
int32_t pos;                                // текущая позиция в шагах
int8_t dir;                                 // направление (1, -1)
// ========= GStepper2 ==========
// тикер
bool tick();                                // тикер движения, вызывать часто. Вернёт true, если мотор движется
bool tickManual();                          // ручной тикер для вызова в прерывании таймера с периодом getPeriod(). Вернёт true, если мотор движется
bool ready();                               // однократно вернёт true, если мотор доехал до установленной позиции и остановился
// вращение
void setSpeed(int16_t speed);               // установить скорость в шагах/сек и запустить вращение
void setSpeed(float speed);                 // установить скорость в шагах/сек (float) и запустить вращение
// движение к цели
void setTarget(int32_t ntar, GS_posType type = ABSOLUTE);       // установить цель в шагах и опционально режим ABSOLUTE/RELATIVE
void setTargetDeg(int32_t ntar, GS_posType type = ABSOLUTE);    // установить цель в градусах и опционально режим ABSOLUTE/RELATIVE
int32_t getTarget();                                            // получить целевую позицию в шагах
void setAcceleration(uint16_t nA);          // установка ускорения в шаг/сек^2
void setMaxSpeed(int speed);                // установить скорость движения при следовании к позиции setTarget() в шагах/сек
void setMaxSpeed(float speed);              // установить скорость движения при следовании к позиции setTarget() в шагах/сек, float
void setMaxSpeedDeg(int speed);             // установить скорость движения при следовании к позиции в град/сек
void setMaxSpeedDeg(float speed);           // установить скорость движения при следовании к позиции в град/сек, float
void setCurrent(int32_t npos);              // установить текущую позицию
int32_t getCurrent();                       // получить текущую позицию
void reset();                               // сбросить текущую позицию в 0
// всякое
void autoPower(bool mode);                  // автоотключение мотора при достижении позиции - true (по умолч. false)
uint32_t getPeriod();                       // получить текущий период тиков
void brake();                               // резко остановить мотор
void pause();                               // пауза - доехать до заданной точки и ждать (ready() не вернёт true, пока ты на паузе)
void resume();                              // продолжить движение после остановки/паузы
uint8_t getStatus();                        // текущий статус: 0 - стоим, 1 - едем, 2 - едем к точке паузы, 3 - крутимся со скоростью, 4 - тормозим
// ===== ДЕФАЙНЫ НАСТРОЕК =====
// дефайнить перед подключением библиотеки
#define GS_NO_ACCEL                         // отключить модуль движения с ускорением (уменьшить вес кода)
#define GS_FAST_PROFILE размер_массива (например 10)
Включает быстрый планировщик скорости. Участок разгона/торможения разбивается 
на указанное количество отрезков (+8 байт SRAM на участок), на них скорость будет одинаковая. 
Это позволяет быстро вычислять скорость мотора и достигнуть 30000 шаг/с на участке разгона 
(в обычном режиме в два раза меньше).Остальные примеры смотри в examples!
// крутим туда сюда, тикаем в loop
#include "GyverStepper2.h"
GStepper2<STEPPER2WIRE> stepper(2048, 2, 3);
void setup() {
  Serial.begin(9600);
  //stepper.enable();
  stepper.setMaxSpeed(100);     // скорость движения к цели
  stepper.setAcceleration(200); // ускорение
  stepper.setTarget(300);       // цель
}
bool dir = 1;
void loop() {
  stepper.tick();   // мотор асинхронно крутится тут
  // если приехали
  if (stepper.ready()) {
    dir = !dir;   // разворачиваем
    stepper.setTarget(dir * 300); // едем в другую сторону
  }
  // асинхронный вывод в порт
  static uint32_t tmr;
  if (millis() - tmr >= 30) {
    tmr = millis();
    Serial.println(stepper.pos);
  }
}Многоосевой планировщик траекторий для шаговых моторов и создания станка с ЧПУ
- ОСТАНОВКА В КАЖДОЙ ТОЧКЕ. БУФЕР НА ОДНУ СЛЕДУЮЩУЮ ПОЗИЦИЮ
 - Макс. скорость:
- Обычный режим: 37000 шаг/с на полной, 14000 шаг/с на разгоне
 - Быстрый профиль: 37000 шаг/с на полной, 37000 шаг/с на разгоне
 
 - Трапецеидальный профиль скорости (планировщик 2-го порядка)
 - Настройка скорости и ускорения
 - Любое количество осей. Будут двигаться синхронно к заданным целям
 - Быстрая целочисленная модель планирования траектории и скорости
 - Режим постоянного вращения для одной оси (для движения к концевику например)
 - Тормоз/плавная остановка/пауза на траектории планировщика
 - Оптимизировано для работы по прерыванию таймера
 - Быстрый контроль пинов шаговика для Arduino AVR
 - Скорость и ускорение можно задать в любое время, но применяются они после остановки мотора!
 
Планировщик управляет любым количеством моторов, вращая их к указанной позиции. В данной версии остановка происходит в каждой точке траектории, после чего поднимается флаг ready() и ожидает установки следующей точки.
- Смотри симуляцию в Processing: папка Planner Simulation/Planner
 
РАЗВЕРНУТЬ
GPlanner<драйвер, количество осей> planner;void addStepper(uint8_t axis, Stepper &stp);    // подключить мотор класса Stepper на ось axis
// примечание: тип драйвера должен совпадать у планировщика и моторов
void setBacklash(uint8_t axis, uint16_t steps); // установить компенсацию люфта на ось axis в количестве шагов steps
void enable();                              // включить моторы 
void disable();                             // выключить моторы
void power(bool v);                         // переключить питание
// НАСТРОЙКИ
void setMaxSpeed(float nV);                 // установка максимальной скорости планировщика в шаг/сек
void setAcceleration(uint16_t nA);          // установка ускорения планировщика в шаг/сек^2
// ПЛАНИРОВЩИК
uint32_t getPeriod();                       // возвращает время в мкс до следующего вызова tick/tickManual
bool ready();                               // true - готов принять следующую точку маршрута
void pause();                               // пауза (доехать до заданной точки и ждать). ready() не вернёт true, пока ты на паузе
void stop();                                // остановить плавно (с заданным ускорением)
void brake();                               // резко остановить моторы из любого режима
void resume();                              // продолжить после остановки/паузы
void reset();                               // сбросить счётчики всех моторов в 0
void home();                                // отправить в 0 по всем осям
uint8_t getStatus();                        // текущий статус: 0 - стоим, 1 - едем, 2 - едем к точке паузы, 3 -крутимся со скоростью
// СКОРОСТЬ
void setSpeed(uint8_t axis, float speed);   // режим постоянного вращения для оси axis со скоростью speed шаг/сек (м.б. отрицателеьной)
// ПОЗИЦИЯ
void setCurrent(int16_t cur[]);             // установить текущее положение моторов
void setCurrent(int32_t cur[]);             // установить текущее положение моторов
int32_t getCurrent(int axis);               // получить текущую позицию по оси axis
// установить цель в шагах и начать движение. type - ABSOLUTE (по умолч.) или RELATIVE
// ABSOLUTE - конкретные координаты точки, куда двигаться
// RELATIVE - смещение относительно текущих положений моторов
// вернёт true, если цель установлена. false, если цель совпадает с текущей
bool setTarget(int32_t target[]);
bool setTarget(int16_t target[]);
bool setTarget(int32_t target[], type);
bool setTarget(int16_t target[], type);
int32_t getTarget(int axis);                // получить цель в шагах на оси axis
// ТИКЕР
// тикер, вызывать как можно чаще. Вернёт true, если мотор крутится
// здесь делаются шаги как для движения по точкам, так и для вращения по скорости
bool tick();
// ручной тикер для вызова в прерывании или где то ещё. Выполняется 20..50 us
bool tickManual();
// ======= ДЕФАЙНЫ НАСТРОЕК =======
// объявлять перед подключением библиотеки
#define GS_FAST_PROFILE размер_массива (например 10)
Включает быстрый планировщик скорости. Участок разгона/торможения разбивается 
на указанное количество отрезков (+8 байт SRAM на участок), на них скорость будет одинаковая. 
Это позволяет быстро вычислять скорость мотора и достигнуть 30000 шаг/с на участке разгона 
(в обычном режиме в два раза меньше).Остальные примеры смотри в examples!
// базовый пример: как создать и запустить планировщик
// при запуске моторы будут отправлены на первую позицию
// при достижении - на вторую. После этого движение прекратится
// открой плоттер и смотри графики
#include "GyverPlanner.h"
// создаём моторы класса Stepper с указанием типа драйвера и пинов
// МОТОРЫ ДОЛЖНЫ БЫТЬ С ОДИНАКОВЫМ ТИПОМ ДРАЙВЕРА
// вот они красавцы
Stepper<STEPPER2WIRE> stepper1(2, 3);
Stepper<STEPPER2WIRE> stepper2(4, 5);
// создаём планировщик, указываем в <> тип драйвера КАК У МОТОРОВ
// и количество осей, равное количеству моторов (любое больше 1)
GPlanner<STEPPER2WIRE, 2> planner;
void setup() {
  Serial.begin(115200);
  // добавляем шаговики на оси
  planner.addStepper(0, stepper1);  // ось 0
  planner.addStepper(1, stepper2);  // ось 1
  // устанавливаем ускорение и скорость
  planner.setAcceleration(100);
  planner.setMaxSpeed(300);
  planner.reset();  // сбрасываем все позиции в 0 (они и так в 0 при запуске)
  // массив с целевыми позициями осей, размер массива равен количеству осей
  int target[] = {300, 200};
  // отправляем
  planner.setTarget(target);
}
void loop() {
  // здесь происходит движение моторов, вызывать как можно чаще
  planner.tick();
  // вернёт true, если все моторы доехали
  if (planner.ready()) {
    // загружаем новую точку
    int newTarget[] = {10, 50};
    planner.setTarget(newTarget);
  }
  // асинхронно вывожу в порт графики
  static uint32_t tmr;
  if (millis() - tmr >= 20) {
    tmr = millis();
    Serial.print(stepper1.pos);
    Serial.print(',');
    Serial.println(stepper2.pos);
  }
}Многоосевой планировщик траекторий для шаговых моторов и создания станка с ЧПУ
- ПЛАНИРОВАНИЕ СКОРОСТИ НА МАРШРУТЕ. НАСТРАИВАЕМЫЙ БУФЕР
 - Макс. скорость:
- Обычный режим: 37000 шаг/с на полной, 14000 шаг/с на разгоне
 - Быстрый профиль: 37000 шаг/с на полной, 37000 шаг/с на разгоне
 
 - Трапецеидальный профиль скорости (планировщик 2-го порядка)
 - Настройка скорости и ускорения
 - Любое количество осей. Будут двигаться синхронно к заданным целям
 - Быстрая целочисленная модель планирования траектории и скорости
 - Режим постоянного вращения для одной оси (для движения к концевику например)
 - Тормоз/плавная остановка/пауза на траектории планировщика
 - Оптимизировано для работы по прерыванию таймера
 - Быстрый контроль пинов шаговика для Arduino AVR
 - Скорость и ускорение можно задать в любое время, но применяются они после остановки мотора!
 
Планировщик управляет любым количеством моторов, вращая их к указанной позиции. В данной версии реализован буфер траектории, который можно наполнять точками, пока available() возвращает true. addTarget() принимает:
- Массив точек указанного при инициализации размера
 - Флаг остановки. Если передать 1 - планировщик остановит мотор в этой точке и будет ждать дальнейшей команды resume()
 - Тип точки: ABSOLUTE (абсолютная координата) или RELATIVE (относительно предыдущей точки)
 
Когда плаанировщик приезжает до точки остановки - он встаёт на паузу (например для включения выключения инструмента), после совершения нужных действий вызываем resume() и он продолжает движение. В отличие от предыдущего GPlanner, в GPlanner2 реализован просчёт траектории в буфере и планирование скорости для всех точек, что позволяет системе двигаться быстрее и не тормозить в каждой точке.
- Смотри симуляцию в Processing: папка Planner Simulation/Planner2
 
РАЗВЕРНУТЬ
GPlanner2<драйвер, количество осей> planner;                 // объявяление
GPlanner2<драйвер, количество осей, размер буфера> planner;  // + размер буфера (по умолч. 32)void addStepper(uint8_t axis, Stepper &stp);    // подключить мотор класса Stepper на ось axis
// примечание: тип драйвера должен совпадать у планировщика и моторов
void setBacklash(uint8_t axis, uint16_t steps); // установить компенсацию люфта на ось axis в количестве шагов steps
void enable();                              // включить моторы
void disable();                             // выключить моторы
void power(bool v);                         // переключить питание
// НАСТРОЙКИ
void setMaxSpeed(float nV);                 // установка максимальной скорости планировщика в шаг/сек
void setAcceleration(uint16_t nA);          // установка ускорения планировщика в шаг/сек^2
void setDtA(float newDta);                  // установить dt смены скорости в повороте, 0.0.. 1.0 по умолч. 0.3
// ПЛАНИРОВЩИК
uint32_t getPeriod();                       // возвращает время в мкс до следующего вызова tick/tickManual
void start();                               // начать работу
void stop();                                // остановить плавно (с заданным ускорением)
void brake();                               // резко остановить моторы из любого режима
void resume();                              // продолжить после остановки или конечной точки маршрута
void reset();                               // сбросить счётчики всех моторов в 0
bool ready();                               // флаг достижения точки остановки. После неё нужно вызывать resume
bool available();                           // true - в буфере планировщика есть место под новю точку
uint8_t getStatus();                        // текущий статус:
// 0 ожидание команды (остановлен)
// 1 ожидание буфера
// 2 в пути
// 3 на паузу
// 4 на стоп
// 5 крутится setSpeed
// СКОРОСТЬ
void setSpeed(uint8_t axis, float speed);   // режим постоянного вращения для оси axis со скоростью speed шаг/сек (м.б. отрицателеьной)
// ПОЗИЦИЯ
// добавить новую точку маршрута. Массив координат, флаг окончания и абсолютный/относительный
void addTarget(int32_t tar[], uint8_t l, GS_posType type = ABSOLUTE);
void addTarget(int16_t tar[], uint8_t l, GS_posType type = ABSOLUTE);
// ABSOLUTE - конкретные координаты точки, куда двигаться
// RELATIVE - смещение относительно текущих положений моторов
void setCurrent(int16_t cur[]);             // установить текущее положение моторов
void setCurrent(int32_t cur[]);             // установить текущее положение моторов
int32_t getCurrent(int axis);               // получить текущую позицию по оси axis
int32_t getTarget(int axis);                // получить текущую цель в шагах на оси axis
// ТИКЕР
// тикер, вызывать как можно чаще. Вернёт true, если мотор крутится
// здесь делаются шаги для движения по точкам, для вращения по скорости, а также перестройка буфера
bool tick();
// ручной тикер для вызова в прерывании или где то ещё. Выполняется 20..50 us
bool tickManual();
// обработчик буфера. Сам вызывается в tick. Нужно вызывать вручную при работе с tickManual
// вернёт true, если планировщик отправил моторы на новую позицию (в этот момент можно запускать таймер)
void checkBuffer();
// ======= ДЕФАЙНЫ НАСТРОЕК =======
// объявлять перед подключением библиотеки
#define GS_FAST_PROFILE размер_массива (например 10)
Включает быстрый планировщик скорости. Участок разгона/торможения разбивается 
на указанное количество отрезков (+8 байт SRAM на участок), на них скорость будет одинаковая. 
Это позволяет быстро вычислять скорость мотора и достигнуть 30000 шаг/с на участке разгона 
(в обычном режиме в два раза меньше).Остальные примеры смотри в examples!
// пример с записанным в памяти маршрутом
// смотри график, а лучше запусти stepperPlot
int path[][2] = {
  {100, 250},
  {160, 30},
  {230, 250},
  {60, 100},
  {270, 100},
};
// количество точек (пусть компилятор сам считает)
// как вес всего массива / (2+2) байта
int nodeAmount = sizeof(path) / 4;
#include "GyverPlanner2.h"
Stepper<STEPPER2WIRE> stepper1(2, 3);
Stepper<STEPPER2WIRE> stepper2(4, 5);
GPlanner2<STEPPER2WIRE, 2> planner;
void setup() {
  Serial.begin(115200);
  // добавляем шаговики на оси
  planner.addStepper(0, stepper1);  // ось 0
  planner.addStepper(1, stepper2);  // ось 1
  // устанавливаем ускорение и скорость
  planner.setAcceleration(500);
  planner.setMaxSpeed(500);
  // начальная точка системы должна совпадать с первой точкой маршрута
  planner.setCurrent(path[0]);
  planner.start();
}
int count = 0;  // счётчик точек маршрута
void loop() {
  // здесь происходит движение моторов, вызывать как можно чаще
  planner.tick();
  // если в буфере планировщика есть место
  if (planner.available()) {
    // добавляем точку маршрута и является ли она точкой остановки (0 - нет)
    planner.addTarget(path[count], 0);
    if (++count >= sizeof(path) / 4) count = 0; // закольцевать
  }
  // асинхронно вывожу в порт графики
  static uint32_t tmr;
  if (millis() - tmr >= 20) {
    tmr = millis();
    Serial.print(stepper1.pos);
    Serial.print(',');
    Serial.println(stepper2.pos);
  }
}- v1.1 - добавлена возможность плавного управления скоростью в KEEP_SPEED (см. пример accelDeccelButton)
 - v1.2 - добавлена поддержка ESP8266
 - v1.3 - изменена логика работы setTarget(, RELATIVE)
 - v1.4 - добавлена задержка для STEP, настроить можно дефайном DRIVER_STEP_TIME
 - v1.5 - пофикшен баг для плат есп
 - v1.6 - Исправлена остановка для STEPPER4WIRE_HALF, скорость можно задавать во float (для медленных скоростей)
 - v1.7 - Исправлен баг в отрицательной скорости (спасибо Евгению Солодову)
 - v1.8 - Исправлен режим KEEP_SPEED
 - v1.9 - Исправлена ошибка с esp функцией max
 - v1.10 - повышена точность
 - v1.11 - повышена точность задания скорости
 - v1.12 - пофикшена плавная работа в KEEP_SPEED. Добавлена поддержка "внешних" драйверов. Убран аргумент SMOOTH из setSpeed
 - v1.13 - исправлены мелкие баги, оптимизация
 - v1.14 - исправлены ошибки разгона и торможения в KEEP_SPEED
 - v1.15 - оптимизация, исправлены мелкие баги, stop() больше не сбрасывает maxSpeed
 - v1.15.2 - добавил включение EN если указан, даже при отключенном autoPower
 - v2.0 - оптимизация. Ядро шаговика вынесено в отдельный класс Stepper. Добавлены многоосевые планировщики траекторий
 - v2.1 - добавил GyverStepper2, упрощённая и оптимизированная версия GyverStepper
 - v2.1.1 - исправлена бага в GyverStepper
 - v2.1.2 - совместимость Digispark
 - v2.1.3 - починил FOLLOW_POS в GStepper, починил RELATIVE в GPlanner2 и исправил багу с рывками
 - v2.1.4 - GPlanner2: исправил рывки, добавил адаптивное перестроение траектории без остановок, чутка оптимизировал вычисления
 - v2.1.5 - возможность менять скорость и ускорение во время работы планировщика (GStepper2, GPlanner, GPlanner2)
 - v2.1.6 - исправлена ошибка компиляции при вызове disable() в GStepper
 - v2.1.7 - добавлен clearBuffer() в GPlanner2
 - v2.1.8 - оптимизация, исправлен KEEP_SPEED в GStepper
 - v2.2.0 - добавлен скоростной профиль GS_FAST_PROFILE для GStepper2, GPlanner, GPlanner2. Поддержка режима "слежения" для GStepper2
 - v2.2.1 - небольшая оптимизация SRAM
 - v2.3 - fix compiler warnings, поддержка esp32
 - v2.4 - повышена плавность движения шаговиков в Planner и Planner2. Исправлена бага в Stepper2
 - v2.5 - исправлено плавное изменение скорости для KEEP_SPEED
 - v2.6
- disable() в виртуальном режиме отключает сигнал с мотора (для 4-проводных драйверов)
 - улучшена производительность для step-dir драйверов
 - добавил autoPower() в GStepper2
 - исправлен рывок при смене направления в GStepper
 
 - v2.6.1 - поправлена бага в GStepper2
 - v2.6.2 - оптимизированы вычисления в GStepper2, GPlanner и GPlanner2
 - v2.6.3 - reverse() в step-dir драйвере теперь применяется сразу
 - v2.6.4 - исправлен RELATIVE setTarget() в GPlanner #11
 - v2.7
- исправлены различные ошибки компиляции
 - исправлены некоторые критические баги
 - добавлено управление питанием в планировщики
 - добавлена компенсация люфта в планировщики
 - исправлены баги при нулевом ускорении во всех библиотеках
 - исправлена медленная остановка и удар при большом ускорении
 - увеличена производительность для esp8266
 
 
При нахождении багов создавайте Issue, а лучше сразу пишите на почту [email protected] Библиотека открыта для доработки и ваших Pull Request'ов!
При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать:
- Версия библиотеки
 - Какой используется МК
 - Версия SDK (для ESP)
 - Версия Arduino IDE
 - Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде
 - Какой код загружался, какая работа от него ожидалась и как он работает в реальности
 - В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код