Pololu-Senseur-QTR-Utiliser
Référence des commandes QTRSensor
Les précédentes versions de la bibliothèque s'appelaient PololuQTRSensors mais il a été modifié en QTRSensors pour la différencier de la bibliothèque senseur QTR Arduino pour le Robot Orangutan et 3pi. A part ce changement de nom de bibliothèque (et de classe), la nouvelle bibliothèque QTRSensors est fonctionnellement identique aux précédentes versions. |
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.
A noter que le contrôle des LEDs émettrices ne fonctionnera que si vous avez spécifié une broche valide pour le contrôle des LEDs IR dans l'appel du constructeur. |
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
Les valeurs de calibrations maximales mesurées pour chaque senseur (avec les diodes IR éteintes).
~QTRSensors() - descructeur
Destructor: ~QTRSensors()
Destructeur de la classe QTRSensors qui libère la mémoire allouée par les tableaux de calibration.
QTRSensorsRC() - constructeur
Constructor: QTRSensorsRC()
Cette version du constructeur n'effectue aucune initialisation. Si ce constructeur est utiliser alors le code doit également appeler init() avant d'utiliser les méthodes de la classe.
Constructor: QTRSensorsRC(unsigned char* digitalPins, unsigned char numSensors, unsigned int timeout = 2000, unsigned char emitterPin = QTR_NO_EMITTER_PIN);
Cette version du constructeur appelle la méthode init() décrite ci-dessous.
void QTRSensorsRC::init(unsigned char* digitalPins, unsigned char numSensors, unsigned int timeout = 2000, unsigned char emitterPin = QTR_NO_EMITTER_PIN)
Initialise le tableau de senseur QTR-RC (digital).
- Le tableau digitalPins doit contenir les broches digitales Arduino correspondant à chaque senseur.
- numSensors spécifie la longueur du tableau digitalPins (le nombre de senseur QTR-RC que vous utilisez). numSensors ne doit pas excéder 16 positions.
- timeout spécifie le nombre de microsecondes au-delà desquels la lecture du senseur sera considérée comme complètement noir! Cela signifie, si la longueur de l'impulsion pour une broche excède le timeout, la mesure de l'impulsion cesse et la lecture pour cette broche considère que le résultat est complètement noir. Pololu recommande un timeout entre 1000 et 3000 µs (0.001 et 0.003 secondes) dépendant de facteurs comme la hauteur du senseur et la lumière ambiante. Cela permet d'écourter le cycle de lecture des senseurs tout en maintenant une mesure utile de la reflectande.
- emitterPin est la broche digitale Arduino qui contrôle l'allumage et l'extinction des LEDs Infrarouge. Cette broche est optionnelle, broche qui n'existe que sur les détecteurs de lignes QTR 8A et 8RC QTR. Si une broche valide est spécifié alors les LED InfraRouges ne sont allumée que durant les opérations de lecture. Si la valeur QTR_NO_EMITTER_PIN (255) est utilisé lors de l'appel alors vous pouvez laisser le broche emitter déconnectée sur votre senseur de ligne afin que les LED Infrarouge restent toujours allumées.
QTRSensorsAnalog() - constructeur
Constructor: QTRSensorsAnalog()
Cette version du constructeur -destiné au senseurs de type analogique- n'effectue aucune initialisation. Si ce constructeur est utilisé, l'utilisateur doit appeler la méthode init() avant l'utilisation des autres méthodes de cette classe.
Constructor: QTRSensorsAnalog(unsigned char* analogPins, unsigned char numSensors, unsigned char numSamplesPerSensor = 4, unsigned char emitterPin = QTR_NO_EMITTER_PIN)
Ce constructeur fait juste un appel à init(), tel que détaillé ci-dessous.
void init(unsigned char* analogPins, unsigned char numSensors, unsigned char numSamplesPerSensor = 4, unsigned char emitterPin = QTR_NO_EMITTER_PIN)
Initialise un ensemble de senseur QTR-A (analogique).
- pins est un tableau de broches qui contient les broches d'entrées analogiques utilisées pour chaque senseur. Par exemple, si les pins sont {0, 1, 7}, le premier senseur est l'entrée analogique 0, le deuxième senseur est l'entrée analogique 1 et le troisième senser est l'entrée analogique 7.
- numSensors indique la longueur du tableau analogPins (le nombre de senseurs QTR-A utilisés). La valeur de numSensors ne peut pas dépasser 16.
- numSamplesPerSensor indique le nombre d'échantillonnages 10-bit à réaliser par canal/senseur lors de chaque lecture (échantillons dont la bibliothèque fait une moyenne). Le nombre total de conversion analogique-vers-digital réalisés est également au numSensors * numSamplesPerSensor.
accroître ce paramètre améliore la suppression du bruit mais au coût d'un temps de capture plus important (accroissement du temps d'échantillonnage total). Ce paramètre ne peut pas excéder la valeur de 64. Pololu recommande la valeur 4. - emitterPin est la broche digitale Arduino qui permet de contrôler les LEDs infrarouges (allumées ou éteintes). Cette broches est optionnelle et elle n'existe que sur les modèles de QTR 8A et QTR 8RC des senseurs de ligne. Si une broche valide est spécifiée, alors les diodes infrarouge ne seront allumées que durant la lecture. Si la valeur QTR_NO_EMITTER_PIN (255) est utilisée pour ce paramètre alors vous pouvez laisser la broches des diode Infrarouge déconnectée et les LEDs seront constamment alimentées.
Note d'usage
Calibration
La bibliothèque propose la méthode calibrate() pour facilement calibrer les senseurs dans les conditions particulières qu'il va rencontrer. La calibration des senseurs peu permet de produire des lectures sensiblement plus fiable, ce qui aura pour effet de simplifier votre propre code par la suite. En conséquence, nous recommandons de réaliser une phase de calibration dans la routine d'initialisation de votre application.
Ce peu simplement être réaliser durant une période de temps fixe durant laquelle vous effectuer des appels récurrents à la méthode calibrate(). Durant cette phase de calibration, vous devrez exposer chaque senseur de réflectance aux lectures les plus claires et foncées auxquels il seront exposés. Par exemple, si vous réalisez un suiveur de ligne, vous aurez besoin de le faire glisser progressivement au dessus de la ligne durant la phase de calibration de sorte que chaque senseur puisse avoir l'occasion de faire une lecture sur la surface la plus réflective (la plus claire) et de la surface la moins réfléchissante (la plus sombre).
Un exemple de routine de calibration peut être:
#include <QTRSensors.h>
// créer un objet pour votre type de senseur (RC ou Analogique)
// Dans cet exemple, il s'agit de trois senseur sur les
// entrées analogiques 0 à 2 (donc les broches digitales de
// 14 à 16)
QTRSensorsRC qtr((char[]) {14, 15, 16}, 3);
// QTRSensorsA qtr((char[]) {0, 1, 2}, 3);
void setup()
{
// optionnel: attendre une action de l'utilisateur comme
// la pression d'un bouton.
// Puis démarrer la phase de calibration et déplacez le
// senseurs au dessus des deux surfaces avec les reflectances
// opposées (extrêmes) que votre application rencontrera:
int i;
for (i = 0; i < 250; i++) // Réaliser une pendant ~5 secondes
{
qtr.calibrate();
delay(20);
}
// optionnel: signaler que la phase de calibration est
// achevée et attendre une action de l'utilisateur
// (comme par exemple, la pression d'un bouton)
}
Lectures avec les senseurs
Cette bibliothèque offre différentes approches pour lire les senseurs:
- Vous pouvez obtenir les valeurs brutes des senseurs en utilisant la méthode read(), qui reçoit un argument optionnel qui vous permet d'effectuer une lecture avec les diodes émettrices éteintes (note: l'extinction des diodes émettrices est uniquement possible pour les senseurs QTR-8x).
- Vous pouvez obtenir les valeurs calibrées en utilisant la méthode readCalibrated(), qui dispose également d'un argument optionnel vous permetant de faire une lecture avec les LED IR éteintes. Les valeurs calibrées ont toujours une valeur située entre 0 à 1000, où 0 étant considérée comme la plus réfléchissante (ex: la plus blanche) que la surface la plus réfléchissante rencontrée durant la phase de calibration -ET- 1000 étant la surtface la moins réfléchissante (ex: plus noir) que la surface la moins réfléchissante rencontrée durant la phase de calibration.
- Les applications de détection de ligne peuvent demander la position de la ligne en utilisant la méthode readLine(). readline() accepte un premier argument booléen optionnel qui indique la couleur de la ligne (ligne noire sur fond blanc -ou- ligne blanche sur fond noir). Le second argument optionnel indique si les LEDs Infrarouge doivent être allumées ou éteintes durant la mesure. readLine() utilise les valeurs de calibration pour chaque senseur et retourne un entier qui indique la position supposée de la ligne. Si vous utilisez N senseurs, une valeur 0 retournée signifie que la ligne est sous le senseur 0 (ou au-delà du senseur 0) et retourne une valeur 1000x(N-1) si la ligne est sous le senseur N-1 (ou entre le senseur N-1 -dernier senseur) ou au-delà de ce dernier).
Lorsque vous déplacez le senseur perpendiculairement à la ligne, la position de la ligne changera de façon monotone entre 0 et 1000 * (N-1) ou vice versa. Changer de façon monotone indique le la valeur croit (ou décroit) constamment dans le même sens.
Cette position de ligne peut être utilisée pour dans un contrôle PID en boucle fermée.
Une routine élémentaire permettant de suivre une ligne en utilisant les valeurs du senseur et effectuer le suivit de ligne pourrait ressembler à ceci:
void loop()
{
unsigned int sensors[3];
// obtenir les valeurs calibrées du senseur (dans un tableau de senseur)
// ainsi que la position de la ligne dans une gamme de valeur de
// 0 à 2000, avec 1000 retournée pour la ligne au milieu du senseur.
int position = qtr.readLine(sensors);
// Si tous les senseurs ont une très faible réflectance, alors prendre
// un action appropriée pour cette situation.
if (sensors[0] > 750 && sensors[1] > 750 && sensors[2] > 750)
{
// Faire une action. Cela peu signifier que l'on est à la fin
// de la course ou peut être tombé de la table, auquel cas, nous
// nous devrions arrêter de bouger, se retourner, aller à la
// recherche de la ligne.
return;
}
// Calculer l' "erreur" par rapport à la position de la ligne.
// Nous allons faire en sorte que l'erreur = 0 lorsque la ligne est
// placée sous le milieu du senseur (parce que c'est notre but).
// L'erreur aura une valeur entre -1000 et +1000.
// Si nous avons le senseur 0 à gauche et le senseur 2 à droite alors
// une lecture d'erreur de -1000 signifie que nous voyons la ligne
// sur la gauche par rapport au centre du senseur alors qu'une
// lecture de +1000 signifie que la ligne est sur la droite
// par rapport au centre.
int error = position - 1000;
// Vitesse des moteurs
int leftMotorSpeed = 100; // gauche
int rightMotorSpeed = 100;// droite
if (error < -500) // ligne sur la gauche
// tourner à droite
// -> arrêter moteur gauche
leftMotorSpeed = 0;
if (error > 500) // ligne sur la droite
// tourner à gauche
// -> arrêter le moteur droit
rightMotorSpeed = 0;
// Fixer la vitesse des moteurs en utilisant
// les valeurs de leftMotorSpeed et rightMotorSpeed
}
Contrôle PID
TLa valeur entière retournée par readLine() peu facilement être convertie la mesure de notre erreur de position pour les applications de suivit de ligne, comme démontré dans le précédent exemple de code. La fonction utilisée pour générer cette valeur de position/error est conçue pour être monotonique, ce qui signifie que la valeur change toujours dans la même direction au fur et a mesure que que les senseurs croisent la ligne. Cela en fait une grandeur utile pour réaliser un contrôle PID (Proportionnel Intégram Dérivé).
Expliquer la nature du contrôle PID va au delà des objectifs de ce document, mais wikipedia offre un bon article sur le sujet.
Le code suivant est un exemple très simple de contrôleur PD pour suivit de ligne (le terme intégrale "I" d'un régulateur PID n'est habituellement pas nécessaire dans le cadre d'un suivit de ligne). Les valeurs des différentes constantes PID (ou PD dans le cas présent) est généralement spécifique à votre propre application mais d'une façon générale vous pourriez noter que la constante de dérivation Kd est habituellement beaucoup plus grande que la constante proportionnelle Kp. C'est parce que la dérivée de l'erreur (quantification de la variation de l'erreur) est beaucoup plus petite que l'erreur elle même. Par conséquent, pour produire une correction signification il est nécessaire de multiplier le terme dérivé par une constante beaucoup plus grande.
int lastError = 0;
void loop()
{
unsigned int sensors[3];
// Obtenir les valeurs calibrées retournées dans
// tableau de senseur accompagné de la position
// de la ligne (valeur entre 0 et 2000) avec
// 1000 correspondant à la ligne au milieu du
// senseur
int position = qtr.readLine(sensors);
// Calculer notre "erreur" depuis la position
// de la ligne. Nous allons la calculer de sorte
// que l'erreur égale 0 si la ligne est sous la
// position centrale du senseur (ce qui est notre
// but). L'erreur aura une valeur entre -1000 et
// +1000. Si nous avons le senseur 0 à gauche et
// le senseur 2 à droite, alors une valeur lue
// de -1000 signifie que la ligne est vue sur la
// gauche du senseur. Une valeur de +1000
// signifie que que nous voyons la ligne sur
// la droite du senseur.
int error = position - 1000;
// Baser la vitesse des moteurs sur base des
// termes proportionnel et dérivés d'un PID.
// KP est la constante proportionnelle (commencer
// avec une valeur 0.1)
// KD est la constance dérivée (vous pouvez peut-être
// commencer avec un valeur autour de 5)
// Note: lors d'un asservissement PID, il est très
// important d'avoir le bon signe pour les valeurs
// sinon, la boucle de contrôle sera totalement
// instable.
// motorSpeed peut avoir une valeur positive ou
// négative en fonction du sens de la direction
// prise.
int motorSpeed = KP * error + KD * (error - lastError);
lastError = error;
// M1 et M2 sont les vitesses par défaut des moteurs.
// Ce sont les vitesses adéquate des deux moteurs
// pour suivre -SANS ERREUR- une ligne parfaitement
// droite.
// Si vos moteurs sont identiques alors M1 et M2 devraient
// être égale (ou presque, chaque moteur étant un peu
// différent de l'autre).
// Il est préférable de commencer avec une petite valeur
// pour M1 et M2 lorsque vous commencez à tester votre
// boucle de contrôle. En effet, l'erreur (écart par
// rapport à la ligne) devient rapidement plus grande
// si la vitesse est plus élevée.
// Après avoir atteint un résultat satisfaisant à
// faible vitesse, vous pouvez augmenter les valeurs
// de M1 et M2 et poursuivre l'affinement des valeurs
// des constantes KP et KD de votre PID.
int m1Speed = M1 + motorSpeed;
int m2Speed = M2 - motorSpeed;
// Cela peut aider de maintenir une vitesse positive
// pour les moteurs (ce point est optionnel).
// Un test similaire pourrait être ajouté pour garder
// la vitesse des moteurs en dessous du maximum
// autorisé.
if (m1Speed < 0)
m1Speed = 0;
if (m2Speed < 0)
m2Speed = 0;
// Fixer la vitesse des mmoteur en utilisant les
// variables m1Speed et m2Speed
}
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)