Продолжаем строить робота
Строим дальше нашего робота.
После того как собрано шасси, мы начали собирать «корпус» робота. Для этого использовали детали из обычного металлического конструктора.
Для скрепления деталей использовали пластиковые стяжки. Для питания робота сначала мы использовали батарейки на 9В (типа «Крона»), но они достаточно быстро разряжались, поэтому использовали аккумулятор от гоночной машинки, тоже на 9В. Для включения/выключения использовали ... выключатель:
Сейчас немного отвлечемся от сборки робота. Для дистанционного управления роботом на первом этапе мы решили использовать пульт от медиа плеера. Для получения сигнала мы будем использовать ИК приемник VS1838B. Прежде чем включать ИК приемник в общую схему робота и писать программу управления, необходимо уточнить каким кнопкам пульта какое действие робота будет соответствовать, и какие коды, полученные Arduino, соответствуют этим кнопкам. Для выяснения этого мы собрали небольшую схему с ИК приемником и подключили его к Arduino:
Как водится, для общения с ИК приемником взяли одну из имеющихся в открытом доступе библиотек. Программа получилась такая:
#include <IRremote.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
}
void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
irrecv.resume(); // Receive the next value
}
}
Дальше дело не хитрое — нажимай кнопки и записывай коды:
Продолжаем собирать управляющую часть робота. Для управления двигателями нам нужен H-bridge, таким мы уже пользовались в проекте Зоотроп. Но здесь мы не будем использовать непосредственно саму микросхему и пучок проводов к ней. Умные люди придумаю расширения к Arduino, называются они Shield, или по-русски шилды. Представляют собой эти шилды платы размером с Arduino или чуть больше, на этих платах реализуется какая-то функциональность, но самое главное, что подсоединяется она к Arduino с использованием установленных на них штыревых разъёмов. Получается такой бутерброд из плат. На основе H-bridge делают разные MotorShield'ы, как следует из названия, предназначены для управления моторами. Мы взяли Ardumoto L298P Motor Driver Shield. Как я уже говорил, шилд легко подсоединяется к Arduino, имеет удобные клеммы для подключения двигателей и питания (от них же питается и сам Arduino).
Шилд использует пины 12 и 13 для включения/выключения двигателей, и пины 3 и 11 для управления скоростью вращения двигателей. Специально для этого шилда уже есть куча библиотек с полезными функциями, мы выбрали первую попавшуюся, и она заработала. Вроде бы все готово для программирования первой версии дистанционно управляемого робота. Но в процессе отладки программы мы столкнулись с неожиданной проблемой. Начали появляться странности: после выполнения нескольких команд, робот отказывался реагировать на поступающие сигналы, в некоторых случаях отказывался работать один из двигателей (исправный). По отдельности оба компонента работали хорошо, ИК исправно принимал команды, двигатели крутились в разные стороны. При объединении схем, опять появлялись проблемы. Логика подсказывала, что проблема появляется из библиотек, поскольку программа на тот момент была простейшая. При более детальном изучении библиотеки был обнаружен следующий текст
// define which timer to use
//
// Uncomment the timer you wish to use on your board. If you
// are using another library which uses timer2, you have options
// to switch IRremote to use a different timer.
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
#else
// #define IR_USE_TIMER1 // tx = pin 9
#define IR_USE_TIMER2 // tx = pin 3
#endif
Спинным мозгом получилось догадаться, что если двигатель использует третий пин, то, наверное, не совсем правильно использовать тот же пин в таймере для IR приемника. По поводу таймеров в Arduino это отдельная большая тема, сейчас главное то, что если используется таймер (а их в Arduino uno два), то на этот же пин лучше ничего не вешать. Вобщем, следуя велению того же спинного мозга первая строчка была раскомментирована, вторая наоборот. Вот так выглядит финальная версия программы робота версии 1.2:
#include <IRremote.h>
#include <ArduMoto.h>
ArduMoto Moto; //создаем объект для работы с моторами
int RECV_PIN = 7; //пин где сидит ИК приемник
IRrecv irrecv(RECV_PIN); //создаем объект для работы с ИК приемником
decode_results results; //создаем объект для обработки результатов работы ИК приемника
const float kB=0.85; //коэффициент для мотора B, так как он крутится быстрее
const float kA=1;
const float kAll=0.7;/общий коэффициент
void setup()
{
irrecv.enableIRIn(); //подключаем ИК приемник
Moto.begin();//подключаем моторы
Moto.setSpeed('A',0);//останавливаем моторы на всякий случай
Moto.setSpeed('B',0);
}
void left(int velocity)
{
Moto.setSpeed('A',velocity*kAll*kA);
Moto.setSpeed('B',-velocity*kAll*kB);
}
void right(int velocity)
{
Moto.setSpeed('A',-velocity*kAll*kA);
Moto.setSpeed('B',velocity*kAll*kB);
}
void forward(int velocity)
{
Moto.setSpeed('A',velocity*kAll*kA);
Moto.setSpeed('B',velocity*kAll*kB);
}
void backward(int velocity)
{
Moto.setSpeed('A',-velocity*kAll*kA);
Moto.setSpeed('B',-velocity*kAll*kB);
}
void forwardleft(int velocity)
{
Moto.setSpeed('A',velocity*kAll*kA);
Moto.setSpeed('B',0.4*velocity*kAll*kB);
}
void forwardright(int velocity)
{
Moto.setSpeed('B',velocity*kAll*kB);
Moto.setSpeed('A',0.4*velocity*kAll*kA);
}
void backwardright(int velocity){
Moto.setSpeed('B',-velocity*kAll*kB);
Moto.setSpeed('A',-0.4*velocity*kAll*kA);
}
void backwardleft(int velocity){
Moto.setSpeed('A',-velocity*kAll*kA);
Moto.setSpeed('B',-0.4*velocity*kAll*kB);
}
void loop() {
if (irrecv.decode(&results)) {//если получили сигнал то надо что-то сделать
switch (results.value){
case 0x807fc03f://едем вперед
forward(100);
break;
case 0x807f40bf:
backward(100);
break;
case 0x807f9867:
forward(0);
break;
case 0x807f708f:
forwardleft(100);
break;
case 0x807f58a7:
forwardright(100);
break;
case 0x807f807f:
backwardright(100);
break;
case 0x807f06f9 :
backwardleft(100);
break;
case 0x807f906f :
left(100);
break;
case 0x807fb847 :
right(100);
break;
}
irrecv.resume();
}
}
И все стало работать, как предполагалось. В этом ролике робот еще не умеет делать команды поворотов направо и налево c одновременным движением назад, а так же повоторы на месте. Работает на аккумуляторе от гоночной машинки.
После робот был немного усовершествован. Мы установили на него более емкий аккумулятор, при этом меньших размеров:
Для зарядки мы используем «умное» зарядное устройство:
В программу добавили команды поворотов, указанные раннее. И робот стал двигаться намного веселее (на заднем и на переднем плане слышно и видно Фёдора, который возмущается, что ему не дают поиграть с роботом):
Небольшое слайдшоу: