Voir la source de Carte Romeo
De Wiki Arobose
Aller à :
Navigation
,
rechercher
La carte ROMEO de DFROBOT est une carte tout-en-un conçue pour faire ses premiers pas vers la robotique. Cette carte très simple d'utilisation permet de commander 2 moteurs, d'interfacer des capteurs et de piloter le robot à distance via un module X-bee. Elle est basée sur un microcontroleur ATMEGA32u4 (V2.0 R3). Pour tester la carte ROMEO, nous avons utilisé la plateforme de développement Turtle 2WD de DFROBOT. Cette plateforme est équipée de 2 roues montées en direct sur 2 motoréducteurs. == Commande des moteurs == Le moteur à courant continu est l'élément principal qui permet au robot de se déplacer. Sa vitesse est proportionnelle à la tension d'alimentation. Plus la tension est élevée plus le moteur va tourner rapidement. Il faut donc créer une tension continue variable pour faire varier la vitesse du moteur. === Signaux PWM === Les signaux PWM permettent de fournir une tension continue variable à partir de signaux numériques (0 et 5V). Le microcontroleur va générer un signal en forme de créneaux. En faisant varier le rapport cyclique, la tension moyenne va varier et le moteur va tourner plus ou moins vite. === Electronique === La carte ROMEO est équipée d'un module de commande pour moteur à courant continu (L298). Ce pont H va fournir la puissance nécessaire au moteur pour tourner. Le microcontroleur va fournir un signal PWM et un signal de direction pour chaque moteur. === Exemple de code === ==== Langage Arduino ==== Le L298 utilise la pin 4 (M1 : direction) et 5 (E1 : PWM) pour le moteur 1 et la pin 6 (E2 : PWM) et 7 (M2 : direction) pour le moteur 2. Un exemple avec le langage ARDUINO est expliqué [http://www.dfrobot.com/wiki/index.php/DFRduino_Romeo-All_in_one_Controller_V1.1%28SKU:DFR0004%29 ici] ==== Langage C ==== ===== Fonctions PWM ===== Pour générer un signal PWM, le microcontroleur a besoin d'un timer interne. Il utilise le timer 3A pour E1 et le timer 4D pour E2. Dans un premier temps, il faut initialiser les timers en mode PWM. Nous configurons le mode PWM avec des valeurs fréquemment utilisées pour la commande de moteurs. <syntaxhighlight lang="c"> /* timer3 is used for phase-correct 8-bits PWM mode and with clock prescaled to system clock divided by 64 */ void pwm_3_setup(void) { /* set timer3 prescale factor to 64 */ TCCR3B = (1 << CS31) | (1 << CS30); /* put timer3 in phase correct PWM mode */ TCCR3A = (1 << WGM30); } /* timer4 is used for phase and frequency correct 10-bits PWM mode * and with clock prescaled to system clock divided by 64 */ void pwm_4_setup(void) { TC4H = 0; /* set timer4 prescale factor to 64 */ TCCR4B = (1 << CS42) | (1 << CS41) | (1 << CS40); /* put timer 4 in phase and frequency correct PWM mode */ TCCR4D =(1 << WGM40); /* not used */ TCCR4E = 0; /* Set top to 0xFF */ OCR4C = 0xFF; } </syntaxhighlight> Il faut activer les pins utilisées par le L298 (5:OC3A et 6:OC4D). <syntaxhighlight lang="c"> /* enable OC4D (pin D6) as pwm output */ void pwm_3A_enable(void) { /* enable PC6(OC3A) pin as output pin */ DDRC |= (1 << PORTC6); /* enable OC3A pin as PWM pin */ TCCR3A |= (1 << COM3A1); } /* enable OC4D (pin D6) as pwm output */ void pwm_4D_enable(void) { /* enable PD7 pin as output pin */ DDRD |= (1 << PORTD7); /* enable OC4D pin as PWM pin */TCCR4C |= (1 << PWM4D); TCCR4C |= (1 << COM4D1); } </syntaxhighlight> Pour finir, il faut indiquer la valeur du PWM : cette valeur indique le temps haut du signal compris entre 0 et 255. Par exemple, pour avoir un signal carré (temps haut = temps bas), il faut avoir une valeur de 127. Ces valeurs sont écrites dans les registres OCRnx. <syntaxhighlight lang="c"> /* write value a in PWM 3A */ void pwm_3A_write(char a) { OCR3A = a; } /* write value a in PWM 4D */ void pwm_4D_write(char a) { OCR4D = a; } </syntaxhighlight> ===== Fonctions moteur ===== Nous avons ensuite créer des fonctions qui permettent au robot d'avancer, reculer et tourner en précisant la vitesse (de 0 à 255). <syntaxhighlight lang="c"> void motor_setup(void) { /* Motor controller */ DDRD = (1 << PORTD4); /* E1 (PD4) as output pin */ DDRE = (1 << PORTE6); /* E2 (PE6) as output pin */ pwm_3_setup(); pwm_4_setup(); pwm_3A_enable(); pwm_4D_enable(); } /* stop */ void stop(void) { PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */ PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */ pwm_4D_write(0); pwm_3A_write(0); } /* advance * speed from 0 to 255 */ void advance(uint8_t m1_speed, uint8_t m2_speed) { PORTD |= (1 << PORT4); /* E1 (PD4) = 1 */ PORTE |= (1 << PORT6); /* E2 (PE6) = 1 */ pwm_3A_write(m1_speed); pwm_4D_write(m2_speed); } /* back off * speed from 0 to 255 */ void back_off(uint8_t m1_speed, uint8_t m2_speed) { PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */ PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */ pwm_3A_write(m1_speed); pwm_4D_write(m2_speed); } /* turn left * speed from 0 to 255 */ void turn_left(uint8_t m1_speed, uint8_t m2_speed) { PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */ PORTE |= (1 << PORT6); /* E2 (PE6) = 1 */ pwm_3A_write(m1_speed); pwm_4D_write(m2_speed); } /* turn right * speed from 0 to 255 */ void turn_right(uint8_t m1_speed, uint8_t m2_speed) { PORTD |= (1 << PORT4); /* E1 (PD4) = 1 */ PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */ pwm_3A_write(m1_speed); pwm_4D_write(m2_speed); } </syntaxhighlight> Pour finir, les fonctions main() et setup() <syntaxhighlight lang="c"> void pin_setup(void) { /* Motor controller */ DDRD = (1 << PORTD4); /* PD4 as output pin */ DDRE = (1 << PORTE6); /* PE6 as output pin */ } void setup(void) { pin_setup(); pwm_3_setup(); pwm_4_setup(); pwm_3A_enable(); pwm_4D_enable(); } int main(void) { setup(); while (1) { turn_left(100); //advance(200); // stop(); } return 0; } </syntaxhighlight> == Communication XBee == Les modules Xbee de digi sont des modules de communication sans fils respectant la norme 802.15.4. Ces modules sont très simples à utiliser car ils convertissent les signaux Xbee en commande série. La carte ROMEO est conçue pour recevoir un module Xbee lui permettant de communiquer à distance via sa liaison série. Le module est branché sur les pins 0 (RXD1) et 1 (TXD1) du microcontroleur utilisant l'USART 1. === Commande à distance === Nous allons utiliser ce module pour piloter le robot à distance à partir du PC en envoyant un caractère de commande à la carte ROMEO. Pour cela, il faut également un module et un adaptateur XBee USB pour le PC. Dans un premier temps, nous allons configurer la liaison série. Le message envoyé contient 8 bits de données et 1 bit de stop sans contrôle de parité. La vitesse de transmission est de 9600 bauds. <syntaxhighlight lang="c"> /* setup USART1 * speed : 9600 Baud * 8-bits, no parity, 1-stop-bit */ void USART_1_setup(void) { PORTD &= ~(1 << PORT2); /* initialize pin PD2 (RX) as input pin */ PORTD |= (1 << PORT3); /* initialize pin PD3 (TX) as output pin */ UBRR1 = 103; /* 9600 Baud at 16MHz */ UCSR1A = 0; /* 8-bits, no parity, 1-stop-bit */ UCSR1C = (1 << UCSZ11) | (1 << UCSZ10); } </syntaxhighlight> Il existe 2 solutions pour recevoir une donnée via la liaison série : La première solution est très simple mais elle est bloquante. En effet, si aucune donnée n'est reçue (perte de communication), le programme va rester bloqué dans le « while » ce qui peut être gênant pour le système. <syntaxhighlight lang="c"> void USART_1_receiver_enable(void) { UCSR1B |= (1 << RXEN1); } unsigned char USART_1_receive(void) { // wait for data to be received while (!(UCSR1A & (1 << RXC1))) ; // get and return received data from buffer return UDR1 ; } </syntaxhighlight> La seconde solution utilise les interruptions. La fonction ISR est exécutée seulement quand une donnée est reçue (flag levé). Le reste du temps, le programme est exécuté normalement sans attendre la réception d'une donnée. <syntaxhighlight lang="c"> volatile char receive_char; void USART_1_receiver_interrupt_enable(void) { UCSR1B |= (1 << RXEN1); /* enable interrupt on the RXC1 flag */ UCSR1B |= (1 << RXCIE1); SREG |= (1 << SREG_I); } // receiver interrupt ISR( USART1_RX_vect) { unsigned char dustbin = 0; receive_char = UDR1; } </syntaxhighlight> La fonction principale va tester le caractère reçu : 'a' pour avancer, 'b' pour reculer, 'r' pour tourner a droite, 'l' pour tourner à gauche et n'importe quel autre caractère pour s’arrêter. <syntaxhighlight lang="c"> void pin_setup(void) { /* Motor controller */ DDRD = (1 << PORTD4); /* PD4 as output pin */ DDRE = (1 << PORTE6); /* PE6 as output pin */ } void setup(void) { pin_setup(); pwm_3_setup(); pwm_4_setup(); pwm_3A_enable(); pwm_4D_enable(); USART_1_setup(); //USART_1_receiver_enable(); USART_1_receiver_interrupt_enable(); } int main(void) { //char c; setup(); while (1) { //c = USART_1_receive(); switch (/*c*/receive_char) { case 'a': advance(100); break; case 'b': back_off(100); break; case 'r': turn_right(100); break; case 'l': turn_left(100); break; default: stop(); break; } } return 0; } </syntaxhighlight> == Conversion analogique / numérique == Les capteurs que nous utilisons retourne généralement une information (tension) sous forme analogique. Pour exploiter cette information, le microcontroleur doit la convertir en signal numérique. Le convertisseur analogique / numérique de l'ATMEGA32U4 est un convertisseur 10 bits soit une précision de 1024 points. En se basant sur une tension de référence (généralement la tension d'alimentation), il va, par approximation successive, définir la valeur numérique correspondante à la tension. Dans un premier temps, nous allons configurer le convertisseur. Le microcontroleur a 6 entrées analogiques sur le port F qu'il faut configurer en entrée. La tension de référence pour effectuer la conversion est la tension d'alimentation Vcc = 5V. <syntaxhighlight lang="c"> /* Voltage reference : Vcc * Right adjust result * and with clock prescaled to system clock divided by 1024 */ void adc_setup(void) { /* initialize PORTF pins as input pin */ DDRF = 0x00; /* set ADC prescale factor to 1024 */ ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); /* Vcc is reference voltage */ ADMUX |= (1 << REFS0); /* Set ADC to Free-Running Mode */ ADCSRB = 0; /* adc enable */ ADCSRA |= (1 << ADEN); } </syntaxhighlight> Ensuite, nous allons lire la valeur de chaque entrée en démarrant la conversion. <syntaxhighlight lang="c"> void adc_start_conversion(uint8_t pin) { //adc_enable(pin); ADMUX = (1 << REFS0) | pin; DIDR0 = (1 << pin); ADCSRA |= (1 << ADSC); // adc start conversion } uint16_t adc_read(uint8_t pin) { uint8_t low; adc_start_conversion(pin); while (ADCSRA & (1 << ADSC)) ; // wait for result low = ADCL; // must read LSB first return (ADCH << 8) | low; // must read MSB only once! } </syntaxhighlight> [[Category:Produits]]
Revenir à la page
Carte Romeo
.
Affichages
Page
Discussion
Voir le texte source
Historique
Outils personnels
Connexion
Navigation
Accueil
Communauté
Actualités
Modifications récentes
Page au hasard
Aide
Rechercher
Boîte à outils
Pages liées
Suivi des pages liées
Pages spéciales
Catégories
[
×
]
Produits
[
×
]
Tutoriels