Differences

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

Link to this comparison view

pm:prj2024:fstancu:ioan.birjovanu [2024/05/24 08:01]
ioan.birjovanu
pm:prj2024:fstancu:ioan.birjovanu [2024/05/27 11:50] (current)
ioan.birjovanu
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
  
 +<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ă. 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 }} {{ pm:​prj2024:​fstancu:​robot_3d_model.jpg?​770 }}
  
 +<note tip>
 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. 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.
 +</​note>​
  
 +{{ pm:​prj2024:​fstancu:​screw_switch.jpg?​770 }}
  
-===== Software Design =====+<note tip> 
 +Î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>​
  
 +{{ pm:​prj2024:​fstancu:​robot_3d_model_under2.jpg?​770 }}
  
 <note tip> <note tip>
-Descrierea codului aplicaţiei (firmware):​ +După asamblarea șasiului printat 3D șmontarea componentelor electrice în acesta, robotul va arăta astfel:
-  * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) +
-  * librării ş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:​robot_internals.jpg?​770 }} 
 + 
 +===== Software Design ​=====
  
 <note tip> <note tip>
-Care au fost rezultatele obţinute în urma realizării proiectului vostru.+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>​
  
-===== Concluzii =====+<​code>​ 
 +#include <​Servo.h>​
  
-===== Download =====+#define RCPinFWD 2 
 +#define RCPinSide 3 
 +#define RCPinSwitch 4
  
-<note warning> +#define Motor1Pin1 9 
-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ă ;-).+#define Motor1Pin2 8 
 +#define Motor2Pin1 11 
 +#define Motor2Pin2 10 
 +#define RelayPin 13 
 +#define ServoPin 12
  
-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 Alin331CC -> **:​pm:​prj2009:​cc:​dumitru_alin**.+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(RelayPinOUTPUT); 
 +
 + 
 +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> 
 +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>​
  
-===== Jurnal =====+<​code>​ 
 +#include <​avr/​io.h>​ 
 +#include <​avr/​interrupt.h>​ 
 +#include <​util/​delay.h>​
  
 +#define CLOCK_SPEED 16000000UL
 +#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> <note tip>
-Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului.+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 ===== ===== Bibliografie/​Resurse =====
  
-<​note>​ +**Resurse Software** 
-Listă cu documente, datasheet-uri,​ resurse Internet folosite, eventual grupate pe **Resurse Software** ​şi **Resurse Hardware**. +  * [[https://​ocw.cs.pub.ro/​courses/​pm/​lab/​lab0-2023|Laboratorul 0: GPIO]] 
-</note>+  * [[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.1716526880.txt.gz · Last modified: 2024/05/24 08:01 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