KursyPoradnikiInspirujące DIYForum

Jak wykorzystać Raspberry Pi do budowy robota z kamerą?

Jak wykorzystać Raspberry Pi do budowy robota z kamerą?

Niektórzy uważają, że wykorzystanie Linuxa do budowy robotów nie ma większego sensu.

W tym artykule postaram się pokazać, że jest to bardzo łatwe i ma swoje zalety. Szczególnie, gdy jednostką sterującą będzie Raspberry Pi. Pora na robota z kamerą!

Opisywany robot powstał tylko jako prezentacja możliwego podejścia - nie jest ukończoną konstrukcją. W tej chwili nie posiada możliwości autonomicznego sterowania. Jest więc raczej zdalnie sterowaną platformą, którą można rozwijać poprzez dodanie czujników otoczenia lub analizę obrazu z zamontowanej kamery.

Robot z kamerą - lista elementów

Na początek wymienię elementy składowe omawianego robota.

Podstawa robota została wydrukowana na drukarce 3D. To nadal wstępny prototyp:

RPi-bot

Projekt podwozia dla robota na Raspberry Pi.

Po zmontowaniu robot prezentuje się następująco:

Prototyp robota z kamerą.

Prototyp robota z kamerą.

Oprogramowanie

Jako system operacyjny wybrałem Raspbiana. Jest to popularna dystrybucja Linuxa dedykowana dla Raspberry Pi, oparta o Debiana. Więcej informacji można znaleźć na stronie projektu.

Pierwszym etapem po instalacji była konfiguracja Wi-Fi - wykonywałem ją z poziomu konsoli, wykorzystując bezprzewodową klawiaturę (na zdjęciu widoczny jeszcze moduł USB od klawiatury). Po skonfigurowaniu WiFi, dalsze prace można było prowadzić przez ssh, więc klawiatura nie była już więcej potrzebna.

Wstępna konfiguracja.

Wstępna konfiguracja.

Wykorzystanie kamery w robocie

W budowanym robocie wykorzystałem kamerkę dedykowaną, ale na wszelki wypadek testowałem również kamerkę podłączaną przez USB. Obie działały bez problemu, chociaż dedykowana była dużo lżejsza oraz nie zajmowała portu USB.

Po podłączeniu kamery musimy sprawdzić, czy system ją widzi. Najprościej wykonać polecenie:

Jeśli zobaczymy urządzenie /dev/video0 to znaczy, że nasza kamerka została wykryta prawidłowo. Moja kamerka USB została wykryta automatycznie, natomiast w przypadku kamerki dedykowanej, konieczne okazało się zainstalowanie modułu jądra bcm2835-v4l2:

Mając kamerę, musimy zastanowić się nad wyborem programu do jej obsługi. Możemy oczywiście napisać własny np. wykorzystując bibliotekę OpenCV, ale na początek najłatwiej jest po prostu udostępnić obraz z kamery przez WiFi.

Na szczęście nie musimy pisać odpowiedniego programu - znajdziemy w internecie gotowe rozwiązania. W pakietach dostarczanych z Raspbianem odnajdziemy program Motion. Pozwala on na udostępnienie obrazu z kamerki przez www, czyli spełnia nasze oczekiwania, jednak nie polecam go - jest strasznie zasobożerny, użycie CPU sięga 100%, a nawet na RPi 2 liczba klatek na sekundę jest zaskakująco niska - 2-3 klatki.

Instalacja mjpg-streamer

Znacznie lepiej jest wykorzystać program mjpg-streamer. Program działa znacznie szybciej na Raspberry i nie powoduje problemów z obciążeniem procesora, a liczba klatek na sekundę jest znacznie większa.

Niestety nie jest on dostępny jako gotowy pakiet (albo ja takiego nie znalazłem), konieczne jest pobranie go ręcznie. Gotową wersję, dostosowaną do Raspberry pobrać można poleceniem:

Gdy mamy już pogram musimy go skompilować. Najpierw zainstalujemy pakiety, które są do tego niezbędne:

