Библиотека для управление шаговым мотором через прерывание!

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

Привет всем!

Ищу библиотеку для управления шаговым  мотором. Нужно:

-Рампа (плавное ускорение, замедление)

-работа через прерывание!!!

-ускорение/замедление в непрерывном режиме работы. Когда не задаешь конечное положение, а только скорость..

 

К сожалению  http://www.airspayce.com/mikem/arduino/AccelStepper/ не подходит. Код кривой. Уже исправил 5 ошибок.  Кроме того там максимум 4200 шагов в секунду и нельзя менять параметры, когда мотор едет. А мне нужно больше. Вернее сказать этого достаточно, но нужно еще и опрашивать клавиатуру, выводить  данные на дисплей и тп.  Если использовать AccelStepper/, то окно порядка 50мкс. За это время надо все успеть...

Вместо того, что бы вызывать все время  run, нужно вызывать ее по прерыванию, в нужный момент... может есть готовая библиотека, зачем городить велосипед на основе  gribl

Спасибо..

 

 

 

 

 

 

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

timerone можно использовать. там можно регулировать частоту прерываний, и соответственно скорость вращения. в функции написать уже свою программу управления двигателем

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

  Спасибо за идею. Все не так просто. мне нужно после каждого шага перепрограммировать таймер , что бы получались задержки:

20000, 10000....... 53, 52, 52, 51, 51,51, 51, 50, 50, 50 Микросекунд.

Параметры сильно  зависят от ускорения и скорости.

Другими словами: можно использовать примерно 30% кода из    Timer1  и 50% кода из accelstepper.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

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

vvadim
Онлайн
Зарегистрирован: 23.05.2012

Похоже тс прийдётся самому себе писать библиотеку

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

vvadim пишет:

Похоже тс прийдётся самому себе писать библиотеку

Только часть. Оно уже написано:

https://github.com/grbl/grbl/blob/master/stepper.c

luc1f3r
Offline
Зарегистрирован: 23.05.2014

Есть успехи?

Брал adfruit motor shield, т.к. было сказано о возможности подключения 2 шаговых двигателей одновременно. Но, как оказалось, управлять ими одновременно нельзя. AccelStepper даже близко не выдаёт нужных скоростей при управлении двумя моторами одновременно. Простейший код распределения шагов по таймерам и интервалам с использованием шилдовой библиотеки AFmotor и то дал более адекватный результат. Но этого всё-равно не достаточно.

Готовых солюшенов для применения grbl с моим шилдом найти не удалось. Что посоветуете?

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

Привет!

После 2-х месяцев копания и экспериментов ( по понедельникам) я таки давел мою машинку до рабочего состояния.

1. Я Заменил механику. Убрал коробку передач/ купил новый шаговый, с правильной коробкой и резиновыми прокладками для шумоизоляции. Купил новый контроллер шаговика - Мой китайский шаговый мотор  оказался странным. Тошиба с ним глючит. Перешел на микрошаг.

2. Я перепилил AccelStepper.  убрал лишнее (только контроллер)- 4300 -> 5600 Шагов в секунду. убрал расчет лишинего "Double в цикле  -8000,  убрал вообще плавающую точку - еще быстрее стало (18000 или того. Мотор просто загибается.) Но без этого расчета разгон/торможение не работает, т.е. выключаю только когда разогнался. Походу пофиксил множество багов. Будут силы , выложу свою версию на гитхаб.

3. Поменял логику: Отказался от проверок клавиатуры и вывода на экран позиции во время движения. Если нажимается кнопка - то сразу выходит из программы, мотор плавно тормозит и только потом опрашивает  IK  пульт.

4. Любое "программирование" мотора только когда он стоит. Код Accestepper писали какие-то пинеры, и  такого рода манипуляции не совсем возможны.

последний пункт принес больше всего. После 3,4 все наконец-то заработало. Из за перебора механики, мне больше не надо разгоняться до 2300 шагов в секунду, а при 800 Все стабильно работает.

