Руководства · 15 мин чтения

Как сделать робот-машинку на Arduino: управление по Bluetooth шаг за шагом

Собери робот-машинку на Arduino шаг за шагом: детали и стоимость, подключение L298N и HC-05, аккумуляторы 18650, код движения, управление с телефона и борьба с уводом и перезагрузками.

Собрать машинку на Arduino — один из самых увлекательных способов изучить электронику и программирование в одном проекте. С двумя DC-моторами с редуктором, драйвером моторов L298N, двумя аккумуляторами 18650, Bluetooth-модулем HC-05 и Arduino Uno за одни выходные можно собрать робот-машинку, которой управляешь с телефона. По ходу дела ты своими глазами увидишь, почему моторы нельзя подключать прямо к Arduino, почему так важен выбор аккумулятора и как несколько строк кода двигают настоящую машину.

В этом руководстве мы вместе от начала до конца соберём двухмоторную (2WD) робот-машинку: список деталей и разбивка стоимости, сборка шасси, таблицы подключения, код движения вперёд-назад и поворотов и управление по Bluetooth с телефона. Двум проблемам, с которыми новички мучаются чаще всего, — машинка едет не прямо и Arduino перезагружается при старте моторов, — отведены отдельные разделы с проверенными практическими решениями. В последних разделах — как управлять той же машинкой с ESP32 или Raspberry Pi Pico и как превратить её в робота, объезжающего препятствия или следующего по линии.

Плата Arduino Uno
Плата Arduino Uno
Драйвер моторов L298N
Драйвер моторов L298N
Bluetooth-модуль HC-05
Bluetooth-модуль HC-05
Литий-ионный аккумулятор 18650
Литий-ионный аккумулятор 18650

Как работает робот-машинка на Arduino?

Робот-машинку можно разделить на четыре части. Arduino — мозг: читает команду с телефона и решает, какой мотор в какую сторону и с какой скоростью крутить. Драйвер моторов L298N — мышцы: превращает слабые сигналы Arduino на 5 V в большой ток, который нужен моторам. Моторы с редуктором вращают колёса, а аккумуляторный блок питает всё. Руля у таких машинок нет: они поворачивают, вращая два колеса с разной скоростью или в разные стороны. Это называется дифференциальным приводом: если левое колесо крутится вперёд, а правое назад, машинка разворачивается на месте вправо. Небольшое свободно вращающееся поворотное колесо спереди или сзади удерживает корпус в равновесии.

Жёлтый TT-мотор с редуктором и колесо 65 мм
Стандартный мотор для робот-машинки: TT-мотор с жёлтым пластиковым редуктором и колесом 65 мм. Редуктор снижает скорость мотора в 48 раз и увеличивает крутящий момент.
ПараметрЖёлтый TT-мотор (1:48)
Рабочее напряжение3–6 V
Передаточное число1:48 (пластиковые шестерни)
Скорость без нагрузкиОколо 90–120 об/мин при 3 V, 200–250 об/мин при 6 V
Ток без нагрузкиОколо 150–160 mA
Ток при заторможенном валуОколо 1,1–1,5 A
Диаметр колеса (в наборах)65 мм
Скорость машинки при 6 VОколо 0,7 м/с (π × 0,065 м × 200 / 60)

Самая важная строка в таблице — ток при заторможенном валу: когда колесо упирается в препятствие или машинка трогается, каждый мотор ненадолго потребляет больше 1 ампера. Пин Arduino может отдать максимум 20–40 mA, поэтому моторы всегда подключают через драйвер. Выполняя эту работу, L298N теряет около 1,5–2,5 V; при аккумуляторном блоке 7,4 V моторам остаётся 5–6 V — как раз идеальный диапазон для TT-моторов. Внутреннее устройство драйвера и идею H-моста подробно объясняем в статье Управление DC-мотором через L298N.

Список деталей

ДетальКол-воПримечание
Акриловое шасси 2WD для робот-машинки1Обычно в наборе 2 TT-мотора, 2 колеса, поворотное колесо, выключатель, крепления моторов и винты
Arduino Uno R3 (можно клон) + USB-кабель1Подойдёт и Nano; номера пинов те же
Модуль драйвера моторов L298N12 A на канал; управляет двумя моторами независимо
Bluetooth-модуль HC-05 или HC-061Для связи с Android-телефоном
Литий-ионный аккумулятор 186502Фирменные, способные отдавать не меньше 5 A
Отсек на 2 аккумулятора 18650 (последовательно)1Соединяет два аккумулятора последовательно, получается 7,4 V
Зарядное устройство для 186501Заряжающее каждый аккумулятор отдельно
Перемычки (папа-мама и мама-мама)20+Между Arduino, L298N и HC-05
Резисторы 1 kΩ и 2 kΩ1 + 1Делитель напряжения для входа RXD у HC-05
Керамический конденсатор 100 nF2–4На клеммы моторов для подавления помех
Электролитический конденсатор 470–1000 µF (16 V и выше)1Рекомендуется; на вход питания L298N
Стяжки, двусторонний скотч, стойки M3НесколькоЧтобы закрепить платы и провода

В большинстве наборов шасси есть ещё и отсек на 4 батарейки AA; как скоро станет ясно, в паре с L298N он слишком слабый, поэтому в список добавлены аккумуляторы 18650. HC-06 — более простой собрат HC-05, работающий только ведомым, и для управления машинкой с телефона он вполне подходит. Пластиковые диски с прорезями из набора — это диски энкодера для датчика скорости, с помощью которого позже можно заставить машинку ехать идеально прямо; не выбрасывай их, просто пока отложи.

Стоимость: куда уходит бюджет?

