La finalul laboratorului veți putea:
NXP Cup este un concurs de robotică în care echipele construiesc și programează o mașină autonomă la scară mică. Obiectivul tipic este parcurgerea unui traseu marcat pe sol, cât mai rapid și cât mai stabil, fără intervenție umană.
Într-o rundă de concurs, mașina trebuie să:
O mașină NXP Cup conține, în general, următoarele blocuri:
| Componentă | Rol | Exemple de probleme practice |
|---|---|---|
| Microcontroller | Rulează codul de control în timp real | frecvență de eșantionare, latență, limitări de memorie |
| PixyCam2 | Detectează vectori ai traseului în imagine | calibrare, lumină ambientală, vector pierdut, intersecții |
| Servo direcție | Virează roțile față | limitare mecanică, saturație, răspuns neliniar |
| Motor / driver motor | Controlează viteza mașinii | inerție, derapaj, limitare de curent |
| Encoder / feedback viteză | Estimează viteza roților | impulsuri lipsă, cuantizare, perioade de eșantionare |
| Baterie | Alimentează sistemul | scădere de tensiune, variație de performanță |
În fiecare iterație a buclei de control, mașina execută aproximativ pașii de mai jos:
1. Citește vectorii raportați de PixyCam2. 2. Calculează eroarea de direcție din vectorul detectat de PixyCam2. 3. Calculează eroarea: error = 0 - pixy_error. 4. Aplică un controller PID pe eroare. 5. Transformă ieșirea PID într-o comandă pentru servo. 6. Alege viteza motorului în funcție de stabilitate și de curbură. 7. Trimite comenzile către actuatoare. 8. Repetă la următorul pas de timp.
Ideea importantă este că mașina nu „știe” traseul dinainte. Ea reacționează continuu la măsurători. Dacă linia este la stânga, trebuie să vireze stânga; dacă linia este la dreapta, trebuie să vireze dreapta; dacă linia este aproape de centru, trebuie să meargă drept.
Un controller PID folosește trei termeni:
| Termen | Formulă conceptuală | Efect |
|---|---|---|
| P - proporțional | depinde de eroarea curentă | reacționează rapid la abaterea față de linie |
| I - integral | acumulează eroarea în timp | corectează erori persistente |
| D - derivativ | depinde de variația erorii | reduce oscilațiile și anticipează schimbările rapide |
Formula discretă folosită în laborator este:
integral = integral + error * dt; derivative = (error - previous_error) / dt; output = kp * error + ki * integral + kd * derivative; previous_error = error;
După calcul, ieșirea se limitează la intervalul acceptat de servo:
if (output > max_output) output = max_output; if (output < min_output) output = min_output;
O implementare simplă pentru urmărirea liniei poate folosi următoarea arhitectură:
pixy.c -> citire vectori PixyCam2 pixy_vector.c -> estimarea erorii din vectorul PixyCam2 pid.c -> controller PID steering.c -> conversie PID output -> comandă servo speed.c -> control viteză main.c -> bucla principală de control
Pentru laborator nu aveți nevoie să modificați tot codul mașinii. Veți lucra pe exerciții izolate, cu teste automate, iar la final veți încărca pe mașină doar binarul pentru exercițiul de PID.
Veți primi:
Nu veți primi codul complet al mașinii. Scopul este să lucrați pe interfețe clare, asemănător cu situațiile în care integrați un modul într-un sistem existent. În proiectul folosit la laborator, informația despre traseu vine de la PixyCam2, nu de la o bară de senzori reflectivi.
Reglați parametrii kp, ki și kd astfel încât mașina să urmărească linia cât mai stabil.
pid_config.txt cu parametrii editabili;flash_car.sh;Exemplu de fișier de configurare:
kp=0.35 ki=0.00 kd=0.08 speed=0.40
ki = 0.kp până când mașina începe să urmărească linia, dar fără oscilații mari.kd pentru a reduce oscilațiile.ki doar dacă mașina are o abatere persistentă într-o parte../flash_car.sh pid_config.txt
După încărcare, testați mașina pe traseu și completați tabelul:
| Încercare | kp | ki | kd | speed | Observații |
|---|---|---|---|---|---|
| 1 | |||||
| 2 | |||||
| 3 | |||||
| 4 |
kp este prea mic?kp este prea mare?kd?Implementați o funcție care primește un vector detectat de PixyCam2 și returnează eroarea de direcție normalizată față de centrul imaginii.
Acest exercițiu se face pe laptop și nu necesită mașina.
Implementați funcția:
typedef struct { int x0; int y0; int x1; int y1; } PixyVector; float estimate_pixy_vector_error(PixyVector vector, int frame_width);
PixyCam2 raportează vectori în coordonate de imagine. În acest exercițiu folosim doar vectorul principal al traseului. Coordonata x crește de la stânga la dreapta, iar coordonata y crește de sus în jos. Pentru a decide direcția, folosiți capătul de jos al vectorului, adică punctul cu y mai mare. Dacă y0 == y1, folosiți media dintre x0 și x1.
Funcția trebuie să întoarcă o eroare normalizată în intervalul [-1.0, 1.0]:
-1.0 înseamnă că vectorul este la marginea stângă a imaginii;0.0 înseamnă că vectorul este în centrul imaginii;1.0 înseamnă că vectorul este la marginea dreaptă a imaginii.
Dacă frame_width ⇐ 1, funcția trebuie să returneze 0.0. Înainte de normalizare, limitați coordonata x la intervalul [0, frame_width - 1].
Formula recomandată este:
center = (frame_width - 1) / 2.0 error = (x - center) / center
| Vector | Rezultat aproximativ | Explicație |
|---|---|---|
{39, 0, 39, 51} | 0.0 | capătul de jos este în centru |
{39, 0, 0, 51} | -1.0 | capătul de jos este la stânga |
{39, 0, 78, 51} | 1.0 | capătul de jos este la dreapta |
{39, 0, 52, 51} | aproximativ 0.333 | capătul de jos este ușor la dreapta |
{20, 20, 58, 20} | 0.0 | vector orizontal: se folosește media x |
Un posibil testbench este inclus în arhiva de laborator în exercise2_pixy_vector/test_pixy_vector.c.
Compilare și rulare din arhiva de laborator:
cd nxp_car_lab_skeleton make test-pixy
Dacă programul se termină fără eroare, testele au trecut.
Implementați conversia dintre ieșirea controllerului PID și comanda trimisă către servo.
Acest exercițiu se face pe laptop și nu necesită mașina.
Controllerul PID produce o valoare abstractă, de exemplu în intervalul [-1.0, 1.0]:
-1.0 înseamnă viraj maxim stânga;0.0 înseamnă roți drepte;1.0 înseamnă viraj maxim dreapta.Servo-ul primește un impuls PWM în microsecunde. În acest exercițiu folosim convenția:
| Comandă | PWM |
|---|---|
| viraj maxim stânga | 1000 |
| centru | 1500 |
| viraj maxim dreapta | 2000 |
Implementați funcția:
int pid_output_to_servo_us(float pid_output);
Funcția trebuie să:
pid_output la intervalul [-1.0, 1.0];[1000, 2000];Formula recomandată:
servo_us = 1500 + pid_output * 500
| pid_output | Rezultat așteptat |
|---|---|
-1.0 | 1000 |
-0.5 | 1250 |
0.0 | 1500 |
0.5 | 1750 |
1.0 | 2000 |
2.0 | 2000 |
-2.0 | 1000 |
Un posibil testbench:
#include <assert.h> int pid_output_to_servo_us(float pid_output); int main(void) { assert(pid_output_to_servo_us(-1.0f) == 1000); assert(pid_output_to_servo_us(-0.5f) == 1250); assert(pid_output_to_servo_us(0.0f) == 1500); assert(pid_output_to_servo_us(0.5f) == 1750); assert(pid_output_to_servo_us(1.0f) == 2000); assert(pid_output_to_servo_us(2.0f) == 2000); assert(pid_output_to_servo_us(-2.0f) == 1000); return 0; }
Compilare și rulare din arhiva de laborator:
cd nxp_car_lab_skeleton make test-steering
Dacă programul se termină fără eroare, testele au trecut.
La finalul laboratorului încărcați:
pid_config.txt cu cea mai bună combinație găsită;estimate_pixy_vector_error;pid_output_to_servo_us;| Componentă | Punctaj |
|---|---|
| Explicații despre reglarea PID și observații din testarea pe mașină | 30% |
| Parametri PID funcționali pe traseu | 25% |
| Exercițiul 2: estimarea erorii din vectorul PixyCam2 | 20% |
| Exercițiul 3: conversie comandă servo | 15% |
| Claritate, cod simplu, teste rulate local | 10% |
kp sau creșteți ușor kd.kp.