Пауза между переключением направления двигателя

Я новичок как на этом форуме, так и в Arduino. Мой робот состоит из Arduino Uno с Arduino Motor Shield, мотор-редуктора 12 В постоянного тока и двух концевых выключателей. Робот должен был бесконечно двигаться по рельсам между двумя стенами взад-вперед. У меня все подключено, и я могу переключать направления вращения двигателя, нажимая концевые выключатели. Однако я также хочу, чтобы между переключением направлений была пауза:

... Робот движется вперед...

Если передний концевой выключатель нажат
Остановить двигатель
Пауза 2 секунды
Запустите двигатель против часовой стрелки

... Робот движется назад...

Если нажат задний концевой выключатель
Остановить двигатель
Пауза 2 секунды
Запустите двигатель по часовой стрелке

... Робот движется вперед...

Простая delay(2000) не работает, так как концевой выключатель остается прижатым к стене. Я пробовал подход millis(), но тот факт, что концевой выключатель остается нажатым (HIGH), я никогда не могу создать разницу во времени, необходимую для запуска действия. Я узнал о State Machine, но не уверен, может ли это помочь моему делу и как это сделать?

Может ли кто-нибудь помочь мне реализовать двухсекундную паузу между переключением направления вращения двигателя?

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

int switchFront_State = 0;
int switchRear_State = 0;

const int ledYellow = 6;
const int ledGreen = 5;

const int switchFront = 4;
const int switchRear = 2;

const int motorDirection = 12;
const int motorBreak = 9;
const int motorPWM = 3;

void setup() {
  Serial.begin (9600);

  pinMode(switchFront, INPUT_PULLUP); // Передний переключатель
  pinMode(switchRear, INPUT_PULLUP); // Задний переключатель

  pinMode(ledYellow, OUTPUT);
  pinMode(ledGreen, OUTPUT);

  // Настройка канала А
  pinMode(motorDirection, OUTPUT); // Контакт направления двигателя
  pinMode(motorBreak, OUTPUT); // Размыкающий штифт двигателя
  pinMode(motorPWM, OUTPUT); // вывод ШИМ двигателя
}

void runMotorBackward(){ // Двигатель движется назад
  digitalWrite(motorDirection, LOW);
  digitalWrite(motorBreak, LOW);
  digitalWrite(motorPWM, 128);
}

void motorStop(){ // Останов двигателя
  digitalWrite(motorBreak, HIGH);
  digitalWrite(motorPWM, 0);
}

void runMotorForward(){ // Двигатель движется вперед
  digitalWrite(motorDirection, HIGH);
  digitalWrite(motorBreak, LOW);
  digitalWrite(motorPWM, 128);
}

void loop(){
  switchFront_State = digitalRead (switchFront);
  switchRear_State = digitalRead (switchRear);

  if (switchFront_State == HIGH){ // Если передний переключатель нажат
    digitalWrite(ledYellow, HIGH); // желтый светодиод
    motorStop();
    runMotorBackward();
    } else {
    digitalWrite(ledYellow, LOW);
  }

  if (switchRear_State == HIGH){ // Если нажат задний переключатель
    digitalWrite(ledGreen, HIGH); // Зеленый светодиод
    motorStop();
    runMotorForward();
  } else {
    digitalWrite(ledGreen, LOW);
  }
}

, 👍3

Обсуждение

Рассматривали ли вы использование полного конечного автомата, а не просто определение состояний переключателей?, @Ignacio Vazquez-Abrams

Я не понимаю, почему задержка (2000) работает?, @Gerben

Gerben, задержка (2000) работает, но она требует, чтобы концевой выключатель был в положении LOW, чтобы двигатель снова заработал. Первоначально я попытался поместить задержку (2000) между motorStop() и runMotorForward() / runMotorBackward(), что сработало, но не очень удобно для меня. Другими словами, задержка сработает, если концевой выключатель будет нажат (HIGH), но двигатель не запустится снова, пока концевой выключатель снова не будет отпущен (LOW)., @Dragan Miletic

Игнасио Васкес-Абрамс, я не уверен, что вы имеете в виду под "полной государственной машиной"? Как я уже сказал, я новичок в Arduino и программировании в целом., @Dragan Miletic


2 ответа


Лучший ответ:

3

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

int direction_state = 1; //сообщение, где робот движется вперед