Цены постоянно меняются в зависимости от продавца и курса валют, поэтому цифр не приводим; вместо этого показываем, какие позиции съедают бюджет и где можно сэкономить. Общее правило: электронные модули (L298N, HC-05, резисторы) дешёвые, а большая часть бюджета уходит на плату, набор шасси и прежде всего на аккумуляторы и зарядное устройство. На аккумуляторах экономить стоит в последнюю очередь: хорошие 18650 можно перезаряжать сотни раз и использовать во всех следующих робототехнических проектах.

ПозицияУровень ценыКак сэкономить
Набор шасси (с моторами и колёсами)СреднийНабор обычно дешевле, чем моторы, колёса и поворотное колесо по отдельности
Arduino UnoСредний (клон) – высокий (оригинал)Для учёбы подойдёт клон; можно взять и уже имеющиеся Uno или Nano
Драйвер моторов L298NНизкийОдин модуль управляет двумя моторами; одного хватит и для 4WD
HC-05 / HC-06Низкий – среднийЕсли управляешь только с телефона, хватит HC-06
2× аккумулятора 18650 + зарядноеСамая крупная статьяОчень дешёвые аккумуляторы с надписью «9900 mAh» обычно поддельные; здесь не экономь
Провода, резисторы, конденсаторы, винтыНизкийБольшинство из этого уже есть в стартовых наборах
Если у тебя уже есть стартовый набор Arduino, плата, перемычки и резисторы найдутся; нужны только набор шасси, L298N, HC-05 и аккумуляторы. Готовые наборы «умной машинки», где всё в одной коробке, удобны тем, что в них своя плата управления моторами и готовый код, но стоят дороже и лишают возможности разобраться в подключении.

2WD или 4WD?

Параметр2WD (2 мотора + поворотное колесо)4WD (4 мотора)
ПоворотыРазворачивается на месте, резко и легкоПоворачивает с боковым проскальзыванием колёс (skid steer); на ковре с трудом
Потребляемый токОколо 0,3–0,6 A во время ездыПримерно вдвое больше
Время работы от аккумулятораДольшеКороче
Неровная поверхностьПоворотное колесо может цепляться за краяСцепление лучше
Езда по прямойПоворачиваясь, поворотное колесо может сбить машинку с курсаСтабильнее
Подключение к L298NКаждый мотор на своём каналеДва мотора с каждой стороны параллельно на одном канале
Лучше всего дляПервой машинки, робота, следующего по линииУлицы, более тяжёлых грузов

Для первой машинки советуем 2WD: она дешевле, потребляет меньше тока, легко разворачивается на месте и лучше подходит для следующих проектов, например робота, следующего по линии. Если собираешь 4WD, подключи два мотора с каждой стороны параллельно к одним и тем же клеммам OUT и проверь, что оба крутятся в одну сторону. Один канал L298N тогда несёт ток двух моторов; при обычной езде это нормально, но если колёса застрянут, предел 2 A на канал может быть превышен, и тепловая защита драйвера отключит моторы.

Питание: почему два аккумулятора 18650?

Большинство проблем робот-машинок — из-за неправильного аккумулятора. Правильный источник должен одновременно выполнять два условия: оставлять моторам достаточное напряжение после потерь в L298N и не проседать, когда моторы при старте потребляют амперы. Два литий-ионных аккумулятора 18650, соединённых последовательно (2S), дают 8,4 V при полном заряде и 7,4 V в среднем и легко отдают несколько ампер. Для входа VIN у Arduino Uno рекомендуется 7–12 V, так что тот же блок может питать и моторы, и Arduino. С аккумуляторами на 2500 mAh машинка 2WD, потребляющая в движении в среднем 0,8 A (моторы плюс платы), теоретически проработает около 3 часов; поскольку блок никогда не разряжают полностью, реалистичнее 2–2,5 часа. Чтобы посчитать со своими значениями, используй утилиту «Время работы от батареи».

Литий-ионный аккумулятор 18650
Литий-ионный аккумулятор 18650: диаметр 18 мм, длина 65 мм; 4,2 V при полном заряде и 3,6–3,7 V в среднем. Два последовательно — идеальный блок на 7,4 V для робот-машинки.
Источник питанияНапряжениеСпособность отдавать токДля робот-машинки
Батарейка-«крона» (PP3) на 9 V9 VОчень низкаяНе подходит; самая частая причина перезагрузок
4× AA щелочные6 V (быстро проседает под нагрузкой)СредняяСлабо; после L298N до моторов доходит лишь около 4 V
4× AA NiMH (аккумуляторы)4,8 VХорошаяС L298N не хватает напряжения
2× Li-ion 18650 (2S)7,4 V (8,4 V при полном заряде)Высокая (несколько ампер)Лучший выбор
3× Li-ion 18650 (3S)11,1 V (12,6 V при полном заряде)ВысокаяСлишком много для TT-моторов; превышает предел 12 V для перемычки 5V
USB-пауэрбанк5 VХорошаяТолько для отдельного питания Arduino
Литий-ионные аккумуляторы мощные, но требуют аккуратности. Вставляя аккумуляторы, дважды проверь, где плюс и где минус; вставленный наоборот или закороченный 18650 сильно нагревается и может вызвать пожар. Напряжение на один аккумулятор никогда не должно опускаться ниже 3,0 V; заряжай, когда машинка начинает замедляться (около 6,6 V для блока). Модули TP4056 заряжают только один аккумулятор и не могут напрямую заряжать последовательный блок; вынимай аккумуляторы из отсека, заряжай их в зарядном устройстве для 18650 и никогда не оставляй без присмотра во время зарядки.

Вместо того чтобы гадать, сколько заряда осталось, его можно измерить. Подключи плюс аккумулятора (после выключателя) к A0 через делитель напряжения из двух резисторов 10 kΩ: блок на 8,4 V даёт на A0 4,2 V — ниже предела измерения Arduino в 5 V. Делитель потребляет всего около 0,4 mA, так что на время работы от аккумулятора не влияет.

C++ (Arduino IDE)
1// Pil + (anahtardan sonra) → 10 kΩ → A0 → 10 kΩ → GND / battery + (after the switch) → 10 kΩ → A0 → 10 kΩ → GND
2const float DIVIDER = 2.0;   // iki eşit direnç gerilimi yarıya böler / two equal resistors halve the voltage
3
4void setup() {
5  Serial.begin(9600);
6}
7
8void loop() {
9  float v = analogRead(A0) * 5.0 / 1023.0 * DIVIDER;
10  Serial.print(F("Pil / Battery: "));
11  Serial.print(v, 2);
12  Serial.println(F(" V"));
13  if (v < 6.6) Serial.println(F("Sarj et / Charge now"));   // hücre başına 3,3 V / 3.3 V per cell
14  delay(1000);
15}

Пошаговая сборка

  1. Сними защитную бумагу с акриловых деталей. Если моторы пришли без проводов, припаяй к каждому мотору по два провода и укрепи места пайки термоклеем: оторвавшийся от вибрации провод мотора — самая частая поломка.
  2. Закрепи моторы снизу шасси Т-образными акриловыми креплениями и длинными винтами M3 из набора. Оси двух моторов должны быть на одной линии, а клеммы проводов моторов — смотреть внутрь.
  3. Если собираешься использовать диски энкодера, надень их на внутреннюю сторону вала мотора сейчас: когда колёса стоят, это сделать трудно.
  4. Установи поворотное колесо посередине другого конца шасси на стойках. Подбери высоту стоек так, чтобы шасси было параллельно полу.
  5. Надень колёса до упора, совместив их с D-образным валом; болтающееся колесо постоянно уводит машинку.
  6. Закрепи отсек для аккумуляторов двусторонним скотчем или липучкой там, где его вес будет ближе к оси колёс. Если большая часть веса приходится на поворотное колесо, ведущие колёса будут проскальзывать.
  7. Установи Arduino и L298N на верхнюю палубу на пластиковых стойках. К USB-порту Arduino должен быть лёгкий доступ, а радиатор L298N — на открытом воздухе; следи, чтобы металлические винты не касались паек снизу плат.
  8. Включи выключатель последовательно в плюсовой провод аккумулятора, чтобы включать и выключать машинку, не вынимая аккумуляторы.
  9. Скрути два провода каждого мотора на пути к L298N, сделай все провода короткими и стяни их стяжками. Прежде чем вставить аккумуляторы, проверь мультиметром, что между клеммами отсека нет короткого замыкания.
Перед установкой моторов на шасси ненадолго прикоснись выводами каждого мотора к 2 батарейкам AA, чтобы проверить направление вращения, и пометь провода. Если оба мотора пометить так, что «красный провод на плюсе — значит вперёд», при подключении не будет ошибок с направлением.

Схема подключения

Подключение удобно разделить на две части: силовую (аккумулятор, выключатель, L298N, моторы) и сигнальную (тонкие провода от Arduino к L298N и HC-05). Сними маленькие перемычки с пинов ENA и ENB на L298N: эти пины мы подключим к выходам PWM Arduino, чтобы задавать скорость в коде. Перемычку 5V на L298N оставь на месте: поскольку блок ниже 12 V, логику драйвера питает собственный стабилизатор платы.

Двухканальный модуль драйвера моторов L298N
Драйвер моторов L298N: моторы подключаются к синим винтовым клеммам по бокам, аккумулятор — к тройной клемме спереди; пины ENA, IN1–IN4 и ENB идут к Arduino.
Клемма L298NПодключение
OUT1, OUT2Левый мотор (на 4WD — два левых мотора параллельно)
OUT3, OUT4Правый мотор (на 4WD — два правых мотора параллельно)
12VПлюс аккумулятора через выключатель
GNDМинус аккумулятора и пин GND Arduino (общая земля)
5VС Arduino Uno не подключается; с ESP32 и Pico питает плату
Перемычка 5VОстаётся на месте (аккумулятор ниже 12 V)
Перемычки ENA и ENBСняты; пины идут к выходам PWM Arduino
ПодключениеArduino UnoESP32Raspberry Pi Pico
L298N ENA (скорость левого мотора)D5 (PWM)GPIO 25GP15
L298N IN1D7GPIO 27GP14
L298N IN2D8GPIO 33GP13
L298N ENB (скорость правого мотора)D6 (PWM)GPIO 26GP10
L298N IN3D9GPIO 32GP12
L298N IN4D4GPIO 4GP11
HC-05 TXDD10 (RX для SoftwareSerial)Не нужен (встроенный Bluetooth)GP1 (UART0 RX)
HC-05 RXDD11, через делитель 1 kΩ / 2 kΩНе нуженGP0 (UART0 TX), напрямую
HC-05 VCC5VНе нуженВыход 5V на L298N
Питание платыVIN ← плюс аккумулятора после выключателя5V (VIN) ← выход 5V на L298NVSYS ← выход 5V на L298N
GNDОбщий с GND L298N и минусом аккумулятораОбщийОбщий
Никогда не нарушай три правила: все GND (минус аккумулятора, L298N, Arduino, HC-05) должны быть соединены вместе; моторы никогда не питаются от пина 5V Arduino; а выход 5V L298N нельзя подключать к пину VIN Arduino. VIN нужно не меньше 7 V; с 5 V стабилизатор Arduino не может нормально работать, и плата становится нестабильной. Пин RXD у HC-05 — вход на 3,3 V; понизь сигнал TX Uno на 5 V делителем 1 kΩ и 2 kΩ: D11 → 1 kΩ → RXD, RXD → 2 kΩ → GND (5 V × 2/3 ≈ 3,3 V).

