PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Asuro und Labyrinthe aus Linien - machbar?



desenfrenada
04.01.2006, 21:41
Hallo,

ich möchte meinem Asuro so programmieren, daß er aus einem kreisfreien Labyrinth herausfindet (also immer nächstlinken Weg nehmen). Die Idee war weiters, nur rechtwinklige Kreuzungen zuzulassen, damit man es vielleicht schaffen kann, nach 90° Kurven die Linie wiederzufinden. Sackgassen könnte man mit 180°-Wendungen lösen oder damit, der Sackgasse eine Schlaufe anzufügen, die den Roboter in die Richtung leitet, wo er herkam (hoffe, man kann sich das vorstellen). Das Ziel wird durch einen Gegenstand gekennzeichnet, dessen Erreichen wird mit PollSwitch() erkannt.

Verwenden möchte ich für alles die Linienfolgeeinheit (Erweiterungen der Hardware sollten nicht geschehen laut Aufgabenstellung), habe aber bis jetzt ziemliche Probleme damit, den Roboter auf der Spur zu halten.

Bis jetzt habe ich mal die Sensoren und die LED gegen Umgebungslicht abgeschottet, wie es im Forum mehrfach empfohlen wird, nun geht es schon etwas besser. Ich werde noch weiter mit den Werten rumprobieren, wollte aber doch mal in die Runde fragen, ob ihr die Idee für machbar haltet und wie gut eure Roboter im Linienfolgen sind und wo die Grenzen liegen, zum Beispiel, wie groß der Durchmesser von Kreisen sein soll, die der Roboter schafft.

Danke, desenfrenada

bekoeppel
04.01.2006, 22:06
Hallo desenfrenada,
wie stellst du dir das Labyrinth vor? Ich werde nicht ganz schlau aus deiner Beschreibung.
Fährt der Roboter einfach Linien nach, die sich verzweigen. Wenn eine Linie zu Ende ist das Ziel nicht gefunden wurde (d.h. PollSwitch nicht ausgelöst), fährt er zurück bis zur letzen Verweigung und probiert immer weiter?

Oder sind die "Wände" einfach Linien am Boden?

Bei der ersten Variante funktionniert dein Vorhaben mit grosser Wahrscheinlichkeit nicht, weil du mit zwei Helligkeitssensoren eine Verzweigung nicht (oder fast nicht) erkennen kannst.

Bei der zweiten Variante könnte es klappen, allerdings musst du da aber wissen, dass der Roboter immer ca. 2cm über die "Wand" hinausfährt, bis der Liniensensor die Linie erkennt hat.

Bei beiden musst du wissen, dass die Methode, immer den linken Weg nehmen, nur funktionniert, wenn du sicher bist, dass es keine Schleifen hat. Wenn du durch vorwärtsfahren und NIE drehen wieder an einen Punkt kommen kannst, an dem du schon warst, dann funktionniert deine Methode nicht.
Falls das der Fall wäre, müsstest du jeden genommenen Weg entweder am Boden markieren (was ohne zusätzlicher Hardware nicht geht) oder im Programm speichern (was eher schwierig wird, da du erstens nicht viel Speicher hast, was für grosse Labyrinthe nötig wäre, oder zweitens, dass der Roboter die Kreuzungen nicht voneinander unterscheiden kann).
Wenn der Roboter dann nämlich einen Weg nehmen will, den er markiert hat, weiss er, dass er dort schon vorher durchgegangen war und kann die nächste Verzweigung in Angriff nehmen.

lg beni

desenfrenada
04.01.2006, 22:16
Die Wände sind als Linien am Boden abstrahiert, ja. So wie hier:
http://www.cs.tuwien.ac.at/prolog/Von%20Labyrinthen%20zu%20Algorithmen_f.pdf
Folie neun.

Das Labyrinth ist per Definition kreisfrei, da muß die immer-links Variante funktionieren.