Teraz już możemy rozpakować pobrane archiwum oraz wykonać kompilację:

Nie jestem entuzjastą kompilacji na Raspberry, ale ten projekt jest na tyle mały, że zajmuje to tylko chwilkę. Teraz możemy uruchomić nasz serwer udostępniający obraz z kamery:

Aby sprawdzić, czy wszystko działa otwieramy przeglądarkę www i wpisujemy adres IP Raspberry. Port na którym działa serwer to 8090, podaliśmy taki w linii poleceń.

W moim przypadku Raspberry Pi miało adres 192.168.1.10, więc otworzyłem w przeglądarce http://192.168.1.10:8090 zobaczyłem wtedy następującą stronę:

Zrzut ekranu 2015-10-31 o 18.07.59

Mjpg-streamer w praktyce.

Dalej musimy wybrać zakładkę Stream, ponieważ później będziemy zainteresowani samym obrazem. Oczywiście warto popatrzeć na pozostałe możliwości jakie daje mjpg-streamer.

Opcje dostępne w mjpg-streamer.

Opcje dostępne w mjpg-streamer.

Jak widzimy w podpowiedzi, obraz jest dostępny pod adresem /?action=stream. Możemy to sprawdzić wpisując w przeglądarce adres: http://192.168.1.10:8090/?action=stream

Dostęp do strumienia z obrazem.

Dostęp do strumienia z obrazem.

Sterownik silników

Kolejnym elementem bez którego nie zbudujemy robota jest układ sterowania. Do budowy prostego robota wręcz idealnie nadaje się moduł RPi Motor HAT produkowany przez firmę MSX Elektronika.

MSX_moduly_RPI_6

Moduł sterownika silników od MSX Elektronika.

Podstawowe cechy modułu to:

  • dwa popularne mostki TB6612 - datasheet
  • układ PCA9685 jako 16-kanałowy PWM - datasheet
  • 4 wolne wyjścia PWM np. do sterowania serwomechanizmami
  • przetwornica impulsowa do zasilania modułu oraz RPi

Jak widzimy, moduł pozwala nie tylko sterować silnikami, daje też możliwość zasilania całego robota. Dzięki wbudowanej przetwornicy wystarczy podłączyć akumulator, a moduł będzie zasilał własną logikę oraz płytkę Raspberry Pi.

Moduł może być też zasilany z 5V, czyli z płytki RPi - dzięki temu możemy również robota zasilać z USB. Jest to bardzo wygodne rozwiązanie podczas programowania.

Na początek powinniśmy zapoznać się ze schematem płytki oraz sterowaniem silnikami. Poniżej możemy zobaczyć jak mostek H jest połączony ze źródłem sygnału PWM:

Schemat modułu RPi HAT.

Schemat modułu RPi HAT.

Układ PCA9685 jest wyposażony w 16 wyjść PWM oznaczonych CH0-CH15. Jak widzimy wyjścia CH0, CH1, CH14 i CH15 są dostępne na złączu, więc możemy je wykorzystać do rozszerzania możliwości naszego robota, np. do sterowania serwomechanizmami.

Pozostałe wyjścia PWM są podłączone do mostków TB6612. Ciekawostką jest wykorzystanie PWM również do sterowania kierunkiem pracy mostka, czyli jako zwykłe wyjście GPIO. Jest to o tyle dobre rozwiązanie, że RPi ma mało wolnych wyprowadzeń, a w ten sposób wykorzystując i2c można sterować wszystkimi wejściami TB6612. Jako przykład zobaczmy kanał A mostka. Do jego sterowania wykorzystywane są 3 wejścia: PWM_A, IN_A1, IN_A2:

  • PWM_A - jest podłączone do wyjścia CH2
  • IN_A1 - CH4
  • IN_A2 - CH3

PWM_A odpowiada za wypełnienie PWM wyjściwowego sygnału (a więc prędkość obrotową silnika). Linie IN_A1 oraz IN_A2 ustalają kierunek obrotów silnika, są zwykłymi liniami GPIO.

Program w Pythonie

