Pololu-Senseur-QTR-Utiliser

De MCHobby - Wiki
Sauter à la navigation Sauter à la recherche

Référence des commandes QTRSensor

Page-under-construction.pngPage(s) en cours de traduction/élaboration.

Page(s) under translation/construction

Pour les senseurs analogiques QTR-xA, vous aurez besoin d'instancier un objet QTRSensorsAnalog et pour les senseurs digitaux QTR-xRC vous aurez besoin d'instancier un objet QTRSensorsRC. A part les constructeurs, ces deux objets fournissent les mêmes méthodes pour lire les valeurs du senseur (les deux classes dérivent la même classe abstraite de base). Le bibliothèque offre un accès aux valeurs brutes du senseur ainsi que des fonctions de haut niveau incluant la calibration et suivit de ligne.

Cette section de la bibliothèque définit un objet pour chacun des deux types de senseur QTR avec la classe QTRSensorsAnalog destinée aux senseurs QTR-xA et une classe QTRSensorsRC destinée au senseurs QTR-xRC. En interne, la bibliothèque prend en charge les différences entre les QTR-xA et QTR-xRC offrant ainsi une interface commune pour les deux senseurs. La seule différence visible depuis l'extérieur, c'est le constructeur. Cela est possible car les deux classes dérive d'une classe commune QTRSensors, celle-ci offre une interface abstraite qui doit être implémentée dans les classe dérivées. La classe abstraite QTRSensors ne doit pas être instanciée.

Les classes QTRSensorsAnalog et QTRSensorsRC doivent être instanciées avant d'être utilisée. Cela permet à plusieurs senseurs de ligne QTR dêtre contrôlé indépendamment les uns des autres.

Pour la calibration, la mémoire est allouée en utilisant la fonction malloc(). Cela préserve la RAM: si les 8 senseurs sont calibrées avec l'émetteur activé et désactivé, un total de 64 octets (sur les 2048 disponibles) sont dédiés au stockage de la calibration. Cependant, pour une application utilisant uniquement 3 senseurs avec des émetteurs toujours actifs durant la lecteur alors seuls 6 octets seront nécessaires.

En interne, la bibliothèque utilise toutes des fonctions standards comme micros() pour la gestion du temps et analogRead() ou digitalRead() pour obtenir les valeurs du senseur. De sorte, cette bibliothèque devrait fonctionner avec tous les Arduino sans conflit avec d'autres bibliothèques.

Les fonctions

read()

void read(unsigned int *sensorValues, unsigned char readMode = QTR_EMITTERS_ON)

Lit les valeurs brutes des senseurs dans un tableau (array). Le tableau DOIT avoir la taille correspondant aux valeurs des senseurs spécifiés dans le constructeur. Les valeurs retournées sont une mesure de la réflectance (facteur de réflexion) en unités qui dépend du type de senseur utilisé. Une valeur plus élevée indique une réflectance inférieure (une surface noire ou le vide). Les senseurs QTR-xA retournera une valeur brute entre 0 et 1023. Les senseurs QTR-xRC retournera une valeur entre 0 et un argument timeout (exprimé en microsecondes, indiqué dans le constructeur avec 2000 par défaut).

Toutes les fonction qui lisent des valeurs prennent un argument readMode en paramètre. Celui-ci spécifie le type de lecture qui est effectué. Plusieurs options sont possibles:

  • QTR_EMITTERS_OFF indique que la lecture doit être effectuée sans allumer les LEDs infrarouge (IR), ce qui permet d'évaluer le niveau de lumière ambiante près du senseur;
  • QTR_EMITTERS_ON indique que les diodes émettrices doivent être activées durant la lecture, ce qui permet de lire la réflectance;
  • QTR_EMITTERS_ON_AND_OFF indique que la lecture doit être réaliser avec les deux états (allumé et éteint). La résultat retourné par l'option QTR_EMITTERS_ON_AND_OFF correspond à allumé + max – éteint, où "allumé" correspond à une lecture avec les LEDs IR allumée, "éteint" correspond à la lecture avec les LED IR éteinte et "max" la valeur maximale lue par le senseur.
    Cette option permet de réduire la quantité d'interférence provenant des variations de lumière ambiante.

Exemple d'utilisation:

unsigned int sensor_values[8];
sensors.read(sensor_values);

emittersOn()

void emittersOn()

Allume les LEDs IR (InfraRouge). Principalement utilisée par la méthode read() et appeler cette fonction avant ou après la lecture du senseur n'a aucun effet sur la lecture. Vous devriez utiliser cette fonction uniquement pour effectuer des tests.

Cette fonction en fait quelque-chose que si la broche émetteur IR (emitter) à été spécifiée dans le constructeur (donc une valeur différente de QTR_NO_EMITTER_PIN).

emittersOff()

void emittersOff()

Désactive les LEDs Infrarouges. Comme pour emitterOn(), cette fonction est utilisée par read() et appeler cette fonction avant ou après une lecture de senseur n'a aucun effet sur les lectures (mais peut être utilisée pour effectuer des tests).

calibrate()

void calibrate(unsigned char readMode = QTR_EMITTERS_ON)

Effectue une lecture des senseurs pour calibration. Les valeurs du senseur ne sont pas retournée; à la place, les valeurs maximales et minimales sont stockées en interne et utilisé par la méthode readCalibrated() (lecture calibrée). Vous pouvez accéder aux valeurs de calibration (ex: les lectures min et max du senseur) via les pointeurs des membres publiques calibratedMinimumOn, calibratedMaximumOn, calibratedMinimumOff et calibratedMaximumOff. Notez que ces pointeurs pointent vers des tableaux ayant une longueur numSensors tel que spécifié dans le constructeur. Ces tableaux ne seront alloués qu'après l'appel de calibrate(). Si la la calibration est uniquement réalisée avec les LED IR allumées alors les tableaux de calibration destinés aux valeurs off (éteinte) ne seront pas alloués.

readCalibrated()

void readCalibrated(unsigned int *sensorValues, unsigned char readMode = QTR_EMITTERS_ON)

Retourne la lecture des senseurs calibrés avec une valeur entre 0 et 1000, où 0 corresponds à une lecture inférieure ou égale à la valeur minimale obtenue par calibrate() et 1000 correspond à une lecture supérieure ou égale à la valeur maximale. Les valeurs de calibration sont stockées séparément pour chacun des senseurs infrarouges, par conséquent, la différence entre les senseurs est automatiquement prise en compte.

readLine()

unsigned int readLine(unsigned int *sensorValues, unsigned char readMode = QTR_EMITTERS_ON, unsigned char whiteLine = 0)

Fonctionne de la même façon que readCalibrated mais cette fonction est conçue pour le suivit de ligne:

  • Cette fonction retourne une estimation de la position de la ligne.
  • L'estimation est faite en utilisant la moyenne pondérée des senseurs par indice, indice du senseur multiplié par 1000. De sorte, une valeur 0 indique que la ligne est sous le senseur 0 (ou qu'il a été sous le senseur 0 juste avant d'être perdu), une valeur de 1000 indique que le senseur est sous le senseur 1, 2000 indique sous le senseur 2, etc.

Une valeur intermédiaire indique indique que la ligne est entre deux senseurs. La formule est:

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

Aussi longtemps que les senseurs ne sont pas trop espacés par rapport à la ligne alors cette fonction est conçue pour retourner une valeur monotone. Une fonction monotone reste toujours croissante ou décroissante (son sens de variation est constant, voir l'article Fonction monotone sur wikipedia.fr).

Une valeur monotone est une entrée idéale pour réaliser un asservissement PID en boucle fermée.

De surcroît, cette méthode se souvient où elle a vu la ligne la dernière fois, de sorte que si la ligne est perdue sur la gauche ou la droite, la position de la ligne sera indiquée du bon côté afin de diriger le robot dans la bonne direction pour rattraper la ligne.

Par exemple, si le senseur 4 est le senseur le plus à droite et que vous quittez la ligne par la gauche (dont la ligne est quelque par plus loin sur la droite), la valeur lue augmente progressivement jusque 4000 puis continuera à retourner 4000 lorsque le robot aura quitté la ligne.

Par défaut, cette fonction par du principe que la ligne est noir (valeur élevée) entourée de blanc (valeur faible). Si vous désirez utiliser des lignes blanches sur fonds noir alors vous pouvez placer le second argument whiteLine à true. Dans ce cas, chaque senseur sera remplacé par la valeur maximale du senseur moins sa valeur actuelle (avant le calcul de moyenne).

calibratedMinimumOn

unsigned int* calibratedMinimumOn

Les valeurs minimales de calibration pour chaque senseur (avec diode IR allumée). Les pointeurs ne sont pas alloués (et placés à 0) jusqu'à ce la méthode calibrate() soit appelée. Ensuite le pointeur pointera vers un tableau qui aura exactement la taille du nombre de senseur. En fonction du readMode utiliser avec calibrate() seules les valeurs On ou Off seront allouées (en fonction des besoins).

Cette variable et les suivantes sont rendues publiques pour que vous puissiez réaliser vos propres calculs et réaliser des t^aches comme sauvegarde en EEPROM, réaliser un contrôle sur les valeurs, etc

calibratedMaximumOn

unsigned int* calibratedMaximumOn

Les valeurs maximales de calibration mesurée pour chaque senseur (avec les diode IR allumées).

calibratedMinimumOff

unsigned int* calibratedMinimumOff

Les valeurs minimales de calibration pour chaque senseur, avec les diodes émettrices eteintes.

calibratedMaximumOff

unsigned int* calibratedMaximumOff

The calibrated maximum values measured for each sensor, with emitters off.

~QTRSensors() - descructeur

Destructor: ~QTRSensors()

The destructor for the QTRSensors class frees up memory allocated for the calibration arrays.

QTRSensorsRC() - constructeur

Constructor: QTRSensorsRC()

This version of the constructor performs no initialization. If it is used, the user must call init() before using the methods in this class.

Constructor: QTRSensorsRC(unsigned char* digitalPins, unsigned char numSensors, unsigned int timeout = 2000, unsigned char emitterPin = QTR_NO_EMITTER_PIN);

This constructor just calls init(), below.

void QTRSensorsRC::init(unsigned char* digitalPins, unsigned char numSensors, unsigned int timeout = 2000, unsigned char emitterPin = QTR_NO_EMITTER_PIN)

Initializes a QTR-RC (digital) sensor array.

  • The array digitalPins should contain the Arduino digital pin numbers for each sensor.
  • numSensors specifies the length of the digitalPins array (the number of QTR-RC sensors you are using). numSensors must be no greater than 16.
  • timeout specifies the length of time in microseconds beyond which you consider the sensor reading completely black. That is to say, if the pulse length for a pin exceeds timeout, pulse timing will stop and the reading for that pin will be considered full black. It is recommended that you set timeout to be between 1000 and 3000 µs, depending on factors like the height of your sensors and ambient lighting. This allows you to shorten the duration of a sensor-reading cycle while maintaining useful measurements of reflectance.
  • emitterPin is the Arduino digital pin that controls whether the IR LEDs are on or off. This pin is optional and only exists on the 8A and 8RC QTR sensor arrays. If a valid pin is specified, the emitters will only be turned on during a reading. If the value QTR_NO_EMITTER_PIN (255) is used, you can leave the emitter pin disconnected and the IR emitters will always be on.

QTRSensorsAnalog() - constructeur

Constructor: QTRSensorsAnalog()

This version of the constructor performs no initialization. If this constructor is used, the user must call init() before using the methods in this class.

Constructor: QTRSensorsAnalog(unsigned char* analogPins, unsigned char numSensors, unsigned char numSamplesPerSensor = 4, unsigned char emitterPin = QTR_NO_EMITTER_PIN)

This constructor just calls init(), below.

void init(unsigned char* analogPins, unsigned char numSensors, unsigned char numSamplesPerSensor = 4, unsigned char emitterPin = QTR_NO_EMITTER_PIN)

Initializes a QTR-A (analog) sensor array.

  • The array pins should contain the Arduino analog input pin number for each sensor. For example, if pins is {0, 1, 7}, sensor 1 is on analog input 0, sensor 2 is on analog input 1, and sensor 3 is on analog input 7.
  • numSensors specifies the length of the analogPins array (the number of QTR-A sensors you are using). numSensors must be no greater than 16.
  • numSamplesPerSensor indicates the number of 10-bit analog samples to average per channel (per sensor) for each reading. The total number of analog-to-digital conversions performed will be equal to numSensors times numSamplesPerSensor. Increasing this parameter increases noise suppression at the cost of sample rate. This parameter must not exceed 64. Recommended value: 4.
  • emitterPin is the Arduino digital pin that controls whether the IR LEDs are on or off. This pin is optional and only exists on the 8A and 8RC QTR sensor arrays. If a valid pin is specified, the emitters will only be turned on during a reading. If the value QTR_NO_EMITTER_PIN (255) is used, you can leave the emitter pin disconnected and the IR emitters will always be on.

Note d'usage

Calibration

This library allows you to use the calibrate() method to easily calibrate your sensors for the particular conditions it will encounter. Calibrating your sensors can lead to substantially more reliable sensor readings, which in turn can help simplify your code since. As such, we recommend you build a calibration phase into your application’s initialization routine. This can be as simple as a fixed duration over which you repeated call the calibrate() method. During this calibration phase, you will need to expose each of your reflectance sensors to the lightest and darkest readings they will encounter. For example, if you have made a line follower, you will want to slide it across the line during the calibration phase so the each sensor can get a reading of how dark the line is and how light the ground is. A sample calibration routine would be:

#include <QTRSensors.h>
 
// create an object for your type of sensor (RC or Analog)
// in this example we have three sensors on analog inputs 0 - 2, a.k.a. digital pins 14 - 16
QTRSensorsRC qtr((char[]) {14, 15, 16}, 3);
// QTRSensorsA qtr((char[]) {0, 1, 2}, 3);
 
void setup()
{
  // optional: wait for some input from the user, such as  a button press
 
  // then start calibration phase and move the sensors over both
  // reflectance extremes they will encounter in your application:
  int i;
  for (i = 0; i < 250; i++)  // make the calibration take about 5 seconds
  {
    qtr.calibrate();
    delay(20);
  }
 
  // optional: signal that the calibration phase is now over and wait for further
  // input from the user, such as a button press
}

Lire les senseurs

This library gives you a number of different ways to read the sensors.

  1. You can request raw sensor values using the read() method, which takes an optional argument that lets you perform the read with the IR emitters turned off (note that turning the emitters off is only supported by the QTR-8x reflectance sensor arrays).
  2. You can request calibrated sensor values using the readCalibrated() method, which also takes an optional argument that lets you perform the read with the IR emitters turned off. Calibrated sensor values will always range from 0 to 1000, with 0 being as or more reflective (i.e. whiter) than the most reflective surface encountered during calibration, and 1000 being as or less reflective (i.e. blacker) than the least reflective surface encountered during calibration.
  3. For line-detection applications, you can request the line location using the readLine() method, which takes as optional parameters a boolean that indicates whether the line is white on a black background or black on a white background, and a boolean that indicates whether the IR emitters should be on or off during the measurement. readLine() provides calibrated values for each sensor and returns an integer that tells you where it thinks the line is. If you are using N sensors, a returned value of 0 means it thinks the line is on or to the outside of sensor 0, and a returned value of 1000 * (N-1) means it thinks the line is on or to the outside of sensor N-1. As you slide your sensors across the line, the line position will change monotonically from 0 to 1000 * (N-1), or vice versa. This line-position value can be used for closed-loop PID control.

A sample routine to obtain the sensor values and perform rudimentary line following would be:

void loop()
{
  unsigned int sensors[3];
  // get calibrated sensor values returned in the sensors array, along with the line position
  // position will range from 0 to 2000, with 1000 corresponding to the line over the middle 
  // sensor.
  int position = qtr.readLine(sensors);
 
  // if all three sensors see very low reflectance, take some appropriate action for this 
  // situation.
  if (sensors[0] > 750 && sensors[1] > 750 && sensors[2] > 750)
  {
    // do something.  Maybe this means we're at the edge of a course or about to fall off 
    // a table, in which case, we might want to stop moving, back up, and turn around.
    return;
  }
 
  // compute our "error" from the line position.  We will make it so that the error is zero 
  // when the middle sensor is over the line, because this is our goal.  Error will range from
  // -1000 to +1000.  If we have sensor 0 on the left and sensor 2 on the right,  a reading of 
  // -1000 means that we see the line on the left and a reading of +1000 means we see the 
  // line on the right.
  int error = position - 1000;
 
  int leftMotorSpeed = 100;
  int rightMotorSpeed = 100;
  if (error < -500)  // the line is on the left
    leftMotorSpeed = 0;  // turn left
  if (error > 500)  // the line is on the right
    rightMotorSpeed = 0;  // turn right
 
  // set motor speeds using the two motor speed variables above
}

Contrôle PID

The integer value returned by readLine() can be easily converted into a measure of your position error for line-following applications, as was demonstrated in the previous code sample. The function used to generate this position/error value is designed to be monotonic, which means the value will almost always change in the same direction as you sweep your sensors across the line. This makes it a great quantity to use for PID control.

Explaining the nature of PID control is beyond the scope of this document, but wikipedia has a very good article (anglais) on the subject.

The following code gives a very simple example of PD control (I find the integral PID term is usually not necessary when it comes to line following). The specific nature of the constants will be determined by your particular application, but you should note that the derivative constant Kd is usually much bigger than the proportional constant Kp. This is because the derivative of the error is a much smaller quantity than the error itself, so in order to produce a meaningful correction it needs to be multiplied by a much larger constant.

int lastError = 0;
 
void loop()
{
  unsigned int sensors[3];
  // get calibrated sensor values returned in the sensors array, along with the line position
  // position will range from 0 to 2000, with 1000 corresponding to the line over the middle 
  // sensor
  int position = qtr.readLine(sensors);
 
  // compute our "error" from the line position.  We will make it so that the error is zero when
  // the middle sensor is over the line, because this is our goal.  Error will range from
  // -1000 to +1000.  If we have sensor 0 on the left and sensor 2 on the right,  a reading of 
  // -1000 means that we see the line on the left and a reading of +1000 means we see the 
  // line on the right.
  int error = position - 1000;
 
  // set the motor speed based on proportional and derivative PID terms
  // KP is the a floating-point proportional constant (maybe start with a value around 0.1)
  // KD is the floating-point derivative constant (maybe start with a value around 5)
  // note that when doing PID, it's very important you get your signs right, or else the
  // control loop will be unstable
  int motorSpeed = KP * error + KD * (error - lastError);
  lastError = error;
 
  // M1 and M2 are base motor speeds.  That is to say, they are the speeds the motors should
  // spin at if you are perfectly on the line with no error.  If your motors are well matched,
  // M1 and M2 will be equal.  When you start testing your PID loop, it might help to start with
  // small values for M1 and M2.  You can then increase the speed as you fine-tune your
  // PID constants KP and KD.
  int m1Speed = M1 + motorSpeed;
  int m2Speed = M2 - motorSpeed;
 
  // it might help to keep the speeds positive (this is optional)
  // note that you might want to add a similiar line to keep the speeds from exceeding
  // any maximum allowed value
  if (m1Speed < 0)
    m1Speed = 0;
  if (m2Speed < 0)
    m2Speed = 0;
 
  // set motor speeds using the two motor speed variables above
}

Basé sur "Arduino Library for the Pololu QTR Reflectance Sensors" de Pololu (www.pololu.com/docs/0J19/1) - Traduit en Français par shop.mchobby.be CC-BY-SA pour la traduction
Toute copie doit contenir ce crédit, lien vers cette page et la section "crédit de traduction". Traduit avec l'autorisation expresse de Pololu (www.pololu.com)

Based on "Arduino Library for the Pololu QTR Reflectance Sensors" from Pololu (www.pololu.com/docs/0J19/1) - Translated to French by shop.mchobby.be CC-BY-SA for the translation
Copies must includes this credit, link to this page and the section "crédit de traduction" (translation credit). Translated with the Pololu's authorization (www.pololu.com)