CxemCAR на Arduino - Bluetooth управление машинкой с Android. Простая Bluetooth машинка на Arduino Блютуз машинка из ардуино c телефона

Машинка на Ардуино с Bluetooth управлением от Android телефона — это очень простой, но интересный проект на Arduino UNO с использованием модуля Motor Shield. На этой странице вы узнаете какие потребуются компоненты для изготовления робота машинки на Ардуино своими руками, пошаговую инструкцию по сборке электрической схемы и сможете скачать все необходимые программы для Android и Arduino.

Для этого проекта использовался модуль Motor Shield L293D , два колеса с редукторами, плата Arduino UNO, блютуз модуль HC-05 и два светодиода для фар. Управление происходит дистанционно через Bluetooth сигнал от смартфона или планшета. После сборки модели и установки программ, вы сможете через приложение на смартфоне поворачивать машинкой, ездить вперед и назад, включать и выключать фары.

Машинка на Ардуино своими руками

Для этого проекта нам потребуется:

  • плата Arduino Uno / Arduino Nano / Arduino Mega;
  • Motor Control Shield L293D;
  • Bluetooth модуль HC-05/06;
  • два мотора с редукторами и колесами;
  • аккумулятор 9 Вольт (крона);
  • 2 резистора и 2 светодиода;
  • корпус и колеса от старой машинки;
  • паяльник, термопистолет, провода, припой и т.д.
Детали для робота — машинки на Ардуино УНО

Схема сборки машинки на Ардуино

Если у вас есть все необходимые детали (в проекте можно обойтись без светодиодов и резисторов), то далее мы рассмотрим, как сделать машинку из ардуино своими руками. Для начала следует припаять к контактам моторчиков провода и зафиксировать их изолентой, чтобы контакты не оторвались. Провода необходимо соединить с клеммниками M1 и M2 на Motor Shield (полярность потом можно будет поменять).


Питание на Bluetooth модуль идет от контактов для сервопривода, в проекте серво нам не понадобятся. А на питание идет стабилизированное напряжение 5 Вольт, что нам подходит. К портам TX и RX удобнее будет припаять коннекторы «мама», а к портам «Pin0» и «Pin1» на Motor Shield припаять штырьки (BLS). Таким образом, вы сможете легко отключать Bluetooth модуль от Arduino при необходимости загрузки скетча.

Управление светодиодами идет от порта «Pin2», здесь провод можно припаять напрямую к порту. Если вы делаете несколько машинок с Блютуз, которыми будете управлять одновременно, то рекомендуем сделать перепрошивку модуля HC-05 . Делается прошивка модуля очень просто, а затем вы уже не будете путать машинки, так как у каждой будет отображаться свое уникальное имя на Андроиде.

Приложение и скетч для машинки на Ардуино

После сборки схемы загрузите следующий скетч для машинки (не забудьте отключать Bluetooth модуль от Ардуино при загрузке) и установите приложение на смартфоне. Все файлы для проекта (библиотека AFMotor.h, скетч для машинки и приложение для Android) можно скачать одним архивом по прямой ссылке . Работу скетча можно проверить управлением машинки от компьютера через Serial Monitor по USB.

#include // подключаем библиотеку для шилда AF_DCMotor motor1(1); // подключаем мотор к клеммнику M1 AF_DCMotor motor2(2); // подключаем мотор к клеммнику M2 int val; // освобождаем память в контроллере void setup () { Serial .begin (9600); pinMode (2, OUTPUT ); // Порт для светодиодов motor1.setSpeed (250); motor1.run (RELEASE ); // останавливаем мотор motor2.setSpeed (250); // задаем максимальную скорость мотора motor2.run (RELEASE ); // останавливаем мотор } void loop () { if (Serial .available ()) // проверяем, поступают ли какие-то команды { val = Serial .read (); if (val == "f") { // едем вперед motor1.run (FORWARD ); motor1.setSpeed (250); motor2.run (FORWARD ); motor2.setSpeed (250); } if (val == "b") { // едем назад motor1.run (BACKWARD ); motor1.setSpeed (200); motor2.run (BACKWARD ); motor2.setSpeed (200); } if (val == "s") { // останавливаемся motor1.run (RELEASE ); motor2.run (RELEASE ); } if (val == "l") { // поворачиваем налево motor1.run (FORWARD ); motor1.setSpeed (100); motor2.run (BACKWARD ); motor2.setSpeed (250); } if (val == "r") { // поворачиваем направо motor1.run (BACKWARD ); motor1.setSpeed (250); motor2.run (FORWARD ); motor2.setSpeed (100); } if (val == "1") { // включаем светодиоды digitalWrite (2,HIGH ); } if (val == "0") { // выключаем светодиоды digitalWrite (2,LOW ); } } }

Пояснения к коду:

  1. для тестирования, можно отправлять команды с компьютера через USB;
  2. вращение моторов при подключении к аккумулятору будут отличаться;
  3. вы можете задавать свою скорость вращения моторами.

После проверки работы машинки, установите приложение на смартфон или планшет. При первом подключении к Bluetooth модулю HC-05/06, потребуется сделать сопряжение с Андроид (затем сопряжение будет выполняться автоматически). Если у вас возникли сложности с подключением — прочитайте эту статью

В статье рассмотрим подключение и управление Arduino по bluetooth.

