Das Ring Programm



Der Ring als obere Hauptkomponente des Roboters ist verantwortlich für die Ansprache der verschiedenen Sensoren und das Umwandeln der dazugehörigen Werte. Hierzu wurden unterschiedliche Prozeduren und Formeln entwickelt, um nutzbare Werte zu erhalten.

Ultraschall


Die Ultraschallsensoren werden durch einen Trigger angesprochen und senden ein Echo als Antwort. Der Wert, welcher dabei übermittelt wird, ist in Zentimetern angegeben. Der Wertebereich liegt dabei zwischen 0 und 255.

Kompass


Der Kompass stellte sich entgegen anfänglicher Vermutungen als einer der schwierigsten Komponenten heraus. Die übermittelten Rohwerte müssen erst durch eine Unterprozedur umgewandelt werden, um eine von einem geeichten Punkt aus ermessene Gradzahl anzugeben.

Infrarot


Die insgesamt sieben Infrarotsensoren geben jeweils eine Stärke des Signals an. Diese Stärke wird dann in einer Unterprozedur zu zwei Werten zusammengefasst: Richtung und Stärke. Dabei liegt der Bereich des Richtungswertes von -7 bis 7 und eine Stärke von 0 bis 4.

Median


Zusätzlich wurde, um mögliche fehlerhafte Werte zu vermeiden, ein Median integriert. Jeder Wert wird in einen für ihn angelegten Median geschickt, im Hauptprogramm werden nur besagte Medianwerte verwendet.
Wir verwenden hierzu den RunningMedian von robtillaart http://playground.arduino.cc/Main/RunningMedian
bzw. den FastRunningMedian von rkail: http://forum.arduino.cc/index.php?topic=53081.msg1160999#msg1160999

Sam Vogelskamp


Wie funktioniert das Master Programm?


1. Die Grundlage → Eine Loop


void loop()
{
lesen();
auswerten();
setze_modus();

In der Loop „liest“ das Programm (Prozedur: lesen();) zuerst die Werte von den IR und US Sensoren, sowie den Wert des Kompass aus, die er über den I2C – Bus von dem 2. Teensy bekommt und weist diesen den nötigen Variablen zu.

Im zweiten Schritt schreibt das Programm (Prozedur: auswerten();) die Werte, die gerade vorliegen, in die Ausgabe, sodass man diese über den Serial Monitor ablesen kann.

Zuletzt liest das Programm die Taster Werte (setzte_modus(); - Prozedur) und weißt jedem Wert, und somit jeder Taste einen individuellen Modus zu.

if (modus == 1) { eichfahrt(); }
if (modus == 2) { kalibrieren(); }
if (modus == 3) { handeln(); }
if (modus == 4) { aus(); }

Je nach dem welcher Modus aufgerufen wird startet eine bestimmte Prozedur.

delay(30);
}

Am Ende der Loop werden immer 30 ms gewartet, da die Werte am 2. Teensy nur alle 30 ms aktualisiert werden und es sonst zu überflüssigen Wiederholungen kommt.


2. Die Modi spezifischen Prozeduren


Modus 1 → Eichfahrt

void eichfahrt();
{
fahre(0,0,3);

Der Robotort dreht sich im Kreis solange...

for(int i=0; i<1500; i++)
{
comp_read_raw(comp_raw);
}

...bis er 1500 mal den Kompass ausgelesen und aktualisiert hat damit er alle Werte genauestens abschätzen kann.

aus();
}

Ist dies vollbracht schaltet er sich aus.

Modus 2 → Kalibrieren

void kalibrieren()
{
head=-comp_calc(0);
warteblink(1000);
modus=10;
}

Bei dieser Prozedur speichert der Roboter die aktuelle Ausrichtung als Kompass 0 ab und schaltet sich aus.

Modus 3 → Handeln

Dieser Modus ist der Einzige, der die Motoren ansteuert und die Befehle gibt, in welche Richtung der Roboter sich bewegen soll. Dies ist abhängig von der Position des Balles zum Roboter, dem Wandabstand und der Ausrichtung.
Im folgenden werde ich auf die einzelnen Fälle eingehen. Da der Roboter die selben Aktionen ausführt, egal ob der Ball vorne links im 45°, oder vorne rechts im 45° Winkel liegt, nur in die entgegengesetzte Richtung, beschränke ich mich hierbei auf die Aktionen, bei denen der Ball auf der rechten Seite des Roboters liegt.

Bevor aber die Fallunterscheidung im Bezug auf die Ballposition stattfindet, wird eine allgemeine Tempo Variabele festgesetzt, die angibt, wie schnell der Roboter in seinen Aktionen fahren soll.

Tempo=50;
// Im Normalfall soll der Roboter mit 50% der Max. Stärke fahren

if ((us1 < 25) || (us2 < 25) || (us3 < 25) || (us4 < 25))
{
// Ist der Roboter zu nah an der Wand wird das Tempo aus 30% der Ma. Stärke gesetzt
tempo=30;
}

1. Fall – Der Ball liegt vor dem Roboter:

if (ballrichtung == 0)
{
fahre(0,tempo,(-kompass/10));
}

Der Roboter fährt nach vorne und dreht sich gerade (Kompass 0), falls er schief stehen sollte.

2. Fall – Der Ball liegt direkt vor dem Roboter in der Einkerbung:

else if ((ballrichtung == 2) || (ballrichtung == -2))
{
if ((kompass > -3) || (kompass < 3))
// Der Roboter steht grade
{
if ((us2+10) < us4)
// Rechts vom Tor
{
if (us1<10) {fahre(0,0,-10);}
// Vor der Wand stehend -> drehen
else fahre(0,tempo,((-kompass/10)-2));
// Sonst nach vorne fahren mit Drehung links
}
else if ((us4+10) < us2)
// Links vom Tor
{
if (us1<10) {fahre(0,0,10);}
// Vor der Wand stehend -> drehen
else fahre(0,tempo,((-kompass/10)+2));
// Sonst nach vorne fahren mit Drehung rechts
}
}
else if (kompass < -3)
// Steht der Roboter schief nach links
{
if (us1<11) {fahre(0,0,15);}
// Und in der linken Ecke -> rechts drehen
else {fahre(0,0,(-kompass/10));}
// Sonst nach vorne fahren und gerade drehen
}
else if (kompass > 3)
// steht der Roboter schief nach rechts
{
if (us1<11) {fahre(0,0,-15);}
// Und in der rechten Ecke -> links drehen
else {fahre(0,0,(-kompass/10));}
// Sonst nach vorne fahren und gerade drehen
}
}
// Ende zweiter Fall

3. Fall – Der Ball liegt im 30° Winkel vorne rechts:

if (ballrichtung == 3)
{
fahre(60,tempo,(-kompass/10));
}

In diesem Fall soll sich der Roboter im 60° Winkel nach rechts bewegen und somit hinter den Ball fahren. Denn die grundlegende Strategie ist immer hinter den Ball zu kommen, um ihn nach vorne zu schieben.

4. Fall – Der Ball liegt im 45° Winkel vorne rechts:

if (ballrichtung == 4)
{
fahre (80,tempo,(-kompass/10));
}

Liegt der Ball bei Ballrichtung 4, fährt der Roboter im 80° Winkel auf den Ball zu.

5. Fall – Der Ball liegt im 90° Winkel rechts vom Roboter:

if (ballrichtung == 5)
{
fahre (120,tempo,(-kompass/10));
}

Liegt der Ball rechts auf gleicher Höhe, fährt der Roboter im 120° Winkel dahinter.

6. Fall – Der Ball liegt im 135° Winkel rechts hinter dem Roboter:

if (ballrichtung == 6)
{
fahre (180,tempo,(-kompass/10));
}

In diesem Fall fährt der Roboter nach hinten (180° Winkel).

7. Fall – Der Ball liegt gerade hinter dem Roboter:

if (ballrichtung == 7)
{
if (us2 < us4)
// Ssteht der Roboter rechts im Feld
{
fahre(-150,tempo,(-kompass/10));
// fährt er nach hinten links
}
else if(us2 > us4)
// Steht der Roboter links im Feld
{
fahre(150,tempo,(-kompass/10));
// fährt er nach hinten rechts
}
}

8. Fall – Der Ball ist nicht zu sehen:

if (ballentfernung == 0)
{
if (us3 < 20)
// ist der Abstand zur hinteren Wand gering
{
fahre(0,0,(-kompass/10));
// dann soll der Roboter sich gerade drehen
else
{
fahre (180,tempo,(-kompass/10));
// anderfalls fährt der Roboter nach hinten
}
}

Modus 4 → Ausschalten

void aus()
{
schreibeMotoren(0, HIGH, HIGH, 0, HIGH, HIGH, 0, HIGH, HIGH);
}

Alle Motoren werden in dieser Prozedur ausgeschaltet.





Bericht von Niklas Pengemann