# Micro contrôleurs AVR/AVR et robotique : mini-Q 2WD

Nous allons étudier une nouvelle platine robotique dans ce chapitre. Encore une nouvelle, dirons certains, alors que l'étude des deux autres n’est pas complète !
Et bien oui et nous assumons ce choix.
La platine Asuro a un rapport qualité/prix intéressant. C'est la seule des trois platines qui se programme à distance. Cela devrait être toujours le cas car la programmation d'un robot consiste à faire un programme a le mettre dans le robot et à l'essayer. Pour cette dernière étape il faut déconnecter le fil de programmation, ce que nous n'avons pas à faire avec Asuro. Elle a cependant des inconvénients. Parmi ceux-ci la mécanique avec la demi balle de ping-pong n’est pas exceptionnelle. Les batteries sont de type AAA.
La platine Pololu a été abandonnée en enseignement à cause essentiellement du fait qu’il n'y a aucun moyen de savoir de combien a tourné chaque roue... ou plutôt que pour le faire il faut acheter un ensemble roue plus codeur assez coûteux. Les batteries sont elles aussi de type AAA. Les exemples fournis sont très intéressants et peut-être trop intéressants : on a quasiment tout.
La platine mini-Q possède, quant à elle, des codeurs sur ses roues et utilisent des batteries de type AA. Cela a été suffisant pour la choisir comme base de notre enseignement. Signalons que le petit circuit de programmation vendu avec cette platine nous semble trop fragile pour une utilisation intensive avec des étudiants. D'ailleurs la version 2 commercialisée à partir de 2015, utilise maintenant une platine compatible "Leonardo" avec un connecteur USB micro ce qui nous semble plus adapté à une utilisation répétée.

## Introduction

Schéma du miniQ 2WD vous donne son schéma interne (qui comporte une erreur d'ailleurs).
* La carte Arduino équivalente est la : Arduino nano /w ATMega328
* Le programmateur d'origine est : AVR ISP
* Le port série est en général /dev/ACM0 sous Linux
Nous allons présenter dans ce chapitre la programmation du robot miniQ en langage C pur. Nous rappelons que les platine compatible Arduino sont programmables en C pur à partir de l'environnement Arduino. Il suffit d’utiliser un "main" et l'éditeur de lien se débrouille. Évidemment les primitives Arduino ne sont alors plus disponibles ou alors ont un fonctionnement non prévisible.
Une version plus orientée "langage Arduino" de ce chapitre est en cours de construction aussi. Elle est disponible ICI dans le Wiki de l'IUT de Troyes.

## Boutons poussoirs et Conversion Analogique Numérique (Robot version 1)

L'entrée de conversion analogique numérique numéro 5 est reliée comme le montre la figure ci-dessous.

## Utilisation du timer 0 pour la MLI

Un chapitre entier a été consacré au timer 0 dans ce livre. Vous avez intérêt à le relire avant d'aller plus loin.
Certains se demandent probablement s'il ne serait pas mieux d’utiliser le timer 1 pour la réalisation de la MLI (Modulation de Largeur d'Impulsion). C'est probablement vrai, mais c’est impossible à réaliser sans interruption. Nous allons essayer d'expliquer pourquoi maintenant.

### Commande des deux moteurs

Le timer 0 comme les autres timers permet une commande simultanée de deux moteurs. Puisqu’il s'agit du timer 0, les deux bits associés sont OC0A en PD6 (bit 6 du PORTD) et OC0B en PD5. Si le concepteur du robot a câblé ces deux bits comme commande des moteurs il est naturel d’utiliser le timer 0. C'est le cas comme on peut le voir sur le schéma de principe. Vous voyez bien PD5 connecté à EN1... mais par contre PD6 connecté à IN2. C'est forcément une erreur : PD6 doit être connecté à EN2. L'erreur est naturellement sur le schéma et non sur la carte, heureusement pour nous !
Côté puissance, la commande nécessite deux signaux :
* ENi qui reçoit donc la MLI
* INi qui détermine le sens de rotation
avec i=1 ou i=2 pour chacun des moteurs.
Le code d'initialisation de la PWM (ou MLI) est examiné maintenant.

#### Code pour initialiser la MLI

Rappelons avant de commencer comment est câblé le module de commande des moteurs avec le processeur à l'aide d'une figure ci-contre)
Voici le code fourni avec la platine est le suivant :
Ce que fait la ligne TCCR0B=0X03 est décrit dans le commentaire. On rappelle que la division de l'horloge est choisie par les trois bits de poids faibles de TCCR0B
* (000) arrêt
* (001) division par 1
* (010) division par 8
* (011) division par 64
* (100) division par 256
* (101) division par 1024
* (110) front descendant de T0
* (111) front montant de T0
T0 est un bit qui n’est pas placé au même endroit suivant la famille.
Ce que fait la ligne TCCR0A = 0XA3 est un peu plus complexe et nécessite la lecture de deux tableaux (qui sont rappelés). Voici le premier pour le poids fort de TCCR0A.

##### Mode PWM rapide et comparaison

| COM0A1 | COM0A0 | Description |
| 0 | 0 | Opération Normale PORT, OC0A déconnecté |
| 0 | 1 | WGM02=0 Opération Normale PORT, OC0A déconnecté |
| 0 | 1 | WGM02=1 Basculement de OC0A sur la comparaison |
| 1 | 0 | Mise à 0 de OC0A sur la comparaison et à 1 à BOTTOM |
| 1 | 1 | Mise à 1 de OC0A sur la comparaison et à 0 à BOTTOM |
qui est identique pour COM0B1 et COM0B0. Les deux bits de poids fort du 0xA3 choisissent donc le troisième mode, et idem pour B. On utilise donc pour les deux moteurs la mise à zéro de OC0A (et aussi OC0B) qui sont les deux sorties reliées à EN1 et EN2.
L'autre tableau à lire est :

##### Description des bits pour la génération de forme d'onde

| Mode | WGM02 | WGM01 | WGM00 | Mode de fonctionnement | Bas si | Mise à jour de OCRAx si | Drapeau TOV0 positionné si |
| 0 | 0 | 0 | 0 | Normal | 0XFF | immédiatement | MAX |
| 1 | 0 | 0 | 1 | PWM à phase correct | OXFF | TOP | BOTTOM |
| 2 | 0 | 1 | 0 | CTC | OCR0A | immédiatement | MAX |
| 3 | 0 | 1 | 1 | PWM rapide | 0XFF | BOTTOM | MAX |
| 4 | 1 | 0 | 0 | Reservé | - | - | - |
| 5 | 1 | 0 | 1 | PWM à phase correct | OCR0A | TOP | BOTTOM |
| 6 | 1 | 1 | 0 | Reservé | - | - | - |
| 7 | 1 | 1 | 1 | PWM rapide | OCR0A | BOTTOM | TOP |
Même si WGM02 est dans un autre registre, il n'y a aucune difficulté de remarquer que c’est la ligne 3 (PWM rapide) qui est choisie. Ceci est facilement trouvé avec la figure qui est rappelée :

#### Code pour utiliser les moteurs

Il est possible de trouver des exemples de programmation du robot dans cette page commerciale par exemple. À partir de ces exemples nous présentons un code source légèrement modifié pour être conforme au schéma de principe. Nous avons aussi renommé les paramètres pour savoir qui est moteur gauche et droit et diminué aussi leur taille.
Les deux directions sont définies avec les paramètres MG_DIR et MD_DIR avec G pour Gauche et D pour Droite). Les vitesses des moteurs sont réglées avec MG_EN et MD_EN variant de 0 (arrêt) à 255 (pleine vitesse).

### Travail à faire : Exercice 1

Vous devez réaliser une commande du robot pour qu’il réalise un huit (deux cercles connectés par un point). Vous choisirez le rayon de vos cercles en jouant sur les rapports cycliques. Puis vous jouerez sur les temporisations pour gérer tout cela. Bien entendu, le fait qu’il n'y ait pas d'information de retour sur l'endroit où vous êtes complique un peu la mise au point.
1°) Voici un code complet d'initialisation et d'utilisation des moteurs :
Modifier ce code pour réaliser un simple cercle. Seule la partie main est à modifier !
* Vos essais seront faits sur la table de travail.
* Il y a des risques de chutes ! Soyez donc prudents !
* Ne mettez pas de vitesses excessives !
* N'oubliez pas que votre câble USB n’est pas infini !
2°) Réaliser maintenant votre huit (deux cercles se touchant par un point). On pourra réaliser tout cela dans le noir avec une prise de trajectoire par appareil photo à pose longue.
3°) Étude du rayon du cercle. Nous avons vu en cours que $R(t)={\frac {L}{2}}{\frac {v_{g}(t)+v_{d}(t)}{v_{g}(t)-v_{d}(t)}}$ Essayez d'étudier si le rayon peut s'écrire $R=K{\frac {\alpha _{g}+\alpha _{d}}{\alpha _{g}-\alpha _{d}}}$ où $\alpha _{g}$ et $\alpha _{d}$ désignent le rapport cyclique des moteurs gauche et droit (qui varient entre 0 et 255) et K est une constante à déterminer.

## Utiliser les détecteurs infra-rouge frontaux

Le robot dispose de cinq détecteurs infra-rouge pour le suivi de lignes. Ce n’est pas ces détecteurs que nous allons étudier mais un détecteur et deux émetteurs dirigés respectivement vers la droite et vers la gauche. Cela devrait nous permettre de détecter des obstacles. Le détecteur est relié à INT0/PB0 et peut donc être géré par une interruption.
L'idée générale est d'envoyer un train d'impulsions en émission et de compter ce que l’on reçoit.

### Code d'émission

Vous pouvez utiliser le code suivant :
Si vous regardez attentivement le schéma de principe vous déduisez facilement que l'émission se fait à l'aide d'un zéro.

### Réception par interruption

L'interruption est d’abord initialisée à l'aide du code :
Le code de l'interruption est tout simple :

### setup associé

La terminologie "setup" employée dans le titre de cette section est naturellement issue de l'environnement Arduino. Même si nous programmons en C, l’idée d'imposer une architecture de programme divisée en deux parties (setup et loop) nous semble pertinente. C'est pourquoi nous la reprenons ici.
Les lignes de code associé à la détection infra-rouge à mettre dans la partie setup du programme sont :

### Un code pour éviter les obstacles

Tout ce qui précède peut être utilisé pour détecter et donc éviter les obstacles. L’idée générale est très simple :
* on initialise le compteur "count" à 0
* On émet à droite 24 impulsions plusieurs fois, on compte ensuite ce que l’on reçoit (cela est réalisé automatiquement à l'aide d'une interruption).
* si c’est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.
* on initialise le compteur à 0
* On émet à gauche 24 impulsions plusieurs fois, on compte ce que l’on reçoit.
* si c’est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.
La mise au point de ce code peut prendre beaucoup de temps.
Indications : le code pour émettre plusieurs fois peut être par exemple :
Ce code émet 20 fois 24 impulsions.
Le DISTANCE_IR du "if(count>DISTANCE_IR)" peut être défini par une constante. Divers essais chez moi on montré que la valeur 35 est un bon point de départ. Si vous augmentez cette valeur vous détecterez les obstacles plus près et si vous la diminuez ce sera le contraire. Il est défini comme une constante DISTANCE_IR dans le code de la section suivante et nous vous encourageons très fortement d’utiliser cette technique pour la mise au point.

### Travail à faire : exercice 2

Vous devez mettre au point un code qui permette de ne jamais percuter des obstacles, c'est-à-dire qui évite les obstacles qu’il détecte à droite comme à gauche.
Indication : à ce stade vous n'avez pas de documentation sur l’utilisation complète des PORTs B et D. On vous demande d’utiliser le code :
Ce code doit être naturellement complété par le code donné dans la section Utiliser les détecteurs infra-rouge frontaux ainsi que par l'écriture du sous-programme "Eviter_Obstacle" qui est le cœur même de ce que l’on cherche à faire. Vous pouvez noter qu'une constante SPEED est définie à 60 ce qui évite de faire de la casse. Une constante DISTANCE_IR est définie à 35 et devra être utilisée dans le test après réception.
Tout ce qui précède peut être utilisé pour détecter et donc éviter les obstacles. L’idée générale est très simple :
* on initialise le compteur "count" à 0
* On émet à droite 24 impulsions plusieurs fois, on compte ensuite ce que l’on reçoit (cela est réalisé automatiquement à l'aide d'une interruption).
* si c’est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.
* on initialise le compteur à 0
* On émet à gauche 24 impulsions plusieurs fois, on compte ce que l’on reçoit.
* si c’est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.
La mise au point de ce code peut prendre beaucoup de temps.
Indications : le code pour émettre plusieurs fois peut être par exemple :
Ce code émet 20 fois 24 impulsions.
Le DISTANCE_IR du "if(count>DISTANCE_IR)" peut être défini par une constante. Divers essais chez moi on montré que la valeur 35 est un bon point de départ. Si vous augmentez cette valeur vous détecterez les obstacles plus près eet si vous la diminuez ce sera le contraire. Il est défini comme une constante DISTANCE_IR dans le code de la section suivante et nous vous encourageons très fortement d’utiliser cette technique pour la mise au point.

### Travail à faire : exercice 3

On vous donne un labyrinthe dont vous ne connaissez pas la forme et on vous demande de le parcourir, si possible sans heurter les bords.

## Utilisation de l'infra-rouge pour suivre une ligne

Le robot mini-Q est équipé de cinq couples leds/photo-transistors (infra-rouge) dirigés vers le bas. Ils sont destinés à mesurer la réflexion du support sur lequel roule le robot. Si vous prenez un support blanc et que vous fixez un scotch noir vous arriverez à détecter le support noir qui n'a pas la même réflectance infra-rouge que le support blanc.
La mise au point sera difficile car sur le robot que nous avons essayé les sensibilités des capteurs ne sont pas identiques. La calibrage de chacun des capteurs peut se faire par le programme simple :
qui affichera toutes les secondes les valeurs des 5 photo-transistors infra-rouges. On ne désire pas utiliser ce programme puisque nous avons comme objectif de faire du C pur. Vous allez alors constater que le ce simple programme est bien plus long en C pur, mais nous allons le réaliser en plusieurs étapes.

### Travail à réaliser : Exercice 4

Le travail à réaliser se décompose en plusieurs questions.
Ce travail consiste à utiliser la liaison série pour calibrer vos 5 capteurs. Calibrer veut dire ici, trouver les seuils en-dessous desquels on considère que l’on a du noir. Ces seuils ne sont pas tous identiques pour tous les robots et pour un même robot pour tous les capteurs. Pour les trouver, vous positionnez une fois le capteur sur du blanc, une fois sur du noir et le seuil sera à mi-chemin.
Un moyen de faire cela de manière assez facile à ajuster consiste à définir des constantes comme ci-dessous :
GG veut dire le plus à gauche, DD le plus à droite.
Les seuils se trouvent en mettant le robot en marche pour que son alimentation se fasse avec les accumulateurs et non l'USB !
Les seuils donnés ici sont dépendants du robot dont vous disposez. Il vous faudra bien sûr les adapter à votre robot.

#### Question 1

On désire calibrer les cinq capteurs avec une plaque blanche de test comprenant une piste en chatterton noir. Pour cela on va d’abord régler les problèmes de la liaison série. On vous demande de partir de la librairie ci-dessous (voir le chapitre correspondant) :
On vous demande de réaliser un sous-programme "void serialWrite16(uint16_t can)" capable d'afficher la variable 16 bits "can" en clair et en décimal sur votre liaison série.
Indication : voici un code qui affiche en hexadécimal :
Il suffit donc de le modifier en calculant les milliers, les centaines, les dizaines et les unités et en les transformant en caractères.

#### Question 2

Il va nous falloir maintenant lire les convertisseurs analogique numérique. Le prototype de ce que l’on cherche à faire est :
Indication :

#### Question 3

Une fois les seuils de chaque capteur trouvé, convertir l’ensemble des données en un nombre binaire sur 5 bits. Le bit de poids faible sera à 1 si une ligne noire est présente sous le capteur A0 et ainsi de suite jusqu'au bit b4. Tester de nouveau avec un affichage binaire.
Indication : vous pourrez vous inspirer du code Arduino d'un un travail dévaluation donné à l'IUT de Troyes et en particulier du code suivant :
qui convertit les 5 données analogiques des capteurs infra-rouge en un nombre binaire sur 5 bits. Ce nombre peut ainsi être utilisé dans un "switch". Cherchez les valeurs autorisées de Read_IRLine.

#### Question 4

Vous commencerez ensuite à essayer de réaliser un programme qui suit une ligne fermée en avançant. Le principe est d'accélérer le bon moteur quand on dévie de la ligne.
La valeur 0x00 sera traitée comme valeur aberrante dans un premier temps : on a perdu la piste donc on s'arrête. Maisdans un deuxième temps, vous pouvez aussi faire ce que nous a fait un étudiant : faire marche arrière dans ce cas précis... et c’est pas mal du tout comme idée.

