Traqueur de ligne

Le module traqueur de ligne TCL1543 est pourvu de 5 détecteurs optiques à infrarouges ITR20001 dont le principe de fonctionnement est le suivant :

Un émetteur émet un rayon IR en direction du sol. Un photo-transistor détecte la fraction de ce rayonnement réfléchi par le sol. Si le sol est réfléchissant ou clair, le récepteur recevra davantage de lumière que s’il est sombre.

Chaque détecteur fournit au microcontrôleur une valeur analogique.
Il suffit de comparer les valeurs des 5 détecteurs pour juger de la position de la ligne noire, et ainsi contrôler la trajectoire du robot.

 

Le TCL1543 communique avec le microcontrôleur par un protocole SPI (SPI sur Raspberry Pi)

 

Calibration

Selon l’éclairement ambiant et la réflexivité des surfaces constituant le sol et la ligne, les détecteurs vont renvoyer des valeurs extrêmes (surface « noire », surface »blanche ») différentes.

Il faut calibrer le capteur, afin d’optimiser le « contraste de l’image.

Pour cela, une procédure de calibration doit être faite :

  • on balaye toute la ligne avec le capteur
  • on enregistre les valeurs minimum et maximum obtenues par chaque détecteur IR
  • on utilise ses valeurs extrêmes pour déterminer si le détecteur voit du noir ou du blanc.

 

Utilisation avec Arduino

Bibliothèque

Pour utiliser plus simplement le détecteur de ligne, il faut installer la bibliothèque  TRSensors2.

 

Calibration

La calibration est nécessaire pour adapter le détecteur au contraste de la ligne à suivre (dépend des matériaux, de l’éclairement, …).

Elle peut se faire à l’aide de ce petit script :

#include "TRSensors2.h"

#define NUM_SENSORS 5

TRSensors trs = TRSensors();
unsigned int sensorValues[NUM_SENSORS];

void setup()
{
  Serial.begin(115200);
  Serial.println("TRSensor : calibration en cours ...");
  for (int i = 0; i < 400; i++)  // la procedure dure environ 10 secondes
  {
    trs.calibrate();       // calibration ... 
  }
  Serial.println("Calibration terminee");
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(trs.calibratedMin[i]);
    Serial.print('\t');
  }
  Serial.println();
  
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(trs.calibratedMax[i]);
    Serial.print('\t');
  }
  Serial.println();
}

void loop()
{
  delay(250);
}

  • Téléverser le programme et ouvrir le moniteur série .
  • Lorsque le premier message apparait, balayer lentement le capteur au dessus de la ligne à détecter.
  • Noter soigneusement les valeurs qui s’affichent.

par exemple :

213 229 231 210 170
358 373 389 358 298

Dans la fonction setup() des futurs programmes utilisant le capteur, il faudra ajouter quelques lignes pour adapter le capteur à la ligne à détecter.

par exemple :

unsigned int minSensorValues[NUM_SENSORS] = {213, 229, 231, 210, 170};
unsigned int maxSensorValues[NUM_SENSORS] = {358, 373, 389, 358, 298};
trs.SetCalibrates(minSensorValues, maxSensorValues);

Il faut effectuer la procédure de calibration une seule fois pour une ligne donnée.

 

Détection d’une ligne

#include "TRSensors2.h"

#define NUM_SENSORS 5
// sensors 0 through 5 are connected to analog inputs 0 through 5, respectively
TRSensors trs = TRSensors();
unsigned int sensorValues[NUM_SENSORS];


void setup()
{
  Serial.begin(115200);
  Serial.println("TRSensor");
  
  // Donnees de calibrations
  unsigned int minSensorValues[NUM_SENSORS] = {213, 229, 231, 210, 170};
  unsigned int maxSensorValues[NUM_SENSORS] = {358, 373, 389, 358, 298};
  trs.SetCalibrates(minSensorValues, maxSensorValues);
}

void loop()
{
  // Lecture de la position de la ligne (nombre entre 0 et 4000)
  unsigned int position = trs.readLine(sensorValues);
  
  Serial.println(position);
 
  delay(250);
}

La position de la ligne est donnée par la méthode .readLine() qui renvoie un nombre entre 0 et 4000 :

Position de la ligne
par rapport au capteur
gauche centre droite
Nombre renvoyé par
.readLine()
0 2000 4000

 

Autres méthodes

Lecture des valeurs « brutes » renvoyées par le capteur.

trs.AnalogRead(sensorValues);

Lecture des valeurs « calibrées » renvoyées par le capteur
trs.readCalibrated(sensorValues);

 

Utilisation avec Raspberry Pi

Bibliothèque

On peut utiliser une bibliothèque « maison » : TRsensor.py

Téléchargement : TRsensor

TRsensor.py
import RPi.GPIO as GPIO
import time

CS = 5
Clock = 25
Address = 24
DataOut = 23

