W świecie płytek typu Arduino, łatwo jest realizować pojedyncze doświadczenia. Mruganie diodami, kilkakrotne obrócenie serwem, bipniecie buzzerem – do podstawowych eksperymentów wystarczy garść kabelków połączeniowych i kilka linijek kodu.
„Schody” zaczynają się, gdy chcemy zrealizować jakieś konkretne zadanie, która wymaga połączenia kilku bloków funkcjonalnych. Wtedy wychodzą na jaw problemy z zasilaniem, dogadywaniem się niektórych elementów, poziomami logiki, niewystarczającą liczbą pinów oraz „hackami” w bibliotekach.
Dlatego właśnie postanowiłem sprawdzić klona Digisparka w warunkach bojowych.
Cel…
…skonstruowanie małego i taniego robota mobilnego, na częściach popularnie dostępnych na rynku. 3-punktowe podwozie, 2 silniki elektryczne (lub serwa 360), zasilany z baterii, zdalne sterowanie za pomocą pilota na podczerwień. Szkielet kombinowany z czego popadnie – głównie metalowe klocki konstrukcyjne i lego.
Jednostka centralna…
Będziecie potrzebować:
- Digispark z bootloaderem micronucleus
- Kabel microusb do programowania
…klon Digisparka. Mimo wielu problemów, jakie niesie ze sobą to urządzonko, myślę że zadziała.
Już wiem, że połączenie USB jest raczej kapryśne. Czasami przeprogramowanie układu wymaga kilkukrotnego włożenia-wyciągniecia z portu USB komputera. Aktywny hub niewiele tu pomaga.
Szkice czasem tylko udają, że się ładują, bootloaderowi zdarza się zniknąć a piny nie zawsze działają zgodnie ze swoim przeznaczeniem… Brzmi jak wyzwanie, nieprawdaż?
Środowisko programowania…
Będziecie potrzebować:
- Arduino IDE z zainstalowanym wsparciem dla Digispark (pod Windows lub Linux)
…Arduino IDE 1.5.8 dla linux 64-bit (MINT 17.3), zmodyfikowane dla Digisparka. Dlaczego to? Digispark, którego używam do tego projektu, swego czasu się zbuntował i konieczne było przeflaszowanie bootloadera (zobacz; Digispark i micronucleus: crach). Niestety okazało się, że najnowsze Arduino IDE (1.6.6) pobrane ze strony arduino.cc, rozszerzone o wsparcie dla Digispark (zobacz: Digispark: jak zacząć pod Windows), nie obsługuje wersji micronucleus 2.+ – akurat tej, która jest dostępna na githubie Digistump. Użyłem więc starszej wersji środowiska, udostępnianej przez Digispark.
Dodatkowe narzędzia…
W trakcie rozwijania i testowania przydadzą się:
- Konwerter UART2USB (+Putty na hoście), z kablem USB
- Programator ISP, np. USBASP2
- Analizator logiczny
- Oscyloskop
- Multimetr
Niestety, z Digisparkiem nie zawsze wszystko idzie zgodnie z planem. Oczywiście idealną pomocą jest oscyloskop – ale to dość kosztowna „zabawka”. Alternatywnie polecam np. analizator logiczny. Podstawowe modele można kupić za bardzo rozsądne pieniądze.
Dodatkowo przyda się przejściówka USB2UART. Dzięki niej będziecie mogli użyć biblioteki SoftSerial do przesyłania logów z Digisparka. Więcej dowiecie się tutaj: Digispark: port szeregowy UART.
Budowa
Będziecie potrzebować:
- Materiały do konstrukcji podwozia – kółka, klocki konstrukcyjne, lego
- Płytkę stykową, do osadzenia wszystkich elementów
- Pojemnik na baterie
- Paski plastykowe do spinania elementów (tralki)
- Recepturki, taśmę klejącą dwustronną

Swoje roboty najczęściej buduję z metalowych klocków konstrukcyjnych. Swego czasu byłem nawet w ich muzeum w Police nad Metui – niektórzy czytelnicy na pewno kojarzą firmę Merkur. Ale i w Polsce mamy ciekawych producentów – np. firmę Alexander i jej serię Mały Konstruktor. Na podstawie ich kompletu raz zbudowałem całkiem fajną ciężarówkę:
Oczywiście bardzo lubię też lego – które łatwo łączą się z np. serwami.
Do konstruowania robotów często wykorzystuję tzw. drewo cytrusowe. Pochodzi ze… skrzynek na owoce wyproszonych z okolicznego warzywniaka. Część z nich jest zrobiona ze zwykłej dykty, ale niektóre z 3mm sklejki – bardzo lekkiej i łatwej w obróbce (wystarczy nóż segmentowy).
Do montażu stosuję też paski plastykowe (tzw. tralki), dwustronną taśmę klejącą, recepturki – co tam podpadnie pod rękę.
Silniki
Będziecie potrzebować:
- Silniki albo serwa 360 zasilane na 4-6V
- Najlepiej takie wyposażone w przekładnie – 100obr/min to już dość rozsądna szybkość.
Do napędu mojego robocika planowałem użyć tanich silników RF-300A. Oryginalnie wykorzystywane są w napędach CD/DVD. Można je zasilać napięciem 3-6V. Na biegu jałowym zużywają 22mA, a przy zatrzymaniu wału maksymalnie 390mA.

Właściwie to kupiłem je głównie dlatego, że były tanie (ok. 5PLN/szt). Niestety okazały się za słabe. Przy ciężarze 4-rech baterii AA, 2 silniki mogły uciągnąć prototyp tylko na pełnej mocy, jedynie na wprost i po kafelkach – o jeździe po dywanie czy skręcaniu jednym silnikiem nie było mowy.
Generalnie skręcanie silnikami bez-przekładniowymi jest dość dyskusyjne.
Inną opcja mogą być mini-silniczki z przekładniami, np. polulu. To świetne rozwiązanie. Takie napędy są naprawdę bardzo trwałe i dają niesamowity ciąg. Niestety… kosztują konkretne pieniądze.
Tutaj zastosowałem 2 serwa 360st. Dokładniej są to zmodyfikowane Redoxy s90. Ze względu na sposób wykonania modyfikacji, steruje się nimi jak zwykłymi silnikami kluczując zasilanie sygnałem PWM.
Przerobienie „normalnego” serwa na 360 nie jest takie trudne: modyfikacja serwa towrprosg90 na 360st.
Serwa przymocowałem do kasty za pomocą 2 tralek. Użyłem też kółek lego – łatwo je przymocować do krzyżakowych orczyków serwa.
Sterowanie silnikami: tranzystory
Będziecie potrzebować:
- Tranzystory NPN, np. TIP122
- Rezystory bazowe – w zależności od silników i tranzystorów
Z każdego z serw wychodzą 2 kabelki. Jeżeli podłączymy je po prostu do + i masy zasilania – nie będziemy mieli żadnej możliwości sterowania nimi. Oczywiście nie możemy też podłączyć kabelków bezpośrednio do AtTiny85 – pobór prądu z silników by je usmażył.
Dlatego podłączymy je inaczej: jeden kabelek silniczka do „+” zasilania, a drugi – przez tranzystor do masy. Podłączając kabelek od silnika do kolektora tranzystora, którego emiter łączymy z masą, będziemy mogli sterować przepływem prądu przez silnik. Tranzystor w stanie nasycenia, sterowany przez sygnał PWM podawany na bazę, będzie zachowywał się jak przełącznik. Włączając i wyłączając prąd (zgodnie z sygnałem PWM), będziemy sterować szybkością obrotową silników.
Pozostaje wybrać tranzystor. Kilka NPN znalazłem w szufladzie:
Zacznijmy od Ic – maksymalnego prądu, jako może przepłynąć przez złącze kolektor-emiter. Zablokowane serwo pobierze nawet 500mA. Ic dla 2n2222 to 600mA – trochę za blisko granicy. TIP122 to 5A (wow!). bc547 – tylko 100mA, więc odpada ze stawki. bd139 ma Ic na poziomie 1.5A – też się nada.
Teraz sprawdzimy jaki prąd Ib musi popłynąć przez złącze baza-emiter, żeby tranzystor się nasycił. W przypadku bd139:

Widać to, że:
Czyli, żeby wygenerować 500mA, potrzebowalibyśmy prądu bazy 50mA. To znacząco za dużo dla AtTiny.
W instrukcji do TIP122 znajdziecie wykres 2.

Widać na nim, że:
Stąd dla 500mA, minimalny prąd bazy to 2mA. AtTiny wyrobi się bez problemu.
Z powyższego wykresu widać jeszcze jedno: napięcie Vbe nasycenia dla prądu 0.5A to ok. 1.4V. Informacja ta będzie nam potrzebna do wyznaczenia rezystora bazy . Skoro zasilanie bazy będzie 5V, na złączu baza-emitor spadek wyniesie 1.4V, spadek napięcia na rezystorze musi wynieść 3.6V. Stąd:
Rezystor 1750Ω powinien dać radę – ja użyję mniejszego (1kΩ), który da większy prąd bazy gwarantując nasycenie.

Podłączenie:
Tranzystory zamontowałem na płytce stykowej i podłączyłem do Digispark’a:

Zauważcie, że bazy tranzystorów podłączyłem do pinów P1 i P4 Digisparka.
Oczywiście w ten sposób będę mógł jedynie włączać/wyłączać silniki oraz regulować ich szybkością obracania się tylko w jedną stronę. Możliwość odwracania biegu dają dopiero układy takie jak L293D.
Zasilanie
Będziecie potrzebować:
- Baterii lub akumulatorów – np. 4xAA, 2×14500
- Pudełka na akumulatory/baterie – najlepiej z wyłącznikiem
- LM78S05 (jeżeli napięcie akumulatorów, baterii > 6v)
- Jeżeli LM78S05: kondensatorów 0.33uF i 0.1uF (330 i 100 nF, oznaczenia 334 i 104)
- Kabelki połączeniowe – męsko-męskie i męsko-żeńskie
Serwa wymagają zasilania ok. 4-6V. Z początku planowałem użyć pojemnika z 4-ma bateriami AA. Niestety baterie te – choć łatwo dostępne, dość dużo ważą. Postanowiłem zamienić je na 2 akumulatory z serii 14500. To bardzo ciekawe ogniwa. Mają rozmiar paluszków AA – a każda daje napięcie ok. 3.7 (naładowane nawet 4.3). Wystarczą więc tylko 2 połączone szeregowo.

Nie ma jednak nic za darmo: naładowane akumulatory dają razem nawet ponad 8 woltów. Taki poziom napięcia mógłby uszkodzić napędy. Potrzebny jest więc dodatkowy stabilizator. Prosty LM78S05 powinien wystarczyć. Daje 5V na wyjściu przy maksymalnym prądzie 2A. Koszt ok. 1,5 PLN.

Model „s” może przewodzić 2x więcej prądu od wersji 7805. Wydawało mi się to bezpiecznym marginesem.
W jaki sposób podłączyć ten stabilizator? Instrukcja podaje tak:
Nie miałem pod ręką kondensatora 330nF – użyłem 220nF – też powinien być ok. Podłączyłem wszystko na płytce stykowej:
Odpowiednie umieszczenie pudełka z bateriami umożliwia też użycie jego przełącznika do włączania/wyłączania robota:
Zdalne sterowanie
Będziecie potrzebować:
- Pilota na podczerwień
- Diodę IR odbiorczą, np. TSSOP2238,
- Kondensator elektrolityczny ok. 4.7uF, podłączony między Vcc i GND
Do zdalnego sterowania robotem użyłem podczerwieni: zestawu pilot – dioda odbiorcza IR. Raczej nie próbujcie walczyć z diodą IR bez kondensatora między zasilaniem a masą. Będziecie dostawać przedziwne wyniki. Kolejne wciśnięcia tego samego klawisza będą dawać inne kody.
Podłączenie jest bardzo proste:

Zasilanie Vcc podłączom do 5V (wyjście z 78S05), masę do masy, a pin OUT do P2 Digisparka.
Jeżeli chodzi o samego pilota – chwyciłem co leżało pod ręką – akurat zgrabny pilot od radiomagnetofonu sony.
W przypadku tego czujnika, bardziej skomplikowane jest samo oprogramowanie. Najpierw do nowego projektu dodajcie bibliotekę: DigisparkIrLib. W kodzie pojawią się dodatkowe nagłówki:
#include <IRLibTimer.h> #include <IRLibMatch.h> #include <IRLib.h> ...
Biblioteka DigisparkIrLib wymaga drobnej modyfikacji. Odnajdźcie plik w katalogu Arduino IDE: ./hardware/digistump/avr/libraries/DigisparkIRLib/IRLib.h i zmieńcie linijkę:
#define MY_IR_PROTOCOL ...
Tak, żeby określała rodzaj Waszego pilota; u mnie:
#define MY_IR_PROTOCOL PROTO_SONY
Najczęściej:
#define MY_IR_PROTOCOL PROTO_NEC
Takim protokołem posługuje się np. pilot keyes:

Dekoder przetworzy tylko sygnały z protokołu, który wybierzecie; tzn. jeżeli podacie:
#define MY_IR_PROTOCOL PROTO_SONY
…biblioteka zdekoduje sygnały z pilota sony, ale nie keyes’a (który posługuje się protokołem nec’a). Generalnie możnaby włączyć wszystkie znane protokoły:
#define MY_IR_PROTOCOL ALL_IR_PROTOCOL
…ale wtedy kod rozrośnie się tak, że nie zmieści się w AtTiny.
Biblioteka DigisparkIrLib wczytuje sygnał ze wskazanej linii IR i umieszcza go buforze. Bufor ten przetwarza dekoder. Dekoder używa MY_IR_PROTOCOL
żeby poprawnie zinterpretować zawartość bufora. W przypadku poprawnego rozpoznania, dostaniecie liczbę (typu long), inną dla każdego przyciśniętego klawisza.
Teraz będziecie musieli określić, jakie kody generują się po wciśnięciu klawiszy na pilocie. Pomoże Wam taki program:
#include <IRLibTimer.h> #include <IRLibMatch.h> #include <IRLib.h> #include <SoftSerial.h> #include <TinyPinChange.h> //On basis of Digistump examples //IR output connected to P2 #define IR_PIN 2 IRrecv My_Receiver(IR_PIN); IRdecode My_Decoder; //Softserial connectected to 0,1 (RX, TX) SoftSerial sserial(0,1); void setup() { sserial.begin(9600); My_Receiver.enableIRIn(); } void loop() { if (My_Receiver.GetResults(&amp;My_Decoder)) { //decode received rawBuffer My_Decoder.decode(); //make sure you only look at your type of remote control if ( My_Decoder.decode_type == PROTO_SONY ) { sserial.print( My_Decoder.value ); sserial.println(); } My_Receiver.resume(); } }
Podłączcie RX przejściówki USB2UART do pinu P1 i wciskajcie przyciski na pilocie – na konsoli hosta zobaczycie kolejne kody klawiszy.
Oprogramowanie
Oprogramowanie jest niezbyt skomplikowane. Oprócz DigisparkIrLib, sketch wymaga dodania biblioteki DigisparkTinySoftPwm.
Znając kody klawiszy, sam program nie jest już zbyt trudny:
#include <TinySoftPwm.h> #include <IRLibTimer.h> #include <IRLibMatch.h> #include <IRLib.h> //Define pins #define PIN_LEFT 4 #define PIN_RIGHT 1 #define IR_PIN 2 //Define PWMs #define ENGINE_STOP 0 #define ENGINE_MAX 255 #define SPEED_STEP 5 //Variables controlling PWM for each engine int speedMeL = ENGINE_STOP; int speedMeR = ENGINE_STOP; //IR instance IRrecv My_Receiver(IR_PIN); IRdecode My_Decoder; void setup() { My_Receiver.enableIRIn(); pinMode(PIN_LEFT, OUTPUT); pinMode(PIN_RIGHT, OUTPUT); TinySoftPwm_begin(128, 0); } void loop() { //Taken from TinySoftPWMDemo: process PWM timers static uint32_t StartUs = micros(); if ((micros() - StartUs) &amp;amp;gt;= 60) { StartUs = micros(); TinySoftPwm_process(); } //Get results from decoder if (My_Receiver.GetResults(&amp;amp;amp;My_Decoder)) { //decode received rawBuffer My_Decoder.decode(); //make sure you only look at your type of remote control if ( My_Decoder.decode_type == PROTO_SONY ) { int key_value = My_Decoder.value; switch (key_value) { case 21538://operate button break; case 28962://function button break; case 31526://band button break; case 26150://play button speedMeL = ENGINE_MAX; speedMeR = ENGINE_MAX; break; case 3622://stop button speedMeL = ENGINE_STOP; speedMeR = ENGINE_STOP; break; case 24870://left button speedMeL = ENGINE_MAX; speedMeR = ENGINE_STOP; break; case 4390://right button speedMeL = ENGINE_STOP; speedMeR = ENGINE_MAX; break; case 9250://volup button speedMeL += SPEED_STEP; speedMeR += SPEED_STEP; break; case 25634://voldown button speedMeL -= SPEED_STEP; speedMeR -= SPEED_STEP; break; } if (speedMeL < ENGINE_STOP )speedMeL = ENGINE_STOP; if (speedMeR < ENGINE_STOP )speedMeR = ENGINE_STOP; if (speedMeL > ENGINE_MAX )speedMeL = ENGINE_MAX; if (speedMeR > ENGINE_MAX )speedMeR = ENGINE_MAX; TinySoftPwm_analogWrite(PIN_LEFT, speedMeL); TinySoftPwm_analogWrite(PIN_RIGHT, speedMeR); } //Make receiver listen to a next code My_Receiver.resume(); } }
Biblioteka IR wczytuje i dekoduje kody z pinu P2. Jeżeli wciśnięto klawisz play na pilocie, na P1 i P4 generowany jest sygnał PWM, który uruchamia silniki. Wciśnięcie stop je zatrzymuje. W przypadku skręcania – zatrzymuję jeden silnik i kręcę drugim.
To oczywiście bardzo prosty algorytm – możecie go ulepszyć!
Efekty
Tak jeździ:
I kilka fotek:
Podsumowanie
No i udało się: robot reaguje na pilota, jeździ po dywanie – od biedy można by dołączyć do niego jeszcze kilka detali.
Podczas całej budowy okazało się, że największym problemem są… biblioteki. A dokładniej ich niepełna – i raczej nastawiona na programistów, niż użytkowników – dokumentacja. Trochę trzeba się naczytać kodu, żeby dowiedzieć się, że IR używa dodatkowego timera – blokując w ten sposób pin P0.
Sam Digispark też nie pomaga – pin P3 jest uruchamiany przez bootloader szukający hosta. Jeżeli podłączycie do P3 silnik – przy starcie czipu zacznie on działać… P5 to reset – podanie na niego stanu niskiego, spowoduje zresetowanie Digisparka. Właściwości te opiszę w kolejnych tekstach z serii.
gdy nie chce Wam wgrywać programu na DigiSpark’a (mimo, że program się kompiluje) spróbujcie go podłączać przez jakikolwiek hub USB