deutsch     english    français     Imprimer

 

5.4 TECHNOLOGIE DES CAPTEURS

 

 

INTRODUCTION

 

Un capteur est un composant permettant de mesurer une grandeur physique telle que la température, l’intensité lumineuse, la pression ou des distances. Dans la plupart des cas, la valeur délivrée par le capteur est un nombre compris dans la plage des valeurs mesurées. Il existe cependant également des capteurs qui ne connaissent que deux états à la manière d’interrupteurs. On compte parmi ces derniers les capteurs tactiles, les capteurs permettant de savoir si le niveau d’un récipient est plein, etc.

La grandeur physique mesurée est généralement convertie par le capteur en une tension électrique qui est ensuite évaluée par de l’électronique supplémentaire [plus...Pour que le signal puisse être traité par un ordinateur, il faut au préalable qu’il soit
converti en un signal digital à l’aide d’un convertisseur analogique-numérique (AN),
en anglais ADC (Analog to Digital Converter
].

La structure interne d’un capteur peut être très complexe comme c’est le cas pour les capteurs ultrasoniques, gyroscopiques ou ceux permettant de mesurer des distances au LASER. La courbe caractéristique d’un capteur décrit la relation entre la grandeur physique mesurée et les valeurs délivrées par le capteur. De nombreux capteurs ont une courbe caractéristique plus ou moins linéaire mais il est toujours nécessaire de déterminer le facteur de conversion (pente) et l’ordonnée à l’origine. Pour ce faire, on procède au calibrage du capteur grâce à une série de mesures de grandeurs connues.

Le capteur ultrasonique permet de déterminer la distance à un objet en mesurant le temps nécessaire à une courte impulsion ultrasonique de voyager jusqu’à l’objet et d’être réfléchie jusqu’au capteur. Pour des distances comprises entre 30 cm et 2m, le capteur délivre des valeurs comprises entre 0 et 255 où 255 (-1 en mode simulation) est retourné lorsqu’il n’y a pas d’objet détecté à portée du capteur. 

Capteur ultrasonique
Courbe caractéristique

Dans la plupart des applications, le programme interroge les valeurs lues par le capteur à intervalles réguliers. On appelle ceci « faire du polling ». Les valeurs d’un capteur sont donc lues et traitées en boucle. La résolution temporelle, qui correspond au nombre de mesures par seconde, dépend du capteur, de la rapidité de l’ordinateur et de la connexion à disposition pour relier la brique et le programme. Le capteur ultrasonique n’est par exemple capable de faire que deux mesures par seconde.

La valeur d’un capteur ne prenant que deux valeurs distinctes peut également être déterminée par polling. Il est cependant plus commode de concevoir les changements d’états comme des événements à traiter par programme à l’aide de fonctions de rappel déclenchées à chaque nouvelle lecture de valeur.

CONCEPTS DE PROGRAMMATION: Capteurs, calibration de capteurs, polling et événements, seuil  de déclenchement

 

 

POLLING VS ÉVÉNEMENTS

 

Dans de nombreuses situations, il est possible de décider si l’on préfère contrôler un capteur par polling ou par gestionnaire d’événements. Tout dépend de l‘utilisation que l’on veut en faire. On peut comparer les deux façons de procéder en connectant un moteur et un capteur tactile à la brique. Dans ce cas, une pression sur le bouton tactile devrait enclencher le moteur et une nouvelle pression devrait arrêter les moteurs.

Les événements sont bien plus malins pour cette application puisqu’ils informent de la pression sur le capteur tactile au travers d’un appel de fonction. Il suffit de passer cette fonction comme paramètre nommé lors de la création du capteur tactile avec TouchSensor(). Avec le polling, il est nécessaire d’utiliser un drapeau isOff (aussi appelé fanion, flag en anglais) dans le but de ne réagir que lors des transitions du capteur d’un état à l’autre. 
En utilisant le polling et un fanion :

from nxtrobot import *
#from ev3robot import *

def switchMotorState():
    if motor.isMoving():
        motor.stop()
    else:
        motor.forward()

robot = LegoRobot()
motor = Motor(MotorPort.A)
robot.addPart(motor)
ts = TouchSensor(SensorPort.S3)
robot.addPart(ts)

isOff = True
while not robot.isEscapeHit():
    if ts.isPressed() and isOff:
        isOff = False
        switchMotorState()
    if not ts.isPressed() and not isOff:
        isOff = True
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

En utilisant les événements :

#from nxtrobot import *
from ev3robot import *

def onPressed(port):
    if motor.isMoving():
        motor.stop()
    else:
        motor.forward()
        
robot = LegoRobot()

motor = Motor(MotorPort.A)
robot.addPart(motor)
ts = TouchSensor(SensorPort.S1, 
         pressed = onPressed)
robot.addPart(ts)
while not robot.isEscapeHit():
    pass
robot.exit()
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

MEMENTO

 

Les capteurs peuvent être gérés par polling ou par les événements. Il est indispensable de bien comprendre les deux techniques différentes et d’être en mesure de choisir de manière éclairée l’une ou l’autre selon la situation. Dans le modèle de la programmation événementielle, on définit des fonctions dont le nom commence conventionnellement par la chaine de caractères « on ». Ces dernières sont appelées fonctions de rappel puisqu’elles sont automatiquement appelées par le système en réponse aux événements survenus. Il faut enregistrer les fonctions de rappel en recourant à des paramètres nommés lors de la création de l’objet gérant le capteur.

 

 

INTERROGER UN CAPTEUR ULTRASONIQUE PAR POLLING

 

Note préliminaire : Si votre kit EV3 n’est pas livré avec un capteur ultrasonique, il est possible de réaliser cette section avec le capteur infrarouge.

Il est nécessaire d’interroger un capteur par polling si l’on a besoin d’un débit de mesures constant. Nous allons dans cette section permettre au robot de chercher un objet cible placé sur le sol quelque part dans la pièce, quelle que soit sa position de départ, pour le rejoindre.

Pour détecter une cible, on va recourir au capteur ultrasonique qui fonctionne exactement comme un système de radar. Pour apprendre à maîtriser un capteur, il n’y a rien de mieux que de développer un petit programme de test même si celui-ci n’est d’aucune utilité par la suite. Il est pratique et recommandé d’écrire les valeurs lues par le capteur dans la console Python et sur l’écran de la brique ainsi que de les traduire sous forme de son audible qui sera d’autant plus aigu que la distance sera grande. Ceci vous permettra de vous libérer les mains et les yeux tout en suivant en temps réel l’évolution des valeurs du capteur pendant les manipulations du robot à la main.

# from nxtrobot import *
from ev3robot import *

robot = LegoRobot()
us = UltrasonicSensor(SensorPort.S1)
robot.addPart(us)
isAutonomous = robot.isAutonomous()
while not robot.isEscapeHit():  
    dist = us.getDistance()
    print "d = ", dist
    robot.drawString("d=" + str(dist), 0, 3)
    robot.playTone(10 * dist + 100, 50)
    if dist == 255:
        robot.playTone(10 * dist + 100, 50)
    if isAutonomous:
       Tools.delay(1000)
    else:
       Tools.delay(200)
robot.exit()
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

Pour trouver et s’approcher d’une cible, on peut tourner le robot comme une antenne de radar et chercher constamment la cible à l’aide du capteur ultrasonique. Lorsque la cible est détectée, il faut noter la direction actuelle et continuer de tourner jusqu’à ce que l’écho ne soit plus détecté. Ceci permet de détecter la taille apparente de l’objet, à savoir l’angle sous lequel l’objet est « visible ». On oriente ensuite le robot au milieu du cône de détection pour le diriger vers la cible et s’arrêter lorsqu’il est à la distance désirée de l’objet.

En mode simulation, on peut visualiser la distance mesurée à l’aide de setBeamAreaColor() et setProximityCircleColor(). La cible affichée correspond au fichier image spécifié comme paramètre à la fonction RobotContext.useTarget().


Cependant, la détection de la cible par le capteur virtuel ne se fera pas à l’aide de l’image affichée mais à l’aide d’un maillage (mesh en anglais) de triangles. Chacun de ces triangles est formé d’un point central P et de deux arrêtes. La cible affichée ci-contre est formée des meshes suivants :
PP0P1, PP1P2, PP2P3, PP3P4, PP4P0.

Dans le programme, on peut indiquer les sommets des triangles en tant que paramètre de la méthode useTarget(). Les coordonnées se réfèrent alors à un système de coordonnées dont l’origine se trouve au centre de la fenêtre, l’axe Ox étant dirigé vers la droite et l’axe Oy vers le bas.

Les coordonnées pour un hexagone de diamètre 100 sont par exemple

[50, 0] , [25, 43], [-25, 43], [-50, 0], [-25, -43], [25, -43].

 

 

from simrobot import *
#from nxtrobot import *
#from ev3robot import *

mesh = [[50, 0], [25, 43], [-25, 43], [-50, 0], 
          [-25, -43], [25, -43]] 
RobotContext.useTarget("sprites/redtarget.gif", mesh, 400, 400)

def searchTarget():
    global left, right
    found = False
    step = 0
    while not robot.isEscapeHit():  
        gear.right(50)
        step = step + 1
        dist = us.getDistance()
        print "d = ", dist
        if dist != -1:  # simulation
        #if dist < 80:   # real
            if not found:
                found = True
                left = step
                print "Left at", left
                robot.playTone(880, 500)
        else:
            if found:    
                right = step
                print "Right at ", right
                robot.playTone(440, 5000)
                break

left = 0
right = 0
robot = LegoRobot()
gear = Gear()
robot.addPart(gear)
us = UltrasonicSensor(SensorPort.S1)
robot.addPart(us)
us.setBeamAreaColor(makeColor("green"))  
us.setProximityCircleColor(makeColor("lightgray"))
gear.setSpeed(5)

print "Searching..."
searchTarget()

gear.left((right - left) * 25)   # simulation
#gear.left((right - left) * 100)  # real

print "Moving forward..."
gear.forward()

while not robot.isEscapeHit() and gear.isMoving(): 
    dist = us.getDistance()
    print "d =", dist
    robot.playTone(10 * dist + 100, 100)
    if dist < 40:
        gear.stop()
print "All done"        
robot.exit()
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

MEMENTO

 

On peut généralement déterminer la valeur d’un capteur par des interrogations répétées à intervalles réguliers (polling) par l’entremise d’une méthode « getter » telle que getValue(), getDistance(), etc.

Lorsque l’on passe du mode simulation au mode réel, il est nécessaire d’ajuster certaines valeurs, en particulier les intervalles de temps. Il faut remarquer également que s’il ne détecte pas de cible, le capteur retourne -1 en mode simulation et 255 en mode réel.
En mode simulation, l’orientation du capteur ultrasonique par rapport au robot est déterminée par le port auquel il est connecté selon le tableau ci-dessous ::

Port capteur Orientation du capteur
S1 Vers l’avant
S2 Vers la gauche
S3 Vers l’arrière

 

 

ÉVÉNEMENTS ET SEUILS DE DÉCLENCHEMENT

 
Les capteurs fournissant des données continues peuvent également être contrôlés par le modèle de programmation événementielle si l’on définit un seuil de déclenchement de l’événement. Le seuil de déclenchement correspondant à une valeur de la grandeur physique mesurée dont le franchissement dans un sens donné déclenche l’événement.
 

Les capteurs possèdent un seuil de déclenchement par défaut mais celui-ci peut être modifié par un appel à setTriggerLevel().

Le programme suivant s’assure que le robot reste à l’intérieur d’une zone circulaire, pour éviter par exemple qu’il ne tombe d’une table. On utilise en l’occurrence le capteur photosensible de sorte qu’il ne réagisse qu’au contraste foncé / clair. Si la surface est foncée, le gestionnaire d’événements  onDark est déclenché.

Lorsque l’on utilise le NXT en mode réel, il est très important d’allumer la LED rouge du capteur avec activate(True).


 
from simrobot import *
#from nxtrobot import *
#from ev3robot import *

RobotContext.setStartPosition(250, 200)
RobotContext.setStartDirection(-90)
RobotContext.useBackground("sprites/circle.gif")
  
def onDark(port, level):
    gear.backward(1500)
    gear.left(545)
    gear.forward()

robot = LegoRobot()
gear = Gear()
robot.addPart(gear)
ls = LightSensor(SensorPort.S3, 
      dark = onDark)
robot.addPart(ls)
ls.setTriggerLevel(100)  # adapt value
gear.forward()
while not robot.isEscapeHit():
    pass
robot.exit()
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

MEMENTO

 

Le franchissement d’un seuil par les valeurs mesurées par le capteur peut être interprété comme un événement. On appelle cela le déclenchement (triggering).

Valeurs par défaut pour les seuils de déclenchement:

Capteur

Niveau de déclenchement par défaut

Capteur sonore 50
Capteur photosensible 500
Capteur ultrasonique
10

On peut résumer les avantages et les désavantages du modèle événementiel par rapport au polling de la manière suivante:

Avantages du modèle événementiel Désavantages du modèle événementiel
Style de programmation plus clair et simplifié de fait que le code définissant le comportement est séparé du reste du programme dans une fonction de rappel (gestionnaire d’événement).
Le programme principal est interrompu de manière non prédictible (programmation asynchrone), ce qui peut interférer avec le flux d’instructions du programme principal.
L’événement est toujours détecté, même lorsque le PC est lent.

Les fonctions de rappel (gestionnaires d’événements) peuvent engendrer des effets de bord indésirables, en particulier lorsqu’elles modifient des variables globales ou l’état du robot.

Le programme peut continuer normalement et n’a pas à se préoccuper de capteurs.

Les fonctions de rappel sont exécutées dans un fil d’exécution séparé (thread), ce qui peut engendrer des conflits dus à la nature parallèle de l’exécution.

Le déclenchement est un concept central de la  technique de mesure.
Une seule valeur de la grandeur mesurée peut être détectée, à savoir le seuil de déclenchement.
Le modèle événementiel correspond bien au modèle d’états d’exécution. L’événement change l’état du système.
Les fonctions de rappel ne devraient en principe pas contenir du code dont le temps d’exécution est très court pour éviter que les autres événements ne soient perdus.

 

 

EXERCICES

 

1.


Programmer le robot équipé du capteur sonore de telle manière qu’il démarre lorsqu’on frappe dans les mains pour la première fois. Lorsqu’on frappe des mains les fois suivantes, le robot doit changer de direction. Résoudre ce problème en mode simulation et en mode réel. En mode réel, il faut équiper le robot du capteur sonore. En mode simulation, il faut installer un microphone sur le PC et régler de manière appropriée le niveau d’enregistrement dans le panneau de configuration.

2.

Connecter un moteur et un capteur tactile à la brique et développer un programme qui enclenche le moteur lors d’une pression sur le capteur tactile et qui l’éteint lors d’une deuxième pression.

3.

Construire un robot équipé d’un capteur ultrasonique et d’un capteur tactile qui cherche trois objets fins (bougies, canettes, …), leur rentre dedans et les fait tomber.

En mode simulation, on peut interpréter la superposition avec une cible comme un événement tactile et utiliser squaretarget.gif (taille 60x60 pixels) pour représenter les objets à l’écran. On pourra utiliser le code suivant pour définir RobotContext. Essayez de bien comprendre les données dans la liste mesh.

 

 

mesh = [[-30, -30], [-30, 30], [30, -30], [30, 30]]
RobotContext.useTarget("sprites/squaretarget.gif", mesh, 350, 250)
RobotContext.useObstacle("sprites/squaretarget.gif", 350, 250) 
RobotContext.useTarget("sprites/squaretarget.gif", mesh, 100, 150)
RobotContext.useObstacle("sprites/squaretarget.gif", 100, 150) 
RobotContext.useTarget("sprites/squaretarget.gif" ,mesh, 200, 450)
RobotContext.useObstacle("sprites/squaretarget.gif", 200, 450) 
RobotContext.setStartPosition(40, 450)  


4*.

Un robot équipé d’un capteur ultrasonique est placé au hasard dans une zone rectangulaire. Sa mission est de se placer aussi vite que possible aussi proche que possible du centre de la zone. Cette tâche peut être réalisée aussi bien en mode simulation qu’en mode réel.

En mode simulation, on peut utiliser les images bar0.gif et bar1.gif pour délimiter la zone rectangulaire à l’écran.

 

 


 

MATÉRIEL SUPPLÉMENTAIRE: CAPTEURS ARDUINO

 

Au contraire de la brique EV3, la carte de développement Arduino possède un système d’entrées/sorties standard avec des ports d’entrées digitaux. Elle dispose également de ports analogiques permettant de connecter des capteurs délivrant une tension proportionnelle à la grandeur mesurée. Cela permet l’utilisation d’une grande variété de capteurs et d’actuateurs bon marchés et d’y connecter des circuits électroniques bricolés. En connectant la carte Arduino à la brique EV3 au-travers d’une liaison appropriée, il est possible d’accéder à tous ces composants depuis un programme EV3. La connexion peut facilement se faire par une liaison I2C étant donné que les deux dispositifs supportent le protocole I2C.
 

En l’occurrence, la brique EV3 joue le rôle du maître I2C et l’Arduino celui de l’esclave. Les logiciels supplémentaires requis pour permettre cette liaison sont inclus d’office dans la distribution de TigerJython. La brique EV3 peut être opérée en mode direct (contrôle à distance) ou en mode autonome. Pour d’avantage d’informations, consulter la page http://www.aplu.ch/ev3.