Hallo zusammen,
ich möchte hier mal meine Fortschritte im Bereich Perimetertracking dokumentieren und ggf. hat ja noch der Eine oder Andere eine Idee, diese zu optimieren.
Am Anfang hatte ich vor innerhalb der Schleife (ca. 1 m Abstand) zur Ladestation zu fahren und dann nahe der Ladestation auf die Schleife zu wechseln und dann in die Ladestation zu fahren. Der Vorteil liegt darin, dass man innerhalb der Schleife wesentlich schneller fahren kann als über der Schleife, da die Toleranzbereiche größer sind.
Leider hat mir meine Umgebung leider einen Strich durch die Rechnung gemacht, da ich zwei Passagen habe wo der Draht teilweise nur 1m bzw. nur 50cm voneinander liegt.
Als erstes habe ich dann meinen Code so geschrieben, dass ich den PID für das Tracking mit der Perimeteramplitude als Eingang versorgt habe. Das hat auch relative gut funktioniert. Hierzu muss ich noch erwähnen, dass ich hinten eine dritte Spule an den Mower angebracht habe, so dass ich nun Rückwärts den Perimeter abfahren kann.
https://youtu.be/st3JQdVQ0fY
Doch es gab zwei Nachteile:
Zum einen muss das Perimetersignal nach Möglichkeit immer die gleiche Stärke haben, so dass die PID Parameter von Schleife zu Schleife extra getuned werden müssen.
Zum anderen darf der Robbi auf keinen Fall weiter als 20 cm mit dem Hinterrad (was nun vorne ist) über den Perimeter fahren. Dies kann mit der Amplitude und einer Spule nicht wirklich festgestellt werden, da das Maximum der Amplitude ca. 8cm vom Drath entfernt ist.
Anbei mal ein Bild der Gemessenen Amplituden Werte. Links von 0 ist Außerhalb des Perimeters:
Hier habe ich es nun gemacht wie im Ardumower Code und und stoppe nach zwei Sekunden und drehe den Mower dann.
Hätte ich bestimmt noch besser hinbekommen, doch dann bin ich auf folgendes Video gestoßen Zeit: 1:22
https://www.youtube.com/watch?v=SGJ9yxEgr70&index=34&list=PL4GsVqyuXHkeDUMbMyggVdhITIbzJ1SZK
Weitere Recherchen brachten mich zu folgendem Video Zeit: 5:09
https://www.youtube.com/watch?v=btD0FLkGNDQ&index=33&list=PL4GsVqyuXHkeDUMbMyggVdhITIbzJ1SZK
Man sieht sehr schön, wie der Roboter gegen den Perimeter bounced.
Das es diesen Algorithmus gibt, was mir schon lange bewusst, doch wenn ich Videos davon über Line Follower angeschaut habe, sah das nicht wirklich toll aus.
Der Algorithmus löst auf jeden Fall das Problem, dass ich zu weit über den Perimeter fahre, da der Roboter wenn er über den Perimeter fährt sofort nach innen gelenkt wird. Dann fährt er in einem kleinen Bogen am Perimeter innen entlang, bis er wieder bounced. Weiterhin ist man von der Amplitude wie im originalen Ardumower Code unabhängig.
Hier mein Ergebnis. Wenn ich die Ladestation an einem geraden Abschnitt stelle, wird er vermutlich gerade einfahren.
https://youtu.be/khzK0Fq8tkA
Realisiert habe ich dies, in dem ich das Bouncen fest programmiert habe. Das funktioniert, da die Geschwindigkeit immer gleich ist. Das Fahren innerhalb des Perimeters wird durch das Intergral des PID bestimmt. Weiterhin treffe ich noch einige Fallentscheidungen in Abhängigkeit, wie viel Zeit von der letzten Peirmetertransition vergangen ist. Letztendlich mache ich es wie im Ardumower Code aber etwas abgeändert. Die PID Werte KP und KD habe ich mal drinnen gelassen obwohl aktuell nicht benötigt.
Wenn man sich die Bedienungsanleitung von Ambrogio anschaut, kann man auch innerhalb des Perimeters fahren und dann bei engen Passagen auf das Perimeterkabel wechseln. Weiterhin kann man ein Dreieckmuster in das Perimeterkabel verlegen und dem Robbi sagen, er soll auf die andere Seite des Rasens wechseln um den Weg zur Ladestation abzukürzen. Ggf. werde ich das Später noch umsetzen.
ich möchte hier mal meine Fortschritte im Bereich Perimetertracking dokumentieren und ggf. hat ja noch der Eine oder Andere eine Idee, diese zu optimieren.
Am Anfang hatte ich vor innerhalb der Schleife (ca. 1 m Abstand) zur Ladestation zu fahren und dann nahe der Ladestation auf die Schleife zu wechseln und dann in die Ladestation zu fahren. Der Vorteil liegt darin, dass man innerhalb der Schleife wesentlich schneller fahren kann als über der Schleife, da die Toleranzbereiche größer sind.
Leider hat mir meine Umgebung leider einen Strich durch die Rechnung gemacht, da ich zwei Passagen habe wo der Draht teilweise nur 1m bzw. nur 50cm voneinander liegt.
Als erstes habe ich dann meinen Code so geschrieben, dass ich den PID für das Tracking mit der Perimeteramplitude als Eingang versorgt habe. Das hat auch relative gut funktioniert. Hierzu muss ich noch erwähnen, dass ich hinten eine dritte Spule an den Mower angebracht habe, so dass ich nun Rückwärts den Perimeter abfahren kann.
https://youtu.be/st3JQdVQ0fY
Doch es gab zwei Nachteile:
Zum einen muss das Perimetersignal nach Möglichkeit immer die gleiche Stärke haben, so dass die PID Parameter von Schleife zu Schleife extra getuned werden müssen.
Zum anderen darf der Robbi auf keinen Fall weiter als 20 cm mit dem Hinterrad (was nun vorne ist) über den Perimeter fahren. Dies kann mit der Amplitude und einer Spule nicht wirklich festgestellt werden, da das Maximum der Amplitude ca. 8cm vom Drath entfernt ist.
Anbei mal ein Bild der Gemessenen Amplituden Werte. Links von 0 ist Außerhalb des Perimeters:
Hier habe ich es nun gemacht wie im Ardumower Code und und stoppe nach zwei Sekunden und drehe den Mower dann.
Hätte ich bestimmt noch besser hinbekommen, doch dann bin ich auf folgendes Video gestoßen Zeit: 1:22
https://www.youtube.com/watch?v=SGJ9yxEgr70&index=34&list=PL4GsVqyuXHkeDUMbMyggVdhITIbzJ1SZK
Weitere Recherchen brachten mich zu folgendem Video Zeit: 5:09
https://www.youtube.com/watch?v=btD0FLkGNDQ&index=33&list=PL4GsVqyuXHkeDUMbMyggVdhITIbzJ1SZK
Man sieht sehr schön, wie der Roboter gegen den Perimeter bounced.
Das es diesen Algorithmus gibt, was mir schon lange bewusst, doch wenn ich Videos davon über Line Follower angeschaut habe, sah das nicht wirklich toll aus.
Der Algorithmus löst auf jeden Fall das Problem, dass ich zu weit über den Perimeter fahre, da der Roboter wenn er über den Perimeter fährt sofort nach innen gelenkt wird. Dann fährt er in einem kleinen Bogen am Perimeter innen entlang, bis er wieder bounced. Weiterhin ist man von der Amplitude wie im originalen Ardumower Code unabhängig.
Hier mein Ergebnis. Wenn ich die Ladestation an einem geraden Abschnitt stelle, wird er vermutlich gerade einfahren.
https://youtu.be/khzK0Fq8tkA
Realisiert habe ich dies, in dem ich das Bouncen fest programmiert habe. Das funktioniert, da die Geschwindigkeit immer gleich ist. Das Fahren innerhalb des Perimeters wird durch das Intergral des PID bestimmt. Weiterhin treffe ich noch einige Fallentscheidungen in Abhängigkeit, wie viel Zeit von der letzten Peirmetertransition vergangen ist. Letztendlich mache ich es wie im Ardumower Code aber etwas abgeändert. Die PID Werte KP und KD habe ich mal drinnen gelassen obwohl aktuell nicht benötigt.
Code:
class TFLfollowLine: public Node
{
private:
double last_error, integral;
public:
double Kp, Ki, Kd;
unsigned long lastRun;
TFLfollowLine() {
Kp = 0; //
Ki = 0.5;
Kd = 0;
lastRun = 0;
last_error=0;
integral = 0;
}
virtual void onInitialize(Blackboard& bb) {
lastRun = 0;
last_error=0;
integral = 0;
}
virtual NodeStatus onUpdate(Blackboard& bb) {
if ( millis() - lastRun < 100) return BH_RUNNING;
lastRun = millis();
double error = bb.perimeterSenoren.magnetudeB;
if(error <= 0) {
error =-1;
} else {
error = 1;
}
double derivate = error-last_error;
integral = integral + (Ki*error);
//Set integral to 0 if crossing the line
if (sign0minus(error) != sign0minus(integral)) { //sign0minus => 0 belongs to minus
integral = 0;
}
double Output = Kp * error + integral + Kd * derivate ;
if(Output > bb.LINEFOLLOW_SPEED_LOW) Output = bb.LINEFOLLOW_SPEED_LOW;
if(Output < -1*bb.LINEFOLLOW_SPEED_LOW) Output = -1*bb.LINEFOLLOW_SPEED_LOW;
last_error = error;
bb.cruiseSpeed = bb.LINEFOLLOW_SPEED_LOW;
bb.driveDirection = DD_REVERSE_LINE_FOLLOW;
if(error>0.0f) { //Inside Perimeter
if ( (millis()-bb.perimeterSenoren.perimeterLastTransitionTimeB) > 3500 ) { // If more than 3.5sec inside rotate full
bb.cruiseSpeed = 15;
bb.driveDirection = DD_ROTATECW;
bb.motor.L->setSpeed(15);
bb.motor.R->setSpeed(-15);
} else if ( (millis()-bb.perimeterSenoren.perimeterLastTransitionTimeB) > 2800 ) { // If more than 2.8sec inside rotate more aggressive
bb.motor.L->setSpeed(-(bb.cruiseSpeed - Output));
bb.motor.R->setSpeed(-(bb.cruiseSpeed+10));
} else if ( (millis()-bb.perimeterSenoren.perimeterLastTransitionTimeB) > 2000 ) { // If more than 2sec inside rotate aggressive
bb.motor.L->setSpeed(-(bb.cruiseSpeed - Output));
bb.motor.R->setSpeed(-(bb.cruiseSpeed+5));
} else {
bb.motor.L->setSpeed(-(bb.cruiseSpeed - Output));
bb.motor.R->setSpeed(-(bb.cruiseSpeed));
}
} else { //Outside Perimeter
if ( (millis()-bb.perimeterSenoren.perimeterLastTransitionTimeB) > 2000 ) { // // If more than 2sec outside rotate full
bb.cruiseSpeed = 15;
bb.driveDirection = DD_ROTATECC;
bb.motor.L->setSpeed(-15);
bb.motor.R->setSpeed(15);
} else if ( (millis()-bb.perimeterSenoren.perimeterLastTransitionTimeB) > 1500 ) { // If more than 1.5sec outside rotate more aggressive
bb.motor.L->setSpeed(-(bb.cruiseSpeed+7));
bb.motor.R->setSpeed(-(-15));
} else if ( (millis()-bb.perimeterSenoren.perimeterLastTransitionTimeB) > 1000 ) { // If more than 1sec outside rotate aggressive
bb.motor.L->setSpeed(-(bb.cruiseSpeed+7));
bb.motor.R->setSpeed(-(-8));
} else {
bb.motor.L->setSpeed(-(bb.cruiseSpeed+10)); //5
bb.motor.R->setSpeed(-(bb.cruiseSpeed -25)); //30
}
}
return BH_RUNNING;
}
};
Wenn man sich die Bedienungsanleitung von Ambrogio anschaut, kann man auch innerhalb des Perimeters fahren und dann bei engen Passagen auf das Perimeterkabel wechseln. Weiterhin kann man ein Dreieckmuster in das Perimeterkabel verlegen und dem Robbi sagen, er soll auf die andere Seite des Rasens wechseln um den Weg zur Ladestation abzukürzen. Ggf. werde ich das Später noch umsetzen.