Die Kreuzungen sind genau im rechten Winkel angelegt, und jede Kreuzung ist so gestaltet, daß der Roboter mit BEIDEN Photosensoren über einen schwarzen Balken muß, also die Kreuzung erkennt, und stehen bleibt.
Dann soll er eine 90° LInkskurve machen, schauen ob die Linie weitergeht, falls nicht, zurückfahren in die Position vor der Linkskurfe, gerade aus schauen, und schließlich rechts.

Ich hoffe, das hat es besser beschrieben, wie das Labyrinth aussehen soll.

MSSputnik
04.01.2006, 23:19
Hallo,

ich denke schon, dass es möglich ist.

Probier doch erst mal, ob eine Kreuzung erkannt werden kann.

Wenn das möglich ist, dann sollte das ganze auch funktionieren, denn das suchen nach der weiterführenden Strecke halte ich auf jeden Fall realisierbar.

Martin

desenfrenada
05.01.2006, 08:10
Ich werde mich heute an die 90° Kurven machen. Mal schauen, ob ich das mit Odometrie oder einfach mit Motor anwerfen und sleep lösen kann.
Außerdem wären 180° Kurven (zum Umdrehen, für Sackgassen) ein Hit, denn meine ursprüngliche Idee (bei Sackgassen dem Roboter eine Schleife hinmalen, die ihn sanft in die ursprüngliche Richtung zurückführt) funktioniert nicht sehr gut, weil er die halbe Zeit aus diesen Schleifen entflieht. Ich verwende die LineDemo-Routine, die dem Selftest beiliegt, aber diese muß ich noch ziemlich verbessern, damit es vielleicht funktioniert.

Dazu muß ich mal mein Terminalprogramm "reparieren", damit ich die Helligkeitswerte auslesen kann (so much to do, so little time :)...

Danke fürs Feedback, hoffentlich kommt noch mehr.

Melitta

Manf
05.01.2006, 08:45
Du kannst ja das Labyrinth entsprechend Folie 4 aufzeichnen, nicht als Graph entsprechend Folie 9. Dann kannst Du an der Wand entlang gehen.
Im praktischen Fall wird der ASURO dann auf der Wand stehen, aber im Bewußtsein sich rechts dieser Wand im Gang zu befinden, in einem Gang der auf der anderen Seite auch eine Wand hat die er gerade nicht berührt aber von der er weiß wo sie ist.

Er nimmt dann natürlich auch nicht die Abzweigungen wahr die der Gang sonst noch hat.

Allgemein ist es praktisch sicher schwierig mit nur 2 Sensoren der Linie zu folgen, also bei Schwärzung den Kurs zu korrigieren und dabei gleichzeitig die Schwärzung zu erkennen, die eine Abzweigung darstellt.
Manfred

desenfrenada
05.01.2006, 09:02
@Manf: ach sooo *versteh* du meinst, den Roboter so zu programmieren, daß er merkt, sobald einer seiner Photosensoren "schwarz" registriert, ist er an einer Kreuzung oder in einer Sackgasse, steht also an einer Wand an. Stimmt, das ist wahrscheinlich nicht so empfindlich wie das Linienverfolgen.
Hm. Wenn ich die Gänge und Wände genügend breit mache - mal testen.
(dazu muß ich allerdings erstmal wieder Daten vom Roboter auslesen können... aber das ist ein anderer Thread :)

Danke für die Idee!

RedBaron
05.01.2006, 10:36
Hallo desenfrenada,

versuch doch einmal Folgendes mit den Linienfolgesensoren (Vorausetzung: die Wege im Labyrinth müssen so breit sein, dass der ASURO knapp darin drehen kann, sonst wird es etwas komplizierter (mit Rückwrtsfahren und so ...)):

a) linker Fototransitor dunkel, rechter hell: Der ASURO befindet sich auf einer Kante am linken Rand eines Gangs. Geradeaus fahren.

b) beide hell, der ASURO ist mitten im Gang oder auf einer Kreuzung: drehe nach links (auf der Hochachse, also linker Motor rückwärts, rechter Motor vorwärts mit gleicher Geschwindigkeit) bis der linke Fototransitor dunkel wird.

c) beide dunkel: am Ende einer Sackgasse. Drehe rechts bis der rechte wieder hell wird.