В качестве блютуз-модуля будет использоваться широко распространенный hc-06.

В нашем проекте будем через bluetooth включать и выключать светодиод, подключенный к 13 порту.

Начнем с написания приложения на android-смартфон. Приложение будет писаться в удобной и простой среде программирования App Inventor. Программы будут составляться онлайн.

Пройдите по ссылке http://ai2.appinventor.mit.edu/ . Там вас попросят войти в Google-аккаунт, который вам придется завести, если его еще нет.

После входа вы попадете в программу, где сможете создать проект нажав «start new project». Вам потребуется ввести имя проекта. Назовем его led_control.

Откроется пустое окно приложения.

Здесь будем располагать необходимые компоненты. Выберите ListPicker в окне слева и поместите его в проект.

У компонента ListPicker в окне справа найдите свойство Text, и измените «Text for ListPicker1» на «Выберите BT-устройство».

Откройте закладку Layout в окне слева, поместите в приложение компонент HorizontalArrangement, измените его свойство Width на «Fill parent». Добавьте в HorizontalArrangement 2 кнопки Button, у каждой из них установите свойство Width в «Fill parent». Должно получиться так:

Изменим подписи на кнопках: на первой будет написано LED ON, на второй — LED OFF.

Ниже добавим Label и очистим его Text.

Осталось добавить компонент, организующий передачу данных по bluetooth. Откройте закладку Connectivity и поместите в проект BluetoothClient. Этот компонент окажется не на экране телефона, а под ним, т.к. он не является визуальным.

Теперь можно приступать к написанию программы. В верхней правой части программы выберите режим Blocks.

Здесь будет составляться программа из графических блоков. Слева кликните на компонент ListPicker1 и выберите ListPicker1.BeforePicking.

Снова нажмите на ListPicker1 и выберите set ListPicker1.Elements to

Поставьте его как на скриншоте.

Этим мы получили список сопряженных bluetooth-устройств. Теперь подключимся к выбранному устройству. Напишите блок как на скриншоте ниже.

Розовый блок с надписью Connected — это первый блок в закладке Text. Впишите Connected в пустое окошко.

Теперь напишем обработчик кнопок. При нажатии на первую кнопку будет отсылаться текст «led_on», а при нажатии на вторую — «led_off». Так же будет изменяться и надпись в Label1.

Осталось загрузить проект в ваш смартфон. Нажмите Build и выберите способ загрузки.

Для первого варианта вам понадобятся интернет и считыватель QR-кодов. Нажмите и дождитесь окончания сборки проекта и формирования QR-кода, после чего откройте считыватель QR-кодов на смартфоне и считайте код. Останется только загрузить и установить файл.

Во втором варианте проект в формате.apk сохранится на ваш компьютер и вы сможете скинуть его на смартфон любым удобным способом (например по USB).

Теперь займемся программой на Arduino.

Прием-передача данных осуществляется через COM-порт, поэтому будем использовать Serial. Будем посимвольно принимать сигналы, формировать строку и дальше сравнивать сформированную строку с командами led_on и led_off.

Arduino

