Проект 11: Робот который ездит по линии

Этот проект основан на роботе, собранном из набора 4WD Smart Car Kit, который будет следовать за линией и выполнять различные виды поворотов с помощью четырех датчиков линии. Используя управление двумя моторами через библиотеку AlashMotorControlX2, робот будет обнаруживать и следовать за черной линией на белом фоне. В этом проекте робот будет выполнять нормальные и резкие повороты в зависимости от показаний датчиков линии.

Принцип работы

Датчики линии определяют, находится ли робот на линии или вне ее. В зависимости от показаний датчиков, Arduino принимает решение о направлении движения робота: вперед, налево, направо, резкий поворот налево или резкий поворот направо. Моторы управляются через библиотеку AlashMotorControlX2.

Необходимые компоненты

  • Arduino Uno

  • 4 датчика линии

  • Модуль драйвера двигателя L298N или TA6586

  • 2 DC мотора

  • Источник питания

  • Шасси робота с колесами

  • Трасса с черной линией на белом фоне

Подключение компонентов

Подключение датчиков линии:

  • Крайний левый датчик → пин 2

  • Центральный левый датчик → пин 3

  • Центральный правый датчик → пин 4

  • Крайний правый датчик → пин 12

  • VCC → 5V Arduino

  • GND → GND Arduino

Подключение модуля L298N:

  • ENA → пин 10 (управление скоростью левого мотора)

  • IN1 → пин 9 (направление левого мотора)

  • IN2 → пин 8 (направление левого мотора)

  • IN3 → пин 7 (направление правого мотора)

  • IN4 → пин 6 (направление правого мотора)

  • ENB → пин 5 (управление скоростью правого мотора)

  • VCC → 5V Arduino

  • GND → GND Arduino

  • VM → внешний источник питания

Настройка чувствительности датчиков линии

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

Настройка чувствительности датчиков:

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

  2. Для точной настройки датчиков можно использовать специальный проект «Датчик линии», в котором подробно описан процесс настройки чувствительности датчиков. Обратитесь к этому проекту для получения более детальной информации.

Тестирование и корректировка:

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

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

  3. Продолжайте регулировать настройки, пока робот не начнет двигаться идеально по линии.

Алгоритм работы

Робот работает по следующему алгоритму:

  1. Считывание датчиков - все 4 датчика линии считывают состояние поверхности

  2. Анализ положения - определяется, на какой части линии находится робот

  3. Выбор действия: - Все датчики на белом → движение вперед - Центральный левый на черном → поворот налево - Центральный правый на черном → поворот направо - Крайний левый на черном → резкий поворот налево - Крайний правый на черном → резкий поворот направо

  4. Выполнение действия - робот выполняет выбранное движение

  5. Повторение - цикл повторяется

Пример кода для L298N

// Подключаем библиотеку
#include <AlashMotorControlX2.h>

// Определение пинов для моторов (стиль AlashMotorControlX2)
// Мотор A - Левый мотор
const unsigned int PIN_IN1_A = 9;  // Пин IN1 левого мотора (Логика HIGH = вперед для мотора A)
const unsigned int PIN_IN2_A = 8;  // Пин IN2 левого мотора (Логика LOW = вперед для мотора A)
const unsigned int PIN_EN_A  = 10; // Пин Enable (PWM) левого мотора - должен быть PWM-пином!

// Мотор B - Правый мотор
const unsigned int PIN_IN1_B = 7;  // Пин IN1 правого мотора (Логика HIGH = вперед для мотора B)
const unsigned int PIN_IN2_B = 6;  // Пин IN2 правого мотора (Логика LOW = вперед для мотора B)
const unsigned int PIN_EN_B  = 5;  // Пин Enable (PWM) правого мотора - должен быть PWM-пином!

// Инициализация двух моторов для L298N с PWM (Enable пинами)
// Используем конструктор с 6 параметрами
AlashMotorControlX2 motors(PIN_IN1_A, PIN_IN2_A, PIN_EN_A,
                           PIN_IN1_B, PIN_IN2_B, PIN_EN_B,
                           DRIVER_L298N, // Явно указываем тип драйвера (по умолчанию L298N)
                           DRIVER_L298N);

