Запрограммируем робота на основе Arduino.
Начну с теории и описания всего того, что нам пригодится.

image

Напомню Arduino – это аппаратная вычислительная платформа, основными компонентам которой являются простая плата ввода/вывода и среда разработки на языке Processing/Wiring. Документация на аппаратную часть и программный код опубликованы под лицензией «copyleft» но разработчики выразили желание, чтобы название «Arduino» было торговой маркой для официального продукта и не использовалось для производных работ без разрешения. В документе об использовании названия Arduino подчеркивается, что проект открыт для всех желающих.

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


Плата Arduino состоит из микроконтроллера Atmel AVR и элементной обвязки для программирования и интеграции с другими схемами. На каждой плате обязательно присутствуют линейный стабилизатор напряжения 5 В и 16 МГц кварцевый генератор. В микроконтроллер предварительно прошит загрузчик, поэтому внешний программатор не нужен.

Проект Arduino постоянно развивается и имеет множество модификаций. На данный момент доступны 10 версий плат, но конкретно в данном проекте использовалась плата Arduino Diecimila. Она представляет собой небольшую электронную плату, ядром которой является микроконтроллер ATmega168. На плате есть: 14 цифровых входов/выходов, 6 из которых могут работать в режиме ШИМ (PWM) (а следовательно управлять аналоговыми устройствами вроде двигателей и передавать двоичные данные), 6 аналоговых входов, тактовый генератор на 16 МГц, разъёмы питания и USB, ICSP-порт (что-то вроде последовательного интерфейса для цифровых устройств), несколько контрольных светодиодов и кнопка сброса. Этого вполне достаточно, чтобы подключить плату к USB-порту компьютера, установить необходимое программное обеспечение (драйвер и среду разработки) и начать программировать.

image
Внешний вид платы Arduino Diecimila.

Краткая спецификация

Микроконтроллер: ATmega168
Рабочее напряжение: 5 В
Входное напряжение (рекомендуемое): 7-12 В
Входное напряжение (пределы): 6-20 В
Цифровые порты ввода/вывода: 14 портов (из них 6 с ШИМ-сигналом)
Аналоговые порты ввода: 6 портов
Ток для портов: 40 мА
Ток для 3.3В источника: 50 мА
ППЗУ (Flash Memory): 16 KB (из них 2 Кб используются загрузчиком)
ОЗУ (SRAM): 1 Кб
ПЗУ (EEPROM): 512 байт
Тактовая частота: 16 МГц

Что же нужно для того, чтобы сделать своего робота ?

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

Важным этапом, естественно, служит получение в своё распоряжение одной из плат Arduino. В моём случае это плата Arduino Diecimila. Также для подключения платы к компьютеру необходим USB кабель любой длины стандарта A-B. Через этот кабель будет осуществляться обмен данными между компьютером и микроконтроллером, а также подача питания на плату, т.е. внешний блок питания не обязателен. Еще один компонент, который необходим для управления моторами – это плата расширения MotorShield.

image
Плата расширения MotorShield и комплект деталей.

image
Что и как подключать к MotorShield.

Далее нужно определиться с целями: мне нужно к имеющемуся игрушечному танку приделать дистанционное управление, но не обычное «куда нажал – туда поехал», а такое, при котором танку передавались бы координаты на воображаемом поле и он самостоятельно бы их достигал. Т.е. нужно представить, что комната (или любой другой участок, по которому будет двигаться танк) р��збита на квадраты, представляющие собой систему координат. Тогда танку необходимо будет передавать координаты какого-либо квадрата и он должен будет повернуться к нему и проехать необходимое расстояние, чтобы стать в этот квадрат.

image
Игрушечный танк с материнской платой.

image
Материнская плата явно больше платы Arduino :).

Есть танк с моторами, есть плата, есть плата расширения. Необходимо средство для передачи координат. Это будет программа на компьютере пользователя, которая будет передавать данный на танк посредством Wi-Fi связи. Должен заметить, что Wi-Fi не понятен плате, поэтому на танке присутствует еще и обычная материнская плата (позже заменена на ноутбук ), которая будет от адаптера Wi-Fi транслировать данные в COM-порт, через который будет связь с платой Arduino. От нее сигналы уже будут поступать на плату расширения, и моторы должны будут закрутиться. Задача сводится к написанию двух программ: одной – для передачи данных от компьютера на Wi-Fi адаптер, другой – для обработки данных внутри микроконтроллера.

