Как собрать машинку на дистанционном управлении
Наверняка все в детстве играли в машинки на пульте управления. В 2024 году у меня появилась идея собрать свою машинку. Как говориться — «Первые 40 лет в жизни мальчика самые сложные».
В основе проекта лежат 2 платы arduino, а также китайский набор, включающий в себя 4 двигателя (прямо как Audi Quattro) и «основу», на которой размещаются все компоненты. Полный список всех модулей будет указан ниже.
В процессе создания проекта можно выделить следующие этапы:
Создание схемы
Закупка компонентов
Сборка/пайка
Программирование
Для начала необходимо осознать:, а что вообще будет представлять из себя машинка?
Ничего сложного, машинка представляет из себя платформу с 4 колесами. Колеса стоят неподвижно, а поворот осуществляется путем изменения скорости вращения правых и левых колес или их полной остановки. Для резких разворотов применяется вращение колес в разные стороны. Это называется — танковый ход.
Для питания схемы используется 2 аккумулятора 18 650 и модуль заряда. Аккумуляторы с номинальным напряжением 3.7 V соединены последовательно, т. е. итоговое напряжение около 7.4 V. Когда они полностью заряжены — будет чуть больше.
Команды с пульта будут передаваться по радиоканалу, поэтому нужно ещё 2 радиомодуля на пульт и на машинку.
Управляться все это будет при помощи 2-х Arduino Uno, как самый простой и доступный способ. Для таких проектов лучше использовать Nano версию, однако в тот момент у меня уже имелось 2 Uno, а ждать не хотелось.
Создание схемы
Начинаем с продумывания «силовой» установки. Придумывать ничего не нужно, в интернете полно схем. Однако, большинство из них описывают подключение 2-х двигателей, а у нас на борту целых 4. Немного покопавшись, удалось найти схему для 4-х двигателей.
Схема, взятая за основу
Основная схема подключения найдена, а значит нужно только её немного доработать.
В схеме в качестве питающего элемента используется Крона, но т.к. в данном проекте используются аккумуляторы, нужно заменить Крону на модуль питания.
Осталось добавить радиомодуль и готово… Но тут неприятный момент. Модуль работает по протоколу SPI, а линии SPI, согласно схеме выше — уже заняты. Придётся немного переделать схему. Радио подключается к SPI выводам платы, а управление драйверами двигателей переключается на свободные пины. Надо быть внимательным, т.к. необходимо, чтобы плата поддерживала аналоговый режим на подключаемых пинах.
Итоговая схема получилась такой:
Итоговая схема
Обратите внимание, для экономии места на схеме показаны 2 шины. От радиомодуля — коричневая с зеленой полосой и от второго драйвера — серая с оранжевой полосой. Цвета проводов взяты с начальной схемы, но итоговый проект собирался с более удобными цветами, поэтому на схеме и на фото они будут отличаться, но это не делает схему не дееспособной.
Как видим из схемы, Arduino не сможет взять на себя силовую нагрузку двигателей, поэтому управление осуществляется через 2 драйвера.
Для пульта управления схема выглядит гораздо проще. Выбираем схему подключения радиомодуля и добавляем к ней джостик. Питание пульта осуществляется по стандартному USB Type‑B разъёму на плате.
Схема пульта
Закупка компонентов
Итоговый набор, необходимый для сборки игрушки:
Arduino Uno — 2 шт.
Джостик
Радиомодуль nrf24l01 — 2 шт.
Драйвер двигателя L298N — 2 шт.
Набор для сборки машинки (4 двигателя, 4 колеса, платформа)
Аккумулятор 18 650 — 2 шт.
Модуль заряда Li‑ion аккумуляторов Type‑C 2S USB BMS 15W 8.4V 1.5A с балансировкой
Отсек для аккумуляторов
Сборка
Сама сборка ничего сложного из себя не представляет, если руководствоваться схемой. Но быстро собрать всё равно не получится, т.к. проводов довольно много, сложно их отслеживать. Паять много не придётся, в данном проекте припаяны только провода к двигателям и к зарядному модулю. Остальное подключается к пинам Ardiuno.
Сборка нижней части
На нижнем уровне закрепляются двигатели и их драйверы. Остальные модули располагаются на верхней платформе. Для надежности можно закрепить хомутами большие элементы.
Итоговый результат
Получился такой вот Франкенштейн. В дальнейшем планируется провести кабель‑менеджмент и распечатать дня машинки внешний корпус на 3D принтере. Пока, как говориться: «На скорость не влияет».
Собрать пульт труда не составляет, поэтому приложу тут только готовую версию с корпусом. Корпус напечатан на 3D принтере, но это уже другая история…
Пульт управления в корпусе
Аппаратная часть схемы собрана, а значит можно поставить аккумуляторы на зарядку и заняться разработкой программного обеспечения.
Программирование
Разработка программного обеспечения ведется в Arduino IDE 2.
Внизу будут ссылки на полные скетчи (так называются программы для Arduino), а тут приведу лишь описание основных циклов и некоторых функций.
Если вы новичок, вам нужно загрузить скетч Car.ino в контроллер машинки, а CarControl.ino в контроллер пульта.
В основном коде пульта ничего сложного не происходит. Считываются показания и отправляются по радиоканалу. Убедитесь, что в setup () у вас совпадают уникальные ID радиоканалов на пульте и машинке.
void loop() {
indications[0] = -(analogRead(pinX) - 512);
indications[1] = -(analogRead(pinY) - 512);
radio.write(&indications, 4);
delay(100);
}
Вся логика зашита в контроллер на машинке. Код основного цикла приведен ниже.
void loop() {
if(radio.available()){ // Если в буфер приёмника поступили данные
radio.read(&indications, 4); // Читаем показания потенциометра
power = indications[0];
turnPower = indications[1];
int motorPower = map(abs(power), 0, 512, 0, 255);
int motorTurnPower = map(abs(turnPower), 0, 512, 0, 255);
if (power > 10) {
forward();
setSpeed(motorPower, turnPower);
} else if (power < -10) {
back();
setSpeed(motorPower, turnPower);
} else {
if (turnPower > 10) {
right();
setSpeed(motorTurnPower, 0);
} else if (turnPower < -10) {
left();
setSpeed(motorTurnPower, 0);
} else {
disable();
setSpeed(0, 0);
}
}
}
delay(50);
}
Если настройки в setup () обеих плат совпадают, то данные будут автоматически приниматься и отправляться во временный буфер. Далее читаем этот буфер и если там что‑то есть, то помещаем принятые данные в локальные переменные.
Таким образом, мы получаем 2 переменные. Значение по оси Y и X, что соответствует 'мощности' вперед/назад и 'мощности' поворота. Для управления силой сигнала, arduino принимает число от 0 до 255, а от стика получаемые числа лежат в диапазоне от -512 до 512. Принятые сигналы перегоняются в диапазон [0; 255].
Теперь у нас 4 переменные:
Значение по X в диапазоне [-512; 512]
Значение по Y в диапазоне [-512; 512]
Модуль значения по Х в диапазоне [0; 255]
Модуль значения по Y в диапазоне [0; 255]
Сами значения служат для определения направления, а модули значений для отправки управляющих сигналов. Во всех условиях используются проверки на минимальное значение — 10, т.к. стик по умолчанию отправляет ненулевое значение. Стик в нуле, но arduino считает, что он немного отклонен. Такая вот фича.
Далее руководствуемся следующей логикой: если стик сильно отклонен вперед, то устанавливаем передний ход. Если назад — то задний. Если же стик по оси Y неподвижен, проверяем ось X и если джостик отклонен по ней — активируем режим разворота на месте в нужную сторону. При несоблюдении никаких условий выше — отключаем моторы.
Немного про функции. Включение переднего/заднего хода или режима разворота на месте осуществляется путем подачи низких и высоких сигналов на драйвер. Значения сигналов для разных режимов можно найти в описании драйвера L298N.
Ниже приведена функция расчёта мощности на каждый двигатель.
void setSpeed(int power, int turn) {
if (turn > 30) {
analogWrite(PIN_ENA, power);
analogWrite(PIN_ENB, map(power - turn, 0, 512, 130, 255));
analogWrite(PIN_ENA_2, map(power - turn, 0, 512, 130, 255));
analogWrite(PIN_ENB_2, power);
} else if (turn < -30) {
analogWrite(PIN_ENA, map(power - turn, 0, 512, 130, 255));
analogWrite(PIN_ENB, power);
analogWrite(PIN_ENA_2, power);
analogWrite(PIN_ENB_2, map(power - turn, 0, 512, 130, 255));
} else {
analogWrite(PIN_ENA, power);
analogWrite(PIN_ENB, power);
analogWrite(PIN_ENA_2, power);
analogWrite(PIN_ENB_2, power);
}
}
Если значения мощности поворота меньше 30 в любую сторону, значение поворота игнорируется и на управляющие выводы передаётся чистое значение по оси Y. т. е. едем вперед или назад.
Если же есть значение поворота, т. е. стик отклонен сразу по 2 осям. Например: правый верхний угол. Тогда нужно ехать вперед и подворачивать машинку направо.
Этот режим работы реализуется путем подачи заниженного значения мощности на одну из сторон. Если хотим повернуть направо — правые колеса вращаются медленнее, чем левые. Это достигается вычитанием Y — X и перерасчётом диапазона [0;512] в [130;255]. Начальное значение в 130 выставлено, чтобы колеса не блокировались полностью при повороте (хотя это иногда происходит).
Результат
Осталось залить программы в контроллеры и готово. Можно играться!
Полные версии скетчей: