This is an old revision of the document!
Autor: Cinjau Constantin Iulian
Grupa: 336CB
Descriere generala:
Prin intermediul unei aplicatii de telefon minimaliste(facuta in MIT App Inventor) vom putea trimite comenzi de miscare a mainii: miscarea degetelor sau rotirea acesteia, catre placuta Arduino cu ajutorul modulului de bluetooth cu care microcontroller-ul comunica prin protocolul I2C, urmand ca placuta sa comunice cu LCD-ul(care va afisa comanda data de utilizator pe telefon) prin SPI si sa trimita semnale catre unul dintre cele doua motorase pentru a se realiza miscarea solicitata, de asemenea vor fi implementate anumite verificari astfel incat miscarea degetelor sa fie posibila doar intre niste unghiuri limita(de la 0 grade, in pozitia normala, la maxim 90 de grade) si rotirea mainii sa fie posibila intre 0 grade(pozitia normala) pana la 180 de grade(asa cum este si in realitate), in aceste cazuri limita se vor afisa si niste mesaje specifice pe LCD pentru a anunta user-ul ca limita miscarii respective a fost atinsa si sa incerce sa faca miscarea inversa.
Lista piese:
Prin intermediul laptopului conectat la Arduino Uno(ATMega328p) prin USB vom furniza acesteia tensiunea necesara pentru a functiona. La randul sau, prin intermediul portului de 5V, placuta va alimenta:
In ceea ce priveste cele 2 servo-motoare, nu le vom putea conecta tot la pinul de 5V al placutei, deoarece nu ar mai fi destula tensiune de alimentare si pentru ele, ceea ce inseamna ca va trebui sa avem cate o sursa de tensiune suplimentara pentru fiecare in parte. Servo-motorul Micro Servo 9g SG90, poate fi alimentat cu o tensiune cuprinsa intre 3V si 7.2V, asa ca cele 2 surse auxiliare de tensiune pe care le voi folosi sunt formate fiecare in parte din 3 baterii de 1.5V AA legate in serie pentru a avea o tensiune de alimentare per motor de 4.5V. Pentru linia de semnal catre cele 2 motoare am folosit pinii 10 si 11 de pe placuta.
Pentru a putea controla cele 2 motorase intr-un mod mai interactiv am dezvoltat in prima faza o aplicatie de Android minimalista, folosind site-ul MIT App Inventor si un tutorial pe Youtube dupa care sa ma ghidez. Aplicatia contine un:
O imagine cu interfata aplicatiei:
Pentru comunicarea realizata prin Bluetooth, a trebuit sa folosesc un fel de “protocol” de comunicatie, in sensul ca aplicatia de pe telefon am definit-o astfel incat atunci cand doreste sa trimita un mesaj(cand se schimba pozitia unui slider sau se apasa butonul), marcheaza acest lucru prin trimiterea caracterului '?', pentru a delimita 2 valori diferite, se foloseste caracterul '&', iar pentru a marca finalul unui mesaj se foloseste caracterul ';', deci mesajul pe care il primim pe placuta va fi in formatul: ?fingers=value1&wrist=value2;. Pentru a comunica cu modulul Bluetooth HC-05 am folosit biblioteca SoftwareSerial.h prin intermediul careia am creat un obiect de tipul SoftwareSerial pe care am atasat pinii: 9(pentru RX) si 8(pentru TX). Din cadrul acestei clase am utilizat 3 functii importante: available(), write() si read(). Aceste functii le-am folosit pentru a implementa alte 3 functii:
1. **verify_bt_serial** = functie care este apelata in loop, si care are urmatoarea logica: asteapta sa se primeasca token-ul de inceput al mesajului(?), dupa ce primeste token-ul de inceput, citeste datele de pe seriala byte cu byte si le pune intr-un buffer pana cand primeste token-ul de final al mesajului(;), caz in care trimite mesajul catre functia de parsare si reseteaza buffer-ul si flag-ul de asteptare al inceputului unui nou mesaj. De asemenea, aceasta face si o verificare, in cazul in care mesajul pe care il primeste depaseste 20 de caractere(aplicatia nu va trimite atatea caractere in niciun caz), va ignora mesajul, pentru ca este posibil ca acesta este posibil sa contina date incorecte datorita conexiunii. 2. **parse_message** = functie in care parsam valorile primite intr-un mesaj, aceasta verifica in primul rand daca mesajul este in formatul in care il asteptam(fingers=xx&wrist=yyy), si daca salveaza cele doua valori in format string(xx si yyy) pentru ca ulterior sa fie prelucrate de functia de validare a datelor si executarea comenzii pe servomotoare. 3. **write_values_to_servo** = functie care valideaza cele doua string-uri de mai sus in 2 moduri:daca valoarea convertita de la string folosind functia toInt() este 0, si ultima valoarea scrisa pe motoras este ceva mult mai mare decat valori apropiate lui 0, este posibil ca valorile xx sau yyy sa fi continut caractere ciudate si de aceea returnul conversiei era 0, caz in care vom ignora valorile si vom astepta altele noim, iar, al doilea mod de validare consta in verificarea celor 2 valori sa fie in limitele permise: pentru degete [0, 90] grade si pentru incheietura [0, 180] grade. De asemenea functia verifica si daca noua valoare pentru un motor este egala cu cea veche, caz in care nu mai face write pentru ca ar fi inutil. Daca toate validarile merg ok, atunci noile valori sunt transmise catre servomotoare.
Pentru controlul servomotoarelor am folosit libraria Servo.h cu care am creat 2 obiecte de tipul Servo: pe primul dintre ele(cel pentru incheietura) l-am atasat la pinul 10 si pe celalalt(cel pentru degete) la pinul 11 prin intermediul metodei attach din cadrul clasei. Pentru a transmite semnal catre servomotoare am folosit metoda write. Pentru a folosi LCD-ul am folosit libraria LiquidCrystal_I2C.h, creand un obiect de tipul LiquidCrystal_I2C pentru care am aflat Slave Address-ul necesar protocolului I2C. Ca si functii utilizate din aceasta biblioteca sunt: init, backlight, setCursor si print. Datele de pe ecran sunt reprezentate de cele doua unghiuri, respectiv niste avertismente atunci cand se ating cele 2 limite(90/180 de grade) si le-am actualizat la un interval de o secunda prin intermediul unui timer pe care il voi descrie mai jos. Dupa cum am specificat si in descrierea aplicatiei de Android, placuta trimite un semnal periodic(1 sec) telefonului, pentru ca utilizatorul sa stie ca, conexiunea este inca stabila si toate comenzile pe care le trimite ajung la placuta. Am realizat acest lucru periodic, tot cu ajutorului unui timer configurat prin intermediul Timer0, astfel incat sa genereze 250 de intreruperi pe secunda, si la cea de-a 250-a sa realizeze atat actualizarea datelor de pe LCD, cat si transmiterea semnalului catre telefon. Pentru a-l configura am definit functia init_timer0_one_sec, in care am pus modul de functionare(CTC), valoarea prescaler-ului(256) si valoarea pragului de numarare(250), respectiv activarea intreruperii atunci cand counter-ul ajunge la un anumit prag, iar in rutina de tratare a intreruperii ISR(TIMER0_COMPA_vect) doar verificam unde am ajuns cu celalalt counter, si daca s-a ajuns la 250(adica a trecut o secunda), avem un flag pe care il facem true si prin care anuntam functia loop ca poate face transmisia catre telefon si afisarea pe LCD. In functia de setup apelam functia de initializare a timer-ului, configuram baudrate-ul serialei de comunicare cu modulul de bluetooth, initializam LCD-ul, respectiv cele 2 servomotoare. In functia de loop, apelam functia de verificare a serialei cu modulul(verify_bt_serial), care la randul ei le apela pe celelalte cand era nevoie, adica cand s-a primit vreo comanda, respectiv, verifica flag-ul pentru a vedea daca trebuie actualizat LCD-ul sau trimis semnal catre telefon.