Обучаться основам электроники (да и вообще обучаться) лучше всего в интерактивном режиме. Не просто заучивать правила, схемы и прочее, а сразу пробовать изученное на практике. И такую возможность представляет радиоуправляемая машинка с ARDUINO и Bluetooth.
Корни у девайса — китайские, в англоязычном мануале даже не все иероглифы убраны. Однако, это очень интересный проект, который может научить многому. Дело в том, что и железо, и софт здесь можно изменять, с добавлением новых модулей и надстроек для ПО.
Что собой представляет Robotale?
Разработчики позиционируют проект, как обучающую и развивающую электронную систему, в основе которой — Arduino-микроконтроллер atmega-328 core. Кроме того, есть Bluetooth модуль, инфракрасный модуль, сенсоры, помогающие устройству избегать препятствий. В комплекте — целый ряд программ для управления устройством, и плата расширения, которая позволяет устанавливать дополнительные модули, добавляя функциональность устройству.
Характеристики устройства
- Электромотор: 6-9V (4 штуки, по 1 на каждое из колес);
- Четыре колеса;
- Крепление для мотора;
- 2 плексигласовых платы;
- Управляющая плата L298N;
- ARDUINO UNO328;
- Плата расширения с сенсорами;
- PTZ;
- Сервопривод;
- Ультразвуковой модуль;
- Инфраскрасный сенсор;
- Пульт дистанционного управления;
- Адаптер;
- Bluetooth-модуль.
К комплекте с устройством поставляются отвертки, винты, USB-кабель.
Как это работает?
Машинка поставляется в разобранном виде, так что придется собирать ее своими руками. Несмотря на обилие деталей, сборка достаточно простая, с ней справится и ребенок (правда, для этого нужен некоторый опыт работы отверткой и, иногда — пайки). Уже на начальном этапе человек, собирающий этот автомобиль из отдельных частей, сможет понять, каким образом все это работает и взаимодействует.
После того, как все собрано, на ПК или ноутбуке, с которого будет производиться управление устройством и доработка ПО, нужно установить управляющую программу для Arduino Uno.
При желании, набор «железа» и программ можно изменять и дополнять — здесь роль играет только желание и возможность (опыт) это желание реализовать. Комплект Robotale представляет продвинутый электронный конструктор, который могут использовать как дети, так и взрослые. Конечно, работать с Arduino не так просто, но тем интереснее будет обучаться, в процессе сборки машинки и подключения дополнительных модулей.
Например, можно добавить модуль Bluetooth, и научить автомомобиль понимать команды, которые передаются по беспроводной связи. Кстати, в этом устройстве, при сопряжении с Bluetooth-гаджетом, нужно ввести код сопряжения «1234». После этого можно попробовать управлять.
К примеру, можно сделать так, чтобы при нажатии на букву «R» на клавиатуре мобильного устройства или ноутбука (устройства, сопряженного с машинкой), мигал красный светодиод pin13. Это можно обеспечить при помощи следующего участка программы:
int ledpin = 13;
void setup ()
{
Serial.begin (9600);
pinMode (ledpin, OUTPUT);
}
void loop ()
{
val = Serial.read ();
if (val == 'r')
{
digitalWrite (ledpin, HIGH);
delay ((500);
digitalWrite (ledpin, LOW);
delay (500);
Serial.println («keyes»);
}
}
А затем:
int MotorRight1 = 5;
int MotorRight2 = 6;
int MotorLeft1 = 10;
int MotorLeft2 = 11;
void setup ()
{
Serial.begin (9600);
pinMode (MotorRight1, OUTPUT); / / Pin 8 (PWM)
pinMode (MotorRight2, OUTPUT); / / Pin 9 (PWM)
pinMode (MotorLeft1, OUTPUT); / / Pin 10 (PWM)
pinMode (MotorLeft2, OUTPUT); / / Pin 11 (PWM)
}
void go () / / Forward
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
}
void left () / / turn right
{
digitalWrite (MotorRight1, HIGH);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
}
void right () / / turn left
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, HIGH);
digitalWrite (MotorLeft2, LOW);
}
void stop () / / stop
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
}
void back () / / Check out
{
digitalWrite (MotorRight1, HIGH);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, HIGH);
digitalWrite (MotorLeft2, LOW);;
}
void loop ()
{
char val = Serial.read ();
Serial.write (val);
if (-1! = val) {
if ('W' == val)
go ();
else if ('A' == val)
left ();
else if ('D' == val)
right ();
else if ('S' == val)
back ();
else if ('Q' == val)
stop ();
delay (500);
}
else
{
/ / Stop ();
delay (500);
}
}
Если же необходимо задействовать все функции, включая распознавание инфракрасного сигнала, команд Bluetooth-модуля и прочие возможности, следует использовать такой код:
/ / ******************************
# Include <IRremote.h>
# Include <Servo.h>
/ / *********************** Definition of motor pin ********************* ****
int MotorRight1 = 5;
int MotorRight2 = 6;
int MotorLeft1 = 10;
int MotorLeft2 = 11;
int counter = 0;
const int irReceiverPin = 2; / / OUTPUT signals IR receiver connected to pin 2
char val;
/ / *********************** Set to detect the IRcode ****************** *******
long IRfront = 0x00FFA25D; / / Forward code
long IRback = 0x00FF629D; / / Check out
long IRturnright = 0x00FFC23D; / / Right
long IRturnleft = 0x00FF02FD; / / Left
long IRstop = 0x00FFE21D; / / Stop
long IRcny70 = 0x00FFA857; / / CNY70 self-propelled mode
long IRAutorun = 0x00FF 906F; / / Self-propelled mode ultrasound
long IRturnsmallleft = 0x00FF22DD;
/ / ************************* Defined CNY70 pin ******************* *****************
const int SensorLeft = 7; / / Left sensor input pin
const int SensorMiddle = 4; / / The sensor input pin
const int SensorRight = 3; / / Right sensor input pin
int SL; / / Left sensor status
int SM; / / The sensor status
int SR; / / Right sensor status
IRrecv irrecv (irReceiverPin); / / Define an object to receive infrared signals IRrecv
decode_results results; / / Decoding results will result in structural variables in decode_results
/ / ************************* Defined ultrasound pin ****************** ************
int inputPin = 13; / / define pin ultrasonic signal receiver rx
int outputPin = 12; / / define ultrasonic signal transmitter pin 'tx
int Fspeedd = 0; / / in front of distance
int Rspeedd = 0; / / the right distance
int Lspeedd = 0; / / left distance
int directionn = 0; / / = 8 post = 2 front left and right = 6 = 4
Servo myservo; / / set myservo
int delay_time = 250; / / settling time after steering servo motors
int Fgo = 8; / / Forward
int Rgo = 6; / / turn right
int Lgo = 4; / / turn left
int Bgo = 2; / / reverse
/ / ************************************************ ******************** (SETUP)
void setup ()
{
Serial.begin (9600);
pinMode (MotorRight1, OUTPUT); / / Pin 8 (PWM)
pinMode (MotorRight2, OUTPUT); / / Pin 9 (PWM)
pinMode (MotorLeft1, OUTPUT); / / Pin 10 (PWM)
pinMode (MotorLeft2, OUTPUT); / / Pin 11 (PWM)
irrecv.enableIRIn (); / / Start infrared decoding
pinMode (SensorLeft, INPUT); / / define left Sensors
pinMode (SensorMiddle, INPUT) ;/ / definition sensors
pinMode (SensorRight, INPUT); / / definition of the right sensor
digitalWrite (2, HIGH);
pinMode (inputPin, INPUT); / / define ultrasound input pin
pinMode (outputPin, OUTPUT); / / define ultrasonic output pin
myservo.attach (9); / / define servo motor output section 5 pin (PWM)
}
/ / ************************************************ ****************** (Void)
void advance (int a) / / Forward
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
delay (a * 100);
}
void right (int b) / / turn right (single wheel)
{
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
delay (b * 100);
}
void left (int c) / / turn left (single wheel)
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
delay (c * 100);
}
void turnR (int d) / / turn right (wheel)
{
digitalWrite (MotorRight1, HIGH);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
delay (d * 100);
}
void turnL (int e) / / turn left (wheel)
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, HIGH);
digitalWrite (MotorLeft2, LOW);
delay (e * 100);
}
void stopp (int f) / / Stop
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
delay (f * 100);
}
void back (int g) / / Check out
{
digitalWrite (MotorRight1, HIGH);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, HIGH);
digitalWrite (MotorLeft2, LOW);;
delay (g * 100);
}
void detection () / / measure three angles (front Left. Right)
{
int delay_time = 250; / / settling time after steering servo motors
ask_pin_F (); / / read from front
if (Fspeedd <10) / / if the distance is less than 10 cm in front of
{
stopp (1); / / clear the output data
back (2); / / Check out 0.2 seconds
}
if (Fspeedd <25) / / if the distance is less than 25 cm in front of
{
stopp (1); / / clear the output data
ask_pin_L (); / / read from left
delay (delay_time); / / wait for stable servo motor
ask_pin_R (); / / read the right distance
delay (delay_time); / / wait for stable servo motor
if (Lspeedd> Rspeedd) / / If the distance is greater than the right from the left
{
directionn = Lgo; / / go left
}
if (Lspeedd <= Rspeedd) / / if the distance is less than or equal to the left to the right distance
{
directionn = Rgo; / / go right
}
if (Lspeedd <15 && Rspeedd <15) / / if the distance to the left and right are less than 10 cm distance
{
directionn = Bgo; / / to go after
}
}
else / / add as greater than 25 cm in front of
{
directionn = Fgo; / / to move forward
}
}
/ / ************************************************ *********************************
void ask_pin_F () / / Measure the distance from the front
{
myservo.write (90);
digitalWrite (outputPin, LOW); / / make ultrasonic transmitter low voltage 2 μ s
delayMicroseconds (2);
digitalWrite (outputPin, HIGH); / / make ultrasonic transmitting high voltage 10 μ s, where at least 10 μ s
delayMicroseconds (10);
digitalWrite (outputPin, LOW); / / maintain low voltage ultrasonic transmitter
float Fdistance = pulseIn (inputPin, HIGH); / / read worse time difference
Fdistance = Fdistance/5.8/10; / / will turn to time distance (unit: cm)
Serial.print («F distance:»); / / output distance (unit: cm)
Serial.println (Fdistance); / / display the distance
Fspeedd = Fdistance; / / will enter Fspeedd (former speed) from Reading
}
/ / ************************************************ ********************************
void ask_pin_L () / / Measure the distance from the left
{
myservo.write (177);
delay (delay_time);
digitalWrite (outputPin, LOW); / / make ultrasonic transmitter low voltage 2 μ s
delayMicroseconds (2);
digitalWrite (outputPin, HIGH); / / make ultrasonic transmitting high voltage 10 μ s, where at least 10 μ s
delayMicroseconds (10);
digitalWrite (outputPin, LOW); / / maintain low voltage ultrasonic transmitter
float Ldistance = pulseIn (inputPin, HIGH); / / read worse time difference
Ldistance = Ldistance/5.8/10; / / will turn to time distance (unit: cm)
Serial.print («L distance:»); / / output distance (unit: cm)
Serial.println (Ldistance); / / display the distance
Lspeedd = Ldistance; / / will be read into the distance Lspeedd (left-speed)
}
/ / ************************************************ ******************************
void ask_pin_R () / / Measure the distance from the right
{
myservo.write (5);
delay (delay_time);
digitalWrite (outputPin, LOW); / / make ultrasonic transmitter low voltage 2 μ s
delayMicroseconds (2);
digitalWrite (outputPin, HIGH); / / make ultrasonic transmitting high voltage 10 μ s, where at least 10 μ s
delayMicroseconds (10);
digitalWrite (outputPin, LOW); / / maintain low voltage ultrasonic transmitter
float Rdistance = pulseIn (inputPin, HIGH); / / read worse time difference
Rdistance = Rdistance/5.8/10; / / will turn to time distance (unit: cm)
Serial.print («R distance:»); / / output distance (unit: cm)
Serial.println (Rdistance); / / display the distance
Rspeedd = Rdistance; / / will be read into the distance Rspeedd (Right-speed)
}
/ / ************************************************ ****************************** (LOOP)
void loop ()
{
SL = digitalRead (SensorLeft);
SM = digitalRead (SensorMiddle);
SR = digitalRead (SensorRight);
performCommand ();
/ / ************************************************ *************************** normal remote mode
if (irrecv.decode (& results))
{ / / Decoding is successful, you receive a set of infrared signals
/ ************************************************* ********************** /
if (results.value == IRfront) / / Forward
{
advance (10) ;/ / forward
}
/ ************************************************* ********************** /
if (results.value == IRback) / / Check out
{
back (10) ;/ / after retirement
}
/ ************************************************* ********************** /
if (results.value == IRturnright) / / turn right
{
right (6); / / turn right
}
/ ************************************************* ********************** /
if (results.value == IRturnleft) / / turn left
{
left (6); / / turn left);
}
/ ************************************************* ********************** /
if (results.value == IRstop) / / Stop
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
}
/ / ************************************************ *********************** cny70 model black self-propelled mode: LOW White:
if (results.value == IRcny70)
{
while (IRcny70)
{
SL = digitalRead (SensorLeft);
SM = digitalRead (SensorMiddle);
SR = digitalRead (SensorRight);
if (SM == HIGH) / / in sensors in black areas
{
if (SL == LOW & SR == HIGH) / / left and right black white, turn left
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
analogWrite (MotorLeft1, 0);
analogWrite (MotorLeft2, 80);
}
else if (SR == LOW & SL == HIGH) / / left and right black white, turn right
{
analogWrite (MotorRight1, 0) ;/ / right turn
analogWrite (MotorRight2, 80);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
}
else / / Both sides white, straight
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
analogWrite (MotorLeft1, 200);
analogWrite (MotorLeft2, 200);
analogWrite (MotorRight1, 200);
analogWrite (MotorRight2, 200);
}
}
else / / the sensors in the white area
{
if (SL == LOW & SR == HIGH) / / left and right black white, fast turn left
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
}
else if (SR == LOW & SL == HIGH) / / left and right black white, quick right turn
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, HIGH);
}
else / / are white, stop
{
digitalWrite (MotorRight1, HIGH);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, HIGH);
digitalWrite (MotorLeft2, LOW);;
}
}
if (irrecv.decode (& results))
{
irrecv.resume ();
Serial.println (results.value, HEX);
if (results.value == IRstop)
{
digitalWrite (MotorRight1, HIGH);
digitalWrite (MotorRight2, HIGH);
digitalWrite (MotorLeft1, HIGH);
digitalWrite (MotorLeft2, HIGH);
break;
}
}
}
results.value = 0;
}
/ / ************************************************ self-propelled mode ultrasound ***********************
if (results.value == IRAutorun)
{
while (IRAutorun)
{
myservo.write (90); / / return to the pre-prepared so that the servo motor position once the measure under preparation
detection (); / / measure the angle and direction of judgment to where to move
if (directionn == 8) / / If directionn (direction) = 8 (forward)
{
if (irrecv.decode (& results))
{
irrecv.resume ();
Serial.println (results.value, HEX);
if (results.value == IRstop)
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
break;
}
}
results.value = 0;
advance (1); / / normal forward
Serial.print («Advance»); / / display direction (forward)
Serial.print ("");
}
if (directionn == 2) / / If directionn (direction) = 2 (reverse)
{
if (irrecv.decode (& results))
{
irrecv.resume ();
Serial.println (results.value, HEX);
if (results.value == IRstop)
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
break;
}
}
results.value = 0;
back (8); / / reverse (car)
turnL (3); / / move slightly to the left (to prevent stuck in dead alley)
Serial.print («Reverse»); / / display direction (backwards)
}
if (directionn == 6) / / If directionn (direction) = 6 (right turn)
{
if (irrecv.decode (& results))
{
irrecv.resume ();
Serial.println (results.value, HEX);
if (results.value == IRstop)
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
break;
}
}
results.value = 0;
back (1);
turnR (6); / / turn right
Serial.print («Right»); / / display direction (turn left)
}
if (directionn == 4) / / If directionn (direction) = 4 (turn left)
{
if (irrecv.decode (& results))
{
irrecv.resume ();
Serial.println (results.value, HEX);
if (results.value == IRstop)
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
break;
}
}
results.value = 0;
back (1);
turnL (6); / / turn left
Serial.print («Left»); / / display direction (turn right)
}
if (irrecv.decode (& results))
{
irrecv.resume ();
Serial.println (results.value, HEX);
if (results.value == IRstop)
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
break;
}
}
}
results.value = 0;
}
/ ************************************************* ********************** /
else
{
digitalWrite (MotorRight1, LOW);
digitalWrite (MotorRight2, LOW);
digitalWrite (MotorLeft1, LOW);
digitalWrite (MotorLeft2, LOW);
}
irrecv.resume (); / / Continue to accept a set of infrared signals
}
}
void performCommand () {
if (Serial.available ()) {
val = Serial.read ();
}
if (val == 'f') {/ / Forward
advance (10);
} Else if (val == 'z') {/ / Stop Forward
stopp (10);
} Else if (val == 'b') {/ / Backward
back (10);
} Else if (val == 'y') {/ / Stop Backward
back (10);
} else if (val == 'l') {/ / Right
turnR (10);
} Else if (val == 'r') {/ / Left
turnL (10);
} Else if (val == 'v') {/ / Stop Turn
stopp (10);
} Else if (val == 's') {/ / Stop
stopp (10);
}
}
На самом деле, машинка очень гибкая в настройке, для нее можно писать новые программы, добиваясь расширения функций (особенно, если подключать другие модули — подключать можно не только то, что идет в комплекте, но и дополнительные элементы). То, что показано выше — это только один из примеров, а их, на самом деле, десятки.
Вывод: Машинка Robotale предназначена для изучения основ электроники, в особенности, изучения принципа работы ARDUINO. Обучение проводится в интерактивной форме, причем владелец автомобиля обучается, спользуя самый эффективный способ — мгновенный переход от теории к практике.
Автор: marks