Присылай код, посмотрю, может ты тоже скорость во время движеня мотора меняешь, и он свою позицию в Рампе забывает... Или в сериальный порт пишешь... (4,5 мкс при 115000)

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

achest, есть рабочая версия переделанного AccelStepper?

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

achest пишет:

Готовых солюшенов для применения grbl с моим шилдом найти не удалось. Что посоветуете?

Сменить шилд на RAMPS.   http://reprap.org/wiki/RAMPS_1.4/ru
http://www.banggood.com/3D-Printer-Kit-RAMPS-1_4-Control-Board-5Pcs-4988-Driver-With-Heat-Sink-p-936955.html
 

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

achest, есть рабочая версия переделанного AccelStepper?

Привет!

Ты просто читаешь мои мысли. Я тольк в воскресенье дописал до конца и залил все на гитхаб.

https://github.com/achest/stepperQ

Мои TODO:

-Пока релиализована только "железный" контроллер , с 1 входом для Шага. Надо добавить поддержку разных вариантов в часности обычного драйвера L297 с 4-входами.

-Нет примеров. Надо написать 4-5 штук и нормально задокументировать. Постараюсь сделать на этой неделе...

Основная идея, отличия от  AccelStepper.

Управление по прерыванию. Надо сказать мотору куда,и как быстро ехать и сказать start(). он сам доедет куда надо....

 

После переделки, общий  код сократился в 3 раза и стало сразу комфортно. Могу писать на экран когда угодно, не нужно ни о чем думать, пока мотор едет, просто программировать то, что нужно.

 

 

 

 

 

uragan
Offline
Зарегистрирован: 23.02.2015

А униполярным ШД можно управлять по пяти проводам?

vvadim
Онлайн
Зарегистрирован: 23.05.2012

 

ИНТЕРЕСНО!

maxvalin
Offline
Зарегистрирован: 22.02.2016

здравствуйте! ну интересно же! а?
в самого затык с ШД.
Все никак не могу заставить его работать вне общего цикла. в холостую крутит нормально, а только добавляют меню и обработку кнопок и енкодера- кирдык..
уже не знаю в какую тему форума лезть, нигде никто не отвечает..

MacSim
Offline
Зарегистрирован: 28.11.2012

у меня вообще все без библиотек крутиться..., народу библиотеки готовые подавай.

maxvalin
Offline
Зарегистрирован: 22.02.2016

библиотеку не надо подавать, подсказать как сделать чтоб пока крутился шд остальное приостанавливалось. Иначе движется он с затыком, еле еле.

maxvalin
Offline
Зарегистрирован: 22.02.2016

разобрался благодаря вашим советам, использовал другую команду. Опять же, если бы знать команды и как их использовать правильно, ведь этого нигде не прочитать. Вот сейчас хочу понять как отключить шд после движения чтоб не стоял род напряжением, как это сделать? я даже не могу прописать в поиске правильный вопрос..

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

Я довел мою библиотеки до рабочего состояния

https://github.com/achest/stepperQ

Пользуйтесть на здоровье.

 

vvadim
Онлайн
Зарегистрирован: 23.05.2012

попробовал вашу библиотеку - и вправду шустрее крутятся.

а вот быстрой остановки у меня не получается, всё равно с замедлением.

тестировал на таком примере

#include <stepperQ.h>

const int buttonPin = 2;

int dir_pin = 7;
int step_pin = 8 ;

void setup() {

  stepperq.init(dir_pin, step_pin);
  stepperq.setMaxSpeed(400);
  stepperq.setAcceleration(200);
  pinMode(buttonPin, INPUT);
}
void loop ()
{
  if (digitalRead(buttonPin) == LOW)
  {
    stepperq.moveTo(2000);
    stepperq.start();
  }

  if (digitalRead(buttonPin) == HIGH)
  {
      stepperq.stop();
  }
}

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

