Closed sadr0b0t closed 7 years ago
Код обработчика таймера handle_interrupts https://github.com/1i7/stepper_h/blob/master/stepper_h/stepper_timer.cpp#L824
на одном шаге работает в 3 приема:
На третьем же проходе взводятся счетчики для следующего шага. Проверка, делать ли следующий шаг мотору, проверяется в начале каждого цикла - смотрим значение флага
cstatuses[i].stopped
Этот же флаг выставляется на первом проходе, когда проверяются концевики и виртуальные границы, поэтому, по правильной логике, не должен отработать даже второй проход.
В чем проблема, пока непонятно. Пока единственное логичное объяснение - на первой итерации код не попадает в первых проход, а сразу отправляется во второй-третий. Теоретически, это возможно при определенных значениях частоты таймера (в задержку между двумя шагами должны уместиться как минимум 3 импульса). Но это вроде как не этот случай, плюс - последующие шаги отрабатывают и проверки срабатывают, значит бага скорее всего где-то еще.
Короче, понятно.
Если готовить вращение таким образом (указывать в prepare_whirl скорость 0):
// подготовить вращение
prepare_whirl(sm, dir, 0);//sm->pulse_delay);
(для прошивки rraptor_mpide3 вполнить команду "rr_go x -1")
то получаем выход за границы на 1 шаг
X.pos=0.0000000000, Y.pos=0.0000000000, Z.pos=0.0000000000
ok
X.***WARNING: fixing step_delay to match minimal pulse_delay step_delay=0us, pulse_delay=1000us
***ERROR: timer handler takes longer than timer period: cycle time=98499us, timer period=200us
pos=-7.5000000000, Y.pos=0.0000000000, Z.pos=0.0000000000
это сообщение будет при включенной отладке в stepper_lib_config.h
#define DEBUG_SERIAL
Казалось бы, долгий Serial.println с предупреждением может ломать тайминг прерывания, но нет, при выключенной отладке за границы все равно выходим, только молча.
Если готовить вращение так (указывать задержку sm->pulse_delay)
// подготовить вращение
prepare_whirl(sm, dir, sm->pulse_delay);
То выхода за границы нет.
Сообщение с предупреждением выводится в stepper_timer.h https://github.com/1i7/stepper_h/blob/master/stepper_h/stepper_timer.cpp#L1072
// проверим, корректна ли задержка
if(step_delay < smotors[i]->pulse_delay) {
// посмотрим, что делать с ошибкой
if(small_pulse_delay_handle == FIX) {
// попробуем исправить:
// не будем делать шаги чаще, чем может мотор
// (следует понимать, что корректность вращения уже нарушена)
step_delay = smotors[i]->pulse_delay;
#ifdef DEBUG_SERIAL
Serial.print("***WARNING: fixing step_delay to match pulse_delay ");
Serial.print("step_delay=");
Serial.print(step_delay);
Serial.print("us, pulse_delay=");
Serial.print(smotors[i]->pulse_delay);
Serial.println("us");
#endif // DEBUG_SERIAL
} else if(small_pulse_delay_handle == STOP_MOTOR) {
// останавливаем мотор
cstatuses[i].stopped = true;
if(cstatuses[i].stepper_info != NULL) {
cstatuses[i].stepper_info->status = STEPPER_STATUS_FINISHED;
}
} else if(small_pulse_delay_handle == CANCEL_CYCLE) {
// завершаем весь цикл
canceled = true;
}
// иначе, игнорируем
// в любом случае, обозначим ошибку
if(cstatuses[i].stepper_info != NULL) {
cstatuses[i].stepper_info->error_pulse_delay_small = true;
}
}
Инересно, что в случае, если задержка step_delay=0, то ее значение исправляется на тот же step_delay = smotors[i]->pulse_delay динамически. Но при варианте с автоматическим исправлением, почему-то, происходит выход за границу, нужно понять, почему, и добавить тесты на эту ситуацию.
Короче, вот исправление (комент к коммиту не корректен - это исправление текущего тикета #1 , а не #3 ) https://github.com/1i7/stepper_h/commit/2979e6483eea7fcab50c68de8a316aa723ffc7ee
объяснение в коменте к тесту
// а вот и объяснение: если указываем step_delay=0 в prepare_whirl, то первый шаг будет
// сделан без всех проверок сразу на 1й тик таймера (этапы tick1 и tick2 будут пропущены),
// т.к. первый тик сразу получается наиближайшим к фронту шага (т.е. нулю).
// Решение: во всех местах, где устанавливаем значение step_delay для очередного шага,
// нужно делать проверку, что в нее уместится как минимум 3 тика таймера
// (сравнения с аппаратными ограничениями задержки для шагов мотора достаточно,
// т.к. она должна заведомо включать как минимум 3 тика).
// В нашем случае - это метод prepare_whirl, но другие места (особенно там, где есть динамическая
// задержка) нужно тоже все проверить.
этот же коммит исправляет тикет (нужно проверить на контроллере, а лучше как-нибудь через отдельный тест-кейс) https://github.com/1i7/stepper_h/issues/2
добавил тесты для prepare_whirl и prepare_steps, для остальных вариантов подготовки шагов еще предстоит написать тесты
Мотор всегда делает первый шаг в цикле, даже если есть причины его не делать (например, если координата собирается или уже вышла за пределы виртуальной границы).
Например: