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:23]
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 }} {{ pm:​prj2024:​fstancu:​screw_switch.jpg?​770 }}
  
 +<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. Î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_under.jpg?770 }}+{{ pm:​prj2024:​fstancu:​robot_3d_model_under2.jpg?770 }}
  
-===== Software Design =====+<note tip> 
 +După asamblarea șasiului printat 3D și montarea componentelor electrice în acesta, robotul va arăta astfel: 
 +</​note>​
  
 +{{ pm:​prj2024:​fstancu:​robot_internals.jpg?​770 }}
 +
 +===== Software Design =====
  
 <note tip> <note tip>
-Descrierea codului aplicaţiei (firmware):​ +După finalizarea etapei ​de proiectare de hardwaream programat inițial microcontrollerul folosind environmentul Arduino IDE pentru a testa funcționalitățile acestuia șa mă asigura că acesta funcționează corect. 
-  * mediu de dezvoltare (if any) (e.g. AVR StudioCodeVisionAVR) +Codul inițial în Arduino pentru robot a fost:
-  * 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 ​=====+<​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>
-Care au fost rezultatele obţinute în urma realizării proiectului vostru.+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>​
  
-===== Concluzii =====+<​code>​ 
 +#include <​avr/​io.h>​ 
 +#include <​avr/​interrupt.h>​ 
 +#include <​util/​delay.h>​
  
-===== Download =====+#define CLOCK_SPEED 16000000UL 
 +#define BAUD 9600 
 +#define MYUBRR CLOCK_SPEED/​16/​BAUD-1
  
-<note warning> +#define RCPinFWD PD2 
-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 RCPinSide PD3 
 +#define RCPinSwitch PD4
  
-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**. +#define Motor1Pin1 PB1 
-</​note>​+#define Motor1Pin2 PB0 
 +#define Motor2Pin1 PB3 
 +#define Motor2Pin2 PB2 
 +#define RelayPin PB5 
 +#define ServoPin PB4
  
-===== Jurnal =====+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.1716528202.txt.gz · Last modified: 2024/05/24 08:23 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