А она и не должна получаться, его библиотека основана на бибилиотеке акселстепер. Кстати не все ошибки исправлены:) Так вот, быстрая остановка означает просто остановку начиная с этого момента. Если вы установите ускорение на максимум, и потом воткнете быструю остановку, вот и получите то что хотите.

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

brokly пишет:

А она и не должна получаться, его библиотека основана на бибилиотеке акселстепер. Кстати не все ошибки исправлены:) Так вот, быстрая остановка означает просто остановку начиная с этого момента. Если вы установите ускорение на максимум, и потом воткнете быструю остановку, вот и получите то что хотите.

Именно так. К сожалению остановить Шаговый мотор моментально нельзя. Продавцы драйверов скажут тебе спасибо. Там  импульс по питанию идет не слабый,  может выбить все что угодно.  Дай проводки от мотора кому-нибудь в одну  руку, и покрути мотор... Там индукции надоводится еще как.

по поводу ошибок : Пожалуйста будьте консруктивными и пишите на гит хабе.  Желательно конкретный, исправленый код.

Постараюсь все исправить.

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Не не, я не в упрек. Наоборот , считаю вашу работу очень полезной.

Если честно, то я уже не помню где косяк, но пришел к выводу, что вы обкатывали библиотеку в основном на бесконечных вращениях, а не на целевых. Там ошибка была связана именно с этим.

А вот вспомнил одну. После остановки мотора на запрос текущей скорости получим не нулевое значени.

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

brokly пишет:

Если честно, то я уже не помню где косяк, но пришел к выводу, что вы обкатывали библиотеку в основном на бесконечных вращениях, а не на целевых. Там ошибка была связана именно с этим.

Один такой баг  я исправил.   Спасибо форуму.    Теперь правда надо переписывать проверки, когда целевая скорость достигается за 1-2 шага.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Я так исправил, может и коряво... 

void StepperQ::init(uint8_t dirpin, uint8_t steppin) {
    _currentPos = 0;
    _targetPos = 0;
    _maxSpeed = 1.0;
    _acceleration = 1.0;
    _sqrt_twoa = 1.0;
    _pin[1] = dirpin;
    _pin[0] = steppin;
    // NEW
    _n = 0;
    _c0 = 0.0;
    _cn = 0.0;
    _cmin = 1.0;
    _direction = DIRECTION_CCW;
   
    TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // brokly

    pinMode(_enablePin, OUTPUT);
    pinMode(_pin[1], OUTPUT);
    pinMode(_pin[0], OUTPUT);
}

//......

float StepperQ::speed() {
   if ((TCCR1B & (_BV(CS10) | _BV(CS11) | _BV(CS12))) == 0) return 0; //если таймер остановлен, то мотор не крутится, brokly
   return 1000000.0/_cn;
}

И еще на какой то баг наступал, припоминаю. Но там полез и увидел две закоментированные коротенькие строчки, раскоментировал и ошибка пофиксилась.

И еще , ни в коем случае не в упрек. У вас там дебаггинг таскает с собой ненужный код. Ну если дебаг этой библы не нужен юзеру, то все равно в коде будут проверки, а не дебажим ли мы, поэтому я поправил дабагинг в следующий вид :

#ifdef DEBUG
    Serial2.print("\n\r n=");
    Serial2.print(_n);
    Serial2.print(" _cn=");
    Serial2.print(_cn);
#endif

Естественно для включения дебага нужна строка:

#define DEBUG

Кажись тут правил:

void StepperQ::stop(){
#ifdef DEBUG
   Serial2.print("\n\r StepperQ:stop"); 
#endif  
   // move(abs(_n));  
   //_direction ==1 ? abs(_n):-abs(_n);
   move(_direction ==1 ? abs(_n):-abs(_n));
}

Там какая то шляпа всплывала при смене направления вращения.

vvadim
Онлайн
Зарегистрирован: 23.05.2012

написал при остановке

stepperq.setAcceleration(3000);

получилось почти мгновенно)))

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

Спасибо большое за помощь. Ошибки исправил. Тормозить  в лево будет правльно и таймер запускать тоже.

Логгинг еще не исправил. Поставлю Eclipse,  отформатирую код по человечески, подправлю.

Спасибо!

 

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

Не совсем понимаю хаяние  AccelStepper, ИМХО в целом она грамотно написана... Если знаете ошибки в текущей версии - давайте их тут обсудим.

НЕЛЬЗЯ шаговик останавливать мгновено.

1) от этого плохо драйверу, так как там токи очень высокие получаются

2) вредно механике, так как это ударная нагрузка

3) Идет пропуск шагов. (Если вы шаговиком как обычным мотором пользуетесь, то это не важно)

 

 

 

achest
achest аватар
Offline
Зарегистрирован: 01.10.2012

roman2712@mail.ru пишет:

Не совсем понимаю хаяние  AccelStepper, ИМХО в целом она грамотно написана... Если знаете ошибки в текущей версии - давайте их тут обсудим.

Спасибо за квалифицированную дискуссию.

Недостаки Accelstellpper:

1. Концепт, что внутри loop() все время должен вызываться .run().  Это называется  polling pattern.  это плохо.

Плохо, потому, что потребляет много энергии, что процессор 90% времени просто стоит (ждет) и считает нули и тп.

Плохо, потому, что нельзя в loop написать чего-либо, что требует времени. На пример вывод на обычный экран 1 строчки, уже сбивает работу шаговика. А вывести все 5 строчкек на экран, 10 раз в секунду, так все, ничего больше не работает. Шаговик только кашляет. Я даже  хотел поставить отдельно 2-ю ардуину для шаговика отдельно.

Если твоя цель: 100 шагов в секунду, то все более-менее ок. Как только ты пытаешься разгонять мотор до 1000 шагов в секунуду, то у тебя остается примерно 800мкс окно. В него очень очень сложно вписаться. При работе через прерывание таких проблем нет.

т.е. вопрос в применимости библиотеки.

2. Нельзя менять скорость во время движения мотора. 2 раза лишние вычисления чисел с плавающей точкой ( 20-50 мкс за цикл) еще пару других багов. Хочешь, могу сделать форк accestepper и сравним. К сожалению уже не помню, что там исправил. Мелочи. Оригинал может 4400 шагов в минуту, моя модификация 7800. Но и количество проверок тоже меньше.

Кстати, менять ускорение во время движения я так и не научился....  

Я не ругаю библиотеку,  я написал свою, которая для меня лучше. Я прошу помощи в ее тестировании, и в исправлении в ней ошибок.

 

 

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

1) ссогласен. Этот момент легко переписывается. Я это через дочерний класc и сделал. 

2) Изменение скорости в большую величину Accelstellpper отрабатывает корректно. А вот уменшение - нет.

Для решения второй проблемы я делал так

void myStepper::speedNow(float _speedNow)
{
   if (_speedNow >= abs(_speed))
   {
      if (speedDown) moveTo(targetPosTemp);
      speedDown = 0;
      setMaxSpeed(_speedNow);
   }
   else 
   {
      if (!speedDown) targetPosTemp = _targetPos;
      speedTemp = _speedNow;
      speedDown = 1;
      stop();
   }
}

void  myStepper::limitSpeed()
{
    if (speedDown)
    {
       if (speedTemp > abs(speed()))
       {
	  moveTo(targetPosTemp);
	  setMaxSpeed(speedTemp);
	  speedDown = 0;
       }
    }
}

void myStepper::run()
{
   limitSpeed();
   AccelStepper::run();
}

speedNow и limitSpeed для отработки снижения скорости

