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

| Параметр | Жёлтый 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; номера пинов те же |
| Модуль драйвера моторов L298N | 1 | 2 A на канал; управляет двумя моторами независимо |
| Bluetooth-модуль HC-05 или HC-06 | 1 | Для связи с Android-телефоном |
| Литий-ионный аккумулятор 18650 | 2 | Фирменные, способные отдавать не меньше 5 A |
| Отсек на 2 аккумулятора 18650 (последовательно) | 1 | Соединяет два аккумулятора последовательно, получается 7,4 V |
| Зарядное устройство для 18650 | 1 | Заряжающее каждый аккумулятор отдельно |
| Перемычки (папа-мама и мама-мама) | 20+ | Между Arduino, L298N и HC-05 |
| Резисторы 1 kΩ и 2 kΩ | 1 + 1 | Делитель напряжения для входа RXD у HC-05 |
| Керамический конденсатор 100 nF | 2–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» обычно поддельные; здесь не экономь |
| Провода, резисторы, конденсаторы, винты | Низкий | Большинство из этого уже есть в стартовых наборах |
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 часа. Чтобы посчитать со своими значениями, используй утилиту «Время работы от батареи».

| Источник питания | Напряжение | Способность отдавать ток | Для робот-машинки |
|---|---|---|---|
| Батарейка-«крона» (PP3) на 9 V | 9 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 |
Вместо того чтобы гадать, сколько заряда осталось, его можно измерить. Подключи плюс аккумулятора (после выключателя) к A0 через делитель напряжения из двух резисторов 10 kΩ: блок на 8,4 V даёт на A0 4,2 V — ниже предела измерения Arduino в 5 V. Делитель потребляет всего около 0,4 mA, так что на время работы от аккумулятора не влияет.
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}Пошаговая сборка
- Сними защитную бумагу с акриловых деталей. Если моторы пришли без проводов, припаяй к каждому мотору по два провода и укрепи места пайки термоклеем: оторвавшийся от вибрации провод мотора — самая частая поломка.
- Закрепи моторы снизу шасси Т-образными акриловыми креплениями и длинными винтами M3 из набора. Оси двух моторов должны быть на одной линии, а клеммы проводов моторов — смотреть внутрь.
- Если собираешься использовать диски энкодера, надень их на внутреннюю сторону вала мотора сейчас: когда колёса стоят, это сделать трудно.
- Установи поворотное колесо посередине другого конца шасси на стойках. Подбери высоту стоек так, чтобы шасси было параллельно полу.
- Надень колёса до упора, совместив их с D-образным валом; болтающееся колесо постоянно уводит машинку.
- Закрепи отсек для аккумуляторов двусторонним скотчем или липучкой там, где его вес будет ближе к оси колёс. Если большая часть веса приходится на поворотное колесо, ведущие колёса будут проскальзывать.
- Установи Arduino и L298N на верхнюю палубу на пластиковых стойках. К USB-порту Arduino должен быть лёгкий доступ, а радиатор L298N — на открытом воздухе; следи, чтобы металлические винты не касались паек снизу плат.
- Включи выключатель последовательно в плюсовой провод аккумулятора, чтобы включать и выключать машинку, не вынимая аккумуляторы.
- Скрути два провода каждого мотора на пути к L298N, сделай все провода короткими и стяни их стяжками. Прежде чем вставить аккумуляторы, проверь мультиметром, что между клеммами отсека нет короткого замыкания.
Схема подключения
Подключение удобно разделить на две части: силовую (аккумулятор, выключатель, L298N, моторы) и сигнальную (тонкие провода от Arduino к L298N и HC-05). Сними маленькие перемычки с пинов ENA и ENB на L298N: эти пины мы подключим к выходам PWM Arduino, чтобы задавать скорость в коде. Перемычку 5V на L298N оставь на месте: поскольку блок ниже 12 V, логику драйвера питает собственный стабилизатор платы.

| Клемма L298N | Подключение |
|---|---|
| OUT1, OUT2 | Левый мотор (на 4WD — два левых мотора параллельно) |
| OUT3, OUT4 | Правый мотор (на 4WD — два правых мотора параллельно) |
| 12V | Плюс аккумулятора через выключатель |
| GND | Минус аккумулятора и пин GND Arduino (общая земля) |
| 5V | С Arduino Uno не подключается; с ESP32 и Pico питает плату |
| Перемычка 5V | Остаётся на месте (аккумулятор ниже 12 V) |
| Перемычки ENA и ENB | Сняты; пины идут к выходам PWM Arduino |
| Подключение | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| L298N ENA (скорость левого мотора) | D5 (PWM) | GPIO 25 | GP15 |
| L298N IN1 | D7 | GPIO 27 | GP14 |
| L298N IN2 | D8 | GPIO 33 | GP13 |
| L298N ENB (скорость правого мотора) | D6 (PWM) | GPIO 26 | GP10 |
| L298N IN3 | D9 | GPIO 32 | GP12 |
| L298N IN4 | D4 | GPIO 4 | GP11 |
| HC-05 TXD | D10 (RX для SoftwareSerial) | Не нужен (встроенный Bluetooth) | GP1 (UART0 RX) |
| HC-05 RXD | D11, через делитель 1 kΩ / 2 kΩ | Не нужен | GP0 (UART0 TX), напрямую |
| HC-05 VCC | 5V | Не нужен | Выход 5V на L298N |
| Питание платы | VIN ← плюс аккумулятора после выключателя | 5V (VIN) ← выход 5V на L298N | VSYS ← выход 5V на L298N |
| GND | Общий с GND L298N и минусом аккумулятора | Общий | Общий |
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() даёт на это время.
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.

