🚗 Машинка на Arduino с шасси на 3D принтере

🚗 Машинка на Arduino с шасси на 3D принтере Конструкторы

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

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

2. Bluetooth–модуль «HC-06» .

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

В качестве пульта дистанционного управления будет служить сотовый телефон с Android. Напишем свою программу!

3. Драйвер двигателей TB6612FNG двухканальный.

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

4. Плата управления MOD-IO (Olimex)

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

Забегая вперёд скажу, что продукт Олимекс MOD-IO — это жёсткий перебор. Прекрасно можно будет применить и обычную

, о чём в продолжении истории!

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

Основная активность, сопряжение arduino и android

Наследуем класс от AppCompatActivity и объявляем переменные:

public class MainActivity extends AppCompatActivity {
        private BluetoothAdapter bluetoothAdapter;
        private ListView listView;
        private ArrayList<String> pairedDeviceArrayList;
        private ArrayAdapter<String> pairedDeviceAdapter;
        public static BluetoothSocket clientSocket;
        private Button buttonStartControl;
}

Метод onCreate() опишу построчно:

@Override
protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState); //обязательная строчка
     //прикрепляем ранее созданную разметку
     setContentView(R.layout.activity_main); 
     //цепляем кнопку из разметки          
     Button buttonStartFind = (Button) findViewById(R.id.button_start_find); 
     //цепляем layout, в котором будут отображаться найденные устройства
     listView = (ListView) findViewById(R.id.list_device); 
      
     //устанавливаем действие на клик                                                                           
     buttonStartFind.setOnClickListener(new View.OnClickListener() { 
                                                                                                    
         @Override
         public void onClick(View v) {
             //если разрешения получены (функция ниже)
             if(permissionGranted()) { 
               //адаптер для управления блютузом
                bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
                if(bluetoothEnabled()) { //если блютуз включен (функция ниже)
                    findArduino(); //начать поиск устройства (функция ниже)
                  }
              }
         }
    });

     //цепляем кнопку для перехода к управлению
     buttonStartControl = (Button) findViewById(R.id.button_start_control); 
     buttonStartControl.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
                //объект для запуска новых активностей
                Intent intent = new Intent(); 
                //связываем с активностью управления
                intent.setClass(getApplicationContext(), ActivityControl.class);
                //закрыть эту активность, открыть экран управления
                startActivity(intent); 
         }
     });

 }


Нижеприведенные функции проверяют, получено ли разрешение на использование блютуза (без разрешение пользователя мы не сможем передавать данные) и включен ли блютуз:

↑ будем строить машинку с ду!

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

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

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

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

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

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

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

Объясню на примере пакета для управления шасси. Кроме стартового и стопового байтов, в своём пакете мне необходимо передавать одну команду, и два значения ШИМ, для левой и правой стороны приводов. Для команды мне достаточно одного байта, а для каждого значения ШИМ, я передаю
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. Дальше остается прочитать эти данные из структуры например так:

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

Хоть в моей программе передача пока не используется, тем не менее, возможность передачи реализована. Передавать данные проще. Точно также, как и для приемного пакета, создадим структуру:

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;

Во-первых, это пошло от программы под Андроид. Дело в том что в 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.

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

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

ISR(USART_RXC_vect)
{
	uint8_t Data = UDR;
	RB_push_char( Data );	// Складываем принятый байт в кольцевой буфер
}

Да, я пока пренебрег всякими проверками фрейма.

Смотрите про коптеры:  Настройка и обкатка ДВС радиоуправляемой модели - Обзоры и статьи .ua

Теперь нам остается время от времени проверять наш буфер. Для этого я инициировал таймер, в котором я устанавливаю флаг разрешающий проверку кольцевого буфера

ISR(TIMER0_OVF_vect)
{
	TCNT0 = 0x64;
	ReadRingBuffer = 1;
}

В основном цикле добавляем условие для проверки флага.

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

Функция RB_read_buffer проверяет кольцевой буфер, если размер пакета, стартовый и стоповые байты находятся на своих местах — пакет считается валидным, функция возвращает “1». В качестве аргумента, функция принимает указатель, куда складывать принятый пакет.

↑ приложение под android для машинки

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

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

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

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

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

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

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

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

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

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

↑ программа микроконтроллера

Программа МК умеет принимать команды по последовательному интерфейсу с 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);
}

Выбираем компоненты

В прошлом мы с приятелями

собственную прошивку для роботов Lego Mindstorms NXT, поддерживающую удалённое управление роботом по bluetooth с Android-коммуникатора. Для экспериментов тогда была приобретена отладочная плата Olimex SAM7 с ARM7 на борту, которую в этот раз можно использовать в качестве управляющего контроллера.

В качестве шасси используем корпус игрушечной машинки.

Нужен bluetooth-модуль. Результат хотелось получить быстро, поэтому модуль был выбран из единственного доступного в магазине на тот момент BTM-112, хотя он оказался сравнительно дорогим.

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

В сумме наши компоненты:

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

Гоночная машинка на bluetooth управлении.

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

Так как продавец, после того, как я скинул ему ссылку на обзор конструктора, сделал мне скидку я ставлю п.18. Шла посылка очень долго, честно говоря, думал где-то потерялась или это я привык, что почта хорошо работает в последнее время. За время доставки коробка особо не помялась, можно даже дарить. Как и любая упаковка игрушки из китая, коробка служит одновременно и витриной ), на каждой стороне коробки изображение всех возможных вариантов этой машинки. Из полезного на одной стороне есть QR код с ссылкой на скачку приложения под Android и iOS.

Смотрите про коптеры:  Радиоуправление Telecrane A21-E1B, F21-E1B, A24, F24, A21-E1B, купить, цена

🚗 Машинка на Arduino с шасси на 3D принтере

Итак, что нам предлагает производитель:

● Масштаб 1:20
● Два ведущих колеса
● Управление через блютуз
● Голосовое управление
● Программируемое движение

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

🚗 Машинка на Arduino с шасси на 3D принтере

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

🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере

На днище машинки расположен отсек для аккумулятора, аккумулятор кстати на 700mAh 4.8V набранный из 4х NiCd элементов формата АА. А также на есть корректор поворотов, если машина не едет прямо и кнопка включения игрушки.

🚗 Машинка на Arduino с шасси на 3D принтере

Машинка имеет резиновые шины, сменные, хотя их явно никто менять не будет. Передняя и задняя подвески независимые, даже есть пружины, хотя они в принципе носят декоративный характер.

🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере

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

🚗 Машинка на Arduino с шасси на 3D принтере

Хотя это я слишком громко сказал, сняв верхнюю половинку корпуса, она держится на 6 саморезах, видно одну простенькую плату управления с bluetooth чипом, к которой подключены все провода и движок управления поворотами, сервы здесь нет.

🚗 Машинка на Arduino с шасси на 3D принтере

На фото видно микруху управления моторами, bluetooth чип с затертой маркировкой. В корпусе заднего моста находится коллекторный моторчик с редуктором. На шестернях имеется смазка.

🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере

Скачав по QR коду приложения, я приступил к тестированию машинки. Немного о приложении, видно что написано на коленке, но оно работает, хотя не часто, но бывают отвалы. В приложении, кроме управления кнопками на экране, есть еще и голосовое управление, но это для особых извращенцев), команды простые типа run, left, stop. Но видать произношение у меня хромает, так как выполнялись мои команды через пень-колоду. Есть также интересная фишка, конструктор маршрута, там добавляешь кусочки маршрута, например 2 сек. прямо направо 2 сек., и машинка едет по этому маршруту. Это мне больше понравилось, чем голосовое управление. Немного скринов с приложения.

🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере
🚗 Машинка на Arduino с шасси на 3D принтере

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

