Robo Kit, czyli pierwsze kroki z robotyką. Line Follower.
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:
Montaż czujników na uniwersalnej płytce możecie znaleźć na stronie akademia.nettigo.pl
Końcowy montaż płytki oraz instrukcja podłączenia znajduje się tutaj
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, wyglądajcie kolejnych wpisów ;)
- Arduino Uno R3
- Motor Shield R3
- Magician Chasiss
- płytka prototypowa UM-2
- 4x transoptor CNY70
- 2 rezystory 100 Ohm ( zestaw 10 sztuk rezystorów 100 Ohm )
- 2 rezystory 220 Ohm (zestaw 10 sztuk rezystorów 220 Ohm)
- 8 rezystorów 100k Ohm (zestaw 5 sztuk rezystorów 10k Ohm)
- liczne zworki zrobione z rozizolowanego drutu miedzianego
Cały program do pobrania z http://static.nettigo.pl/robo/linefollower.ino
Fajnie wyszło, a program wbrew pozorom jest bardo krótki.
Teraz wszyscy mogą zobaczyć jakie to łatwe :-). Sam nie zdawałem sobie z tego sprawy.
Podczas weryfikowania programy wyskakuje mi 'MS_DCMotor’does not name a type nie wiem jak temu zaradzić :/
Proszę sprawdzić czy skopiował Pan cały kod, czy nie pominął Pan pierwszego wersu:
#include… etc.
Jest to deklaracja biblioteki, w której opisane są funkcje do obsługi silników (setSpeed, itp). Proszę też sprawdzić czy na pewno ściągnął Pan tę bibliotekę (MotorShield).
nie miałem pobranej biblioteki( https://github.com/hanseartic/MotorShield ) dziękuje za pomoc :)
Nie ma sprawy, cieszę się, że mogłem pomóc :)
Dobra mam jeszcze jedno pytanie :) jak zrobiłeś zasilanie ? chodzi mi gdzie podłaczyłeś baterie. czy to tego czarnego gniazda co jest obok wejścia USB w Arduino UNO
Baterie podłączyłem bezpośrednio do MotorShielda, gniazdo nr 8 ;)
http://nettigo.pl/products/355
ahaa spoko dzięki :). Co prawda nie robię tego robocika co tu jest opisany ale dość podobny który w pewnym sensie podąża za światłem :)
Powiem tylko, że czarne wejście jest niezbyt dobre dla baterii, bo za nim jest stabilizator liniowy, który zamienia nadmiar prądu w ciepło (czyli straty). Ale ciężko wymyślić na poczekaniu coś równie wygodnego dla początkujących.
Wraz z rozwojem twojej wiedzy o majsterkowaniu w elektronice warto zainteresować się czymś takim jak przetwornice. One potrafią zmniejszać i zwiększać napięcie bez większych strat. Niektóre modele są o tyle dobre, że potrafią dbać o różne rodzaje akumulatorów i ich nie rozładowywać poza pewną bezpieczną granicę.
kurcze mam kolejny problem :/ nie wiem dlaczego ale nie chce mi zczytywać danych z fotorezystora i nie wiem w czym jest problem :/ czy mógł by ktoś sprawdzić ew. poprawić mój program ?
#include
// v1.0
#define predkosc 255
#define predkosc2 100
#define predkosc3 0
#define wartosc 2
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);
struct odczyty
{
int foto;
} odczyt;
void sprawdz(struct odczyty &odczyt)
{
odczyt.foto = analogRead(0);
}
void steruj(struct odczyty odczyt)
{
if(odczyt.foto > wartosc)
{
prawy.setSpeed(predkosc);
lewy.setSpeed(predkosc);
//jedzie na wprost
if(odczyt.przewf <wartosc)
{
prawy.setSpeed(predkosc3);
lewy.setSpeed(predkosc);
// obrót
}
}
{
lewy.setSpeed(0);
prawy.setSpeed(0);
}
*/
void setup()
{
prawy.setSpeed(0);
lewy.setSpeed(0);
prawy.run(FORWARD|RELEASE);
lewy.run(FORWARD|RELEASE);
Serial.begin(9600);
}
void loop()
{
sprawdz(odczyt);
steruj(odczyt);
//drukuj(odczyt);
delay(10);
}
To nie wina programu, tylko wybranego pinu do odczytu :) MotorShield wykorzystuje piny analogowe 0 i 1, zwraca na nich wartość prądu obciążenia silnika. Jak zmienisz pin na np. 2, powinno być dobrze :D