Zum Hauptinhalt springen

Die Liniensensoren

Bibliotheken des Herstellers Pololu

Für die Verwendung der Liniensensoren (Bodensensoren) wird die folgende Klasse bereitgestellt:

#include <Pololu3piPlus32U4.h>
using namespace Pololu3piPlus32U4;

LineSensors lineSensors;

Einführung

Der Zumo32u4 hat fünf unabhängige IR-Bodensensoren, welche Linien oder auch Abgründe detektieren können. Die Sensoren befinden sich auf der Unterseite des Roboters, direkt hinter dem Metallschild.

Liniensensoren des Zumo

Ein einzelner Bodensensor bestehend aus einer Reihenschaltung eines Fototransistors (welcher vereinfacht als lichtabhängiger Widerstand angesehen werden kann) und eines Kondensators. Ist der Kondensator aufgeladen, so hängt die Entladekurve vom Fototransistor und somit vom detektierten IR-Licht ab. Wird mit dem Mikrocontroller die Entladezeit des Kondensators gemessen, so kann damit die Menge des detektierten IR-Lichtes bestimmt werden.

Die Klasse Zumo32U4LineSensors (Zumo) oder LineSensors (3pi+) stellt alle notwendigen Methoden zum Konfigurieren, Auslesen und Weiterverabeiten der 5 IR-Bodensensoren bereit.

Konfigurieren (nur Zumo 32u4)

caution

Die Bodensensoren des 3pi+ 32u4 müssen nicht extra konfiguriert oder initialisiert werden.

void initThreeSensors()

void initThreeSensors(uint8_t emitterPin = SENSOR_LEDON)

Initialisiert und konfiguriert das Liniensensor-Objekt so, dass drei Sensoren (die beiden äußeren und der mittlere) verwendet werden. Kann verwendet werden, wenn auch alle drei Näherungssensoren genutzt werden.

void initFiveSensors()

void initFiveSensors(uint8_t emitterPin = SENSOR_LEDON)

Initialisiert und konfiguriert das Liniensensor-Objekt so, dass alle fünf Sensoren verwendet werden. Funktioniert nur, wenn die seitlichen Näherungssensoren deaktiviert wurden. Korrekte Jumper-Einstellung an der Platine der Liniensensoren beachten.

Beispiel

// Konfiguriert den Zumo 32u4 für 5 Bodensensoren
#include <Zumo32U4.h>

Zumo32U4LineSensors lineSensors; // Liniensensor-Objekt
void setup()
{
lineSensors.initFiveSensors(); // Konfiguration für 5 Bodensensoren
}

void init(...)

void init (uint8_t *pins, uint8_t numSensors, uint16_t timeout = 2000, uint8_t emitterPin = SENSOR_LEDON )

Initialisiert das Liniensensor-Objekt so, dass es einen benutzerdefinierten Satz von pins verwendet. Meistens sollte die Konfiguration mit void initThreeSensors() oder void initFiveSensors() ausreichen.

  • Das Array pins enthält die Arduino-Pin-Nummer für jeden Sensor.

  • numSensors gibt die Länge des Arrays pins an (d.h. die Anzahl der verwendeten Linien-Sensoren).

  • timeout gibt die Zeitspanne in Mikrosekunden an, nach welcher der Sensor die Fläche als vollständig schwarz betrachtet. Das heißt, wenn die Impulslänge für einen Pin die Zeitüberschreitung überschreitet, wird das Impuls-Timing gestoppt und der Messwert für diesen Pin wird als volles Schwarz betrachtet. Es wird empfohlen, dass der Timeout zwischen 1000 und 3000 us eingestellt wird, abhängig vom Bodenabstand der Sensoren und der Umgebungsbeleuchtung. Die Verwendung von Timeout ermöglicht es, die Dauer eines Sensorlesezyklus zu verkürzen und gleichzeitig nützliche analoge Messungen des Reflexionsgrades beizubehalten.

  • emitterPin ist der Arduino-Pin, der die IR-LEDs Liniensensoren steuert.

Beispiel

Initialisieren der drei mittleren IR Sensoren.

#inlcude <Zumo32U4.h>

Zumo32U4LineSensors lineSensors; // Liniensensor-Objekt

