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 ;)

Cały program do  pobrania z http://static.nettigo.pl/robo/linefollower.ino

13 thoughts on “Robo Kit, czyli pierwsze kroki z robotyką. Line Follower.

  1. sprae

    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.

    Odpowiedz
  2. Snowman

    Podczas weryfikowania programy wyskakuje mi ‘MS_DCMotor’does not name a type nie wiem jak temu zaradzić :/

    Odpowiedz
    1. S. Autor wpisu

      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).

      Odpowiedz
  3. Snowman

    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

    Odpowiedz
  4. Snowman

    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 :)

    Odpowiedz
  5. sprae

    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ę.

    Odpowiedz
  6. Snowman

    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);
    }

    Odpowiedz
    1. S. Autor wpisu

      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

      Odpowiedz
  7. Pingback: Starter Kit » Beam Follower czyli robot z Arduino goni światło » Starter Kit

  8. Pingback: Starter Kit » Robo kit – uruchomienie » Starter Kit

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

This site uses Akismet to reduce spam. Learn how your comment data is processed.