PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Linienfolger



Toran
19.04.2018, 13:31
Hallo Zusammen,
mal wieder bin ich auf ein kleines Problemchen gestoßen und will versuchen hier ein paar Denkanstöße zu bekommen.
ich bin gerade dabei einen Linienfolger mit dem Arduino zu programmieren. Ich habe genau einen Farbsensor (TCS3200). Bisher habe ich das so programmiert, dass der Robi nach rechts abbiegt, wenn er die Linie verlässt. Das funktioniert auch soweit ganz gut, nur, wenn er nach rechts abdriftet, dreht mein Roboter Kreise.
Ich habe versucht ihn nur eine bestimmte Zeit nach rechts fahren zu lassen und dann nach links fahren zu lassen, aber da ist der Roboter komplett eskaliert.



#include <TimerOne.h>

const int m1 = 10; //declaring the motors
const int m2 = 11;
const int m3 = 12;
const int m4 = 13;

const int s0 = A10; //declaring the outputs of thbe color sensor
const int s1 = A11;
const int s2 = A12;
const int s3 = A13;
const int out = A14;

double previousTime=0; //declarinng of a timer variable

float red=0,green=0,blue=0; //declaring all necessary color variables
float redA[10], greenA[10], blueA[10];
float rav=0,gav=0,bav=0;
int counter=0;
int state=0;
int interval;


void setup() {
// put your setup code here, to run once:
pinMode(m1,OUTPUT); //backwards right wheel
pinMode(m2,OUTPUT); //forward right wheel
pinMode(m3,OUTPUT); //backwards left wheel
pinMode(m4,OUTPUT); //forward right wheel

pinMode(s0, OUTPUT); //setting the ports to input
pinMode(s1, OUTPUT);
pinMode(s2, OUTPUT);
pinMode(s3, OUTPUT);
pinMode(out, INPUT);
pinMode(48,OUTPUT);
pinMode(51,OUTPUT);

digitalWrite(s0, HIGH); //frequency scaling of 20%
digitalWrite(s1, LOW);






Serial.begin(9600); //starting the Serial monitor on a frequency of 9600

}
void driveForward() //driving forward
{
analogWrite(m1,0);
analogWrite(m2,100);
analogWrite(m3,0);
analogWrite(m4,100);
}

void driveBackwards() //driving backwards
{
analogWrite(m3,100);
analogWrite(m2,0);
analogWrite(m3,100);
analogWrite(m4,0);
}

void turnRight() //turning right
{
analogWrite(m1,900);
analogWrite(m2,0);
analogWrite(m3,0);
analogWrite(m4,900);

}

void turnLeft() //turning left
{
analogWrite(m1,0);
analogWrite(m2,90);
analogWrite(m3,90);
analogWrite(m4,0);
}
void brake() //stopDriving
{
analogWrite(m1,0);
analogWrite(m2,0);
analogWrite(m3,0);
analogWrite(m4,0);
}
void colorSensorStuff()
{

digitalWrite(s2, LOW);
digitalWrite(s3, LOW);
red = pulseIn(out, LOW);
//red = map(red, 120,3000,255,0);
Serial.print(counter+1);
Serial.print(".)");
Serial.print("R= ");
Serial.print(red);
Serial.print(" ");
//delay(100);

//GREEN
digitalWrite(s2, HIGH);
digitalWrite(s3, HIGH);
green = pulseIn(out, LOW);
//green = map(green, 120,3000,255,0);
Serial.print("G= ");
Serial.print(green);
Serial.print(" ");
// delay(100);

//BLUE
digitalWrite(s2, LOW);
digitalWrite(s3, HIGH);
blue = pulseIn(out, LOW);
//blue = map(blue, 120,3000,255,0);
Serial.print("B= ");
Serial.print(blue);
Serial.println(" ");
// delay(500);

redA[counter]=red;
greenA[counter]=green;
blueA[counter]=blue;

counter++;

if(counter==9)
{

counter=0;
for(int i=0;i<10;i++)
{

rav=rav+redA[i];
gav=gav+greenA[i];
bav=bav+blueA[i];



}

rav=(rav/10);
gav=(gav/10);
bav=(bav/10);
/*
Serial.print("Average values: ");
Serial.println(" ");
Serial.print("Rav= ");
Serial.print(rav);
Serial.print(" ");
Serial.print("Gav= ");
Serial.print(gav);
Serial.print(" ");
Serial.print("Bav= ");
Serial.print(bav);
Serial.println(" ");
*/
}



}
void loop()
{

// put your main code here, to run repeatedly:

colorSensorStuff();
//delay(1000);
int currentTime=millis();


if( red>=55 && green >= 55 && blue >= 55)
{
Serial.println("Thats black! Follow the black way!");
state=0;
driveForward();
digitalWrite(51,HIGH);
digitalWrite(48,LOW);
}
else
{
interval=currentTime-previousTime;
turnRight();
digitalWrite(48,HIGH);
digitalWrite(51,LOW);
if(interval>=1000)
{
turnLeft();
}

}



}


