Nume: Grunberg Edar-Albert
E-mail: Login to see contact info.
Link proiect: https://ocw.cs.pub.ro/courses/pm/prj2021/dbrigalda/simon-whack
La început, se alege jocul dorit cu ajutorul Joystick-ului. Apoi, buzzer-ul va cânta o melodie de start joc.
Acest joc se va juca cu ajutorul unui joystick. Pe breadboard vor fi plasate 5 LED-uri (rosu-galben-albastru ). Înainte ca jucătorul să realizeze o acțiune, el va aștepta si va memora ordinea în care se vor aprinde x din cele 5 led-uri. Mai departe, înclinând Joystick-ul în stânga sau dreapta, jucătorul va putea selecta led-ul dorit. Dacă nu este sigur ce led urmează într-o secvență, atunci, pierzând din scor un punct, jucătorul poate cere un hint. Acesta va fi realizat printr-un servomotor ce va indica spre led-ul ce trebuie selectat.
Jocul începe la fel ca primul, în sensul că va cânta melodia de început, apoi led-urile se vor lumina într-o ordine. Apoi un singur led se va aprinde, la întâmplare. După, începe jocul propriu-zis: cu un delay se vor aprinde led-urile de la stânga la dreapta, iar jucătorul va trebui să apese pe joystick în momentul în care este aprins led-ul pe care l-a văzut la început, pentru a-i scădea numărul de vieți. Led-ul va avea, la întâmplare, între 2 și 5 vieți, iar ca să termine o rundă, va trebui să i se ducă toate viețile led-ului.
Pe parcursul jocurilor, pe un ecran LCD se va afișa textul “Your Score is: …” și un număr ce reprezintă viețile rămase.
Pentru ambele jocuri se va ține o evidență a scorului jucătorilor (pentru primul la final se compară rezultatele și pe LCD se va afișa câștigătorul, iar pentru al doilea se memorează rezultatul pentru a-l afișa la finalul jocului).
Pentru mine, proiectul acesta este fascinant, întrucât pot învăța cum funcționează un joystick (precum cele utilizate în controller-ele de PlayStation sau XBox). De asemenea, îl consider o provocare și un mod de a-mi satisface plăcerea de a inventa ceva.
Se incepe prin alegerea jocului de catre unul din cei 2 jucatori. Pe ecran se pot vedea la început numele jocurilor (SimSays sau WaL) și 2 triunghiuri ce vor pointa către cele 2 jocuri. Selecția se realizează cu ajutorul Joystick-ului, înclinându-l la dreapta (pentru Whack-a-Led) sau la stânga (pentru Simon Says). În tot acest timp, led-urile de pe placuță luminează la întamplare (adică, cât timp se decide ce joc doresc jucătorii să joace, LED-urile se sting și se aprind la întâmplare, pentru a nu fi totul monoton). Când se alege jocul, acestea se sting și se afișează pe ecran “Game Starts! Player 1”.
Simon Says se desfășoară pe runde si nivele (fiecare nivel are 3 runde). Nivelul reprezintă numărul de led-uri ce se vor aprinde în secvență. Dacă jucătorul greșește un led din secvență, atunci led-urile vor face blink de 3 ori, toate, deodată, iar dacă secvența a fost corectă de la cap la coadă, atunci led-urile fac blink o singură dată (adică atunci când se câștigă o runda). Totuși, ca să se înțeleagă când se trece la un nou nivel, led-urile se vor aprinde de la stânga la dreapta cu un delay.
După ce led-urile se aprind singure în secvența întâmplătoare, ele vor face toate blink o singură dată, pentru a anunța jucătorul că este rândul său să reproducă secvența.
Pentru a ști ce led este selectat, acesta va face blink (în continuu, pe o intrerupere).
Joystick-ul va incrementa sau decrementa (stânga / dreapta) un index, ce va referi câte un LED. Scorul va depinde de corectitudinea cu care a apăsat acel led.
Buzzer-ul este folosit pentru a “reda o melodie de start” când începe jocul, pentru a anunța jucătorul că a selectat LED-ul potrivit sau nu (sunete pentru selecție bună și pentru selecție greșită).
Servomotorul este acționat cu ajutorul unui buton atunci când jucătorul trebuie să restabilească secvența de culori și va indica spre led-ul ce trebuie selectat, dar jucătorul va pierde 1 punct din scor-ul actual.
Butonul este folosit pentru a folosi Servomotorul (pentru a cere hint)
Pe LCD se afișează scorul, viețile rămase, jucătorul este anunțat că va începe jocul, iar la final sunt afișate scorurile ambilor jucători și câștigătorul (cel care a avut scorul cel mai mare)
La Whack-a-Led nu mai sunt nivele si runde, este doar un joc repetitiv, singurul lucru diferit la fiecare “rundă” este LED-ul pe care trebuie să îl infrângă jucătorul și delay-ul cu care se schimbă ce led se arpinde (pentru că este un număr random).
Pentru a alege un led trebuie apăsat butonul Joystick-ului.
Servomotorul este folosit pentru a aduce aminte jucătorului care este led-ul ce trebuie înfrânt
Număr Piese | Denumire Piese | Descriere |
---|---|---|
1 | Arduino UNO | 29 lei (Ardushop) |
2 | Cablu USB alimentare | 2 lei (Ardushop) |
30 | Rezistențe de 2k și de 220 | 3 lei (Ardushop) |
100 | Fire Jumper și rigide | 12 lei + 12 lei (Ardushop + Optimus Digital) |
2 | Modul Joystick Biaxial Negru cu 5 pini | 2 x 5.49 lei (Optimus Digital) |
30 | Led-uri: albastre, roșii, galbene | ~5 lei (Ardushop) |
2 | Ecran LCD 1602 cu convertor I2C | 2 x (12 lei + 5 lei) (Ardushop) |
1 | Servomotor | 14 lei (Ardushop) |
1 | Breadboard Micutz + Breadboard Măricel | 3 lei + 10 lei (Ardushop + Optimus Digital) |
Funcția setup() se ocupă de afișarea inițială pe ecran a jocurilor ce pot fi alese și de setarea corectă a regiștrilor. (pentru timer 1 COMPA și COMPB, LED-uri, etc.).
Totul începe în funcția loop(). La început aceasta apelează funcția wait_for_choice(), unde se stă într-o buclă până se selectează jocul dorit, cu ajutorul Joystick-ului (stânga-dreapta). Pentru ca să se înțeleagă ce joc este selectat, am creat câteva caractere pentru LCD-ul meu. Pentru început, pe ecran sunt 2 triunghiuri ce pointează către un joc fiecare. De exemplu: Dacă se alege jocul din dreapta (WaL), atunci triunghiul din dreapta se transformă într-o față veselă, iar cel din stânga într-una tristă.
Mențiune: butonul Joystick-ului funcționează pe intrerupere (pe pin-ul digital 4), iar înclinarea Joystick-ului la stânga sau la dreapta o citesc din registrul ADCH (ce ia valori între 0 și 3), pentru că ADCL e mereu 255, normal, adică, folosesc noțiuni de AVR pentru citirea valorilor date de Joystick.
Mențiune: Scrierea pe LCD o fac în marea majoritate cu funcția LCD_print_prompt care scrie 2 string-uri pe cele 2 linii. Unde nu am folosit funcția LCD_print_prompt() pentru a scrie pe ecran, înseamnă ca am scris si caracterele mele speciale, cu funcția lcd.write().
După ce s-a ales jocul, buzzer-ul începe să cânte o melodie realizată de mine în funcția play_start_song() din songs.h și led-urile încep să facă un “joc de lumini”, se aprind toate pe rând si apoi se sting. (cu funcția turn_on_all_leds() din ledPlay.h). Acest lucru se întâmplă pentru ambele jocuri la fel.
Apoi, după această introducere în joc se aprind la întâmplare led-uri (cu funcția random() ce are seed pin-ul analogic A3), iar ordinea în care s-au aprins este salvată în vectorul randomArr. Ca să se delimiteze secvența generată random de momentul în care jucătorul trebuie să o reproducă, led-urile se aprind si se sting toate după ce s-a terminat secvența (turn_off_all_leds() + turn_on_all_leds()).
Acum se intră în funcția wait_for_sequence(), unde au loc următoarele lucruri: jucătorul poate folosi Joystick-ul (stânga-dreapta) pentru a selecta led-ul dorit. Acțiunea aceasta se realizează în 2 locuri: in loop() se incrementează sau se decrementează o variabilă ce reprezintă index-ul în cadrul vectorului LEDS, iar pe timer 1 (cu TOP la OCR1A, ce se activează la fiecare 20ms) se stinge și se aprinde la fiecare o secundă led-ul selectat, adică cel aflat la index-ul incrementat sau decrementat de Joystick.
În tot acest timp, cu diverse funcții, afișez pe ecran Scorul si Viețile rămase.
Tot în acest moment, când se așteaptă ca jucătorul să termine sau să greșească secvența, se mai poate face un lucru. Apăsând butonul conectat la pinul digital 2 (cu intrerupere atașată cu funcția attachInterrupt()), se activează servomotorul, adică știind index-ul LED-ului ce trebuie selectat pentru a continua secvența, servomotorul va arăta spre valoarea de la același index, din vectorul servoPositions[5] (care conține valori în grade, de la 1 la 180). Servomotorul este acționat astfel: la fiecare 20 ms, ISR(TIMER1_COMPA_vect) activează pin-ul digital 3 (cu PWM) și se intră pe ISR(TIMER1_COMPB_vect), unde se pune același pin pe valoarea LOW. Pentru a schimba poziția servomotorului trebuie modificată valoarea lui OCR1B. Făcând calculele (regula de 3 simplă), am aflat intervalul de valori pe care OCR1B le poate lua pentru a muta servomotorul între 0 si 180 grade. Aici, deoarece am setat prescaler-ul pentru timer la valoarea 64, rezoluția servomotorului este una bună, valorile fiind între 250 si 500 pentru OCR1B. Totuși, deoarece Servomotorul începea să se miște brusc la 1s și să se întoarcă la loc, am decis ca de fiecare dată când se cere hint, să arate spre led-ul bun, iar apoi să se întoarcă la o valoare de referință (respectiv 125 - adică SERVONOTICK).
int SERVO_convert_from_degrees(int grade);
Extra, aici am făcut o funcție de conversie din valori 200-500 în 0-180 ca să lucrez mai ușor, în grade.
Jocul se încheie atunci când jucătorul a făcut 3 greșeli, adică când și-a consumat toate cele 3 vieți.
Pentru următorul jucător se reia procesul, diferit pentru el este jocul led-urilor de la început.
La final, după ce s-a terminat jocul, tot procesul se reia.
Jocul acesta este mai simplu, se aprinde un singur LED la întâmplare după ce a cântat melodia la început și led-urile și-au terminat jocul de lumini. Acest led este memorat în variabila g_whackLed.
La fel ca la Simon Says, pentru a anunța jucătorul că e rândul său să se joace, se aprind toate led-urile, apoi se sting.
Pe ecran acum se afișează scorul, numărul de vieți rămase și căte vieți are LED-ul ce trebuie înfrânt.
Acum, Din loop() se intră în funcția wait_for_whacking(). Aici se aprinde de la stânga la dreapta câte un LED (într-un while din care se iese ori când led-ul nu mai are vieți, ori când nu mai are jucătorul vieți). În momentul în care este aprins led-ul pe care trebuia să-l țină minte jucătorul, se apasă butonul Joystick-ului (se intră pe întreruperea asociată lui, unde se verifică dacă este led-ul bun și se activează flag-uri, astfel încât când se reia funcția wait_for_whacking să se poată actualiza ecranul) și scorul jucătorului creste cu 1 punct, iar led-ului i se va lua o viață. Dacă a apăsat pe joystick când alt led s-a este aprins, jucătorului i se scade o viață și se reia de la început până când nu mai are vieți rămase.
Asemenea jocului Simon Says, și în acest joc paote fi acționat Servomotorul, pentru a-i aduce aminte jucătorului care este LED-ul ce trebuie înfrânt.
La final, după ce s-a terminat jocul, tot procesul se reia.
Proiectul mi-a ieșit de la cap la coadă, exact așa cum am vrut eu. Totuși, mă gândeam ca al doilea joc, pe care inițial l-am numit Whack-a-Mole, să fie o copie a jocului cu același nume, dar mi-am dat seama că îmi va fi greu să am câte un buton pentru fiecare LED. De aceea am decis să îl redenumesc Whack-a-Led și să inventez propriile mele reguli.
După multe momente în care credeam că nu o să pot să termin proiectul deoarece vedeam că nu voi putea să folosesc toate componentele pe care doream să le folosesc, am reușit într-un final să finalizez, totul fiind funcțional.
Totuși, cele mai importante realizări pentru mine au fost faptul că am înțeles cum se lucrează cu un Servomotor, un buzzer și un LCD în același timp. Inițial, deoarece doream să folosesc funcții deja existente precum Servo.write() sau tone() sau lcd.print(), mi-am dat seama că este aproape imposibil. Multe din ele se foloseau de același timer (1) pe care îl foloseam și eu pentru blink-ul led-urilor. Astfel, am fost nevoit să învăț cum controlez Servomotorul direct pe Timer, cu întreruperi, iar scrierea pe LCD a trebuit să o fac numai în afara întreruperilor, deoarece biblioteca pentru LCD-ul meu cu convertor I2C nu permitea acest lucru.
De asemenea, cu ocazia acestui proiect am învățat cum să folosesc letcon-ul pentru a lipi pinii modulului I2C pe spatele ecranului LCD 1602, lucru care prima oară a eșuat , dar am rectificat această greșeală pe parcurs .
Realizarea acestui proiect m-a motivat să vreau să mai folosesc plăcuța Arduino și pentru alte proiecte personale legate în special de senzori.
Documentul în format PDF: 335CC_Grunberg_Edar-Albert