D5 и D6 выбраны для скорости неслучайно. На Uno библиотека Servo отключает PWM на пинах 9 и 10, а функция tone() — на пинах 3 и 11. С ENA и ENB на 5 и 6 управление скоростью моторов продолжит работать, если позже добавишь сервопривод или зуммер. D2 и D3 зарезервированы для энкодеров, потому что поддерживают прерывания. Расположение пинов своей платы можно посмотреть в утилите «Распиновка».

Первый скетч: вперёд, назад, влево и вправо

Прежде чем переходить к Bluetooth, проверим моторы и подключение отдельно. Сердце кода — функция drive(left, right): она принимает скорость каждого мотора отдельно от -255 до 255, где положительное значение — вперёд, отрицательное — назад, а ноль — стоп. Как значение скорости превращается в напряжение, объясняем в статье Что такое PWM? Перед загрузкой поставь машинку на коробку, чтобы колёса крутились свободно; 3-секундная пауза в setup() даёт на это время.

C++ (Arduino IDE)
1// Sol motor / left motor: ENA=5, IN1=7, IN2=8 — Sağ motor / right motor: ENB=6, IN3=9, IN4=4
2const int ENA = 5, IN1 = 7, IN2 = 8;
3const int ENB = 6, IN3 = 9, IN4 = 4;
4
5const int SPEED = 180;   // temel hız 0-255 / base speed 0-255
6const int TRIM = 0;      // % düzeltme: + sol, - sağ motoru yavaşlatır / % trim: + slows left, - slows right
7
8void drive(int left, int right) {               // her biri -255 … 255 / each -255 … 255
9  if (TRIM > 0) left = left * (100 - TRIM) / 100;
10  if (TRIM < 0) right = right * (100 + TRIM) / 100;
11  digitalWrite(IN1, left > 0);  digitalWrite(IN2, left < 0);
12  digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
13  analogWrite(ENA, abs(left));
14  analogWrite(ENB, abs(right));
15}
16
17void forward()   { drive(SPEED, SPEED); }
18void backward()  { drive(-SPEED, -SPEED); }
19void turnLeft()  { drive(-SPEED, SPEED); }     // yerinde sola / spin left in place
20void turnRight() { drive(SPEED, -SPEED); }     // yerinde sağa / spin right in place
21void stopCar()   { drive(0, 0); }
22
23void setup() {
24  int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
25  for (int p : pins) pinMode(p, OUTPUT);
26  stopCar();
27  delay(3000);             // tekerlekleri kaldırmak için zaman / time to lift the wheels
28}
29
30void loop() {
31  forward();   delay(1500);
32  stopCar();   delay(500);
33  backward();  delay(1500);
34  stopCar();   delay(500);
35  turnLeft();  delay(600);
36  stopCar();   delay(500);
37  turnRight(); delay(600);
38  stopCar();   delay(2000);
39}
ДвижениеЛевый моторПравый моторКод
ВперёдВперёдВперёдdrive(180, 180)
НазадНазадНазадdrive(-180, -180)
Разворот влево на местеНазадВперёдdrive(-180, 180)
Разворот вправо на местеВперёдНазадdrive(180, -180)
Плавный поворот влевоМедленно вперёдВперёдdrive(90, 180)
СтопСтоитСтоитdrive(0, 0)

С колёсами в воздухе машинка должна по очереди поехать вперёд, назад, влево и вправо. Если одно колесо крутится не в ту сторону, код не меняй: поменяй местами два провода этого мотора на клеммах OUT у L298N. Если оба колеса крутятся не туда, поменяй провода обоих моторов. Если моторы гудят, но не крутятся, значение SPEED слишком мало: большинству TT-моторов для страгивания нужно значение PWM не меньше примерно 80–120, и этот порог растёт по мере разряда аккумулятора.

Управление по Bluetooth с телефона (HC-05)

HC-05 работает как беспроводной последовательный кабель между телефоном и Arduino: приложение на телефоне отправляет букву, Arduino её читает и выполняет соответствующее движение. Большинство приложений-пультов, которые находятся в Play Store по запросу «Bluetooth RC Car» или «Bluetooth RC Controller», отправляют F для движения вперёд, B назад, L влево, R вправо и S для остановки, когда отпускаешь кнопку; некоторые используют ещё G, I, H и J для диагоналей и 0–9 плюс q для скорости. Пины модуля, режимы мигания светодиода и AT-команды разобраны в статье Bluetooth-модуль HC-05.

Bluetooth-модуль HC-05
HC-05: подключается к телефону по классическому Bluetooth (SPP); скорость по умолчанию 9600 бод, PIN-код для сопряжения 1234 или 0000.
  1. Пока загружаешь скетч ниже, выключатель машинки может оставаться выключенным: Arduino и HC-05 питаются по USB. Если светодиод HC-05 быстро мигает, модуль ждёт подключения.
  2. Найди HC-05 в настройках Bluetooth на Android-телефоне и выполни сопряжение с PIN-кодом 1234 (или 0000, если не подходит).
  3. Открой приложение-пульт, дай разрешения на Bluetooth и устройства поблизости и выбери HC-05 в списке устройств. После подключения светодиод модуля каждые две секунды коротко мигает дважды.
  4. Оставь Arduino подключённой по USB, открой монитор порта на скорости 9600 бод и нажимай кнопки в приложении. На экране появится буква, которую отправляет каждая кнопка; если приложение отправляет другие буквы, поменяй под них строки case в коде.
  5. Отключи USB-кабель, включи выключатель, поставь машинку на пол и поехали.
C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial bt(10, 11);               // RX, TX → HC-05 TXD, RXD (RXD bölücüyle / RXD via divider)
4
5const int ENA = 5, IN1 = 7, IN2 = 8;     // sol motor / left motor
6const int ENB = 6, IN3 = 9, IN4 = 4;     // sağ motor / right motor
7const int TRIM = 0;                      // % düzeltme / % trim
8const unsigned long TIMEOUT = 600;       // ms; 0 = kapalı / 0 = disabled
9
10int speed = 200;                         // 0-255
11unsigned long lastCmd = 0;
12
13void drive(int left, int right) {
14  if (TRIM > 0) left = left * (100 - TRIM) / 100;
15  if (TRIM < 0) right = right * (100 + TRIM) / 100;
16  digitalWrite(IN1, left > 0);  digitalWrite(IN2, left < 0);
17  digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
18  analogWrite(ENA, abs(left));
19  analogWrite(ENB, abs(right));
20}
21
22void setup() {
23  int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
24  for (int p : pins) pinMode(p, OUTPUT);
25  drive(0, 0);
26  Serial.begin(9600);                    // gelen harfleri görmek için / to see incoming letters
27  bt.begin(9600);                        // HC-05 veri modu hızı / HC-05 data mode baud rate
28}
29
30void loop() {
31  if (bt.available()) {
32    char c = bt.read();
33    Serial.println(c);
34    lastCmd = millis();
35    int half = speed / 2;
36    switch (c) {
37      case 'F': drive(speed, speed);   break;   // ileri / forward
38      case 'B': drive(-speed, -speed); break;   // geri / backward
39      case 'L': drive(-speed, speed);  break;   // yerinde sola / spin left
40      case 'R': drive(speed, -speed);  break;   // yerinde sağa / spin right
41      case 'G': drive(half, speed);    break;   // ileri-sol / forward-left
42      case 'I': drive(speed, half);    break;   // ileri-sağ / forward-right
43      case 'H': drive(-half, -speed);  break;   // geri-sol / back-left
44      case 'J': drive(-speed, -half);  break;   // geri-sağ / back-right
45      case 'S': drive(0, 0);           break;   // dur / stop
46      case 'q': speed = 255;           break;   // tam hız / full speed
47      default:
48        if (c >= '0' && c <= '9') speed = map(c - '0', 0, 9, 100, 240);   // hız kademesi / speed level
49    }
50  }
51  if (TIMEOUT > 0 && millis() - lastCmd > TIMEOUT) drive(0, 0);   // komut yoksa dur / no command: stop
52}
БукваДвижениеЛевый / правый мотор
FВперёд+скорость / +скорость
BНазад−скорость / −скорость
LРазворот влево−скорость / +скорость
RРазворот вправо+скорость / −скорость
G, IВперёд-влево, вперёд-вправоОдна сторона на половине скорости
H, JНазад-влево, назад-вправоОдна сторона на половине скорости
SСтоп0 / 0
0–9, qУровень скорости0 → 100, 9 → 240, q → 255

TIMEOUT в коде — защитная функция: такие приложения отправляют одну и ту же букву, пока кнопка удерживается, поэтому если 600 мс не приходит ни одной буквы, код считает, что связь потеряна, и останавливает машинку. Так машинка не продолжит ехать в стену, если телефон окажется вне зоны действия или приложение закроется. Если твоё приложение отправляет букву лишь один раз на нажатие, машинка будет останавливаться через 600 мс; тогда поставь TIMEOUT в 0, чтобы отключить эту функцию. Кроме того, в loop() нигде нет delay(): долгие паузы заставляют команды запаздывать, а почему — узнаешь из статьи millis() и delay().

HC-05 и HC-06 используют классический Bluetooth, поэтому с iPhone не работают: iOS не разрешает такое последовательное подключение. Если хочешь управлять с iPhone, используй BLE-модуль вроде HM-10 или ESP32 с BLE. Если хочешь сделать собственное приложение-пульт, загляни в руководство Arduino и Bluetooth в App Inventor.

Машинка едет не прямо: причины и решения

Если машинка медленно уходит в сторону, хотя обоим моторам для движения «вперёд» дано одинаковое значение PWM, не волнуйся: это самая частая проблема робот-машинок. Дешёвые моторы с редуктором крутятся с разной скоростью даже при одинаковом напряжении: из-за разницы в трении шестерён, щётках и магнитах каждый мотор чуть-чуть отличается. Добавь к этому болтающееся колесо, постоянно поворачивающееся поворотное колесо или вес, сваленный на одну сторону, и увод на 20–30 см за 2 метра окажется совершенно нормальным. Сначала устрани механические причины, а оставшуюся разницу исправь программно.

СимптомВероятная причинаРешение
Всегда уводит в одну сторонуМоторы крутятся с разной скоростьюПрограммная поправка через TRIM или энкодеры
При старте виляет, потом выравниваетсяОдин мотор трогается позже, или поворачивается поворотное колесоПлавный старт; шаровая опора вместо поворотного колеса
Увод каждый раз разныйБолтающееся колесо, проскальзывающая шина или погнутое крепление мотораНадень колесо на вал до упора, затяни винты
Вместо движения вперёд крутится на местеУ одного мотора перепутаны проводаПоменяй провода этого мотора на клемме OUT
Увод растёт по мере разряда аккумулятораПри низком напряжении разница между моторами растётЗаряди аккумулятор; настраивай TRIM на полном заряде
При разгоне тянет в одну сторонуВес смещён на одну сторонуПеренеси аккумулятор и платы на середину, ближе к оси колёс

