Laborator 3: NXP Cup Car

Obiective

La finalul laboratorului veți putea:

  • să explicați pe scurt ce este NXP Cup și care sunt componentele principale ale mașinii;
  • să descrieți fluxul de date dintre senzori, algoritmul de control și actuatoare;
  • să reglați un controller PID pentru urmărirea liniei;
  • să implementați și să testați local două module software utile pentru o mașină autonomă de tip line follower.

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

  • citească traseul folosind senzori;
  • estimeze poziția față de linie;
  • decidă direcția și viteza potrivite;
  • comande servo-ul de direcție și motoarele;
  • rămână stabilă la curbe, intersecții și schimbări de contrast.

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
Senzori de linie Măsoară poziția liniei față de mașină zgomot, calibrare, lumină ambientală, pierderea liniei
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 senzorii de linie.
2. Calculează poziția liniei față de centrul mașinii.
3. Calculează eroarea: error = target_position - measured_position.
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ă:

sensors.c        -> citire și calibrare senzori
line_position.c  -> estimarea poziției liniei
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:

  • binarul de bază pentru mașină;
  • un fișier de configurare pentru parametrii PID;
  • un script de încărcare pe placă;
  • schelete de cod pentru exercițiile locale;
  • teste automate pentru verificarea exercițiilor locale.

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.

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

  • un binar precompilat pentru mașină;
  • un fișier pid_config.txt cu parametrii editabili;
  • un script de încărcare, de exemplu flash_car.sh;
  • acces la mașină pentru testarea finală.

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

  • Ce se întâmplă când kp este prea mic?
  • Ce se întâmplă când kp este prea mare?
  • Cum se schimbă comportamentul când măriți kd?
  • A fost necesar un termen integral? De ce?

Exercițiul 2: Estimarea poziției liniei

Scop

Implementați o funcție care primește valorile senzorilor de linie și returnează poziția estimată a liniei față de centrul mașinii.

Acest exercițiu se face pe laptop și nu necesită mașina.

Interfață

Implementați funcția:

float estimate_line_position(const int sensors[], int n);

Valorile din sensors sunt intensități normalizate între 0 și 1000, unde o valoare mai mare înseamnă că senzorul vede mai puternic linia.

Pozițiile senzorilor sunt distribuite uniform în intervalul [-1.0, 1.0]. Pentru n = 5, pozițiile sunt:

senzor:    0     1     2     3     4
poziție: -1.0  -0.5   0.0   0.5   1.0

Poziția liniei se calculează ca medie ponderată:

position = sum(sensor_value[i] * sensor_position[i]) / sum(sensor_value[i])

Dacă suma valorilor este 0, funcția trebuie să returneze 0.0.

Exemple

Intrare Rezultat aproximativ Explicație
[0, 0, 1000, 0, 0] 0.0 linia este în centru
[1000, 0, 0, 0, 0] -1.0 linia este complet la stânga
[0, 0, 0, 0, 1000] 1.0 linia este complet la dreapta
[0, 500, 1000, 500, 0] 0.0 linia este centrată
[0, 0, 500, 1000, 0] aproximativ 0.333 linia este ușor la dreapta

Test local

Un posibil testbench:

#include <assert.h>
#include <math.h>
 
float estimate_line_position(const int sensors[], int n);
 
static void almost_equal(float a, float b) {
    assert(fabsf(a - b) < 0.02f);
}
 
int main(void) {
    int centered[] = {0, 0, 1000, 0, 0};
    int left[] = {1000, 0, 0, 0, 0};
    int right[] = {0, 0, 0, 0, 1000};
    int symmetric[] = {0, 500, 1000, 500, 0};
    int slight_right[] = {0, 0, 500, 1000, 0};
    int missing[] = {0, 0, 0, 0, 0};
 
    almost_equal(estimate_line_position(centered, 5), 0.0f);
    almost_equal(estimate_line_position(left, 5), -1.0f);
    almost_equal(estimate_line_position(right, 5), 1.0f);
    almost_equal(estimate_line_position(symmetric, 5), 0.0f);
    almost_equal(estimate_line_position(slight_right, 5), 0.333f);
    almost_equal(estimate_line_position(missing, 5), 0.0f);
 
    return 0;
}

Compilare și rulare:

gcc -Wall -Wextra -std=c11 line_position.c test_line_position.c -lm -o test_line_position
./test_line_position

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

  • -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

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:

gcc -Wall -Wextra -std=c11 steering.c test_steering.c -o test_steering
./test_steering

Dacă programul se termină fără eroare, testele au trecut.

Livrabile

La finalul laboratorului încărcați:

  • fișierul pid_config.txt cu cea mai bună combinație găsită;
  • răspunsurile la întrebările de la exercițiul 1;
  • implementarea pentru estimate_line_position;
  • implementarea pentru pid_output_to_servo_us;
  • capturi sau output text care arată că testele locale trec.

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 poziției liniei 20%
Exercițiul 3: conversie comandă servo 15%
Claritate, cod simplu, teste rulate local 10%

Recomandări

  • Schimbați un singur parametru PID la un moment dat.
  • Nu începeți cu viteză mare.
  • Dacă mașina oscilează stânga-dreapta, reduceți kp sau creșteți ușor kd.
  • Dacă mașina reacționează prea lent, creșteți kp.
  • Dacă pierde linia în curbe, reduceți viteza sau creșteți reacția controllerului.
  • Pentru exercițiile locale, testați și cazuri extreme, nu doar exemplele din enunț.
rasb/lab/03.txt · Last modified: 2026/06/25 16:09 by cezar.zlatea
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0