По факту если скинуть пяток баксов, будет хорошая игрушка для ребенка, это при условии, что я ее покупал когда она стоила 16$. Машинка одинаково хорошо катается по ковру и по асфальту, особенно если асфальт ровный. Пороги в квартире преодолевает. Не слишком резвая, можно просто катать без телефона). Батарейки хватит минут на 20 точно. Машинку планировал подарить мелкому племяннику сразу, но мой сын решил сначала ее сам обкатать ).Следует понимать, что это просто интересная игрушка для вашего ребенка, а не гоночный болид для заядлых RC-шников. На этом наверное все, в видео можно посмотреть как она катается. В принципе, если будут опять скидки, можно взять ребенку. Спасибо всем за прочтение.

Товар предоставлен для написания обзора магазином. Обзор опубликован в соответствии с п.18 Правил сайта.

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

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

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

Метод loop() и дополнительные функции

В постоянно повторяющемся методе loop() происходит считывание данных. Сначала рассмотрим основной алгоритм, а потом функции, задействованные в нем.


void loop() {
  //если хоть несчитанные байты
  if(BTSerial.available() > 0) {
     //считываем последний несчитанный байт
     char a = BTSerial.read();
     
    if (a == '@') {
      //если он равен @ (случайно выбранный мною символ)
      //обнуляем переменную val
      val = "";
      //указываем, что сейчас считаем скорость
      readSpeed = true;

    } else if (readSpeed) {
      //если пора считывать скорость и байт не равен решетке
      //добавляем байт к val
      if(a == '#') {
        //если байт равен решетке, данные о скорости кончились
        //выводим в монитор порта для отладки
        Serial.println(val);
        //указываем, что скорость больше не считываем
        readSpeed = false;
        //передаем полученную скорость в функцию езды 
        go(val.toInt());
        //обнуляем val
        val = "";
        //выходим из цикла, чтобы считать следующий байт
        return;
      }
      val =a;
    } else if (a == '*') {
      //начинаем считывать угол поворота
      readAngle = true; 
    } else if (readAngle) {
      //если решетка, то заканчиваем считывать угол
      //пока не решетка, добавляем значение к val
      if(a == '#') {
       Serial.println(val);
       Serial.println("-----");
        readAngle = false;
        //передаем значение в функцию поворота
        turn(val.toInt());
        val= "";
        return;
      }
      val =a;
    }
    //получаем время последнего приема данных
    lastTakeInformation = millis();
  } else {
     //если несчитанных байтов нет, и их не было больше 150 миллисекунд 
     //глушим двигатели
     if(millis() - lastTakeInformation > 150) {
     lastTakeInformation = 0;
     analogWrite(angleSpeed, 0);
     analogWrite(speedRight, 0);
     analogWrite(speedLeft, 0);
     }
     
  }
}

Получаем результат: с телефона отправляем байты в стиле “@скорость#угол#” (например, типичная команда “@200#60#”. Данный цикл повторяется каждый 100 миллисекунд, так как на андроиде мы установили именно этот промежуток отправки команд. Короче делать нет смысла, так как они начнут становится в очередь, а если сделать длиннее, то колеса начнут двигаться рывками.

Все задержки через команду delay(), которые вы увидите далее, подобраны не через физико-математические вычисления, а опытным путем. Благодаря всем выставленным задрежам, машинка едет плавно, и у всех команд есть время на отработку (токи успевают пробежаться).

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

void go(int mySpeed) {
  //если скорость больше 0
  if(mySpeed > 0) {
  //едем вперед
  digitalWrite(dirRight, HIGH);
  analogWrite(speedRight, mySpeed);
  digitalWrite(dirLeft, HIGH);
  analogWrite(speedLeft, mySpeed);
  } else {
    //а если меньше 0, то назад
    digitalWrite(dirRight, LOW);
    analogWrite(speedRight, abs(mySpeed)   30);
    digitalWrite(dirLeft, LOW);
     analogWrite(speedLeft, abs(mySpeed)   30);
  }
  delay(10);
 
}