class TRSensor(object):
    def __init__(self,numSensors = 5):
        self.numSensors = numSensors
        self.calibratedMin = [0] * self.numSensors
        self.calibratedMax = [1023] * self.numSensors
        self.last_value = 0
        
    """
    Reads the sensor values into an array. There *MUST* be space
    for as many values as there were sensors specified in the constructor.
    Example usage:
    unsigned int sensor_values[8];
    sensors.read(sensor_values);
    The values returned are a measure of the reflectance in abstract units,
    with higher values corresponding to lower reflectance (e.g. a black
    surface or a void).
    """
    def AnalogRead(self):
        value = [0,0,0,0,0,0]
        #Read Channel0~channel4 AD value
        for j in range(0,6):
            GPIO.output(CS, GPIO.LOW)
            for i in range(0,4):
                #sent 4-bit Address
                if(((j) >> (3 - i)) & 0x01):
                    GPIO.output(Address,GPIO.HIGH)
                else:
                    GPIO.output(Address,GPIO.LOW)
                #read MSB 4-bit data
                value[j] <<= 1
                if(GPIO.input(DataOut)):
                    value[j] |= 0x01
                GPIO.output(Clock,GPIO.HIGH)
                GPIO.output(Clock,GPIO.LOW)
            for i in range(0,6):
                #read LSB 8-bit data
                value[j] <<= 1
                if(GPIO.input(DataOut)):
                    value[j] |= 0x01
                GPIO.output(Clock,GPIO.HIGH)
                GPIO.output(Clock,GPIO.LOW)
            #no mean ,just delay
            for i in range(0,6):
                GPIO.output(Clock,GPIO.HIGH)
                GPIO.output(Clock,GPIO.LOW)
#			time.sleep(0.0001)
            GPIO.output(CS,GPIO.HIGH)
        return value[1:]
        
    """
    Reads the sensors 10 times and uses the results for
    calibration.  The sensor values are not returned; instead, the
    maximum and minimum values found over time are stored internally
    and used for the readCalibrated() method.
    """
    def calibrate(self):
        max_sensor_values = [0]*self.numSensors
        min_sensor_values = [0]*self.numSensors
        for j in range(0,10):
        
            sensor_values = self.AnalogRead();
            
            for i in range(0,self.numSensors):
            
                # set the max we found THIS time
                if((j == 0) or max_sensor_values[i] < sensor_values[i]):
                    max_sensor_values[i] = sensor_values[i]

                # set the min we found THIS time
                if((j == 0) or min_sensor_values[i] > sensor_values[i]):
                    min_sensor_values[i] = sensor_values[i]

        # record the min and max calibration values
        for i in range(0,self.numSensors):
            if(min_sensor_values[i] > self.calibratedMin[i]):
                self.calibratedMin[i] = min_sensor_values[i]
            if(max_sensor_values[i] < self.calibratedMax[i]):
                self.calibratedMax[i] = max_sensor_values[i]

    """
    Returns values calibrated to a value between 0 and 1000, where
    0 corresponds to the minimum value read by calibrate() and 1000
    corresponds to the maximum value.  Calibration values are
    stored separately for each sensor, so that differences in the
    sensors are accounted for automatically.
    """
    def	readCalibrated(self):
        value = 0
        #read the needed values
        sensor_values = self.AnalogRead();

        for i in range (0,self.numSensors):

            denominator = self.calibratedMax[i] - self.calibratedMin[i]

            if(denominator != 0):
                value = (sensor_values[i] - self.calibratedMin[i])* 1000 / denominator
                
            if(value < 0):
                value = 0
            elif(value > 1000):
                value = 1000
                
            sensor_values[i] = value
        
        print("readCalibrated",sensor_values)
        return sensor_values
            
    """
    Operates the same as read calibrated, but also returns an
    estimated position of the robot with respect to a line. The
    estimate is made using a weighted average of the sensor indices
    multiplied by 1000, so that a return value of 0 indicates that
    the line is directly below sensor 0, a return value of 1000
    indicates that the line is directly below sensor 1, 2000
    indicates that it's below sensor 2000, etc.  Intermediate
    values indicate that the line is between two sensors.  The
    formula is:

       0*value0 + 1000*value1 + 2000*value2 + ...
       --------------------------------------------
             value0  +  value1  +  value2 + ...

    By default, this function assumes a dark line (high values)
    surrounded by white (low values).  If your line is light on
    black, set the optional second argument white_line to true.  In
    this case, each sensor value will be replaced by (1000-value)
    before the averaging.
    """
    def readLine(self, white_line = 0):

        sensor_values = self.readCalibrated()
        avg = 0
        sum = 0
        on_line = 0
        for i in range(0,self.numSensors):
            value = sensor_values[i]
            if(white_line):
                value = 1000-value
            # keep track of whether we see the line at all
            if(value > 200):
                on_line = 1
                
            # only average in values that are above a noise threshold
            if(value > 50):
                avg += value * (i * 1000);  # this is for the weighted total,
                sum += value;                  #this is for the denominator 

        if(on_line != 1):
            # If it last read to the left of center, return 0.
            if(self.last_value < (self.numSensors - 1)*1000/2):
                #print("left")
                return 0;
    
            # If it last read to the right of center, return the max.
            else:
                #print("right")
                return (self.numSensors - 1)*1000

        self.last_value = avg/sum
        
        return self.last_value

 

Calibration

La procédure d’autocalibration nécessite de déplacer le capteur au dessus de la ligne à suivre.

On doit réaliser une calibration à chaque fois que l’on change l’éclairement ambiant, ou la nature de la ligne à suivre.

 

La classe TRSensor dispose d’une méthode d’autocalibration autoCalibration()

Une fois les valeurs obtenues, on peut les conserver et les fournir lors des constructions futures de l’objet TRSensor :

TR  = TRSensor(cMin = [421, 448, 451, 490, 348], cMax = [92, 106, 109, 125, 152])

 

 

 

 

Vous aimerez aussi...

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.