Проект 2: Управление моторами L298N

Управление моторами робота Фобо

Введение

Робот Фобо собран! Пора научить его двигаться! 🚗

В Проекте 1 вы собрали робота и подключили все компоненты. Теперь напишем код для управления моторами через драйвер L298N.

Примечание

Предварительные требования: Робот Фобо полностью собран (Проект 1), батареи заряжены

Как работает L298N

Драйвер моторов L298N получает команды от Arduino и управляет моторами, используя питание от батарей.

Управление: - IN1, IN2 — направление Motor A (правые моторы) - IN3, IN4 — направление Motor B (левые моторы) - ENA, ENB — скорость (ШИМ 0-255)

Управление направлением (IN1-IN4)

L298N имеет 2 канала (Motor A и Motor B), каждый управляется двумя входами:

IN1/IN3

IN2/IN4

Результат

HIGH

LOW

Вращение вперёд

LOW

HIGH

Вращение назад

LOW

LOW

Стоп (свободное вращение)

HIGH

HIGH

Стоп (тормоз)

Пример:

// Motor A вперёд
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);

// Motor B назад
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);

Управление скоростью (ENA, ENB)

ШИМ (PWM) управляет скоростью мотора через analogWrite():

  • ENA (D5) — скорость левых моторов

  • ENB (D6) — скорость правых моторов

  • Значения: 0 (стоп), 127 (50%), 255 (100%)

analogWrite(ENA, 180);  // Средняя скорость
analogWrite(ENA, 255);  // Полная скорость

Первое движение

Создадим программу для движения вперёд.

Полный код:

/*
 * Проект 2: Управление моторами L298N
 * Первый тест движения робота Фобо
 */

// Определение пинов для моторов
const int IN1 = 4;   // Направление Motor A (правая сторона)
const int IN2 = 2;
const int IN3 = 8;  // Направление Motor B (левая сторона)
const int IN4 = 12;
const int ENA = 5;   // ШИМ скорость Motor A (правые)
const int ENB = 6;   // ШИМ скорость Motor B (левые)

void setup() {
  // Настройка всех пинов как OUTPUT
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);

  Serial.begin(9600);
  Serial.println("========================================");
  Serial.println("  Робот Фобо: Тест моторов");
  Serial.println("========================================");
}

void moveForward(int speed) {
  // Motor A (правая сторона) вперёд
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, speed);

  // Motor B (левая сторона) вперёд
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, speed);

  Serial.println("→ Движение вперёд");
}

void stopMotors() {
  // Остановка обоих моторов
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, 0);

  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, 0);

  Serial.println("■ Стоп");
}

void loop() {
  moveForward(150);  // Едем вперёд на средней скорости
  delay(2000);       // 2 секунды

  stopMotors();      // Останавливаемся
  delay(1000);       // Пауза 1 секунда

  // Цикл повторяется
}

Загрузка и тестирование

Опасно

Выньте батареи перед загрузкой кода через USB! (см. Урок 1)

Результат: Робот едет вперёд 2 сек → стоп 1 сек → повторяется.

Расширенный код: Все направления движения

Полный набор функций для управления роботом:

/*
 * Проект 2: Полный контроль моторов
 * Все направления движения для робота Фобо
 */

// Определение пинов для моторов
const int IN1 = 4;   // Направление Motor A (правая сторона)
const int IN2 = 2;
const int IN3 = 8;  // Направление Motor B (левая сторона)
const int IN4 = 12;
const int ENA = 5;   // ШИМ скорость Motor A (правые)
const int ENB = 6;   // ШИМ скорость Motor B (левые)

// Глобальные переменные для скорости
int defaultSpeed = 180;  // Скорость по умолчанию (0-255)

void setup() {
  // Настройка пинов
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);

  Serial.begin(9600);
  Serial.println("========================================");
  Serial.println("  Робот Фобо: Полный контроль моторов");
  Serial.println("========================================");
  Serial.println();
}