Wykorzystamy Pythona. Programowanie w nim jest bardzo łatwe, a programy nie muszą być kompilowane, co ułatwia tworzenie programu, pozwala też na łatwe eksperymentowanie. Programować można zdalnie logując się przez ssh do Raspberry.

Nie bez znaczenia jest również gotowa biblioteka obsługująca PCA9685. Jej kod znajdziemy tutaj. Sterownik PCA9685 znajdziemy w pliku Adafruit_PWM_Servo_Driver.py.

Pierwszy krok to sprawdzenie, czy i2c działa. Wykorzystamy do tego program i2cdetect, który znajdziemy w pakiecie i2c-tools (jeśli go nie zainstalowaliśmy, najwyższy czas to zrobić).

Aby sprawdzić, czy mamy działający interfejs i2c piszemy:

Jeśli zobaczymy coś w rodzaju: /dev/i2c-1, oznacza to, że mamy interfejs i2c gotowy do działania. Brak interfejsu może wynikać z braku odpowiedniego modułu. Aby go załadować musimy wydać komendę:

Teraz powinniśmy i2c odnaleźć bez problemu. Wygodniej jest automatycznie ładować odpowiedni moduł, bez konieczności wydawania polecenia modprobe. Aby moduł był ładowany podczas startu systemu, możemy dodać odpowiedni wpis do pliku /etc/modules:

Interfejs jest gotowy, możemy sprawdzić, czy Raspberry jest w stanie wykryć płytkę sterownika. Wydajemy polecenie i2cdetect 1

Jak widzimy, moduł jest dostępny pod adresem 60 (hexadecymalnie). Czas napisać prosty skrypt w Pythonie, który uruchomi silnik. Napierw zobaczmy kod, później omówimy jego treść:

Pierwsze, co rzuca się w oczy, to mała ilość linijek programu. Tylko 5 + jedna od importu biblioteki.

W pierwszej linijce importujemy klasę PWM z biblioteki Adafruit_PWM_Servo_Driver. Klasa ta odpowiada za obsługę układu PCA9685, w który jest wyposażony nasz moduł. Kolejna linijka to utworzenie obiektu klasy PWM. Jako parametr podajemy adres układu - odczytaliśmy go wcześniej, więc podajemy 0x60. Następnie ustalamy częstotliwość pracy - 1kHz.

Ostatnie 3 linijki to właściwe sterowanie silnikiem. Najpierw ustawiamy wypełnienie PWM. Podajemy 1000 jako przykładową wartość - zakres jest od 0 do 4095, powinniśmy więc uzyskać ok. 25% wypełnienia. Następnie ustalamy kierunek pracy silnika. Podanie jako wypełnienia wartości (0, 0) daje wypełnienie 0%, więc na linii CH4 uzyskamy stan niski.

Aby uzyskać ciągły stan wysoki musimy zamienić kolejność parametrów i podajemy (4096, 0). W ten sposób na wyjściu CH3 uzyskamy stały stan wysoki.

Rozwijanie programu

Gdy wiemy jak sterować silnikiem możemy napisać skrypt, za pomocą którego będziemy mogli sterować całym robotem. Skrypt będzie uruchamiany z dwoma parametrami, każdy z zakresu od -4095, do 4095. Pierwszy parametr będzie ustalał kierunek i prędkość lewego silnika, a drugi prawego. Kod programu:

Program zawiera sporo powtórzeń, można więc go trochę udoskonalić. Po pierwsze wypadałoby zebrać definicje kanałów PWM do stałych (albo chociaż zmiennych). Po drugie sterowanie lewym i prawym silnikiem jest prawie identyczne, lepiej byłoby więc nie duplikować kodu.

Poniżej znacznie krótsza wersja (chociaż nie wiem czy czytelniejsza):

Mając ten program możemy zdalnie sterować robotem z poziomu konsoli:

Sterowanie silnikami z konsoli.

Sterowanie silnikami z konsoli.

W tym momencie moglibyśmy podłączyć czujniki i rozwinąć skrypt o autonomiczną pracę naszego robota. Możemy też popracować nad zdalnym sterowaniem obecnej platformy.