Я у вас следующую математику вообще не понял,

  if (_n == 0)
  {
    _cn = _c0;
    _direction = (distanceTo > 0) ? DIRECTION_CW : DIRECTION_CCW;
    changeDirection() ;
    setPeriod(_cn);
    _n++;
  }
  else  if (_n > 0 && _cn > _cmin )
  {
    _cn = _cn - ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
    _cn = max(_cn, _cmin);
    _n++;
  }
  else if (_n > 0 && _cn < _cmin)
  {
    _cn = _cn + ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
    _n--;
  }
  else if (_n <= 0) {
    _cn = _cn - ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
    _n++;
  }

я понимаю, что _cn < _cmin - это как раз отслеживание уменьшение скорости, почему формула в  (_n > 0 && _cn < _cmin) c "+". А потом _n--.  Можете пояснить ваш ход мысли ? 

И еще. В расчете шагов у вас убран пересчет шагов до остановки в зависимости от скорости (это и дает прирост скорости на 2000 им/с, специально проверил :)). Но тогда получается не очень красивая ситуация в случае, если  количество необходимых шагов (в программе) меньше чем количество шагов торможения _stepsToStop.

 

Kamikadze
Offline
Зарегистрирован: 09.03.2017

roman2712@mail.ru пишет:

1) ссогласен. Этот момент легко переписывается. Я это через дочерний класc и сделал. 

2) Изменение скорости в большую величину Accelstellpper отрабатывает корректно. А вот уменшение - нет.

Для решения второй проблемы я делал так

void myStepper::speedNow(float _speedNow)
{
   if (_speedNow >= abs(_speed))
   {
      if (speedDown) moveTo(targetPosTemp);
      speedDown = 0;
      setMaxSpeed(_speedNow);
   }
   else 
   {
      if (!speedDown) targetPosTemp = _targetPos;
      speedTemp = _speedNow;
      speedDown = 1;
      stop();
   }
}

void  myStepper::limitSpeed()
{
    if (speedDown)
    {
       if (speedTemp > abs(speed()))
       {
	  moveTo(targetPosTemp);
	  setMaxSpeed(speedTemp);
	  speedDown = 0;
       }
    }
}

void myStepper::run()
{
   limitSpeed();
   AccelStepper::run();
}

speedNow и limitSpeed для отработки снижения скорости

Я у вас следующую математику вообще не понял,

  if (_n == 0)
  {
    _cn = _c0;
    _direction = (distanceTo > 0) ? DIRECTION_CW : DIRECTION_CCW;
    changeDirection() ;
    setPeriod(_cn);
    _n++;
  }
  else  if (_n > 0 && _cn > _cmin )
  {
    _cn = _cn - ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
    _cn = max(_cn, _cmin);
    _n++;
  }
  else if (_n > 0 && _cn < _cmin)
  {
    _cn = _cn + ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
    _n--;
  }
  else if (_n <= 0) {
    _cn = _cn - ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
    _n++;
  }

я понимаю, что _cn < _cmin - это как раз отслеживание уменьшение скорости, почему формула в  (_n > 0 && _cn < _cmin) c "+". А потом _n--.  Можете пояснить ваш ход мысли ? 

И еще. В расчете шагов у вас убран пересчет шагов до остановки в зависимости от скорости (это и дает прирост скорости на 2000 им/с, специально проверил :)). Но тогда получается не очень красивая ситуация в случае, если  количество необходимых шагов (в программе) меньше чем количество шагов торможения _stepsToStop.

 

А все понял

Zibn
Offline
Зарегистрирован: 03.01.2018

Господа, простите нуба, но я никак не могу разобраться с одной проблемкой. Необходимо сделать так, чтобы два шаговика управлялись джойстиком. В наличии ардуинон нано, шилд на три драйвера и собственно джойстик. Уже три дня ковыряюсь никак не могу запустить, может есть у кого готовый скетчик или пару советов, буду премного благодарен.