Table of Contents

Laborator: NXP Cup Car

Obiective

La finalul laboratorului veți putea:

Context: NXP Cup

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ă:

Mașina NXP: componente principale

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ță

Cum funcționează controlul

Î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.

Controller PID

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;

Idee de implementare

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.

Materiale primite

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.

Exercițiul 1: Reglarea controllerului PID pe mașină

Scop

Reglați parametrii kp, ki și kd astfel încât mașina să urmărească linia cât mai stabil.

Ce primiți

Exemplu de fișier de configurare:

kp=0.35
ki=0.00
kd=0.08
speed=0.40

Cerințe

  1. Porniți de la ki = 0.
  2. Creșteți kp până când mașina începe să urmărească linia, dar fără oscilații mari.
  3. Creșteți kd pentru a reduce oscilațiile.
  4. Folosiți ki doar dacă mașina are o abatere persistentă într-o parte.
  5. Reduceți viteza dacă mașina devine instabilă în curbe.
  6. Notați combinația de parametri care a funcționat cel mai bine.

Încărcare pe mașină

./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

Întrebări

Exercițiul 2: Estimarea erorii din vectorul PixyCam2

Scop

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.

Interfață

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]:

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

Exemple pentru frame_width = 79

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

Test local

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.

Exercițiul 3: Limitare și conversie comandă servo

Scop

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.

Context

Controllerul PID produce o valoare abstractă, de exemplu în intervalul [-1.0, 1.0]:

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

Interfață

Implementați funcția:

int pid_output_to_servo_us(float pid_output);

Funcția trebuie să:

  1. limiteze pid_output la intervalul [-1.0, 1.0];
  2. convertească liniar valoarea limitată la intervalul [1000, 2000];
  3. returneze rezultatul ca întreg.

Formula recomandată:

servo_us = 1500 + pid_output * 500

Exemple

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

Test local

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.

Livrabile

La finalul laboratorului încărcați:

Criterii de evaluare

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%

Recomandări