Radar à ultrasons Motivation : élément d'un mobile capable de déterminer les obstacles sur sa route. 1 Matériel : Autonome : il peut éviter les obstacles, trouver un passage etc. Télécommandé : il peut rendre compte de l'environnement. Module SFR05 : sonar, alimenté en 5V, fournit une impulsion dont la durée est proportionnelle à la distance de l'objet détecté. Documentation : DOCS\Telemetre_SFR05.odt Servomoteur de télécommande : Principe en fin de texte. Modèle standard, se trouve dans toutes les bonnes épiceries. Liaison par 3 fils : Gnd, +5V, commande. Ne pas utiliser l'alimentation par USB à cause des pointes de courant lors du démarrage du moteur. 2 Ci-contre le montage réalisé : 3 Analyse pour la mise en oeuvre : La détection s'effectue dans un faisceau de 55 d'ouverture la récision de position sera donc faible. On choisit un balayage de -45 à +45 par rapport à la direction frontale qui couvre en fait -(45+27) à +(45+27). L'espace sera découpé en 7 angles de mesure. 4 Organisation du système : (Sonar + Servo) <-> Arduino PC (affichage) L'Arduino commande le Servo, dialogue avec le Sonar et transmet les valeurs de distance par paquets de 7 valeurs, transmises sous forme de texte, séparées par «;». Le PC place les 7 points de mesure dans un système de coordonnées polaires : 25/10/12 1 / 5
5 Programme dans l'arduino : DOCS\reperage.pde /* Mesure de distance / direction transmission au PC */ uint8_t trig = 3; uint8_t echo = 2; uint8_t servo = 4; #include <Servo.h> Servo mservo; uint32_t date; int8_t position; boolean sens; uint8_t distances[7]; uint8_t angles[]=45,60,75,90,105,120,135; void setup() pinmode(trig,output); mservo.attach(servo); date=millis(); position=0; sens = true; Serial.begin(9600); Serial.println("debut des mesures"); void affiche() for (uint8_t x=0;x<7;x++) Serial.print(distances[x],DEC); if (x!=6) Serial.print(';'); Serial.println(); void loop() uint32_t longueur; mservo.write(angles[position]); if ((millis() - date) >= 142) date = millis(); //mservo.write(angles[position]); digitalwrite (trig,high); delay(1); digitalwrite (trig,low); longueur = (pulsein(echo,high))/58; if (longueur > 255) longueur = 255; distances[position] = (uint8_t) longueur; if (sens) position ++; if (position == 7) affiche(); position = 5; sens=false; else position --; 25/10/12 2 / 5
if (position == -1) affiche(); position = 1; sens=true; Explications sur ce programme : Programme principal: Si il s'est écoulé plus de 1/7 de seconde, alors: Positionner le servo Mesurer la distance (et la mémoriser) Si c'est la 7eme Mesure: transmetre les valeurs à: programme de guidage, monitoring sur PC etc. Remarques: Le servo met «un certain temps» pour changer de position il ne faudra mesurer que lorsqu'il sera en position. La mesure devra se faire dans les deux sens de rotation pour gagner du temps. Le programme ne devra pas rester «bloqué» sur des attentes ( pas de delay() ) Variables globales: Tableau contenant les distances ( 7 valeurs) Pointeur dans ce tableau pour sélectionner une case pouvant stocker une valeur de mesure. Sens de balayage: le tableau ne sera pas rempli dans le «même sens» Date de la dernière mesure Constantes Valeur du temps entre deux mesures: 142ms Vitesse de la liaison série (vers le PC) Broches utilisées Tableau des différentes directions de mesure Fonctions utilisées du langage: Millis() retournant uint16_t ou long variable associée «date» librairie servo.h fournissant une classe d'objets «servo» avec les méthodes:.write(position) position étant donné en degrés ;attach(pin) pin étant la broche fournissant des données au servo. pulsein(pin, front) mesure la durée en millisecondes avant l'apparition d'un front (montant ou descendant).la durée retournée est uint16_t ou long Quelques précisions Conversion µs cm : division par 58 (vitesse du son 340m/s à 15 C) Envoi des valeurs de distance au PC en ASCII, séparateur «;», 7 valeurs par ligne. Durée (maximale) de l'envoi à 9600 bauds: 6x(3 caractères+ «;») + 3 caractères =CR +LF soit 29 caractères soit 290 bits => durée 30ms ce qui est acceptable pour un écart entre mesures de 142ms. Cependant si un autre traitement doit être ajoiuté au programme, il faudra augmenter la vitesse ou supprimer le «monitoring». 25/10/12 3 / 5
6 Programme dans le PC: /* Reception et affichage des données du Sonar Les données sont transmises par paquet de 7 valeurs. Les points correspondants sont placés sur un rayon correspondant à la distance de l'objet détecté. Fonctionne avec "reperage.pde" sur l'arduino */ import processing.serial.*; //Librairie série final int WIDTH = 1200; //Dimensions affichage final int HEIGHT = 600; final int xcenter = WIDTH / 2; final int ycenter = HEIGHT ; final int LINE_FEED = 10; //10:code terminant un paquet // rayons des arcs de cercle de la graduation en distance (cm) int[ ] radius_values = 300, 250, 200, 150, 100, 50 ; Serial arduinoport; int degree = 0; int [ ] radius = new int [10] ; // définit "arduinoport" du type "port série" PFont font; // font: variable du type "Fonte utilisée pour les caractères affichés" void setup() size(width, HEIGHT); // Crée l'affichage println(serial.list()); // tableau des ports com utilisés /* le Programme considère que le 1er port est celui de l'arduino, on est donc obligé de vérifier cela ou de déconnecter les autres USB Il faudra veiller à ce que le N de port ne soit pas trop élevé */ String arduinoportname = Serial.list()[0]; // Crée une instance de l'objet "port série" nommé arduinoport arduinoport = new Serial(this, arduinoportname, 9600); // Définit l'évènement qui lance la fonction "serialevent", ici c'est la réception de "line feed" arduinoport.bufferuntil(line_feed); font = loadfont("univers-bold-12.vlw"); // définit la fonte textfont(font); // utilise cette fonte pour les Textes affichés // Fonction appelée lorsqu'un paquet est reçu void serialevent(serial port) if (arduinoport.available() > 0) // vérification de la réception effective // Le paquet reçu est une suite de caractères (une "chaine"), deux valeurs sont séparées de ";" final String arduinooutput = arduinoport.readstringuntil(line_feed); // la chaine est découpée et chaque "texte" de valeur converti en "int" final int[] data = int(split(trim(arduinooutput), ';')); if (data.length == 7) // on vérifie que 7 valeurs ont été reçues for (int n=0;n<data.length;n++) // on limite la valeur à 300 radius[n] = min(300, data[n]); // DESSIN des graduations 25/10/12 4 / 5
void init_screen() background(255); // couleur du fond: blanc stroke(0); // couleur du tracé : noir strokeweight(1); // épaisseur du tracé // traçage des cercles de graduation for (int r = 0; r < radius_values.length; r++) final int current_radius = radius_values[r]*4; arc(xcenter, ycenter, current_radius, current_radius,pi, TWO_PI); // Programme principal void draw() init_screen(); fill(0); // couleur de "remplissage (des caractères): noir String s = "1 mètre"; // Ecriture de la valeur sur l'arc de cercle correspondant text(s,xcenter-20, ycenter - 2*radius_values[4]-5); fill(255); // couleur de "remplissage: blanc strokeweight(10); // épaisseur du tracé: épais // Tracé de "gros" points aux 7 directions à la distance mesurée for (int a = 0;a<7;a++) double phase = (315 - a*15)* Math.PI / 180; int x = (int)(radius[a] * Math.cos(phase))*2; int y = (int)(radius [a]* Math.sin(phase))*2; point(xcenter + x, ycenter + y); 7 Evolution: liaison Arduino-PC par Bluetooth Dans cette optique l'arduino utilisé est un «home made»: Atmega 328P Quartz 16MHz Régulater 5V Adaptateur USB-UART Adaptateur Bluetooth -UART Commutateur pour sélectionner le mode de communication. La liaison USB est utilisée pour programmer l'arduino et pour la mise au point. La liaison Bluetooth est utilisée pour transmettre les données au PC. Il faut noter que je n'ai pas pu faire cohabiter le driver Bluetooth et le logiciel Processing. Il aurait fallu se rabattre sur Labview ou un autre langage pour traiter les données reçues. 25/10/12 5 / 5