Micro contrôleurs AVR/AVR et robotique : pololu

Leçons de niveau 14
Une page de Wikiversité, la communauté pédagogique libre.
Début de la boite de navigation du chapitre
AVR et robotique : pololu
Icône de la faculté
Chapitre no 13
Leçon : Micro contrôleurs AVR
Chap. préc. :AVR et robotique : ASURO
Chap. suiv. :AVR et robotique : mini-Q 2WD
fin de la boite de navigation du chapitre
En raison de limitations techniques, la typographie souhaitable du titre, « Micro contrôleurs AVR : AVR et robotique : pololu
Micro contrôleurs AVR/AVR et robotique : pololu
 », n'a pu être restituée correctement ci-dessus.

Pololu est comme ASURO une base robotique mobile. Il est cependant plus petit qu'ASURO mais animé par un processeur plus puissant. Bien sûr tout dépend de ce que l’on appelle la puissance d'un microcontroleur puisqu’ils sont tous les deux issus de la famille AVR de chez Atmel, famille de processeurs 8 bits. La puissance dont il est question est essentiellement la taille de mémoire programme, 8 ko pour ASURO contre 32 ko pour Pololu. Sa documentation pour le programmeur peut être trouvée en anglais ICI.

Compilation et programmation[modifier | modifier le wikicode]

Nous allons nous intéresser à la programmation du robot Pololu dans cette section. Nous allons nous cantonner essentiellement au langage C. Bien sûr n’importe quel autre langage peut être utilisé mais vous perdrez alors la librairie associée à ce robot, ce qui est plutôt gênant, sauf si vous avez une connaissance approfondie des timers et autre périphériques.

Notez qu’il existe un moyen d’utiliser l'environnement Arduino pour programmer. Ceci est documenté ICI en anglais et utilisé un peu plus loin dans ce document.

Voici notre programme de départ (trouvé dans la documentation Pololu)

#include <pololu/orangutan.h>
/*
 * lcd1: for the Orangutan controllers and 3pi robot
 *
 * This example uses the OrangutanLCD library to display things on the LCD.
 *
 * http://www.pololu.com/docs/0J20
 * http://www.pololu.com
 * http://forum.pololu.com
 */
 
int main()
{
  while(1)
  {
    print("Hello");           // display "Hello" at (0, 0), a.k.a. upper-left
    delay_ms(200);
    lcd_scroll(LCD_RIGHT, 3, 200);// shift the display right every 200ms three times
    clear();                  // clear the LCD
    lcd_goto_xy(3, 1);             // go to the fourth character of the second LCD line
    print("Hello");           // display "Hello" at (3, 1), a.k.a. lower-right
    delay_ms(200);
    lcd_scroll(LCD_LEFT, 3, 200); // shift the display left every 200ms three times
    clear();                  // clear the LCD
  }
 
  return 0;
}

Ce programme écrit un "Hello" sur l'afficheur et le déplace dans celui-ci. Nous supposerons pour la suite qu’il est dans un fichier qui s’appelle hello.c

Compilation et programmation sous Linux[modifier | modifier le wikicode]

Installation de la librairie[modifier | modifier le wikicode]

Il suffit de télécharger la librairie et de suivre les instructions 2.a. Download Instructions. Comme indiqué dans cette page il y a trois techniques pour procéder :

  • Windows : recommandé de télécharger le "Bundle" pour Windows. C'est un exécutable.
  • Windows : télécharger l'exécutable léger
  • Linux : la librairie toute compilée dans cette même page.

Une fois téléchargé, dé-zipper et copier les librairies dans "/usr/local/avr/lib" ou un répertoire équivalent dépendant de votre installation du compilateur avr-gcc. Pour nous, seul le fichier "libpololu_atmega328p.a" suffit car nous avons un processeur ATMega328p. Copier ensuite le répertoire complet pololu dans "/usr/local/avr/include". Voila, votre librairie est installée.

À ce point vous disposez de la documentation en anglais pour commencer 3. Functional Overview and Example programs

Pour plus d'information encore, lire la référence complète de la librairie Pololu AVR Library Command Reference

Compilation[modifier | modifier le wikicode]

On admettra pour simplifier cette section que votre distribution Linux contient le compilateur avr-gcc et avrdude installés. C'est le cas pour Ubuntu si vous avez le package électronique.

La compilation se fait en trois étapes :

avr-gcc -g -mmcu=atmega328p -Wall -Os -c hello.c  hello.c -I ./
avr-gcc -g -mmcu=atmega328p -o hello.elf -Wl,-Map,hello.map hello.o -L./ -lpololu_atmega328p 
avr-objcopy -R .eeprom -O ihex hello.elf hello.hex
  • L'option -I./ n’est pas nécessaire si vous avez correctement installé votre librairie et en particulier vos fichiers d'inclusions qui sont dans un répertoire "pololu". On rappelle que cette option donne un chemin au compilateur où il doit chercher ces fichiers.
  • L'option -L./ n’est pas nécessaire si vous avez correctement installé votre librairie "libpololu_atmega328p.a". On rappelle que cette option donne un chemin au compilateur où il doit la chercher.

L'objectif de ces trois lignes est de réaliser un fichier d'extension ".hex" (ici hello.hex).

Programmation du composant[modifier | modifier le wikicode]

Le logiciel de programmation utilisé ici est avrdude. La commande ci-dessous doit être lancée dans le répertoire où a été créé le fichier d'extension ".hex".

[smoutou@localhost]$avrdude -p m328p -c avrispv2 -P /dev/ttyACM0 -U flash:w:hello.hex

Évidemment cette ligne n'est valable que si vous utilisez le câble prévu pour pololu (mais vendu séparément).

Par exemple, la documentation Programming with AVRDUDE fait apparaître la ligne de commande :

avrdude -p m328p -P COM6 -c avrispv2 -U flash:w:test.hex

C'est donc à vous d'adapter cette commande à votre cordon matériel de programmation de l'AVR.

Exercice 1[modifier | modifier le wikicode]

Dans 3. Functional Overview and Example programs chercher les exemples correspondants à la gestion de l'afficheur de texte (Orangutan LCD Control Functions) et la gestion des boutons poussoirs (Orangutan Pushbutton Interface Functions) et laisser aller votre imagination pour réaliser des exercices dont vous choisirez le cahier des charges. Par exemple l'appui sur "A" affiche "gauche", l'appui sur "B" affiche "centre" et l'appui sur "C" affiche "droite".

Pour information, les noms symboliques des boutons sont :

  • TOP_BUTTON : bouton "C"
  • MIDDLE_BUTTON : bouton "B"
  • BOTTOM_BUTTON : bouton "A"

Lire aussi la référence complète de la librairie Pololu AVR Library Command Reference

Compilation et programmation sous environnement Arduino[modifier | modifier le wikicode]

Voir ICI, la documentation en anglais pour trouver des informations sur l'installation des librairies Pololu avec l'environnement Arduino.

Sous Linux[modifier | modifier le wikicode]

La gestion de la communication ISP pour la programmation doit être correctement réalisée. Si ce n’est pas le cas :

  • "Outils→Port série→ dev/ttyACM0"
  • "Outils→Programmateur→ AVR ISP v2"
  • "Outils→Type de carte→ Pololu orangutan or 3pi Robot/w ATmega8328p via programmer "

Si tout est installé correctement

  • "Fichier → Exemples" dans la partie inférieure vous avez tous les exemples pour l'environnement Arduino.

L'icone "→" vous permet de compiler et charger directement.

Sous Windows[modifier | modifier le wikicode]

Nous n'avons pas encore essayé mais seule la gestion du port série doit être différente à priori.

Exercice 1 bis[modifier | modifier le wikicode]

Cet exercice est identique à l'exercice 1 mais utilise l'environnement Arduino.

  • Dans "Fichier → exemples →OrangutanLCD→OrangutanLCDExample" choisir le premier exemple correspondant à la gestion de l'afficheur de texte (Orangutan LCD Control Functions).
  • Dans "Fichier → exemples →OrangutanLCD→PushButtonsExamples" choisir l'exemple gérant les boutons poussoirs et lire son code source.
  • Laisser aller votre imagination pour réaliser des exercices dont vous choisirez le cahier des charges. Par exemple l'appui sur "A" affiche "gauche", l'appui sur "B" affiche "centre" et l'appui sur "C" affiche "droite".

Pour information, les noms symboliques des boutons sont :

  • TOP_BUTTON : bouton "C"
  • MIDDLE_BUTTON : bouton "B"
  • BOTTOM_BUTTON : bouton "A"

Documentation de la librairie complète[modifier | modifier le wikicode]

La documentation complète de la librairie se trouve ICI en anglais.

La Propulsion à l'aide des deux moteurs[modifier | modifier le wikicode]

Ce robot est propulsé par deux moto-réducteurs. Voir une présentation de Pololu 3pi.

Cinématique du robot différentiel Pololu[modifier | modifier le wikicode]

Ce travail a déjà été réalisé dans le chapitre sur le robot ASURO de ce livre.

Électronique de commande des moteurs[modifier | modifier le wikicode]

C'est un circuit spécialisé, le TB6612FNG, qui commande les deux moteurs. Il est naturellement interfacé au processeur. Nous commençons par décrire la programmation directe n'utilisant aucune librairie, c'est-à-dire qui écrit directement dans les PORTs du processeur. Même si cette façon de faire est absolument déconseillée pour un projet important, elle reste néanmoins suffisamment pédagogique pour que nous nous y intéressions.

Quelques instructions pour commander les moteurs[modifier | modifier le wikicode]

(traduit à partir de cette page)

On commence par initialiser les entrées/sorties de notre AVR :

#include <avr/io.h>
 
// use Data Direction Registers (DDRx) to
// set the four motor control pins as outputs
DDRD |= (1 << PORTD3) | (1 << PORTD5) | (1 << PORTD6);
DDRB |= (1 << PORTB3);

Voici des commandes destinées au cirsuit TB6612FNG :

  • Pour mettre le moteur1 en pleine vitesse :
PORTD |= (1 << PORTD5); // drive pin PD5 high
PORTD &= ~(1 << PORTD6); // drive pin PD6 low
  • Pour freiner doucement le moteur 1:
PORTD |= (1 << PORTD5) | (1 << PORTD6); // drive pins PD5 and PD6 high
  • Puis pour mettre le moteur2 en pleine vitesse :
PORTD &= ~(1 << PORTD3); // drive pin PD3 low
PORTB |= (1 << PORTB3); // drive pin PB3 high
  • Puis pour mettre le moteur2 en pleine vitesse en marche arrière :
PORTD |= (1 << PORTD3); // drive pin PD3 high
PORTB &= ~(1 << PORTB3); // drive pin PB3 low
  • Pour freiner doucement le moteur 2:
PORTD |= (1 << PORTD3); // drive pin PD3 high
PORTB |= (1 << PORTB3); // drive pin PB3 high

Exemple avec environnement Arduino[modifier | modifier le wikicode]

Voici un exemple complet qui utilise l'environnement Arduino :

#include <avr/io.h>
void setup() // run once, when the sketch starts
{
// use Data Direction Registers (DDRx) to
// set the four motor control pins as outputs
DDRD |= (1 << PORTD3) | (1 << PORTD5) | (1 << PORTD6);
DDRB |= (1 << PORTB3);
}
void loop() // run over and over again
{
  // moteur gauche pleine vitesse
  PORTD |= (1 << PORTD5);    // drive pin PD5 high
  PORTD &= ~(1 << PORTD6);    // drive pin PD6 low
  delay(200);
  // on arrte lentement le moteur gauche
  PORTD |= (1 << PORTD5) | (1 << PORTD6);    // drive pins PD5 and PD6 high
  // moteur droit pleine vitesse
  PORTD &= ~(1 << PORTD3);    // drive pin PD3 low
  PORTB |= (1 << PORTB3);    // drive pin PB3 high
  delay(200);
  // on arrte lentement le moteur droit
  PORTD |= (1 << PORTD3);    // drive pin PD3 high
  PORTB |= (1 << PORTB3);    // drive pin PB3 high
  while(1);
}

Notez le while(1); final qui empêche la boucle loop de se réaliser. Une façon plus élégante de faire cela est probablement de tout mettre dans setup() et rien dans loop().

Pour information, 2. Motor Driver Truth Tables vous donne les informations pour un éventuel changement de sens de moteur

Exercice 2[modifier | modifier le wikicode]

Réaliser un signal de commande des deux moteurs avec un rapport cyclique de 1/3 avec une fréquence d'environ 100 Hz par logiciel dans une boucle (environ 500 fois) pour tester si Pololu avance en ligne droite (lorsqu'on utilise le même rapport cyclique pour les deux moteurs).


Librairie Moteur sous Arduino[modifier | modifier le wikicode]

Voici la les fonctions disponibles dans la librairie "Moteur" accessibles avec

#include <OrangutanMotors.h>

Les fonctions disponibles sont :

void motors_init(void);
void set_m1_speed(int speed);
void set_m2_speed(int speed);
void set_motors(int m1, int m2);

Vous y avez accès de la manière suivante

  1. declaration d'une variable de type OrangutanMotors
#include <OrangutanMotors.h>
//********** ... ************
OrangutanMotors motors;

L'utilisation se fait alors par exemple par :

int motorSpeeds = 255;
//********** ... ************
motors.setSpeeds(motorSpeed, motorSpeed);

Chercher aussi dans la référence complète de la librairie Pololu AVR Library Command Reference

Exercice 3 (Arduino)[modifier | modifier le wikicode]

On vous demande de chercher les fonctions de gestion des moteurs dans l'exemple (Fichier→Exemples→OrangutanMotors→OrangutanMotorExample) et de les mettre en œuvre pour réaliser :

  • 1/4 de tours sur place
  • un cercle complet de rayon intérieur 20 cm
  • une ligne droite de 20 cm, puis 1/4 de tour sur place, puis un cercle de 20 cm de rayon, puis 1/4 de tour puis retour au point de départ

Exercice 3 bis[modifier | modifier le wikicode]

Idem à l'exercice 3 mais directement en C.

Dans 3. Functional Overview and Example programs on vous demande de chercher les fonctions de gestion des moteurs (Orangutan Servo Control Functions) et de les mettre en œuvre pour réaliser :

  • 1/4 de tours sur place
  • un cercle complet de rayon intérieur 20 cm
  • une ligne droite de 20 cm, puis 1/4 de tour sur place, puis un cercle de 20 cm de rayon, puis 1/4 de tour puis retour au point de départ

Les capteurs[modifier | modifier le wikicode]

Une des applications possibles est le suivi de lignes... et pour cela il nous faut savoir si l’on est sur une ligne noire ou si l’on est sur un fond blanc. Nous allons ainsi nous intéresser aux cinq capteurs dédiés à ce problème.

Les capteurs de suivi de ligne : fonctionnement[modifier | modifier le wikicode]

Il s'agit d'une base composée d'une Diode électroluminescente émettant dans l’infrarouge et d'un photo-transistor. La lumière émise par la photodiode est reçue par le photo-transistor après réflexion sur une surface et donc dépend de la réflectance de la surface. C'est cette dépendance qui va être utilisée ici.

On peut donc dire que le courant du transistor dépend lui-même de cette réflectance. Mesurer un courant revient à mesurer une tension (si on envoie le courant dans une résistance) mais nécessite un convertisseur analogique numérique. Pour économiser ces convertisseurs, les concepteurs de Pololu ont imaginé d’utiliser une temporisation pour cette mesure. C'est ce que nous allons expliquer maintenant.

Voici par exemple le schéma du capteur :

Le capteur infrarouge de Pololu

Ce capteur est donc constitué d'un photo-transistor (à gauche de U4) et d'une photo-diode à droite. Entre les deux intervient le sol qui est un milieu plus ou moins réfléchissant. Le fonctionnement de ce capteur est lié au fait que la même broche PC0 (23) peut être alternativement passée en entrée ou en sortie. Lorsqu'elle est positionnée en sortie on peut y mettre un 0 ou un 1 logique. Cela donnera une tension de 0 ou Vcc. Pour nous seul le 0 est utilisé.

Nous allons tenter maintenant d’en expliquer le fonctionnement. Voici les deux schémas équivalents de notre capteur.

Mesurer un temps de décharge pour le capteur infrarouge de Pololu
  • PC0 est positionné en sortie. On le positionne alors à 0 logique, alors une tension de 0 se trouve en PC0 comme dans le schéma équivalent de gauche. La charge du condensateur s'effectue. De quels paramètres dépend le temps de charge ? Évidemment du couple R et C mais aussi du courant du photo-transistor schématisé ici par son générateur de courant équivalent. L’idée est de charger suffisamment longtemps de manière indépendante du photo-transistor.
  • PC0 est positionné en entrée. Maintenant c’est le photo-transistor qui décharge (à courant constant ou pas) et il est clair que le temps de décharge dépend essentiellement du courant correspondant, c'est-à-dire de la réflectance. Le mesurer donnera une information en ce sens.