## Capteurs infra-rouge sur les roues pour se repérer

Les roues sont réalisées de telle façon qu'un photo-coupleur infrarouge permette de compter des ticks. Il y en a environ 8 par tours, cela donne une résolution assez faible. Nous ne chercherons donc pas à réaliser des calculs de trajectoires précis.
Le travail de calcul de trajectoire à partir de données internes s’appelle Navigation à l'estime et cela réalise une intégration (d'un point de vie mathématique). Le meilleur moyen de s'en persuader est d'imaginer les conséquences de petites erreurs sur des points de mesure. L'incertitude de la position augmente au fur et à mesure du déplacement.

### Pourquoi le problème de se repérer est difficile

Avant de se poser des questions il faut essayer de bien comprendre ce que veut dire connaître exactement l'état du robot. Celui-ci est donné par trois paramètres même si l’on est en deux dimensions : $(x,y,\theta )$. x et y sont naturellement le repérage de la position sur les deux axes x et y et $\theta$ est l'orientation du robot par rapport à l'axe des x. Regardez la figure ci-contre pour vous convaincre de la pertinence de ces trois données.
Imaginons que vous ayez fait déplacer votre robot pendant un temps T quelconque. Vous relevez les compteurs de chacune des roues et convertissez en centimètres parcourus et trouvez deux nombres A et B. Est-il possible d’en déduire la nouvelle position (et orientation) sachant que l’on connaît exactement la position de départ ? Autre manière de poser le problème : je connais parfaitement $(x_{d},y_{d},\theta _{d})$ ainsi que la distance parcourue par chacune des roues est-il possible d’en déduire $(x_{f},y_{f},\theta _{f})$ ? Malheureusement la réponse à cette question est partiellement négative ! Il n'est possible que d’avoir $\theta _{f}$ mais pas le reste.
Tout cela est résumé simplement par la figure ci-contre. Dans cette figure, les deux longueurs (en pointillés) rouges sont identiques (et égales à A) et les deux longueurs (en pointillés) bleues sont elles aussi identiques (et égales à B) et pourtant on obtient deux points d'arrivées différents. Seule l'orientation finale est identique. Cela montre qu'aucune formule ne permet le calcul de xf à partir de xd, A et B.
Doit-on abandonner l’idée de trouver le point final à partir du point de départ ? Non, heureusement. En fait le problème présenté devient possible si les deux distances parcourues A et B deviennent différentielles (c'est-à-dire toutes petites). C'est quand même une mauvaise nouvelle malgré tout. Cela veut dire qu’il nous faut mémoriser les distances parcourues par chacune des roues à des instants précis et assez fréquemment pour se rapprocher de l’idée mathématique de différentielle. Nous essaierons dans un premier temps dix mesures par seconde. Nous utiliserons des compteurs sur 8 bits en complément à deux... et dix fois par seconde nous mémoriserons donc les valeurs des deux compteurs (droit et gauche) dans une mémoire.

### Code de départ

Voici le code permettant d’utiliser les capteurs. Il commence par une initialisation :
Puis vient lesinterruptions proprement dites qui incrémentent chacune son compteur.

### Travail à faire : exercice 5

On vous demande d'exécuter votre code de suivi de ligne sur une forme inconnue d'avance et d’utiliser les photo-transistors infra-rouge des roues pour reconstruire la trajectoire suivie.
* l'évaluation du programme sera fait sans référence particulière : vous ne savez pas quand vous revenez au point de départ (aucune marque sur le circuit)
* l'évaluation du programme est fait avec une référence particulière. Une barre perpendiculaire à la trajectoire (donc détectable avec les photo-transistors) est présente au point de départ et au point d'arrivée. Cette contrainte forte devrait permettre de diminuer les erreurs sur la trajectoire.

## Travail à faire : exercice final

Votre robot sera enfermée dans une pièce/labyrinthe (maquette de taille en rapport avec le robot) ayant une forme non connue à l'avance. Il devra se déplacer en évitant les murs et essayer en même temps de déduire la forme de la pièce.

## MiniQ version 2

Voici un site commercial qui propose de la documentation et une présentation de la version 2 (compatible Arduino Leonardo) du Robot mobile miniQ. Contrairement à la version 1, tous les codes proposés comme exemples sont fournis en langage Arduino. Ce qui est présenté ici est, par contre, en code C standard.
On rappelle que l’utilisation du code C nécessite une entête. Elle sera de la forme :

### Boutons poussoirs et Conversion Analogique Numérique (Robot version 2)

Une nouvelle version du robot MiniQ est disponible depuis 2015. La grande différence est qu’il est architecturé autour du 32U4 au lieu de l'ATMega328. Cela peut paraître anecdotique, mais les périphériques du 32U4 sont relativement différents de ceux du 328 en ce qui concerne la conversion analogique numérique et la MLI.
Le robot MiniQ (version 2) possède trois interrupteurs montés comme dans la figure ci-contre. Le point important est le numéro du convertisseur (AN8). Notez aussi le nombre d'interrupteurs : 3 (qui sont appelés de KEY1 à KEY3. KEY1 est du côté gauche (avec la convention usuelle du regard dirigé vers l'avant).

#### Trouver l'interrupteur appuyé

Exercice 1 :
1°) Montrer que vous savez faire un programme Arduino qui utilise A6 (Conversion Analogique Numérique) et affiche dans un moniteur série les différentes valeurs suivant le/les boutons appuyés. Remplir alors le tableau ci-dessous.
| Key3 | Key2 | Key1 | ADC8 (V et N) |
| 0 | 0 | 0 | ? |
| 0 | 0 | 1 | ? |
| 0 | 1 | 0 | ? |
| 0 | 1 | 1 | ? |
| 1 | 0 | 0 | ? |
| 1 | 0 | 1 | ? |
| 1 | 1 | 0 | ? |
| 1 | 1 | 1 | ? |
Faire un programme qui affiche correctement (en clair) la touche appuyée. Pour cela on cherchera les points milieux des valeurs trouvées dans le tableau.
Les valeurs trouvées expérimentalement sont :
* KEY1 (sw3) appuyé : CAN8 = 135
* KEY2 (sw4) appuyé : CAN8 = 575
* KEY3 (sw5) appuyé : CAN8 = 722
2°) Écrire un sous-programme en C pur d'initialisation de la conversion analogique numérique.

#### Conversion en binaire

Continuer l'exercice précédent en réalisant un sous-programme qui retournera un nombre binaire représentant l'interrupteur appuyé.
| b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| 0 | 0 | 0 | 0 | 0 | key3 | key2 | key1 |
Ce tableau indique que quand key1 est appuyé on a un 1 dans b0 tandis que si c’est key3 le 1 correspondant est dans b2....
Le prototype de la fonction demandée sera :

#### Touches incrémentation/décrémentation

Réaliser un sous-programme capable d'incrémenter/décrémenter une variable (de type unsigned char donc variant de 0 à 255) en fonction de l'appui sur les boutons.

### Utilisation du timer 4 pour commander les moteurs

Les moteurs du miniQ version 2 sont commandés par le timer4. Il s'agit d'un timer assez complexe, qui peut fonctionner sur 10 bits et permet la commande de transistors de puissance FET (commandes inversées avec temps morts). Heureusement, nous nous contenterons du fonctionnement simple sur 8 bits.

#### Un exemple pour le moteur gauche

Le moteur gauche est commandé par la broche PC6(=/OC4A) du PORTC.
La sélection marche avant marche arrière n’est pas réalisée. Passons maintenant à l'autre moteur.

#### Un exemple pour le moteur droit

Le moteur droit est connecté à la sortie PD7/OC4D du PORTD. Voici le code permettant de gérer correctement le moteur droit.

#### Travail à faire