String val = ""; void setup() { Serial.begin(9600); pinMode(13, OUTPUT); } void loop() { while (Serial.available()) { //пока приходят данные char c = Serial.read(); //считываем их val += c; //и формируем строку delay(3); } if (val != "") { Serial.println(val); } if (val == "led_on") { digitalWrite(13, HIGH); } else if (val == "led_off") { digitalWrite(13, LOW); } val = ""; }

String val = "" ;

void setup () {

Serial . begin (9600 ) ;

pinMode (13 , OUTPUT ) ;

void loop () {

while (Serial . available () ) { //пока приходят данные

char c = Serial . read () ; //считываем их

val += c ; //и формируем строку

delay (3 ) ;

}

Загрузите код в Arduino.

Теперь можно подключить Bluetooth-модуль HC-06. Подключается он очень просто:

Vcc 5v (можно 3,3 v)

ЕСЛИ ПОПЫТАТЬСЯ ЗАГРУЗИТЬ ПРОГРАММУ В ARDUINO С ПОДКЛЮЧЕННЫМ МОДУЛЕМ, ТО ВЫЛЕЗЕТ ОШИБКА, Т.К. И МОДУЛЬ И ЗАГРУЗКА ПРОГРАММЫ ЗАДЕЙСТВУЮТ ПОРТЫ RX И TX!

Подайте питание на Arduino. На bluetooth-модуле должен заморгать светодиод, это означает, что он ожидает подключения. Возьмите смартфон, найдите в настройках bluetooth, включите его и запустите поиск. Найдите устройство с именем hc-06 и подключитесь к нему. С первого раза может не получиться. После однократного успешного сопряжения можно запускать программу на смартфоне.

Сначала нажмите на «Выберите BT-устройство» и выберите модуль среди сопряженных устройств. Далее нажимайте кнопки включения и выключения светодиода. Если все сделано правильно, то все будет работать.

Мы сделали очень простое приложение с использованием Bluetooth, без дизайна и даже проверки, подключились мы к модулю или нет. В следующих уроках будем делать более сложные приложения и получше познакомимся с App Inventor.

И работу с ним.

Модернизация Motor Shield

Получилось так, что производители модуля Motor Shield лишили своих покупателей возможности устанавливать поверх своего продукта другой модуль. Видимо им нравится быть сверху или просто зажали нормальную панельку контактов.

Меня этот нюанс совсем не устраивает. Именно поэтому я решил взяться за паяльник и привести Motor Shield к удобному для меня виду.


Аккуратно выдрал родные панельки контактов и выкинул их нафиг.


Установил на их место нормальные.


В таком виде модулем стало пользоваться гораздо удобнее. Теперь я смогу нормально подключить провода от Bluetooth в разъемы, а не припаивать их намертво к контактам на Motor Shield.

Bluetooth модуль JY-MCU для Arduino


Сам Bluetooth модуль JY-MCU довольно миниатюрный. В комплект поставки входит кабель для подключения. Назначение выводов расписано на обратной стороне.


Запитать его можно от источника питания 3,6-6В. Это предоставляет нам возможность подключить его напрямую к Arduino без использования стабилизатора или делителя напряжения.

Код, используемый при подключении к устройству: 1234.

Подключение Bluetooth JY-MCU к Arduino Mega 2560

Подключение довольно простое.

Официальная схема подключения:

  • TXT на JY-MCU подключаем к RX (0) на Arduino
  • RXD на JY-MCU подключаем к TX (1) на Arduino

При таком варианте подключения придется каждый раз отключать питание модуля Bluetooth перед загрузкой скетча. Не забывайте про это.

Меня такой вариант не устраивает, поэтому я решил использовать дискретные порты с поддержкой Serial.

Неофициальная схема подключения:

  • VCC на JY-MCU подключаем к +5В Arduino
  • GND на JY-MCU подключаем к GND Arduino
  • TXT на JY-MCU подключаем к дискретному PIN 50 на Arduino
  • RXD на JY-MCU подключаем к дискретному PIN 51 на Arduino

Вот теперь можно загружать скетчи без отключения питания модуля Bluetooth.

Чтобы закрепить Bluetooth, я решил использовать плату Proto Shield и миниатюрную беспаечную макетную плату. К ней в будущем и буду подключать остальное оборудование, элементы управления и индикации.




Скетч для управления роботом на Arduino по Bluetooth через смартфон на Android

В своём скетче я реализовал следующие функции:

  • Движение вперед
  • Движение назад
  • Разворот влево
  • Разворот вправо
  • Плавный поворот влево при движении вперед
  • Плавный поворот вправо при движении вперед
  • Плавный поворот влево при движении назад
  • Плавный поворот вправо при движении назад
  • Остановка
  • Установка скорости 0%

    Установка скорости 10%

    Установка скорости 20%

    Установка скорости 30%

    Установка скорости 40%

    Установка скорости 50%

    Установка скорости 60%

    Установка скорости 70%

    Установка скорости 80%

    Установка скорости 90%

    Установка скорости 100%

В скетче использовал функции, чтобы не дублировать код при схожих событиях.

#include // Подключаем библиотеку для управления двигателями
#include // Подключаем библиотеку для сервоприводов
#include // Подключаем библиотеку для работы с Serial через дискретные порты

//Создаем объекты для двигателей
AF_DCMotor motor1(1); //канал М1 на Motor Shield - задний левый
AF_DCMotor motor2(2); //канал М2 на Motor Shield - задний правый
AF_DCMotor motor3(3); //канал М3 на Motor Shield - передний левый
AF_DCMotor motor4(4); //канал М4 на Motor Shield - передний правый

// Создаем объект для сервопривода
Servo vservo;

SoftwareSerial BTSerial(50, 51); // RX, TX

// Создаем переменную для команд Bluetooth
char vcmd;
// Создаем переменные для запоминания скорости двигателей
int vspdL, vspdR;
/* Создаем переменную, на значение которой будет уменьшаться скорость при плавных поворотах.
Текущая скорость должна быть больше этого значения. В противном случае двигатели со стороны направления поворота просто не будут вращаться */
int vspd = 200;

void setup() {
// Устанавливаем скорость передачи данных по Bluetooth
BTSerial.begin(9600);
// Устанавливаем скорость передачи данных по кабелю
Serial.begin(9600);
// Выбираем пин к которому подключен сервопривод
vservo.attach(9); // или 10, если воткнули в крайний разъём
// Поворачиваем сервопривод в положение 90 градусов при каждом включении
vservo.write(90);
// Устанавливаем максимальную скорость вращения двигателей
vspeed(255,255);
}

void loop() {
// Если есть данные
if (BTSerial.available())
{
// Читаем команды и заносим их в переменную. char преобразует код символа команды в символ
vcmd = (char)BTSerial.read();
// Отправляем команду в порт, чтобы можно было их проверить в "Мониторе порта"
Serial.println(vcmd);

// Вперед
if (vcmd == "F") {
vforward();
}
// Назад
if (vcmd == "B")
{
vbackward();
}
// Влево
if (vcmd == "L")
{
vleft();
}
// Вправо
if (vcmd == "R")
{
vright();
}
// Прямо и влево
if (vcmd == "G")
{
vforwardleft();
}
// Прямо и вправо
if (vcmd == "I")
{
vforwardright();
}
// Назад и влево
if (vcmd == "H")
{
vbackwardleft();
}
// Назад и вправо
if (vcmd == "J")
{
vbackwardright();
}
// Стоп
if (vcmd == "S")
{
vrelease();
}
// Скорость 0%
if (vcmd == "0")
{
vspeed(0,0);
}
// Скорость 10%
if (vcmd == "1")
{
vspeed(25,25);
}
// Скорость 20%
if (vcmd == "2")
{
vspeed(50,50);
}
// Скорость 30%
if (vcmd == "3")
{
vspeed(75,75);
}
// Скорость 40%
if (vcmd == "4")
{
vspeed(100,100);
}
// Скорость 50%
if (vcmd == "5")
{
vspeed(125,125);
}
// Скорость 60%
if (vcmd == "6")
{
vspeed(150,150);
}
// Скорость 70%
if (vcmd == "7")
{
vspeed(175,175);
}
// Скорость 80%
if (vcmd == "8")
{
vspeed(200,200);
}
// Скорость 90%
if (vcmd == "9")
{
vspeed(225,225);
}
// Скорость 100%
if (vcmd == "q")
{
vspeed(255,255);
}
}
}

// Вперед
void vforward() {
vspeed(vspdL,vspdR);
vforwardRL();
}

// Вперед для RL
void vforwardRL() {
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
}

// Назад
void vbackward() {
vspeed(vspdL,vspdR);
vbackwardRL();
}

// Назад для RL
void vbackwardRL() {
motor1.run(BACKWARD);
motor2.run(BACKWARD);
motor3.run(BACKWARD);
motor4.run(BACKWARD);
}

// Влево
void vleft() {
vspeed(vspdL,vspdR);
motor1.run(BACKWARD);
motor2.run(FORWARD);
motor3.run(BACKWARD);
motor4.run(FORWARD);
}

// Вправо
void vright() {
vspeed(vspdL,vspdR);
motor1.run(FORWARD);
motor2.run(BACKWARD);
motor3.run(FORWARD);
motor4.run(BACKWARD);
}

// Вперед и влево
void vforwardleft() {
if (vspdL > vspd) {
vspeed(vspdL-vspd,vspdR);
}
else
{
vspeed(0,vspdR);
}
vforwardRL();
}

// Вперед и вправо
void vforwardright() {
if (vspdR > vspd) {
vspeed(vspdL,vspdR-vspd);
}
else
{
vspeed(vspdL,0);
}
vforwardRL();
}

// Назад и влево
void vbackwardleft() {
if (vspdL > vspd) {
vspeed(vspdL-vspd,vspdR);
}
else
{
vspeed(0,vspdR);
}
vbackwardRL();
}

// Назад и вправо
void vbackwardright() {
if (vspdR > vspd) {
vspeed(vspdL,vspdR-vspd);
}
else
{
vspeed(vspdL,0);
}
vbackwardRL();
}

// Стоп
void vrelease(){
motor1.run(RELEASE);
motor2.run(RELEASE);
motor3.run(RELEASE);
motor4.run(RELEASE);
}

// Изменение скорости
void vspeed(int spdL,int spdR){
if (spdL == spdR) {
vspdL=spdL;
vspdR=spdR;
}
motor1.setSpeed(spdL);
motor2.setSpeed(spdR);
motor3.setSpeed(spdL);
motor4.setSpeed(spdR);
}

Программа Bluetooth RC Car - управление роботом-машинкой со смартфона на Android

В свой смартфон я установил программу Bluetooth RC Car . На мой взгляд - это лучшая софтинка для управления роботом-машинкой.


Программа позволяет передавать команды при нажатии на кнопки или реагировать на данные с акселерометра в смартфоне, регулировать скорость движения ползунком, включать передние и задние фонари, включать и выключать звуковой сигнал, включать и выключать сигнал “аварийка”.




Для работы программы требуется Android версии 2.3.3 или выше. Размер программы 3 мегабайта.

Список команд:

  • F – вперед
  • B – назад
  • L – влево
  • R – вправо
  • G – прямо и влево
  • I – прямо и вправо
  • H – назад и влево
  • J – назад и вправо
  • S – стоп
  • W – передняя фара включена
  • w – передняя фара выключена
  • U – задняя фара включена
  • u – задняя фара выключена
  • V – звуковой сигнал включен
  • v – звуковой сигнал выключен
  • X – сигнал “аварийка” включен
  • x - сигнал “аварийка” выключен
  • 0 – скорость движения 0%
  • 1 – скорость движения 10%
  • 2 – скорость движения 20%
  • 3 – скорость движения 30%
  • 4 – скорость движения 40%
  • 5 – скорость движения 50%
  • 6 – скорость движения 60%
  • 7 – скорость движения 70%
  • 8 – скорость движения 80%
  • 9 – скорость движения 90%
  • q – скорость движения 100%

Как вы видите, полигон для творчества вполне неплохой. Я бы еще добавил возможность раздельного включения правых и левых фонарей для передних и задних фар.

Жирным я выделил команды, поддержка которых уже реализована в скетче. Остальные я собираюсь использовать по другому назначению.

Принцип передачи команд: при нажатии на кнопку в программе, команда передается по Bluetooth один раз, а при отпускании кнопки сразу передается команда S-остановка.

Демонстрация работы

В следующий раз я планирую подключить к роботу ультразвуковой дальномер и реализовать алгоритм объезда препятствий.

Не будем покупать плохие игрушки у Китайцев, а купим у них дешевый конструктор-шасси, несколько модулей и приложим руки!

Вот что у меня получилось в итоге: проходимое шасси, управляемое - ТА-ДА!!! - с моего смартфона на Андроиде.


«Я и прямо, я и боком,
С поворотом, и с прискоком,
И с разбега, и на месте,
И двумя ногами вместе…»

Сегодня мы соберём забавную машинку с дистанционным управлением по Bluetooth. Исходники программы управления под Android в комплекте.

Достойный образец игрушки

У меня двое детей, дочь и сын. Обоим на дни рождения дарят игрушки. То, что дарят дочери, как правило, не вызывает моих негативных реакций. А сыну, как и полагается, дарят всевозможные машинки, танки и прочую технику. Из всей этой прорвы китайщины у меня не вызывает нареканий только игрушечная бензопила, которую я сам и подарил.

Почему так? Наверное потому что эта пила продавалась в магазине инструментов «STIHL». Как я полагаю, «STIHL» сделал игрушечный аналог своей продукции небольшим рекламным тиражом. В результате появилась на свет вполне вменяемая игрушка, очень похожая на своего старшего брата. Цепь резиновая – крутится, процентов на 80 реализованы органы управления. Есть даже шнур с ручкой для завода пилы, выключатель, кнопка газа. В комплекте есть запасная цепь и инструмент для смены цепи.


Вот такая игрушечная пила

О чём это я? Ах, да, об архитектуре! Это я к тому, что при желании отличную игрушку сделать можно. И есть на что равняться.

Будем строить машинку с ДУ!

Практический и технический интерес вызывают игрушки с радиоуправлением. Однако, ребёнку в возрасте 4-6 лет не будут дарить игрушки со «взрослым» пропорциональным управлением. Скорее всего, игрушка будет сломана, а деньги выкинуты на ветер.
В итоге, обычно дарят что-то недорогое. Из всего этого – «недорогого» - машинки или шибко быстрые или тормозные; танки хилые; и прочие очевидные и скрытые недостатки. И уж конечно никакого пропорционального управления.

В один прекрасный день у одной из машинок перестало вращаться правое колесо. Разобрал, проверил моторчик – исправный.
На плате управления три микросхемы – Китай голимый, вменяемой документации найти не смог. Один чип – приёмник радиосигнала с логическими выходами и два мостовых драйвера двигателей. Один из драйверов вышел из строя. Сваять сходу мостовой драйвер двигателя из дискретных компонентов у меня не получилось.

В местном магазине радиодеталей ничего подходящего не было. Вот я и подался в дальние страны за чудо-микросхемами. Собрал пожитки, набил карманы сухарями, налил чашечку кофе, запустил браузер и пошел… .
Нашел подходящий по параметрам драйвер двигателя, заказал сразу два. На всякий случай, вдруг один будет неисправен или сам спалю. Вот тогда и начала зарождаться мысль о своей машинке. После того, как посылка дошла из славного Китая, я успешно заменил драйвер и машинка была отремонтирована.

Не откладывая в долгий ящик идею о своей машинке, я снова подался для выбора основы - шасси будущей машинки. Шасси бывают разные, для наземного транспорта: гусеничные, колесные, с двумя, тремя, четырьмя колесами и т.п.

Как я выбирал шасси

Во-первых, я выбрал наземный вид транспорта, значит и шасси у меня будет наземное. Гусеничные шасси, как правило, дороже и не слишком быстроходные. Двух-трёх-колесные мне кажутся слабо проходимыми, такое шасси сможет ездить только по ровной поверхности.
Я остановился на . По моему мнению, такое шасси будет обладать отличной проходимостью и скоростью.


В комплекте поставки шасси:
две пластины из акрила с кучей технологических отверстий для крепления все возможных датчиков, плат управления и прочих компонентов
4 колеса
4 привода в сборе (электродвигатель + редуктор)
4 диска с прорезями для датчиков скорости, по одному на каждое колесо
крепеж
Да, это снова Китай. Да, дешёвый. Да, нешибко качественный. НО! Нам бы для начала попробовать. Ведь «взрослое» шасси и стоит по-взрослому, мы до него ещё не доросли.

Болото мыслей и Техзадание

Когда держишь в руках перспективную вещь, например, в плане возможностей по обвесу модели всевозможными датчиками, серво и пр., начинаешь тонуть в болоте мыслей и трясине перспектив. Но, скажем себе - СТОП! И составим себе мини-ТЗ на прототип с кратким описанием всех узлов.
У нас должна получиться RC-модель наземного траспортного средства с управлением по Bluetooth, с возможностью реверса и плавного регулирования скорости вращения колес.

Что нам потребуется для сборки машинки?

.


Поворотные колеса отсутствуют, значит, управление поворотом будет как у гусеничного ТС. То есть, для прямого движения, вперед/назад, правая и левая сторона приводов вращаются с одинаковой скоростью. А для осуществления поворота, скорость вращения на одной из сторон должна быть меньше или больше.


Для дистанционного управления машинкой используем канал Bluetooth. Модуль «HC-06» - это мост Bluetooth, последовательный интерфейс, позволяющий передавать данные в обе стороны. На входе - TTL-сигналы последовательного интерфейса «RxD» и «TxD» для подключения к микроконтроллеру (целевой плате).
В качестве пульта дистанционного управления будет служить сотовый телефон с Android. Напишем свою программу!



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


Выбрана эта плата т.к. валялась в ящике стола и полностью подходит для нашей цели. Есть дискретные входы/выходы, выведены сигналы МК «RxD» и «TxD», куда будет подключен «HC-06“.
Забегая вперёд скажу, что продукт Олимекс MOD-IO - это жёсткий перебор. Прекрасно можно будет применить и обычную , о чём в продолжении истории!

Итого: шасси + плата управления + Bluetooth-модуль + программа управления под Android.

Общая схема подключения

Не схема в чистом виде, а именно схема подключения, так как все платы у нас уже готовые, и остаётся их соединить между собой.

Схема в Протеусе


Расписывать, что и куда я подключил не буду. Скорее всего у вас будет другая плата управления. Исходники я прикладываю, так что прошивку сможете править. Ну, а если кто-то не в силах скомпилировать прошивку под свою плату, обращайтесь - помогу по мере свободного времени.

Программа микроконтроллера

Программа МК умеет принимать команды по последовательному интерфейсу с Bluetooth-модуля.
И, в соответствии с командами, управлять левой и правой парой приводов. Реверс и управление скоростью работают при помощи ШИМ.

Код в достаточной мере прокомментирован. Хочу отдельно остановиться на моей реализации обмена данными.
Приём данных у меня реализован через кольцевой буфер. Вещь не новая и реализаций много.

Функции кольцевого буфера у меня вынесены в отдельную библиотеку состоящую из:
заголовочного файла ring_buffer.h и файла реализаций функций ring_buffer.с
Для использования библиотеки её нужно подключить в main.c
#include "ring_buffer.h"

Далее, в заголовочном файле необходимо настроить библиотеку. Для настройки необходимо задать всего четыре директивы:
#define RX_PACKET_SIZE 7 // Размер RxD пакета #define BUFFER_SIZE 16 // Размер приёмного буфера. Должен быть в два раза больше RX_PACKET_SIZE #define START_BYTE "s" // Стартовый байт #define STOP_BYTE "e" // Стоповый байт

Собственно настраивать больше нечего.

Использование кода В main.c настраиваем USART микроконтроллера.
Вызываем функцию настройки USART
USART_Init(MYUBRR);

#define BAUD 9600 #define MYUBRR F_CPU/16/BAUD-1 void USART_Init(unsigned int ubrr) { /* Set baud rate */ UBRRH = (unsigned char)(ubrr >> 8); UBRRL = (unsigned char)ubrr; /* Enable receiver and transmitter */ UCSRB = (1 << TXCIE) | (1 << RXCIE)| (1 << TXEN) | (1 << RXEN); /* Set frame format: 8data, 2stop bit */ UCSRC = (1 << URSEL) | (0 << USBS) | (3 << UCSZ0); }

Приём пакета данных

В функции обработчика прерывания приема байта по USART, нам необходимо всего лишь положить принятый байт в кольцевой буфер. Разбор пакета будем делать потом.
ISR(USART_RXC_vect) { uint8_t Data = UDR; RB_push_char(Data); // Складываем принятый байт в кольцевой буфер }
Да, я пока пренебрег всякими проверками фрейма.

Теперь нам остается время от времени проверять наш буфер. Для этого я инициировал таймер, в котором я устанавливаю флаг разрешающий проверку кольцевого буфера
ISR(TIMER0_OVF_vect) { TCNT0 = 0x64; ReadRingBuffer = 1; }

В основном цикле добавляем условие для проверки флага.
if (ReadRingBuffer) { if (RB_read_buffer((uint8_t*)&RxPacket) == 1) Чтение буфера { // Разбираем пакет, делаем что-нибудь } ReadRingBuffer = 0; }

Функция RB_read_buffer проверяет кольцевой буфер, если размер пакета, стартовый и стоповые байты находятся на своих местах - пакет считается валидным, функция возвращает "1». В качестве аргумента, функция принимает указатель, куда складывать принятый пакет.
Для пущей надежности, пакет можно снабдить контрольной суммой, в одном из своих коммерческих проектов я так и сделал. То есть к проверке размера, старт/стопового байтов прибавляется еще проверка контрольной суммы. Но пока обойдемся без неё.

Как я разбираю пакет

Теперь самое интересное, как я разбираю пакет. В пакете могут передаваться данные размерностью больше байта, знаковые данные, данные с плавающей точкой.
Объясню на примере пакета для управления шасси. Кроме стартового и стопового байтов, в своём пакете мне необходимо передавать одну команду, и два значения ШИМ, для левой и правой стороны приводов. Для команды мне достаточно одного байта, а для каждого значения ШИМ, я передаю int16 - 16 бит, знаковый тип. То есть, я не передаю флаг (байт/признак) направления. Для смены направления, я передаю положительное или отрицательное значение ШИМ.

Приёмный пакет у меня организован в виде структуры.
struct RxPacket { uint8_t StartByte; uint8_t Command; int16_t Left_PWM; int16_t Right_PWM; uint8_t StopByte; } RxPacket;

Вызывая функцию RB_read_buffer ((uint8_t*)&RxPacket ) , в качестве аргумента передаем указатель на структуру приёмного пакета. То есть, при принятом пакете, будет все разложено по своим полочкам в структуре RxPacket. Дальше остается прочитать эти данные из структуры например так:
lCmd = RxPacket.Command; lLPWM = RxPacket.Left_PWM; lRPWM = RxPacket.Right_PWM;

Передача пакета данных

Хоть в моей программе передача пока не используется, тем не менее, возможность передачи реализована. Передавать данные проще. Точно также, как и для приемного пакета, создадим структуру:
struct TxPacket { uint8_t StartByte; uint8_t Rc5System; uint8_t Rc5Command; uint8_t StopByte; } TxPacket;

Где, есть стартовый и стоповый байт и информационная часть. Мы уже инициализировали приемник USART.
Для инициирования передачи пакета - вызываем функцию
void send_packet() { // Запись стартового байта в регистр UDR UDR = START_BYTE; }
В данном примере, в этой функции, я записываю только стартовый байт в регистр UDR. Вроде бы немного, но в этой же функции можно реализовать подготовку пакета или еще что-то полезное. И это, на мой взгляд более логично. Логично в плане самодокументирования кода. То есть, если я в коде, просто запишу значение в регистр UDR это может быть воспринято, как передача всего одного байта, а вызывая самоговорящую функцию send_packet () - я говорю о том, что я отправляю пакет данных.

Далее, когда передатчик USART отправит весь байт из регистра UDR - будет вызван обработчик прерывания по передаче.
ISR(USART_TXC_vect) { unsigned char *Pointer = (unsigned char *)&(TxPacket); static unsigned char TxIndex = 1; if (TxIndex < sizeof(TxPacket)) { UDR = *(Pointer + TxIndex); TxIndex++; } else TxIndex = 1; }

В обработчике я объявляю переменную указателя и присваиваю её адрес структуры TxPacket. Далее объявляется статическая переменная - индекс передаваемого байта, которой при объявлении присвоено значение 1 . Начинаем с одного потому, что первый байт из структуры мы уже отправили. В целом, в структуре можно обойтись и без стартового байта, все равно я его отправляю отдельно, но объявления этого байта оставлено в структуре для понимания того как выглядит пакет.

Условие if (TxIndex < sizeof(TxPacket)) проверяет, что индекс меньше чем размер пакета. Если условие верно, то записываем байт в регистр UDR: UDR = *(Pointer + TxIndex);
инкрементируем TxIndex. Когда USART передаст очередной байт, то мы снова попадём в обработчик, но будет передан уже следующий байт из структуры и так будут переданы все байты структуры. Когда TxIndex будет больше чем размер структуры - условие будет не верно и мы попадем в else TxIndex = 1; Где будет проинициализирован TxIndex, но в регистр UDR уже ничего не записывается, соответственно обработчик больше не будет вызван до следующего инициирования передачи пакета. Таким образом, процесс передачи полностью автоматический, и даже, если мы изменим структуру пакета, то обработчик переписывать не придётся.

В рамках описания программы МК осталось рассказать про реализацию управления драйверами. Драйвер управляется тремя сигналами: A1 (B1), A2 (B2) и PWMA (PWMB). A1 и A2 предназначены для включения/выключения драйвера и для изменения полярности выхода. На вход PWMA подается ШИМ сигнал с МК - можно управлять скоростью вращения. Для ШИМ сигнала я задействовал два аппаратных ШИМа таймера 1.
#define _WGM13 0 #define _WGM12 1 #define _WGM11 0 #define _WGM10 1 // Timer 1 init TCCR1A = (1 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) | (_WGM11 << WGM11) | (_WGM10 << WGM10); TCCR1B = (0 << CS12) | (0 << CS11) | (1 << CS10) | (_WGM13 << WGM13) | (_WGM12 << WGM12); TCNT1 =0x0000; OCR1A = 0; OCR1B = 0;

Таймер 16-битный, но ШИМ инициализирован на 8 бит. И как вы наверное уже заметили, в приёмном пакете у меня есть два значения для задания ШИМ, для левого и правого привода соответственно. Переменные знаковые 16-битные.
Объясню почему я так сделал.

Во-первых , это пошло от программы под Андроид. Дело в том что в Java нет без знаковых типов и я уже наступал на эти грабли. И для передачи числа от 0 до 255 мне пришлось бы как то извернуться. Я решил пойти более простым путем - отсылаю знаковое 16-бит число. При этом, 16 бит знакового типа это от -32786 до 32768, нам хватит.

Во-вторых , так на мой взгляд более прозрачно - скорость вращения и направления описывается всего одной переменной.

И в-третьих , как не крути, для наших целей меньше чем в три байта не уложиться. Пожертвуем еще одним байтом, зато всё становится понятно, положительное значение ШИМ - прямое вращение, отрицательное значение - обратное вращение.

Для управления приводами я написал функцию drive (int leftPWM, int rightPWM); .
void drive(int leftPWM, int rightPWM) { // Движение ВПЕРЁД левое колесо if (leftPWM > 0){ ClearBit(A2_PORT, A2_PIN); SetBit(A1_PORT, A1_PIN); } // Движение НАЗАД левое колесо if (leftPWM < 0){ ClearBit(A1_PORT, A1_PIN); SetBit(A2_PORT, A2_PIN); } // Движение ВПЕРЁД правое колесо if (rightPWM > 0){ ClearBit(B2_PORT, B2_PIN); SetBit(B1_PORT, B1_PIN); } // Движение НАЗАД правое колесо if (rightPWM < 0){ ClearBit(B1_PORT, B1_PIN); SetBit(B2_PORT, B2_PIN); } // Остановка if (leftPWM == 0){ ClearBit(A1_PORT, A1_PIN); ClearBit(A2_PORT, A2_PIN); } // Остановка if (rightPWM == 0){ ClearBit(B1_PORT, B1_PIN); ClearBit(B2_PORT, B2_PIN); } set_PWM((uint8_t)(abs(leftPWM)), (uint8_t)(abs(rightPWM))); }
В соответствии со значением ШИМ, осуществляется управление сигналами A1 (B1), A2 (B2) и устанавливается значение ШИМ вызовом функции set_PWM (leftPWM, rightPWM) .

Уфф, выдохся…
Подытожим: приняли пакет, разобрали, передали значение ШИМ в функцию drive .

Приложение под Android для машинки

Нет, так подробно, как программу для МК я разбирать не буду. В разработке ПО под Android я ещё новичок и не готов рассказывать достаточно компетентно и глубоко.

Основная функция программы - передача данных модулю HC-06 по каналу Bluetooth. Программа имеет не замысловатый интерфейс.

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

Дальше кнопка «Выкл» - включает/отключает связь с «HC-06». Ниже слева направо: передаваемое значение ШИМ левого канала, тип датчика, значение правого канала. Ниже два слайдера регулировки чувствительности скорости и поворота.

В программе реализовано два типа управления машинкой. Для переключение типа датчика нужно коснуться надписи названия датчика: «Наклон» или «Шаркать».

1. Управление машинкой с помощью наклона телефона. Нулевое положение телефона - горизонтальное. При наклоне телефона вперед значение ШИМ увеличивается пропорционально наклону в диапазоне от 0 до 255 . При наклоне телефона назад значение ШИМ уменьшается пропорционально наклону в диапазоне от 0 до -255


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

2. Управление касанием. Моё фирменное название для такого управления - «шаркать».


Можно воспринимать как тачпад. При касании в сером квадрате, значение ШИМ увеличивается/уменьшается в зависимости от места касания, чем дальше от центра вниз или вверх тем больше/меньше значение.

Никаких «красивостей» и наворотов нет. Вот вроде бы и всё.

Немножко дёгтя на «лыжи»

Есть косяк у моего телефона. Ага, телефон «лыжа» - LG G2 mini. На нём соединение по Bluetooth устанавливается неадекватно. Соединение устанавливается нормально только, если Bluetooth был включен непосредственно перед запуском приложения.
Я сделал так: при запуске приложении проверяю включен ли Bluetooth, если выключен - делаю запрос на включении. А при «сворачивании», закрытии приложения - принудительно выключаю Bluetooth.
И еще один момент, при смене ориентации экрана, Bluetooth выключается и снова выдается запрос на включения, приходится выключать автоматическое переключение разворота экрана.

Резюме

Я считаю, что достиг цели! При не очень больших усилиях я создал RC-модель с вменяемым пропорциональным управлением. Машинкой можно с увлечением играть даже взрослому, делая развороты на месте, выписывая сложные пируэты, притормаживая и ускоряясь при необходимости.
И её легко починить при поломке.

Есть еще поле для деятельности, есть куда расти. Можно «наворачивать» шасси, можно модернизировать и улучшать ПО для телефона.
И об этом будет продолжение!


В этом материале предлагаем узнать, как можно сделать радиоуправляемую машинку в домашних условиях.

Для изготовления машинки, нам понадобится:
- игрушечная машинка;
- две карты Arduino Uno;
- две платы радио модуля NRF24;
- конденсатор на 470 мф, 25 вольт;
- плата драйвера двигателя L298N;
- двигатель;
- сервопривод;
- аналоговый джойстик;
- аккумуляторные батарейки;
- батарейка крона;
- две кнопки включения и выключения;
- корпус.

Первым делом необходимо припаять конденсатор на выводы питания радио модуля. Также предварительно нужно собрать аккумуляторные батарейки, чтобы получить суммарную мощность в 12 вольт для питания двигателя и платы Arduino.

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

Теперь необходимо проделать отверстия диаметром 4 мм в нижней части корпуса машинки и колесах.

Собираем все. Просовываем винт в колесо, и фиксируем двумя гайками.

Просовываем еще один винт в отверстие на корпусе, фиксируем гайками.

В конце остается надеть колесо с уголком на гайку в корпусе машинки и зафиксировать еще парой гаек. Проделываем то же самое со вторым колесом.

Теперь необходимо соединить сервопривод к поворотной системе.

Также в двигателе есть специальные крепежные отверстия, в которые нужно вставить два винтика, чтобы закрепить двигатель на корпусе машинки.

Теперь необходимо залить код на плату Arduino. В конце статьи будет представлен код для приемника, а также код для передатчика.

Представляем схему сборки джойстика или передатчика.

Ниже вы можете увидеть схему сборки приемника.

В конце остается собрать электронику и механику самодельного радиоуправляемого автомобиля. При включении надо сначала включить пульт управления, после чего саму машинку.

Как и обещали, ниже даем ссылки на коды, необходимые для программирования платы
Код для приемника: (скачиваний: 3609)
Код для передатчика: (скачиваний: 2617)

Также представим короткую инструкцию по прошивке плат Arduino Uno. Плату нужно подключить к компьютеру через USB кабель. Далее с официального сайта () нужно скачать бесплатную программу, установить ее, установить драйверы платы и прошить ее при помощи этой программы.

Если же вы используете китайскую плату , то ее драйвер можете скачать по этой ссылке: