Position et détection d'obstacle : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
(Programme test de fonctionnement)
(programme finale : Obtention des coordonnées x , y , l'angle)
 
(26 révisions intermédiaires par 2 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
 
[[Catégorie:RobotGEII]]
 
[[Catégorie:RobotGEII]]
  
=Présentation=
+
='''Présentation'''=
 +
 
 
[[Fichier:edr.jpg|thumb|upright=1.0||Exemple de Robot]]
 
[[Fichier:edr.jpg|thumb|upright=1.0||Exemple de Robot]]
Notre projet à pour but de concevoir un robot pour participer à [http://www.gesi.asso.fr/coupe_robotique_des_iut/ La coupe de France des IUT GEII à Cachan]
 
  
Dans cette partie nous allons nous concentrer sur la position du robot sa navigation et sa faculté a éviter les obstacles décrit dans le [http://www.gesi.asso.fr/coupe_robotique_des_iut/images/2014/reglement_Vierzon_2014_V002.pdf règlement].
+
Notre projet à pour but de concevoir un robot pour participer à [http://www.gesi.asso.fr/coupe_robotique_des_iut/ La coupe de France des IUT GEII à Cachan]Dans cette partie nous allons nous concentrer sur la position du robot sa navigation et sa faculté a éviter les obstacles décrit dans le [http://www.gesi.asso.fr/coupe_robotique_des_iut/images/2014/reglement_Vierzon_2014_V002.pdf règlement].
  
 
=Navigation=
 
=Navigation=
Ligne 11 : Ligne 11 :
 
==Codeur rotatif==
 
==Codeur rotatif==
  
Afin de connaitre la position des roues, de savoir de combien elles ont tournés nous utiliserons un codeur rotatif.
+
Afin de connaitre la position des roues, de savoir de combien elles ont tournés nous utiliserons un codeur rotatif.Les codeurs rotatifs sont un type de capteurs permettant de délivrer une information d'angle, en mesurant la rotation effectuée autour d'un axe.L'information de vitesse peut alors être déduite de la variation de la position par rapport au temps. Plus le codeur rotatif tourne lentement, plus la déduction de vitesse perd en précision.
Les codeurs rotatifs sont un type de capteurs permettant de délivrer une information d'angle, en mesurant la rotation effectuée autour d'un axe.
+
 
L'information de vitesse peut alors être déduite de la variation de la position par rapport au temps. Plus le codeur rotatif tourne lentement, plus la déduction de vitesse perd en précision.
+
Il en existe 2 principaux types :
  
Il existe 2 principaux types :
 
 
 
* Le codeur rotatif incrémental qui ajoute ou soustrait (selon le sens de rotation) une unité à un compteur à chaque rotation supérieure à la résolution du capteur. Le compteur est généralement remis à zéro lorsque l'appareil est allumé. C'est le cas de la souris d'ordinateur à boule.
 
* Le codeur rotatif incrémental qui ajoute ou soustrait (selon le sens de rotation) une unité à un compteur à chaque rotation supérieure à la résolution du capteur. Le compteur est généralement remis à zéro lorsque l'appareil est allumé. C'est le cas de la souris d'ordinateur à boule.
  
 
* Le codeur rotatif absolu qui intègre son propre compteur. Ce genre de capteur est généralement calibré et initialisé une seule fois, et il conserve normalement sa valeur lors de l'arrêt de l'appareil. C'est le cas des compteurs kilométriques des automobiles à la différence du "compteur journalier" qui peut être remis a zéro par l'utilisateur.
 
* Le codeur rotatif absolu qui intègre son propre compteur. Ce genre de capteur est généralement calibré et initialisé une seule fois, et il conserve normalement sa valeur lors de l'arrêt de l'appareil. C'est le cas des compteurs kilométriques des automobiles à la différence du "compteur journalier" qui peut être remis a zéro par l'utilisateur.
  
 +
Nous utiliseront des codeurs incrémentaux fixé sur les axes des deux moteur ce qui nous permettra d'asservir la rotation des robot c'est à dire que nous pourrons avoir un retour sur les commande du moteur de plus on connaîtra l'angle pris par le robot par rapport a sa position de départ. En effet ce genre des capteur est plus précis par rapport à l'autre.
  
 +
[[Fichier:cdif.jpg|center|upright=5.0||Fonctionnement d'un codeur]]
  
Nous utiliseront des codeurs incrémentaux fixé sur les axes des deux moteur ce qui nous permettra d'asservir la rotation des robot c'est à dire que nous pourrons avoir un retour sur les commande du moteur de plus on connaîtra l'angle pris par le robot par rapport a sa position de départ. En effet ce genre des capteur  a plus de précision par rapport à l'autre car en réinitialisant il va supprimé les erreurs accumulé .
+
==équation de positionnement ==
  
[[Fichier:cdif.jpg|center|upright=5.0||Fonctionnement d'un codeur]]
 
  
 +
Le positionnement du robot en intégration les information reçu des codeur incrémentaux qui constituera des petits déplacements avec les quelle on pourra nous positionner.
  
==équation de positionnement ==
 
Le positionnement du robot en intégration les information reçu des codeur incrémentaux qui constituera  des petits déplacements  avec les quelle on pourra nous positionner.
 
  
Il y a en fait deux manières d'approximer la trajectoire parcourue par le robot pendant un temps :
+
Il y a deux manières d'approximer la trajectoire parcourue par le robot sur un laps de temps :
  
  
* En utilisant des segments de droites. On considère alors que le robot va en ligne droite pendant le temps . Ceci revient à supposer que les '''deux roues ont une vitesse constante''' et identique sur cet élément de trajectoire. A la fin de cet élément de trajectoire, on corrige l'orientation du robot en fonction de la différence de distance parcourue par les deux roues
+
* '''En utilisant des segments de droites'''. On considère alors que le robot va en ligne droite sur toute la période. Ceci revient à supposer que les '''deux roues ont une vitesse constante''' et identique sur cet élément de trajectoire. A la fin de cet élément de trajectoire, on corrige l'orientation du robot en fonction de la différence de distance parcourue par les deux roues.
  
  
 +
* '''En utilisant des arcs de cercles''' . On considère alors que le robot se déplace et change d'orientation en suivant un arc de cercle pendant le temps . Ceci revient à considérer que chacune des roues a une vitesse constante sur la période mais que les''' vitesses des 2 roues ne sont pas identiques.'''
  
* En utilisant des arcs de cercles(permet de tourner) . On considère alors que le robot se déplace et change d'orientation en suivant un arc de cercle pendant le temps . Ceci revient à considérer que chacune des roues a une vitesse constante sur la période  mais que les''' vitesses des 2 roues ne sont pas identiques.'''
 
  
 
[[Fichier:Pos2.PNG|center|upright=2.0||positionnement par segement]]
 
[[Fichier:Pos2.PNG|center|upright=2.0||positionnement par segement]]
  
  
et on peux cacluler les positionement en calculant la distance parcouru et le temps fonctionnement des 2 roues :
+
On peux alors cacluler les positionement en calculant la distance parcouru et le temps de trajet des 2 roues :
  
  
Ligne 49 : Ligne 47 :
  
  
et donc on peut accéder à position (coordonnées x,y)
+
On peut alors accéder à la position du robot (coordonnées x,y)
  
  
 
[[Fichier:Equaposseg2.PNG|center|upright=3.0||positionnement par segement]]
 
[[Fichier:Equaposseg2.PNG|center|upright=3.0||positionnement par segement]]
 +
  
 
== Réalisation de la roue codeuse ==
 
== Réalisation de la roue codeuse ==
 +
  
 
Nous avons pris les mesures du moteur et du châssis imposé pour la compétition afin de fabriquer notre roue codeuse puis nous l'avons représenter sur le logiciel de création de Charly robot. Nous avons choisit des fentes ouvertes sur l’extérieur, c'est a dire pas de contour la taille de la fente est limité par les outils que nous avons une fraise de 2 mm donc la taille de nos fente est de 2 mm une taille minimal permet une précision maximal lors de la rotation. La première roue que l'on a usiner était trop fine et donc pas assez rigide :  
 
Nous avons pris les mesures du moteur et du châssis imposé pour la compétition afin de fabriquer notre roue codeuse puis nous l'avons représenter sur le logiciel de création de Charly robot. Nous avons choisit des fentes ouvertes sur l’extérieur, c'est a dire pas de contour la taille de la fente est limité par les outils que nous avons une fraise de 2 mm donc la taille de nos fente est de 2 mm une taille minimal permet une précision maximal lors de la rotation. La première roue que l'on a usiner était trop fine et donc pas assez rigide :  
 +
 +
 
[[Fichier:20141107_084323.jpg|vignette|upright=5.0|sans cadre|centre|première roue usiné]]
 
[[Fichier:20141107_084323.jpg|vignette|upright=5.0|sans cadre|centre|première roue usiné]]
  
 +
 +
Nous avons donc choisit de tester une roue à deux épaisseurs : l'une plus fine (1 mm) pour la partie extérieur et l'autre plus épaisse pour la partie intérieure de la roue (2 mm). :
  
  
nous avons donc choisit de mettre deux épaisseurs l'une plus fine (1 mm) pour la partie extérieur et l'autre plus épaisse pour la partie intérieure de la roue (2 mm). :
 
 
[[Fichier:20141107 084318.jpg|vignette|upright=5.0|sans cadre|centre|deuxième roue usiné]]
 
[[Fichier:20141107 084318.jpg|vignette|upright=5.0|sans cadre|centre|deuxième roue usiné]]
  
Cette solution etant aussi fragile que la precedente nous avons finalment opter pour une roue à une seul epaisseur de 2mm pour avoir une bonne rigidité et peu de vibration.
+
 
 +
Cette solution étant aussi fragile que la précédente nous avons finalement opter pour une roue à une seul épaisseur de 2mm pour avoir une bonne rigidité et peu de vibration.
 +
 
  
 
== Réalisation du montage électronique ==
 
== Réalisation du montage électronique ==
  
le montage Electronique a pour but d'avoir les signaux de l'optocoupleur [http://www.vishay.com/docs/84756/tcut1300.pdf TCUT 1300 ]pour nous permettre de compter les numéros d’encoche parcouru et savoir le sens de rotation grace aux 2 phototransistor  . On a d'abord utilisé le montage d'un groupe qui a travaillé sur le projet avant nous , toutefois leur montage n'a pas fonctionner . On a fini par modifié leur montage pour pouvoir le programme et on a abouti au monter suivant :
+
 
 +
le montage Electronique a pour but de récupérer et traiter les signaux obtenus par les optocoupleurs [http://www.vishay.com/docs/84756/tcut1300.pdf TCUT 1300 ] pour nous permettre de compter le nombres d’encoche parcouru et connaitre le sens de rotation grâce aux 2 photo-transistor. Nous avons tout d'abord utilisé le montage d'un groupe qui a travaillé sur le projet avant nous, toutefois leur montage n'a pas fonctionner. On a fini par modifié leurs montage afin de corriger les erreurs ce qui a donné le montage suivant :
 +
 
  
 
[[Fichier:Montage.JPG|center|upright=3.0||montage détecteurs d'encoches]]
 
[[Fichier:Montage.JPG|center|upright=3.0||montage détecteurs d'encoches]]
  
  
* Si il y de la lumiere emit par la photodiode et recu par le photo-transistor on a un état logique "1" => trou
+
* Si il y de la lumière émise par la photodiode et reçu par le photo-transistor on a un état logique "1" => ce qui correspond a une encoche.
 +
 
 +
 
 +
* Si il y a un obstacle entre la photodiode et le photo-transistor on a un état logique "0" => pas d'encoche.On obtiendra donc un signal de cette allure :
 +
 
  
* Si il y a quelque chose assez absorbant de rayonnement IR entre la photodiode  et le photo-transistor on a un état logique "0" => pas trou.
 
et donc on devra avoir une signal de cette allure :
 
 
[[Fichier:Capture.JPG|center|upright=3.0||signal détecteur d'encoche]]
 
[[Fichier:Capture.JPG|center|upright=3.0||signal détecteur d'encoche]]
 +
  
 
== Phase de test ==
 
== Phase de test ==
  
'''On a eu une problème c'est quand la roue codeuse tourne rapidement on arrive plus à détecter la trou donc l’état 0 :'''
 
  
Pour la résoudre on a utilisé à la place d'un RE résistance fixe une résistance variable qu'on a tester les différence valeur à fin d'avoir un rapport cyclique le proche possible de 50% quand on est au vitesse maximal . En effet cette problème est du à la présence d'un capacité au montage donc si on tourne rapidement le rue codeuse la circuit ne peux plus détecter le 0 à cause la constante de temps R*C trop petit donc il faut augmenté R à fin que le temps de réponse sera plus rapide .En effet si RE est petit la tension n'aura pas de temps de descendre puis remonter donc elle reste à l’état haut .
+
'''Le problème rencontré est que lorsque la roue codeuse tournait rapidement on ne détecté plus l'encoche : '''état 0''' Pour résoudre ce problème on a utilisé à la place d'une résistance fixe une résistance variable qu'on a tester avec différentes valeur à fin d'avoir un rapport cyclique le proche possible de 50% en vitesse maximal. En effet ce problème est du à la présence d'une capacité au montage donc si la roue codeuse tourne rapidement le circuit ne peux plus détecter le "0" ce qui s'explique par la constante de temps R*C trop petite, donc il faut augmenté R à fin que le temps de réponse soit plus rapide. En effet si la résistance est trop faible la tension n'aura pas le temps de descendre puis remonter donc elle reste à l’état haut .
 +
 
  
 
REMARQUE :
 
REMARQUE :
*  On place un condensateur en parallèle de chaque phototransistors pour filtrer les éventuelles pics qui pourraient venir perturber le fonctionnement des capteurs.
 
  
*On a inserer un '''condensateur de découplage''' à fin de filterer les pic provenant d'alimentation
+
 
 +
* On place un condensateur en parallèle de chaque photo-transistors pour filtrer les pics qui pourraient venir perturber le fonctionnement des capteurs.
 +
 
 +
 
 +
* On a aussi insérer un '''condensateur de découplage''' à fin de filtrer les pic provenant de l'alimentation.
 +
 
  
 
== Réalisation de la carte ==
 
== Réalisation de la carte ==
  
Suite à la phase de test nous avons commencé la conception de la carte
+
 
 +
Suite à la phase de test nous avons commencé la conception de la carte  
 +
 
  
 
Le schéma:
 
Le schéma:
 +
  
 
[[Fichier:Shémarb.PNG|center|upright=5|vignette|Schéma de la carte roue codeuse]]
 
[[Fichier:Shémarb.PNG|center|upright=5|vignette|Schéma de la carte roue codeuse]]
 +
  
 
Le board :
 
Le board :
 +
  
 
[[Fichier:Boardrb.PNG|center|upright=5|vignette|Board de la carte roue codeuse]]
 
[[Fichier:Boardrb.PNG|center|upright=5|vignette|Board de la carte roue codeuse]]
  
  
Tout sera relié à un microcontrôleur en occurrence c'est [http://www.atmel.com/Images/Atmel-8127-AVR-8-bit-Microcontroller-ATtiny4-ATtiny5-ATtiny9-ATtiny44_Datasheet.pdf/ ATtiny44] (mais on a fait les testes en utilisant un arduino Uno)  car c'est la moins chere et presente 5 pin qui nous suffit largement  (voir annexe pour la documentation )
+
====''' Changement du Semestre 4 '''====
  
== Compter le numéro d’encoche et détermination de sens ==
 
  
Il faut faire un programme qui, à partir des signaux obtenu dans la partie montage électronique compte le numéro d’encoches tout en tenant compte de sens de rotation !<br />
+
Durant le quatrième semestre nous avons procédé a la correction du schéma et du board, en effet pendant la phase de test de la carte ci-dessus nous nous sommes aperçu que certain composant été mal positionné nous avons donc procédé a des modification.
Il faut tout d'abord initialisé un sens comme le sens direct qui , à chaque encoche parcouru incrémentera le compteur d'un et diminuer à chaque encoche parcouru dans le sens inverse .<br />
 
Pour détecter dans quelle sens la rue tourne, on compare le retard juste après la changement (on peut comparé juste après la phase montante ou que après la phase descendante mais pour un meilleur précision on compare pour les 2 phases) d'état de la signal A par rapport à la signal B de l’optocoupleur , en effet il y a 4 cas de figures possibles :<br />
 
  
[[Fichier:Signaux_de_l'optocoupleur.PNG|thumb|upright=1.0||Exploitation des 2 signaux d'un optocoupleur]]
 
  
# La signal A =1 et B=1 ==> sens directe ==> on incrémente <br />
+
ci-dessous le schéma et le board définitif:
  
# La signal A =1 et B=0 ==> sens indirecte ==> on diminue <br />
 
  
# La signal A =0 et B=1 ==> sens indirecte ==> on diminue <br />
+
Le schéma :
  
# La signal A =0 et B=0 ==> sens directe ==> on incrémente <br />
 
  
Maintenant il faut écrire le programme :
+
[[Fichier:Schéma1.PNG|center|upright=5|vignette|Schéma corrigé de la carte roue codeuse]]
* En premier temps on a fais le programme en utilisant les fonctions que la bibliothèque d'arduino nous offre pour tester et bien comprendre.<br />
+
 
      Voici donc le programme:  
+
 
{{boîte déroulante/début|titre=Programme comptant les encoches }} <source lang="java">
+
Le board :
  
volatile  int s=0;
 
void setup()
 
{
 
  Serial.begin(9600);
 
  attachInterrupt(0, counnt, CHANGE);
 
}
 
void loop()
 
{
 
  Serial.println(s);
 
}
 
void count()
 
{
 
  if (digitalRead(2)==HIGH)
 
  {
 
      if (digitalRead(3)==HIGH)      s++ ;
 
    else      s-- ;
 
  }
 
  else
 
  {
 
    if (digitalRead(3)==HIGH) s-- ;
 
    else s++ ;
 
  }
 
}
 
</source> {{boîte déroulante/fin}}
 
  
 +
[[Fichier:Board1.PNG|center|upright=5|vignette|Board corrigé de la carte roue codeuse]]
  
* Puis pour essayer d'amiliorer on a programmer les differant registres directement à fin d'amiliorer la vitesse d'excustion tache faite dans la microcontrôleur , en effet il y a une augementation d'un facteur  de 30  en programmant les registre .<br />
 
  
      Voici donc le programme:
+
Tout sera relié à un microcontrôleur en l'occurrence c'est un[http://www.atmel.com/Images/Atmel-8127-AVR-8-bit-Microcontroller-ATtiny4-ATtiny5-ATtiny9-ATtiny44_Datasheet.pdf/ ATtiny44] (mais on a réaliser les testes en utilisant une carte arduino Uno) car ce microcontrôleur présente l'avantage d’être peu onéreux et le nombre de pin qui nous suffit largement (voir annexe pour la documentation )
  
{{boîte déroulante/début|titre=Programmation des registres pour  compter les encoches }} <source lang="java">
 
  
 
  
#include <avr/io.h>
 
  
volatile  int s=0;
+
== Comptage du nombres d’encoche et détermination du sens de rotation ==
  
ISR(INT0_vect)    // programmed'interruption : le programme principal est interrompu,
 
  
{                // l'interruptionexécutée et ensuite le programme principal continu normalement sonexécution
+
Il faut faire un programme qui, à partir des signaux obtenu dans la partie montage électronique compte le nombre d’encoches tout en tenant compte du sens de rotation !<br />Il faut tout d'abord initialisé un sens comme le sens direct qui à chaque encoche parcouru incrémentera le compteur et diminuera à chaque encoche parcouru dans le sens inverse .<br />Pour détecter dans quelle sens la roue tourne, on compare le retard juste après la changement (on peut comparé juste après la phase montante ou après la phase descendante mais pour une meilleur précision on compare pour les 2 phases) d'état du signal A par rapport aux signal B de l’optocoupleur, en effet il y a 4 cas de figures possibles :<br />
  
  if (PORTD&(1<<PIND2)==HIGH)
 
  
  { 
 
  
    if (PORTD&(1<<PIND3)==HIGH)
 
  
      s++ ;
+
[[Fichier:Signaux_de_l'optocoupleur.PNG|thumb|upright=1.0||Exploitations des 2 signaux d'un optocoupleur]]
  
    else
 
  
      s-- ;
+
# Le signal A = 1 et B = 1 ==> sens direct ==> on incrémente <br />
 +
# Le signal A = 1 et B = 0 ==> sens indirect ==> on diminue <br />
 +
# Le signal A = 0 et B = 1 ==> sens indirect ==> on diminue <br />
 +
# Le signal A = 0 et B = 0 ==> sens direct ==> on incrémente <br />
  
  }
 
  
  else
+
Maintenant il faut écrire le programme :
  
  {   
 
  
    if (PORTD&(1<<PIND3)==HIGH)s-- ;
+
* Dans un premier temps on a réaliser un programme en utilisant les fonctions que la bibliothèque d'Arduino nous offre pour tester et bien comprendre.<br />
  
    else s++ ;
 
  
  }  
+
Voici donc le premier programme:
 +
{{boîte déroulante/début|titre=Programmation des registres pour compter les encoches }} <source lang="java">
  
}   
 
  
void setup()
+
volatile  int s = 0;
  
{
+
voidsetup() {
  
 
   Serial.begin(9600);
 
   Serial.begin(9600);
  
   cli();         // arrêt desinterruptions
+
   attachInterrupt(0, counnt, CHANGE);
  
  EICRA=0x01;    // mode dedéclenchement de l'interruption : change
+
}
  
  EIMSK=0x01;    // choix desinterruptions actives : interruption 0
+
voidloop() {
  
   sei();         // autorisation desinterruptions
+
   Serial.println(s);
  
 
}
 
}
  
void loop()
+
voidcount() {
 +
 
 +
  if (digitalRead(2) == HIGH)
 +
 
 +
  { if (digitalRead(3) == HIGH)      s++ ;
 +
 
 +
    else      s-- ;
  
{
+
  }
 +
 
 +
  else  {
 +
 
 +
    if (digitalRead(3) == HIGH) s-- ;
  
  Serial.println(s);
+
    else s++ ;
  
 +
  }
  
 
}
 
}
  
 +
</source> {{boîte déroulante/fin}}
  
 +
 +
* Puis pour essayer d’améliorer ce programme on a programmer en utilisant les registres directement à fin d’améliorer la vitesse d'exécution du microcontrôleur, en effet il y a une augmentation d'un facteur 30 de la vitesse d’exécution en programmant les registres .<br />
 +
 +
 +
Voici donc le programme:
 +
 +
 +
{{boîte déroulante/début|titre=Programmation des registres pour compter les encoches }} <source lang="java">
 +
 +
 +
#include<avr/io.h>
 +
volatile  int s = 0;
 +
ISR(INT0_vect)    // programme d'interruption : le programmeprincipal est interrompu,
 +
{ //l'interruption exécutée et ensuite le programme principal continu normalementson exécution
 +
  if (PORTD & (1 << PIND2) == HIGH)
 +
  { if (PORTD & (1 << PIND3) ==HIGH)      s++ ;
 +
    else      s-- ;
 +
  }  else    {
 +
    if (PORTD & (1 << PIND3) ==HIGH)s-- ;
 +
    else s++ ;
 +
  }
 +
 +
voidsetup() {
 +
  Serial.begin(9600);
 +
  cli();          // arrêt des interruptions 
 +
  EICRA=0x01;    // mode de déclenchement de l'interruption: change  EIMSK=0x01; 
 +
  // choix des interruptions actives :interruption 0
 +
  sei();          // autorisation des interruptions
 +
  }
 +
void loop() {  Serial.println(s);  }
 
</source> {{boîte déroulante/fin}}
 
</source> {{boîte déroulante/fin}}
  
== programme finale : Obtention des coordonnées x , y , l'angle ==
+
== programme finale : Obtention des coordonnées x , y , l'angle ==
 +
 
  
 
{{boîte déroulante/début|titre=Programme comptant les encoches }} <source lang="java">
 
{{boîte déroulante/début|titre=Programme comptant les encoches }} <source lang="java">
  
  
#include <avr/io.h>
 
#include <math.h>
 
  
volatile  int d=0;
+
volatile  int g=0;
+
 
 +
#include<avr/io.h>
 +
 
 +
#include<math.h>
 +
 
 +
volatile  int d = 0;
 +
 
 +
volatile  int g = 0;
  
double delta_moy =0;
+
doubledelta_moy = 0;
double delta_dif =0;
 
double delta_angle =0;
 
double delta_x =0;
 
double delta_y =0;
 
double angle =0;
 
double x =0;
 
double y =0;
 
double phi =0;
 
double delta_phi = 0;
 
double difference_encouche_droite =0;
 
double difference_encouche_gauche =0;
 
double COEF_a_trouver=0;
 
const double pi = 3.14;
 
void setup()
 
  
{
+
doubledelta_dif = 0;
  
  Serial.begin(9600);
+
doubledelta_angle = 0;
  cli();          // arrêt des interruptions
 
  
  EICRA=0x05;     // mode de déclenchement de l'interruption : change
+
doubledelta_x = 0;
  
  // ISC00 =1      // ISC01 =0      // ISC10 =1      // ISC11 = 0
+
doubledelta_y = 0;
  
  EIMSK=0x03;    // choix des interruptions actives : interruption 0 & 1
+
doubleangle = 0;
  sei();         // autorisation desinterruptions
 
  
}
+
doublex = 0;
ISR(INT0_vect)    // programmed'interruption : le programme principal est interrompu,
 
  
{                // l'interruptionexécutée et ensuite le programme principal continu normalement sonexécution
+
doubley = 0;
  
  if (PORTD&(1<<PIND2)==HIGH)
+
doublephi = 0;
  { 
 
    if (PORTD&(1<<PIND3)==HIGH)
 
      g++ ;
 
    else
 
      g-- ;
 
  }
 
  else
 
  {   
 
    if (PORTD&(1<<PIND3)==HIGH)g-- ;
 
    else g++ ;
 
  } 
 
}
 
ISR(INT_vect1)    // programmed'interruption : le programme principal est interrompu,
 
  
{                // l'interruptionexécutée et ensuite le programme principal continu normalement sonexécution
+
doubledelta_phi = 0;
  
  if (PORTD&(1<<PIND3)==HIGH)
+
doubledifference_encouche_droite = 0;
  
  { 
+
doubledifference_encouche_gauche = 0
  
    if (PORTD&(1<<PIND2)==HIGH)
+
                                    ; doubleCOEF_a_trouver = 0;
      d++ ;
 
    else
 
      d-- ;
 
  }
 
  else
 
  {   
 
    if (PORTD&(1<<PIND2)==HIGH)d-- ;
 
    else d++ ;
 
  } 
 
}
 
void loop()
 
{
 
  difference_encouche_droite=d-difference_encouche_droite;
 
  difference_encouche_gauche=g-difference_encouche_gauche;
 
  delta_moy =((g+d)/2)*COEF_a_trouver;
 
  delta_dif =d-g;
 
  delta_phi=int(delta_dif/23.3) %int(2*pi);
 
  delta_x=delta_moy*cos(delta_phi);
 
  delta_y=delta_moy*sin(delta_phi);
 
  x=delta_x+x;
 
  y=delta_y+y;
 
  phi=int(delta_phi+phi) % int(2*pi) ;
 
  
  Serial.print("g="  );
+
constdouble pi = 3.14;
  Serial.print(g);
 
  Serial.print("et d =");
 
  Serial.println(d);
 
Serial.print("et phi =");
 
  Serial.println(phi);
 
//  il faut mieux mesurer L (distanceentre les 2 rue )
 
// demande au prof la conversion enint pour le modulo
 
}
 
  
</source> {{boîte déroulante/fin}}
+
voidsetup() {
  
=Transmissions des coordonnées vers la carte principal =
+
  Serial.begin(9600);  cli();          // arrêt des interruptions
==Contrainte et choix de support de transmission ==
 
  
[[Fichier:799px-PROT.PNG|center|upright=5.0||comparative des different support de transmission]]
+
  EICRA = 0x05;  // mode de déclenchement de l'interruption :change
Les constraint :  
 
  
* Support du transmission le plus rapide à fin une meilleur precision et comptage de nombre d'encouches peu importe à quel vitesse le robt tourne .
+
  // ISC00 =1      // ISC01 =0      // ISC10 =1      // ISC11 = 0
  
 +
  EIMSK = 0x03;  // choix des interruptions actives :interruption 0 & 1
  
* notre carte comunique que avec la carte mere à fin d'envoyer les coordonné donc on pas besoin juste d'un seul fil pour le transfert de donné => pas besoin de  beacoup de conxeion sans oublier la masse & le vcc.
+
  sei();          // autorisation des interruptions
  
* le type de reseau qu'on cherche est maitre-esclave : carte mere- notre carte qui envoi les information  sachant que notre microcontrleur supporte que i²c et SPI  : on debut on fais une comparaison général des differant supprt de transmission puis on se lmite au I²C et SPI à fin d'en choisir un
+
}
en comparant les diferant support de transmission presenté dans le tableau on peu voir que:
 
* 1wire, i2c & SMBUS  sont lents ce qui nous induit au erreur de posionnement => on ne prend pas .
 
* Il nous reste  CAN, SPI et M-BUS qu'on peux prendre => on essai de prendre le plus facile et le plus compatible :
 
* le M-BUS est peu compatible => on prend pas .
 
* le CAN est relativment complexe  => on prend pas .
 
* le SPI est relativment facil et je l'ai utlisé au paravant => on prend .
 
  
==Explication de SPI ==
+
ISR(INT0_vect)   // programm ed'interruption : le programmeprincipal est interrompu,
SPI ( Serial Peripheral Interface) est une liason serie sychronisé à l'aide d'un horloge ,de type maitre esclave .
 
[[Fichier:Spi-diagram.png|center|upright=5.0||comparative des different support de transmission]]
 
  
 +
{ //l'interruption exécutée et ensuite le programme principal continu normalementson exécution
  
Le bus SPI est composé de 4 signaux logiques :
+
  if (PORTD & (1 << PIND2) ==HIGH{
# SCLK — Serial Clock, Horloge (généré par le maître) permet de sychronisé la transmission de donnés .
 
# MOSI — Master Output, Slave Input (généré par le maître et envoyé à l'esclave )
 
# MISO — Master Input, Slave Output (généré par l'esclave et envoyé au maître )
 
# SS — Slave Select, Actif à l'état bas (généré par le maître)
 
  
Donc en gros on met SS =0  puis à l'aide de MISO  on envoi x,y,phi puis on remet SS=1 .
+
    if (PORTD & (1 << PIND3) ==HIGH)      g++ ;
==Méthodes pour programmer un ATtiny44a ==
 
  
Il y a plusier facon de programmer un microprocceseur dont on retient 2 :
+
    else      g-- ;
  
* Géneralement et plus facil pour un debut travaillant sur windows est de trouvé un IDE telle que atmel stuio qui oas mal fais mais tres lors lors de compilation.
+
  } else  {
  
* Sous Linux il est plus rapide et plus efficase pour prgrammer un microprosseur à l'aide d'un terminale en suivant plus etape :
+
    if (PORTD & (1 << PIND3) ==HIGH)g-- ;
***** etape de compilation
 
# se déplacer dans le répertoire de votre programme  : cd /home/ge1/deElec/
 
# CONFIGUER QUELLE µc  avr-gcc -Wall -g -Os -mmcu=attiny10 -o prog.o prog.c && avr-objcopy -j .text -j .data -O ihex prog.o prog.hex 
 
#  transferer le programme  avrdude -c avrisp2 -P usb -p t44
 
  
==Programme test de fonctionnement ==
+
    else g++ ;
===c'est programme pour clignoter UNE led :===
 
  
{{boîte déroulante/début|titre=Programme test }} <source lang="java">
+
  }
  
 +
}
  
#define F_CPU 1000000UL#include <avr/io.h>#include <util/delay.h>
+
ISR(INT_vect1)   // programme d'interruption : le programmeprincipal est interrompu,
int main(void){DDRB|=1<<PB1;  while (1)  { PORTB^= 1<<PB1; _delay_ms(300);  }
 
</source> {{boîte déroulante/fin}}
 
  
== Programme de de transmission de donné entre 2 arduino ==
+
{ //l'interruption exécutée et ensuite le programme principal continu normalementson exécution
Il y a un master & un slave :
 
===le master : ===
 
  
{{boîte déroulante/début|titre=Programme du master }} <source lang="java">
+
  if (PORTD & (1 << PIND3) ==HIGH)  {
  
#include <SPI.h>
+
    if (PORTD & (1 << PIND2) ==HIGH)      d++ ;
//master
 
void setup (void)
 
{
 
Serial.begin(115200);
 
  digitalWrite(SS, HIGH);
 
  // ensure SS stays high for now
 
  // Put SCK, MOSI, SS pins intooutput mode
 
  // also put SCK, MOSI into LOWstate, and SS into HIGH state.
 
  // Then put SPI hardware into Mastermode and turn SPI on
 
  SPI.begin ();
 
  // Slow down the master a bit
 
  SPI.setClockDivider(SPI_CLOCK_DIV128);
 
  }
 
  // end of setup
 
void loop (void)
 
{  uint8_t c,a;
 
  // enable Slave Select
 
  digitalWrite(SS, LOW);
 
     // SS is pin 10
 
  // send test string
 
  a=SPI.transfer (10);  
 
  digitalWrite(SS, HIGH);
 
  Serial.println(a,DEC);
 
  // disable Slave Select
 
  delay (100);
 
  // 1 seconds delay
 
  }
 
</source>
 
{{boîte déroulante/fin}}
 
  
=== le slave : ===
+
    else      d-- ;
  
{{boîte déroulante/début|titre=Programme du slave }} <source lang="java">
+
  } else  {
  
#define F_CPU 1000000UL
+
    if (PORTD & (1 << PIND2) ==HIGH)d-- ;
  
#include <avr/io.h>
+
    else d++ ;
  
#include <avr/interrupt.h>
+
  }
  
#include <util/delay.h>
+
}
  
 +
voidloop() {
  
 +
  difference_encouche_droite = d -difference_encouche_droite;
  
MCUCR|=1<<ISC00;
+
  difference_encouche_gauche = g -difference_encouche_gauche;
  
MCUCR|=1<<ISC01;
+
  delta_moy = ((g + d) / 2) * COEF_a_trouver;
  
ISR (INT0_vect)
+
  delta_dif = d - g;
  
{
+
  delta_phi = int(delta_dif / 23.3) % int(2 *pi);
  
  static uint8_t x=0;  
+
  delta_x = delta_moy * cos(delta_phi);
  
 
+
  delta_y = delta_moy * sin(delta_phi);
  
  x++;  
+
  x = delta_x + x;  y = delta_y + y;
  
}
+
  phi = int(delta_phi + phi) % int(2 * pi) ;
  
 +
  Serial.print("g="  );
  
 +
  Serial.print(g);
  
 +
  Serial.print("et d =");
  
 +
  Serial.println(d);
  
ISR (USI_OVF_vect)  
+
  Serial.print("et phi =");
  
{
+
  Serial.println(phi);//  il faut mieux mesurer L (distance entre les2 rue )// demande au prof la conversion en int pour le modulo
  
  static uint8_t i=0;
+
}
  
  // valeur a transmettre pour le coupsuivant
 
  
  USIDR=i;
+
</source> {{boîte déroulante/fin}}
  
  //acquittement de l'ovf
+
=Transmissions des coordonnées vers la carte principal =
  
  USISR|=1<<USIOIF;
 
  
  // test de transmission  
+
==Contrainte et choix de support de transmission ==
  
  i+=3;
 
  
}
+
[[Fichier:799px-PROT.PNG|center|upright=5.0||comparatif des différent support de transmission]]
  
  
 +
Les contraintes :
  
int main (void)
 
  
{
+
* Nous avons besoin d'un support de transmission rapide et précis quelque soit la vitesse de la roue codeuse.
  
    //MISO comme sortie
 
  
    DDRA|=1<<PA7;
+
* notre carte communique avec la carte mère à fin d'envoyer les coordonné.
  
    // mode 3wire
 
  
    USICR|=1<<USIWM0;
+
* le type de réseau qu'on recherche est une liaison maître-esclave : c'est notre carte qui envoi les information.
  
    // clock
 
  
    USICR|=1<<USICS1;
+
Sachant que notre microcontrôleur ne supporte que les protocoles i²c et SPI, on se limite donc au I²C et SPI :
  
    //interruption
 
  
    USICR|=1<<USIOIE;
+
En comparant les deux peu voir que:
  
    sei();
 
  
    // acquittement d'un ovf eventuel
+
* le protocole '''i2c''' est lent ce qui nous expose a des erreur de positionnement.
  
    USISR|=1<<USIOIF;
 
  
    while (1)
+
* le '''SPI''' est est plus rapide ce qui nous nous amène a le choisir plutôt que le '''i2c''' .
  
    {
 
  
      // attente du SS
+
== Fonctionnement du protocole SPI ==
  
      while((PINA&(1<<PA7))!=0);
 
  
      // fin du SS
+
SPI ( Serial Peripheral Interface) est une liaison série synchronisé à l'aide d'une horloge, de type maître-esclave.
  
      while((PINA&(1<<PA7))==0);
 
  
      // remise a zero du compteur defront
+
[[Fichier:Spi-diagram.png|center|upright=5.0||comparative des différent support de transmission]]
  
      // permet de resynchroniser encas de pb
 
  
      // a faire plutot parinterruption sur front de SS
+
Le bus SPI est composé de 4 signaux logiques :
  
      USISR &=0b11110000;
 
  
    }
+
# SCLK — Serial Clock, Horloge (généré par le maître) permet de synchronisé la transmission de donnés .
 +
# MOSI — Master Output, Slave Input (généré par le maître et envoyé à l'esclave )
 +
# MISO — Master Input, Slave Output (généré par l'esclave et envoyé au maître )
 +
# SS — Slave Select, Actif à l'état bas (généré par le maître)
  
}
 
  
</source> {{boîte déroulante/fin}}
+
Donc en gros on met SS = 0 puis à l'aide de MISO on envoi x,y,phi puis on remet SS = 1 .
  
== Assemblage de données  ==
 
Apres avoir reussi à faire un transmission de donné en SPI entre arduino et ATtiny44 on va essieé de ressmeblger les element permettant d'avoir les coordonné :
 
=== Simuation des roues codeuse en reliant un GBF au pin : PB2 ===
 
  
{{boîte déroulante/début|titre=Programme comptant les encoches }} <source lang="java">
+
== Méthodes pour programmer un ATtiny44a ==
  
  
#define F_CPU 1000000UL
+
Il y a plusieurs façon de programmer un microprocesseur voici les deux plus courantes :
  
#include <avr/io.h>
 
  
#include <avr/interrupt.h>
+
* Généralement il est plus facile pour un débutant travaillant sous Windows d'utiliser un IDE telle que atmel studio qui bien fait mais très long lors de compilation.
  
#include <util/delay.h>
 
  
 +
* Sous Linux il est plus rapide et plus efficace de programmer un microprocesseur à l'aide d'un terminale en suivant plusieurs étape :
  
  
volatile uint8_t x=0;
+
***** étape de compilation
  
  
 +
* se déplacer dans le répertoire de votre programme : cd /home/ge1/deElec/
  
ISR (USI_OVF_vect)
 
  
{
+
* CONFIGURER QUELLE µc avr-gcc -Wall -g -Os -mmcu=attiny44 -o prog.o prog.c && avr-objcopy -j .text -j .data -O ihex prog.o prog.hex
  
  
 +
* transférer le programme avrdude -c avrisp2 -P usb -p t44 -U flash:w:"prog.hex"
  
  // valeur a transmettre pour le coupsuivant
+
==Programme test de fonctionnement ==
  
  USIDR=x;
 
  
}
+
===Programme pour faire clignoter une led:===
  
ISR (INT0_vect)
 
  
{
+
{{boîte déroulante/début|titre=Programme test }} <source lang="java">
  
  // valeur a transmettre pour le coupsuivant
 
  
 +
#define F_CPU 1000000UL#include <avr/io.h>#include <util/delay.h>int main(void){DDRB|=1<<PB1;  while (1)  { PORTB^= 1<<PB1; _delay_ms(300);  }
 +
== Programme de transmission de donné entre une carte arduino et un attiny44 ==
  
  
  x++;
+
Il y a un master & un slave :
  
}
 
  
 +
=== Le master : ===
  
  
int main (void)
+
{{boîte déroulante/début|titre=Programme du master }} <source lang="java">
  
 +
#include <SPI.h> //master void setup (void)
 +
{
 +
Serial.begin(115200);
 +
    digitalWrite(SS, HIGH);
 +
    // ensure SS stays high for now
 +
    // Put SCK, MOSI, SS pins intooutput mode
 +
    // also put SCK, MOSI into LOWstate, and SS into HIGH state.
 +
    // Then put SPI hardware into Mastermode and turn SPI on
 +
    SPI.begin ();
 +
    // Slow down the master a bit
 +
  SPI.setClockDivider(SPI_CLOCK_DIV128);
 +
    }
 +
    // end of setup void loop (void)
 
{
 
{
 +
  uint8_t c,a;
 +
    // enable Slave Select
 +
    digitalWrite(SS, LOW);
 +
      // SS is pin 10
 +
    // send test string
 +
    a=SPI.transfer (10);
 +
    digitalWrite(SS, HIGH);
 +
    Serial.println(a,DEC);
 +
    // disable Slave Select
 +
    delay (100);
 +
    // 1 seconds delay
 +
  } </source>{{boîte déroulante/fin}}
  
MCUCR|=1<<ISC00;
+
=== le slave : ===
  
MCUCR|=1<<ISC01; // RISING EDGEINT0
 
  
GIMSK|=1<<INT0;
+
{{boîte déroulante/début|titre=Programme du slave }}
  
    //MISO comme sortie
 
  
    DDRA|=1<<PA5;
+
<source lang="java">#define F_CPU 1000000UL
  
    // mode 3wire
 
  
     USICR|=1<<USIWM0;
+
#include <avr/io.h> 
 +
#include <avr/interrupt.h> 
 +
#include <util/delay.h>
 +
    MCUCR|=1<<ISC00;
 +
    MCUCR|=1<<ISC01; ISR (INT0_vect)
 +
  {
 +
    static uint8_t x=0;
 +
      x++;
 +
  }
 +
      ISR (USI_OVF_vect)
 +
  {
 +
    static uint8_t i=0;    // valeur a transmettre pour le coup suivant
 +
    USIDR=i;     //acquittement de l'ovf
 +
    USISR|=1<<USIOIF;    // test de transmission
 +
    i+=3;
 +
  }
 +
      int main (void) }      //MISO comme sortie     
 +
      DDRA|=1<<PA7;      // mode 3wire
 +
      USICR|=1<<USIWM0;     // clock
 +
      USICR|=1<<USICS1;      //interruption
 +
      USICR|=1<<USIOIE;
 +
      sei();      // acquittement d'un ovf éventuel
 +
      USISR|=1<<USIOIF;
 +
      while (1)      {        // attente du SS
 +
        while((PINA&(1<<PA7))!=0);      // fin du SS
 +
        while((PINA&(1<<PA7))==0);      // remise a zero du compteur de front
 +
        // permet de resynchroniser en cas de pb
 +
      // a faire plutôt par interruption sur front de SS
 +
        USISR &=0b11110000;   
 +
    }
 +
}
  
    // clock
 
  
    USICR|=1<<USICS1;
+
</source> {{boîte déroulante/fin}}
  
    //interruption
+
== Assemblage de données ==
  
    USICR|=1<<USIOIE;
 
  
    sei();
+
Après avoir réussi à faire un transmission de donné en SPI entre arduino et ATtiny44 on va tenter de rassembler les éléments permettant d'avoir les coordonné :
  
    // acquittement d'un ovf eventuel
+
=== Simulation des roues codeuse en reliant un GBF au pin : PB2 ===
  
    USISR|=1<<USIOIF;
 
  
    while (1)
+
{{boîte déroulante/début|titre=Programme comptant les encoches }} <source lang="java">
  
    {
 
  
      // attente du SS
 
  
       while((PINA&(1<<PA7))!=0);
+
#define F_CPU 1000000UL
 +
#include <avr/io.h>
 +
#include <avr/interrupt.h>
 +
#include <util/delay.h>
 +
  volatile uint8_t x=0;
 +
  ISR (USI_OVF_vect) {      // valeur a transmettre pour le coup suivant
 +
  USIDR=x; }
 +
ISR (INT0_vect) {    // valeur a transmettre pour le coup suivant
 +
       x++; } 
 +
int main (void) {
 +
MCUCR|=1<<ISC00;
 +
MCUCR|=1<<ISC01;    // RISING EDGEINT0
 +
GIMSK|=1<<INT0;    //MISO comme sortie
 +
        DDRA|=1<<PA5;      // mode 3wire
 +
        USICR|=1<<USIWM0;  // clock
 +
        USICR|=1<<USICS1;    //interruption
 +
        USICR|=1<<USIOIE;
 +
      sei();    // acquittement d'un ovf eventuel
 +
    USISR|=1<<USIOIF;
 +
    while (1)    {      // attente du SS
 +
      while((PINA&(1<<PA7))!=0);       // fin du SS
 +
      while((PINA&(1<<PA7))==0);      // remise a zero du compteur defront
 +
                                      // permet de resynchroniser encas de pb
 +
                                      // a faire plutot parinterruption sur front de SS
 +
      USISR &=0b11110000;
 +
    }
 +
}
  
      // fin du SS
 
  
      while((PINA&(1<<PA7))==0);
+
</source> {{boîte déroulante/fin}}
  
      // remise a zero du compteur defront
 
  
      // permet de resynchroniser encas de pb
+
=== Utilisation de l'algorithme pour obtenir les position définit précédemment ===
  
      // a faire plutot parinterruption sur front de SS
 
  
      USISR &=0b11110000;
+
c'est la partie finale du projet que l'on a malheureusement pas pu terminer :
  
    }
 
  
}
+
insérer l'algorithme et les différentes parties plus hauts pour avoir les coordonnés polaire et l'angle du robot.
 +
 
 +
 
 +
{{boîte déroulante/début|titre= à compléter}} <source lang="java">
 +
 
 +
 
 +
#include <avr/io.h>
 +
#include <math.h> 
 +
volatile  int d=0;
 +
volatile  int g=0;
 +
 
  
 +
/*double delta_moy =0;
 +
double delta_dif =0;
 +
double delta_angle =0;
 +
double delta_x =0;
 +
double delta_y =0;
 +
double angle =0;
 +
double x =0;
 +
double y =0;
 +
double phi =0;
 +
double delta_phi = 0;
 +
double difference_encouche_droite =0;
 +
double difference_encouche_gauche =0;
 +
double COEF_a_trouver=0;
 +
const double pi = 3.14;
 +
*/void setup()
 +
  {  Serial.begin(9600);
 +
        cli();                // arrêt des interruptions  EICRA|=0x05;
 +
                              // mode de déclenchement de l'interruption : change
 +
      // ISC00 =1
 +
      // ISC01 =0
 +
      // ISC10 =1
 +
      // ISC11 = 0
 +
  EIMSK|=0x03;
 +
                    // choix des interruptions actives : interruption 0 & 1
 +
  sei();          // autorisation des interruptions}
 +
  ISR(INT0_vect)    // programme d'interruption : le programme principal est interrompu,
  
</source> {{boîte déroulante/fin}}
 
  
=Annexes=
+
 +
              // l'interruption exécutée et ensuite le programme principal continu normalement son exécution
 +
if ((PORTD&(1<<PIND2))!=0) 
  
==Pages en relation avec le positionnement==
 
  
http://www.telecom-robotics.org/wiki/Tutoriels/AsservissementParPidEtPositionnementParRouesCodeuses/CalibrationDuPositionnement
+
{
 +
    Serial.println("h");
 +
    if ((PORTD&(1<<PIND3))!=0)
 +
      g++ ;
 +
    else
 +
      g-- ;
 +
  }
 +
  else
 +
  {
 +
      Serial.println("l");
 +
    if ((PORTD&(1<<PIND3))!=0)g++ ;
 +
    else g-- ;
 +
    }
 +
  } ISR(INT_vect1)    // programme d'interruption : le programme principal est interrompu,{                // l'interruption exécutée et ensuite le programme principal continu normalement son exécution  if (PORTD&(1<<PIND3)!=0)  {      if (PORTD&(1<<PIND2)!=0)      d++ ;    else      d-- ;  }  else  {        if (PORTD&(1<<PIND2)!=0)d-- ;    else d++ ;  }  } void loop(){/*  difference_encouche_droite=d-difference_encouche_droite;  difference_encouche_gauche=g-difference_encouche_gauche;  delta_moy =((g+d)/2)*COEF_a_trouver;  delta_dif =d-g;  delta_phi=int(delta_dif/23.3) %int(2*pi);  delta_x=delta_moy*cos(delta_phi);  delta_y=delta_moy*sin(delta_phi);  x=delta_x+x;  y=delta_y+y;  phi=int(delta_phi+phi) % int(2*pi) ;*/int tmp=g;  Serial.print("g="  );  Serial.println(tmp);//  Serial.print("et d =");// Serial.println(d);  delay(200); // Serial.print("et phi ="); // Serial.println(phi);  /* il faut mieux mesurer L (distance entre les 2 rue )    demande au prof la conversion en int pour le modulo    trouver la coefficient de réduction j'ai mis à un   
  
http://manubatbat.free.fr/doc/positionning/node5.html
 
  
http://www.pobot.org/Asservissement-d-un-moteur-a.html
+
*/}</source> {{boîte déroulante/fin}}
  
http://www.google.fr/imgres?imgurl=http%3A%2F%2Fhades.mech.northwestern.edu%2Fimages%2F8%2F82%2FPhototransistor_amplifiers.png&imgrefurl=http%3A%2F%2Fhades.mech.northwestern.edu%2Findex.php%2FPhotodiodes_and_Phototransistors&h=261&w=300&tbnid=gZQHvvEuM1dFUM%3A&zoom=1&docid=Zmypbg4snhteNM&ei=klR3VKuEBsWY7gaEv4GgBA&tbm=isch&iact=rc&uact=3&dur=12876&page=1&start=0&ndsp=19&ved=0CEQQrQMwCQ
+
=Annexes=
  
http://www.vishay.com/docs/84756/tcut1300.pdf
+
==Pages en relation avec le positionnement==
  
http://www.atmel.com/Images/Atmel-8127-AVR-8-bit-Microcontroller-ATtiny4-ATtiny5-ATtiny9-ATtiny10_Datasheet.pdf
+
* http://www.telecom-robotics.org/wiki/Tutoriels/AsservissementParPidEtPositionnementParRouesCodeuses/CalibrationDuPositionnement
 +
* http://manubatbat.free.fr/doc/positionning/node5.html
 +
* http://www.pobot.org/Asservissement-d-un-moteur-a.html
 +
* http://www.vishay.com/docs/84756/tcut1300.pdf
 +
* http://www.atmel.com/Images/Atmel-8127-AVR-8-bit-Microcontroller-ATtiny4-ATtiny5-ATtiny9-ATtiny10_Datasheet.pdf

Version actuelle datée du 19 mai 2015 à 12:55


Présentation

Exemple de Robot

Notre projet à pour but de concevoir un robot pour participer à La coupe de France des IUT GEII à CachanDans cette partie nous allons nous concentrer sur la position du robot sa navigation et sa faculté a éviter les obstacles décrit dans le règlement.

Navigation

Codeur rotatif

Afin de connaitre la position des roues, de savoir de combien elles ont tournés nous utiliserons un codeur rotatif.Les codeurs rotatifs sont un type de capteurs permettant de délivrer une information d'angle, en mesurant la rotation effectuée autour d'un axe.L'information de vitesse peut alors être déduite de la variation de la position par rapport au temps. Plus le codeur rotatif tourne lentement, plus la déduction de vitesse perd en précision.

Il en existe 2 principaux types :

  • Le codeur rotatif incrémental qui ajoute ou soustrait (selon le sens de rotation) une unité à un compteur à chaque rotation supérieure à la résolution du capteur. Le compteur est généralement remis à zéro lorsque l'appareil est allumé. C'est le cas de la souris d'ordinateur à boule.
  • Le codeur rotatif absolu qui intègre son propre compteur. Ce genre de capteur est généralement calibré et initialisé une seule fois, et il conserve normalement sa valeur lors de l'arrêt de l'appareil. C'est le cas des compteurs kilométriques des automobiles à la différence du "compteur journalier" qui peut être remis a zéro par l'utilisateur.

Nous utiliseront des codeurs incrémentaux fixé sur les axes des deux moteur ce qui nous permettra d'asservir la rotation des robot c'est à dire que nous pourrons avoir un retour sur les commande du moteur de plus on connaîtra l'angle pris par le robot par rapport a sa position de départ. En effet ce genre des capteur est plus précis par rapport à l'autre.

Fonctionnement d'un codeur

équation de positionnement

Le positionnement du robot en intégration les information reçu des codeur incrémentaux qui constituera des petits déplacements avec les quelle on pourra nous positionner.


Il y a deux manières d'approximer la trajectoire parcourue par le robot sur un laps de temps :


  • En utilisant des segments de droites. On considère alors que le robot va en ligne droite sur toute la période. Ceci revient à supposer que les deux roues ont une vitesse constante et identique sur cet élément de trajectoire. A la fin de cet élément de trajectoire, on corrige l'orientation du robot en fonction de la différence de distance parcourue par les deux roues.


  • En utilisant des arcs de cercles . On considère alors que le robot se déplace et change d'orientation en suivant un arc de cercle pendant le temps . Ceci revient à considérer que chacune des roues a une vitesse constante sur la période mais que les vitesses des 2 roues ne sont pas identiques.


positionnement par segement


On peux alors cacluler les positionement en calculant la distance parcouru et le temps de trajet des 2 roues :


positionnement par segement


On peut alors accéder à la position du robot (coordonnées x,y)


positionnement par segement


Réalisation de la roue codeuse

Nous avons pris les mesures du moteur et du châssis imposé pour la compétition afin de fabriquer notre roue codeuse puis nous l'avons représenter sur le logiciel de création de Charly robot. Nous avons choisit des fentes ouvertes sur l’extérieur, c'est a dire pas de contour la taille de la fente est limité par les outils que nous avons une fraise de 2 mm donc la taille de nos fente est de 2 mm une taille minimal permet une précision maximal lors de la rotation. La première roue que l'on a usiner était trop fine et donc pas assez rigide :


première roue usiné


Nous avons donc choisit de tester une roue à deux épaisseurs : l'une plus fine (1 mm) pour la partie extérieur et l'autre plus épaisse pour la partie intérieure de la roue (2 mm). :


deuxième roue usiné


Cette solution étant aussi fragile que la précédente nous avons finalement opter pour une roue à une seul épaisseur de 2mm pour avoir une bonne rigidité et peu de vibration.


Réalisation du montage électronique

le montage Electronique a pour but de récupérer et traiter les signaux obtenus par les optocoupleurs TCUT 1300 pour nous permettre de compter le nombres d’encoche parcouru et connaitre le sens de rotation grâce aux 2 photo-transistor. Nous avons tout d'abord utilisé le montage d'un groupe qui a travaillé sur le projet avant nous, toutefois leur montage n'a pas fonctionner. On a fini par modifié leurs montage afin de corriger les erreurs ce qui a donné le montage suivant :


montage détecteurs d'encoches


  • Si il y de la lumière émise par la photodiode et reçu par le photo-transistor on a un état logique "1" => ce qui correspond a une encoche.


  • Si il y a un obstacle entre la photodiode et le photo-transistor on a un état logique "0" => pas d'encoche.On obtiendra donc un signal de cette allure :


signal détecteur d'encoche


Phase de test

Le problème rencontré est que lorsque la roue codeuse tournait rapidement on ne détecté plus l'encoche : état 0 Pour résoudre ce problème on a utilisé à la place d'une résistance fixe une résistance variable qu'on a tester avec différentes valeur à fin d'avoir un rapport cyclique le proche possible de 50% en vitesse maximal. En effet ce problème est du à la présence d'une capacité au montage donc si la roue codeuse tourne rapidement le circuit ne peux plus détecter le "0" ce qui s'explique par la constante de temps R*C trop petite, donc il faut augmenté R à fin que le temps de réponse soit plus rapide. En effet si la résistance est trop faible la tension n'aura pas le temps de descendre puis remonter donc elle reste à l’état haut .


REMARQUE :


  • On place un condensateur en parallèle de chaque photo-transistors pour filtrer les pics qui pourraient venir perturber le fonctionnement des capteurs.


  • On a aussi insérer un condensateur de découplage à fin de filtrer les pic provenant de l'alimentation.


Réalisation de la carte

Suite à la phase de test nous avons commencé la conception de la carte


Le schéma:


Schéma de la carte roue codeuse


Le board :


Board de la carte roue codeuse


Changement du Semestre 4

Durant le quatrième semestre nous avons procédé a la correction du schéma et du board, en effet pendant la phase de test de la carte ci-dessus nous nous sommes aperçu que certain composant été mal positionné nous avons donc procédé a des modification.


ci-dessous le schéma et le board définitif:


Le schéma :


Schéma corrigé de la carte roue codeuse


Le board :


Board corrigé de la carte roue codeuse


Tout sera relié à un microcontrôleur en l'occurrence c'est unATtiny44 (mais on a réaliser les testes en utilisant une carte arduino Uno) car ce microcontrôleur présente l'avantage d’être peu onéreux et le nombre de pin qui nous suffit largement (voir annexe pour la documentation )



Comptage du nombres d’encoche et détermination du sens de rotation

Il faut faire un programme qui, à partir des signaux obtenu dans la partie montage électronique compte le nombre d’encoches tout en tenant compte du sens de rotation !
Il faut tout d'abord initialisé un sens comme le sens direct qui à chaque encoche parcouru incrémentera le compteur et diminuera à chaque encoche parcouru dans le sens inverse .
Pour détecter dans quelle sens la roue tourne, on compare le retard juste après la changement (on peut comparé juste après la phase montante ou après la phase descendante mais pour une meilleur précision on compare pour les 2 phases) d'état du signal A par rapport aux signal B de l’optocoupleur, en effet il y a 4 cas de figures possibles :



Exploitations des 2 signaux d'un optocoupleur


  1. Le signal A = 1 et B = 1 ==> sens direct ==> on incrémente
  2. Le signal A = 1 et B = 0 ==> sens indirect ==> on diminue
  3. Le signal A = 0 et B = 1 ==> sens indirect ==> on diminue
  4. Le signal A = 0 et B = 0 ==> sens direct ==> on incrémente


Maintenant il faut écrire le programme :


  • Dans un premier temps on a réaliser un programme en utilisant les fonctions que la bibliothèque d'Arduino nous offre pour tester et bien comprendre.


Voici donc le premier programme:

Programmation des registres pour compter les encoches

volatile  int s = 0;

voidsetup() {

  Serial.begin(9600);

  attachInterrupt(0, counnt, CHANGE);

}

voidloop() {

  Serial.println(s);

}

voidcount() {

  if (digitalRead(2) == HIGH)

  { if (digitalRead(3) == HIGH)      s++ ;

    else      s-- ;

  }

  else  {

    if (digitalRead(3) == HIGH) s-- ;

    else s++ ;

  }

}


  • Puis pour essayer d’améliorer ce programme on a programmer en utilisant les registres directement à fin d’améliorer la vitesse d'exécution du microcontrôleur, en effet il y a une augmentation d'un facteur 30 de la vitesse d’exécution en programmant les registres .


Voici donc le programme:


Programmation des registres pour compter les encoches

#include<avr/io.h>
volatile  int s = 0;
ISR(INT0_vect)    // programme d'interruption : le programmeprincipal est interrompu,
{ //l'interruption exécutée et ensuite le programme principal continu normalementson exécution
  if (PORTD & (1 << PIND2) == HIGH)
  { if (PORTD & (1 << PIND3) ==HIGH)       s++ ;
    else       s-- ;
  }  else    {
    if (PORTD & (1 << PIND3) ==HIGH)s-- ;
    else s++ ;
  }
}  
voidsetup() {
  Serial.begin(9600);
  cli();          // arrêt des interruptions  
  EICRA=0x01;     // mode de déclenchement de l'interruption: change   EIMSK=0x01;  
  // choix des interruptions actives :interruption 0 
  sei();          // autorisation des interruptions
  } 
void loop() {   Serial.println(s);  }

programme finale : Obtention des coordonnées x , y , l'angle

Programme comptant les encoches

 

#include<avr/io.h>

#include<math.h>

volatile  int d = 0;

volatile  int g = 0;

doubledelta_moy = 0;

doubledelta_dif = 0;

doubledelta_angle = 0;

doubledelta_x = 0;

doubledelta_y = 0;

doubleangle = 0;

doublex = 0;

doubley = 0;

doublephi = 0;

doubledelta_phi = 0;

doubledifference_encouche_droite = 0;

doubledifference_encouche_gauche = 0

                                    ; doubleCOEF_a_trouver = 0;

constdouble pi = 3.14;

voidsetup() {

  Serial.begin(9600);  cli();          // arrêt des interruptions

  EICRA = 0x05;   // mode de déclenchement de l'interruption :change

  // ISC00 =1      // ISC01 =0      // ISC10 =1       // ISC11 = 0

  EIMSK = 0x03;   // choix des interruptions actives :interruption 0 & 1

  sei();          // autorisation des interruptions

}

ISR(INT0_vect)    // programm ed'interruption : le programmeprincipal est interrompu,

{ //l'interruption exécutée et ensuite le programme principal continu normalementson exécution

  if (PORTD & (1 << PIND2) ==HIGH)  {

    if (PORTD & (1 << PIND3) ==HIGH)      g++ ;

    else      g-- ;

  } else   {

    if (PORTD & (1 << PIND3) ==HIGH)g-- ;

    else g++ ;

  }

}

ISR(INT_vect1)    // programme d'interruption : le programmeprincipal est interrompu,

{ //l'interruption exécutée et ensuite le programme principal continu normalementson exécution

  if (PORTD & (1 << PIND3) ==HIGH)   {

    if (PORTD & (1 << PIND2) ==HIGH)      d++ ;

    else      d-- ;

  } else   {

    if (PORTD & (1 << PIND2) ==HIGH)d-- ;

    else d++ ;

  }

}

voidloop() {

  difference_encouche_droite = d -difference_encouche_droite;

  difference_encouche_gauche = g -difference_encouche_gauche;

  delta_moy = ((g + d) / 2) * COEF_a_trouver;

  delta_dif = d - g;

  delta_phi = int(delta_dif / 23.3) % int(2 *pi);

  delta_x = delta_moy * cos(delta_phi);

  delta_y = delta_moy * sin(delta_phi);

  x = delta_x + x;  y = delta_y + y;

  phi = int(delta_phi + phi) % int(2 * pi) ;

  Serial.print("g="   );

  Serial.print(g);

  Serial.print("et d =");

  Serial.println(d);

  Serial.print("et phi =");

  Serial.println(phi);//   il faut mieux mesurer L (distance entre les2 rue )// demande au prof la conversion en int pour le modulo

}

Transmissions des coordonnées vers la carte principal

Contrainte et choix de support de transmission

comparatif des différent support de transmission


Les contraintes :


  • Nous avons besoin d'un support de transmission rapide et précis quelque soit la vitesse de la roue codeuse.


  • notre carte communique avec la carte mère à fin d'envoyer les coordonné.


  • le type de réseau qu'on recherche est une liaison maître-esclave : c'est notre carte qui envoi les information.


Sachant que notre microcontrôleur ne supporte que les protocoles i²c et SPI, on se limite donc au I²C et SPI :


En comparant les deux peu voir que:


  • le protocole i2c est lent ce qui nous expose a des erreur de positionnement.


  • le SPI est est plus rapide ce qui nous nous amène a le choisir plutôt que le i2c .


Fonctionnement du protocole SPI

SPI ( Serial Peripheral Interface) est une liaison série synchronisé à l'aide d'une horloge, de type maître-esclave.


comparative des différent support de transmission


Le bus SPI est composé de 4 signaux logiques :


  1. SCLK — Serial Clock, Horloge (généré par le maître) permet de synchronisé la transmission de donnés .
  2. MOSI — Master Output, Slave Input (généré par le maître et envoyé à l'esclave )
  3. MISO — Master Input, Slave Output (généré par l'esclave et envoyé au maître )
  4. SS — Slave Select, Actif à l'état bas (généré par le maître)


Donc en gros on met SS = 0 puis à l'aide de MISO on envoi x,y,phi puis on remet SS = 1 .


Méthodes pour programmer un ATtiny44a

Il y a plusieurs façon de programmer un microprocesseur voici les deux plus courantes :


  • Généralement il est plus facile pour un débutant travaillant sous Windows d'utiliser un IDE telle que atmel studio qui bien fait mais très long lors de compilation.


  • Sous Linux il est plus rapide et plus efficace de programmer un microprocesseur à l'aide d'un terminale en suivant plusieurs étape :


          • étape de compilation


  • se déplacer dans le répertoire de votre programme : cd /home/ge1/deElec/


  • CONFIGURER QUELLE µc avr-gcc -Wall -g -Os -mmcu=attiny44 -o prog.o prog.c && avr-objcopy -j .text -j .data -O ihex prog.o prog.hex


  • transférer le programme avrdude -c avrisp2 -P usb -p t44 -U flash:w:"prog.hex"

Programme test de fonctionnement

Programme pour faire clignoter une led:

Programme test

#define F_CPU 1000000UL#include <avr/io.h>#include <util/delay.h>int main(void){DDRB|=1<<PB1;  while (1)  {	PORTB^= 1<<PB1; 	_delay_ms(300);  }
== Programme de transmission de donné entre une carte arduino et un attiny44 ==


Il y a un master & un slave :


=== Le master : ===


{{boîte déroulante/début|titre=Programme du master }} <source lang="java">

#include <SPI.h> //master void setup (void) 
{ 
Serial.begin(115200);
    digitalWrite(SS, HIGH);
    // ensure SS stays high for now
    // Put SCK, MOSI, SS pins intooutput mode
    // also put SCK, MOSI into LOWstate, and SS into HIGH state.
    // Then put SPI hardware into Mastermode and turn SPI on
    SPI.begin ();
    // Slow down the master a bit
   SPI.setClockDivider(SPI_CLOCK_DIV128);
    }
    // end of setup void loop (void) 
{
  uint8_t c,a;
    // enable Slave Select
    digitalWrite(SS, LOW);
      // SS is pin 10
    // send test string
    a=SPI.transfer (10);
    digitalWrite(SS, HIGH);
    Serial.println(a,DEC);
    // disable Slave Select
    delay (100);
    // 1 seconds delay
   }

le slave :

Programme du slave


#define F_CPU 1000000UL


#include <avr/io.h>  
#include <avr/interrupt.h>  
#include <util/delay.h>
    MCUCR|=1<<ISC00; 
    MCUCR|=1<<ISC01; ISR (INT0_vect)
  {
     static uint8_t x=0;
       x++;
  }
      ISR (USI_OVF_vect)
  {
     static uint8_t i=0;     // valeur a transmettre pour le coup suivant
     USIDR=i;     //acquittement de l'ovf 
     USISR|=1<<USIOIF;     // test de transmission
     i+=3;
  }
      int main (void) }      //MISO comme sortie      
      DDRA|=1<<PA7;      // mode 3wire
      USICR|=1<<USIWM0;      // clock
      USICR|=1<<USICS1;      //interruption
      USICR|=1<<USIOIE;
      sei();      // acquittement d'un ovf éventuel
      USISR|=1<<USIOIF;
      while (1)      {        // attente du SS
        while((PINA&(1<<PA7))!=0);       // fin du SS
        while((PINA&(1<<PA7))==0);       // remise a zero du compteur de front
        // permet de resynchroniser en cas de pb 
       // a faire plutôt par interruption sur front de SS
        USISR &=0b11110000;     
     } 
 }

Assemblage de données

Après avoir réussi à faire un transmission de donné en SPI entre arduino et ATtiny44 on va tenter de rassembler les éléments permettant d'avoir les coordonné :

Simulation des roues codeuse en reliant un GBF au pin : PB2

Programme comptant les encoches

#define F_CPU 1000000UL 
#include <avr/io.h> 
#include <avr/interrupt.h> 
#include <util/delay.h>
   volatile uint8_t x=0;
   ISR (USI_OVF_vect) {      // valeur a transmettre pour le coup suivant
   USIDR=x; }
 ISR (INT0_vect) {    // valeur a transmettre pour le coup suivant
      x++; }   
int main (void) {
 	MCUCR|=1<<ISC00;
 	MCUCR|=1<<ISC01;    // RISING EDGEINT0
 	GIMSK|=1<<INT0;     //MISO comme sortie
         DDRA|=1<<PA5;      // mode 3wire
        USICR|=1<<USIWM0;   // clock
        USICR|=1<<USICS1;     //interruption
        USICR|=1<<USIOIE;
       sei();     // acquittement d'un ovf eventuel
     USISR|=1<<USIOIF;
     while (1)     {       // attente du SS
       while((PINA&(1<<PA7))!=0);       // fin du SS
       while((PINA&(1<<PA7))==0);       // remise a zero du compteur defront
                                       // permet de resynchroniser encas de pb
                                       // a faire plutot parinterruption sur front de SS
       USISR &=0b11110000;
     }
 }


Utilisation de l'algorithme pour obtenir les position définit précédemment

c'est la partie finale du projet que l'on a malheureusement pas pu terminer :


insérer l'algorithme et les différentes parties plus hauts pour avoir les coordonnés polaire et l'angle du robot.


à compléter

#include <avr/io.h> 
#include <math.h>  
volatile  int d=0;
volatile  int g=0;


/*double delta_moy =0;
 double delta_dif =0;
double delta_angle =0;
double delta_x =0;
double delta_y =0;
double angle =0;
double x =0;
double y =0;
double phi =0;
double delta_phi = 0;
double difference_encouche_droite =0;
double difference_encouche_gauche =0;
double COEF_a_trouver=0;
const double pi = 3.14;
*/void setup()
  {  Serial.begin(9600);
        cli();                // arrêt des interruptions  EICRA|=0x05;
                              // mode de déclenchement de l'interruption : change
       // ISC00 =1
       // ISC01 =0
       // ISC10 =1
       // ISC11 = 0
  EIMSK|=0x03;
                    // choix des interruptions actives : interruption 0 & 1
  sei();           // autorisation des interruptions}
  ISR(INT0_vect)    // programme d'interruption : le programme principal est interrompu,


{  
               // l'interruption exécutée et ensuite le programme principal continu normalement son exécution
if ((PORTD&(1<<PIND2))!=0)  


{
    Serial.println("h");
    if ((PORTD&(1<<PIND3))!=0)
      g++ ;
    else
       g-- ;
  }
  else
   {
       Serial.println("l");
    if ((PORTD&(1<<PIND3))!=0)g++ ;
    else g-- ;
     } 
   } ISR(INT_vect1)    // programme d'interruption : le programme principal est interrompu,{                 // l'interruption exécutée et ensuite le programme principal continu normalement son exécution  if (PORTD&(1<<PIND3)!=0)  {      if (PORTD&(1<<PIND2)!=0)      d++ ;    else       d-- ;  }  else   {        if (PORTD&(1<<PIND2)!=0)d-- ;    else d++ ;  }   } void loop(){/*  difference_encouche_droite=d-difference_encouche_droite;  difference_encouche_gauche=g-difference_encouche_gauche;  delta_moy =((g+d)/2)*COEF_a_trouver;  delta_dif =d-g;  delta_phi=int(delta_dif/23.3) %int(2*pi);  delta_x=delta_moy*cos(delta_phi);  delta_y=delta_moy*sin(delta_phi);  x=delta_x+x;  y=delta_y+y;  phi=int(delta_phi+phi) % int(2*pi) ;*/int tmp=g;  Serial.print("g="   );  Serial.println(tmp);//  Serial.print("et d =");//  Serial.println(d);  delay(200); // Serial.print("et phi ="); // Serial.println(phi);  /* il faut mieux mesurer L (distance entre les 2 rue )    demande au prof la conversion en int pour le modulo     trouver la coefficient de réduction j'ai mis à un     


*/}

Annexes

Pages en relation avec le positionnement