Когда механические проблемы устранены, доводи настройку программно. Константа TRIM в коде замедляет более быстрый мотор на заданный процент: положительное значение замедляет левый мотор, отрицательное — правый. Калибруй так:

  1. Полностью заряди аккумуляторы: калибровка на полном заряде даёт стабильные результаты.
  2. Наклей на пол прямую полосу скотча длиной 2 метра и поставь машинку в её начало, направив вдоль скотча.
  3. В loop() первого скетча оставь только forward() и паузу 3 секунды, затем запусти машинку.
  4. Если машинку уводит вправо, левый мотор быстрее: увеличь TRIM на 3; если уводит влево, уменьши TRIM на 3.
  5. Повторяй, пока увод на 2 метрах не сократится до нескольких сантиметров, затем скопируй то же значение TRIM в скетч для Bluetooth.
  6. Калибруй на той скорости, которую используешь чаще всего: разница между моторами немного меняется со скоростью.

Следующий уровень для идеально прямой езды и измерения расстояния — энкодер. Диски с 20 прорезями из набора надеваются на валы моторов, а каждую прорезь считает щелевой датчик скорости на LM393. Подключи выходы датчиков к пинам D2 и D3, поддерживающим прерывания, и сравнивай число импульсов двух колёс: если левая сторона уходит вперёд, немного замедли левый мотор. Такое простое пропорциональное (P) регулирование держит машинку прямо независимо от заряда аккумулятора и покрытия пола. Колесо 65 мм за оборот проходит около 20,4 см, так что каждый импульс означает примерно 1 см пути. Как работают прерывания, объясняем в статье Прерывания в Arduino.

Arduino перезагружается при старте моторов

Если Arduino перезапускается или HC-05 теряет связь (светодиод снова начинает часто мигать), когда машинка трогается, меняет направление или врезается в препятствие, проблема почти всегда в питании. При старте два мотора вместе могут потреблять 2–3 A; слабый аккумулятор этого не выдерживает, и его напряжение на мгновение проседает. Процессор Uno для безопасности сам перезагружается, когда его питание опускается ниже 2,7 V (brown-out). К этому добавляются электрические помехи от щёток моторов и падение напряжения на тонких проводах. Вот решения, начиная с самых действенных:

  • Смени аккумулятор: используй два заряженных 18650 вместо батарейки на 9 V или уставших батареек AA; на этом заканчивается большинство проблем.
  • Правильный путь питания: питай Arduino от аккумулятора через VIN; не подключай выход 5V у L298N к VIN.
  • Конденсаторы на моторах: припаяй керамический конденсатор 100 nF между двумя клеммами каждого мотора; он гасит помехи от щёток в самом источнике.
  • Накопительный конденсатор: подключи электролитический конденсатор 470–1000 µF к клеммам 12V и GND у L298N (плюсом к 12V). Он покрывает кратковременный запрос тока при старте.
  • Плавный старт: вместо прыжка сразу к 255 повышай скорость ступенями, как показано ниже; бросок тока становится меньше.
  • Остановка перед реверсом: прямое переключение с движения вперёд на задний ход доводит ток мотора до пика; перед сменой направления остановись на 100–200 мс.
  • Толстые короткие силовые провода: между аккумулятором и L298N не используй перемычки и макетную плату; бери провод сечением не меньше 0,5 мм² и винтовые клеммы.
  • Раздельное питание: если проблема остаётся, питай Arduino от пауэрбанка, а моторы — от аккумулятора и соедини два GND.
C++ (Arduino IDE)
1// Yumuşak kalkış: ilk koddaki drive() ile kullan / soft start: use with drive() from the first sketch
2void rampTo(int target) {
3  for (int s = 60; s < target; s += 20) {
4    drive(s, s);
5    delay(15);              // yaklaşık 10 adımda tam hız / full speed in about 10 steps
6  }
7  drive(target, target);
8}
9
10// Kullanım: forward() yerine rampTo(SPEED) / usage: rampTo(SPEED) instead of forward()
Простой способ понять, в чём проблема — в питании или в коде: отсоедини провод VIN, оставь Arduino с питанием по USB от компьютера (соединение GND сохрани) и запусти моторы от аккумулятора. Если перезагрузки прекратились, проблема точно в питании. Мультиметр между VIN и GND, на котором видно напряжение в момент, когда машинка трогается, тоже прямо показывает провал. Другие причины — в статье Arduino постоянно перезагружается.

Робот-машинка на ESP32 и Raspberry Pi Pico

У ESP32 есть встроенный классический Bluetooth, поэтому HC-05 не нужен: библиотека BluetoothSerial создаёт с телефоном то же последовательное подключение, и приложения-пульты из раздела выше работают без изменений. Входы L298N считают HIGH всё, что выше примерно 2,3 V, так что сигналов ESP32 на 3,3 V достаточно. Питай плату ESP32 от выхода 5V у L298N через пин 5V (VIN) платы; аккумулятор прямо к этому пину не подключай. Для ESP32-S3 и ESP32-C3 этот код не скомпилируется: у них есть только BLE.