// Движение вперёд
void moveForward(int speed) {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);

  analogWrite(ENA, speed);
  analogWrite(ENB, speed);

  Serial.print("→ Вперёд | Скорость: ");
  Serial.println(speed);
}

// Движение назад
void moveBackward(int speed) {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);

  analogWrite(ENA, speed);
  analogWrite(ENB, speed);

  Serial.print("← Назад | Скорость: ");
  Serial.println(speed);
}

// Поворот налево (левые моторы назад, правые вперёд)
void turnLeft(int speed) {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);   // Правые моторы вперёд (Motor A)
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);  // Левые моторы назад (Motor B)

  analogWrite(ENA, speed);
  analogWrite(ENB, speed);

  Serial.print("↺ Поворот налево | Скорость: ");
  Serial.println(speed);
}

// Поворот направо (левые моторы вперёд, правые назад)
void turnRight(int speed) {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);  // Правые моторы назад (Motor A)
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);   // Левые моторы вперёд (Motor B)

  analogWrite(ENA, speed);
  analogWrite(ENB, speed);

  Serial.print("↻ Поворот направо | Скорость: ");
  Serial.println(speed);
}

// Остановка
void stopMotors() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);

  analogWrite(ENA, 0);
  analogWrite(ENB, 0);

  Serial.println("■ Стоп");
}

// Тестовая программа
void loop() {
  Serial.println("\n--- Начало цикла тестирования ---");

  // Вперёд
  moveForward(defaultSpeed);
  delay(2000);

  stopMotors();
  delay(1000);

  // Назад
  moveBackward(defaultSpeed);
  delay(2000);

  stopMotors();
  delay(1000);

  // Поворот налево
  turnLeft(defaultSpeed);
  delay(1000);

  stopMotors();
  delay(1000);

  // Поворот направо
  turnRight(defaultSpeed);
  delay(1000);

  stopMotors();
  delay(3000);  // Пауза 3 секунды перед новым циклом
}

Калибровка моторов

Проблема: Даже при одинаковом ШИМ моторы вращаются с разной скоростью из-за различий в обмотках, износа и трения. Робот едет по дуге вместо прямой.

Решение: Подобрать разные значения ШИМ для левых и правых моторов.

Метод калибровки:

  1. Запустите робота вперёд на 3 секунды (на открытом пространстве)

  2. Если уходит влево → увеличьте скорость левых моторов

  3. Если уходит вправо → увеличьте скорость правых моторов

  4. Повторяйте, пока не поедет прямо

Калибровочный код:

/*
 * Калибровка моторов робота Фобо
 */

const int IN1 = 4;
const int IN2 = 2;
const int IN3 = 8;
const int IN4 = 12;
const int ENA = 5;
const int ENB = 6;

// Калибровочные значения ШИМ (подбираются вручную)
int speedLeft = 180;   // Скорость левых моторов (Motor B)
int speedRight = 180;  // Скорость правых моторов (Motor A)

void setup() {
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);

  Serial.begin(9600);
  Serial.println("Калибровка моторов");
  Serial.print("Левые: ");
  Serial.print(speedLeft);
  Serial.print(" | Правые: ");
  Serial.println(speedRight);
}

void moveForwardCalibrated() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);

  analogWrite(ENA, speedRight);  // Индивидуальная скорость для правых (Motor A)
  analogWrite(ENB, speedLeft);   // Индивидуальная скорость для левых (Motor B)
}

void stopMotors() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 0);
  analogWrite(ENB, 0);
}

void loop() {
  // Едем вперёд 3 секунды для теста
  moveForwardCalibrated();
  delay(3000);

  // Останавливаемся
  stopMotors();
  delay(10000);  // 10 секунд на анализ результата
}

Пример калибровки:

  1. Первый запуск: speedLeft = 180, speedRight = 180 → робот уходит влево

  2. Второй запуск: speedLeft = 190, speedRight = 180 → всё ещё уходит влево

  3. Третий запуск: speedLeft = 200, speedRight = 180 → робот едет прямо! ✓