void turn(int angle) {
  //подаем ток на плюс определителя угла
  digitalWrite(pinAngleStop, HIGH);
  //даем задержку, чтобы ток успел установиться
  delay(5);
  
  //если угол 150 и больше, поворачиваем вправо 
  //если 30 и меньше, то влево 
  //промежуток от 31 до 149 оставляем для движения прямо
  if(angle > 149) {
        //если замкнут белый, но разомкнуты  черный и красный
        //значит достигнуто крайнее положение, дальше крутить нельзя
        //выходим из функции через return 
        if( digitalRead(pinWhite) == HIGH && digitalRead(pinBlack) == LOW && digitalRead(pinRed) == LOW) {
          return;
        }
        //если проверка на максимальный угол пройдена
        //крутим колеса
        digitalWrite(angleDirection, HIGH);
        analogWrite(angleSpeed, speedTurn);
  } else if (angle < 31) { 
        if(digitalRead(pinRed) == HIGH && digitalRead(pinBlack) == HIGH && digitalRead(pinWhite) == HIGH) {
          return;
        }
        digitalWrite(angleDirection, LOW);
        analogWrite(angleSpeed, speedTurn);
  }
  //убираем питание 
  digitalWrite(pinAngleStop, LOW);
  delay(5);
}

Поворачивать, когда андроид отправляет данные о том, что пользователь зажал угол 60, 90, 120, не стоит, иначе не сможете ехать прямо. Да, возможно сразу не стоило отправлять с андроида команду на поворот, если угол слишком мал, но это как-то коряво на мой взгляд.

Настройки приложения

Скриншот настроек Android приложения CxemCar версии 1.0:

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

Точка разворота для мотора (ось X)

При наклоне Android-устройства влево или вправо программа притормаживает тот двигатель, в сторону которого наклонено устройство, т.о. осуществляется поворот. Однако, когда значение наклона доходит до заданной в настройках точки разворота, то двигатель начинает вращаться в другую сторону.

MAC адрес

Для установления связи с Bluetooth модулем машинки, в настройках приложения необходимо задать MAC-адрес. Предварительно необходимо настроить сопряжение устройств в настройках вашего Android-устройства. Для этого переходим в Настройки -> Bluetooth и нажимаем “Поиск устройств”, телефон находит наш Bluetooh-модуль, нажимаем по нему и вводим пароль (как правило 1234).

Узнать Bluetooth адрес модуля можно из какого-нибудь приложения, к примеру Bluetooth Terminal. Для этого внизу нажимаем “Connect a device – Secure” и в появившемся окошке нажимаем кнопку “Scan for devices”. ПО сканирует Bluetooth устройства и отобразит их MAC-адреса:

Этот MAC-адрес и необходимо прописать в настройках приложения CxemCAR.

Само ПО под Android я не буду расписывать, т.к. оно довольно таки громоздкое и поэтому если у вас возникнут какие-либо вопросы по нему, то обращайтесь тему поддержки данного проекта на форуме.

Определение угла поворота

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

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

Решение проблемы: отслеживать угол через замыкание. На фото продемонстрирована небольшая штучка, которая крепится недалеко от поворотного механизма. На часть, которая крутится вместе с колесами влево/вправо двигателем, прикрепляется гребешок с железными контактами.

Принцип работы: к каждой линии припаивается провод (всего их четыре), нижний подключается к плюсу (он зажат гребешком всегда, см. картинку), остальные провода уходят на минус. Когда зубик гребешка попадает и на нижний ряд, и на, допустим, третий, происходит замыкание, ток течет, это замечает Arduino.

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

Переменные

Для начала рассмотрим константы и переменные, которые понадобятся.

#include <SoftwareSerial.h>
//переназначаем пины входавывода блютуза
//не придется вынимать его во время заливки скетча на плату
SoftwareSerial BTSerial(8, 9);

//пины поворота и скорости
int speedRight = 6;
int dirLeft = 3;
int speedLeft = 11;
int dirRight = 7;

//пины двигателя, поворачивающего колеса
int angleDirection = 4;
int angleSpeed = 5;

//пин, к которому подключен плюс штуки, определяющей поворот
//подробная технология описана в первой части
int pinAngleStop = 12;

//сюда будем писать значения
String val;
//скорость поворота
int speedTurn = 180;
//пины, которые определяют поворот
//таблица и описания системы в первой статье
int pinRed = A0;
int pinWhite = A1;
int pinBlack = A2;

//переменная для времени
long lastTakeInformation;
//переменные, показывающие, что сейчас будет считываться
boolean readAngle = false;
boolean readSpeed = false;

Подключение bluetooth

Я использовал модель HC-05, что сыграло роковую шутку. Подключаются все блютузы одинаково: один провод на 3.3В (иногда начинал работать только от 5В), второй на минус, еще два на порт 0 и 1 (чтение и отправка соответственно). Провод, подписанный RXD на bluetooth, втыкается в TXD ардуино, а TXD в RXD (если перепутаете, то данных не увидите).

Есть оговорка: порты 0 и 1 по умолчанию используются Serial, через который заливает скетч. То есть, пока воткнут блютуз, скетч не зальется. Есть два выхода: вынимать блютуз на время заливки или переназначить входы и выходы блютуза. Второй вариант осуществляется двумя строчками

#include <SoftwareSerial.h> \подключение библиотеки
SoftwareSerial BTSerial(8, 9); \установка 8 и 9 пина заместо 0 и 1

Подводный камень, съевший у меня трое суток работы – скорость общения. По привычке установил 9600 и пошел пробовать. То данные не приходили, то была каша символов. И в конце концов ответ – модель HC-05 общается на 38400! Очень сильно обратите внимание на то, что в Setup() я выполню BTSerial.begin(39400), хотя Serial.begin(9600).

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

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

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

Приложение

Так как я не владею навыком написания приложение под Anroid, то для создания пульта управления использовать уже известный у многих начинающих разработчиков инструмент визуального программирования — App inventor.

Что-то подсмотрел у других в интернете, что доработал, и получилось такое простое приложение.

Сначала нужно включить машинку и сделать сопряжение по Bluetooth со смартфоном. Пароль модуля 0000 или 1234. После этого откройте приложение и нажмите «Подключиться к машинке». Подключитесь к модулю HC-06. Светодиод на нём должен перестать мигать.

Если сразу начать нажимать на стрелки направлений движения, то не поедет. В первую очередь нужно нажать на одну из трёх скоростей, а уже потом на стрелки направления. Тогда поедет.

И, так как я не публиковал это приложение в Google Play, смартфон может ругаться на его безопасность. Но можно смело устанавливать. В нём всё работает безопасно.

Принцип работы

В Android устройстве формируются команды перемещения машинки в зависимости от наклона смартфона/планшета, либо от нажатой кнопки. Все расчеты производятся в Android-приложении, и сразу же вычисляются значения ШИМ для левого и правого двигателей. Приложение обладает гибкими настройками, такими как диапазон ШИМ, чувствительность наклона, минимальный порог ШИМ и др.

По Bluetooth передаются команды вида:L-255rR-120rL – команда для левого двигателя, R – для правогоминус обозначает вращение двигателя для движения назад255 – число ШИМ, для Arduino это максимальная скорость вращенияr – конец команды.

L255rR-255rПо данной команде левый двигатель будет вращаться вперед, а правый назад, что заставит машинку вращаться вокруг своей оси против часовой стрелки.

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

Символы команд L, R и H можно задавать в настройках Android-приложения.

В программе контроллера предусмотрен таймер, который отключает двигатели, если последняя команда была получена более, чем n-секунд назад. Настройка количества секунд хранится в EEPROM памяти контроллера и может быть изменена с Android устройства. Диапазон данной настройки составляет от 0.1 сек до 99.9 секунд.

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

Сборка

Можно купить готовое шасси для машинки сразу вместе с моторами и колёсами. Останется только установить электронику и всё подключить.

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

Из инструментов могут понадобиться:

  • Ручной или электрический лобзик (я пользовался ручным), чтобы отрезать нужные куски от материала.
  • Дрель или шуроповёрт, свёрла.
  • Крепёжные элементы — болты, гайки и саморезы любого подходящего диаметра.

Получилось дёшево и сердито. А главное работает.

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

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

Платы в идеале лучше прикручивать короткими болтами с диаметром 3 мм. Но и таких у меня не оказалось. Поэтому пришлось делать в оргстекле отверстия 2 мм и прикручивать платы саморезами. Держится вполне нормально.

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

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

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

Система отправки команд

Статья становится слишком длинной, поэтому рассмотрение кода Arduino и Android вынесу в отдельную вторую часть, а сейчас опишу принцип.

На андроид устройстве есть джойстик (круг, о реализации которого также во второй части). Андроид считывает показания с него и конвертирует их в подходящие для ардуино числа: скорость из пикселей превращает в значение от -255 до 255 (отрицательные – задний ход), а также определяет угол.

После установки сокета данные отправляются в следующем формате: @скорость#*угол#. @ — говорит о том, что следующие цифры содержат скорость, # — извещает об окончании значения скорости, * — начало значения угла, # — закончить запись угла. Цикл бесконечен, команды отправляются каждые 100 миллисекунд (цифра подобрана оптимальная). Если ничего не нажато на андроиде, то ничего и не отправляется.

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

Соединяем управляющую плату с моторами

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

К сожалению, опыта в этой области у меня нет никакого (все-таки я программист, а не схемотехник), поэтому пришлось прибегнуть к помощи знакомых. По совету я взял микросхему усилителя L298N (избыточную для моих нужд, зато работающую из коробки) и собрал

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

В общем, функционально схема простая, один мотор используется как двигатель, второй мотор — как руль (у него стоит блокиратор на определенном угле поворота).Для управления каждым мотором нужно подать напряжение на соответствующие управляющие ноги (положительное или отрицательное напряжение либо нуль).

Так как Android-приложение передает плавное управление, состояние моторов изменяется по преодолению заданного порога.

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

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

Аккумулятор на 9В питает Arduino через порт VIN и драйвер моторов через порт 12V. Модуль Bluetooth питается от Arduino через порт 3,3V. Параллельно портам питания этого модуля подключается конденсатор для стабилизации напряжения. В ином случае Bluetooth может отключаться и терять подключение. Сервомотор также питается от микроконтроллера через порт 5V. Он управляет поворотными колёсами.

Если на драйвере мотора установлена перемычка Enable, то её нужно снять. Этот порт необходим для управления скоростью моторов. Он должен подключаться обязательно к ШИМ порту, обозначенном на Arduino знаком ~. На схеме выше это порт 3. Управление моторами осуществляется через порты 2 и 4 Arduino, они подключаются к портам Input 3 и Input 4 на драйвере моторов.

Если после сборки вы нажимаете на пульте управления кнопку для движения вперёд, а машинка едет назад, то поменяйте местами провода на портах Out3 и Out4.

А если моторы вращаются в разные стороны, то поменяйте местами провода на любом из моторов.

Пины RX и TX Bluetooth модуля подключаются к портам TX и RX на Arduino, то есть наоборот. К сожалению, из-за несовместимости библиотеки RemoteXY.h с библиотекой SoftwareSerial.h запрограммировать другие порты Arduino для последовательной передачи данных не получится. Поэтому при прошивке микроконтроллера придётся каждый раз отключать питание Bluetooth модуля.

Сервомотор управляется портом 5 на Arduino программируется библиотекой Servo.h.

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

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

Схема сборки машинки с Блютуз управлением
Схема сборки машинки с Блютуз управлением

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

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

Оцените статью
Радиокоптер.ру
Добавить комментарий

Adblock
detector