Ардуино и Контролер за Радио-Контролирана Хоби Количка

Източник:  www.sparkfun.com

Оригинално Заглавие: RC Hobby Controllers and Arduino

Превод: Т.Б.

Дистанционно с Ардуино

Роботите, количките, робо-количките, както и всички видове подобни устройства, изискват някаква степен на отдалечен контрол. В повечето от случаите е наистина изкушаващо да си го реализирате сами посредством модулите Xbee или друга подобна безжична технология. Понякога това не е никак лоша идея, но по-често това е прекалено „изсилване“ /ненужно като параметри хардуерна мощ/ и един от често разочароващите методи. Сега Вие сигурно си мислите, „Спомням си добрите стари дни, когато просто поставях батериите в RC количката, натискайки бутоните – тя започваше да се движи“.

Е, добре дошли отново в тези добри стари дни.

RC предавателят/приемникът комбинират широк обхват от прости и нескъпи решения – справяйки се с сериозни задачи, но най-хубавото за тях, е че те всички отговарят на даден стандарт, което наистина ги прави взаимозаменяеми. С една дума излиза, че е едно и също като начин свързването на RC приемник към вашия Ардуино проект, по същия начин по който свързвате серво мотор, а кодът е също толкова елементарен. В това ръководство, аз ще Ви преведа през основите на пълноценното използване на вашята Ардуино платформа, за да я накарате да интерпретира команди от нескъпо RC дистанционно, за да можете да контролирате всичко /което желаете/, в това число четири-колесен робот и мн. др.

Това звучи страхотно, но Аз Никога не съм докосвал RC Предавател …

Това не е толкова сложно, колкото звучи – ще Ви помогна да навлезете в материята. Радио-контролираните предаватели и приемници обикновенно се използват за управление на модели на колички и самолети. Типичният предавател ще разполага с няколко контролни повърхности, като например скрол или джойстик, както и някои ключове или клавиатури. Всяка степен на свобода, която контролерът Ви осигурява представлява точно определен радио канал. Или с други думи, джойстика заема два канала (x & y), където клавиатурата или ключа ще заема само един канал. RC предавателите най-общо имат между четири и шест от тези канали.

Тъй като повечето RC модели могат да бъдат обобщени като фантазия в кутия със серво-мотори, то точно това трябва и да управлява приемника. Въпреки, че те всички идват в различни форми/размери/габарити, същите те разполагат с нещо, което ги обединява: ред от серво-драйвери. Тези драйвери са подравнени, така че да можете да включите своите серво-мотори директно в приемника. Това е доста удобно, тъй като ни позволява, да включим приемника в ардуино, който от своя страна може да интерпретира „серво-езика“ и в последствие да реши как да го използва.

Е нека го закачим!

Добре, това е духът! Ние ще закачим няколко канала от RC приемникът, за да разберем как изглежда входа на приемника. RC предавателя/приемника са чифт, разполагам с шест канала, но ние ще видим как точно да ги свържем сега. Това означава, че са ни необходими три цифрови извода, които да прочитат входа, както и 5V, за да захраним приемника. Тук отдолу е дадена схема, по която аз си свързах моите:

Забележете, че RC приемникът е надолу, Обърнах го с цел да направя проводниците по-лесно проследими. Ще са Ви необходими мъжко-женски джъмпери ако разполагате с такива. Ако ли не, Вие може да използвате някои слепнати мъжки и женски джъмпери заедно. Цифровите изводи, който аз избрах са напълно случайни; вие трябва да можете да използвате всеки цифров вход върху Ардуино, който желаете, но горната схема отговаря на кодът по-долу.

Сега нека кача скица и да видим какво е свързцано към тези изводи. „Серво езикът“, който RC приемника създава, всъщност е истинска PWM (Ширичонно Импулсна Модулация). Arduino има удобна функция вградена в него, за прочитане на тези импулси и за връщане на тяхната дължина в милисекунди. Функцията се нарича  pulseIn() . Нега хвърлим един поглед върху простата схема, която написах за да отпечатаме суровия вход на приемника към последователен /сериен/ монитор.

// Начало на кода

/*
 RC PulseIn Serial Read out
 By: Nick Poole
 SparkFun Electronics
 Date: 5
 License: CC-BY SA 3.0 - Creative commons share-alike 3.0
 use this code however you'd like, just keep this license and
 attribute. Let me know if you make hugely, awesome, great changes.
 */

int ch1; // Here's where we'll keep our channel values
int ch2;
int ch3;

void setup() {

  pinMode(5, INPUT); // Set our input pins as such
  pinMode(6, INPUT);
  pinMode(7, INPUT);

  Serial.begin(9600); // Pour a bowl of Serial

}

void loop() {

  ch1 = pulseIn(5, HIGH, 25000); // Read the pulse width of
  ch2 = pulseIn(6, HIGH, 25000); // each channel
  ch3 = pulseIn(7, HIGH, 25000);

  Serial.print("Channel 1:"); // Print the value of
  Serial.println(ch1);        // each channel

  Serial.print("Channel 2:");
  Serial.println(ch2);

  Serial.print("Channel 3:");
  Serial.println(ch3);

  delay(100); // I put this here just to make the terminal
              // window happier
}
// Край на кода