C++ (Arduino IDE)
1#include "BluetoothSerial.h"
2
3BluetoothSerial bt;
4
5const int ENA = 25, IN1 = 27, IN2 = 33;   // sol motor / left motor
6const int ENB = 26, IN3 = 32, IN4 = 4;    // sağ motor / right motor
7
8int speed = 200;                          // 0-255
9unsigned long lastCmd = 0;
10
11void drive(int left, int right) {
12  digitalWrite(IN1, left > 0);  digitalWrite(IN2, left < 0);
13  digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
14  analogWrite(ENA, abs(left));
15  analogWrite(ENB, abs(right));
16}
17
18void setup() {
19  int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
20  for (int p : pins) pinMode(p, OUTPUT);
21  drive(0, 0);
22  bt.begin("BlueGrays-Car");              // telefonda görünecek ad / name shown on the phone
23}
24
25void loop() {
26  if (bt.available()) {
27    char c = bt.read();
28    lastCmd = millis();
29    switch (c) {
30      case 'F': drive(speed, speed);   break;   // ileri / forward
31      case 'B': drive(-speed, -speed); break;   // geri / backward
32      case 'L': drive(-speed, speed);  break;   // yerinde sola / spin left
33      case 'R': drive(speed, -speed);  break;   // yerinde sağa / spin right
34      case 'S': drive(0, 0);           break;   // dur / stop
35      case 'q': speed = 255;           break;   // tam hız / full speed
36      default:
37        if (c >= '0' && c <= '9') speed = map(c - '0', 0, 9, 100, 240);
38    }
39  }
40  if (millis() - lastCmd > 600) drive(0, 0);    // komut yoksa dur / no command: stop
41}

У стандартной Raspberry Pi Pico нет Bluetooth, поэтому HC-05 подключается к пинам UART0. Поскольку Pico работает на 3,3 V, делитель напряжения на этот раз не нужен. Питай Pico через пин VSYS, а HC-05 — прямо от выхода 5V у L298N; при работе от аккумулятора без USB на пине VBUS напряжения нет. В коде для Pico скорость задаётся в процентах от -100 до 100:

MicroPython
1from machine import Pin, PWM, UART
2import time
3
4bt = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))   # GP0 → HC-05 RXD, GP1 ← HC-05 TXD
5
6ena = PWM(Pin(15)); ena.freq(1000)                  # sol motor hızı / left motor speed
7enb = PWM(Pin(10)); enb.freq(1000)                  # sağ motor hızı / right motor speed
8in1, in2 = Pin(14, Pin.OUT), Pin(13, Pin.OUT)
9in3, in4 = Pin(12, Pin.OUT), Pin(11, Pin.OUT)
10
11def drive(left, right):                             # -100 … 100 (%)
12    in1.value(left > 0); in2.value(left < 0)
13    in3.value(right > 0); in4.value(right < 0)
14    ena.duty_u16(int(abs(left) * 655))
15    enb.duty_u16(int(abs(right) * 655))
16
17speed = 80
18last = time.ticks_ms()
19drive(0, 0)
20
21while True:
22    if bt.any():
23        c = bt.read(1)
24        last = time.ticks_ms()
25        if c == b'F':   drive(speed, speed)          # ileri / forward
26        elif c == b'B': drive(-speed, -speed)        # geri / backward
27        elif c == b'L': drive(-speed, speed)         # yerinde sola / spin left
28        elif c == b'R': drive(speed, -speed)         # yerinde sağa / spin right
29        elif c == b'S': drive(0, 0)                  # dur / stop
30        elif c == b'q': speed = 100                  # tam hız / full speed
31        elif c and 48 <= c[0] <= 57:                 # '0'…'9' hız kademesi / speed level
32            speed = 40 + (c[0] - 48) * 6
33    if time.ticks_diff(time.ticks_ms(), last) > 600:
34        drive(0, 0)                                  # komut yoksa dur / no command: stop

Что дальше: прокачай свою машинку

  • Робот, объезжающий препятствия: добавь спереди датчик расстояния HC-SR04 и сервопривод, поворачивающий его влево и вправо; подробности в руководстве Робот, объезжающий препятствия.
  • Робот, следующий по линии: поставь снизу спереди 2–3 инфракрасных датчика TCRT5000 и следуй по чёрной линии на полу; см. Робот, следующий по линии.
  • Пульт с джойстиком: собери настоящий пульт без телефона из второй Arduino, модуля джойстика и nRF24L01.
  • ИК-пульт: управляй кнопками телевизионного пульта; сопоставь коды из статьи ИК-приёмник и пульт с командами движения.
  • Управление по Wi-Fi: пусть ESP32 раздаёт страницу-пульт, которая открывается в браузере телефона; основы — в руководстве Веб-сервер и WebSocket на ESP32.
  • Энкодеры и расстояние: с датчиками скорости проезжай ровно 1 метр и поворачивай ровно на 90 градусов; это основа роботов, проходящих лабиринты.
  • Робот-рука: поставь сверху на машинку небольшую робот-руку на сервоприводах, чтобы перевозить предметы.
Ультразвуковой датчик HC-SR04
Ультразвуковой датчик HC-SR04
Инфракрасный датчик TCRT5000
Инфракрасный датчик TCRT5000
Сервопривод SG90
Сервопривод SG90

Частые ошибки и решения

  • Ни один мотор не крутится: GND не общие, выключатель выключен, перемычки ENA и ENB сняты, а пины не подключены, или аккумулятор сел.
  • Светодиод L298N горит, но моторы только гудят: значение PWM ниже порога страгивания мотора или напряжение аккумулятора низкое; увеличь скорость и заряди аккумулятор.
  • Скетч не загружается: возможно, выбраны не тот порт или плата; если HC-05 подключён к пинам 0 и 1, отключай его на время загрузки. Другие причины — в статье Скетч не загружается в Arduino.
  • Телефон видит HC-05, но не подключается: модуль подключён к другому телефону, приложению не дано разрешение на «устройства поблизости» или неверный PIN-код сопряжения.
  • Машинка реагирует на команды с опозданием: в loop() есть delay() или в монитор порта выводится слишком много; паузы делай через millis().
  • Радиатор L298N сильно греется: колёса заклинены или на машинке 4WD слишком большой ток на канал; проверь механическое трение.
  • При включении машинка на мгновение дёргается: при запуске пины ненадолго находятся в неопределённом состоянии; в самых первых строках setup() сделай пины выходами и вызови drive(0, 0).

