Как заставить автомобиль повернуться на 90 градусов?

У меня есть модель автомобиля elegoo, и я пытаюсь заставить его поворачиваться на 90 градусов всякий раз, когда он поворачивается на 90 градусов. Эта модель имеет трассировку линий и прекрасно работает на криволинейных поверхностях, но не работает на поворотах на 90 градусов.

    /Line Tracking IO define
#define LT_R !digitalRead(10)//подключен к контакту 10. Значение инвертируется
#define LT_M !digitalRead(4)
#define LT_L !digitalRead(2)
 
#define ENA 5//вход для включения двигателя A. Контролирует скорость
#define ENB 6//вход для включения двигателя B
#define IN1 7//Управление направлением вращения двигателя A. Если один из них имеет высокое вращение двигателя(затвор ИЛИ)
#define IN2 8//Тот же двигатель A
#define IN3 9//3 и 4 для двигателя В
#define IN4 11
 
#define carSpeed 100
 
void forward(){ //car goes forward
  analogWrite(ENA, carSpeed);
  analogWrite(ENB, carSpeed);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  Serial.println("go forward!");
}
 
void back(){ //car goes backwards
  analogWrite(ENA, carSpeed);
  analogWrite(ENB, carSpeed);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  Serial.println("go back!");
}
 
void left(){ //goes left
  analogWrite(ENA, carSpeed);
  analogWrite(ENB, carSpeed);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  Serial.println("go left!");
}
 
void right(){ //goes right
  analogWrite(ENA, carSpeed);
  analogWrite(ENB, carSpeed);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW); 
  Serial.println("go right!");
} 
 
void stop(){ //питание отключено 
   digitalWrite(ENA, LOW);
   digitalWrite(ENB, LOW);
   Serial.println("Stop!");
} 
 
void setup(){
  Serial.begin(9600);
  pinMode(LT_R,INPUT);//принимает входные данные от всех датчиков
  pinMode(LT_M,INPUT);
  pinMode(LT_L,INPUT);
}

void loop() {
 
  if(LT_M){
    forward();
    while(LT_M);
  }
  else if(LT_R) { 
    right();    
    while(LT_R);                          
  }   
  else if(LT_L) {
    left(); 
    while(LT_L);
  }

  else if (LT_M && LT_R && !LT_L) {
  delay(500);
  right();   
  } 
  
  else if (LT_L && LT_R && !LT_R) {
   delay(500);
   left();    
    }

, 👍2

Обсуждение

Ваш код не завершен. Иногда вы используете контакты " ENA " и " ENB " с "digitalWrite", а иногда с "analogWrite". "#define LT_R !digitalRead(10) - это определение макрокоманды: Итак, что означает pinMode(LT_R,INPUT);`? Мне интересно, почему некоторые части этой программы работают., @Peter Paul Kiefer

Петерполкифер прав с утверждениями pinMode. Это позволит настроить только вывод 0 или 1 в качестве входного. Это не может работать так, как вы хотели. Скорее всего, вы извлекаете выгоду из того факта, что при запуске все контакты уже настроены в качестве входных данных., @chrisl


1 ответ


1

Во-первых: Ваш код как 2 проблемы:

  • Как указано в комментариях PeterPaulKiefer, когда вы используете

      pinMode(LT_R,INPUT);
    

    Это работает не так, как вы задумали. LT_R определяется вверху как

      #define LT_R !digitalRead(10)
    

    Таким образом, компилятор увидит

      pinMode(!digitalRead(10), INPUT);
    

    digitalRead() вернет ноль или единицу, поэтому здесь вы настраиваете вывод 0 или вывод 1 (в зависимости от состояния датчика при запуске). Вместо этого вам нужно напрямую использовать ПИН (10) или использовать другое определение для самого ПИН. Ваш код работает только потому, что все контакты настроены как ВХОДНЫЕ (tristate) при запуске микроконтроллера, чтобы они не сломали что-то неправильным сигналом. Тебе там повезло.

  • Последние два оператора if никогда не выполняются:

      else if (LT_M && LT_R && !LT_L) {
          delay(500);
          right();   
      }
      else if (LT_L && LT_R && !LT_R) {
          delay(500);
          left();    
      }
    

    Условия здесь сначала будут оценивать LT_M (в первом операторе) и LT_L (во втором операторе) соответственно. Только если они верны, будет вычислена остальная часть выражения. Но вы уже проверили, что оба они верны выше. Когда они есть, следующие операторы if не выполняются (такова логика операторов if else). И если они окажутся ложными, код также не будет выполнен.

    Когда вы дойдете до правого угла под углом 90°, сработает средний и правый датчики. В настоящее время это приведет к тому, что робот просто продолжит двигаться вперед.

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

Также имейте в виду, что острый угол требует гораздо большего поворота, чем поворот. В зависимости от ширины линии и расстояния между вашими датчиками вы можете различать или не различать эти два случая. Вы должны проанализировать, какие состояния датчиков у вас будут в каких ситуациях, записать это, а затем написать код для каждого состояния. Вы также можете поместить все состояния датчика в одно единственное число, чтобы его было легче проверить в коде. Что-то вроде этого:

byte all_states = digitalRead(2) + 2*digitalRead(4) + 4*digitalRead(10);

Каждая комбинация даст вам уникальный номер для работы. Эффективно это сохраняет состояния датчиков в одном бите числа каждый. Бит 0 предназначен для вывода 2, бит 1 предназначен для вывода 4, а бит 2 предназначен для вывода 10. Вы также можете написать это с помощью побитовых операторов:

byte all_states = digitalRead(2) | (digitalRead(4)<<1) | (digitalRead(10)<<2);

Например: Если сработает нужный датчик, но не остальные, вы получите двоичное число 0b00000100, которое равно 4 десятичным. Если срабатывают левый и средний датчики, но не правый, это приводит к 0b00000011, что равно 3 после запятой. Затем вы можете проверить с помощью инструкции switch:

switch(all_states){
    case 0: //Датчики не срабатывают
        break;
    case 1: // Сработал левый датчик
        break;
    case 2: // срабатывание среднего датчика
        break;
    case 3: // сработали средний и левый датчики
        break;
    ...
}

Вы видите, как это работает. Затем код для каждого случая помещается между каждым случаем и строкой разрыва.

,