Функцията pulseIn() взима три аргумента:  първият е изводът, на който се появява вашият импулс; втория  представлява типа на импулса, който търсите; и третият представлява число време-прекъсване, което показва колко точно време желаете да чакате този импулс да се появи. Въпросната функция връща като резултат дължината на импулса в микросекунди, и именно по този начин ние ще прочитаме входящите PWM, по същия начин ако беше серво.мотор. Когато Вие изпълните този код, Вие трябва да получите като резултат някакви стойности /числа/ – които се появяват в изхода на терминала. Числата най-вероятно за вас няма да означават нищо, но по същество те трябва като стойности да бъдат някъде между 1000 и 2000. Това което наистина в случая е от значение, е че когато Вие започнете да движите контролната повърхност с това число, да завъртате потенциометри и да превкл. ключове , е хубаво наистина да обърнете внимание на канала, който се засяга. Сега, след като разполагаме с всички тези стойности, ние можем да кодираме различни състояния с тяхна помощ и да правим каквото си пожелаем. Скицата отдолу е моята скица след като я модифицирах, за да поставя тези стойности във функцията pulseIn() в този контекст. // Начало на кода

	 
/*
 RC PulseIn Joystick
 By: Nick Poole
 SparkFun Electronics
 Date: 5
 License: CC-BY SA 3.0 - Creative commons share-alike 3.0
 use this code however you'd like, just keep this license and
 attribute. Let me know if you make hugely, awesome, great changes.
 */

int ch1; // Here's where we'll keep our channel values
int ch2;
int ch3;

void setup() {

pinMode(5, INPUT); // Set our input pins as such
pinMode(6, INPUT);
pinMode(7, INPUT);

Serial.begin(9600); // Pour a bowl of Serial

}

void loop() {

  ch1 = pulseIn(5, HIGH, 25000); // Read the pulse width of
  ch2 = pulseIn(6, HIGH, 25000); // each channel
  ch3 = pulseIn(7, HIGH, 25000);

  if(ch1>1000){Serial.println("Left Switch: Engaged");}
  if(ch1<1000){Serial.println("Left Switch: Disengaged");}
  /* I found that Ch1 was my left switch and that it
  floats around 900 in the off position and jumps to 
  around 1100 in the on position */

Serial.print("Right Stick X:"); // Ch3 was x-axis
Serial.println(map(ch3, 1000,2000,-500,500)); // center at 0

Serial.print("Right Stick Y:"); // Ch2 was y-axis
Serial.println(map(ch2, 1000,2000,-500,500)); // center at 0

Serial.println(); //make some room

delay(100);// I put this here just to make the terminal
           // window happier
}
// Край на кода

Тук можете да видите, че аз съм си представил, коя контролна повърхност, кой канал контролира и същевременно съм написал няколко реда с print функцията, които ще повлияят върху моите действия връху предавателя на чист Английски. Съответно Вие бихте могли да разгърнете това за всеки отделен канал на вашия приемник, вие също така бихте могли да заместите тази скица с Firmata и да контролирате обработващата скица с вашия RC предавател, но аз си мисля, че най-добрата демонстрация, която аз мога да Ви представя е като метна този код на един робот и като го пораздвижа. Е хайде най-накрая да се захващаме.

Радио Приемник Robot Rig?

Аз лично се спрях на магическото шаси и на драйвера за мотора Ardumoto shield, за моя роботска платформа, за да реализирам този проект. Тъй като той разполага само с две колела, то той е добър начин да демонстрираме диференциалното управление и как да смесим всичко, че да проработи. Първото нещо, което ще направим е да модифицираме Ardumoto шийлда, за да създадем друг импровизиран „RCmoto“ шийлд, чрез добавянето на някои рейки към прототипиращата рейка, в която ние ще можем да включим нашия приемник.

Направих шест реда от три, тъй като предавателят разполага с шест канала, и не Ви е необходимо да го свързвате към рейката на батерията на приемника, тъй като Вие използвате захранването и масата на рейката на серво-мотора. Когато запоите тези вътре, имайте впредвид, че вашия приемник ще бъде обърнат впоследствие наопаки, затова го запоете по подходящ начин. Вие трябва да имате възможност да видите сега как аз съм ги свързал, като наблюдавате изображенията по-горе. Редът с масата е окъсен целия и включен към маса – по същия начин е процедирано с положителния полюс на захранването – след което всеки сигнален извод се разделя към цифровия извод. Това определено не е най-правилния начин за реализиране, но той работи доста добре. А ето и как изглежда шасито с нашия модифициран шийлд Ardumoto и със свързания към него Ardumoto:

Не е никак зле нали? Уверете се, че вашите мотори са свързани по подходящия начин и добавете захранващ източник (9V батерия на мен ми свърши прекрасна работа), тъй като вече е крайно време да го подкараме това нещо. Единствената стъпка, която ни остана е да напишем няколко реда код, за да преведем серво командите за управление към команди за левия/десния серво-мотор. Ще Ви осигуря кода сега и ще го разясня отдолу.

// Начало на кода

	 
/*
 RC PulseIn Joystick Servo Control
 By: Nick Poole
 SparkFun Electronics
 Date: 5
 License: CC-BY SA 3.0 - Creative commons share-alike 3.0
 use this code however you'd like, just keep this license and
 attribute. Let me know if you make hugely, awesome, great changes.
 */

int ch1; // Here's where we'll keep our channel values
int ch2;
int ch3;

int move; // Forward/Back speed
int turn; // Turning Factor

int pwm_a = 3;  //PWM control for motor outputs
int pwm_b = 11;  //PWM control for motor outputs
int dir_a = 12;  //direction control for motor outputs
int dir_b = 13;  //direction control for motor outputs

void setup() {

pinMode(5, INPUT); // Set our input pins as such
pinMode(6, INPUT);
pinMode(7, INPUT);

Serial.begin(9600); // Pour a bowl of Serial (for debugging)

  pinMode(pwm_a, OUTPUT);  //Set control pins to be outputs
  pinMode(pwm_b, OUTPUT);
  pinMode(dir_a, OUTPUT);
  pinMode(dir_b, OUTPUT);

  analogWrite(pwm_a, 0);  
  analogWrite(pwm_b, 0);
}

void loop() {

  ch1 = pulseIn(4, HIGH, 25000); // Read the pulse width of  
  ch2 = pulseIn(5, HIGH, 25000); // each channel
  ch3 = pulseIn(6, HIGH, 25000);
  /*
  if(ch1>1000){Serial.println("Left Switch: Engaged");}
  if(ch1<1000){Serial.println("Left Switch: Disengaged");}

Serial.print("Right Stick X:");
Serial.println(map(ch3, 1000,2000,-500,500));

Serial.print("Right Stick Y:");
Serial.println(map(ch2, 1000,2000,-500,500));

Serial.println();

delay(100);

clearAndHome();
*/

move = map(ch2, 1000,2000, -500, 500); //center over zero
move = constrain(move, -255, 255); //only pass values whose absolutes are
                                   //valid pwm values

/*What we're doing here is determining whether we want to move
forward or backward*/
if(move>0){digitalWrite(dir_a, 1);digitalWrite(dir_b, 1);};
if(move<0){digitalWrite(dir_a, 0);digitalWrite(dir_b, 0); move=abs(move);};

/*Here we're determining whether a left or a right turn is being 
executed*/
turn = map(ch1,1000,2000,-500,500);
turn = constrain(turn, -255, 255);

/*This is where we do some mixing, by subtracting our "turn" 
variable from the appropriate motor's speed we can execute
a turn in either direction*/
if(turn>0){analogWrite(pwm_b, move-turn); analogWrite(pwm_a, move);};
if(turn<0){turn=abs(turn); analogWrite(pwm_a, move-turn); analogWrite(pwm_b, move);};

Serial.print("move:"); //Serial debugging stuff
Serial.println(move);

Serial.print("turn:"); //Serial debugging stuff
Serial.println(turn);

Serial.print("move-turn:"); //Serial debugging stuff
Serial.println(move-turn);

Serial.println(); //Serial debugging stuff
Serial.println();
Serial.println();

}

// Край на кода

Окей, нека да погледна дали мога да обясня как точно се осъществява управлението в горната скица. Това което направих, в основни линии отбелязва посоката на движение напред/назад – отговаряща на моя джойстик, това най-общо са стойности в интервала от -255 до 255, с др.стойност представящ пълната скорост назад/напред. За да комуникирате по този начин с Arduino шийлда, Вие трябва да ги разделите на отделни числа: такива за посока и скорост. За да направя това, аз просто проверих, за да съм сигурен дали въпросното число е положително. Ако е така, аз променях посоката на движение на двата мотора на 1-ца. Ако ли пък въпросното число е отрицателно, то тогава просто задавах посока на двата мотора 0-ла. Всичко, което трябваше да направя след това е да получа „абсолютната стойност“ на това число и да го използвам като моя основна PWM стойност за двата мотора. Аз казвам „основна PWM стойност“, тъй като това не е точно това, което се изпраща като данни към двата мотора, вместо честата на завъртане /оборотите/ да се изважда от едната страна.

Очевидно има и съвсем други подходи, за да реализирате диференциалното управление; с малко повече редове код Вие можете да обърнете, някой конкретен мотор в обратната посока и по този начин да се въртите на място. Също така този код не управлява по начина, по който най-вероятно очаквате, когато карате наобратно. При някои случаи, това трябва да Ви е достатъчно, за да стартирате с Роботите и радио управляемите модели , също така се надявам, че сте били вдъхновени до такава степен, че да грабнете хоби-предавателят за следващия ви проект с робот.

Успешно хакване!