Samochodzik, czyli jak wykorzystać modem Xbee.
Jakiś czas temu wpadłem na pomysł budowy quadrocoptera. Jednak, że nie od razu Rzym zbudowano, stwierdziłem, że zacznę od skonstruowania czegoś mniejszego, tańszego i bezpieczniejszego, czegoś na czym mógłbym spokojnie testować zdalne sterowanie. Tak oto urodziła się idea trójkołowego samochodzika.
Od czego zacząć
Konstrukcja nie powala, po prostu wyciąłem z kartonu prostokąt o wymiarach 10×20 i doczepiłem do niego zaciskami dwa sześciowoltowe silniczki.
Jego sercem i rozumem jest Arduino UNO z nałożonym Motor Shieldem. W zasadzie w tak prostym modelu można pominąć ów shield, gdyby założyć, że nie będziemy korzystać z biegu wstecznego i sterować silnikami za pomocą PWM,, ale akurat miałem go pod ręką i grzechem byłoby tego nie wykorzystać ;) Poza tym wykorzystałem dwa modemy Xbee S2 oraz, znaleziony na dnie szafy, joystick analogowy, który z powodzeniem można zastąpić Joystick Shield Kitem. Wykorzystanie go ma tą zaletę, że oszczędzi Wam wiele pracy i zmniejszy ilość walających się kabli.
Rozbieranie joysticka
Josticki analogowe to tak naprawdę dwa potencjometry, ustawione prostopadle do siebie. Jeden odpowiada za odchylenie w osi OX, drugi w osi OY. Wychylenie drążka powoduje zmianę rezystancji tych potencjometrów, zwykle mają one rezystancje od około 0 do 100k Ohm.
Specjalnie na potrzeby padów, joysticków, etc. w komputerach pojawiły się GamePorty. Jak sami pewnie się domyślacie, najpierw musiałem dojść do tego który przewód za co odpowiada. Odciąłem wtyczkę od kabla i posiłkując się opisem pinów z wikipedii stwierdziłem, że widoczny na zdjęciu przewód pomarańczowy odpowiada za oś OX, a brązowy – OY. Dlatego polecam wykorzystanie shielda – oszczędzicie sobie pracy. Kolejnym problemem był sam odczyt spadku napięcia na potencjometrze. Niestety, nie mogłem mierzyć go bezpośrednio. Dlatego też wykorzystałem opisany TU dzielnik napięcia, tak samo jak tam wykorzystałem rezystor 10k i mierzyłem spadek napięcia zamiast na joysticku – na ów rezystorze. To z kolei spowodowało, że napięcie nie zmieniało się liniowo, lecz hiperbolicznie – w związku z tym ustawiłem cztery możliwe wychylenia (zero/lekko/średnio/mocno) i zbadałem napięcia dla tych wychyleń. W ten sposób ustaliłem, że dla odczytu poniżej 190 (190*5/1023 = 0.92 V) drążek jest wychylony do przodu, dla odczytu powyżej 240 (1,17V) drążek odchylony jest do tyłu, itd.
Skoro już mamy czym sterować…
Przyszedł czas na zastanowienie się jak przekazywać polecenia do Arduino na pokładzie samochodzika. Po podłączeniu (RX do DOUT, TX do DIN) i skonfigurowaniu Xbee wedle tutorialu, nadszedł etap na napisanie programu. Dzięki blogowi Sprae, który w bardzo czytelny sposób tłumaczy tajniki wysyłania struktur, w bólach powstały dwa programy, nadawaczy i odbiorczy (linki na końcu postu):
Jak sami pewnie zauważycie, są to w zasadzie odpowiednio przerobione programy zamieszczone na blogu Sprae, nie wynajdywałem koła od nowa ;) On też tłumaczy tam w bardzo dobry sposób jak działa proces wysyłania i odczytywania poszczególnych bitów. W związku z tym objaśnię w tym poście tylko wybrane fragmenty kodu. Aha, ważna sprawa: program odbiorczy nie chce się kompilować (przynajmniej u mnie) w Arduino IDE 1.0.1 ! Do wgrania programu na Uno wykorzystałem IDE 0.22.
int Speed[] = {0, 100, 175, 255}; int currentSpeed; int currentForce;
Tutaj deklaruję zmienne pomocnicze, które wykorzystam w dalszych częściach kodu.
struct paczka { int dir; int vel; /*velocity*/ int turn; int force; } pack;
Oto struktura, przechowująca odczyt wychylenia joysticka, która zostanie wysłana do pojazdu. Pole:
- ” dir” odpowiada za kierunek (255 – przód, 0 – tył)
- „vel” odpowiada za prędkośc (0 – zero/100 – mała/175 – pół/255 – cała)
- „turn” to kierunek skrętu, czyli czy skręcamy w lewo czy w prawo (0 – nie skręcamy/125 – lewo/255 – prawo)
- „force” to siła z jaką skręcamy (0/100/175/255), a dokładniej jaki jest stosunek wypełnienia PWM sterującego jednym kołem, do wypełnienia PWM odpowiadającego z drugie koło
Całą strukturę zbudowałem w oparciu o wartości typu „int”, gdyż miałem pewne problemy w przesyłaniu do struktury znaków i tablic znaków („char”). Równie dobrze zamiast 225 oznaczającego kierunek w przód, mogłoby być tam np. 5, to są tylko przyjęte przeze mnie oznaczenia. Oznaczenia to tylko umowa. A propos umów i oznaczeń, który wzór na moc czynną jest poprawny?
Odpowiedź na dole strony.
if(NAPY <190) /*forward*/ { if(NAPY >= 150 && NAPY < 190) { currentSpeed = Speed[1]; } else if(NAPY >=100 && NAPY < 150) { currentSpeed = Speed[2]; } else { currentSpeed = Speed[3]; } pack.dir = 255; pack.vel = currentSpeed; }
Ten fragment kodu odpowiada założeniu o który pisałem w poprzednim akapicie. Dla odczytu poniżej 190 (0.92 V) program zapisuje w polu struktury odpowiadającej za kierunek wartość „255”, a następnie sprawdza jak bardzo wychylony jest joystick. Im mniejsze jest zmierzone napięcie tym większa jest wartość wychylenia. Kolejne przedziały są przyporządkowane wartościom z kolejnych komórek pomocniczej tablicy.
Wybrane fragmenty programu odbiorczego:
Deklaracja zmiennych oraz bibliotek.
#include <MotorShield.h> #include <EEPROM.h> MS_DCMotor right(MOTOR_A); MS_DCMotor left(MOTOR_B); int Speed[] = {0, 100, 175, 255}; int currentSpeed;
Biblioteka EEPROM nie jest konieczna do działania samochodzika, w sumie spokojnie można powiedzieć, że jest zbędna ;). Po prostu w czasie tworzenia programu chciałem sprawdzić jak działa przesyłanie danych między XBEE, a najprostsze było napisanie funkcji, opisanej poniżej, zapisującej odebrane dane w pamięci EEPROM.
void pack_save(struct paczka *pack, unsigned int address) { byte *data = (byte *) pack; unsigned int size = sizeof(paczka); for (unsigned int i=0; i<size; i++) { EEPROM.write(address+i, data[i]); } }
W ten sposób mogłem sprawdzić co zostało odebrane. Jeśli chcecie sami sprawdzić co odbiera Wasze Xbee usuńcie symbole „/*” oraz „*/”. Wszystko co jest pomiędzy nimi, w języku C, oznacza komentarz i jest pomijane przez kompilator. Ponieważ prędkość zapisu do pamięci EEPROM jest relatywnie niska, należy zwiększyć opóźnienie w wykonaniu następnej pętli programu (delay). Z doświadczenia wiem, że przy zapisywaniu odebranych danych i opóźnieniu rzędu 10~30 ms, Arduino wiesza się po paru cyklach. Pamiętajcie też, że trwałość pamięci EEPROM jest obliczona na ok 100000 cykli zapisu i odczytu, więc korzystajcie z niej rozważnie.
void rotator_controller(struct paczka pack) { if(pack.dir == 255) { right.run(RELEASE); left.run(RELEASE); right.run(FORWARD); left.run(FORWARD); right.setSpeed(pack.vel); left.setSpeed(pack.vel); } if(pack.dir == 0) { right.run(RELEASE); left.run(RELEASE); right.run(BACKWARD); left.run(BACKWARD); right.setSpeed(pack.vel); left.setSpeed(pack.vel); } if(pack.dir == 125) { right.run(BRAKE); left.run(BRAKE); right.setSpeed(Speed[0]); left.setSpeed(Speed[0]); }
Tak jak widać, jeśli „pack.dir” odpowiadające kierunkowi ma odpowiednią wartość, w tym przypadku, „255” pojazd jedzie do przodu. Na tej samej zasadzie dla „0” będzie jechał do tyłu, a dla „125” zostanie włączony hamulec.
if(pack.turn == 125) /*left*/ { right.setSpeed(pack.vel); if(pack.force == 100) left.setSpeed(pack.vel/1.5); if(pack.force == 175) left.setSpeed(pack.vel/2); if(pack.force == 255) left.setSpeed(pack.vel/3); }
Tak jak napisałem wcześniej, skręcanie polega tu na różnicy wypełnienia PWM sterującego jednym kołem, a drugim. Dzięki temu promień skrętu jest niewielki, a gdyby zmienić odrobinę kod, tak by dla maksymalnego wychylenia koła obracały się w przeciwnych kierunkach, samochodzik będzie się obracał w miejscu. Jak czołg, który zajmuje zaszczytne miejsce na liście „TO DO”.
W zasadzie już wszystko mamy
Do sterowania silnikami wykorzystałem, ze względu na wygodę MotorShielda oraz napisaną do nie go bibliotekę. Biblioteka znakomicie upraszcza cały program, a poza tym zauważyłem ciekawą zależność. Przy własnoręcznie napisanym programie obsługującym silniki wyły nieludzko, z kolei przy tej bibliotece pracują w miarę cicho. W ten sposób można sterować np tym robotem.
Efekty pracy:
Odpowiedź do pytania:
Oba są poprawne. Wszystko zależy od umowy, od tego jakie oznaczenia się przyjmuje. Przykładowo, na wydziale Elektrycznym mojej Alma Mater obowiązuje wzór pierwszy, z kolei na wydziale Elektroniki, stosuje się drugi wzór bo operują oni wielkościami amplitudy sygnału, a do liczenia mocy wykorzystuje się wartość skuteczną. A wartość skuteczna, dla sygnału przemiennego, jest opisywana wzorem:
Programy nadawcze i odbiorcze
Użyte elementy:
Ten samochodzik zbudowany został z następujących elementów z oferty Nettigo:
Widzę, że wpadliśmy na podobny pomysł, ja stosuję teraz eksperymenty z pojazdem jako wprawkę przed heksakopterem. Swój bazowałem na rozbebeszonym zdalnie sterowanym aucie, z którego zostały tylko rama, koła i silniki. Za to do sterowania zamówiłem wii nunchucka i mogę go zdecydowanie polecić, jest do tego świetna biblioteka a i sterowanie może być albo przez obracanie manipulatora albo joystickiem na szczycie.
Pomysł z użyciem Wii do sterowania brzmi fajnie, jak możesz to wrzuć efekty swoich działań na facebookowy fanpage. Bardzo możliwe, że natchniesz tym kogoś do działania ;) Bardzo możliwe, że w pewnym momencie przerzucę się na Twój patent, bo joystick, przez swoją nieliniowość, może stać się niewystarczający. Ale najpierw muszę uruchomić quadrę ;p Życzę powodzenia i mało kłopotów z projektem ;)
w cenie 2 xbee można dostać już ciekawą aparaturę RC
Co do multirotorów, lepiej poświęcić sporo czasu na wgryzanie się w dostępne już oprogramowanie aniżeli odkrywać świat na nowo :) Polecam multiwii – programuje się w arduino
Chętnie się temu przyjrzę ;) Sam myślałem o zastosowaniu MPU6050, właśnie ze względu na dostępne biblioteki ;)
Ładne fajne i proste. Ale potrzeba mi prądu – i dobrych silników z dużym A.
ja: Użyj tranzysorów MOSFET :)
@ Sebastian
Już dałem post z moim dronem na FB Nettigo, poszukaj :)
Aktualnie kończę pracę nad autonomiczną głowicą video do dronów, korzystającą właśnie z MPU-6050. Niestety utknąłem przy przerabianiu mikro serw na korzystające z zewnętrznego pomiaru położenia.
Ziever: Czemu utknąłeś?
odłączenie potencjometru od płyki i przylutowanie zewnętrznego to widocznie zbyt dużo jak na tak małą elektronikę, silnik nie reguluje już
Serwo ala 9g ale metalowe
Pogadaj z tym kolesiem http://www.youtube.com/user/kefir1972
On robił dużo takich rzeczy i ma doświadczenie. I chyba nie było mu potrzebne wyjmowanie potencjometrów :)
sprae says: „Użyj tranzysorów MOSFET :)”.
No właśnie kombinuje na IRF4905. Układ ma służyć do sterowania … hmm w rolnictwie czegoś tam.
ja: I jak idzie? Podaj jakie to „coś” ma parametry prądu i jak ma być sterowane.
@sprae
mi dziala stabilizacja i bez wyjmowania potencjometrów ale potrzebuję znacznie większy zakres ruchów – najlepiej 360 po przełożeniu
Aha, to może lepiej jakieś cyfrowe serwa? Tam się chyba reguluje takie parametry.
Jest to prądnica od ciągnika – ma służyć jako silnik.
Parametrów niestety nie znam oprócz tego, że jest na 12V. Sterowanie obrotami przez PWM. PWM Arduino ma za dużą częstotliwość i silnik nie ma momentu na wolnych obrotach. Programowo zrobiłem 10Hz – i narazie jest OK.
Spróbuje jeszcze na http://nettigo.pl/product/TLC5940NT,TLC5940NT – może tam na sztywno można ustawić 10Hz lub inną zadaną.
ja: W normalnym PWM też można regulować częśtotliwość np. t funkcją http://playground.arduino.cc/Code/PwmFrequency
Zmienia on wartość dzielnika częstotliwości dla generatorów PWM.
Tylko jak jest w komentarzu do niej – trzeba uważać na to których pinów się używa, bo mają różne skutki uboczne przy zmianie częstotliwości.
Narazie mam tak zrobione I2CMaster + I2CSlave – kontrolujący całą maszynerię. I właśnie w I2CSlave jest PWM programowy na 10Hz. Z całej mojej wiedzy(internetowej) to minimalną częstotliwość PWM hardwareową na Arduino jaką można uzyskać to coś koło 60Hz – no chyba, że się mylę. Przy 60Hz mój silnik/prądnica już nie daje rady – nie ma siły/momentu na niskich obrotach.
http://playground.arduino.cc/Code/PwmFrequency – to narazie zostawie w spokoju – bo nie kumam Timerów, Rejestrów itp.
To świetnie :) Powodzenia w budowie!
Tak sobie właśnie pomyślałem.
Jakby wziąć starą myszkę optyczną na PS2, podłączyć do Arduino i sprawić, żeby robot ją ciągnął. Takie coś by sprawiło, że robot miałby dość dużo informacji o położeniu.
Dodatkowo by była stabilizacja by jechał po linii prostej.
Hmm, ciekawe rozwiązanie. Tylko, że ta myszka będzie przekazywać informacje (o zmianie położenia) wtedy i tylko wtedy, gdy jest „styczna z podłożem” (podłoże też chyba ma znaczenie).
Zapewne co by wszystkich zainteresowało to „oczy robocika” – OpenCV.