Робот-машинка на Arduino — отличная отправная точка, которая в одном проекте учит управлению моторами, работе с питанием, беспроводной связи и отладке. В итоге у тебя будет шасси, которое с каждым новым датчиком становится чуть умнее. В приложении BlueGrays есть проекты машинки с управлением по Bluetooth на L298N, робота, объезжающего препятствия, и распознавания чёрной и белой поверхности на TCRT5000 — пошагово, со схемами и кодом.

Частые вопросы

Что нужно, чтобы собрать машинку на Arduino, и сколько это стоит?

Для простой машинки с Bluetooth нужны набор шасси 2WD (2 TT-мотора, колёса, поворотное колесо), Arduino Uno, драйвер моторов L298N, Bluetooth-модуль HC-05, два аккумулятора 18650 с отсеком и несколько перемычек. Цены зависят от продавца; модули дешёвые, а большая часть бюджета уходит на плату, набор шасси и аккумуляторы с зарядным устройством. Если стартовый набор уже есть, стоимость заметно снижается.

Какой аккумулятор нужен для робот-машинки на Arduino?

Лучший вариант — два литий-ионных аккумулятора 18650 последовательно: они дают 7,4 V, после потерь в L298N около 2 V оставляют моторам 5–6 V и отдают большой ток, нужный при старте. Батарейка-«крона» (PP3) на 9 V не может отдать достаточный ток и вызывает перезагрузки, а с 4 батарейками AA моторы с L298N крутятся медленно.

Почему моя машинка на Arduino едет не прямо?

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

Почему Arduino перезагружается при старте моторов?

При старте моторы потребляют несколько ампер, и напряжение слабого аккумулятора на мгновение проседает; процессор Uno сам перезагружается, когда его питание падает. Используй заряженные 18650, поставь конденсаторы 100 nF на клеммы моторов и конденсатор 470–1000 µF на вход L298N и поднимай скорость постепенно. Если проблема остаётся, питай Arduino от отдельного источника и соедини GND.

Работает ли машинка на HC-05 с iPhone?

Нет. HC-05 и HC-06 используют профиль последовательного порта классического Bluetooth, а iOS не позволяет обычным приложениям открывать такое подключение. Чтобы управлять машинкой с iPhone, используй BLE-модуль вроде HM-10 или ESP32 с BLE; Android-телефоны подключаются к HC-05 без проблем.

Можно ли использовать шилд моторов L293D вместо L298N?

Да. Шилд моторов L293D надевается сверху на Arduino Uno и может управлять четырьмя DC-моторами, что упрощает подключение на машинках 4WD. Но его постоянный ток всего около 0,6 A на канал, поэтому при заклинивании моторов он сдаёт раньше, чем L298N, а ещё шилд занимает много пинов. Если нужно что-то эффективнее, MOSFET-драйверы вроде TB6612FNG теряют гораздо меньше напряжения.

Все проекты
Машинка на L298N с управлением по Bluetooth
#80Продвинутый
Premium

Машинка на L298N с управлением по Bluetooth

Преврати телефон в пульт и управляй своей машинкой-роботом. Arduino получает команды из приложения-пульта на телефоне через Bluetooth-модуль и вращает колёса через драйвер моторов; машинка едет вперёд

5.0(38)
65
Робот, объезжающий препятствия
#81Продвинутый
Premium

Робот, объезжающий препятствия

Как насчёт того, чтобы собрать умную машину, которая сама находит дорогу? Робот, объезжающий препятствия, постоянно осматривает всё вокруг благодаря ультразвуковому датчику спереди. Встретив препятств

5.0(38)
49
Управление светодиодом с телефона по Bluetooth
#34Новичок
Premium

Управление светодиодом с телефона по Bluetooth

Небольшая репетиция того, как включать и выключать свет в комнате с телефона. Bluetooth-модуль передаёт в Arduino буквы, отправленные с телефона; одна буква включает красный светодиод, другая — зелёны

4.8(68)
89
Определение чёрной и белой поверхности с TCRT5000
#78Средний
Premium

Определение чёрной и белой поверхности с TCRT5000

С маленьким датчиком, который служит глазом роботов, едущих по линии, можно узнать, чёрный пол или белый. TCRT5000 светит на пол невидимым светом и проверяет, сколько его отражается обратно; на белом

4.7(40)
49
Чтение отражения (приближения) с TCRT5000
#77Средний
Premium

Чтение отражения (приближения) с TCRT5000

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

4.6(33)
43
Измерение расстояния HC-SR04 (вывод в порт)
#27Новичок

Измерение расстояния HC-SR04 (вывод в порт)

Датчик HC-SR04 работает совсем как летучая мышь, которая находит дорогу в темноте: он посылает звук, которого ты не слышишь, слушает эхо и измеряет, насколько далеко предмет перед ним. Arduino каждые

4.6(46)
71
Парктроник на HC-SR04
#28Средний
Premium

Парктроник на HC-SR04

Мини-версия автомобильного парктроника: чем ближе предмет, тем чаще сигнал. Датчик расстояния измеряет предмет перед собой; если он дальше 20 сантиметров, горит зелёный светодиод, а если ближе — мигае

4.8(64)
85
Работа с сервоприводом
#35Новичок
Premium

Работа с сервоприводом

Рычаг маленького сервопривода по очереди поворачивается в три положения: до упора в начало, ровно на середину и до упора в конец, задерживаясь на каждой остановке на две секунды. Arduino сообщает мото

4.7(48)
67