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 proiectului: surse, 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ța 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 documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **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(RCPinSwitch, HIGH); 
 + 
 +    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 pin, uint8_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 și 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