Sterowanie robotem z przeglądarki

Używanie konsoli nie jest najwygodniejszą opcją do sterowania robotem. Może też być uciążliwe, gdybyśmy chcieli sterować robotem przykładowo przez smartfon lub tablet. Zamiast tego spróbujemy sterować robotem z poziomu przeglądarki.

Skoro zaczęliśmy programować w Pythonie, możemy wykorzystać serwer www oparty o ten język. Ja wybrałem projekt bottle - na stronie projektu znajdziemy dokumentację oraz poradnik użycia.

Postaram się pokazać jak łatwo jest w Pytonie stworzyć prostą aplikację webową (sterującą robotem). Najpierw piszemy bardzo prosty skrypt (podobny do przykładu ze strony Bottle):

Ostatnia linijka to uruchomienie serwera na podanym adresie i porcie. Znacznik @route określa ścieżkę, pod którą będzie dostępna nasza aplikacja. Fragment w nawiasach oznacza parametr (speed, typu int). Nasza aplikacja będzie więc dostępna pod adresem:

http://192.168.1.10:8080/robocik/left/1000

Gdzie 1000 to przykładowa wartość parametru. Program jako odpowiedź wyśle napis przekazany do funkcji template. Rezultat wygląda następująco:

Sterowanie robotem z poziomu przeglądarki.

Sterowanie robotem z poziomu przeglądarki.

Funkcja index(speed) jest wywoływana za każdym razem, kiedy otwieramy podany wcześniej adres. Możemy w niej wysterować silnik - wcześniej już napisaliśmy odpowiednie funkcje. Nowy skrypt wygląda więc następująco:

Tak krótki skrypt wystarczy do sterowania silnikiem przez przeglądarkę internetową. Pozostaje jeszcze dodać sterowanie prawym silnikiem oraz dodać stronę główną, tak żeby nie było konieczności wchodzenia ręcznie na strony /left i /right.

Nasz skrypt jest już gotowy, jednak jeśli spróbujemy otworzyć adres strony głównej sterowania robotem, czyli http://192.168.1.10:8080/robocik/ pojawi się błąd - brakuje szablonu index.

Okazuje się, że funkcja template() może przyjmować dwa rodzaje parametrów: kod HTML, który zostanie bezpośrednio przekazany do przeglądarki, albo nazwę pliku z szablonem strony. Pliki szablonów powinny być przechowywane w podkatalogu views i mieć rozszerzenie .tpl. Jednak są to w rzeczywistości zwykłe pliki HTML. Możemy taki plik utworzyć, a w nim umieścić kod, który będziemy chcieli wyświetlać w przeglądarce:

Końcowy efekt - przesuwając suwaczki zmieniamy prędkość poszczególnych silników:

Sterowanie robotem z poziomu przeglądarki.

Sterowanie robotem z poziomu przeglądarki.

Podsumowanie

Opisywany robot powstał przy okazji recenzowania modułów firmy MSX. Nie jest to w pełni ukończony projekt, raczej wstępny opis który można dalej rozbudować. Bez odpowiednich czujników nazywanie tej konstrukcji robotem jest niewątpliwie pewnym nadużyciem - w sumie jest to zdalnie sterowany pojazd wykorzystujący Raspberry Pi jako kontroler.

Aby zmienić go w prawdziwego robota, należałoby podłączyć czujniki lub dodać przetwarzanie obrazu. Jednak powyższy opis miał na celu pokazanie jak łatwo można przygotować zdalnie sterowaną platformę przy wykorzystaniu modułu RPi Motor HAT, Raspberry Pi oraz języka Python. Mam nadzieję, że pomysły w nim opisane przydadzą się innym osobom w ich konstrukcjach.

Dajcie znać w komentarzach, jeśli jesteście zainteresowani podobną tematyką!

Autor: Piotr (Elvis) Bugalski
Redakcja: Damian (Treker) Szymański

druk 3d, kamera, Raspberry PI, robot

Trwa ładowanie komentarzy...