Tenis to najstarsza z gier video. Swoją premierę miała już w 1972 roku. Ja pamiętam ją jeszcze z mojego dzieciństwa – w wersji na konsolę TVG-10. Spędziłem nad nią wiele godzin:) Wspomnienia wróciły po wizycie w Muzeum Konsol Gier Video Karpaczu. Szybkie poszukiwanie w Sieci pokazało się, że w oparciu o Arduino można zbudować mini-konsolę podłączaną do telewizora.
Projekt
Moja konsolka będzie oparta na Arduino UNO. Używając biblioteki TVOUT będę generował obraz analogowy w systemie PAL, który z kolei wyświetlę na telewizorze.
Konsolka będzie wyposażona w mały wyświetlacz LED oparty o TM1637. Do sterowania systemem wykorzystam kilka przycisków typu tact. Przyda się również wyprowadzony na zewnątrz reset. Gry będę obsługiwał za pomocą dwóch kontrolerów. Zamierzam zrobić właśnie takie, jakie były w TVG-10: walcowate z obracaną końcówką. Są znacznie wygodniejsze niż potencjometryczne (stosowane w niektórych starszych systemach).
Całą konsolę zamknę w plastikowej obudowie. Konsola będzie zasilana przez zewnętrzny zasilacz 12v. Podobne projekty były już opisywane w Sieci wielokrotnie – lista inspiracji na końcu tekstu.
Tekst jest mojego autorstwa i oryginalnie ukazał się na moim blogu Elektronika Bez Spięcia (uczymy.edu.pl): Konsola do gier na Arduino. Niektóre z zagadnień zostały tam opisane w szczegółach – tutaj przytaczam ich skrót.
Kontrolery
Moje kontrolery będą oparte na potencjometrach. Pamiętacie dzielnik napięciowy?
Potencjometr kontrolera wstawię w miejsce rezystora R2 i zmierzę na nim napięcie za pomocą pinu przetwornika analog/cyfra A0 (i A1 dla drugiego gracza):
Oczywiście możecie zastosować ten potencjometr łącząc 5v i masę do pinów skrajnych a środkowy – do wejścia analogowego. Ale wtedy potrzebowalibyście 3 kabelków (i nie można by już było wykorzystać prostego gniazda DC – o czym poniżej).
Dla rezystora R1=4k7 i potencjometru P1=10kΩ, napięcie mierzone przez A0 będzie wynosiło:
Dla P1 = 0Ω (skrajna pozycja potencjometru), napięcie powinno być bliskie zeru. Dla P1 = 10kΩ (druga skrajna pozycja potencjometru):
Biorąc pod uwagę, że funkcja “analogRead()” zwraca 0 dla 0v i 1023 dla 5v, przy tym dzielniku wartości powinny zwierać się w przedziale 0..695. W praktyce na pinie 5v nigdy nie ma 5v – pewnie coś około 4.8 do 4.9v. Rezystory mają swoje odchylenia od wartości nominalnych. W rezultacie pin A0 zwracał wyniki w zakresie 0..720 – ale jedynie, gdy potencjometr był podłączony. W przeciwnym wypadku – 1023.
Zakresy te będą potrzebne do mapowania nastawy potencjometru (zwracanej przez pin analogowy) do pozycji rakietki na ekranie, np.:
1 2 3 4 5 6 7 |
int a0 = analogRead(0); int a1 = analogRead(1); if( a0 >= 0 && a0 <=720){ int a00 = map( a0, 0, 720, ymin, ymax); int a10 = map( a1, 0, 720, ymin, ymax); //... } |
Zmienne ymin i ymax to współrzędne najwyższej i najniższej linii ekranu.
Do podłączenia kontrolerów użyłem gniazda zasilające DC do wtyków 2.1mm:
Z lenistwa kupiłem gotowy kabel z wtykiem pasującym do tych gniazd:
Pozostało przylutować kabeki:
Z drugiej strony do kabla przylutowałem potencjometr:
No i pomysł na kontrolery: butelki po kosmetykach:)
Wystarczyło zeszlifować gwint:
W zakrętkę włożyłem gałkę od potencjometru. Użyłem distalu, żeby je połączyć:
Z drugiej strony butelki wywierciłem otwór na potencjometr i odciąłem denko:
Pozostało wkleić to denko wewnątrz tuby:
W efekcie:
Operację należy powtórzyć dwa razy:)
Wyświetlanie obrazu na telewizorze
Do wyświetlania obrazu na telewizorze wykorzystałem bibliotekę TVOUT: https://github.com/Avamander/arduino-tvout/. Wystarczy pobrać ją z GitHuba plik zip i rozpakować do katalogu z bibliotekami Waszego Arduino IDE. Teraz z katalogu “./arduino-tvout-master/TVoutfonts” skopiujcie wszystkie pliki do katalogu głównego biblioteki (zob. ten wątek). W ten sposób będziecie mogli użyć w swojej aplikacji wszystkie dostępne czcionki:
- 4×6
- 6×8
- 8×8
- 8x8ext
Otwórzcie nowy projekt i z menu “Szkic/Dodaj bibliotekę” dodajcie “TVOut”:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <TVout.h> #include <font6x8.h> #include <video_gen.h> void setup() { // put your setup code here, to run once: } void loop() { // put your main code here, to run repeatedly: } |
Dodajcie czcionki i zainicjalizujcie bibliotekę:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <TVout.h> #include <font6x8.h> #include <video_gen.h> //******************** //Used by TVOUT #define X_MAX 120 #define Y_MAX 96 //******************** //the tv object TVout tv; void setup() { tv.begin(PAL, X_MAX, Y_MAX); tv.select_font(font6x8); } void loop() { } |
Biblioteka ta udostępnia kilka funkcji, które możecie użyć w swoich programach, np:
- tv.fill(WHITE): wypełnij ekran kolorem białym (BLACK – czarnym),
- tv.clear_screem(): wyczyść ekran,
- tv.delay(1000): opóźnienie 1s,
- tv.draw_column(10,10,50,WHITE): narysuj linię pionową na x=10 dla y=10..50 – białym kolorem (szybsze niż draw_line),
- tv.draw_rect(50,50,10,10,WHITE): narysuj na ekranie kwadrat o boku 10 pikseli na pozycji (x, y): (50,50),
- tv.print(): cały zestaw funkcji do wypisywania na ekranie tekstu.
A teraz uwaga (której odkrycie kosztowało mnie trochę czasu):
Biblioteka TVOUT mocno używa przerwań. Może zakłócać działanie innych bibliotek lub ich funkcji. Na przykład… Serial.println().
Użycie w kodzie instrukcji Serial.println() spowoduje przedziwne “efekty”. Obraz będzie nagle znikał a aplikacja będzie się wieszać. W związku z tym: nie używajcie modułu Serial.
Podłączenie do telewizora
Dla Arduino UNO:
- Pin 9: synchronizacja,
- Pin 7: sygnał video,
- Pin 11: sygnał audio
Wybór pinów nie jest przypadkowy: dla UNO R3 nie możecie użyć innych. Biblioteka TVOUT wykorzystuje pewne dodatkowe funkcje portów kontrolera. Jeżeli zamiast AtMega328 (napędzającego UNO R3) użyjecie np. Arduino Mega lub Leonardo – będziecie musieli użyć trochę innych pinów – odsyłam do dokumentacji biblioteki.
Piny te wyprowadzę na 2 wtyczki typu cinch – jedną dla video, drugą dla audio. Wewnętrzny styk to sygnał – zewnętrzny to masa. Do podłączenia video będziecie potrzebowali 2 rezystorów 1kΩ i 470Ω (na podstawie: TVOut library):
Audio można podłączyć bezpośrednio:
Teraz pozostało nawiercić w obudowie otwory pod gniazda cinch:
Do gniazd przylutowałem kable:
Złącza można dodatkowo zarobić koszulkami termokurczliwymi:
Wyświetlacz
Pomyślałem, że przyda się wyświetlacz, który będzie pokazywał np. wybraną grę albo stopień trudności. W tym celu użyłem modułu z TM1637.
Jego dokładny opis znajdziecie tutaj: Wyświetlacz LED z TM1637. Wyświetlacz przykręciłem do górnej części obudowy za pomocą czterech śrubek fi2mm/16mm:
Klawiatura
Na potrzeby wybierania gry, jej startowania i ustawiania poziomu trudności, przyda się kilka przycisków. Mój wybór padł na standardowe przełączniki typu tact. Ponieważ ma być ich 4, postanowiłem podłączyć je poprzez port analogowy.
Dokładny opis takiego podłączenia znajdziecie w tym tekście: Arduino: przyciski podłączane do wejść analogowych. Przyciski przylutowałem na płytce uniwersalnej. Modulik zasilany jest z 5v. Przyciski podłączyłem do wejścia A2. Pamiętajcie również o połączeniu A2 z D2. W ten sposób będzie można podpiąć przerwanie pod port D2 i sprawdzać stan klawiatury dopiero po wciśnięciu klawisza.
Dodatkowy reset
Już pierwsze doświadczenia z konsolą pokazały, że dodatkowy reset jest niezbędny. O tyle łatwiej było go wyprowadzić, że płytka rozszerzenia posiadała już pady do wlutowania odpowiedniego przycisku. Wystarczyło je przedłużyć i wyprowadzić na piny:
Za przycisk posłużył kolejny “tact switch” do którego dolutowałem kabelki z gniazdami gold pin:
Teraz pozostało przykleić go w obudowie – z braku pomysłów użyłem gorącego kleju:
Widok na obudowie:
Montaż
Arduino przykręciłem do podstawki za pomocą śrubek M2 tak, żeby gniazdo zasilające było na samej krawędzi:
Jak widzicie użyłem klona Arduino w stylu “leonardo”. Klon był wyposażony w procesor AtMega328 (SMD) – ale w miejsce wielgachnego USB było microUSB. To pozwoliło mi ładniej wpasować płytkę w obudowę.
W górnej części obudowy wypiłowałem otwór na gniazdo DC:
Całość elektroniki zmontowałem na płytce rozszerzenia:
Nie było tego wiele:
- Gniazda audio/video oraz kontrolerów podłączyłem do terminali,
- Wyświetlacz, klawiaturę i reset podłączyłem przez gniazda typu gold pin.
Z gold-pinami miałem trochę problemów. Po nałożeniu kabelków po prostu nie mieściły się w obudowie:) Zdjąłem plastykową koronkę i wygiąłem piny…
Następnym razem pomyślę o pinach kątowych… Całość zmieściła się w obudowie:
Oprogramowanie…
Na podstawie takiej mini-konsoli możecie napisać kilka całkiem interesujących gier. Tenis to jedna – ale przecież wcale nie musicie się do tego ograniczać. NES i inne konsole ery 8-bitowej mogą dostarczyć Wam wielu inspiracji. Do dyspozycji macie klawisze, wyświetlacz, kontrolery – jest w czym wybierać…
Jeżeli jednak nie chcecie bawić się w programistów – przykładowy kod tenisa możecie pobrać z blogu: How to recreate the classic Pong game… Możecie go wykorzystać, pod warunkiem wykonania pewnych zmian.
W projekcie How to…, autor użył potencjometrów, które podłączył bezpośrednio do wejść analogowych. Ja użyłem dodatkowych rezystorów, dzięki którym podłączyłem kontrolery na 2 przewodach – a nie 3. W projekcie z bloga potencjometry zwracają wartości z przedziału 0..1023, u mnie – 0..720. Trzeba więc przemapować wartości. W funkcji processInputs() zmieńcie linijki od 63 z:
1 2 3 |
wheelOnePosition = analogRead(WHEEL_ONE_PIN); // delay(50); wheelTwoPosition = analogRead(WHEEL_TWO_PIN); |
Na:
1 2 3 |
wheelOnePosition = analogRead(WHEEL_ONE_PIN); // delay(50); wheelTwoPosition = analogRead(WHEEL_TWO_PIN); |
Dalej, jedyny klawisz podłączony był do D2. Jego stan odczytywano w procedurze processInputs(). W linijce 67 zamieńcie:
1 |
button1Status = (digitalRead(BUTTON_ONE_PIN)); |
Na:
1 |
button1Status = analogRead(BUTTON_ONE_PIN) > 500; |
W tym momencie wciśnięcie klawisza spowoduje uruchomienie gry. Możecie podłączyć konsolę do komputera za pomocą video grabera – znacznie ułatwi to pisanie i testowanie kodu.
Podsumowanie
Łatwe? Cóż, wymaga trochę pracy. Zawsze tak jest, gdy z projektów na płytce stykowej chcecie zrobić coś, co będzie trochę mniej… eksperymentalne:) Prawdziwa zabawa zaczyna się gdy dochodzi do lutowania czy konieczności wykonania elementów mechanicznych, albo choćby zmieszczenia wszystkiego w obudowie. A na końcu – można sobie pograć!
Materiały
Do budowy wykorzystałem:
- Arduino UNO R3, klon z microUSB – może być dowolny – mi taki po prostu pasował do obudowy,
- Obudowa Z77 124x72x37mm czerwona,
- Płytka rozwojowa dla Arduino, z resetem,
- Płytka przewlekana, dwustronna, ok 3×5 cm,
- Kabel z wtykiem DC 2.1/5.5mm przewód 2×0.22mm, 2 sztuki,
- Gniazdo zasilające DC 2.1/5.5 mm na panel, 2 sztuki,
- Potencjometr osiowy liniowy 10k, 2 sztuki,
- Tact Switch 6x6x8mm czarny, 5 sztuk,
- Rezystory około 10kΩ i 20kΩ, 1kΩ i 470Ω,
- Gniazdo CHINCH (RCA) na panel złote 2szt,
- Terminal blocki, 3 gniazda – 2 sztuki,
- Śrubki M2 o długości 8mm (do przykręcenia Arduino) i 16mm po 10 sztuk powinno wystarczyć.
Przyda się mini-wiertarka, pistolet na gorący klej, pilniki i papier ścierny.
Źródła
- Biblioteka TVOut
- Arduino Playground: TVOut
- O konsoli TVG-10
- Wyświetlacz tm1637
- Arduino: miernik rezystancji w Scratchu
- Inspiracje: tutaj, tutaj,
- How to recreate the classic pong game…
Bardzo praktyczny blog.
gdzie dostałeś tego shielda do uno ? szukam takiego do mega 2560 i znaleźć nie mogę.. fajny wpis!
@lolek: Ja kupowałem na aliexpress. Ale widziałem też np. w electropark: http://electropark.pl/shieldy/5974-arduino-mega-proto-shield-rev3-pcb.html
Fajna sprawa, ja sam zaczynam zabawę z arduino, tylko robię sterownik kotła c.o. opartym na zarządzaniu via www.
witam nie jestem czepialski – tetris nie tenis:P