Exercice 2 : Reprendre les exemples de code et refaire une initialisation commune pour les deux moteurs. On prendra alors soin de remplacer l'hexadécimal par le nom des bits.
Remarquez que l’on n'a pas géré les directions de rotations des deux moteurs.
Exercice 3 : On désire reprendre le travail de lecture des interrupteurs en C (voir plus haut). Écrire un programme C capable de lire ADC8 (ATTENTION c’est A6 pour l'Arduino). L'appui sur le bouton gauche KEY1 fera tourner le moteur gauche, tandis que l'appui sur le bouton droit fera tourner le moteur droit.
Remarquez que l’on n'a pas géré les directions de rotations des deux moteurs.
Exercice 4 : refaire un sous-programme qui gère les deux moteurs à la fois et le sens. On a déjà utilisé ce genre de sous-programme, il avait le prototype :
Indication : les commandes de sens pour respectivement le moteur droit et le moteur gauche sont les broches PE6 et PD6.

### Suivi de lumière en C

Dans cette section nous désirons réaliser un programme permettant au robot de suivre une source de lumière.

#### Programme de départ (version Arduino)
##### Exercice 5

Éliminer toute la partie non nécessaire pour calibrer les capteurs de lumière en utilisant la liaison série.

##### Exercice 6

Reprendre le code donné et utiliser toute la partie d'utilisation des moteurs en C déjà réalisé auparavant.

##### Exercice 7

Réaliser l'initialisation convertisseur analogique numérique CAN0. On est prêt maintenant à retirer le setup et le loop pour ne faire qu'un main.

### Suivi de ligne en C

Le premier problème à résoudre est de calibrer les cinq seuils des cinq capteurs infrarouges. L'expérience nous a montré qu'ils peuvent avoir des réponses assez différentes et donc que cette étape est nécessaire.

#### Comment calibrer correctement les capteurs pour trouver les seuils

Ceci peut être réalisé par un simple programme Arduino qui nous permet de garder la liaison série :
mais nécessite de graver la séquence d'initialisation (bootloader) si vous utilisez un programmateur. Cela prend environ 1mn.
Un essai avec un Robot m'a donné les résultats suivants.
| Position du capteur | extrême gauche | gauche | centre | droite | extrême droite |
| broche µc | 36 | 37 | 38 | 39 | 40 |
| entrée CAN | ADC7 | ADC6 | ADC5 | ADC4 | ADC1 |
| entrée Arduino | A0 | A1 | A2 | A3 | A4 |
| BLANC | 836 | 982 | 980 | 974 | 970 |
| NOIR | 210 | 390 | 338 | 305 | 305 |
| Seuils | 523 | 686 | 659 | 639 | 637 |

#### Abandon de la gestion des convertisseurs Analogique sous Arduino

Nous voulons maintenant faire la même chose que le programme précédent mais avec une gestion des Convertisseurs Analogiques Numériques en C.

#### Gestion du suivi de ligne en C

Nous disposons d'à peu près de tout le code nécessaire à résoudre le problème avec tout ce que l'on vient de faire. Mais il nous faut de la remise en forme.

##### Exercice 8

Le premier sous-programme que nous allons réaliser est un sous programme qui s'appelle "sense5IR". Son objectif est de retourner une valeur pondérée. L'idée est d'allouer un poids aux 5 capteurs infrarouges :
| Position du capteur | extrême gauche | gauche | centre | droite | extrême droite |
| entrée CAN | ADC7 | ADC6 | ADC5 | ADC4 | ADC1 |
| Poids | +24 | +12 | 0 | -12 | -24 |
Si chaque fois que vous avez un capteur qui détecte du noir vous ajoutez son poids et que vous divisez par le nombre de capteurs qui détectent du noir, vous aurez une valeur discrète entre +24 et -24. C'est cette valeur discrète que devra nous retourner "sense5IR".
Écrire la fonction "int16_t sense5IR" en lui ajoutant "void initCANs".

##### Exercice 9

La boucle d'exécution du programme d'un robot est en générale caractérisée par le paradigme sense plan act :
* lire des capteurs (sense en anglais)
* planifier (plan en anglais)
* agir (act en anglais)
Écrire la partie planification et le programme principal associé.
Indication : La planification consiste à calculer les vitesses des moteurs droit et gauche à partir du résultat de la fonction "sense5IR". L'idée générale est d'augmenter et diminuer les vitesses des moteurs pour rattraper la ligne suivie. Une relation de proportionnalité peut être choisie, mais il est possible de réaliser ici un régulateur PID.
Nous présentons une version préliminaire avec PID, enfin plutôt PD. La partie intégrale d'un PID doit saturer si l'on ne veut pas que ce terme devienne prépondérant.
Contrairement au code précédent, nous avons réussi à le faire fonctionner avec une vitesse de 80.
Tout ceci doit être amélioré.
À ce stade vous disposez de tout le nécessaire pour réaliser un suivi de ligne.

### Détection d'obstacle en C
#### Principe

Sont présents sur le robot, un détecteur infrarouge et deux émetteurs dirigés respectivement vers la droite et vers la gauche. Ils permettent de savoir si le nombre d'impulsions reçu (par écho) peut laisser penser à la présence d'un obstacle. Le détecteur est relié à INT0/PB0 et peut donc être géré par une interruption qui ne fera que compter le nombre d'impulsions reçu. À noter que cette interruption est incapable, par elle-même de savoir qui a émis, la droite ou la gauche.
L'idée générale est donc d'envoyer un train d'impulsions en émission et de compter ce que l'on reçoit.

#### Récepteur

Nous ne nous attarderons pas sur la partie récepteur. Il suffit de configurer l'interruption associée à la broche PB0 et d'incrémenter une variable :
Ajouter ce code à votre programme.

#### Émetteur

Le robot dispose de 2 émetteurs dont le tableau suivant donne les informations importantes :
| Position | Broche | Timer |
| Droite | PB4 | ---- |
| Gauche | PC7 | OC4A |
Si vous suivez, il va falloir de nouveau configurer un timer ! Le tableau ci-dessus pourrait laisser penser qu'il faut prendre le timer 4, mais on rappelle que l'on utilise déjà ce timer pour la MLI des moteurs. On décide de prendre le TIMER0.
On rappelle que l'on aura besoin de code à travers une interruption pour basculer PB4 et PC7 puisqu'ils ne sont reliés à aucun OC0X.

#### Émetteurs et Timer0

Nous allons utiliser le mode comparaison du timer0 afin d'obtenir une fréquence très précise d'émission de 38 kHz.

##### Exercice 10

* Choisir des valeurs de prédiviseur et de comparaison permettant d'obtenir une fréquence de comparaison de 76 kHz.
* Ajouter la configuration du timer a votre programme avec un sous-programme :
* Ajouter l'interruption de comparaison associée a votre programme. N'oubliez pas que cette interruption doit émettre soit du côté droit soit du côté gauche. Il faudra donc lui associer une variable globale "volatile uint8_t left;" qui conditionnera si l'émission se fait à droite ou à gauche. Par exemple :
À ce point, il faut bien comprendre ce que l'on est capable de faire :
* un sei dans le programme principal déclenchera automatiquement une émission à droite ou à gauche (suivant la valeur de la variable "left").
* par conséquent l'interruption "ISR(PCINT0_vect)" comptera toujours les éventuels échos.
* si vous voulez arrêter d'émettre il vous faudra soit réaliser un cli (déconseillé) soit désactiver l'interruption ISR(TIMER0_COMPA_vect) avec le bit OCIE0A du registre TIMSK0.

#### Émission droite/gauche

Pour commencer on utilisera les primitives "_delay_us" pour attendre quelques microsecondes.
* left <- 0
* count <- 0
* Répéter 20 fois :
** Émettre pendant 300us sur l'émetteur droit en autorisant l'interruption de comparaison
** Arrêter d'émettre
** On coupe l'émission pendant 600 us
* Lire valeur du compteur de réception. S'il est plus grand que 20 on prend les mesures appropriées (recul puis rotation appropriée puis marche avant)
On doit faire la même chose avec l'émission à gauche.
* left <- 1
* count <- 0
* Répéter 20 fois :
** Émettre pendant 300us sur l'émetteur gauche en autorisant l'interruption de comparaison
** Arrêter d'émettre
** On coupe l'émission pendant 600 us
* Lire valeur du compteur de réception. S'il est plus grand que 20 on prend les mesures appropriées (recul puis rotation appropriée puis marche avant)
À vous de jouer, vous disposer maintenant d'un détecteur d'obstacles. Vous devez l'associer aux solutions de l'exercice 4 qui sont gestion complète des commandes des moteurs.

##### Exercice 11

* Écrire un programme qui répond au cahier des charges suivant :
* le robot avance en ligne droite
* s'il y a un obstacle à droite (count >20 par ex) alors
** reculer
** tourner sur place vers la gauche
** on repart en marche avant
* s'il y a un obstacle à gauche (count >20 par ex) alors
** reculer
** tourner sur place vers la droite
** on repart en marche avant
Code à compléter avec les exercices précédents :