This is an old revision of the document!
Proiectul implementeaza un pendul invers ce balanseaza un obiect pe verticala în sus folosind un algoritm de control - PID. Sunt mai multe variante de pendul invers, unele mai ușor de implementat (folosirea unei roți cu greutǎți - însuși greutatea, obiectul balansat face balansarea), sau ce am ales sǎ realizez eu, balansarea unui obiect independent de modulul de balansare folosind un motor la baza acestuia.
Ideea de la care am pornit a fost în sine echilibrarea unui pendul, vǎzând pe internet tot felul de self-balancing robots și aplicarea unui algoritm de control.
Proiectul poate fi folosit în sine pentru explicarea mai ușoara a PID-ului altor studenți, având un feedback live asupra ce fac cele 3 elemente din PID asupra unui sistem controlat, putând din interfața web sǎ aplici noi valori la un singur click.
Schema bloc a proiectului:
User-ul va putea trimite valori pentru PID live cǎtre main controller (ESP32) folosind un web server. ESP-ul va aplica algoritmul de control asupra unui Motor folosind valorile pentru PID primite din aplicația web.
Pentru ușurarea sistemului avem urmatoarele surse de input:
Folosind aceste lucruri putem ajunge la poziția de control a pendulului.
Interactiunea componentelor:
Pentru alimentarea circuitului am folosit o sursa in comutatie de 12V si de 6A, deoarece motorul in load maxim poate consuma pana la 3A. Din sursa este alimentat H-bridge-ul de 6A de la Infineon si in acelasi timp un buck converter ce coboara tensiunea la 5V pentru a alimenta ESP-ul prin pin-ul de VIN. In acelasi timp, encoder-ul este alimentat tot la 5V dar cele doua faze de output ale acestuia sunt trase la 3V3 prin 2 rezistene de 2k7 pentru a fi in aceeasi logica de functionare cu cea a ESP-ului. Pendulul este pus in miscare de un motor de 12V cu cuplu mare si 280 de RPM, pentru a putea sustine si greutatea pendulului + encoder-ului, dar si pentru a putea schimba rapid directia pentru stabilizarea pendulului. Ca platforma, am ales ESP32 deoarece este un dual core rapid, un core va fi folosit pentru conotrolul pendulului iar celalalt core va fi folosit pentru a extrage/posta date in interfata web al pendulului. Dupa cum am zis, proiectul va ajuta si ca un learning model pentru aplicarea PID-ului, putand schimba valorile K_p, K_i si k_d live. Pentru ca ESP-ul este atat de rapid, a trebuit sa realizez un timer ce functioneaza la 1000Hz pentru a putea citi la intervale fixe valorile encoder-ului si pentru a putea calcula corect interval-ul intre citiri. Daca nu as fi folosit acest timer, diferenta de timp intre citiri ar fi fost la nivelul micro secundelor, lucru ce incurca funtionarea corecta a pendulului.
Principiu de functionare: Encoder-ul trimite pulsuri catre uC ce sunt citite pe o intrerupere. Aceste impulsuri sunt transformate in grade cu ajutorul unui calcul matematic simplu. Unghiul apoi este bagat ca feedback in PID controller, unde setpoint-ul este setat la 180 de grade (vrem ca pendulul sa stea vertical in sus). Output-ul este mapat intre 0 si 255 (pentru pwm). Timer-ul de 1000Hz, asa cum am spus mai sus, este folosit pentru a stii exact intervalul intre citiri si de a nu avea schimbari aleatorii de timp intre citiri.
Listă de piese:
Schema electrica motor driver:
Schema electrica full: schematic_invertedpendulum.pdf
Modelul 3D al PCB-ului:
Modelele 3D ale proiectului:
Stare actuala pendul: (Nu a venit inca PCB-ul)
Platform.io:
Platform.io este un mediu de dezvoltare built on top of VS Code, mult mai rapid si mai versatil decat simplul Arduino IDE, ce ofera posibilitatea programarii multor environment-uri, printre care si cel de la Esspressif32. Compilarea si upload-ul catre placi este mult mai smooth, putand face si software debug prin serial.
Librarii si surse:
Pentru librarii am folosit Arduino.h si RotaryEncoder.h, care vine cu niste functii mai rapide de a calcula unghiul din cele 1200 de pulsuri folosind un interrupt handler mai eficient.
Algoritmi si structuri: Pe partea de algoritmi, proiectul se bazeaza pe un algoritm de control, mai exact PID, ce se foloseste de unghiul la momentul T al pendulului ca input.
k_p = 1 k_i = 0 k_d = 0 # Loop forever interval = 1 #1ms error_prev = 0 integral = 0 setpoint = 180 while True: # Get angle from encoder(feedback) val = encoder->get_angle() # Calculate the PID terms error = setpoint – val integral = integral + (error * interval) derivative = (error – error_prev) / interval output = (k_p * error) + (k_i * integral) + (k_d * derivative) # Save value for next iteration error_prev = error
Fişierele se încarcă pe wiki folosind facilitatea Add Images or other files. Namespace-ul în care se încarcă fişierele este de tipul :pm:prj20??:c? sau :pm:prj20??:c?:nume_student (dacă este cazul). Exemplu: Dumitru Alin, 331CC → :pm:prj2009:cc:dumitru_alin.