d) links hell, rechts dunkel: sollte eigentlich nicht auftauchen. Alle Lampen anschalten, anhalten und explodieren lassen :feuer .

Als Problem bleibt: Das Ende des Labyrinths zu erkennen und anzuhalten.

Gruß RedBaron

desenfrenada
05.01.2006, 10:43
Ich werd meine Erfahrungen und ERfolge hier posten, sobald ich wieder gscheit flashen kann.

@RedBaron: Ende wird durch einen Gegenstand, an den der Roboter mit einem Tastsensor anstoesst, gekennzeichnet.

Explodieren? *lol* Ich werd ein Benzinfaß draufschnallen!

RedBaron
05.01.2006, 13:01
... bleibt zu überlegen, wie du das Bezin entzündest. :-k Wenn dir nicht besseres einfällt, kannst du den ASURO ja rotieren lassen \:D/ . Reibung erzeugt Wärme...

Spass laß nach! So einfach wie oben beschrieben, geht es natürlich nicht. Jedes Gefährt hat einen leichten Drall. Dein ASURO wird nicht von allein auf einer Kante lang fahren. Da musst du schon einen Regler einbauen, der die Richtung nachjustiert. Machst du das nicht, wird der ASURO kurz über lang abdriften, d.h. z.B. mit beiden Sensoren auf die Linie fahren (beide dunkel, ohne dass das Ende einer Sackgasse erreicht wäre).

Wegen solch einer Regelung kannst du z.B. hier schauen:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=11818
Da du über eine Kante fährst, der linke Regler als Sollwert also einen Dunkelwert aufweist, müssen die Werte des linken Sensors invertiert werden (const - Messwert). Ansonsten sollte es funktionieren.

Über die Regelung muss du noch eine weitere Steuerung legen, die zum einen erkennt, in welchem Zustand sich das System befindet (a)-d), s.o.) und zum anderen dann zwischen den verschieden Aktionen wechselt (Linienfolgung, Linkdrehung, Rechtsdrehung, Anhalten, Explosion).

Das Ganze wird ein wenig dadurch erschwert, dass die Messwerte nicht so wirklich reproduzierbar sind. Du musst filtern. Es ist also nicht so einfach zu erkennen, ob du am Ende einer Sackgasse angelangt bist oder der ASURO ein wenig zu weit nach links abgekommen ist oder sich der Reflexionsgrad des Untergrunds geändert hat oder eine zufällige Messwertschwankung vorliegt oder oder ...

Gruß Red Baron

MSSputnik
14.01.2006, 20:43
Hallo,

