Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2024:fstancu:ioan.birjovanu [2024/05/13 03:03]
ioan.birjovanu
pm:prj2024:fstancu:ioan.birjovanu [2024/05/27 11:50] (current)
ioan.birjovanu
Line 3: Line 3:
  
 Proiectul este reprezentat de un robot controlat wireless cu o radiocomanda FlySky FS-I6. Proiectul este reprezentat de un robot controlat wireless cu o radiocomanda FlySky FS-I6.
-Funcționalitățile robotului sunt: deplasarea plană(directie de tip tanc) și spinnerul cilindric frontal(armă principală).+Funcționalitățile robotului sunt: deplasarea plană(directie de tip tanc), aruncătorul de flăcări(acționat de un switch de pe telecomandă) și controlul vitezei spinnerului cilindric.
  
-Inspirat de seria [[https://​battlebots.com|BattleBots]],​ am dorit să proiectez un battlebot de la 0. Astfel, am ajuns la design-ul curent: Un șasiu simetric(pentru a funcționa și dacă este răsturnat),​ cu două roți motorizate pentru deplasare și un cilindru asimetric ​frontal.+Inspirat de seria [[https://​battlebots.com|BattleBots]],​ am dorit să proiectez un battlebot de la 0. Astfel, am ajuns la design-ul curent: Un șasiu simetric(pentru a funcționa și dacă este răsturnat),​ cu două roți motorizate pentru deplasare și un cilindru asimetric ​ca armă principală.
  
 {{ pm:​prj2024:​fstancu:​robot.jpg?​770 }} {{ pm:​prj2024:​fstancu:​robot.jpg?​770 }}
  
-Robotul a fost printat ​3d folosind o imprimantă Creality CR-10S Pro V2, iar design-ul a fost creat în Autodesk Fusion 360.+Robotul a fost printat ​3D folosind o imprimantă Creality CR-10S Pro V2, iar design-ul a fost creat în Autodesk Fusion 360.
  
 ===== Descriere generală ===== ===== Descriere generală =====
Line 29: Line 29:
   * **Servomotorul:​** Un motor cu rotație fixă, unghiul de rotație al acestuia este controlat de microcontroller folosind un semnal PWM.   * **Servomotorul:​** Un motor cu rotație fixă, unghiul de rotație al acestuia este controlat de microcontroller folosind un semnal PWM.
   * **Controllerul brushless:​** Acesta controlează viteza de rotație a motorului brushless, primește valoarea PWM de la microcontroller.   * **Controllerul brushless:​** Acesta controlează viteza de rotație a motorului brushless, primește valoarea PWM de la microcontroller.
 +
 +<note tip>
 +Radiocomanda transmite receiverului 6 canale, dintre care noi folosim 4:
 +  * Canalul 1: Joystick-ul drept, axa Ox - folosit pentru a controla virajul robotului.
 +  * Canalul 2: Joystick-ul drept, axa Oy - folosit pentru a controla direcția de deplasare a robotului.
 +  * Canalul 3: Joystick-ul stâng, axa Oy - folosit pentru a controla viteza motorului brushless.
 +  * Canalul 5: Switch-ul A - folosit pentru a activa flamethrowerul.
 +</​note>​
 +
 +{{ pm:​prj2024:​fstancu:​flysky_schematic.jpg?​770 }}
 +
 +Astfel, acționând canalul 5 al teleccomenzii,​ robotul se va comporta în următorul fel:
 +
 +{{ pm:​prj2024:​fstancu:​robot_flame.jpg?​770 }}
  
 ===== Hardware Design ===== ===== Hardware Design =====
Line 52: Line 66:
   * Voltmetru OKY4092   * Voltmetru OKY4092
  
-===== Software Design =====+<note tip> 
 +Modelul 3D al robotului a fost conceput în jurul componentelor hardware. Am început cu o platformă cu găuri de montare pentru un Arduino Uno, pe care am extins-o pentru a adăuga bateria și motoarele pentru deplasarea robotului și pentru armă. 
 +</​note>​
  
 +{{ pm:​prj2024:​fstancu:​robot_3d_model.jpg?​770 }}
  
 <note tip> <note tip>
-Descrierea codului aplicaţiei (firmware):​ +Pentru a porni robotul din exterior fără a-l dezasambla pentru a accesa bateria, am proiectat un întrerupător cu șurub: acesta asigură conexiunea circuitului de alimentare al robotului cu borna pozitivă a bateriei atunci când se înfiletează șurubul.
-  * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) +
-  * librării şi surse 3rd-party (e.g. Procyon AVRlib) +
-  * algoritmi şi structuri pe care plănuiţi să le implementaţi +
-  * (etapa 3) surse şi funcţii implementate+
 </​note>​ </​note>​
  
-===== Rezultate Obţinute =====+{{ pm:​prj2024:​fstancu:​screw_switch.jpg?​770 }}
  
 <note tip> <note tip>
-Care au fost rezultatele obţinute în urma realizării proiectului vostru.+Întrerupătorul este accesibil din exterior și este plasat pe panoul central inferior al robotului. Săgeata de pe panoul din imaginea de mai jos semnifică direcția de rotire(spre dreapta) a șurubului pentru a porni robotul. Pentru a opri robotul, întrerupătorul va fi rotit spre stânga.
 </​note>​ </​note>​
  
-===== Concluzii =====+{{ pm:​prj2024:​fstancu:​robot_3d_model_under2.jpg?​770 }}
  
-===== Download =====+<note tip> 
 +După asamblarea șasiului printat 3D și montarea componentelor electrice în acesta, robotul va arăta astfel: 
 +</​note>​
  
-<note warning>​ +{{ pm:prj2024:​fstancu:​robot_internals.jpg?770 }}
-O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectuluisurse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-).+
  
-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**.+===== Software Design ===== 
 + 
 +<note tip> 
 +După finalizarea etapei de proiectare de hardware, am programat inițial microcontrollerul ​folosind ​environmentul Arduino IDE pentru a testa funcționalitățile acestuia și a mă asigura ​că acesta funcționează corect. 
 +Codul inițial în Arduino pentru robot a fost:
 </​note>​ </​note>​
  
-===== Jurnal ​=====+<​code>​ 
 +#include <​Servo.h>​ 
 + 
 +#define RCPinFWD 2 
 +#define RCPinSide 3 
 +#define RCPinSwitch 4 
 + 
 +#define Motor1Pin1 9 
 +#define Motor1Pin2 8 
 +#define Motor2Pin1 11 
 +#define Motor2Pin2 10 
 +#define RelayPin 13 
 +#define ServoPin 12 
 + 
 +volatile long StartTimeFWD ​0; 
 +volatile long CurrentTimeFWD ​0; 
 +volatile long PulsesFWD ​0; 
 +int PulseWidthFWD ​0; 
 + 
 +volatile long StartTimeSide ​0; 
 +volatile long CurrentTimeSide ​0; 
 +volatile long PulsesSide ​0; 
 +int PulseWidthSide ​0; 
 + 
 +int SwitchValue;​ 
 + 
 +Servo servo; 
 + 
 +void setup() { 
 +  Serial.begin(9600);​ 
 +  pinMode(RCPinFWD,​ INPUT_PULLUP);​ 
 +  pinMode(RCPinSide,​ INPUT_PULLUP);​ 
 +  pinMode(RCPinSwitch,​ INPUT); 
 + 
 +  attachInterrupt(digitalPinToInterrupt(RCPinFWD),​PulseTimerFWD,​CHANGE);​ 
 +  attachInterrupt(digitalPinToInterrupt(RCPinSide),​PulseTimerSide,​CHANGE);​ 
 + 
 +  pinMode(Motor1Pin1,​ OUTPUT); 
 +  pinMode(Motor1Pin2,​ OUTPUT); 
 +  pinMode(Motor2Pin1,​ OUTPUT); 
 +  pinMode(Motor2Pin2,​ OUTPUT); 
 + 
 +  servo.attach(ServoPin);​ 
 +  pinMode(RelayPin,​ OUTPUT); 
 +
 + 
 +void loop() { 
 +  if (PulsesFWD < 2000){ 
 +    PulseWidthFWD ​PulsesFWD;​ 
 +  }  
 +  if (PulsesSide < 2000){ 
 +    PulseWidthSide ​PulsesSide;​ 
 +  }  
 +  Serial.print(PulseWidthFWD);​ 
 +  Serial.print(" ​   "); 
 +  Serial.println(PulseWidthSide);​ 
 + 
 +  if (PulseWidthFWD > 1000 && PulseWidthSide > 1000) { 
 +    if (PulseWidthFWD > 1550) { 
 +      digitalWrite(Motor1Pin1,​ HIGH); 
 +      digitalWrite(Motor1Pin2,​ LOW); 
 +    } 
 +    else if (PulseWidthFWD < 1450) { 
 +      digitalWrite(Motor1Pin1,​ LOW); 
 +      digitalWrite(Motor1Pin2,​ HIGH); 
 +    } 
 +    else { 
 +      digitalWrite(Motor1Pin1,​ LOW); 
 +      digitalWrite(Motor1Pin2,​ LOW); 
 +    } 
 + 
 +    if (PulseWidthSide > 1550) { 
 +      digitalWrite(Motor2Pin1,​ HIGH); 
 +      digitalWrite(Motor2Pin2,​ LOW); 
 +    } 
 +    else if (PulseWidthSide < 1450) { 
 +      digitalWrite(Motor2Pin1,​ LOW); 
 +      digitalWrite(Motor2Pin2,​ HIGH); 
 +    } 
 +    else { 
 +      digitalWrite(Motor2Pin1,​ LOW); 
 +      digitalWrite(Motor2Pin2,​ LOW); 
 +    } 
 +  } 
 +  else { 
 +    digitalWrite(Motor2Pin1,​ LOW); 
 +    digitalWrite(Motor2Pin1,​ LOW); 
 +    digitalWrite(Motor1Pin1,​ LOW); 
 +    digitalWrite(Motor1Pin1,​ LOW); 
 +  } 
 + 
 +  SwitchValue = pulseIn(RCPinSwitch,​ HIGH); 
 +  Serial.print("​___"​);​ 
 +  Serial.print(SwitchValue);​ 
 +  Serial.print("​___"​);​ 
 + 
 +  servo.write(SwitchValue);​ 
 + 
 +  if (SwitchValue > 1000) 
 +    digitalWrite(RelayPin,​ HIGH); 
 +  else 
 +    digitalWrite(RelayPin,​ LOW); 
 +
 + 
 +void PulseTimerFWD(){ 
 +  CurrentTimeFWD = micros(); 
 +  if (CurrentTimeFWD > StartTimeFWD){ 
 +    PulsesFWD = CurrentTimeFWD - StartTimeFWD;​ 
 +    StartTimeFWD = CurrentTimeFWD;​ 
 +  } 
 +
 +void PulseTimerSide(){ 
 +  CurrentTimeSide = micros(); 
 +  if (CurrentTimeSide > StartTimeSide){ 
 +    PulsesSide = CurrentTimeSide - StartTimeSide;​ 
 +    StartTimeSide = CurrentTimeSide;​ 
 +  } 
 +
 +</​code>​
  
 <note tip> <note tip>
-Puteți avea și o secțiune ​de jurnal în care să poată urmări asistentul de proiect progresul proiectului.+Codul de Arduino a rămas referințde bază pentru design-ul codului in AVR C pentru microcontrollerul AtMega328P. 
 +Acesta este codul pentru microcontroller scris în AVR C:
 </​note>​ </​note>​
  
-===== Bibliografie/Resurse =====+<​code>​ 
 +#include <avr/io.h> 
 +#include <​avr/​interrupt.h>​ 
 +#include <​util/​delay.h>​
  
-<note+#define CLOCK_SPEED 16000000UL 
-Listă cu documentedatasheet-uriresurse Internet folosite, eventual grupate pe **Resurse Software** ş**Resurse Hardware**.+#define BAUD 9600 
 +#define MYUBRR CLOCK_SPEED/​16/​BAUD-1 
 + 
 +#define RCPinFWD PD2 
 +#define RCPinSide PD3 
 +#define RCPinSwitch PD4 
 + 
 +#define Motor1Pin1 PB1 
 +#define Motor1Pin2 PB0 
 +#define Motor2Pin1 PB3 
 +#define Motor2Pin2 PB2 
 +#define RelayPin PB5 
 +#define ServoPin PB4 
 + 
 +volatile long StartTimeFWD = 0; 
 +volatile long CurrentTimeFWD = 0; 
 +volatile long PulsesFWD = 0; 
 +int PulseWidthFWD = 0; 
 + 
 +volatile long StartTimeSide = 0; 
 +volatile long CurrentTimeSide = 0; 
 +volatile long PulsesSide = 0; 
 +int PulseWidthSide = 0; 
 + 
 +int SwitchValue;​ 
 + 
 +void setup(); 
 +void loop(); 
 +void PulseTimerFWD();​ 
 +void PulseTimerSide();​ 
 +void init_timer1();​ 
 +void init_timer0();​ 
 +long pulseIn(uint8_t pin, uint8_t state); 
 +long micros(); 
 + 
 +volatile unsigned long timer0_overflow_count = 0; 
 + 
 +int main(void) { 
 +    setup(); 
 +    while (1) { 
 +        loop(); 
 +    } 
 +
 + 
 +void setup() { 
 +    // Set input and output pins 
 +    DDRD &= ~((1 << RCPinFWD) | (1 << RCPinSide) | (1 << RCPinSwitch));​ // Set as input 
 +    PORTD |= (1 << RCPinFWD) | (1 << RCPinSide); // Enable pull-up resistors 
 + 
 +    DDRB |= (1 << Motor1Pin1) | (1 << Motor1Pin2) | (1 << Motor2Pin1) | (1 << Motor2Pin2) | (1 << RelayPin) | (1 << ServoPin);​ 
 + 
 +    // Set up external interrupts for FWD and Side 
 +    EICRA |= (1 << ISC00) | (1 << ISC10); // Any logical change on INT0 and INT1 generates an interrupt 
 +    EIMSK |= (1 << INT0) | (1 << INT1); // Enable INT0 and INT1 
 + 
 +    init_timer1();​ 
 +    init_timer0();​ 
 + 
 +    sei(); // Enable global interrupts 
 +
 + 
 +void loop() { 
 +    if (PulsesFWD < 2000) { 
 +        PulseWidthFWD = PulsesFWD;​ 
 +    } 
 +    if (PulsesSide < 2000) { 
 +        PulseWidthSide = PulsesSide;​ 
 +    } 
 + 
 +    if (PulseWidthFWD ​1000 && PulseWidthSide > 1000) { 
 +        if (PulseWidthFWD > 1550) { 
 +            PORTB |= (1 << Motor1Pin1);​ 
 +            PORTB &= ~(1 << Motor1Pin2);​ 
 +        } else if (PulseWidthFWD < 1450) { 
 +            PORTB &= ~(1 << Motor1Pin1);​ 
 +            PORTB |= (1 << Motor1Pin2);​ 
 +        } else { 
 +            PORTB &= ~((1 << Motor1Pin1) | (1 << Motor1Pin2));​ 
 +        } 
 + 
 +        if (PulseWidthSide > 1550) { 
 +            PORTB |= (1 << Motor2Pin1);​ 
 +            PORTB &= ~(1 << Motor2Pin2);​ 
 +        } else if (PulseWidthSide < 1450) { 
 +            PORTB &= ~(1 << Motor2Pin1);​ 
 +            PORTB |= (1 << Motor2Pin2);​ 
 +        } else { 
 +            PORTB &= ~((1 << Motor2Pin1) | (1 << Motor2Pin2));​ 
 +        } 
 +    } else { 
 +        PORTB &= ~((1 << Motor1Pin1) | (1 << Motor1Pin2) | (1 << Motor2Pin1) | (1 << Motor2Pin2));​ 
 +    } 
 + 
 +    SwitchValue = pulseIn(RCPinSwitchHIGH); 
 + 
 +    OCR1A = SwitchValue;​ // Set PWM for servo 
 + 
 +    if (SwitchValue > 1000) { 
 +        PORTB |= (1 << RelayPin);​ 
 +    } else { 
 +        PORTB &= ~(1 << RelayPin);​ 
 +    } 
 +
 + 
 +ISR(INT0_vect) { 
 +    PulseTimerFWD();​ 
 +
 + 
 +ISR(INT1_vect) { 
 +    PulseTimerSide();​ 
 +
 + 
 +void PulseTimerFWD() { 
 +    CurrentTimeFWD = micros(); 
 +    if (CurrentTimeFWD > StartTimeFWD) { 
 +        PulsesFWD = CurrentTimeFWD ​StartTimeFWD;​ 
 +        StartTimeFWD = CurrentTimeFWD;​ 
 +    } 
 +
 + 
 +void PulseTimerSide() { 
 +    CurrentTimeSide = micros(); 
 +    if (CurrentTimeSide > StartTimeSide) { 
 +        PulsesSide = CurrentTimeSide - StartTimeSide;​ 
 +        StartTimeSide = CurrentTimeSide;​ 
 +    } 
 +
 + 
 +void init_timer1() { 
 +    // Timer1 setup for servo control 
 +    TCCR1A = (1 << WGM11) | (1 << COM1A1); 
 +    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); 
 +    ICR1 = 39999; // 50Hz frequency 
 +
 + 
 +void init_timer0() { 
 +    // Timer0 setup for micros 
 +    TCCR0A = 0; 
 +    TCCR0B = (1 << CS01) | (1 << CS00); // Prescaler 64 
 +    TIMSK0 = (1 << TOIE0); // Enable overflow interrupt 
 +
 + 
 +ISR(TIMER0_OVF_vect) { 
 +    timer0_overflow_count++;​ 
 +
 + 
 +long micros() { 
 +    unsigned long m; 
 +    uint8_t oldSREG = SREG; 
 + 
 +    cli(); 
 +    m = timer0_overflow_count;​ 
 +    uint8_t t = TCNT0; 
 + 
 +    if ((TIFR0 & (1 << TOV0)) && (t < 255)) { 
 +        m++; 
 +    } 
 + 
 +    SREG = oldSREG; 
 +    return ((m << 8) + t) * (64 / (F_CPU / 1000000L));​ 
 +
 + 
 +long pulseIn(uint8_t pinuint8_t state) { 
 +    uint8_t bit = digitalPinToBitMask(pin);​ 
 +    uint8_t port = digitalPinToPort(pin);​ 
 +    uint8_t stateMask = (state ? bit : 0); 
 +    unsigned long width = 0; 
 + 
 +    // Wait for any previous pulse to end 
 +    while ((*portInputRegister(port) & bit) == stateMask);​ 
 + 
 +    // Wait for the pulse to start 
 +    while ((*portInputRegister(port) & bit) != stateMask);​ 
 + 
 +    // Wait for the pulse to stop 
 +    while ((*portInputRegister(port) & bit) == stateMask) { 
 +        width++; 
 +        if (width >= 1000000) { 
 +            return 0; 
 +        } 
 +    } 
 + 
 +    return width; 
 +
 +</​code>​ 
 + 
 +În codul de AVR, folosim hardware interrupts pe pinii de input pentru a identifica semnalele PWM de la receiverul radio, iar cu timerul 0 le măsurăm valoarea. Vom folosi apoi acele valori pentru a activa driverul de motoare DC pentru direcție, împreună cu servomotorul si controllerul de viteză pentru motorul brushless. Pentru a trimite un semnal PWM corespunzător valorii primite de la receiver la speed controller șservomotor, vom folosi timerul 1 
 + 
 +===== Concluzii ===== 
 +Acest proiect m-a ajutat să învăț despre programarea microprocesoarelor Atmel in AVR C, fără a folosi abstraction layer-ul oferit de Arduino IDE. De asemenea mi-a consolidat aptitudinile de CAD și de design de circuite. 
 + 
 +Abilitatea de a citi semnalele dintr-un receiver hobby-grade cu ajutorul unui microprocesor deschide o plajă largă de potențiale proiecte viitoare. 
 + 
 +===== Download ===== 
 +<note tip> 
 +Link Repository Git: [[https://​github.com/​IonutBirjovanu/​AVR-BattleBot|BattleBot]]
 </​note>​ </​note>​
 +
 +<note tip>
 +Arhiva care conține următoarele fisiere:
 +  * 3D - un fisier cu toate piesele 3D folosite în proiectarea robotului.
 +  * Battlebot - implementarea proiectului în Arduino
 +  * media - conținut media cu robotul
 +  * Schematic photos - figurile schematicelor robotului
 +  * src - implementarea proiectului în AVR C
 +</​note>​
 +
 +{{pm:​prj2024:​fstancu:​proiect_pm_birjovanu_ioan.zip|arhiva}}
 +
 +===== Bibliografie/​Resurse =====
 +
 +**Resurse Software**
 +  * [[https://​ocw.cs.pub.ro/​courses/​pm/​lab/​lab0-2023|Laboratorul 0: GPIO]]
 +  * [[https://​ocw.cs.pub.ro/​courses/​pm/​lab/​lab2-2023|Laboratorul 2: Întreruperi,​ Timere]]
 +  * [[https://​ocw.cs.pub.ro/​courses/​pm/​lab/​lab3-2023-2024|Laboratorul 3: Timere, PWM]]
 +
 +**Resurse Hardware**
 +  * [[https://​howtomechatronics.com/​|HowToMechatronics]]
 +  * [[https://​electronoobs.com/​|ElectroNoobs]]
  
 <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​ <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​
  
pm/prj2024/fstancu/ioan.birjovanu.1715558596.txt.gz · Last modified: 2024/05/13 03:03 by ioan.birjovanu
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