This shows you the differences between two versions of the page.
|
rasb:lab:03 [2026/06/25 16:09] cezar.zlatea |
rasb:lab:03 [2026/06/30 14:48] (current) rares.sarmasag [Lab 3: NXP Cup Autonomous Car] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Laborator 3: NXP Cup Car ====== | + | ====== Lab 3: NXP Cup Autonomous Car ====== |
| + | {{:rasb:lab:nxpcar-lab.zip|Lab 3 skel}} | ||
| + | ===== Duration ===== | ||
| - | ===== Obiective ===== | + | 2 hours: |
| + | * 0h30 theoretical introduction to NXP Cup, vehicle dynamics, and PID control; | ||
| + | * 1h30 practical tuning and modular firmware development. | ||
| - | La finalul laboratorului veți putea: | + | ===== Learning Objectives ===== |
| - | * 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 ===== | + | After this laboratory, students should be able to: |
| + | * Explain the data flow in an autonomous line-follower (sensors, control, actuators); | ||
| + | * Describe the role of Proportional, Integral, and Derivative terms in a PID controller; | ||
| + | * Tune a PID controller experimentally on physical or emulated hardware; | ||
| + | * Implement and validate coordinate mapping algorithms for line tracking camera sensors; | ||
| + | * Map abstract controller commands to physical servo PWM pulse widths. | ||
| - | 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ă. | + | ===== Laboratory Scenario ===== |
| - | Într-o rundă de concurs, mașina trebuie să: | + | The lab focuses on programming and tuning an autonomous line-following vehicle. The system utilizes a PixyCam2 camera for line detection, a PID controller for trajectory correction, and a steering servomotor. |
| - | * 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 ===== | + | ``` |
| + | [PixyCam2 Camera] -> vector path -> [Error Estimator (Ex 2)] -> error -> [PID Controller] -> output -> [Servo Command (Ex 3)] -> PWM -> [Steering Servo] | ||
| + | ``` | ||
| - | O mașină NXP Cup conține, în general, următoarele blocuri: | + | In each control loop iteration, the vehicle executes the following sequence: |
| + | <code text> | ||
| + | 1. Read the path vectors reported by PixyCam2. | ||
| + | 2. Estimate the lateral steering error from the detected vector. | ||
| + | 3. Compute the tracking error: error = 0.0f - estimated_error. | ||
| + | 4. Apply the PID control algorithm to the tracking error. | ||
| + | 5. Map the PID controller output to a physical servo command. | ||
| + | 6. Adjust the motor speed profile based on path curvature and stability. | ||
| + | 7. Write commands to the actuators (servo and ESC). | ||
| + | 8. Wait for the next control cycle. | ||
| + | </code> | ||
| - | ^ Componentă ^ Rol ^ Exemple de probleme practice ^ | + | The vehicle does not know the track geometry in advance; it reacts dynamically to real-time measurements. If the line shifts left, it steers left; if it shifts right, it steers right; if the line is centered, the wheels remain straight. |
| - | | 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 ===== | + | ===== Equipment Overview: The NXP Cup Platform ===== |
| - | În fiecare iterație a buclei de control, mașina execută aproximativ pașii de mai jos: | + | An NXP Cup autonomous vehicle consists of the following primary components: |
| - | <code text> | + | ^ Component ^ Role ^ Practical Engineering Challenges ^ |
| - | 1. Citește senzorii de linie. | + | | Microcontroller | Runs the real-time control loop | sampling frequency, latency, memory constraints | |
| - | 2. Calculează poziția liniei față de centrul mașinii. | + | | PixyCam2 | Detects path vectors in the image frame | calibration, ambient light, lost vectors, intersections | |
| - | 3. Calculează eroarea: error = target_position - measured_position. | + | | Steering Servo | Controls the front wheel angle | mechanical limits, saturation, non-linear response | |
| - | 4. Aplică un controller PID pe eroare. | + | | Motor / ESC | Drives the vehicle's propulsion | inertia, wheel slippage, current limits, battery sag | |
| - | 5. Transformă ieșirea PID într-o comandă pentru servo. | + | | Encoder | Measures real-time wheel speed | missing pulses, quantization noise, sampling delay | |
| - | 6. Alege viteza motorului în funcție de stabilitate și de curbură. | + | | Battery | Powers the logic board and motors | voltage drops, performance degradation under load | |
| - | 7. Trimite comenzile către actuatoare. | + | |
| - | 8. Repetă la următorul pas de timp. | + | |
| - | </code> | + | |
| - | 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 Theory: PID ===== |
| - | ===== Controller PID ===== | + | The PID controller computes the steering adjustment using three distinct terms: |
| - | Un controller PID folosește trei termeni: | + | ^ Term ^ Conceptual Formula ^ Physical Effect ^ |
| - | + | | P - Proportional | proportional to current error | reacts quickly to immediate deviations from the line | | |
| - | ^ Termen ^ Formulă conceptuală ^ Efect ^ | + | | I - Integral | accumulates error over time | corrects persistent steady-state offsets | |
| - | | P - proporțional | depinde de eroarea curentă | reacționează rapid la abaterea față de linie | | + | | D - Derivative | proportional to error rate-of-change | dampens overshoot and suppresses oscillations | |
| - | | 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: | + | |
| + | The discrete implementation used in the vehicle firmware is: | ||
| <code c> | <code c> | ||
| integral = integral + error * dt; | integral = integral + error * dt; | ||
| Line 67: | Line 67: | ||
| </code> | </code> | ||
| - | După calcul, ieșirea se limitează la intervalul acceptat de servo: | + | After computing the output, it is saturated to the safety limits of the steering servo: |
| <code c> | <code c> | ||
| if (output > max_output) output = max_output; | if (output > max_output) output = max_output; | ||
| Line 74: | Line 73: | ||
| </code> | </code> | ||
| - | ===== Idee de implementare ===== | + | ===== Project Layout ===== |
| - | O implementare simplă pentru urmărirea liniei poate folosi următoarea arhitectură: | + | The workspace is organized into three functional directories: |
| - | <code text> | + | * **''pid_tuning/''** — PlatformIO project for configuring and flashing the physical vehicle. |
| - | sensors.c -> citire și calibrare senzori | + | * ''platformio.ini'': PlatformIO configuration file. |
| - | line_position.c -> estimarea poziției liniei | + | * ''src/configpid.cpp'': Source file where you edit your vehicle's PID gains ($K_p$, $K_i$, $K_d$). |
| - | pid.c -> controller PID | + | * ''lib/libnxpcar.a'': Precompiled static library containing the vehicle's core autonomous driving logic. |
| - | steering.c -> conversie PID output -> comandă servo | + | * **''exercise2_pixy_vector/''** — Coordinate mapping and error estimation. |
| - | speed.c -> control viteză | + | * ''pixy_vector.c'' / ''.h'': Student implementation file and interface. |
| - | main.c -> bucla principală de control | + | * ''test_pixy_vector.o'': Precompiled local unit test suite object. |
| - | </code> | + | * **''exercise3_steering/''** — Steering actuator command conversion. |
| + | * ''steering.c'' / ''.h'': Student implementation file and interface. | ||
| + | * ''test_steering.o'': Precompiled local unit test suite object. | ||
| + | * **''test_runner''** — Precompiled interactive test runner TUI dashboard executable. | ||
| + | * **''Makefile''** — Compiles and links student implementations with precompiled test objects (via ''make test''). | ||
| - | 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. | + | Students do not need to modify the full vehicle firmware. You will implement and validate the core modules locally, write your PID gains in the configuration file, and flash the precompiled vehicle firmware. |
| - | ===== Materiale primite ===== | + | --- |
| - | Veți primi: | + | ===== Exercise 1: Steering PID Controller Flashing & Tuning ===== |
| - | * 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. | + | ==== Objective ==== |
| + | Tune the steering PID gains ($K_p$, $K_i$, $K_d$) of the physical vehicle by editing the configuration file, compiling, and flashing the firmware onto the Teensy 4.1 using PlatformIO. | ||
| - | ===== Exercițiul 1: Reglarea controllerului PID pe mașină ===== | + | ==== Materials ==== |
| + | * The student skeleton PlatformIO project inside ''pid_tuning/''; | ||
| + | * A Teensy 4.1 microcontroller on the NXP Cup Car; | ||
| + | * A USB-micro cable to connect the Teensy to your laptop. | ||
| - | ==== Scop ==== | + | ==== Procedure ==== |
| + | 1. Open the ''pid_tuning/'' directory in VS Code (make sure the **PlatformIO IDE** extension is installed). | ||
| + | 2. Open ''src/configpid.cpp'' and set your desired PID gains (do not modify the `extern` keyword as it is required to link with the precompiled library): | ||
| + | <code c> | ||
| + | extern const float STEER_KP = 1.8f; | ||
| + | extern const float STEER_KI = 0.00f; | ||
| + | extern const float STEER_KD = 0.20f; | ||
| + | </code> | ||
| + | 3. Connect the Teensy 4.1 on your vehicle to your computer via USB. | ||
| + | 4. Build and flash the project: | ||
| + | - In VS Code, click the **PlatformIO: Upload** button (arrow icon at the bottom status bar), or | ||
| + | - Open a terminal inside the ''pid_tuning/'' folder and run: | ||
| + | <code bash> | ||
| + | pio run -t upload | ||
| + | </code> | ||
| + | - PlatformIO will automatically compile your ''configpid.cpp'', link it against the precompiled static library ''lib/libnxpcar.a'', and upload the complete firmware to the vehicle! | ||
| + | 5. Disconnect the USB cable, place the vehicle on the track, and turn on the power switch to observe its behavior. | ||
| + | 6. To adjust the gains, turn off the vehicle, reconnect the Teensy to your laptop via USB, edit the values in ''src/configpid.cpp'', and re-flash. | ||
| + | 7. Start with the integral term disabled (''ki = 0.00''). | ||
| + | 8. Increase the proportional gain ''kp'' progressively (e.g., in steps of 0.2) until the car follows the line, but starts to oscillate left-and-right around the center. | ||
| + | 9. Increase the derivative gain ''kd'' to dampen the oscillations and smooth the vehicle's trajectory. | ||
| + | 10. Record your experimental runs in the table below. | ||
| - | Reglați parametrii ''kp'', ''ki'' și ''kd'' astfel încât mașina să urmărească linia cât mai stabil. | + | ==== Tuning Recommendations ==== |
| - | + | * **One Parameter at a Time**: Alter only a single PID gain parameter between experimental runs to isolate the physical effect of each gain. | |
| - | ==== Ce primiți ==== | + | * **Safety First**: Start testing with the vehicle on a stand or at low speeds before attempting high-speed runs to prevent physical damage to the vehicle. |
| - | + | * **Handling Oscillations**: If the vehicle exhibits high-frequency oscillations (wiggling), decrease ''kp'' or slightly increase ''kd''. | |
| - | * un binar precompilat pentru mașină; | + | * **Handling Sluggishness**: If the vehicle reacts too slowly to curves and drifts wide, increase ''kp''. |
| - | * un fișier ''pid_config.txt'' cu parametrii editabili; | + | * **Handling Curve Instability**: If the vehicle flies off the track in sharp turns, check if the steering controller gains need further tuning or if the track requires lower speed limits. |
| - | * un script de încărcare, de exemplu ''flash_car.sh''; | + | |
| - | * acces la mașină pentru testarea finală. | + | |
| - | + | ||
| - | Exemplu de fișier de configurare: | + | |
| + | ==== Telemetry & Diagnostics over USB Serial ==== | ||
| + | The Teensy car code automatically streams real-time CSV telemetry data over the USB Serial interface (at 115200 baud). If you plug the USB cable while the car is on a stand and open the PlatformIO Serial Monitor, you can observe the real-time CSV output: | ||
| <code text> | <code text> | ||
| - | kp=0.35 | + | CSV format: time,state,vecs,side,lat,heading,curv,conf,steer,motor,dt |
| - | ki=0.00 | + | |
| - | kd=0.08 | + | |
| - | speed=0.40 | + | |
| </code> | </code> | ||
| + | This is useful for verifying that the camera sees the track and the steering controller reacts correctly. | ||
| - | ==== Cerințe ==== | + | Test the vehicle on the track and document your findings: |
| - | - Porniți de la ''ki = 0''. | + | ^ Run ^ Kp ^ Ki ^ Kd ^ Observations ^ |
| - | - Creșteți ''kp'' până când mașina începe să urmărească linia, dar fără oscilații mari. | + | | 1 | | | | | |
| - | - Creșteți ''kd'' pentru a reduce oscilațiile. | + | | 2 | | | | | |
| - | - Folosiți ''ki'' doar dacă mașina are o abatere persistentă într-o parte. | + | | 3 | | | | | |
| - | - Reduceți viteza dacă mașina devine instabilă în curbe. | + | | 4 | | | | | |
| - | - Notați combinația de parametri care a funcționat cel mai bine. | + | |
| - | ==== Încărcare pe mașină ==== | + | ==== Questions & Observations ==== |
| + | * What physical behavior is observed when ''kp'' is too low? | ||
| + | * What physical behavior is observed when ''kp'' is too high? | ||
| + | * How does the vehicle's trajectory change as you increase ''kd''? | ||
| + | * Was an integral term ''ki'' necessary for stable tracking? Explain why. | ||
| - | <code bash> | + | --- |
| - | ./flash_car.sh pid_config.txt | + | |
| - | </code> | + | |
| - | După încărcare, testați mașina pe traseu și completați tabelul: | + | ===== Exercise 2: PixyCam2 Vector Error Estimation ===== |
| - | ^ Încercare ^ kp ^ ki ^ kd ^ speed ^ Observații ^ | + | ==== Objective ==== |
| - | | 1 | | | | | | | + | Implement a C function that parses a raw tracking vector from PixyCam2 and returns a normalized steering error relative to the image frame center. |
| - | | 2 | | | | | | | + | |
| - | | 3 | | | | | | | + | |
| - | | 4 | | | | | | | + | |
| - | ==== Întrebări ==== | + | ==== Theoretical Context ==== |
| + | The PixyCam2 reports line tracking vectors in image coordinates. The $x$ coordinate increases from left to right, and the $y$ coordinate increases from top to bottom. | ||
| + | To determine the immediate direction of the path, you must track the endpoint of the vector that is closest to the front of the car (the bottom of the image frame, which corresponds to the larger $y$ coordinate). | ||
| + | * If $y_0 > y_1$, use $x_0$. | ||
| + | * If $y_1 > y_0$, use $x_1$. | ||
| + | * If the vector is horizontal ($y_0 == y_1$), use the average of $x_0$ and $x_1$. | ||
| - | * Ce se întâmplă când ''kp'' este prea mic? | + | The function must return a normalized error in the range ''[-1.0, 1.0]'': |
| - | * Ce se întâmplă când ''kp'' este prea mare? | + | * ''-1.0'' represents the far-left edge of the frame; |
| - | * Cum se schimbă comportamentul când măriți ''kd''? | + | * ''0.0'' represents the exact center of the frame; |
| - | * A fost necesar un termen integral? De ce? | + | * ''1.0'' represents the far-right edge of the frame. |
| - | ===== Exercițiul 2: Estimarea poziției liniei ===== | + | If the input ''frame_width <= 1'', return ''0.0f''. |
| + | Clamp the selected $x$ coordinate to the valid image boundaries $[0, \text{frame\_width} - 1]$ before normalization. | ||
| - | ==== Scop ==== | + | Students should derive a linear scaling formula to map the clamped $x$ coordinate from the pixel space $[0, \text{frame\_width} - 1]$ to the normalized target space $[-1.0, 1.0]$. |
| - | 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. | + | ==== Examples for frame_width = 79 ==== |
| - | ==== Interfață ==== | + | ^ Vector ^ Result ^ Explanation ^ |
| - | + | | ''{39, 0, 39, 51}'' | ''0.0'' | Bottom endpoint is exactly in the center | | |
| - | Implementați funcția: | + | | ''{39, 0, 0, 51}'' | ''-1.0'' | Bottom endpoint is at the far-left edge | |
| + | | ''{39, 0, 78, 51}'' | ''1.0'' | Bottom endpoint is at the far-right edge | | ||
| + | | ''{39, 0, 52, 51}'' | approx. ''0.333'' | Bottom endpoint is slightly to the right | | ||
| + | | ''{20, 20, 58, 20}'' | ''0.0'' | Horizontal vector: uses average x | | ||
| + | ==== Interface ==== | ||
| + | Implement the function in ''exercise2_pixy_vector/pixy_vector.c'': | ||
| <code c> | <code c> | ||
| - | float estimate_line_position(const int sensors[], int n); | + | typedef struct { |
| - | </code> | + | int x0; |
| + | int y0; | ||
| + | int x1; | ||
| + | int y1; | ||
| + | } PixyVector; | ||
| - | Valorile din ''sensors'' sunt intensități normalizate între ''0'' și ''1000'', unde o valoare mai mare înseamnă că senzorul vede mai puternic linia. | + | float estimate_pixy_vector_error(PixyVector vector, int frame_width); |
| - | + | ||
| - | Pozițiile senzorilor sunt distribuite uniform în intervalul ''[-1.0, 1.0]''. Pentru ''n = 5'', pozițiile sunt: | + | |
| - | + | ||
| - | <code text> | + | |
| - | senzor: 0 1 2 3 4 | + | |
| - | poziție: -1.0 -0.5 0.0 0.5 1.0 | + | |
| </code> | </code> | ||
| - | Poziția liniei se calculează ca medie ponderată: | + | ==== Local Validation ==== |
| - | + | Compile and run the local unit tests from the workspace: | |
| - | <code text> | + | |
| - | position = sum(sensor_value[i] * sensor_position[i]) / sum(sensor_value[i]) | + | |
| - | </code> | + | |
| - | + | ||
| - | 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: | + | |
| - | + | ||
| - | <code c> | + | |
| - | #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; | + | |
| - | } | + | |
| - | </code> | + | |
| - | + | ||
| - | Compilare și rulare: | + | |
| <code bash> | <code bash> | ||
| - | gcc -Wall -Wextra -std=c11 line_position.c test_line_position.c -lm -o test_line_position | + | cd nxp_car_lab_skeleton |
| - | ./test_line_position | + | make test-pixy |
| </code> | </code> | ||
| - | Dacă programul se termină fără eroare, testele au trecut. | + | --- |
| - | ===== Exercițiul 3: Limitare și conversie comandă servo ===== | + | ===== Exercise 3: Servo Command Conversion ===== |
| - | ==== Scop ==== | + | ==== Objective ==== |
| + | Implement a C function to map the abstract floating-point PID controller output to a physical PWM pulse width in microseconds for the steering servomotor. | ||
| - | Implementați conversia dintre ieșirea controllerului PID și comanda trimisă către servo. | + | ==== Theoretical Context ==== |
| + | The PID controller produces an abstract output intended to represent steering direction. The function must: | ||
| + | 1. Clamp the input `pid_output` to the safe operating range of ''[-1.0, 1.0]'', where ''-1.0'' represents maximum left steer and ''1.0'' represents maximum right steer. | ||
| + | 2. Map this clamped value linearly to a standard servo PWM pulse width in the range ''[1000, 2000]'' microseconds, where ''1500'' microseconds represents the center position (wheels straight). | ||
| - | Acest exercițiu se face pe laptop și nu necesită mașina. | + | Students should derive a linear conversion formula that maps the clamped PID steering command from $[-1.0, 1.0]$ to the physical servo PWM pulse width range $[1000, 2000]$ microseconds. |
| - | ==== Context ==== | ||
| - | Controllerul PID produce o valoare abstractă, de exemplu în intervalul ''[-1.0, 1.0]'': | + | ==== Examples ==== |
| - | * ''-1.0'' înseamnă viraj maxim stânga; | + | ^ pid_output ^ Expected PWM (us) ^ |
| - | * ''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: | + | |
| - | + | ||
| - | <code c> | + | |
| - | int pid_output_to_servo_us(float pid_output); | + | |
| - | </code> | + | |
| - | + | ||
| - | Funcția trebuie să: | + | |
| - | + | ||
| - | - limiteze ''pid_output'' la intervalul ''[-1.0, 1.0]''; | + | |
| - | - convertească liniar valoarea limitată la intervalul ''[1000, 2000]''; | + | |
| - | - returneze rezultatul ca întreg. | + | |
| - | + | ||
| - | Formula recomandată: | + | |
| - | + | ||
| - | <code text> | + | |
| - | servo_us = 1500 + pid_output * 500 | + | |
| - | </code> | + | |
| - | + | ||
| - | ==== Exemple ==== | + | |
| - | + | ||
| - | ^ pid_output ^ Rezultat așteptat ^ | + | |
| | ''-1.0'' | ''1000'' | | | ''-1.0'' | ''1000'' | | ||
| | ''-0.5'' | ''1250'' | | | ''-0.5'' | ''1250'' | | ||
| Line 287: | Line 232: | ||
| | ''0.5'' | ''1750'' | | | ''0.5'' | ''1750'' | | ||
| | ''1.0'' | ''2000'' | | | ''1.0'' | ''2000'' | | ||
| - | | ''2.0'' | ''2000'' | | + | | ''2.0'' | ''2000'' (clamped) | |
| - | | ''-2.0'' | ''1000'' | | + | | ''-2.0'' | ''1000'' (clamped) | |
| - | + | ||
| - | ==== Test local ==== | + | |
| - | + | ||
| - | Un posibil testbench: | + | |
| + | ==== Interface ==== | ||
| + | Implement the function in ''exercise3_steering/steering.c'': | ||
| <code c> | <code c> | ||
| - | #include <assert.h> | ||
| - | |||
| int pid_output_to_servo_us(float pid_output); | 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; | ||
| - | } | ||
| </code> | </code> | ||
| - | Compilare și rulare: | + | ==== Local Validation ==== |
| + | Compile and run the local unit tests: | ||
| <code bash> | <code bash> | ||
| - | gcc -Wall -Wextra -std=c11 steering.c test_steering.c -o test_steering | + | cd nxp_car_lab_skeleton |
| - | ./test_steering | + | make test-steering |
| </code> | </code> | ||
| - | Dacă programul se termină fără eroare, testele au trecut. | + | --- |
| - | + | ||
| - | ===== Livrabile ===== | + | |
| - | La finalul laboratorului încărcați: | + | ===== Deliverables ===== |
| - | * fișierul ''pid_config.txt'' cu cea mai bună combinație găsită; | + | Upon completion of the laboratory, submit the following: |
| - | * răspunsurile la întrebările de la exercițiul 1; | + | * Your final tuned PID parameters (Kp, Ki, Kd) documented in your report; |
| - | * implementarea pentru ''estimate_line_position''; | + | * Written answers to the theoretical questions in Exercise 1; |
| - | * implementarea pentru ''pid_output_to_servo_us''; | + | * Your C implementations for ''exercise2_pixy_vector/pixy_vector.c'' and ''exercise3_steering/steering.c''; |
| - | * capturi sau output text care arată că testele locale trec. | + | |
| - | ===== Criterii de evaluare ===== | + | ===== Grading Criteria ===== |
| - | ^ Componentă ^ Punctaj ^ | + | ^ Component ^ Percentage ^ |
| - | | Explicații despre reglarea PID și observații din testarea pe mașină | 30% | | + | | PID tuning analysis and track characterization | 30% | |
| - | | Parametri PID funcționali pe traseu | 25% | | + | | Functional PID parameters on the physical track | 25% | |
| - | | Exercițiul 2: estimarea poziției liniei | 20% | | + | | Exercise 2: PixyCam2 error estimation implementation | 20% | |
| - | | Exercițiul 3: conversie comandă servo | 15% | | + | | Exercise 3: Servo command conversion implementation | 15% | |
| - | | Claritate, cod simplu, teste rulate local | 10% | | + | | Code cleanliness, proper clamping, and local validation | 10% | |
| - | ===== Recomandări ===== | + | ===== General Recommendations ===== |
| + | * **Local Validation**: Always verify your code implementations using the local test suites (''make test'') before deploying or tuning. | ||
| + | * **Code Quality**: Write clean, self-documenting code, handle all safety clamping, and consider extreme edge cases (such as negative or zero frame width). | ||
| - | * 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ț. | ||