Приветствую. Пытаюсь написать обработчик для энкодела, чтобы при натыкании вала мотора с энкодером на препятствие, он начинал вращаться в обратном направлении. Кое что у меня получилось (код приведу ниже), но энкодер не достаточно чувствителен с таким кодом. Хотел бы узнать как можно сделать так, чтобы при малейшем замедлении штатной скорости вращения вала мотора (но не на долю секунды, чтобы не было ложных срабатываний), ардуино это фиксировало и давало команду на вращение вала мотора в обратном направлении?
Пока пошел по такому принципу, как изложу далее, но может знающие люди подскажут более оптимальный принцип. С помощью прерываний в переменную "Step" записывается количество тиков энкодера. Затем раз в 25мс запоминается предыдущее значение переменной "Step" в переменную "Step_Compare". А потом появляется 3-я переменная "Step_Compared_Val", в которой от текущего количества тиков энкодера в переменной "Step" отнимается предыдущее значение, которое находится в переменной "Step_Compare". То есть "Step_Compared_Val = Step - Step_Compare;" И срабатывание вращения в обратном направлении происходит когда "Step_Compared_Val" уменьшается на несколько пунктов. Например "Step_Compared_Val = 30" и в прерываниях это считывается, и если оно меньше чем 28, происходит реверс.
Но в этом принципе или его реализации есть два минуса:
1) Прежде чем "Step_Compared_Val" упадёт на 2 пункта, мотор может достаточно сильно прижать препятствие. А если сделать чтобы срабатывание обратного хода вала было при снижении на 1 пункт, то происходят ложные срабатывания. То есть он не достаточно чувствительный. Мне кажется надо запрограммировать чтобы срабатывание реверса вала было когда замедление вала об препятствие продолжалось какое-то время, например 50-100мс, но мои попытки реализовать эту идею не увенчались успехом.
2) С изменением скорости вращения вала меняется и значение переменной "Step_Compared_Val". Как вы увидите в коде ниже, я сравниваю эту переменную с "жестким числом". И при изменении скорости вала мотора в большую сторону, реверс может вообще не сработать. Хотелось бы узнать как можно динамически задавать это число, чтобы оно подстраивалось под переменную, но с разницей в два пункта, например (мои попытки так сделать не удались).
Вот сам код:
Пока пошел по такому принципу, как изложу далее, но может знающие люди подскажут более оптимальный принцип. С помощью прерываний в переменную "Step" записывается количество тиков энкодера. Затем раз в 25мс запоминается предыдущее значение переменной "Step" в переменную "Step_Compare". А потом появляется 3-я переменная "Step_Compared_Val", в которой от текущего количества тиков энкодера в переменной "Step" отнимается предыдущее значение, которое находится в переменной "Step_Compare". То есть "Step_Compared_Val = Step - Step_Compare;" И срабатывание вращения в обратном направлении происходит когда "Step_Compared_Val" уменьшается на несколько пунктов. Например "Step_Compared_Val = 30" и в прерываниях это считывается, и если оно меньше чем 28, происходит реверс.
Но в этом принципе или его реализации есть два минуса:
1) Прежде чем "Step_Compared_Val" упадёт на 2 пункта, мотор может достаточно сильно прижать препятствие. А если сделать чтобы срабатывание обратного хода вала было при снижении на 1 пункт, то происходят ложные срабатывания. То есть он не достаточно чувствительный. Мне кажется надо запрограммировать чтобы срабатывание реверса вала было когда замедление вала об препятствие продолжалось какое-то время, например 50-100мс, но мои попытки реализовать эту идею не увенчались успехом.
2) С изменением скорости вращения вала меняется и значение переменной "Step_Compared_Val". Как вы увидите в коде ниже, я сравниваю эту переменную с "жестким числом". И при изменении скорости вала мотора в большую сторону, реверс может вообще не сработать. Хотелось бы узнать как можно динамически задавать это число, чтобы оно подстраивалось под переменную, но с разницей в два пункта, например (мои попытки так сделать не удались).
Вот сам код:
C++:
#define INTERRUPT_PIN 2 /* Пин прерываний */
#define ENCODER 50 /* Сигнальный пин энкодера на моторе */
int Start_Motor_Button; /* Кнопка запуска мотора */
int Rotate_Back = 4; /* Вращение вала мотора по часовой стрелке */
int Rotate_Forward = 13; /* Вращение вала мотора против часовой стрелки */
int Motor_State = 0;
long Step = 0; /* Переменная для запоминания количества тиков с энкодера */
long Step_Compare = 0; /* Переменная для запоминания предыдущего кол-ва тиков с энкодера */
long Step_Compared_Val = 0; /* Переменная для получения разницы с предыдущих двух переменных */
long Compare_Time = 0;
void setup() {
pinMode(Rotate_Back, OUTPUT);
pinMode(Rotate_Forward, OUTPUT);
pinMode(Start_Motor_Button, INPUT);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), Read_Enc, RISING);
Serial.begin(9600);
}
void loop() {
Start_Motor_Button = digitalRead(41);
if (Start_Motor_Button == HIGH) { Motor_State = 1; }
switch (Motor_State)
{
case 1:
rotate_Forward();
break;
case 2:
rotate_Back();
break;
}
}
void Read_Enc() { /* Функция считывания тиков энкодера по прерыванию */
if (digitalRead(ENCODER))
{
Step++;
if (Step_Compared_Val < 29) { Motor_State = 2; } /* При свободном вращении Step_Compared_Val имеет значение 30-31 */
}
}
void rotate_Forward() {
analogWrite(Rotate_Back, LOW);
analogWrite(Rotate_Forward, 200);
Step_Compared_Val = Step - Step_Compare;
if (millis() - Compare_Time >= 25)
{
Step_Compare = Step;
Compare_Time = millis();
Serial.print("Шаг сравнения энкодера: ");
Serial.println(Step_Compared_Val); /* Почему-то когда убираю эту строчку, пропадает реакция на препятствие.
Возможно это глюк версии Arduino IDE 1.8.16? */
}
}
void rotate_Back() {
analogWrite(Rotate_Back, 200);
analogWrite(Rotate_Forward, LOW);
}