void loop(){

/*отмечает, что здесь я предполагаю, что пока робот движется вперед,
* задний переключатель невозможно нажать, как и во время
*робот движется назад, передний переключатель невозможен
* нажата.
*/

  while ((digitalRead (switchRear)==LOW) && (digitalRead (switchFront)==LOW))
  // переключатель не нажат, цикл прервется, если нажат любой переключатель
    {
      if (direction_state == 1) runMotorForward(); else
                                runMotorBackward();
    }

  //индикатор, какой переключатель нажат и запуск 2-х секундного мотора останавливается
  if (direction_state==1) digitalWrite(ledYellow,HIGH); 
  else digitalWrite(ledGreen,HIGH);

  motorStop(); // останавливаем мотор
  delay(2000);

  //индикатор 2с двигатель останавливается закончено
  if (direction_state==1) digitalWrite(ledYellow,LOW); //нажат передний переключатель индикатора
  else digitalWrite(ledGreen,LOW);

  direction_state = -direction_state //переключить состояние
  if (direction_state == 1) runMotorForward(); else
                            runMotorBackward();

  delay(2000);

}    

Не стесняйтесь спрашивать, если это не работает

,

Что ж, ваше предложение выше - это именно то, что не работает, добавление ie delay(2000); после runMotorForward() / runMotorBackward() вообще не срабатывает. Первоначально я попытался поместить задержку (2000) между motorStop() и runMotorForward() / runMotorBackward(), что сработало, но не очень удобно для меня. Другими словами, задержка сработает, если концевой выключатель будет нажат (HIGH), но двигатель не запустится снова, пока концевой выключатель снова не будет отпущен (LOW). Как я описал выше, это не вариант, так как робот застрянет при первом же достижении стены. Второй код не имеет паузы?, @Dragan Miletic

dpw, если вы посмотрите на мой код, вы поймете, что нажатие на любой из концевых выключателей (вручную) приведет робота в движение. Я включаю робота, он не движется, затем я нажимаю, скажем, передний концевой выключатель, и робот немедленно начинает двигаться назад, ударяется о заднюю стенку, меняет направление, бежит к передней стене, ударяется о переднюю стенку, меняет направление... , бесконечно или до тех пор, пока на него подается питание. Все, что я хочу, это чтобы робот останавливался на две секунды, когда ударяется о стену, а не просто «отскакивал» от нее., @Dragan Miletic

Привет, Драган, я отредактировал ответы. Возможно, вы можете попробовать это, @dhimaspw

Привет dpw, большое спасибо за исправленный код. Я загрузил его, и он работает ТОЧНО так, как я хочу!!! Кстати, можно ли сделать так, чтобы switchRear переключал двигатель только на движение вперед, и аналогично, чтобы switchFront переключал двигатель только на движение назад. На данный момент направления могут быть перепутаны, если случайно нажать «неправильный» переключатель., @Dragan Miletic

Конечно, можно, вы можете изменить условие "пока". Рад, что могу помочь, и удачи вашему проекту, @dhimaspw

Привет друзья, что-то пошло не так с моим роботом после того, как я поменял мотор. Внезапно приведенный выше код, предоставленный dhimaspw, перестал работать правильно!? При включении робот начинает работать вперед в течение 2 секунд, останавливается на 2 секунды, начинает работать в обратном направлении в течение 2 секунд и т. д.??? Раньше он работал до тех пор, пока не получит сигнал от одного из двух концевых выключателей. Схема осталась нетронутой, за исключением нового мотора, который меня очень сбивает с толку., @Dragan Miletic

Было бы лучше, если бы вы разместили еще один вопрос и разместили там подробности о своем двигателе., @dhimaspw


0

Вы должны сделать логику коммутатора чувствительной к фронту, а не к состоянию. (Это термин, используемый в цифровой электронике.) Это означает, что вам нужно реагировать на переход от выключения к включению, а не на включение переключателя. (Поскольку вы используете режим INPUT_PULLUP, переключатель = LOW.

Итак:

Не используйте в своем цикле

switchFront_State = digitalRead (switchFront);

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

int newSwitchState = digitalRead (switchFront);
if (newSwitchState == LOW && newSwitchState  != switchFront_State) {
    switchFront_State = newSwitchState;
    //Код для обработки нажатия концевого выключателя
} else if (newSwitchState == HIGH && newSwitchState  != switchFront_State) {
    switchFront_State = newSwitchState;
    //Код для обработки перехода переключателя в выключенное состояние
}

Возможно, вам также потребуется использовать millis() для устранения дребезга на вашем коммутаторе. (Игнорируйте изменения переключателя, если не прошло 10-20 миллисекунд, чтобы избежать дрожания переключателя при его первоначальном нажатии или отпускании.)

,