Dvojosová kolíska na kameru ovládaná joystickom: Rozdiel medzi revíziami
Zo stránky SensorWiki
(89 medziľahlých úprav od rovnakého používateľa nie je zobrazených.) | |||
Riadok 9: | Riadok 9: | ||
[[Obrázok:Matsibora_a_Fietisov_koliska.jpg| | [[Obrázok:Matsibora_a_Fietisov_koliska.jpg|440px|thumb|center|Model projekta.]] | ||
== Zadanie == | == Zadanie == | ||
Riadok 19: | Riadok 19: | ||
'''Literatúra:''' | '''Literatúra:''' | ||
* [ | * [https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf ATmega328P Datasheet] | ||
* [http:// | * [http://marcusjenkins.com/wp-content/uploads/2014/06/ARDUINO_V2.pdf Arduino Uno pinout diagram] | ||
Riadok 27: | Riadok 27: | ||
== Analýza a opis riešenia == | == Analýza a opis riešenia == | ||
Celý projekt obsahuje dosku Arduino, dvojosový joystick, | Celý projekt obsahuje dosku Arduino, dvojosový joystick, dva servá sg90, prepojovacie vodiče a samotný držiak kamery. | ||
Použitý joystik má 5 pinov (Vcc, GND, Xaxis, Yaxis a kolík tlačidla). Joystick má 2 centrované potenciometre, pri napájaní produkujú analógový signál a pri použití s Arduino má nasledujúce hodnoty: „0-1023“ a keďže sú v pohotovostnom režime vycentrované, vytvárajú hodnoty okolo „512“ a tlačidlo má digitálny výstup 0/1. | Použitý joystik má 5 pinov (Vcc, GND, Xaxis, Yaxis a kolík tlačidla). Joystick má 2 centrované potenciometre, pri napájaní produkujú analógový signál a pri použití s Arduino má nasledujúce hodnoty: „0-1023“ a keďže sú v pohotovostnom režime vycentrované, vytvárajú hodnoty okolo „512“ a tlačidlo má digitálny výstup 0/1. | ||
Riadok 33: | Riadok 33: | ||
Musíme byť opatrní s joystickom, pretože sú dosť lacné a môže fungovať iba jedna os, čo sa stalo v našom prípade. Na kontrolu osej sme použili terminal PuTTY. | Musíme byť opatrní s joystickom, pretože sú dosť lacné a môže fungovať iba jedna os, čo sa stalo v našom prípade. Na kontrolu osej sme použili terminal PuTTY. | ||
[[Súbor: | [[Súbor:Matsibora_a_Fietisov_joystik.jpg|450px|thumb|left|Joystik.]] | ||
[[Súbor: | [[Súbor:Matsibora_a_Fietisov_hodnoty joystika.png|590px|thumb|center|schema Joystika.]] | ||
[[Súbor: | |||
[[Súbor:Matsibora_a_Fietisov_servo a joystik.jpg|500px|thumb|center|Schéma zapojenia joystika k Arduino.]] | |||
Ďalej budeme hovoriť o servomotoroch. | Ďalej budeme hovoriť o servomotoroch. | ||
Riadok 50: | Riadok 52: | ||
Hmotnosť: 14g | Hmotnosť: 14g | ||
Rozmery(mm): 22 x 11,5 x 27 | Rozmery(mm): 22 x 11,5 x 27 | ||
[[Súbor:sg90.png| | [[Súbor:sg90.png|420px|thumb|left|Servomotor.]] | ||
[[Súbor:рис51.png| | [[Súbor:рис51.png|450px|thumb|center|Schéma zapojenia joystika a servomotorov k Arduino.]] | ||
[[Súbor:ServoAnimation.gif|450px|thumb|center|Riadenie polohy servomotora pomocou dĺžky impulzu.]] | |||
Servomotor je kombináciou DC motora, systému riadenia polohy, prevodov. Polohu hriadeľa DC motora nastavuje riadiaca elektronika v servo na základe duty ratio PWM signálu na pine SIGNAL. Jednoducho povedané, riadiaca elektronika nastavuje polohu hriadeľa ovládaním DC motora. Tieto údaje o polohe hriadeľa sa odosielajú cez pin SIGNAL. Údaje o polohe do riadenia by sa mali odosielať vo forme signálu PWM cez signálny pin servomotora.Generovanie PWM bolo riešené pomocou 16-bitového počítadla a časovača T1. | |||
Potom pre Т1: režim Fast PWM. To, ktorý režim PWM chceme používať sa nastavuje bitmi WGM13...WGM10, ktoré sú rozdelené do registrov TCCR1A a TCCR1B. | |||
[[Súbor:Matsibora_a_Fietisov_tabulka.png|550px|thumb|center|Tabulka.]] | |||
Ďalej musíme vypočítať frekvenciu signálu, na to použijeme vzorec z datasheetu. | |||
[[Súbor:Matsibora_a_Fietisov_vzorec.png|450px|thumb|center|Vzorec.]] | |||
fcpu je 16MHz, fpwm by malo byť 50Hz, N – preddelička. Sme zvolili 64, teda preddeličku nastavíme takto TCCR1B = (1<<CS10)|(1<<CS11);. Potom sa z výpočtov TOP rovná 4999 a túto hodnotu zapíšeme do ICR1. | |||
Ďalej, aby sme mohli ovládať polohu servomotora k OCR1A a OCR1B, musíme zapisovať hodnoty, ktoré sú v rozsahu 5-10% z ICR1 (aby sme dostali impulzy 1,0-2,0 ms, ktoré nám dajú 0° - 180°), kde 7,5 % bude počiatočná pozícia. | |||
=== Algoritmus a program === | |||
Zdrojový kód do drziaka kamery | |||
<tabs> | <tabs> | ||
<tab name="AVR C-code(s vrátením polohy kamery)"><source lang="c++" style="background: LightYellow;"> | |||
#define F_CPU 16000000UL // Define CPU Frequency()16MHz | |||
#include <avr/io.h> // Include AVR std. library file | |||
#include <stdio.h> // Include std. library file | |||
#include <util/delay.h> // Include Delay header file | |||
void ADC_Init() // ADC Initialization function | |||
{ | |||
DDRC=0x00; // Make ADC port as input | |||
ADCSRA = 0x87; // Enable ADC, with freq/128 | |||
ADMUX = 0x40; // Vref: Avcc, ADC channel: 0 | |||
} | |||
int ADC_Read(char channel) | |||
{ | |||
ADMUX = 0x40 | (channel & 0x07); // set input channel to read | |||
ADCSRA |= (1<<ADSC); // Start ADC conversion | |||
while (!(ADCSRA & (1<<ADIF))); | |||
/* Wait until end of conversion by polling ADC interrupt flag*/ | |||
ADCSRA |= (1<<ADIF); // Clear interrupt flag | |||
_delay_ms(1); // Wait a little bit | |||
return ADCW; // Return ADC word | |||
} | |||
int main(void) | |||
{ | |||
ADC_Init(); // ADC initialize function | |||
DDRB|=(1<<PB1)|(1<<PB2); // Make OC1A and OC1B pin as output | |||
TCNT1 = 0; // Set timer1 count zero | |||
ICR1 = 4999; // Set TOP count for timer1 in ICR1 register //50Hz for 20ms pulse width | |||
/* Set Fast PWM, TOP in ICR1, Clear OC1A, OC1B on compare match, clk/64 */ | |||
TCCR1A = (1<<WGM11)|(1<<COM1A1)|(1<<COM1B1); | |||
TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10)|(1<<CS11); | |||
while(1) | |||
{ | |||
OCR1A = 90 + (ADC_Read(0)/2); // Read ADC channel 0 and make count in between 90-600 | |||
OCR1B = 90 + (ADC_Read(1)/2); // Read ADC channel 1 and make count in between 90-600 | |||
_delay_ms(16); // wait a bit | |||
} | |||
return(0); | |||
} | |||
</source></tab> | |||
<tab name="AVR C-code(bez návratu polohy kamery)"><source lang="c++" style="background: LightYellow;"> | <tab name="AVR C-code(bez návratu polohy kamery)"><source lang="c++" style="background: LightYellow;"> | ||
#define F_CPU 16000000UL // Define CPU Frequency()16MHz | |||
#define F_CPU 16000000UL // Define CPU Frequency()16MHz | #include <avr/io.h> // Include AVR std. library file | ||
#include <avr/io.h> | #include <stdio.h> // Include std. library file | ||
#include <stdio.h> | #include <util/delay.h> // Include Delay header file | ||
#include <util/delay.h> | |||
void ADC_Init() | void ADC_Init() // ADC Initialization function | ||
{ | { | ||
DDRC=0x00; | DDRC=0x00; // Make ADC port as input | ||
ADCSRA = 0x87; | ADCSRA = 0x87; // Enable ADC, with freq/128 | ||
ADMUX = 0x40; | ADMUX = 0x40; // Vref: Avcc, ADC channel: 0 | ||
} | } | ||
int ADC_Read(char channel) | int ADC_Read(char channel) | ||
{ | { | ||
ADMUX = 0x40 | (channel & 0x07); // set input channel to read | ADMUX = 0x40 | (channel & 0x07); // set input channel to read | ||
ADCSRA |= (1<<ADSC); | ADCSRA |= (1<<ADSC); // Start ADC conversion | ||
while (!(ADCSRA & (1<<ADIF))); | while (!(ADCSRA & (1<<ADIF))); | ||
/* Wait until end of conversion by polling ADC interrupt flag*/ | /* Wait until end of conversion by polling ADC interrupt flag*/ | ||
ADCSRA |= (1<<ADIF); | ADCSRA |= (1<<ADIF); // Clear interrupt flag | ||
_delay_ms(1); | _delay_ms(1); // Wait a little bit | ||
return ADCW; | return ADCW; // Return ADC word | ||
} | } | ||
int main(void) | int main(void) | ||
{ | { | ||
ADC_Init(); | ADC_Init(); // ADC initialize function | ||
DDRB|=(1<<PB1)|(1<<PB2); | DDRB|=(1<<PB1)|(1<<PB2); // Make OC1A and OC1B pin as output | ||
TCNT1 = 0; | TCNT1 = 0; // Set timer1 count zero | ||
ICR1 = 4999; | ICR1 = 4999; // Set TOP count for timer1 in ICR1 register //50Hz for 20ms pulse width | ||
/* Set Fast PWM, TOP in ICR1, Clear OC1A, OC1B on compare match, clk/64 */ | /* Set Fast PWM, TOP in ICR1, Clear OC1A, OC1B on compare match, clk/64 */ | ||
Riadok 105: | Riadok 160: | ||
TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10)|(1<<CS11); | TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10)|(1<<CS11); | ||
int c_X = 90 + 512/2; | int c_X = 90 + 512/2; // The value of the initial position | ||
int c_Y = 90 + 512/2; | int c_Y = 90 + 512/2; // The value of the initial position | ||
int ADC_ValueX; | int ADC_ValueX; | ||
int ADC_ValueY; | int ADC_ValueY; | ||
OCR1A = c_X; | OCR1A = c_X; // motor to the initial position | ||
OCR1B = c_Y; | OCR1B = c_Y; // motor to the initial position | ||
while(1) | while(1) | ||
{ | { | ||
ADC_ValueX = ADC_Read(0); // reading the value from the joystick | ADC_ValueX = ADC_Read(0); // reading the value from the joystick | ||
ADC_ValueY = ADC_Read(1); // reading the value from the joystick | ADC_ValueY = ADC_Read(1); // reading the value from the joystick | ||
if(ADC_ValueX >= 715) | if(ADC_ValueX >= 715) // when the joystick is tilted from its initial position | ||
{ | { | ||
c_X = c_X +5; | c_X = c_X +5; // changing the position value | ||
if(c_X >=600) {c_X = 600;} // to stay in the range of 90 - 600 | if(c_X >=600) {c_X = 600;} // to stay in the range of 90 - 600 | ||
if(c_X <=90) {c_X = 90;} // to stay in the range of 90 - 600 | if(c_X <=90) {c_X = 90;} // to stay in the range of 90 - 600 | ||
} | } | ||
if(ADC_ValueX <= 310) | if(ADC_ValueX <= 310) | ||
Riadok 143: | Riadok 198: | ||
if(c_Y <=90) {c_Y = 90;} | if(c_Y <=90) {c_Y = 90;} | ||
} | } | ||
OCR1A = c_X; | OCR1A = c_X; // setting the motor to a new value | ||
OCR1B = c_Y; | OCR1B = c_Y; // setting the motor to a new value | ||
_delay_ms(16); | _delay_ms(16); // wait a bit | ||
} | } | ||
return(0); | return(0); | ||
} | } | ||
</source></tab> | </source></tab> | ||
</tabs> | </tabs> | ||
Zdrojový kód: [[Médiá:Matsibora_a_Fietisov_projekt.zip|zdrojaky.zip]] | Zdrojový kód: [[Médiá:Matsibora_a_Fietisov_projekt.zip|zdrojaky.zip]] | ||
Riadok 204: | Riadok 211: | ||
Všetko sme spojili, ako je popísané vyššie. Pomocou Datasheetu sme skontrolovali napäťové charakteristiky našich dielov a vyšlo toto: | Všetko sme spojili, ako je popísané vyššie. Pomocou Datasheetu sme skontrolovali napäťové charakteristiky našich dielov a vyšlo toto: | ||
[[Súbor: | [[Súbor:Matsibora_a_Fietisov_fotka1.jpg|400px|thumb|center|Projekt.]] | ||
[[Súbor:Matsibora_a_Fietisov_fotka2.jpg|400px|thumb|center|Projekt.]] | |||
[[Súbor:Matsibora_a_Fietisov_fotka3.jpg|400px|thumb|center|Projekt.]] | |||
V jednom prípade polohy servopohonov nasledujú polohu joysticku a pohybujú sa, kým posúvame joystick, v druhom - servopohony posúvame smerom, kam ukazuje joystick, a zostanú tam, kým opäť neposunieme páčku alebo nezmeníme smer. | |||
'''Video:''' | '''Video:''' | ||
<center><youtube> | <center><youtube>https://youtube.com/shorts/E7s8BPjaMC8?feature=share</youtube></center> - s vratenym polohy kamery | ||
<center><youtube>https://youtube.com/shorts/G25c8ePBXMc</youtube></center> - bez vratenia polohy kamery | |||
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte. | Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte. | ||
[[Category:AVR]] [[Category:MIPS]] | [[Category:AVR]] [[Category:MIPS]] |
Aktuálna revízia z 20:26, 10. máj 2024
Záverečný projekt predmetu MIPS / LS2024 - Viacheslav Matsibora a Dmytro Fietisov
Dvojosová kolíska na kameru ovládaná joystickom
Držiak kamery pre servomotory SG90, MG90 a pod. Pohyb namontovanej kamery je možný v dvoch osiach (tzv. pan and tilt držiak kamery). Súčasťou balenia sú 4 kusy plastových komponentov a skrutky s maticami. Pre plnú funkčnosť budeme potrebovať 2 servomotory.
Takže budeme používať dva spôsoby riadenia servopohonmi: prvý, keď servopohony nasledujú polohu joysticku a pohybujú sa, kým posúvame joystick, druhý - servopohony začnú pohybovať smerom, kam ukazuje joystick, a zostanú tam, kým opäť neposunieme páčku alebo nezmeníme smer.
Zadanie
Rozhodli sme sa naprogramovať držiak na kameru, ktorý by sa otáčal doľava a doprava a samotná kamera sa pohybovala vertikálne. V našom prípade pôjde o dva typy pohybu a dva programy:
1.) keď servopohony nasledujú polohu joysticku a pohybujú sa, kým posúvame joystick.
2.)servopohony pohybovať smerom, kam ukazuje joystick, a zostanú tam, kým opäť neposunieme páčku alebo nezmeníme smer.
Literatúra:
Analýza a opis riešenia
Celý projekt obsahuje dosku Arduino, dvojosový joystick, dva servá sg90, prepojovacie vodiče a samotný držiak kamery.
Použitý joystik má 5 pinov (Vcc, GND, Xaxis, Yaxis a kolík tlačidla). Joystick má 2 centrované potenciometre, pri napájaní produkujú analógový signál a pri použití s Arduino má nasledujúce hodnoty: „0-1023“ a keďže sú v pohotovostnom režime vycentrované, vytvárajú hodnoty okolo „512“ a tlačidlo má digitálny výstup 0/1.
Musíme byť opatrní s joystickom, pretože sú dosť lacné a môže fungovať iba jedna os, čo sa stalo v našom prípade. Na kontrolu osej sme použili terminal PuTTY.
Ďalej budeme hovoriť o servomotoroch.
Servomotory majú tri vodiče: GND/VCC/signál, v tomto prípade je napájaný 5V z Arduina, môžme použiť 9V alebo 12V, ale najprv si prečítajme datasheet list servomotora, aby sme poznali podporované napätie. Externý zdroj napájania musí mať spoločnú zem. Mame take charakteristiky motorčekov:
Napätie: 3V ~ 7.2V Rýchlosť 0,12 s/60° Točivý moment (@ U=4,8V)1,2 kg.cm Točivý moment (@ U=6V) 1,6 kg.cm Uhol natočenia: 180° Hmotnosť: 14g Rozmery(mm): 22 x 11,5 x 27
Servomotor je kombináciou DC motora, systému riadenia polohy, prevodov. Polohu hriadeľa DC motora nastavuje riadiaca elektronika v servo na základe duty ratio PWM signálu na pine SIGNAL. Jednoducho povedané, riadiaca elektronika nastavuje polohu hriadeľa ovládaním DC motora. Tieto údaje o polohe hriadeľa sa odosielajú cez pin SIGNAL. Údaje o polohe do riadenia by sa mali odosielať vo forme signálu PWM cez signálny pin servomotora.Generovanie PWM bolo riešené pomocou 16-bitového počítadla a časovača T1. Potom pre Т1: režim Fast PWM. To, ktorý režim PWM chceme používať sa nastavuje bitmi WGM13...WGM10, ktoré sú rozdelené do registrov TCCR1A a TCCR1B.
Ďalej musíme vypočítať frekvenciu signálu, na to použijeme vzorec z datasheetu.
fcpu je 16MHz, fpwm by malo byť 50Hz, N – preddelička. Sme zvolili 64, teda preddeličku nastavíme takto TCCR1B = (1<<CS10)|(1<<CS11);. Potom sa z výpočtov TOP rovná 4999 a túto hodnotu zapíšeme do ICR1. Ďalej, aby sme mohli ovládať polohu servomotora k OCR1A a OCR1B, musíme zapisovať hodnoty, ktoré sú v rozsahu 5-10% z ICR1 (aby sme dostali impulzy 1,0-2,0 ms, ktoré nám dajú 0° - 180°), kde 7,5 % bude počiatočná pozícia.
Algoritmus a program
Zdrojový kód do drziaka kamery
#define F_CPU 16000000UL // Define CPU Frequency()16MHz
#include <avr/io.h> // Include AVR std. library file
#include <stdio.h> // Include std. library file
#include <util/delay.h> // Include Delay header file
void ADC_Init() // ADC Initialization function
{
DDRC=0x00; // Make ADC port as input
ADCSRA = 0x87; // Enable ADC, with freq/128
ADMUX = 0x40; // Vref: Avcc, ADC channel: 0
}
int ADC_Read(char channel)
{
ADMUX = 0x40 | (channel & 0x07); // set input channel to read
ADCSRA |= (1<<ADSC); // Start ADC conversion
while (!(ADCSRA & (1<<ADIF)));
/* Wait until end of conversion by polling ADC interrupt flag*/
ADCSRA |= (1<<ADIF); // Clear interrupt flag
_delay_ms(1); // Wait a little bit
return ADCW; // Return ADC word
}
int main(void)
{
ADC_Init(); // ADC initialize function
DDRB|=(1<<PB1)|(1<<PB2); // Make OC1A and OC1B pin as output
TCNT1 = 0; // Set timer1 count zero
ICR1 = 4999; // Set TOP count for timer1 in ICR1 register //50Hz for 20ms pulse width
/* Set Fast PWM, TOP in ICR1, Clear OC1A, OC1B on compare match, clk/64 */
TCCR1A = (1<<WGM11)|(1<<COM1A1)|(1<<COM1B1);
TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10)|(1<<CS11);
while(1)
{
OCR1A = 90 + (ADC_Read(0)/2); // Read ADC channel 0 and make count in between 90-600
OCR1B = 90 + (ADC_Read(1)/2); // Read ADC channel 1 and make count in between 90-600
_delay_ms(16); // wait a bit
}
return(0);
}
#define F_CPU 16000000UL // Define CPU Frequency()16MHz
#include <avr/io.h> // Include AVR std. library file
#include <stdio.h> // Include std. library file
#include <util/delay.h> // Include Delay header file
void ADC_Init() // ADC Initialization function
{
DDRC=0x00; // Make ADC port as input
ADCSRA = 0x87; // Enable ADC, with freq/128
ADMUX = 0x40; // Vref: Avcc, ADC channel: 0
}
int ADC_Read(char channel)
{
ADMUX = 0x40 | (channel & 0x07); // set input channel to read
ADCSRA |= (1<<ADSC); // Start ADC conversion
while (!(ADCSRA & (1<<ADIF)));
/* Wait until end of conversion by polling ADC interrupt flag*/
ADCSRA |= (1<<ADIF); // Clear interrupt flag
_delay_ms(1); // Wait a little bit
return ADCW; // Return ADC word
}
int main(void)
{
ADC_Init(); // ADC initialize function
DDRB|=(1<<PB1)|(1<<PB2); // Make OC1A and OC1B pin as output
TCNT1 = 0; // Set timer1 count zero
ICR1 = 4999; // Set TOP count for timer1 in ICR1 register //50Hz for 20ms pulse width
/* Set Fast PWM, TOP in ICR1, Clear OC1A, OC1B on compare match, clk/64 */
TCCR1A = (1<<WGM11)|(1<<COM1A1)|(1<<COM1B1);
TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10)|(1<<CS11);
int c_X = 90 + 512/2; // The value of the initial position
int c_Y = 90 + 512/2; // The value of the initial position
int ADC_ValueX;
int ADC_ValueY;
OCR1A = c_X; // motor to the initial position
OCR1B = c_Y; // motor to the initial position
while(1)
{
ADC_ValueX = ADC_Read(0); // reading the value from the joystick
ADC_ValueY = ADC_Read(1); // reading the value from the joystick
if(ADC_ValueX >= 715) // when the joystick is tilted from its initial position
{
c_X = c_X +5; // changing the position value
if(c_X >=600) {c_X = 600;} // to stay in the range of 90 - 600
if(c_X <=90) {c_X = 90;} // to stay in the range of 90 - 600
}
if(ADC_ValueX <= 310)
{
c_X = c_X -5;
if(c_X >=600) {c_X = 600;}
if(c_X <=90) {c_X = 90;}
}
if(ADC_ValueY >= 715)
{
c_Y = c_Y +5;
if(c_Y >=600) {c_Y = 600;}
if(c_Y <=90) {c_Y = 90;}
}
if(ADC_ValueY <= 310)
{
c_Y = c_Y -5;
if(c_Y >=600) {c_Y = 600;}
if(c_Y <=90) {c_Y = 90;}
}
OCR1A = c_X; // setting the motor to a new value
OCR1B = c_Y; // setting the motor to a new value
_delay_ms(16); // wait a bit
}
return(0);
}
Zdrojový kód: zdrojaky.zip
Overenie
Všetko sme spojili, ako je popísané vyššie. Pomocou Datasheetu sme skontrolovali napäťové charakteristiky našich dielov a vyšlo toto:
V jednom prípade polohy servopohonov nasledujú polohu joysticku a pohybujú sa, kým posúvame joystick, v druhom - servopohony posúvame smerom, kam ukazuje joystick, a zostanú tam, kým opäť neposunieme páčku alebo nezmeníme smer.
Video:
- s vratenym polohy kamery
- bez vratenia polohy kamery
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.