Cursul precedent a descris o metodă de proiectare pe un exemplu mic, cu un singur senzor și o singură ieșire de putere. Un exemplu mic are avantajul clarității, dar ascunde tocmai ceea ce face dificilă proiectarea reală: concurența dintre subsisteme pentru aceleași resurse ale microcontrolerului. Cursul de față reia aceeași metodă pe un proiect care are aceste dificultăți din plin - un robot mobil autonom construit pentru un concurs studențesc, urmărit de la regulament până la lecțiile de pe teren.
1Obiectul și structura cursului6 min
Robotul are un șasiu pe patru roți, dintre care două motoare cu tracțiune diferențială, patru senzori de linie, doi senzori cu ultrasunete, două encodere optice, un buton de urgență și o legătură serială. Aproape toate modulele studiate în curs intervin simultan, iar un ATmega328P cu douăzeci de pini utilizabili oferă mai puține resurse decât cere suma subsistemelor - proiectarea constă, în bună măsură, în alegerea compromisurilor.
- Metoda: descriere, caiet de sarcini, partiționare cu interfețe fixate dinainte, mașină cu stări finite, cod pe straturi testat separat, plan de testare legat de cerințe (Cursul 10)
- Rezerva de resurse (minimum 20%) e regula practică - vom vedea ce se întâmplă când nu mai există (Cursul 10)
- Să întocmiți un buget de resurse (pini, timere, canale ADC, întreruperi) și să explicați compromisurile impuse de saturarea lui
- Să explicați de ce numărarea impulsurilor de encoder se face în întrerupere, iar calculul vitezei în bucla principală
- Să descrieți cele trei fenomene fizice care trebuie tratate la comanda unui motor cu punte H: zona moartă, saltul de comandă, oprirea de urgență
- Să calculați eroarea de poziție a unui robot urmăritor de linie dintr-un regulator proporțional și să explicați limitele coeficientului Kp
- Să recunoașteți de ce nivelul de testare pe teren nu poate fi înlocuit de laborator
2Contextul și tema de proiect6 min
Contextul competițional impune exact ceea ce lipsește de obicei din proiectele didactice: un caiet de sarcini scris de altcineva, pe care nu îl poți negocia, un termen fix și o probă publică în care sistemul fie funcționează, fie nu. Organizatorii publică regulamentul, dimensiunile terenului, limitele de gabarit și componentele obligatorii de siguranță - butonul de oprire de urgență accesibil din exterior, oprirea automată la pierderea legăturii, alimentarea de la acumulatori proprii. Toate acestea intră direct în caietul de sarcini, fără discuție.
Robotul trebuie să parcurgă autonom un traseu marcat cu bandă, să ocolească obstacolele, să raporteze permanent starea proprie și să poată fi oprit oricând de la o telecomandă. Ceea ce face greu proiectul nu este partea de algoritmică - modestă aici, un regulator proporțional și o mașină cu cinci stări -, ci încadrarea în resurse și respectarea timpilor.
3Caietul de sarcini al robotului9 min
Regulamentul concursului e descrierea sistemului, în limbaj obișnuit, scrisă de cineva care nu proiectează electronică: „robotul trebuie să urmărească traseul marcat” și „trebuie să evite coliziunile” - formulări neverificabile. Primul act tehnic al echipei e transformarea lor într-un caiet de sarcini cu cerințe măsurabile, prin întrebări puse organizatorului: cât de lată e banda? Care e raza minimă de curbură? Traseul are intersecții? Fiecare răspuns devine o cerință.
| Cod | Cerință | Criteriu de acceptare |
|---|---|---|
| CF1 | Urmărește banda de 19mm, curbură min. 250mm | 10 tururi fără pierderea traseului |
| CF3 | Obstacol la <250mm: oprire în ≤300ms | măsurarea distanței de oprire, 20 repetări |
| CF5 | Oprire de urgență: motoarele la zero în ≤50ms | osciloscop, 20 de repetări |
| CF7 | Odometrie: eroare sub 3% pe 2m drept | 10 încercări, comparație cu ruleta |
| CN4 | Niciun defect de senzor nu produce comandă maximă | deconectarea pe rând a fiecărui senzor |
CF4, CN3 și CN4 nu apar nicăieri în regulament - rezultă din lista de întrebări despre situațiile anormale. CN4 exprimă un principiu ne-evident: un senzor deconectat produce, la intrarea ADC, o valoare nedefinită, iar dacă algoritmul o folosește ca validă, rezultatul poate fi o comandă maximă pe motor - exact comportamentul periculos.
Corect proiectat, întrerupe fizic alimentarea etajului de putere, printr-un contact în serie cu puntea H, și abia în al doilea rând anunță microcontrolerul printr-o intrare digitală. Un buton care doar aprinde un bit citit de program nu protejează exact în cazul care contează cel mai mult: acela în care programul s-a blocat.
4Partiționarea sistemului și bugetul de resurse13 min
Cu cerințele fixate, urmează partiționarea: senzori de linie → poziție; encodere → viteze; ultrasunete → ecou; interfața cu operatorul → buton/START/LED; ieșire → PWM și sens către puntea H, cadre către USART. Fiecare subsistem livrează o singură mărime și ascunde complet implementarea din spate - dacă se schimbă tipul senzorului de linie sau modelul punții, se rescrie un singur subsistem.
Absentă din tabelul subsistemelor: orice modul care folosește magistralele sincrone din Cursul 09. Echipa a dorit inițial un afișaj și un senzor inerțial pe I²C, dar ambele au fost eliminate - motivul devine clar imediat: nu au mai rămas pini.
Bugetul de resurse
Placa Arduino Uno oferă douăzeci de pini de intrare-ieșire. Bugetul se face pe patru capitole: pini, timere, canale analogice, surse de întrerupere.
| Pin | Direcție | Semnal |
|---|---|---|
| PD0, PD1 | USART | Comenzi telecomandă / jurnal |
| PD2, PD3 | Intrare | INT0, INT1 - encodere stâng/drept |
| PD4, PD7 | Ieșire | Sensul motoarelor stâng/drept |
| PB1, PB2 | Ieșire | OC1A, OC1B - PWM motoare |
| PB0, PB3 | Intrare | PCINT0/3 - ecoul ultrasunetelor |
| PC0...PC3 | Analogică | Cei patru senzori de linie |
| PC4, PC5 | Analog. / Intrare | Tensiune acumulator / buton urgență |
Nu a rămas niciun pin liber. Consecințe, toate decizii conștiente: (1) patru senzori de linie, nu șase - poziția se cunoaște mai grosier, robotul taie curbele la viteze mari. (2) I²C dispare - PC4/PC5 au fost date senzorului de tensiune și butonului de urgență. (3) nu mai există pin de test liber - soluția de compromis a fost reutilizarea pinului LED-ului de stare, cu prețul unui LED care clipește dezordonat în timpul măsurătorilor.
5Timerele, canalele analogice și întreruperile10 min
Timer1 generează cele două semnale PWM pentru motoare, în modul PWM rapid pe opt biți, prescalare 8: frecvența rezultată e 16.000.000/(8·256) = 7812,5 Hz, peste domeniul audibil, ceea ce elimină fluieratul motoarelor. Timer2 produce ticul de 10 ms al buclei, în mod CTC, prescalare 1024, comparator la 155: perioada e 1024·156/16.000.000 = 9,98 ms. Timer0 rămâne bazei de timp în microsecunde, pentru măsurarea ecourilor.
Manualul recomandă captura pe ICP1 pentru măsurarea precisă a lățimii unui impuls - dar aici Timer1 e deja ocupat de PWM pe opt biți, numărătorul lui se rotește la fiecare 128 µs, în timp ce un ecou poate dura până la 17,5 ms. Compromisul acceptat: citirea bazei de timp în microsecunde la cele două fronturi, rezoluție 4 µs. Sunetul parcurge dus-întors ~1cm în 58 µs, deci 4 µs înseamnă sub un milimetru - mult sub eroarea proprie a senzorului. Compromisul se sprijină pe un calcul, nu pe o impresie.
Convertorul analog-numeric are șase canale accesibile - patru pentru senzorii de linie, unul pentru tensiunea acumulatorului. La prescalarea 128, ceasul ADC e 125 kHz, o conversie durează 13 perioade (104 µs); cele cinci conversii dintr-un ciclu consumă ~520 µs, peste 5% din perioada de 10 ms - nu mult, dar nici neglijabil.
Sursele de întrerupere folosite: INT0/INT1 (encodere), vectorul de schimbare de pin al portului B (ecouri), comparația lui Timer2 (ticul de sistem), recepția USART (comenzi). Vectorul de schimbare de pin e comun unui întreg port - rutina trebuie să deducă ce pin s-a schimbat, comparând valoarea curentă cu cea memorată, și se declanșează pe ambele fronturi, ceea ce e util aici, pentru că avem nevoie de amândouă.
Roțile au diametrul 80mm, discurile encoderelor 60 de fante, viteza maximă proiectată 0,6 m/s. ISR-ul durează măsurat ~4 µs, inclusiv salvarea contextului.
Vezi rezolvarea
Circumferința roții: π·80 = 251,3 mm; cu 60 de fante, un impuls la fiecare 251,3/60 = 4,19 mm. La 600 mm/s, o roată produce 600/4,19 = 143 impulsuri/s. Cu două roți și numărare pe un singur front: 286 întreruperi/s, deci 286·4 µs = 1,14 ms de procesor pe secundă, adică 0,11%. Chiar dublând rezoluția prin numărarea ambelor fronturi, încărcarea rămâne sub un sfert de procent. Numărarea în întrerupere e practic gratuită - justifică alegerea ei în locul scrutării.
6Arhitectura programului și mașina cu stări13 min
Arhitectura e cea hibridă din Cursul 10: întreruperile captează evenimentele rapide, o buclă principală ritmată de un tic de 10 ms ia deciziile. Regula de aur: nimic lent nu are voie să intre în buclă. Dacă bucla ar aștepta sincron ecoul unui senzor, ar sta blocată până la 17,5 ms - mai mult decât toată perioada ticului; robotul ar merge orb și ar ieși de pe traseu în curbă. De aceea ecoul se măsoară prin întreruperi, iar jurnalul se depune într-un tampon circular. Măsurată cu osciloscopul, lățimea impulsului de prelucrare a fost de ~1,1 ms - 11% din perioadă, mult sub limita de 50% cerută de CN1, rezervă care a permis mai târziu adăugarea odometriei.
Mașina cu stări
| Stare | Eveniment | Stare următoare |
|---|---|---|
| AȘTEPTARE | START | URMĂRIRE LINIE |
| URMĂRIRE LINIE | obstacol detectat | OCOLIRE |
| URMĂRIRE LINIE | linie sub prag | LINIE PIERDUTĂ |
| OCOLIRE | ocolire încheiată | URMĂRIRE LINIE |
| LINIE PIERDUTĂ | 2s fără linie | AȘTEPTARE |
| orice stare | buton urgență / STOP | URGENȚĂ |
volatile uint8_t bTic = 0; /* ridicat de ISR-ul lui Timer2 */
int main(void) {
motoareOprireImediata(); /* stare sigura INAINTE de configurare */
porturiInit(); pwmInit(); ticInit(); encodereInit();
ultrasuneteInit(); adcInit(); usartInit(38400);
sei();
for (;;) {
if (!bTic) continue; /* asteptam ticul; nicio intarziere activa */
bTic = 0;
odometrieActualizeaza(); senzoriLinieCiteste();
ultrasunetePlanifica(); alimentareVerifica();
if (butonUrgenta() || comandaStop()) {
motoareOprireImediata(); stare = ST_URGENTA;
}
switch (stare) {
case ST_URMARIRE:
if (distantaFata() < D_OBSTACOL_MM) { ocolireIncepe(); stare = ST_OCOLIRE; }
else if (!linieVizibila()) { cronometruPornire(&tCautare, 2000); stare = ST_LINIE_PIERDUTA; }
else regulatorLinie();
break;
/* ... celelalte cazuri, cate unul per stare ... */
default: /* stare imposibila: oprire preventiva */
motoareOprireImediata(); stare = ST_URGENTA; break;
}
jurnalUmpleTampon(); /* depune octeti, nu asteapta transmisia */
}
}
Verificarea condițiilor de urgență se face înaintea instrucțiunii de selecție, deci se aplică din orice stare, iar ramura implicită duce sistemul în starea sigură - dacă variabila de stare ajunge, dintr-un motiv oarecare, la o valoare imposibilă, robotul se oprește.
7Comanda motoarelor: zonă moartă, rampă, urgență10 min
Motoarele de curent continuu se comandă în PWM, nu în tensiune continuă variabilă - inductanța înfășurării netezește curentul, motorul se comportă ca și cum ar primi tensiunea medie, iar elementul de comutație disipă puțin. Sensul se obține inversând polaritatea printr-o punte H. Regula absolută: cele două brațe ale aceleiași ramuri nu conduc niciodată simultan, altfel e scurtcircuit direct pe acumulator.
Trei fenomene fizice trebuie tratate explicit. Zona moartă: sub un anumit factor de umplere, cuplul nu învinge frecarea statică din reductor, motorul rămâne nemișcat dar consumă curent. Necompensată, regulatorul produce, pentru erori mici, comenzi care nu se materializează în nicio mișcare. Compensarea comprimă domeniul util al comenzii peste intervalul dintre pragul măsurat și valoarea maximă. Saltul de comandă: o trecere bruscă de la zero la maxim cere un curent limitat doar de rezistența înfășurării - cade tensiunea pe acumulator (poate reseta microcontrolerul), patinează roțile (strică odometria). Soluția: o rampă, limitarea variației comenzii pe ciclu; cu pas de 8 unități pe 10 ms, trecerea 0→255 durează 319 ms, imperceptibilă dar suficientă să elimine vârful de curent.
CF5 cere zero în ≤50 ms; rampa ar avea nevoie de peste 300 ms. Funcția de oprire imediată scrie direct zero în registrele de comparare, fără limitarea de variație - o excepție justificată de siguranță, care trebuie scrisă în comentariu, altfel un cititor ulterior o „corectează”.
#define PWM_MIN 40 /* masurat: sub acest prag motorul nu se roteste */
#define RAMPA_PAS 8 /* variatie maxima a comenzii intr-un tic de 10 ms */
/* Comprima domeniul util 1..255 peste PWM_MIN..PWM_MAX */
static uint8_t pwmDinComanda(int16_t modul) {
if (modul <= 0) return 0;
if (modul > 255) modul = 255;
return (uint8_t)(PWM_MIN + ((uint32_t)modul * (PWM_MAX - PWM_MIN)) / 255);
}
static int16_t aplicaRampa(int16_t curent, int16_t dorit) {
if (dorit > curent + RAMPA_PAS) return curent + RAMPA_PAS;
if (dorit < curent - RAMPA_PAS) return curent - RAMPA_PAS;
return dorit;
}
/* Oprire de urgenta: ocoleste DELIBERAT rampa, pt. cerinta de 50 ms. */
void motoareOprireImediata(void) {
OCR1A = 0; OCR1B = 0;
cmdStangaAplicata = 0; cmdDreaptaAplicata = 0;
}
8Odometria din encodere10 min
Fiecare roată motoare poartă un disc cu fante, citit de o pereche LED-fototranzistor. Cu un disc de 60 de fante și roată de 80 mm, un front corespunde la 4,19 mm de drum.
Un encoder cu un singur canal nu poate distinge sensul de rotație. Soluția riguroasă - encoder în cuadratură - ar cere alte două intrări de întrerupere, pe care nu le avem. Soluția de compromis: rutina adună contorul cu semnul comenzii date motorului, presupunând că roata se învârte încotro a fost trimisă. Presupunerea e falsă la frânare (inerția duce roata mai departe) și când o roată e blocată și împinsă înapoi - ambele introduc erori de odometrie, acceptate ca preț al economiei de pini.
volatile int32_t nImpulsStanga = 0, nImpulsDreapta = 0;
volatile int8_t sensStanga = +1, sensDreapta = +1; /* scris de motoareComanda(), citit de ISR */
ISR(INT0_vect) { nImpulsStanga += sensStanga; } /* front crescator, encoder stang */
ISR(INT1_vect) { nImpulsDreapta += sensDreapta; }
/* Contorul are 4 octeti; citirea se protejeaza, dar starea anterioara a bitului I
se reface, ca sa nu validam intreruperile intr-o sectiune unde erau deja oprite. */
int32_t encoderCiteste(volatile int32_t *pContor) {
int32_t v; uint8_t sreg = SREG;
cli(); v = *pContor; SREG = sreg;
return v;
}
Într-un ciclu de 10 ms, contoarele cresc cu 12 impulsuri (stânga) și 10 (dreapta). Ecartamentul robotului e 150 mm. Se cer vitezele și eroarea de cuantizare.
Vezi rezolvarea
Direct pe fereastra de 10 ms: 12·4,19/0,01 = 5030 mm/s - absurd pentru un robot mic. Motivul: la 0,5 m/s, în 10 ms sosește doar ~1 impuls/roată, rezultatul e dominat de cuantizare. Refăcut pe o fereastră de 100 ms, cu aceleași 12 și 10 impulsuri: vs=503 mm/s, vd=419 mm/s, deci v=(503+419)/2=461 mm/s și ω=(419−503)/150=−0,56 rad/s (rotire spre dreapta). Cuantizarea introduce o incertitudine de un impuls, adică 4,19/0,1=41,9 mm/s, ~8% din viteză. Concluzie practică: fereastra de calcul trebuie mai lungă decât ciclul de reglare - contoarele se citesc la 10 ms, dar viteza se calculează pe ultimele zece citiri, cu o întârziere de 100 ms acceptabilă, pentru că viteza servește la raportare, nu la urmărirea liniei.
9Urmărirea liniei: regulatorul proporțional11 min
Cei patru senzori de linie sunt perechi LED-fototranzistor spre podea. Prima operație obligatorie e normalizarea: pentru fiecare senzor se memorează, la o calibrare pe pistă înainte de probă, valoarea pe fond deschis și pe bandă, iar valoarea citită se aduce prin interpolare liniară la o scară comună 0-100. Fără ea, diferențele dintre exemplarele de fototranzistoare ar face senzorii necomparabili, iar poziția calculată ar fi deplasată sistematic.
Poziția liniei e o medie ponderată: fiecărui senzor i se atribuie o poziție convențională (−3, −1, +1, +3), iar eroarea e centrul de greutate al răspunsurilor normalizate. Suma răspunsurilor servește dublu - dacă e sub un prag, niciun senzor nu vede banda, linia e pierdută (implementarea concretă a cerinței CN4).
#define KP_LINIE 18 /* unitati de comanda pe unitate de eroare */
#define PRAG_LINIE 40 /* suma normalizata sub care linia e pierduta */
static const int8_t pozitie[4] = { -3, -1, +1, +3 };
int16_t linieEroare(const uint8_t n[4], int16_t *pSuma) {
int16_t suma = 0; int32_t moment = 0;
for (uint8_t i = 0; i < 4; i++) { suma += n[i]; moment += (int32_t)pozitie[i] * n[i]; }
*pSuma = suma;
if (suma < PRAG_LINIE) return 0; /* eroare nedefinita: linia e pierduta */
return (int16_t)(moment * 100 / suma);
}
void regulatorLinie(void) {
int16_t suma, e = linieEroare(nSenzor, &suma);
int16_t u = (int16_t)(((int32_t)KP_LINIE * e) / 100);
motoareComanda(VITEZA_BAZA + u, VITEZA_BAZA - u);
}
Corecția e proporțională cu eroarea, adunată la comanda unei roți și scăzută din cealaltă. Cu Kp prea mic, robotul reacționează leneș, taie curbele pe interior; cu Kp prea mare, oscilează cu amplitudine crescândă în jurul liniei. Limita superioară a lui Kp e dată de întârzierea totală din buclă (perioada ciclului, constanta de timp a motoarelor, inerția robotului).
Senzorii, normalizați, indică 5, 20, 90, 35 (stânga→dreapta). Viteza de bază 120, Kp=18.
Vezi rezolvarea
Suma = 5+20+90+35 = 150 (peste pragul 40, linia e vizibilă). Momentul = (−3·5)+(−1·20)+(1·90)+ (3·35) = −15−20+90+105 = 160. Eroarea (sutimi) = 160·100/150 = 106, adică 1,06 unități spre dreapta. Corecția u = 18·106/100 = 19. Comenzi: stânga 120+19=139, dreapta 120−19=101 - robotul virează spre dreapta, către bandă. Eroarea maximă posibilă e ±3 unități (±300 sutimi), deci u ∈ [−54, 54], iar comenzile rămân în [66, 174] - nu se saturează niciodată la 255, proprietate bună: dacă s-ar satura la eroare maximă, robotul ar pierde capacitatea de a mai corecta, exact în situația cea mai grea. Toate calculele s-au făcut cu numere întregi, factor de scară 100 explicit - pe un microcontroler fără virgulă mobilă, nu e o preferință de stil, ci diferența dintre câteva microsecunde și câteva sute.
10Planul de testare, cu nivelul de teren8 min
Planul urmează cele patru niveluri din Cursul 10, cu o particularitate: ultimul nivel nu se poate face în laborator. Un robot impecabil pe masa de lucru poate eșua pe pistă din motive care n-au nimic de-a face cu programul - iluminarea sălii, aderența pardoselii.
Nivelul de modul: funcțiile pure (eroarea de poziție, compresia peste zona moartă, rampa) compilate pentru calculatorul gazdă, încercate la limite. Nivelul de subsistem: roți ridicate de pe sol, comandă crescătoare pentru a găsi pragul zonei moarte; rotire manuală de zece ture pentru a verifica 600 de impulsuri la encoder. Nivelul de integrare: motoarele pornite mai numără corect encoderele, sau perturbațiile punții produc fronturi false? Nivelul de teren: scenarii complete pe pistă.
| Test | Cerință | Mod de efectuare | Criteriu |
|---|---|---|---|
| T2 | - | roți ridicate, comandă crescătoare | prag zonei moarte identic ±5 la ambele roți |
| T6 | - | motoare la comandă maximă, roți blocate | contoarele nu cresc cu fronturi parazite |
| T8 | CF5 | buton urgență la viteză maximă, 20 repetări | comanda punții la zero în <50ms |
| T11 | - | caractere aleatoare pe interfața serială | cadre invalide ignorate, fără blocaj |
11Ce a mers și ce nu8 min
Un studiu de caz care raportează numai succese nu e de niciun folos - greșelile se repetă cu regularitate la fiecare generație de echipe.
A mers ceea ce a fost decis pe hârtie înainte de a fi construit: partiționarea cu interfețe scrise a permis ca modulul de tracțiune să fie înlocuit la jumătatea proiectului fără nicio modificare în restul programului; mașina cu stări a dat un comportament definit situațiilor neprevăzute; regula „nimic lent în buclă” n-a trebuit niciodată reconsiderată.
Nu a mers ceea ce a fost decis din mers. Prima greșeală: calibrarea senzorilor cu valori compilate în program - la concurs, iluminarea și pardoseala erau altele, robotul n-a mai văzut banda. Remediul: o calibrare pornită prin butonul de start, cu robotul plimbat manual peste bandă. A doua: alimentarea comună a electronicii și motoarelor - la accelerare bruscă, tensiunea cădea suficient încât microcontrolerul se reseta în mijlocul pistei. Remedierile: un condensator mare la intrarea stabilizatorului, rampa de accelerare, și un circuit de supraveghere a tensiunii. A treia: încrederea în odometrie ca sursă de poziție absolută - erorile se acumulează, iar după câțiva metri poziția estimată se depărtează vizibil de cea reală; utilă pentru manevre scurte, nu pentru navigație pe termen lung fără corecție periodică.
Au fost descoperite la trecerea de la laborator la mediul real - exact nivelul de testare pe care echipele îl programează ultimul și îl scurtează primul când timpul se termină. Concluzia practică: se merge pe pista reală cât mai devreme, cu un robot incomplet, nu târziu cu unul terminat.
Nimic din ce a făcut acest proiect posibil n-a fost o cunoștință nouă despre ATmega328P - registrele timerelor, întreruperile, lanțul ADC erau toate cunoscute din capitolele anterioare. Ceea ce a decis rezultatul a fost ordinea deciziilor, disciplina de a scrie interfețele înaintea implementărilor și obiceiul de a verifica prin măsurare, nu prin presupunere - diferența dintre a ști să programezi un microcontroler și a ști să proiectezi un sistem cu microcontroler.
12Erori frecvente4 min
- „Calibrăm senzorii o dată, în laborator, și punem pragurile în cod." Iluminarea și culoarea pardoselii de la concurs diferă de cele din laborator - robotul nu mai vede banda deloc. Calibrarea trebuie făcută la fața locului, printr-o procedură pornită la fața locului (buton dedicat), niciodată presupusă din valori compilate.
- „Electronica și motoarele se alimentează de la același acumulator, ca să fie mai simplu." Vârful de curent la accelerare bruscă face tensiunea să cadă suficient încât microcontrolerul se resetează. Condensator mare la intrarea stabilizatorului, rampă de accelerare și circuit de supraveghere a tensiunii, aplicate împreună.
- „Odometria ne dă poziția robotului, deci o putem folosi pentru navigație pe distanțe lungi." Cuantizarea, patinarea și sensul presupus (nu măsurat) al roților se acumulează - eroarea crește nemărginit cu distanța. Odometria e utilă doar pentru manevre scurte, unde eroarea n-are timp să se adune; pentru distanțe lungi e nevoie de o corecție periodică independentă.
13Rezumat și glosar5 min
Un proiect complet arată că metoda din Cursul 10 se comportă la fel sub presiunea resurselor insuficiente ca și pe exemplul mic: interfețele scrise dinainte permit dezvoltare în paralel și înlocuirea unui subsistem fără a strica restul; bugetul de resurse (pini, timere, canale ADC, întreruperi) transformă „microcontrolerul ăsta ar trebui să fie suficient” într-o listă verificabilă, iar saturarea lui obligă la compromisuri explicite, documentate, nu întâmplătoare; mașina cu stări face imposibile prin construcție combinațiile periculoase; regula „nimic lent în buclă” se verifică prin măsurătoare cu osciloscopul, nu prin presupunere; comanda motoarelor cere tratarea explicită a zonei moarte, a saltului de comandă și a excepției de oprire de urgență; odometria numără în întrerupere și calculează în buclă, pe o fereastră suficient de lungă pentru a domina zgomotul de cuantizare; urmărirea liniei e un regulator proporțional simplu, dar cu normalizare obligatorie și cu Kp limitat de întârzierea totală a buclei; iar planul de testare adaugă, față de proiectele de laborator, un nivel de teren care nu poate fi înlocuit. Lecția finală nu ține de registre, ci de disciplină: interfețele înaintea implementării, măsurătoarea înaintea presupunerii.
14Întrebări de verificare7 min
- Transformați cerința „robotul trebuie să evite coliziunile” în două-trei cerințe verificabile, cu valori numerice și metoda de măsurare.
- Explicați de ce butonul de oprire de urgență nu trebuie să acționeze numai prin software.
- De ce nu a putut fi folosit modulul de captură al lui Timer1 pentru măsurarea ecoului?
- Un coleg mută calculul vitezelor din bucla principală în ISR-ul encoderului, „ca să fie mai actual”. Ce se strică?
- Ce este zona moartă a unui motor cu reductor și ce comportament produce, necompensată, la un robot urmăritor de linie?
- Descrieți procedura de calibrare a senzorilor de linie pe pistă și explicați de ce valorile compilate în program nu o pot înlocui.
15Încheierea disciplinei2 min
Acesta este ultimul curs al disciplinei Microcontrollere și Microprocesoare. Drumul complet - de la biții și registrele unui microcontroler izolat, până la un sistem autonom care trebuie să funcționeze corect din prima încercare, pe o pistă necunoscută - a folosit, la fiecare pas, aceleași principii: măsoară, nu presupune; scrie interfața înainte de implementare; testează pe straturi.
Aplicarea integrată a tuturor acestor noțiuni - achiziție, decizie, comandă, fără
delay() - se exersează în Laboratorul
07, ultima lucrare de laborator a disciplinei.