Les capteurs de suivi de ligne : schéma complet[modifier | modifier le wikicode]

Dans la section précédente, nous avons présenté un seul capteur. Il y en a cinq dans Pololu, et il nous faut donc montrer comment ils sont connectés.

Les capteurs de suivi de ligne : programmation[modifier | modifier le wikicode]

Voici en résumé comment on procède :

// ...
unsigned int sensors[5];
// ...
while(1){
		// Get the position of the line. Note that we *must* provide
		// the "sensors" argument to read_line() here, even though we
		// are not interested in the individual sensor readings.
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);
		if(position < 1000) {
			// We are far to the right of the line: turn left.
                        // Set the right motor to 100 and the left motor to zero,
			// to do a sharp turn to the left. Note that the maximum
			// value of either motor speed is 255, so we are driving
			// it at just about 40% of the max.
			set_motors(0,100);

			// Just for fun, indicate the direction we are turning on
			// the LEDs.
			left_led(1);
			right_led(0);
		}
		else if(position < 3000) {
			// We are somewhat close to being centered on the line:
			// drive straight.
			set_motors(100,100);
			left_led(1);
			right_led(1);
		} else {
			// We are far to the left of the line: turn right.
			set_motors(100,0);
			left_led(0);
			right_led(1);
		}
	}

Pour un bon fonctionnement, ce programme donné en exemple nécessite une calibration des capteurs.

Lire aussi la référence complète de la librairie Pololu AVR Library Command Reference

Exercice 4 (Environnement Arduino)[modifier | modifier le wikicode]

Lancer l'IDE Arduino.

On va partir de "Fichier → Exemples → Pololu 3pi → Simple3piLineFollower" qui réalise un suiveur de ligne simple comme son non l'indique !

  1. Utiliser le programme d'exemple qui réalise une calibration des capteurs (photo transistors) pour trouver la valeur retournée quand les cinq capteurs sont sur une ligne. Cette valeur devrait théoriquement suffire mais en pratique vous n'allez pas forcément arriver de manière perpendiculaire à une ligne ! Il faut donc mieux s'intéresser aux valeurs retournées quand on est sur le blanc. Nous en avons trouvé deux qui sont absolument indispensables pour la suite.
  2. On vous demande de réaliser un programme qui est une variation de cet exemple. Il s'agit de mettre le robot dans un enclos fermé et de le faire avancer jusqu'à détection d'un mur. Une fois le mur détecté, on fait une petite marche arrière, on tourne de 90° et on repart en avant. Les vitesses des moteurs seront d'environ 30 plutôt que les 100 de l'exemple !!!!
  3. L'enclos possède maintenant une ouverture (pas forcément facile à trouver). On vous demande de faire un programme qui permet au Pololu d'explorer l'enceinte et de trouver sa sortie.

Indications[modifier | modifier le wikicode]

Lire la documentation 3.QTRSensors Methods & Usage Notes pour décider si "robot.readline()" est adaptée à ce travail.

La partie intéressante à modifier se trouve dans :

void loop()
{
  // Get the position of the line.  Note that we *must* provide
  // the "sensors" argument to read_line() here, even though we
  // are not interested in the individual sensor readings.
  unsigned int position = robot.readLine(sensors, IR_EMITTERS_ON);
  if (position < 1000)
  {
    // We are far to the right of the line: turn left.

    // Set the right motor to 100 and the left motor to zero,
    // to do a sharp turn to the left.  Note that the maximum
    // value of either motor speed is 255, so we are driving
    // it at just about 40% of the max.
    OrangutanMotors::setSpeeds(0, 100);

    // Just for fun, indicate the direction we are turning on
    // the LEDs.
    OrangutanLEDs::left(HIGH);
    OrangutanLEDs::right(LOW);
  }
  else if (position < 3000)
  {
    // We are somewhat close to being centered on the line:
    // drive straight.
    OrangutanMotors::setSpeeds(100, 100);
    OrangutanLEDs::left(HIGH);
    OrangutanLEDs::right(HIGH);
  }
  else
  {
    // We are far to the left of the line: turn right.
    OrangutanMotors::setSpeeds(100, 0);
    OrangutanLEDs::left(LOW);
    OrangutanLEDs::right(HIGH);
  }
}

Exercice 5 (Environnement Arduino)[modifier | modifier le wikicode]

Nous posons là une idée à creuser pour un futur exercice. Pour être intéressant, on réalise une navigation à l'estime (dead reckoning en anglais) et donc le robot Pololu doit disposer de codeurs sur ses roues. C'est optionnel et pas donné (42  environ).

Réaliser un quadrillage sur fond blanc. Chaque carré est repéré par une coordonnée entière en x et une coordonnée entière en y. L'objectif est de se déplacer et à chaque fois d'indiquer les coordonnées en x et en y du carré que l’on traverse sur l'afficheur. Interdiction d’utiliser les détecteurs de lignes!

Un PID pour suivre une ligne[modifier | modifier le wikicode]

L'exemple de la section précédente était un suivi de ligne élémentaire. Si l’on veut faire ce travail correctement il faut un régulateur et dans cette section nous choisissons un régulateur PID.

Parcours d'un labyrinthe[modifier | modifier le wikicode]

On appelle labyrinthe un ensemble de lignes droites se coupant à le perpendiculaire. L'objectif est d'aller d'un point de départ vers un point d'arrivée assez caractéristique pour être détecté par le robot. Le robot ne sait absolument pas où est cette arrivée. Il devra donc parcourir le labyrinthe méthodiquement pour la trouver, et ce faisant, parcourra parfois des branches inutiles (ce qui ne présente pas un problème à ce stade mais sera évoqué dans la section suivante).

Programmation : un pas vers le complexe[modifier | modifier le wikicode]

Nous avons déjà eu l’occasion de présenter ce que l’on appelle labyrinthe puisque nous nous sommes intéressé aux parcours dans les labyrinthes. Ce que nous proposons d'examiner ici c’est de résoudre le labyrinthe, c'est-à-dire qu'après un parcours complet, le robot doit être capable d'aller directement du départ vers l'arrivée sans parcourir les branches inutiles.

Résolution d'un labyrinthe[modifier | modifier le wikicode]

Challenges à réaliser avec des groupes d'étudiants[modifier | modifier le wikicode]

Vous trouverez dans la documentation Pololu Building Line Following and Line Maze Courses des idées de challenges pour vos étudiants. Deux types de challenges sont proposés :

  • course sur suivi de ligne
  • course sur labyrinthe

On vous explique en particulier comment construire les circuits correspondants.

Projet étudiant 2013/2014[modifier | modifier le wikicode]

Le but du projet est d’utiliser le robot Pololu pour :

  • réaliser une commande par tablette Android et bluetooth. Ce travail ressemble un peu à ce qui est fait dans les jouets BeeWi sauf que pour ces jouets le code qui s'exécute dans la tablette n’est pas publié !
  • interfacer un accéléromètre MinIMU-9 pour reconstruire la trajectoire réalisée.

Ce projet étant dépendant des connaissances des étudiants du système Android (pas enseigné à l'IUT), la commande par tablette pourra être remplacée par une commande filaire avec la manette Nunchuk si besoin.

Initiation à Pololu[modifier | modifier le wikicode]

Le projet commencera par une prise en main du robot Pololu et consistera à réaliser les exemples donnés. On privilégiera l'environnement Arduino pour travailler, sous Linux ou sous Windows.

Ressources[modifier | modifier le wikicode]

  • Pour l'année scolaire 2012/2013 une tablette Android a été interfacée à un FPGA (voir Les nouvelles interfaces : de la nunchuk de Nintendo à android dans un autre livre). Cette année vous pourrez vous inspirer de ce qui a été fait pour commencer de ce projet.
  • Il existe des ressources en anglais pour interfacer Arduino à la manette Nunchuk (par exemple ICI) si vous remplacez la tablette par la manette.

Avancement du projet[modifier | modifier le wikicode]

Pour des raisons d'effectifs, ce projet a été abandonné pour l'année scolaire 2013/2014. Il sera probablement repris plus tard...