Есть такое задание: управление электромоторчиком используя в том числе и ограничитель.
В качестве элементов используются перечисленные в заголовке, плюс два понижающих резистора для оптопары - 100Ohm последовательно с диодом и 10kOhm развязка от эмиттера на землю, параллельно входу в ESP. Питание: для двигателя и DRV8833 - 12V через преобразователь в 5V, для ESP и оптопары - 3.3V от nodeMCU. Всё это разложено на печеньке небольшой макетки.
Стоит заметить, что электродвигатель мелкий и оснащён редуктором примерно 1:1000, один оборот происходит в течении около 4-5 секунд. Оптопара у меня вскрыта, так как я её готовлю для установки в ограниченное пространство, однако опыты были проведены так же и с оригинальной оптопарой.
Задача: произвести калибровку двигателя путём вращения двигателя в одну сторону до перекрытия оптопары; вращение в другую сторону до перекрытия оптопары с регистрацией времени от старта до останова; ещё одна смена направления и снова вращение до перекрытия оптопары с регистрацией времени от старта до останова; вычисление среднего времени для одного цикла; очередная (на этот раз, демонстрационная) смена направления и вращение в течение 1/4 времени полного цикла. Цель - вращение грубо на четверть оборота.
Код следующий:
При полностью отключенном питании на двигатель, после заливки кода получаем следующий аутпут:
После окончания калибровки происходит просто регистрация факта закрытия/открытия оптопары. Однако, если система в состоянии "Откалибровано", после пятого открытия оптопары происходит сброс состояния и снова производится калибровка. Это сделано для проверки многократной системной отработки (короче, - для пущего тестирования).
Можно заметить в окне вывода, что открытие/закрытие оптопары происходит до странности многократно при одном движении флажка (флажок в данном случае кусочек картонки подносимый рукой). Почему это происходит следует понять, потому что это никак не сходится с задачей.
Далее, если подать питание на цепь управления двигателя, происходят чудеса - оптопара сама по себе срабатывает по многу раз в секунду, двигатель крутит то туда, то сюда вообще бессистемно.
Прошу просветить: Что я делаю не так?
ПЫС. Изначально код имел совсем другую структуру и включал переизбыток пауз. После указания со стороны о недопустимости перехвата цепи обработки процессов на долгое время, было решено перевести в формат отработки как можно меньших шагов и их обработки в дискретные значения времени. Таким образом получилось избавиться от постоянных перезагрузок контроллера. С той же целью был включен оператор yield(), но при текущем построении алгоритма, его использование оказалось избыточным.
В качестве элементов используются перечисленные в заголовке, плюс два понижающих резистора для оптопары - 100Ohm последовательно с диодом и 10kOhm развязка от эмиттера на землю, параллельно входу в ESP. Питание: для двигателя и DRV8833 - 12V через преобразователь в 5V, для ESP и оптопары - 3.3V от nodeMCU. Всё это разложено на печеньке небольшой макетки.
Стоит заметить, что электродвигатель мелкий и оснащён редуктором примерно 1:1000, один оборот происходит в течении около 4-5 секунд. Оптопара у меня вскрыта, так как я её готовлю для установки в ограниченное пространство, однако опыты были проведены так же и с оригинальной оптопарой.
Задача: произвести калибровку двигателя путём вращения двигателя в одну сторону до перекрытия оптопары; вращение в другую сторону до перекрытия оптопары с регистрацией времени от старта до останова; ещё одна смена направления и снова вращение до перекрытия оптопары с регистрацией времени от старта до останова; вычисление среднего времени для одного цикла; очередная (на этот раз, демонстрационная) смена направления и вращение в течение 1/4 времени полного цикла. Цель - вращение грубо на четверть оборота.
Код следующий:
Код:
byte FwdPin = 12;
byte BkwPin = 13;
byte OpcPin = 14;
unsigned long TargetTimer = 0;
byte System_NonCalibrated = 0;
byte System_CalibrationStarted = 1;
byte System_InitExtremeFound = 2;
byte System_FindFwdExtreme = 3;
byte System_ForwExtremeFound = 4;
byte System_FindBkwExtreme = 5;
byte System_BckwExtremeFound = 6;
byte System_AvgCcleTimeFound = 7;
byte System_Calibrated = 8;
byte System_State = 0;
byte System_PrevState = -1;
byte OC_State = 0;
byte OC_Prev = -1;
byte Motor_State = 0;
unsigned long System_StartFwdMtn = -1;
unsigned long System_EndFwdMtn = -1;
unsigned long System_StartBkwMtn = -1;
unsigned long System_EndBkwMtn = -1;
byte Motor_StopSignal = LOW;
byte Motor_RunSignal = HIGH;
byte Motor_RunForwd = 2;
byte Motor_RunBackw = 3;
byte OC_Covered = LOW;
byte OC_NonCovered = HIGH;
byte OC_CoverCount = 0;
unsigned long Motor_AvgCcleTime = 0;
bool debug = true;
void setup() {
// put your setup code here, to run once:
pinMode(OpcPin, INPUT);
pinMode(FwdPin, OUTPUT);
pinMode(BkwPin, OUTPUT);
Serial.begin(115200);
Serial.println();
Serial.println(" Let's ROCK!");
Serial.println();
Serial.println();
}
void debug_print(char str1[], unsigned long str2, char str3[]) {
if (!debug) return;
if (str1 != "") Serial.print(str1);
if (str2 != 0) Serial.print(str2);
if (str3 != "") Serial.print(str3);
Serial.println();
}
void Motor_Stop()
{
digitalWrite(FwdPin, Motor_StopSignal);
digitalWrite(BkwPin, Motor_StopSignal);
Motor_State = Motor_StopSignal;
}
void Motor_StartForward()
{
Motor_Stop();
digitalWrite(FwdPin, Motor_RunSignal);
Motor_State = Motor_RunForwd;
}
void Motor_StartBackward()
{
Motor_Stop();
digitalWrite(BkwPin, Motor_RunSignal);
Motor_State = Motor_RunBackw;
}
void System_Calibration()
{
switch (System_State) {
case 0:
debug_print("System not calibrated. Starting initial rotation backward.", 0, "");
Motor_StartBackward();
System_State = System_CalibrationStarted;
System_StartFwdMtn = 0;
System_StartBkwMtn = 0;
System_EndFwdMtn = 0;
System_EndBkwMtn = 0;
break;
case 1:
if (OC_State == OC_Covered) {
Motor_Stop();
System_State = System_InitExtremeFound;
TargetTimer = millis() + 2000;
debug_print("Initial extreme found. What next?", 0, "");
}
break;
case 2:
TargetTimer = millis() + 400;
Motor_StartForward();
System_StartFwdMtn = millis();
System_State = System_FindFwdExtreme;
debug_print("Started measurement rotation forward. Start forward time = ", System_StartFwdMtn, "");
break;
case 3:
if (OC_State == OC_Covered) {
System_EndFwdMtn = millis();
Motor_Stop();
System_State = System_ForwExtremeFound;
TargetTimer = millis() + 2000;
debug_print("Measurement rotation forward stopped. End forward time = ", System_EndFwdMtn, "");
}
break;
case 4:
TargetTimer = millis() + 400;
Motor_StartBackward();
System_StartBkwMtn = millis();
System_State = System_FindBkwExtreme;
debug_print("Started measurement rotation backward. Start backward time = ", System_StartBkwMtn, "");
break;
case 5:
if (OC_State == OC_Covered) {
System_EndBkwMtn = millis();
Motor_Stop();
System_State = System_BckwExtremeFound;
debug_print("Measurement rotation backward stopped. End backward time = ", System_EndBkwMtn, "");
}
break;
case 6:
Motor_AvgCcleTime = (System_EndFwdMtn - System_StartFwdMtn + System_EndBkwMtn - System_StartBkwMtn) / 2;
TargetTimer = millis() + int(Motor_AvgCcleTime / 4);
Motor_StartForward();
System_State = System_AvgCcleTimeFound;
debug_print("Average circle time calculated - ", Motor_AvgCcleTime, " millisecs.");
break;
case 7:
System_State = System_Calibrated;
debug_print("System calibrated?", 0, "");
break;
}
}
void loop() {
OC_State = digitalRead(OpcPin);
if (System_State < 0 or System_State > 8) System_State = System_NonCalibrated;
if (System_State != System_PrevState) {
debug_print("Current system state - ", System_State, "");
System_PrevState = System_State;
}
if (OC_Prev != OC_State) {
if (OC_State == OC_Covered) {
debug_print("Opto interrupter covered. Time: ", millis(), "");
if (System_State == System_Calibrated) OC_CoverCount++;
if (OC_CoverCount > 5) {
OC_CoverCount = 0;
if (System_State == System_Calibrated) System_State = System_NonCalibrated;
}
}
else {
debug_print("Opto interrupter not covered. Time: ", millis(), "");
}
OC_Prev = OC_State;
}
if (TargetTimer < millis()) if (System_State < System_Calibrated) {
System_Calibration();
}
if (System_State == System_Calibrated and Motor_AvgCcleTime <= 0) {
System_State = System_NonCalibrated;
debug_print("Average circle time corrupted, going to run calibration. Average circle: ", Motor_AvgCcleTime, ".");
}
yield();
}
Let's ROCK!
Current system state -
Opto interrupter not covered. Time: 61
System not calibrated. Starting initial rotation backward.
Current system state - 1
Opto interrupter covered. Time: 4927
Initial extreme found. What next?
Current system state - 2
Opto interrupter not covered. Time: 4927
Opto interrupter covered. Time: 4928
Started measurement rotation forward. Start forward time = 6928
Current system state - 3
Measurement rotation forward stopped. End forward time = 7329
Current system state - 4
Opto interrupter not covered. Time: 7678
Started measurement rotation backward. Start backward time = 9330
Current system state - 5
Opto interrupter covered. Time: 11689
Measurement rotation backward stopped. End backward time = 11689
Current system state - 6
Average circle time calculated - 1380 millisecs.
Current system state - 7
System calibrated?
Current system state - 8
Opto interrupter not covered. Time: 17653
Opto interrupter covered. Time: 20302
Opto interrupter not covered. Time: 20302
Opto interrupter covered. Time: 20302
Opto interrupter not covered. Time: 22919
Current system state -
Opto interrupter not covered. Time: 61
System not calibrated. Starting initial rotation backward.
Current system state - 1
Opto interrupter covered. Time: 4927
Initial extreme found. What next?
Current system state - 2
Opto interrupter not covered. Time: 4927
Opto interrupter covered. Time: 4928
Started measurement rotation forward. Start forward time = 6928
Current system state - 3
Measurement rotation forward stopped. End forward time = 7329
Current system state - 4
Opto interrupter not covered. Time: 7678
Started measurement rotation backward. Start backward time = 9330
Current system state - 5
Opto interrupter covered. Time: 11689
Measurement rotation backward stopped. End backward time = 11689
Current system state - 6
Average circle time calculated - 1380 millisecs.
Current system state - 7
System calibrated?
Current system state - 8
Opto interrupter not covered. Time: 17653
Opto interrupter covered. Time: 20302
Opto interrupter not covered. Time: 20302
Opto interrupter covered. Time: 20302
Opto interrupter not covered. Time: 22919
После окончания калибровки происходит просто регистрация факта закрытия/открытия оптопары. Однако, если система в состоянии "Откалибровано", после пятого открытия оптопары происходит сброс состояния и снова производится калибровка. Это сделано для проверки многократной системной отработки (короче, - для пущего тестирования).
Можно заметить в окне вывода, что открытие/закрытие оптопары происходит до странности многократно при одном движении флажка (флажок в данном случае кусочек картонки подносимый рукой). Почему это происходит следует понять, потому что это никак не сходится с задачей.
Далее, если подать питание на цепь управления двигателя, происходят чудеса - оптопара сама по себе срабатывает по многу раз в секунду, двигатель крутит то туда, то сюда вообще бессистемно.
Прошу просветить: Что я делаю не так?
ПЫС. Изначально код имел совсем другую структуру и включал переизбыток пауз. После указания со стороны о недопустимости перехвата цепи обработки процессов на долгое время, было решено перевести в формат отработки как можно меньших шагов и их обработки в дискретные значения времени. Таким образом получилось избавиться от постоянных перезагрузок контроллера. С той же целью был включен оператор yield(), но при текущем построении алгоритма, его использование оказалось избыточным.