image

Итак, поехали!

Программу, отвечающую за обмен данными между ПК и микроконтроллером через COM-порт, писать можно на чём угодно. Пусть это будет Delphi.

Для краткости приведу исходный код только той функции, которая будет передавать танку команды, отвечающие за поворот и передвижение на нужные угол/расстояние. Функция принимает на вход текущие координаты (x0,y0), новые координаты (x1,y1) и текущий угол поворота танка alpha. Возвращать функция будет новый текущий угол. Текущие координаты и угол хранятся вне функции. Код откомментирован в нужных местах, поэтому описывать не стану.

Copy Source | Copy HTML
  1. Function MoveTank(x0, y0, x1, y1, alpha: integer): integer;
  2. var newAlpha: integer; // новый угол
  3.     FlagsField : byte; // содержит код направления движения
  4.     angle_tmp: integer;
  5.     TmpStr: string;
  6.     angle, dist: byte; // угол и расстояние, передаваемые танку
  7. begin
  8.      // Вычисление нового текущего угла
  9.      newAlpha := Round(ArcTan(Abs((x0-x1)/(y0-y1)))); // Поворот относительно текущего положения
  10.      angle_tmp := (360 + newAlpha - alpha) mod 360; // Расстояние между заданными координатами
  11.      dist := Round(10*Sqrt(Sqr(x0-x1) + Sqr(y0-y1)));
  12.      FlagsField := 0; // Определение оптимального направления движения
  13.  
  14.      if angle_tmp <= 90 then FlagsField := 0 // передом, вправо
  15.      else if angle_tmp < 180 then
  16.             begin
  17.               angle_tmp := 180 - angle_tmp;
  18.               FlagsField := FlagsField or 4; // задом, вправо
  19.             end
  20.      else if angle_tmp < 270 then
  21.             begin
  22.               angle_tmp := angle_tmp - 180;
  23.               FlagsField := FlagsField or 6; // задом, влево
  24.             end
  25.      else begin
  26.               angle_tmp := angle_tmp - 270;
  27.               FlagsField := FlagsField or 2; //передом, влево
  28.             end;
  29.  
  30.      angle := angle_tmp;
  31.  
  32.      // Далее нужно отправить в COM-порт сначала флаги, затем данные.
  33.  
  34.      FlagsField:= FlagsField or 1; // для передачи угла
  35.      TmpStr := Chr(FlagsField);
  36.      ComPort_.Write(TmpStr);
  37.      TmpStr := Chr(angle);
  38.      ComPort_.Write(TmpStr);
  39.  
  40.      FlagsField:= FlagsField and 254; // для передачи расстояния
  41.  
  42.      TmpStr := Chr(FlagsField);
  43.      ComPort_.Write(TmpStr);
  44.      TmpStr := Chr(dist);
  45.      ComPort_.Write(TmpStr);
  46.  
  47.      Result := newAlpha;
  48. end;




Следующий этап — написание программы для прошивки её в плату. Всё, что нам нужно, это принять данные с последовательного порта и обработать поступившую команду, включив вращение моторов танка в нужную сторону. Моторы включаются на определенное время и длительностью этого времени достигается движение на требуемое расстояние

В программе для приёма данных используется пин №9 (TxD). Соответственно 2й контакт СОМ порта материнской платы (RxD) необходимо подключить к пину №9 на Arduino. Ещё одно требование: нужно настроить СОМ порт материнской платы на скорость 9600 бод.

Для управления движением танка будем использовать два мотора — для левой и правой гусениц (разъемы M1 и M2 на Motor Shield). Для упрощения работы с моторами используем фреймворк AFMotor, легко подключаемый к нашему проекту одной строкой «#include «AFMotor.h»». Моторы обозначим цифрами 1 для левой и 2 для правой гусениц. В коде, приведенном ниже, видно, что работа с моторами не представляет собой ничего сложного.

Copy Source | Copy HTML
  1. #include "AFMotor.h" // библиотека для удобства обращения с движками
  2.  
  3. #define TX 9 // пин на Arduino, куда подключен выход из COM-порта
  4.  
  5. // кодирование команд от джойстика
  6.  
  7. #define cmdForward 1
  8. #define cmdBackward 2
  9. #define cmdRapidLeft 3
  10. #define cmdRapidRight 4
  11. #define cmdLeft 5
  12. #define cmdRight 6
  13.  
  14. // скорости вращения движков
  15. // MaxSpeed - обычное движение
  16. // MinSpeed - скорость одной из гусениц при резком повороте
  17. // HalfSpeed - скорость одной из гусениц при плавном повороте
  18.  
  19. #define MaxSpeed 200
  20. #define MinSpeed 100
  21. #define HalfSpeed 150
  22.  
  23. // движение танка со скоростями левой и правой гусениц LTS и RTS
  24. // в направлении Direction
  25.  
  26. void MoveTank(byte LTS, byte RTS, byte Direction);
  27.  
  28. // чтение одного байта с COM-порта
  29. byte COMread();
  30.  
  31. // хранит команду, полученную с COM-порта
  32. byte Command =  0;
  33.  
  34. // текущее направление движения
  35. byte CurrentDirection = FORWARD;
  36.  
  37. // выбираем 1й и 2й разъемы на Motor Shield, куда подключены движки
  38. AF_DCMotor LeftTrack(1, MOTOR12_1KHZ);
  39. AF_DCMotor RightTrack(2, MOTOR12_1KHZ);
  40.  
  41. void setup()
  42. {
  43. LeftTrack.setSpeed(MaxSpeed);
  44. RightTrack.setSpeed(MaxSpeed);
  45. pinMode(TX, INPUT);
  46. }
  47.  
  48. void loop()
  49. {
  50. Command = COMread();
  51. switch (Command)
  52. {
  53. case cmdForward:
  54. MoveTank(MaxSpeed, MaxSpeed, FORWARD);
  55. CurrentDirection = FORWARD;
  56. break;
  57. case cmdBackward:
  58. MoveTank(MaxSpeed, MaxSpeed, BACKWARD);
  59. CurrentDirection = BACKWARD;
  60. break;
  61. case cmdRapidLeft:
  62. MoveTank(MinSpeed, MaxSpeed, CurrentDirection);
  63. break;
  64. case cmdRapidRight:
  65. MoveTank(MaxSpeed, MinSpeed, CurrentDirection);
  66. break;
  67. case cmdLeft:
  68. MoveTank(HalfSpeed, MaxSpeed, CurrentDirection);
  69. break;
  70. case cmdRight:
  71. MoveTank(MaxSpeed, HalfSpeed, CurrentDirection);
  72. break;
  73. default:
  74. LeftTrack.run(RELEASE); // останавливаем двигатели
  75. RightTrack.run(RELEASE);
  76. break;
  77. }
  78. }
  79.  
  80. void MoveTank(byte LTS, byte RTS, byte Direction)
  81. {
  82. LeftTrack.setSpeed(LTS);
  83. RightTrack.setSpeed(RTS);
  84. LeftTrack.run(Direction);
  85. RightTrack.run(Direction);
  86. }
  87.  
  88. byte COMread()
  89. {
  90. byte val =  0;
  91. while (digitalRead(TX));
  92. // ждем стартовый бит
  93. if (digitalRead(TX) == LOW)
  94. {
  95. delayMicroseconds(42);
  96. for (int k = 0; k < 8; k++)
  97. {
  98. delayMicroseconds(84);
  99. val |= digitalRead(TX) << k;
  100. }
  101. // ожидание 9го бита и стопового
  102. delayMicroseconds(168);
  103. return val;
  104. }
  105. }


Осталось только прошить эту программку в Arduino (а делается это нажатием одной кнопки в интерфейсе Arduino IDE) и можно развлекаться, засылая танк в тыл врага :).

Заключение

Конечно, можно не ограничиваться просто пересылкой координат. Можно добавить интерактивности, используя для управления танком джойстик. А используя веб-камеру, прикрепленную к башне танка, можно наблюдать за движением, сидя за компьютером. Но для этого понадобится дополнительное ПО. Но даже это не делает программирование Arduino чем-то непосильным. Работать с такой платой просто, легко, а главное — доступно! Хотя нет, главное — это получение море удовольствия как от результата, так и от самого процесса!