- Пока загружаешь скетч ниже, выключатель машинки может оставаться выключенным: Arduino и HC-05 питаются по USB. Если светодиод HC-05 быстро мигает, модуль ждёт подключения.
- Найди HC-05 в настройках Bluetooth на Android-телефоне и выполни сопряжение с PIN-кодом 1234 (или 0000, если не подходит).
- Открой приложение-пульт, дай разрешения на Bluetooth и устройства поблизости и выбери HC-05 в списке устройств. После подключения светодиод модуля каждые две секунды коротко мигает дважды.
- Оставь Arduino подключённой по USB, открой монитор порта на скорости 9600 бод и нажимай кнопки в приложении. На экране появится буква, которую отправляет каждая кнопка; если приложение отправляет другие буквы, поменяй под них строки case в коде.
- Отключи USB-кабель, включи выключатель, поставь машинку на пол и поехали.
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().
Машинка едет не прямо: причины и решения
Если машинка медленно уходит в сторону, хотя обоим моторам для движения «вперёд» дано одинаковое значение PWM, не волнуйся: это самая частая проблема робот-машинок. Дешёвые моторы с редуктором крутятся с разной скоростью даже при одинаковом напряжении: из-за разницы в трении шестерён, щётках и магнитах каждый мотор чуть-чуть отличается. Добавь к этому болтающееся колесо, постоянно поворачивающееся поворотное колесо или вес, сваленный на одну сторону, и увод на 20–30 см за 2 метра окажется совершенно нормальным. Сначала устрани механические причины, а оставшуюся разницу исправь программно.
| Симптом | Вероятная причина | Решение |
|---|---|---|
| Всегда уводит в одну сторону | Моторы крутятся с разной скоростью | Программная поправка через TRIM или энкодеры |
| При старте виляет, потом выравнивается | Один мотор трогается позже, или поворачивается поворотное колесо | Плавный старт; шаровая опора вместо поворотного колеса |
| Увод каждый раз разный | Болтающееся колесо, проскальзывающая шина или погнутое крепление мотора | Надень колесо на вал до упора, затяни винты |
| Вместо движения вперёд крутится на месте | У одного мотора перепутаны провода | Поменяй провода этого мотора на клемме OUT |
| Увод растёт по мере разряда аккумулятора | При низком напряжении разница между моторами растёт | Заряди аккумулятор; настраивай TRIM на полном заряде |
| При разгоне тянет в одну сторону | Вес смещён на одну сторону | Перенеси аккумулятор и платы на середину, ближе к оси колёс |
Когда механические проблемы устранены, доводи настройку программно. Константа TRIM в коде замедляет более быстрый мотор на заданный процент: положительное значение замедляет левый мотор, отрицательное — правый. Калибруй так:
- Полностью заряди аккумуляторы: калибровка на полном заряде даёт стабильные результаты.
- Наклей на пол прямую полосу скотча длиной 2 метра и поставь машинку в её начало, направив вдоль скотча.
- В loop() первого скетча оставь только forward() и паузу 3 секунды, затем запусти машинку.
- Если машинку уводит вправо, левый мотор быстрее: увеличь TRIM на 3; если уводит влево, уменьши TRIM на 3.
- Повторяй, пока увод на 2 метрах не сократится до нескольких сантиметров, затем скопируй то же значение TRIM в скетч для Bluetooth.
- Калибруй на той скорости, которую используешь чаще всего: разница между моторами немного меняется со скоростью.
Следующий уровень для идеально прямой езды и измерения расстояния — энкодер. Диски с 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.
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()Робот-машинка на 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.
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:
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 градусов; это основа роботов, проходящих лабиринты.
- Робот-рука: поставь сверху на машинку небольшую робот-руку на сервоприводах, чтобы перевозить предметы.



Частые ошибки и решения
- Ни один мотор не крутится: 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
Преврати телефон в пульт и управляй своей машинкой-роботом. Arduino получает команды из приложения-пульта на телефоне через Bluetooth-модуль и вращает колёса через драйвер моторов; машинка едет вперёд

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

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

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

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

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

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

Работа с сервоприводом
Рычаг маленького сервопривода по очереди поворачивается в три положения: до упора в начало, ровно на середину и до упора в конец, задерживаясь на каждой остановке на две секунды. Arduino сообщает мото
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