Запишите калибровочные значения! Вы будете использовать их во всех последующих проектах.

Эксперименты

Эксперимент 1: Разные скорости

Цель: Понять, как скорость влияет на движение робота.

Задание: Протестируйте робота на разных скоростях (100, 150, 200, 255) и запишите наблюдения:

  • При какой минимальной скорости робот начинает двигаться?

  • Как меняется траектория движения при разных скоростях?

  • При какой скорости робот едет ровнее всего?

void loop() {
  Serial.println("Скорость: 100");
  moveForward(100);
  delay(2000);
  stopMotors();
  delay(2000);

  Serial.println("Скорость: 200");
  moveForward(200);
  delay(2000);
  stopMotors();
  delay(2000);
}

Эксперимент 2: Калибровка поворота на 90°

Цель: Научиться точно поворачивать робота на 90 градусов.

Метод: Вызовите turnLeft() и подберите время экспериментально.

void turn90Left() {
  turnLeft(180);
  delay(500);  // Начните с 500 мс, подберите для вашего робота!
  stopMotors();
}

Задание:

  1. Поставьте робота на пол, отметьте начальное направление

  2. Запустите функцию turn90Left()

  3. Измерьте реальный угол поворота

  4. Скорректируйте время в delay() пока не получите ровно 90°

Подсказка: Время зависит от скорости, трения пола и веса робота. Обычно 400-700 мс.

Поиск неисправностей

Моторы не вращаются: - Батареи заряжены? Переключатель включён? - Попробуйте скорость 255: analogWrite(ENA, 255)

Робот едет назад вместо вперёд: Поменяйте HIGH/LOW в moveForward():

digitalWrite(IN1, LOW);   // Было HIGH
digitalWrite(IN2, HIGH);  // Было LOW

Робот едет криво: Откалибруйте моторы (см. раздел «Калибровка моторов»)

Библиотека AlashMotorControlLite (опционально)

Официальная библиотека упрощает код: setSpeed(-100…100), stop()/brake().

Установка: Library Manager → AlashMotorControlLite → Install (подробно в Уроке 1)

#include <AlashMotorControlLite.h>

// Режим DIR_DIR_PWM: IN1, IN2, PWM(ENA/ENB)
AlashMotorControlLite motorRight(DIR_DIR_PWM, 4, 2, 5);
AlashMotorControlLite motorLeft(DIR_DIR_PWM, 8, 12, 6);

void setup() {
  Serial.begin(9600);
  Serial.println("Робот Фобо готов!");
}

void loop() {
  // Вперёд (скорость: -100...100)
  motorLeft.setSpeed(80);
  motorRight.setSpeed(80);
  delay(2000);

  motorLeft.stop();  // Мягкая остановка (выбег 1-3 сек)
  motorRight.stop();
  delay(1000);

  // Назад (отрицательные значения)
  motorLeft.setSpeed(-80);
  motorRight.setSpeed(-80);
  delay(2000);

  motorLeft.brake();  // Резкая остановка (0.1-0.5 сек)
  motorRight.brake();
  delay(1000);

  // Поворот налево
  motorLeft.setSpeed(-70);
  motorRight.setSpeed(70);
  delay(1000);

  motorLeft.stop();
  motorRight.stop();
  delay(3000);
}

Заключение

Поздравляем! 🎉 Вы освоили управление моторами робота Фобо!

Вы научились: Работать с драйвером L298N, управлять направлением (IN1-IN4) и скоростью (ШИМ), создавать функции движения, калибровать моторы.

Что дальше: Проект 3 (движение по квадрату), Проект 6 (следование за рукой), Проект 7 (объезд препятствий), Проект 9 (следование по линии), Проект 14 (мастер-режим).

Важно: Сохраните ваши калибровочные значения (speedLeft, speedRight) — они понадобятся во всех следующих проектах!