Robo Kit, czyli pierwsze kroki z robotyką. Line Follower.

Tu pokazujemy jak prosto i bezproblemowo zacząć zabawę z robotami.

O co chodzi?

Przyświecała nam idea stworzenia zestawu dzięki któremu można w przyjemny sposób rozpocząć przygodę z robotyką. Prostota obsługi jest tu priorytetem, dlatego też zdecydowaliśmy się na wykorzystanie gotowych modułów do realizacji jak największej ilości funkcji. Pojazd podążający za linią (line follower) jest najlepszy na początek. W miarę prosty w realizacji, pozwala jednocześnie zebrać pierwsze doświadczenia. Dzięki wykorzystaniu gotowych modułów (Arduino UNO, Motor Shield, gotowe podwozie robota) możemy kolejne roboty budować w oparciu o te same podzespoły. Jednocześnie nie jesteście ograniczeni tylko do robotów – Arduino może być sercem projektów niemających nic wspólnego z robotyką.

Zasada działania, czyli teoria do pominięcia

Jak sprawić by robot widział linię? Żeby odpowiedzieć sobie na to pytanie, należy wpierw zadać sobie inne: W jaki sposób my widzimy? Czemu nocne niebo jest czarne, kartka jest biała, a liście zielone? Wszystko to wynika ze zdolności do odbijania światła. A w zasadzie – do zdolności odbijania fali o konkretnej długości. Liście są zielone, bo zawarty w nich chlorofil odbija fale elektromagnetyczne o długości odpowiadającej zieleni, resztę pochłania. W ten sam sposób – dno studni czy nocne niebo wydaje się nam czarne, bo światło (fale EM) są przez nie pochłaniane. Właśnie z tej własności skorzystamy budując naszego robota.
Jako oczka followera wykorzystamy transoptory odbiciowe CNY70. Transoptor to zestaw diody i fototranzystora. W tym wypadku jest to dioda podczerwona. Podczerwień to fala EM na tyle długa, że ludzkie oko jej nie widzi. Podlega ona jednak tym samym prawom co światło widzialne – “czerń” ją bardzo dobrze pochłania, a “biel” bardzo dobrze odbija. Dzięki temu transoptor położony na kartce będzie dobrze przewodził, z kolei położony na taśmie izolacyjnej – nie będzie przewodził prawie w ogóle.

Sposób podłączenia

Podłączenie CNY70:

CNY70, wyprowadzenia CNY70, ponumerowane wyprowadzenia

Między pin numer jeden, a zasilanie wpinamy rezystor 300 Ohm, pin numer dwa podłączamy do masy. Do pinu numer 4 równolegle wpinamy rezystor 50k Ohm oraz wyjście do pinu analogowego w arduino, a pin nr trzy podłączamy do masy.
Jak widać, to czy transoptor przewodzi będziemy sprawdzać za pomocą funkcji analogRead(). Rezystory dobrałem na podstawie opisu czujnika na stronie producenta oraz wyciągając wnioski z pomyłek własnych i innych. Przed przystąpieniem do lutowania elementów sprawdźcie miernikiem czy dioda w transoptorze nie przewodzi prądu w obie strony. Jeśli tak jest – znaczy, że szlag ją trafił i takiego transoptora nie ma sensu wlutowywać. Można za to zostawić go sobie i wykorzystać w przyszłości jako czujnik podczerwieni ;). Uważajcie by nie przegrzać i nie uszkodzić elementu, wg producenta maksymalna temperatura lutowania to 260 stopni Celcjusza. Poza tym, przygotujcie sobie rezystory 50k Ohm (lutując równolegle 2 rezystory 100k Ohm) i rezystor 300 Ohm (łącząc szeregowo rezystory 220 i 100 Ohm). Dobrym pomysłem jest też zaznaczenie sobie markerem gdzie będą wlutowane transoptory, tylko pamiętajcie, że same styki powinny pozostać czyste. Po wsadzeniu w płytkę transoptorów proponuję zlutować wyprowadzenia, które idą do masy i dopiero do nich przylutować zworkę. Dla ułatwienia warto po obu stronach płytki poprowadzić długie zworki z drutu, masę i magistralę zasilania, jak widać na zdjęciach poniżej:

1. Magistrala zasilania i masa 2. Zwarte wyprowadzenia, które podłączamy do masy 3. Zlutowane masy
4. Zasilanie doprowadzone do odpowiednich pinów. 5. Widok z góry wlutowanych rezystorów 6. Wlutowane rezystory dzielnika napięć

Pozostało nam już tylko zlutowanie zworek między rezystorami 50k, a transoptorami oraz dolutowanie wyprowadzeń. Do tego ostatniego wykorzystałem zwykły drut miedziany w izolacji. Żeby ułatwić sobie zadanie, formowałem na końcach zworek małe pętelki, które zakładałem na goldpiny wyjścia transoptora.

Teraz ostatni, najtrudniejszy punkt. Trzeba jakoś doprowadzić sygnał z/do Arduino. Do tego proponuję wykorzystać przewód ośmiożyłowy i goldpiny. Najpierw wlutowujemy goldpiny ,a następnie do nich doczepiamy przewody. Tak jak wcześniej, żeby ułatwić sobie lutowanie, trzeba zrobić na końcach przewodu małe pętelki, które później założymy na goldpin. Wpierw trzeba porządnie skęcić przewód palcami, a potem dopiero robić pętelki..

7. Wlutowane transoptory 8. Gotowy moduł, widok z góry 9. Schemat we Fritzingu

Program obsługujący:

#include <MotorShield.h>

#define predkosc 140
#define predkosc2 110
#define wartosc 900
MS_DCMotor lewy(MOTOR_B);
MS_DCMotor prawy(MOTOR_A);
void sprawdz(struct odczyty &odczyt);
void steruj(struct odczyty odczyt);
void drukuj(struct odczyty odczyt);

Deklaracja zmiennych i użytych funkcji. Korzystamy z biblioteki napisanej przez kogoś ze społeczności Arduino do obsługi Motor Shielda, którą można pobrać tutaj.

Funkcja “sprawdz” odpowiada za odczyt napięcia za pomocą pinów analogowych i zapisanie odczytu do struktury. Stała “predkosc” i “predkosc2″ to kolejno, wypełnienie silników gdy robot jedzie prosto i skręca. Z kolei “wartosc” to nasz punkt odniesienia – jeśli funkcja analogRead() zwróci wartość większą niż 900 to czujnik jest umieszczony nad taśmą izolacyjną, a dla wartości mniejszej – nad kartką. Te trzy stałe są wielkościami dobranymi metodą prób i błędów, może się więc zdarzyć, że będziecie musieli je ustawić samodzielnie ;). Tak samo jak z ustawianiem fotela kierowcy, czy dostrajaniem radia.
Dam przykład: gdy zasilałem model baterią o napięciu 7.4V i dużej pojemności – takie wartości były dobre, z kolei gdy podłączyłem robota do zasilacza ustawionego na 6v, musiałem je podwyższyć. Podczas skrętu, jeden silnik nie dawał rady pokonać tarcia, jednak przy wypełnieniu 150 (predkosc2 = 150) już był w stanie to zrobić. Jak widać, zasada jest taka, że im niższe napięcie zasilania, tym większe musi być wypełnienie PWM to zrekompensować. Dlatego zawsze patrzcie na diody wbudowane w MotorShield, one mówią który silnik jest zasilany, czyli które koło powinno się kręcić.

void sprawdz(struct odczyty &odczyt)
{
odczyt.przew = analogRead(2);
odczyt.prwew = analogRead(3);
odczyt.lewwew = analogRead(4);
odczyt.lewzew = analogRead(5);
}

