Sumator PWM -> PPM, dla drona
[img=IMG_1747]
Będzie cykl lataniu, napisany na podstawie moich zabaw z pionowzlotem. Może ktoś zechce zrobić sobie własny? Na początek, aby nie odbiegać za bardzo od tego o czym normalnie skrobię, banalny układ dający super moce, plus trochę teorii o tym jak to działa.
Teoria, historia
Oryginalnie miałem genialny pomysł, aby do zdalnego sterowania tym stworem wykorzystać atmegę328p podłączoną do Dualshocka. Pad używa SPI i jest względnie prosty do kontrolowania z procesora, ma tylko kilka irytujących wad (co się okazło po tym jak zrobiłem prototyp) - powracająca automagicznie na środek gałkę analogową, i jest względnie niedokładny, szczególnie w środku zakresu. Plus rozwiązania jest taki, że jak się wie jak takie rzeczy robić, to wychodzi tanio. I przy okazji człowiek się uczy nowych rzeczy, tu rozmowy z padami. Prototyp jednakże działał całkiem sprawnie i pozwolił na zrobienie dużej ilości testów, dojście do tego jak to wszystko działa, lubię wiedzieć jak to wszystko działa.
Ale żeby działało sprawniej, trzeba było upolować normalna aparaturę do zdalnego sterowania.
Taki zestaw składa się z nadajnika, duże czarne pudełko z wajchami. Czasem ma wyświetlacz, guziczki i inne takie (i potrafi odbierać telemetrię). Do tego jest małe prawie czarne pudełko, które sygnał z tych wajch odbiera i przerabia na coś co jest zrozumiałe dla urządzenia sterowanego. Sygnał z tego małego pudełka może być podawany do komputera sterującego urządzeniem latającym na kilka sposobów:
- PWM - Pulse Width Modulation, idealny jeśli chcemy bezpośrednio z odbiornikiem połączyć serwa.
- PPM - Pulse Position Modulation, jak to ma iść do komputera sterującego, chyba najlepsze wyjście.
- S-Bus, i inne takie, zignoruję.
W systemach 433/868MHz sygnał podróżował powietrzem (na jednej częstotliwości), najczęściej w formie PPM, odbiornik wykonywał konwersje na PWM i w takiej formie podawał go dalej. Ale nastała technologia i aktualnie najpopularniejszymi rozwiązaniami są te pracujące w paśmie 2,4GHz, wyposażone w "frequency-hoping" - odbiornik i nadajnik sobie radośnie skaczą z transmisją/odbiorem po dostępnych kanałach, dzięki czemu trudniej się zakłócają, poza tym dane idą przez cyfrowy modem. Znaczy w trakcie podróży do statku powietrznego są w formie integerów. Dokładne protokoły transmisji zalezą od producenta sprzętu, ale one nie są dla nas zbyt ważne, bo odbiornik te cyfrowe dane i tak zawsze przerabia na coś co jest bardziej lub mniej powszechnym standardem (pwm, ppm, sbus, etc) i w tej formie wędrują do układów sterujących.
W związku z tym, że nie należę do ludzi, którzy pakując się w nowe hobby pragną na to wydać nie wiadomo jakich funduszy (bo może mi się znudzi?), wybór aparatury był oparty głownie na cenie, ilości kanałów i jej skomputeryzowaniu. Najbardziej przypasowała mi FlySky FS‑TH9X.
Chiński klon Turningy 9X. Nadajnik sprzętowo wygląda bardzo dobrze, poza tym w środku siedzi ATmega64A, i dzięki bogu bo, poza tym, że sprzęt fajny to bardziej syfiastego softu w urządzeniu dawno nie widziałem. Problem z softem dało się rozwiązać dolutowując złącze ISP, i flashując weń openTX (er9x jest lepszy, ale wymaga moda 2 przełączników), w każdym razie nowy soft rozszerzył ilość kanałów z 9 do 16 i dodał całą masę przydatnych opcji. Choć może przede wszystkim, nadajnik przestał straszliwie piszczeć przy każdym naciśnięciu przycisku.
Tylko co mi po 16 kanałach jak odbiornik podaje tylko 8, w dodatku PWM. 16 się przyda jak zrobię własny odbiornik, protokół transmisji jest znany. Ale to PWM jest problemem, na dwa sposoby. Po pierwsze - 1 kabel na każdy kanał, optymistycznie, jeśli by chcieć wykorzystać wszystkie kanały, potrzeba 10 przewodów (8 linii danych + zasilanie), pesymistycznie 26 (każdy kanał ma 3 piny). Te 10 przewodów dało by się jeszcze przeboleć, gdyby nie to, że komputerek (Crius v2) ma wejścia tylko na 6 kanałów, z czego przy odrobinie pecha dostępnych jest 5. Aby sterować pionowzlotem potrzeba minimum 4 kanałów - throlle, yaw, pitch, roll. A po co mi więcej? Do włączania/wyłączenia różnych rzeczy, aktualnego trybu lotu, magnetometru, funkcji utrzymywania pozycji i wysokości, etc. I do uzbrojenia silników, co prawda da się je uzbrajać poprzez odpowiednie kombinacje drążków sterujących, ale posiadanie odcięcia przepustnicy na przełączniku jest znaaaaacznie wygodniejsze.
Szczęśliwie Crius/MultiWii przyjmują sygnał PPM jako sterujący, to daje nam wszystkie 8 kanałów na tylko 3 przewodach (sygnałowy, +, -). Tylko jak z PWM zrobić PPM? Łatwo, w internetach dostępnych jest dużo układów sumujących wejścia PWM i robiących z nich PPM, tylko, że jak to ja, mam specyficzne wymagania. Układ musi się dodatkowo zmieścić w oryginalnej obudowie odbiornika, wraz z tym co już tam siedzi, i dać się zintegrować ze złączami tegoż, nie zmieniając ich zachowania. No, poza jednym pinem.
Dlatego powstało to:
Zbudowane na ATtiny2313, który jak na swoje możliwości jest zaskakująco drogi (4,5pln, "mocniejszą" atmegę8 można dostać za 3), ale ma wyprowadzony cały jeden port na jednej krawędzi a ten port ma dostępne przerwanie PCINT na sobie. Poza tym jest w obudowie SOIC (lepiej mi się to lutuje niż TQFP).
Pierwszą myślą było wykorzystanie któregoś z timerów do mierzenia czasu impulsów PWM, zapisanie tego czasu w tablicy, i na podstawie tych danych generowanie impulsów PPM. Ale miałem olśnienie, relacja między PPM i PWM wygląda tak:
Już, olśniło co można zrobić? Dzięki temu kod programu zamyka się w całych 158 bajtach (wraz z obsługą LEDa) i zużywa całe 0 bajów RAM, do tego nic nie trzeba mierzyć i pisać kodu generatora. Jak? Ustawić przerwanie na wszystkie piny portu B, i timer aby pracował przy F_CPU/64. Kiedy nastąpi przerwanie, trzeba ustawić poziom wyjścia PPM na wysoki, i zresetować timer aby jego przerwanie odpaliło się za 304us (powinno być 300, ale przy 8MHz tak się nie da). W przerwaniu timera dajemy wyjście PPM na stan niski, i tyle. Cała filozofia. W efekcie cały kod potrzebny do konwersji wygląda tak:
[code=C] #include <avr/interrupt.h> #include <avr/wdt.h> #include <avr/sleep.h>
// PA1 - LED #define LED_ON() { PORTA |= _BV(1); } #define LED_OFF() { PORTA &= ~_BV(1); } #define LED_INIT() { DDRA |= _BV(1); }
// PD4 - PPM #define PPM_HI() { PORTD |= _BV(4); } #define PPM_LO() { PORTD &= ~_BV(4); } #define PPM_INIT() { DDRD |= _BV(4); }
ISR(PCINT_vect) { PPM_HI(); TCNT1 = 0; OCR1B = 38; // 304us LED_ON(); }
ISR(TIMER1_COMPB_vect) { PPM_LO(); LED_OFF(); }
int main() { GIMSK |= (1 << PCIE); // PC Int PCMSK = 0xFF; // caly port TCCR1A = 0; TCCR1B |= (1 << CS11) | (1 << CS10); //dzielnik 64 TIMSK |= (1 << OCIE1B); // przerwanie dla komparatora B
PPM_INIT(); // ustawienie pinow jako wyjscia LED_INIT(); sei(); // włączenie przerwań for(;;) { sleep_enable(); // w sumie zbędne, ale dla oszczędzania energii nie zaszkodzi sleep_cpu(); // przełącza CPU w idle mode sleep_disable(); } return 0; } [/code]
Po przylutowaniu do płytki wszystkich potrzebnych przewodów, trzeba je na na pająka wpiąć do wtyczki ISP, zaprogramować układ, pozostaje tylko połączenie wsztstkiego. W tym celu trzeba przylutować 8 wejść portu B do wyjść kanałów PWM, kolejność nie ma znaczenia.
Masa jest dostępna na środku tej małej płytki z pinami, zasilanie po lewej stronie, na środkowym rzędzie pinów. Pozostaje kwestia wyprowadzenia wyjścia PPM. Oryginalny układ ma 10 rzędów szpilek (po 3), 8 to wyjścia PWM, dwa to zasilanie i "bind", oba rzędy pełnią identyczne funkcje, dlatego lokalizujemy miejsce zaznaczone na czerwono:
Jest tam ścieżka, którą trzeba przeciąć, jak już ją przetniemy to upewniamy się, że pierwsze dwa piny nie są już ze sobą połączone, jeśli nie są, przylutowujmy kabelek z wyjściem PPM do pierwszego z nich. Upychamy ewentualne wystające kabelki do odbudowy, skręcamy i tadaaaa:
Wszystkie oryginalne funkcje są dostępne dalej, nic poza obudowę (poza anteną) nie wychodzi, całość jest kompatybilna z układem kabelków odbiorników posiadających oryginalnie PPM, i komputer dostanie teraz całe 8 dostępnych kanałów. Można latać, no prawie. Czy są na sali pytania? :D