// Определение пинов для датчиков линии
const unsigned int SENSOR_EXTREME_LEFT = 2;  // Крайний левый датчик
const unsigned int SENSOR_CENTER_LEFT = 3;   // Центральный левый датчик
const unsigned int SENSOR_CENTER_RIGHT = 4;  // Центральный правый датчик
const unsigned int SENSOR_EXTREME_RIGHT = 12; // Крайний правый датчик

// Определение состояний робота
#define STATE_FORWARD     0
#define STATE_RIGHT       1
#define STATE_LEFT        2
#define STATE_SUPER_RIGHT 3
#define STATE_SUPER_LEFT  4
#define STATE_STOP        5

int state = STATE_FORWARD; // Начальное состояние

// Параметры скорости
int SpeedAll = 80;           // Базовая скорость (0-255)
int SuperTurnSpeedAll = 150; // Скорость для резких поворотов (0-255)
int TurnSpeedAll = 100;      // Скорость для обычных поворотов (0-255)

// Переменные для хранения состояния датчиков
boolean centerLeftActive = false;
boolean centerRightActive = false;
boolean extremeLeftActive = false;
boolean extremeRightActive = false;

void setup() {
  Serial.begin(9600); // Инициализация последовательного порта
  while (!Serial) {
    ; // Ожидание открытия Serial Monitor
  }
  Serial.println("Line Follower - AlashMotorControlX2 (L298N with PWM)");

  // Установка пинов датчиков как входы
  pinMode(SENSOR_EXTREME_LEFT, INPUT);
  pinMode(SENSOR_CENTER_LEFT, INPUT);
  pinMode(SENSOR_CENTER_RIGHT, INPUT);
  pinMode(SENSOR_EXTREME_RIGHT, INPUT);

  // Установка начальной скорости
  motors.setSpeed(SpeedAll);
  Serial.println("Setup complete.");
}

void loop() {
  // Чтение состояния датчиков линии
  extremeLeftActive = (digitalRead(SENSOR_EXTREME_LEFT) == HIGH);
  centerLeftActive = (digitalRead(SENSOR_CENTER_LEFT) == HIGH);
  centerRightActive = (digitalRead(SENSOR_CENTER_RIGHT) == HIGH);
  extremeRightActive = (digitalRead(SENSOR_EXTREME_RIGHT) == HIGH);

  // Определение целевого состояния
  int targetState;
  if (centerLeftActive == centerRightActive && extremeLeftActive == extremeRightActive) {
    targetState = STATE_FORWARD;
  } else if (centerLeftActive) {
    targetState = STATE_LEFT;
  } else if (centerRightActive) {
    targetState = STATE_RIGHT;
  } else if (extremeLeftActive) {
    targetState = STATE_SUPER_LEFT;
  } else if (extremeRightActive) {
    targetState = STATE_SUPER_RIGHT;
  } else {
    targetState = STATE_FORWARD; // По умолчанию вперед
  }

  // Вывод информации о состоянии
  Serial.println(targetState);

  // Если состояние не изменилось, выходим из текущей итерации loop
  if (state == targetState) {
    return;
  }

  // Обновляем состояние и выполняем соответствующее действие
  state = targetState;

  switch (state) {
    case STATE_FORWARD:
      goForward();
      Serial.println("F");
      break;
    case STATE_RIGHT:
      turnRight();
      Serial.println("R");
      break;
    case STATE_LEFT:
      turnLeft();
      Serial.println("L");
      break;
    case STATE_SUPER_RIGHT:
      turnSuperRight();
      Serial.println("SR");
      break;
    case STATE_SUPER_LEFT:
      turnSuperLeft();
      Serial.println("SL");
      break;
    case STATE_STOP:
      stopMotors();
      Serial.println("S");
      break;
  }

  delay(50); // Задержка
}

// Функции управления движением
void goForward() {
  motors.setSpeed(SpeedAll);
  motors.forward();
}