Funkcja “steruj” analizuje wskazania transoptorów i kontroluje moc silników. Jeśli choć jeden środkowy czujnik (odległość między nimi jest ciut większa niż szerokość taśmy izolacyjnej, w idealnym przypadku fototranzystory obu czujników znajdują się nad czarną linią, a diody już nie) pojazd jedzie do przodu. Jednak jeśli to czujnik umieszczony na obrzeżach płytki znajdzie się nad czarną linią – program wyłączy odpowiedni silnik. W związku z tym, że trasa czasem się przecina pod kątem prostym dodałem warunek – jeśli oba czujniki umieszczone na obrzeżach znajdują się nad czarnym, pojazd ma jechać dalej (drugi “if”). W komentarzu dopisałem funkcję, która zatrzymuje robota gdy ten wyjedzie na kartkę, jednak nie opłaca się jej stosować. Jak sami zauważycie – w większości przypadków, jeśli robot wyjedzie poza linię to będzie kręcił się w kółko do momentu kiedy wróci na linię. Dzieje się tak, gdyż w przypadku wyjechania poza linię program nie zmienia wartości wypełnienia sygnału zasilającego silniki. Po prostu nie ma opisanego takiego przypadku :).

void steruj(struct odczyty odczyt)
{
if(odczyt.lewwew > wartosc || odczyt.prwew > wartosc)
{
prawy.setSpeed(predkosc);
lewy.setSpeed(predkosc); //jedzie na wprost
if(odczyt.lewzew >wartosc && odczyt.przew > wartosc)
{
prawy.setSpeed(predkosc);
lewy.setSpeed(predkosc);
// jedzie dalej
}
if(odczyt.przew > wartosc && odczyt.lewzew < wartosc)
{
//prawy zwalnia
prawy.setSpeed(0);
lewy.setSpeed(predkosc2);
}
if(odczyt.przew < wartosc && odczyt.lewzew > wartosc)
{
//lewy zwalnia
lewy.setSpeed(0);
prawy.setSpeed(predkosc2);
}
}
/* if(odczyt.lewwew < wartosc && odczyt.prwew < wartosc && odczyt.przew < wartosc && odczyt.lewzew < wartosc)
{
lewy.setSpeed(0);
prawy.setSpeed(0);
}
*/
}

Na koniec moja ulubiona, ratująca życie funkcja “drukuj”. Jeśli coś nie działa, dzięki niej łatwo sprawdzić co ;). Na przykład: robot z jakiegoś powodu nie chce się trzymać linii. Po podłączeniu do Arduino, okazuje się, że czujnik nr “X” nie reaguje na linię, ale za to reaguje na światło lampki. Diagnoza – dioda w transoptorze odmówiła współpracy, albo dołączamy gdzieś obok małą diodę IR, albo wymieniamy cały czujnik ;)

void drukuj(struct odczyty odczyt)
{
Serial.print("analog pin 1: ");
Serial.println(odczyt.przew);
Serial.print("analog pin 2: ");
Serial.println(odczyt.prwew);
Serial.print("analog pin 4: ");
Serial.println(odczyt.lewwew);
Serial.print("analog pin 5: ");
Serial.println(odczyt.lewzew);
Serial.println();
}

Podsumowanie:

Właśnie udało Wam się zbudować swojego pierwszego robota :D. Wszystkie roboty z detekcją linii działają na tej samej zasadzie, w internecie można spotkać wiele projektów opartych na m. in.: attiny2313, atmega168 czy na atmega328p – takiej jak w Uno, jednak programowanie gołych scalaczków może sprawić trudności początkującym. Do budowy toru, proponuję wykorzystać zwykłą, czarną taśmę izolacyjną, tylko zamiast przyklejać ją bezpośrednio do podłogi – lepiej przykleić ją do kartek ze starego zeszytu i dopiero te kartki przykleić taśmą samoprzylepną do podłogi. Klej z taśmy izolacyjnej strasznie brudzi i ciężko schodzi. Tor powinien być możliwie płaski i równy, bez garbów. Poza tym pamiętajcie, że robot ma spory promień skrętu, więc może Follwer może mieć problemy z pokonaniem zakrętu ostrzejszego niż 90 stopni. Popróbujcie, ponaginajcie granice możliwości :D Poniżej zamieszczam program do pobrania i listę wykorzystanych elementów.
Program i projekt na pewno można udoskonalić, do czego Was gorąco zachęcam. Eksperymentujcie, czytajcie i co najważniejsze – nie zniechęcajcie się. Powodzenia w podbijaniu świata robotyki!

Cały program do pobrania tutaj