habe ein paar Tage darüber nachgedacht :-k und 3 Abende lang programmiert [-o< .

Dabei ist dieses Video (http://www.muenchen-surf.de/MSRoboter/files/labyrinth.mp4) herausgekommen.

Ein bisschen Doku finet Ihr auch auf meiner Webseite (http://www.muenchen-surf.de/MSRoboter)

Martin

RedBaron
15.01.2006, 02:50
Hallo MSSputnik,

elegante Lösung!

Wie erkennst du eine Kreuzung? Beide Fototransistoren dunkel? Könntest du bitte diesen Teil deines Programms posten?

Vielen Dank Red Baron

MSSputnik
15.01.2006, 10:17
Hallo,

hier ist meine Funktion, die die Regelung und auch das Kreuzungserkennen erledigt.

Prinzipiell erkenne ich eine Kreuzung daran, das beide LEDs dunkel werden. Eine beendete Line erkenne ich daran das beide LEDs hell werden.



/* Schwellwerte für die Linienerkennung
* Achtung stark Lichtabhängig.
*/
#define LIGHT_HIGH_MID 0x55
#define LIGHT_MID_LOW 0x28

char golinie(int left, int right, unsigned char settings, int speeddif) {
unsigned char status=0;
int fehler=0;
unsigned int speedleft;
unsigned int speedright;
if (autoencode != ADC_RUN) RunADC(ADC_RUN);
encoder[ODLEFT] = 0;
encoder[ODRIGHT] = 0;
MotorDir(left>0?FWD:RWD,right>0?FWD:RWD);
while (run && (!gotSwitch || !(settings&RETURN_ON_SWITCH)) && encoder[ODLEFT] < abs(left) && encoder[ODRIGHT] < abs(right) && status != GREEN && (status!= RED || !(settings&GO_STOP_ON_CROSS))) {
if (count72kHz > 18) { // regelung in definierten Zeitabschnitten ausführen !!! Sleep in dieser Schleife verboten!!!
count72kHz = 0;
fehler = line[0] - line[1];
fehler *= LKP;
speedleft = BASESPEEDLEFT+speeddif+fehler;
speedright = BASESPEEDRIGHT+speeddif-fehler;
if (speedleft > 255) speedleft = 255;
if (speedleft < 65) speedleft = 65;
if (speedright > 255) speedright = 255;
if (speedright < 65) speedright = 65;
MotorSpeed(speedleft,speedright);
status = 0;
if (line[ODLEFT] < LIGHT_MID_LOW && line[ODRIGHT] < LIGHT_MID_LOW)
status = RED;
if (line[ODLEFT] > LIGHT_HIGH_MID && line[ODRIGHT] > LIGHT_HIGH_MID)
status = GREEN;
if (line[ODLEFT] >= LIGHT_MID_LOW && line[ODRIGHT] >= LIGHT_MID_LOW && line[ODLEFT] <= LIGHT_HIGH_MID && line[ODRIGHT] <= LIGHT_HIGH_MID)
status = YELLOW;
StatusLED(status);
}
}
if (settings & GO_STOP) MotorSpeed(0,0);
if (!run) return STOP_RUN;
if (gotSwitch && (settings&RETURN_ON_SWITCH)) return STOP_SWITCH;
if (status == GREEN) return LINE_LOST;
if (status== RED && (settings&GO_STOP_ON_CROSS)) return LINE_CROSS;
return GO_SUCCESS;
}


Hoffe das hilft.

Martin

RedBaron
15.01.2006, 16:51
Hi,

vielen Dank. Du (bzw. dein ASURO) erkennst eine Kreuzung bzw. ein Ende schon durch eine einzelne Messung. Ich habe irgendann einmal etwas ähnliches probiert (Linienende). Habe aber damals Mittelwerte über die Helligkeit gebildet und Mehrfachmessungen zum Erkennen einen Linienendes gemacht. War wohl ein bisschen kompliziert ...

Gruß Red Baron

desenfrenada
17.01.2006, 12:12
@Martin: ich muß mir das Video erst anschaun (Player..), aber Gratulation, daß es funktioniert.

Leider war ich jetzt ziemlich im Diplomstreß, aber die Woche geht sich wieder ein Programmiernachmittag aus.

lg Melitta

desenfrenada
18.01.2006, 22:58
Hm - Linienfolge, Kreuzung erkennen und Ziel erkennen funktionieren.
Aber ich steh grad ganz arg auf der Leitung - wie hast du die Kreuzungsliniensuche realisiert, also das Drehen zb. um maximal 50 Grad und gleichzeitiges Liniensuchen? Bitte um gedankliche Trittleiter.

Danke, lg Melitta

MSSputnik
19.01.2006, 07:28
Hallo,

ich versuche es mal zu erklären und gehe von 2 vorasusetzungen aus: Sollte das nicht der Fall sein, einfach die Punkte überspringen, die nicht zutreffen.
1. Du verwendest die originalen asuro libraries
2. Du hast sonst keine erweiterten selber geschrieben

Zuerst habe ich die erweiterten Asuro Libraries verwendet bzw. z.T. auch selber geschrieben um ein paar anpassungen zu machen. Wenn du diese Libraries verwendest, kannst du den Zustand der Odometrie Zähler und der Linienverfolgung gleichzeitig abrufen. Zu finden sind die Libraries auf Sourceforge oder hier im Forum.

Dann habe ich mir 3 Funktionen geschrieben, die die Programmierung total vereinfacht haben (War bei mir ein aHa Erlebnis \:D/ )

1. Fahre eine Linie. Dabei werden nur die Liniensenoren benutzt. (Habe ich oben glaube ich gepostet.)
2. Fahre nach Vorgabe. Dabei werden nur die Odometriezähler benutzt.
3. Suche Linie. Dabei werden die Odometriezähler benutzt um eine vorgegebene Bewegung (Geradeaus oder Kurve oder eben drehen) durchzuführen. Dabei werden aber gleichzeitig die Liniensenoren abegfragt und eben wie in der obigen Funktion Fahre Linie ausgewertet.

Aufgrund der Rückgabewerde der Funktionen kann ich erkennen, was passiert ist und dann entsprechend darauf reagieren.

Was ich auch noch gemacht habe ist natürlich beim Drehen nach Links. Ich drehe mich erst um 45° ohne auf eine Linie zu achten und dann um weitere 50° wo ich wieder auf die Linie achte. Ansonsten würde ich mich nicht drehen, wenn die Linie geradeaus weiter geht.

Ich hoffe, das hilft.

Martin

MSSputnik
19.01.2006, 07:35
@RedBaron

Das mit der Erkennung einer Linie auf das erste mal und nicht so wie du das gemacht hat hat natürlich den Vorteil, das es einfach ist. Hat aber auch den Nachteil, das es schon bei einer Falschmessung zu einem Fehler kommt.

Kannst auch im Video beobachten. Wenn der Asuro ganz Links auf dem Strich ist, macht er einmal den Fehler das er sich zu früh zurück dreht und damit den linken Teil zwiemal durchsucht.

Ausserdem habe ich festgestellt, das die Linienerkennung natürlich sehr stark vom Umgebungslicht abhängt. Es hat erst mal gar nix funktioniert als ich für das Video mehr Lampen aufgestellt habe um es heller zu machen. :-( Da mußte ich dann erst die Linienerkennung neu Kalibrieren, was bei mir nicht automatisch geschieht.

Martin

desenfrenada
19.01.2006, 09:00
@Martin: ja, danke das alles hilft mir sehr. Ich hab mir gestern noch gedacht, daß es eigentlich fast nur mit Hilfe der Odometrie gehen kann, codetechnisch ist mir dann aber nichts mehr Produktives eingefallen. Wenn du sagst, du hast gepimpte Libraries verwendet, die einen Odometrie und Linienmessung gleichzeitig kontrollieren lassen, dann werde ich mir die mal heraussuchen.
Eine Frage hab ich aber noch: hast du deine Odometrieeinheit geschirmt? Das war am Video nicht wirklich zu erkennen :)
Nach den Erfahrungen, die ich mit den Photosensoren gemacht habe, ist das Umgebungslicht ein arger Störfaktor...

Danke, lg Melitta

MSSputnik
19.01.2006, 10:53
Hallo,

ich habe meine Odometrie Sensorik so wie Arexx sie schuf :-)

aber ich habe die Schwellwerte deutlich anders gewählt als sie in den dortigen Funktionen angegeben sind.
Vorallem gibt es bei mir einen Unterschied zwischen Links und Rechts.
Irgendwo habe ich das schon mal gepostet (glaube ich). Ich werde es heute abend mal hier einstellen wie ich es realisiert habe (meine komplette ADC Funktion).

Ich habe allerdings meine Linieneinheit abgeschirmt. Ich habe einen Kartonstreifen genommen und den um alle 3 LED/Transitoren gewickelt. Damit erhalte ich eine bessere Ausleuchtung und eine Abschirmung vom Umgebungslicht.
Werde heute abend davon auch noch ein Bild einstellen.

Martin

MSSputnik
19.01.2006, 20:50
Hallo,

Hier erst mal meine ADC Routine:
Ist leicht abgeändert vom Original aber trotsdem danke an Rakke. Sein Code hat den Vorteil, das die Odometriesenoren im vergleich zu den anderen häufiger abgefragt werden und daher die Messung genauer wird.


/************************************************** *************************
SIGNAL (SIG_ADC)
Interuptfunktion zum Auswerten mehrerer ADC-Kanäle nach einer vorgebbaren
Konfigurationsliste. Zugriff auf global definierte Variablen für die ADC-Kanäle.

last modification:
Ver. Date Author Comments
------- ---------- -------------- ---------------------------------
beta1 31.03.2005 Robotrixer counting odometrie tics
sto1 29.07.2005 stochri Wheelspeed,hysteresis
rakke 20.12.2005 Rakke Konfigliste, glob. Var für Line, Bat etc
------- ---------- -------------- ---------------------------------

************************************************** *************************/
#define ADC_CTRL_MANYS 12 ///>Zahl der Stützpunkte der configliste

#define ADC_CTRL_ODO_LEFT 1
#define ADC_CTRL_ODO_RIGHT 0
#define ADC_CTRL_LINE_LEFT 3
#define ADC_CTRL_LINE_RIGHT 2
#define ADC_CTRL_SWITCHES 4
#define ADC_CTRL_BATTERY 5

// der folgende define erleichtert das berechnen des Wertes ADMUX.
// admux_pre_calc = (0 <<REFS1) // AVCC with external ...
// | (1 <<REFS0) // ... capacitor at AREF pin;
// | (1 <<ADLAR); // Ergebnis in ADCH, ADCL links ausrichten
#define ADMUX_PRE_CALC 0x60

const unsigned char adc_mux_config_list[ADC_CTRL_MANYS] = {
WHEEL_RIGHT,
WHEEL_LEFT,
IR_RIGHT,
WHEEL_RIGHT,
WHEEL_LEFT,
IR_LEFT,
WHEEL_RIGHT,
WHEEL_LEFT,
SWITCH,
WHEEL_RIGHT,
WHEEL_LEFT,
BATTERIE
};


SIGNAL (SIG_ADC)
{
// für die Odometrie:
static unsigned char flag[2]; ///> merkt sich für jede Seite, ob steigende oder fallende Flanke
static unsigned char adc_cnt=0; ///> Merker für die Auswertung
unsigned char adc_channel; ///> Kanal für die Auswertung

unsigned char side; ///> side = 0: linkes, side = 1: rechtes Rad
unsigned char adc_lo; ///> zum Zwischenspeichern des ADC_lo_Wertes
unsigned char adc_hi; ///> zum Zwischenspeichern des ADC_hi_Wertes
unsigned int temp; ///> Hilfsvariable

const unsigned char grenzlow[2]={167,142}; // {LL,RL}
const unsigned char grenzhigh[2]={173,148}; // {LH,RH}

static unsigned int switcheshist[4]={0,0,0,0};

// ADCL muss zuerst gelesen werden! Sonst können sich zwei Wandlungen überschneiden.
adc_lo= ADCL; // Zwischenspeichern des ADC-Wertes in temp. Variable
adc_hi= ADCH; // Zwischenspeichern des ADC-Wertes in temp. Variable

if(autoencode==ADC_RUN) // Aus Kompatibilitätsgründen und weil sehr praktisch für debugging wird autoencode weiter benutzt
{

adc_channel = adc_mux_config_list[adc_cnt]; // nachgucken: welcher Kanal wurde gerade gewandelt? Fürs bessere Verständnis als eigene Variable eingeführt. Wenns mal knapp wird, lässt sich hiereine sparen...

// Für die Auswertung je nach gewähltem Kanal unterschiedlich verfahren
switch(adc_channel)
{
// Odometriesensoren. Code von stochri weitgehend übernommen.
case ADC_CTRL_ODO_LEFT:
case ADC_CTRL_ODO_RIGHT:
/*
Unterscheidung nach steigender und fallender Flanke. Bei steigender Flanke wird
nur der encoder_counter der jeweiligen Seite hochgesetzt und das Flag für "gestiegene
Flanke" gesetzt.
Die Seite bestimmt sich aus "adc_channel". Da encoder[0] aus AD-Eingang=1 und encoder[1]
aus AD-Eingang=0 kommen, muss die Seite über XOR getauscht werden, um mit WEJA/stochri
kompatibel zu bleiben.
Wenn die Bytes mal ganz arg knapp werden, lässt sich hier eins sparen...
*/
side = adc_channel ^ 1;
// Hysteresis included 25.6.2005 stochri
if ( (adc_hi < grenzlow[side]) && (flag[side] == TRUE)) // falling edge
{
encoder[side] ++;
flag[side] = FALSE;
}

if ( (adc_hi > grenzhigh[side]) && (flag[side] == FALSE)) // rising edge
{
encoder[side] ++;
flag[side] = TRUE;
}
break;

// Liniensensoren. Liefert die gleichen Werte wie "LineData"
case ADC_CTRL_LINE_LEFT:
case ADC_CTRL_LINE_RIGHT:
side = (adc_channel & 0x01)^ 1; // nur das kleinste Bit vom adc_channel auswerten
temp = (((unsigned int)adc_hi)<<8) + ((unsigned int)adc_lo);
line[side] = temp>>6; // Ergebnis ist links ausgerichtet
break;

// Kollisionstaster. Liefert die gleichen Werte wie "Pollswitch" und funktioniert genauso gut. Hm.
case ADC_CTRL_SWITCHES:
temp = ((((unsigned int)adc_hi)<<8) + ((unsigned int)adc_lo))>>6; // align right
temp = (unsigned char)(((10240000L/(long)temp-10000L)*62L+5000L)/10000);
switcheshist[3] = switcheshist[2]; // shiftregister
switcheshist[2] = switcheshist[1]; // shiftregister
switcheshist[1] = switcheshist[0]; // shiftregister
switcheshist[0] = temp;
if (switcheshist[0] == switcheshist[1] && switcheshist[0] == switcheshist[2] && switcheshist[0] == switcheshist[3]) // nur wenn alle werte gelich sind, wird wert übernommen.
switches = temp; // ansonsten bleibt switches beim alten wert.
break;

// Batteriespannung. Liefert die gleichen Werte wie "Batterie" und funktioniert genauso gut. Der Vollständigkeit halber aufgeführt.
case ADC_CTRL_BATTERY:
u_Bat = (((unsigned int)adc_hi)<<8) + ((unsigned int)adc_lo);
u_Bat = u_Bat >>6;
break;
}

/*
ADC-MUX für die nächste AD-Wandlung auf den nächsten Kanal der Konfigliste umschalten.
*/
adc_cnt = adc_cnt + 1; // nächstes Listenelement
if (adc_cnt >= ADC_CTRL_MANYS) // Listenende erreicht?
adc_cnt = 0; // Dann von vorne anfangen!

ADMUX = ADMUX_PRE_CALC + adc_mux_config_list[adc_cnt];// aus der config-Liste den nächsten Kanal holen
}

/*
Schließlich noch die nächste Konversion starten: das ADSC-Bit wird nach Beendigung der Wandlung durch den
ATmega auf null gesetzt.
Dies muss außerhalb der "if(autoencode)" erfolgen, sonst wird der Interrupt nicht mehr ausgelöst!
Soll also - z. B. wenn die Zeit mal knapp ist - der Code "gekürzt" werden, dann über autoencode = 0 ausschalten.
*/
ADCSRA = ADCSRA | (1<<ADSC);
}// Ende der rakke'schen ADC-Interruptroutine


Und hier Bilder von meiner Linienverfolgungseinheit:
Damit bin ich eigentlich sehr zufrieden.

desenfrenada
26.01.2006, 01:16
*hmpf* gestaltet sich schwierig.
Martin, ich glaube, du hast die drei Tage wirklich sehr gründlich programmiert, hm?

desenfrenada
01.02.2006, 09:50
So... ich hab nach wie vor Probleme damit, die Kreuzungen korrekt abzuarbeiten. Vielleicht kann mir wer Tips geben, ich hab mit ganz naiven Annahmen gearbeitet, weil ich nicht soviel Zeit hab, mich tiefer einzuarbeiten.

Ich beschreib mal, was ich gemacht habe: die erweiterte asuro.c verwendet, die die Methode Turn() von Stochri und Andun enthält. Diese Methode hab ich kopiert und einen Liniencheck eingebaut. Also
- drehe links 30 Grad ohne Liniensuche
- drehe weiter 65 Grad, mit Liniensuche
- messe mit FrontLED on und off und rechne den absoluten Helligkeitswert heraus.
- ist dieser Wert unter dem Threshold von Schwarz (den ich vorher ausgemessen hab; ist sehr unterschiedlich auf beiden Seiten der Linienfolgeeinheit), so stoppe die Motoren und beende den Turn
- wenn nichts gefunden, drehe 275 Grad nach rechts mit Liniensuche.

Soweit der abstrakte Ansatz.

Ich drehe mit 90 Speed, damit der Roboter auch ja nicht zu schnell unterwegs ist und etwas übersieht.

Konkrete Fragen zu Problemen kann ich erst heut ab 14 Uhr stellen, weil ich da programmieren kann.
Falls es einstweilen Tips "Du, da gibts ein prinzipielles Problem..." gibt, bin ich sehr dankbar.
Ansonsten meld ich mich später wieder mit konkreten Fragen.

Danke für die Aufmerksamkeit :)
Melitta

MSSputnik
01.02.2006, 14:04
Hi,

prinzipiell habe ich an deinem Vorgehen nichts auszusetzen. Mache ich genau so.

Allerdings erkenne ich auch den Unterschied zwischen 1 LED steht auf Linie und Linie ist unterhalb des Asuro und ich breche mein Drehen dann ab, wenn die Linie unterhalb des Asuros ist.

Das geht deshalb, weil die Helligkeitsunterschiede jedes Fototransistors absolut und relativ zueinander immer unterschiedlich sind bei den Zuständen:
1. Keine Linie
2. Linie nur unter einem Fototransistor
3. Linie zwischen beiden Fototransistoren.

Martin

Tartarus
09.03.2006, 13:43
Hey MSSputnik, ich habe mit Begeisterung dein Programm ausprobiert. Als ich aber versucht habe, die Schwellenwerte für hell/dunkel anzugeben, habe ich die einzige Möglichkeit in der highlevel.c gesehen. Leider wird diese Datei meines Wissens in keinster Weise in den Quellcode des "eigentlichen" Programms mit einbezogen - und somit die Schwellenwerte nicht an den Roboter weitergegeben. Wie kann das sein? Bzw. wie bekommt man denn nun die richtigen Schwellenwerte "auf" den Roboter? ^^


Greetz, Michi

Vogon
09.03.2006, 14:33
Probier doch mal diese Moglichkeit.
Die Ermittlung der Schwellenwerte ist damit recht gut.
https://www.roboternetz.de/phpBB2/viewtopic.php?p=123226#123226

Tartarus
10.03.2006, 09:28
Vielen Dank für die Antwort, Vogon!
Leider hast du meine Frage etwas missverstanden. Die Schwellenwerte hab ich schon ermittelt, ich muss sie nur noch meinem Roboter "beibringen" und da steig ich nicht so wirklich durch, wenn ich ehrlich bin ^^

EDIT:
Ich habs geblickt... wer lesen kann, ist klar im Vorteil *g*
Allerdings ne andere Frage. Wie geht denn aus dem Programm hervor, dass der Roboter sich um z.B. 40° dreht? Bei mir macht der nämlich nur wirres Zeug :D
Ich bin jetzt nicht so der Überflieger was C-Programmierung angeht, von daher bitte ich um etwas Nachsicht ;)

MSSputnik
12.03.2006, 10:11
Hallo,

damit es alle mitbekommen. Die Schwellwerte für die Linienerkennung werden in der highlevel.h eingetragen.

/* Schwellwerte für die Linienerkennung
*/
#define LIGHT_HIGH_MID 0x55
#define LIGHT_MID_LOW 0x28


Und das Drehen um 40° wird über die Funktion 'go' erledigt.
Allerdings habe ich keine Umrechnung in einen Winkel eingebaut. Man kann hier nur 'ticks' also die Zahl der Farbwechsel auf der Odometriescheibe angeben. Bei mir sind ca. 30° 20 ticks oder so.
Damit solltes du 'go(27,-27,GO_STOP,-20)' angeben. (GO_STOP -> nach dem Drehen Motoren ausschalten. -20 -> Von der Basisgeschwindigkeit 20 abziehen für die Drehgeschwindigkeit)

Martin