short pins[] = {SENSOR_DOWN2, SENSOR_DOWN3, SENSOR_DOWN4}; // Array mit Sensor-Pins
lineSensors.init(pins, sizeof(pins), 2000, SENSOR_LEDON); // Initialisierung der Sensoren mit dem vorher definiertem Array

Kalibrieren

void calibrate()

void calibrate(unsigned char readMode = QTR_EMITTERS_ON)

Ließt die Sensorwerte für eine Kalibrierung. Die beim wiederholenden Aufrufen der Methode ermittelten Maximal- und Minimalwerte werden für jeden Sensor einzeln abgespeichert und bei der Methode readCalibrated() genutzt. Auf die Kalibrierungsdaten (Minimal- und Maximalwerte der Sensoren) kann mit den Pointern calibratedMinimumOn, calibratedMaximumOn und calibratedMinimumOff, calibratedMaximumOff zugegriffen werden. Diese Pointer zeigen auf Arrays mit der Länge numSensors, wie es bei der Initialisierung angegeben worden ist.

Die Kalibrierungsdaten werden von den Methoden readCalibrated() und readLine() verwendet.

Beispiel

// Drehen des Roboters um +90°, -180° und abschließend +90° zum Kalibrieren der Liniensensoren

for(int i = 0; i < 120; i++)
{
if (i > 30 && i <= 90)
{
motors.setSpeeds(-60, 60);
}
else
{
motors.setSpeeds(60, -60);
}
lineSensors.calibrate(); // Kalibrierungsmethode
}
motors.setSpeeds(0, 0);
}

Messen

void read(...)

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

Liest die rohen, unkalibrierten Sensorwerte in einen Array sensor_values. Es muss Platz für so viele Werte vorhanden sein, wie bei der Initialisierung an Sensoren angegeben wurden. Die zurückgegebenen Werte sind ein Maß für den Reflexionsgrad in abstrakten Einheiten, wobei höhere Werte einem niedrigeren Reflexionsgrad entsprechen (z.B. eine schwarze Fläche oder ein Hohlraum).

Ein schwarze Linie erzeugt also einen größeren Messwert als der weiße Untergrund.

Beispiel

LineSensors lineSensors;               // Liniensensor-Objekt

unsigned int lineSensorValues[5]; // Array für drei Sensorwerte
lineSensors.read(lineSensorValues); // Array für die Sensorwerte wird überschrieben

void readCalibrated(...)

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

Liefert Werte, die auf einen Wert zwischen 0 und 1000 kalibriert sind, wobei 0 dem von void calibrate() gelesenen Minimalwert entspricht und 1000 dem Maximalwert entspricht. Die Kalibrierungswerte werden für jeden Sensor separat gespeichert, so dass Unterschiede in den Sensoren automatisch berücksichtigt werden. Vor dem Aufruf der Methode sollte immer eine Kalibrierung mit void calibrate() durchgeführt werden.

Wie bei der Methode read() liefert ein schwarzer Untergrund größere Werte, als ein weißer Untergrund.

Beispiel

#define NUM_SENSORS 5
LineSensors lineSensors; // Liniensensor-Objekt

unsigned int lineSensorValues[NUM_SENSORS]; // Array für die Sensorwerte
lineSensors.readCalibrated(lineSensorValues); // Array für die Sensorwerte wird überschrieben

Beispiel zum Auslesen eines einzelnen Sensorwertes

// Mit einem Bodensensor die Linienkante detektieren
#include <Pololu3piPlus32U4.h>
using namespace Pololu3piPlus32U4;

LineSensors lineSensors;
ButtonA buttonA;
Motors motors;
OLED lcd;

#define NUM_SENSORS 5 // Anzahl der verwendeten Sensoren
unsigned int lineSensorValues[NUM_SENSORS]; // Array für die Sensorwerte

int timeStamp = 0;

// Kalibrierung der Bodensensoren durch automatisches drehen des Roboters über der Linie.
void calibrateSensors() {
lcd.clear();
lcd.print(F("Calib ..."));
delay(500);

// Kalibirierungsschleife: Roboter dreht sich und nimmt 120 Messwerte auf
for (int i = 0; i < 120; i++) {
if (i > 30 && i <= 90) {
motors.setSpeeds(-60, 60);
} else {
motors.setSpeeds(60, -60);
}
lineSensors.calibrate(); // Sensoren auswerten und kalibrieren
}
motors.setSpeeds(0, 0); // Motor stoppen
lcd.clear();
}

void setup() {
Serial.begin(115200);

lcd.clear();
lcd.print("Sensor");
lcd.gotoXY(0, 1);
lcd.print("Demo ->A");
buttonA.waitForPress();
calibrateSensors();
}

void loop() {
if ( (millis() - timeStamp) > 500) {
lineSensors.readCalibrated(lineSensorValues); // Sensorwerte einlesen
int sensorValue = lineSensorValues[2]; // Index 2: mittlerer Sensor
Serial.println(sensorValue);
lcd.gotoXY(0, 0);
lcd.print(sensorValue);
lcd.print(" ");

}
}

int readLine(...) (nur Zumo 32u4)

Siehe readLineBlack(...)

int readLineBlack(...) (nur 3pi+ 32u4)

int readLine(unsigned int *sensor_values, unsigned char readMode=QTR_EMITTERS_ON, unsigned char white_line=0)

Funktioniert wie readCalibrated(), gibt aber auch eine geschätzte Position des Roboters in Bezug auf eine Linie zurück. Die Schätzung erfolgt unter Verwendung eines gewichteten Mittelwerts, welcher die Sensorwerte mit Vielfachen von 1000 multipliziert, so dass ein Rückgabewert von 0 anzeigt, dass die Zeile direkt unter Sensor 0 liegt, ein Rückgabewert von 1000 zeigt an, dass die Zeile direkt unter Sensor 1 liegt, 2000 zeigt an, dass sie unter Sensor 2000 liegt, usw. Zwischenwerte zeigen an, dass sich die Linie zwischen zwei Sensoren befindet. Die Formel lautet :

0x0+1000x1+2000x2+x0+x1+x2+\frac{0\cdot x_0 + 1000\cdot x_1 + 2000 \cdot x_2 +\cdots}{x_0 + x_1 + x_2 + \cdots}

Standardmäßig geht diese Funktion von einer dunklen Linie (hohe Werte) aus, die von Weiß (niedrige Werte) umgeben ist. Wenn die verwendete Linie hell auf Schwarz ist, setzen Sie das optionale zweite Argument white_line auf true. In diesem Fall wird jeder Sensorwert vor der Mittelung durch (1000 - Wert) ersetzt.

Beispiel

#define NUM_SENSORS 5
LineSensors lineSensors; // Liniensensor-Objekt

unsigned int lineSensorValues[NUM_SENSORS]; // Array für die Sensorwerte
int position = lineSensors.readLineBlack(lineSensorValues);

Beispiel Linienposition

// Liniensensor-Demo 
#include <Pololu3piPlus32U4.h>
using namespace Pololu3piPlus32U4;

LineSensors lineSensors;
ButtonA buttonA;
Motors motors;
OLED lcd;


#define NUM_SENSORS 5 // Anzahl der verwendeten Sensoren
unsigned int lineSensorValues[NUM_SENSORS]; // Array für die Sensorwerte

int timeStamp = 0;

// Eine Sekunde warten und dann beginnen mit der Kalibirierung der Bodensensoren
// durch automatisches Drehen des Roboters um etwa -90, +180, -90 Grad.
void calibrateSensors()
{
lcd.clear();
lcd.print(F("Calib ..."));
delay(1000);

// Kalibirierungsschleife: Roboter dreht sich und nimmt 120 Messwerte auf
for (int i = 0; i < 120; i++)
{
if (i > 30 && i <= 90){
motors.setSpeeds(-60, 60);
}
else{
motors.setSpeeds(60, -60);
}

lineSensors.calibrate(); // Sensoren auswerten und kalibrieren
}
motors.setSpeeds(0, 0);
lcd.clear();
}

void setup() {

// "Welcome"-Anzeige auf dem Display
lcd.clear();
lcd.gotoXY(0, 0); lcd.print(F("LineDemo"));
lcd.gotoXY(0, 1); lcd.print(F("-> A"));
buttonA.waitForPress();
lcd.clear();

calibrateSensors();
}

void loop() {

int updateTime = 333;

// alle 333 ms auswerten der Sensoren und aktualisieren des Display
if ( (millis() - timeStamp) > updateTime){
timeStamp = millis();
int position = lineSensors.readLineBlack(lineSensorValues);
lcd.gotoXY(0,0);
lcd.print(position);
lcd.print(F(" "));
}
}