Carte Romeo

De Wiki Arobose
(Langage C)
m (Commande à distance)
 
Ligne 21 : Ligne 21 :
  
 
==== Langage C ====
 
==== 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.
 
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.
  
Ligne 95 : Ligne 96 :
 
</syntaxhighlight>
 
</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).
 
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">
 
<syntaxhighlight lang="c">
 +
 
/* stop */
 
/* stop */
 
void
 
void
 
stop(void)
 
stop(void)
 
{
 
{
 +
  PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */
 +
  PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */
 
   pwm_4D_write(0);
 
   pwm_4D_write(0);
 
   pwm_3A_write(0);
 
   pwm_3A_write(0);
Ligne 108 : Ligne 113 :
 
  * speed from 0 to 255 */
 
  * speed from 0 to 255 */
 
void
 
void
advance(char speed)
+
advance(uint8_t m1_speed, uint8_t m2_speed)
 
{
 
{
 
   PORTD |= (1 << PORT4); /* E1 (PD4) = 1 */
 
   PORTD |= (1 << PORT4); /* E1 (PD4) = 1 */
 
   PORTE |= (1 << PORT6); /* E2 (PE6) = 1 */
 
   PORTE |= (1 << PORT6); /* E2 (PE6) = 1 */
   pwm_4D_write(speed);
+
   pwm_3A_write(m1_speed);
   pwm_3A_write(speed);
+
   pwm_4D_write(m2_speed);
 
}
 
}
  
Ligne 119 : Ligne 124 :
 
  * speed from 0 to 255 */
 
  * speed from 0 to 255 */
 
void
 
void
back_off(char speed)
+
back_off(uint8_t m1_speed, uint8_t m2_speed)
 
{
 
{
 
   PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */
 
   PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */
 
   PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */
 
   PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */
   pwm_4D_write(speed);
+
   pwm_3A_write(m1_speed);
   pwm_3A_write(speed);
+
   pwm_4D_write(m2_speed);
 
}
 
}
  
Ligne 130 : Ligne 135 :
 
  * speed from 0 to 255 */
 
  * speed from 0 to 255 */
 
void
 
void
turn_left(char speed)
+
turn_left(uint8_t m1_speed, uint8_t m2_speed)
 
{
 
{
 
   PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */
 
   PORTD &= ~(1 << PORT4); /* E1 (PD4) = 0 */
 
   PORTE |= (1 << PORT6); /* E2 (PE6) = 1 */
 
   PORTE |= (1 << PORT6); /* E2 (PE6) = 1 */
   pwm_4D_write(speed);
+
   pwm_3A_write(m1_speed);
   pwm_3A_write(speed);
+
   pwm_4D_write(m2_speed);
 +
 
 
}
 
}
  
Ligne 141 : Ligne 147 :
 
  * speed from 0 to 255 */
 
  * speed from 0 to 255 */
 
void
 
void
turn_right(char speed)
+
turn_right(uint8_t m1_speed, uint8_t m2_speed)
 
{
 
{
 
   PORTD |= (1 << PORT4); /* E1 (PD4) = 1 */
 
   PORTD |= (1 << PORT4); /* E1 (PD4) = 1 */
 
   PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */
 
   PORTE &= ~(1 << PORT6); /* E2 (PE6) = 0 */
   pwm_4D_write(speed);
+
   pwm_3A_write(m1_speed);
   pwm_3A_write(speed);
+
   pwm_4D_write(m2_speed);
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Pour finir, les fonctions main() et setup()
+
Pour finir, la fonction principale main() et les fonctions setup() qui définissent l'état des pins (entrée ou sortie) et active les modules PWM.
 
<syntaxhighlight lang="c">
 
<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();
 +
}
 +
 +
void
 +
setup(void)
 +
{
 +
  motor_setup();
 +
}
 +
 +
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)
 +
{
 +
  DDRD &= ~(1 << PD2); /* initialize pin PD2 (RX) as input pin */
 +
  DDRD |= (1 << PD3); /* 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
 
void
 
pin_setup(void)
 
pin_setup(void)
Ligne 164 : Ligne 280 :
 
{
 
{
 
   pin_setup();
 
   pin_setup();
 +
 
   pwm_3_setup();
 
   pwm_3_setup();
 
   pwm_4_setup();
 
   pwm_4_setup();
 +
 
   pwm_3A_enable();
 
   pwm_3A_enable();
 
   pwm_4D_enable();
 
   pwm_4D_enable();
 +
 +
  USART_1_setup();
 +
  //USART_1_receiver_enable();
 +
  USART_1_receiver_interrupt_enable();
 
}
 
}
  
Ligne 173 : Ligne 295 :
 
main(void)
 
main(void)
 
{
 
{
 +
  //char c;
 
   setup();
 
   setup();
 +
 
   while (1)
 
   while (1)
  {
+
    {
    turn_left(100);
+
      //c = USART_1_receive();
    //advance(200);
+
 
    // stop();
+
      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;
 
   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>
 
</syntaxhighlight>
  
 
[[Category:Produits]]
 
[[Category:Produits]]

Version actuelle en date du 29 juillet 2013 à 14:29

Catégories