Habt ihr einen oder mehr Tipps was ich machen kann ?
Gruß, Thomas

Holomino
19.04.2018, 14:03
Gegenfrage(n):
Sehe ich es nur nicht, oder setzt Du previousTime nie?
Was meinst Du mit Eskalieren?
Ist das gesund, die Motoren immer zuerst nach rechts und sofort wieder nach links zu schalten, wenn denn intervall >= 1000 ist?
Ist es gewollt, die Geschwindigkeit der Drehrichtungen unterschiedlich zu halten (bei TurnRight schneller als vorwärts)?
Ist die Klausel "red>=55 && green >= 55 && blue >= 55" so richtig herum (folgst Du einer weißen Linie oder gibt der Sensor für schwarz 255;255;255 aus)?

Nicht flapsig gemeint. Vielleicht aber steckt da irgendwo der Fehler.

Toran
19.04.2018, 14:21
>Nicht flapsig gemeint. Vielleicht aber steckt da irgendwo der Fehler.

Keine Angst, ich habe das nicht in den falschen Hals bekommen. Ich habe previousTime jetzt zurückgesetzt. Das hatte ich total vergessen. Den Rat die Motoren anzuhalten und dann wieder anzusteuern habe ich auch mal befolgt.
Die Geschwindigkeit der Drehfunktionen ist gewollt kleiner als beim geradeaus Fahren. Hat den einfachen Grund, dass der Sensor aus irgendeinem Grund nicht ganz mitkommt, wenn die Dinger zu schnell drehen. Der Roboter folgt einer schwarzen Linie. Die Werte vom Sensor müssten eigentlich richtig kalibriert sein. Zu mindest erkennt er jede Art von Schwarz vorausgesetzt das Material reflektiert nicht zu stark.
Leider kann ich heute nicht mehr testen ob deine Tipps Früchte tragen, da mein Akku leer ist und ein Bachelorant dieser Firma hat den für seinen Robi mit nachhaus genommen - ganz toll -.-.
Danke auf jeden Fall für deine Hilfe. Ich bin mir sicher jetzt wird es besser funktionieren.