void turnLeft() {
  int turnSpeed = constrain(SpeedAll + TurnSpeedAll, 0, 255);
  motors.setSpeedA(turnSpeed);
  motors.setSpeedB(turnSpeed);
  motors.backwardA();
  motors.forwardB();
}

void turnRight() {
  int turnSpeed = constrain(SpeedAll + TurnSpeedAll, 0, 255);
  motors.setSpeedA(turnSpeed);
  motors.setSpeedB(turnSpeed);
  motors.forwardA();
  motors.backwardB();
}

void turnSuperLeft() {
  int superTurnSpeed = constrain(SpeedAll + SuperTurnSpeedAll, 0, 255);
  motors.setSpeedA(superTurnSpeed);
  motors.setSpeedB(superTurnSpeed);
  motors.backwardA();
  motors.forwardB();
}

void turnSuperRight() {
  int superTurnSpeed = constrain(SpeedAll + SuperTurnSpeedAll, 0, 255);
  motors.setSpeedA(superTurnSpeed);
  motors.setSpeedB(superTurnSpeed);
  motors.forwardA();
  motors.backwardB();
}

void stopMotors() {
  motors.stop();
}

Пример кода для TA6586

// Подключаем библиотеку
#include <AlashMotorControlX2.h>
#include <AlashMotorDriverType.h> // Подключаем для использования DRIVER_TA6586

// Определение пинов для моторов TA6586
// ВАЖНО: Для TA6586 пины IN1 и IN2 ДОЛЖНЫ быть PWM-пинами!
// Пример для Arduino Uno/Nano (PWM пины: 3, 5, 6, 9, 10, 11)

// Мотор A - Левый мотор
const unsigned int PIN_IN1_A = 9; // Пин IN1 для левого мотора (PWM)
const unsigned int PIN_IN2_A = 10; // Пин IN2 для левого мотора (PWM)
// Пин Enable НЕ используется для TA6586

// Мотор B - Правый мотор
const unsigned int PIN_IN1_B = 5; // Пин IN1 для правого мотора (PWM)
const unsigned int PIN_IN2_B = 6; // Пин IN2 для правого мотора (PWM)
// Пин Enable НЕ используется для TA6586

// Инициализация двух моторов для драйвера TA6586
AlashMotorControlX2 motors(PIN_IN1_A, PIN_IN2_A, // Пины мотора A
                           PIN_IN1_B, PIN_IN2_B, // Пины мотора B
                           DRIVER_TA6586, // Тип драйвера для мотора A
                           DRIVER_TA6586); // Тип драйвера для мотора B

// Определение пинов для датчиков линии
const unsigned int SENSOR_EXTREME_LEFT = 2;
const unsigned int SENSOR_CENTER_LEFT = 3;
const unsigned int SENSOR_CENTER_RIGHT = 4;
const unsigned int SENSOR_EXTREME_RIGHT = 12;

// Определение состояний робота
#define STATE_FORWARD 0
#define STATE_RIGHT 1
#define STATE_LEFT 2
#define STATE_SUPER_RIGHT 3
#define STATE_SUPER_LEFT 4
#define STATE_STOP 5

int state = STATE_FORWARD; // Начальное состояние робота

// Параметры скорости
int SpeedAll = 80;
int SuperTurnSpeedAll = 150;
int TurnSpeedAll = 100;

// Переменные для хранения состояния датчиков
boolean right = false; // Активен центральный правый датчик
boolean left = false; // Активен центральный левый датчик
boolean Sright = false; // Активен крайний правый датчик
boolean Sleft = false; // Активен крайний левый датчик

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // Ожидание открытия Serial Monitor
  }
  Serial.println("Line Follower Robot - AlashMotorControlX2 (TA6586 Driver)");

  // Установка пинов датчиков как входы
  pinMode(SENSOR_EXTREME_LEFT, INPUT);
  pinMode(SENSOR_CENTER_LEFT, INPUT);
  pinMode(SENSOR_CENTER_RIGHT, INPUT);
  pinMode(SENSOR_EXTREME_RIGHT, INPUT);

  Serial.println("Setup complete. Starting loop...");
}

