loop()
устанавливает целевую относительную позицию для каждого двигателя, затем ждет, пока все двигатели не достигнут своей целевой позиции. Выполнение последовательности таких шагов.
При каждом прерывании по таймеру для каждого двигателя, который еще не достиг своей цели, генерируется шаговый импульс. (На самом деле это немного сложнее, поскольку каждый двигатель имеет профили скорости и ускорения, поэтому импульс шага генерируется, когда этого требует профиль движения).
Важно отметить, что шаг импульса очень коротко, контроллер мотора генерирует правильные сигналы для катушек мотора для завершения шага. Шаговый импульс завершается задолго до того, как двигатель достигает конца шага (или даже начинает свой шаг), поэтому, хотя импульсы для каждого двигателя выдаются последовательно, поскольку это не занимает значительного времени по сравнению со временем шага, все двигатели могут шагать одновременно не последовательно.
Таким образом, существует два потока выполнения - таймер ISR и loop()
. ISR позволяет асинхронному переходу к коду loop()
, который затем может выполнять другую работу. За исключением этого случая, он не делает ничего, кроме ожидания завершения шагов, что сводит на нет все преимущества фонового перехода - превращая асинхронное движение в полностью синхронный процесс.
Независимо от достоинств и недостатков Arduino Sketch setup()
/ loop()
framework, эта конкретная реализация полностью его побеждает, никогда не повторяя loop()
и не блокируя бесконечно в конце. Фреймворк ожидает, что loop()
будет запущен до конца, и он будет вызывать его повторно (отсюда и его название - это тело исполнительной власти l oop).
Тело loop()
должно быть реализовано как неблокирующий конечный автомат или последовательность конечных автоматов, например:
void runNoWait()
{
setNextInterruptInterval();
}
void loop()
{
static const int sequence[] = { 200,200,200,200,200,200,200,200,
400,-400,200,-200,600,-600} ;
static const sequence_steps = sizeof(sequence) / sizeof(*sequence) ;
static sequence_index = 0 ;
// If sequence not complete...
if( sequence_index < sequence_steps )
{
// If all motor positions achieved...
if( remainingSteppersFlag == 0x00 )
{
// For each motor set up next position
for( int k = 0; k < NUM_STEPPERS; k++)
{
prepareMovement( k, sequence[sequence_index] ) ;
}
// Start motors
runNoWait() ;
// Next step in sequence
sequence_index++ ;
}
}
// Do other (non-blocking) stuff here while
// simultaneously executing motor sequence
...
}
Это позволит вам эффективно использовать Процессор, выполняющий больше работы и позволяющий более отзывчивое поведение. Например, вы можете опросить вход аварийной остановки, чтобы прервать движение:
void allStop()
{
remainingSteppersFlag = 0 ;
}
void loop()
{
...
// Stop sequence immediately on button press
if( digitalRead(buttonPin) == LOW )
{
allStop() ;
sequence_index = sequence_steps ;
}
...
}