oberallgeier
19.04.2018, 16:16
.. Geschwindigkeit der Drehfunktionen ist gewollt kleiner als beim geradeaus .. einfachen Grund .. der Sensor .. Grund nicht ganz mitkommt, wenn die Dinger zu schnell drehen. Der Roboter folgt einer schwarzen Linie. Die Werte vom Sensor müssten eigentlich richtig kalibriert sein ..Na ja, es gibt schon LInienfolger die (un-)ziemlich schnell sind. Ein Beispiel davon der 3Pi (klick (https://www.youtube.com/watch?v=fl0CJhPiEfY)), der nicht nur bei den runden Kursen fetzt sondern auch bei eckigen "Rundkursen (https://www.youtube.com/watch?v=TsnkyJUXxaE)" und auch im Labyrinth (https://www.youtube.com/watch?v=mJV-KDqHgDQ). Kommt auf Sensorik UND Software drauf an.

HaWe
19.04.2018, 19:04
das Zauberwort für schnelle Linienfolger heißt "PID"-Steuerung - das klappte auch immer schon mit Lego wunderbar:
http://www.inpharmix.com/jps/PID_Controller_For_Lego_Mindstorms_Robots.html

i_make_it
20.04.2018, 07:27
Unabhängig von der Regelungsart (Zweipunkt, P, D, PD, PID, Fuzzy, etc.) geht es als erstes einmal darum ob der Sensor der richtige ist für die Aufgabenstellung.
Linienfolger habe üblicherweise mindestens drei Feflexlichtschranken. Und diese sind monochom und oft auch noch digital und nicht analog.
Ein Farbsensor ist also verdammt wenig und hat einen nicht notwendigen Datenoverhead.

Ein Linienfolgersensor muß ja nur einen Unterschied zwichen Linie (1) und nicht Linie (0) erkennen können.
Eine Linienfolgeaufgabe kommt auch nicht ohne Weiteres zufällig in der Natur vor sondern ist eine künstliche Aufgabenstellung die üblicherweise in Wettbewerben gestellt wird.
Man kann also gemäß der Wettbewerbsbedingungen seinen Sensor gezielt einstellen, so das unabhängig von Vordergrund- (Linie) und Hintergrundfarbe (Boden), ein sicheres Erkennen mit einem Bit möglich ist.
Also wäre es Sinnvoll einen Farbsensor da einzusetzen wo er seine Stärke zeigen kann und nicht zweckendfremded, so das man alle seine Nachteile erst kompensieren muß.

Muß man aber damit leben, dann wäre der erste Schritt, eine Datenreduktion durchzuführen.
Also für jeden Farbkanal einen Schwellwert festlegen und darüber für jeden Kanal festlegen ob er eine 1 oder eine 0 ausgibt.
Dann die Kanäle aufsummieren und nur wenn alle Kanäle 1 sind wird dan final eine 1 ausgegeben, sonst eine 0.
Damit reduziert man z.B. bei einem 3-Kanal Sensor mit 8 Bit Auflösung die über 16,7 Millionen möglichen Kombinationen auf zwei mögliche Zustände.

Allerdings ist das größere Problem, wenn man nur einen Sensor hat.
Denn mir einem Bit kann man nur feststellenn ob man auf der Linie ist oder nicht.
Eine Erkennung in welche Richtung man die Linie verlassen hat, ist wärend der Fahrt nicht möglich.
Bei jeder Änderung müsste man anhalten und auf der Stelle Drehungen durchführen um zu erkennen ob man beim Linksdrehenn ode Rrechtsdrehen wieder auf die Linie zurück findet.

Bei einem Linienfolgesensor mit mindestens drei (Für Wettbewerbe besser 5) Sensoren kann man mit einer Messung deutlich mehr Informationen gewinnen.
Üblicherweise kann die Empfindlichkeit und somit die digitale Schaltschwelle mit einem Komparator eingestellt werden.

Um sich darüber klar zu werden, was man bei der Aufgabenstellung von einem Sensor erwarten kann, kann man sich mal die möglichen Fälle visualisieren.
Im Bild eine 5er Sensorzeile.
33423
Der Fall wenn kein Sensorelement etwas detektiert ist nicht berücksichtigt. (Bei Fall A den High Pegel im Sensor ganz Rechts ignorieren der stammt von einem Fall mit Codemarken paralell zur Linie).
Es sind nur die Fälle für eine Seite berücksichtigt (die andere Seite ist eine Spigelung der Fälle).
Bei Fall A fährt man einfach gadeaus.
Bei Fall B wird das Signal des mittleren Sensors schwächer und der nächste Sensor links gibt ein Signal ungleich 0 zurück.
Je nach Schaltschwelle kann man hier schon ein Auswandern nach links erkennen und mit dem Regeln der Fahrtrichtung beginnen.
Bei Fall C ist ein eindeutiges Auswandern nach links erkennbar und entsprechend ist die Fahrtrichtung nach links zu korrigieren.
Bei Fall D ist ein starkes Auswandern nach links erkennbar, hier könnte man neben starkem Gegenlenken auch die Geschwindigkeit reduzieren um das Verlieren der Linie unwahrscheinlicher zu machen.
Die bisherifgen Fälle treten bei Kurven auf.
Bei Fall E knickt die Linie nach Links ab und ein Anhalten (oder sehr starkes Abbremsen) und scharfes Drehen nach Links um 90° ist durchzuführen.
Bei Fall F kommt man mur mit einem Gedächtniss weiter.
Als Momentaufnahme kann das ein Zielpunkt sein, nur wenn man in diesem Fall weiterfährt und die vorherigen Messungen in Verbindung mit der zurückgelegten Strecke berücksichtigt, kann man erkennen ob es sich um eine Linienkreuzung, T-Stoß oder eine größere Zielfläche handelt.

Dies sind allerdings Überlegungen, die man üblicherweise bei der Analsyse der Aufgabenstellung anstellt, bevor man mit dem Aufbau und der Programmierung beginnt.

Holomino
20.04.2018, 17:10
Ich kann mich erinnern: Auf der CD im ersten Mindstorm-Kasten war das Linienfolger-Experiment unter so ziemlich den gleichen Bedingungen als Aufgabe zu lösen - ein Sensor, zwei Motoren.
Die offizielle Lösung war übrigens, die Räder abwechselnd anzusteuern und so den Sensor immer einmal über die Linie zu bewegen. Das Gefährt hat sich so langsam nach vorne gewibbelt.
Ist noch gar nicht so lange her, noch keine 20 Jahre.

HaWe
20.04.2018, 19:33
jap, das wird dann wohl der RCX gewesen sein, der kam vor knapp 20 Jahren auf den Markt
Das Gewibbel hat dann aber durch PID Regelung fast komplett abgenommen - und die Geschwindigkeit zu... 8)

i_make_it
21.04.2018, 06:24
Das Problem ist das man mit einem einzigen Sensorelement nur einen Kantenfolger realisieren kann.
Da LEGO den Farbsensor nimmt, wird man für PID einfach mehrere Farbabstufungen nutzen um zu erkennen wie weit man von der Kante entfernt ist.
Der Messpunkt ist ja in der Realität eine Messfläche und genau auf der Kante ist man wenn 50% Linie und 50% Hintergrund da sind.

Mann kann mit einem einzigen Sensorelement aber nicht erkennen ob man links oder rechts an der Kante der Linie ist.
Das geht dann nur mit dem hin und her schwenken.
Denn nur da kann man aus der Bewegungsrichtung und dem Messergebniss einen Schluß daraus ziehen ob man grade eine linke oder eine rechte Kante erkennt.

Wenn man also beim Algorithmus für einen Sensor davon ausgeht, das man der rechten Kante folgt, gibt man an:
Wird es heller drehe links, wird es dunkler drehe rechts.
Kommt man dann aber z.B. durch einen scharfen Knick und etwas zu viel Geschwindigkeit an die linke Kante dreht man sich bei der Suche nach der Linie von der selben weg und wird in entgegengesetzte Richtung fahren wenn man sie wiederfindet.

Der Aufbau kann also funktionieren, ist aber nicht besonders robust.

Da sollte man also am besten klären, ob man die Funktion Linienfolgen robust oder experimentel realisieren soll/will.

Eine robuste Implementierung erlaubt prinzipiell höhere Geschwindigkeiten.

HaWe
21.04.2018, 07:50
Das Problem ist das man mit einem einzigen Sensorelement nur einen Kantenfolger realisieren kann.
Da LEGO den Farbsensor nimmt, wird man für PID einfach mehrere Farbabstufungen nutzen um zu erkennen wie weit man von der Kante entfernt ist.
Der Messpunkt ist ja in der Realität eine Messfläche und genau auf der Kante ist man wenn 50% Linie und 50% Hintergrund da sind.

Mann kann mit einem einzigen Sensorelement aber nicht erkennen ob man links oder rechts an der Kante der Linie ist.
Das geht dann nur mit dem hin und her schwenken.
Denn nur da kann man aus der Bewegungsrichtung und dem Messergebniss einen Schluß daraus ziehen ob man grade eine linke oder eine rechte Kante erkennt.

Wenn man also beim Algorithmus für einen Sensor davon ausgeht, das man der rechten Kante folgt, gibt man an:
Wird es heller drehe links, wird es dunkler drehe rechts.
Kommt man dann aber z.B. durch einen scharfen Knick und etwas zu viel Geschwindigkeit an die linke Kante dreht man sich bei der Suche nach der Linie von der selben weg und wird in entgegengesetzte Richtung fahren wenn man sie wiederfindet.

Der Aufbau kann also funktionieren, ist aber nicht besonders robust.

Da sollte man also am besten klären, ob man die Funktion Linienfolgen robust oder experimentel realisieren soll/will.

Eine robuste Implementierung erlaubt prinzipiell höhere Geschwindigkeiten.

Die Statements zu Lego Sensorik stimmen so nicht unbedingt.
Lego verwendet nicht immer einen Farbsensor zur Linienverfolgung, es gibt auch - je nach System - reine Helligkeitssensoren (Lichtsensoren aktiv oder passiv).
Aber auch Farbsensoren können per Firmware/Treiber-Einstellung in einen reinen Helligkeitssensor-Modus geschaltet werden, z.B. für Linienfolger oder andere Zwecke, und das ist bei Lego auch immer der bevorzugte Modus für Linienfolger.
Aber da der TO ja nicht Lego verwendet, sind die Überlegungen zu Lego-Sensortypen auch wohl eher nebensächlich, nur die grundsätzlichen Linienfolger-Algorithmen können ntl ebenfalls verwendet werden.
Farberkennung zur Linienverfolgung ist dabei auch sicher deutlich schwieriger als reine Helligkeitsunterscheidung.

oberallgeier
21.04.2018, 08:48
Ich hatte oben schon pololus 3pi (klick mal) (https://www.pololu.com/product/975/resources) erwähnt. Der hat eine Fülle von Linienfolger-Ratschlägen unter "Pololu 3pi Robot User’s Guide". Der Reihe nach hier, siehe entsprechende Einzelpunkte :

User´s Guide:
https://www.pololu.com/docs/0J21

Pololu AVR C/C++ Library User’s Guide
https://www.pololu.com/docs/0J20

und Pololu AVR Library Command Reference
https://www.pololu.com/docs/0J18

Den 3Pi habe ich selbst, daher kenne ich diese Fülle von Informationen (nicht nur über Linienfolger). Leider (*gg*) keine Farbsensorik.

Toran
23.04.2018, 08:19
Ich kann mich erinnern: Auf der CD im ersten Mindstorm-Kasten war das Linienfolger-Experiment unter so ziemlich den gleichen Bedingungen als Aufgabe zu lösen - ein Sensor, zwei Motoren.
Die offizielle Lösung war übrigens, die Räder abwechselnd anzusteuern und so den Sensor immer einmal über die Linie zu bewegen. Das Gefährt hat sich so langsam nach vorne gewibbelt.
Ist noch gar nicht so lange her, noch keine 20 Jahre.

Die Idee ist echt gut! So kann ich nämlich immer ganz genau ausmachen auf welcher Seite er ausgebrochen ist und dann dementsprechend regulieren. Danke!

i_make_it
23.04.2018, 10:37
Bei Youtube gibt es zu Mindstorms und einem Sensor auch noch andere kreative Lösungen.
Z.B. wurde der Sensor an einem Arm befestigt, der durch einen eigenen Motor hin und her bewegt wird.
Da muß dann die Masse des Roboters nur gedreht werden, wenn man wirklich abbiegt.
Sonst wird nur der Sensor mit dem Arm bewegt.
Nachteil ist halt ein Motor mehr und die Schalter für die Endlagen.
Von der Auswertung ist das identisch zum Drehen des ganzen Roboters.