void loop() {
  // Чтение состояния датчиков линии
  Sleft = (digitalRead(SENSOR_EXTREME_LEFT) == HIGH);
  left = (digitalRead(SENSOR_CENTER_LEFT) == HIGH);
  right = (digitalRead(SENSOR_CENTER_RIGHT) == HIGH);
  Sright = (digitalRead(SENSOR_EXTREME_RIGHT) == HIGH);

  // Определение целевого состояния
  int targetState;
  if (left == right && Sleft == Sright) targetState = STATE_FORWARD;
  else if (left) targetState = STATE_LEFT;
  else if (right) targetState = STATE_RIGHT;
  else if (Sleft) targetState = STATE_SUPER_LEFT;
  else if (Sright) targetState = STATE_SUPER_RIGHT;
  else targetState = STATE_FORWARD;

  // Если состояние не изменилось, ничего не делаем
  if (state == targetState) {
    return;
  }

  // Обновляем состояние и выполняем соответствующее действие
  state = targetState;

  switch (state) {
    case STATE_FORWARD:
      forward();
      break;
    case STATE_RIGHT:
      rightTurn();
      break;
    case STATE_LEFT:
      leftTurn();
      break;
    case STATE_SUPER_RIGHT:
      superRightTurn();
      break;
    case STATE_SUPER_LEFT:
      superLeftTurn();
      break;
    case STATE_STOP:
      stopMotors();
      break;
  }
  delay(10);
}

// Функции управления движением для TA6586
void forward() {
  int constrainedSpeed = constrain(SpeedAll, 0, 255);
  motors.setSpeed(constrainedSpeed);
  motors.forward();
}

void leftTurn() {
  int turnSpeed = constrain(SpeedAll + TurnSpeedAll, 0, 255);
  motors.setSpeedA(turnSpeed);
  motors.setSpeedB(turnSpeed);
  motors.backwardA();
  motors.forwardB();
}

void rightTurn() {
  int turnSpeed = constrain(SpeedAll + TurnSpeedAll, 0, 255);
  motors.setSpeedA(turnSpeed);
  motors.setSpeedB(turnSpeed);
  motors.forwardA();
  motors.backwardB();
}

void superLeftTurn() {
  int superTurnSpeed = constrain(SpeedAll + SuperTurnSpeedAll, 0, 255);
  motors.setSpeedA(superTurnSpeed);
  motors.setSpeedB(superTurnSpeed);
  motors.backwardA();
  motors.forwardB();
}

void superRightTurn() {
  int superTurnSpeed = constrain(SpeedAll + SuperTurnSpeedAll, 0, 255);
  motors.setSpeedA(superTurnSpeed);
  motors.setSpeedB(superTurnSpeed);
  motors.forwardA();
  motors.backwardB();
}

void stopMotors() {
  motors.stop();
}

Результат работы

После загрузки кода робот будет:

  • Двигаться вперед, когда все датчики находятся на белой поверхности

  • Поворачивать налево при обнаружении линии центральным левым датчиком

  • Поворачивать направо при обнаружении линии центральным правым датчиком

  • Выполнять резкий поворот налево при обнаружении линии крайним левым датчиком

  • Выполнять резкий поворот направо при обнаружении линии крайним правым датчиком

Настройка параметров

Для оптимизации работы робота можно изменить следующие параметры:

  • Базовая скорость: Измените SpeedAll для регулировки скорости движения вперед

  • Скорость поворота: Измените TurnSpeedAll для настройки скорости обычных поворотов

  • Скорость резкого поворота: Измените SuperTurnSpeedAll для настройки скорости резких поворотов

  • Задержка цикла: Измените delay(50) для настройки частоты обновления состояния

Заключение

Этот проект позволяет создать робота, который следует за линией и выполняет различные виды поворотов, используя четыре датчика линии и библиотеку AlashMotorControlX2 для управления моторами. Важно правильно настроить чувствительность датчиков линии и отрегулировать скорость робота, чтобы он мог корректно следовать за линией.

Для более детальной информации по настройке датчиков линии обратитесь к проекту «Датчик линии». Экспериментируйте с настройками и компонентами, чтобы убедиться, что робот работает корректно и следует за линией.