PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Linienverfolgung... brauche hilfe



Fouwe
17.06.2009, 22:39
Hey ihr ich hab mich mal rangesetzt um ein linienverfolgungsprogramm zu schreiben bei dem man auch abbiegen kann (sollte :D)

Ich hab mir echt mühe gegeben bin aber noch anfänger deswegen können und sind auch noch einige fehler drin
könnt ihr mir pls etwas helefn damit ich es zum laufen bekomme?

Ich erkläre mal kurz wie ich mir es vorgestellt habe:
Der asuro wird auf eine schwarze linie gesetzt, die er dann nachfährt bis er zu einer unterbrechung ,eine weiße fläche, der linie kommt.
Hier wartet er auf einen befehl entweder "a" oder "d".
bei a soll er sich links an der linie orientieren bei d dementsprechend rechts.
nun soll er also halb auf der linie fahren.
beim linksabbiegen sieht es also so aus, dass der linke sensor über weißem boden und der rechte über schwarzem ist.
falls der linke sensor zu dunkel wird gibt er rechts mehr gas und wenn der rechts sensor zu hell wird gibt er links mehr gas
das macht er nun bis er wieder zu einer unterbrechung kommt (noch nicht umgesetzt) und dann fährt er wieder normal auf der schwarzen linie.

hoffe ihr könnt meine gedanken nachvollziehen und mir tipss geben denn so wie das programm im moment ist, läuft es nicht bzw. kann ich es nicht in eine hex datei verwandeln

ich danke euch schonmal im vorraus :)



#include "asuro.h"


#define SPEED 0x8F
#define LEFT_KEY 'a' // a links abbiegen
#define RIGHT_KEY 'd' // d rechts abbiegen

int speedLeft,speedRight;
unsigned int lineData[2];
int ADOffset;



void LineLeft (void) // Links von der Linie
{
speedLeft += 1; //dann links mehr Gas geben
if (speedLeft > 0xFE) speedLeft = 0xFF;
}

void LineRight (void) //Rechts von der Linie
{
speedRight += 1; //dann rechts mehr Gas geben
if (speedRight > 0xFE) speedRight = 0xFF;
}


void ASStop(void) // ASURO hält an
{
speedRight = speedLeft = 0;
FrontLED(OFF);
BackLED(OFF,OFF);
}

void TurnRight(void) // Asuro biegt rechts ab
{


GoTurn(4,0,100);
LineData(lineData);



if (lineData[0] > 200) // 200 ist geschätzt!!! ASURO ist zu weit rechts, also muss er rechts schneller
{
StatusLED(GREEN);
LineRight();
}
else if ( lineData[1] < 300) // 300 ist geschätzt!!! ASURO ist zu weit links er muss links schneller
{
StatusLED(RED);
LineLeft();
}
else
{
StatusLED(OFF);
speedLeft = speedRight = SPEED;
}
MotorSpeed(speedLeft,speedRight);


}



void TurnLeft(void) // Asuro biegt links ab
{


GoTurn(4,0,100);
LineData(lineData);

if (lineData[1] > 200) // 200 ist geschätzt!!! ASURO ist zu weit links, also muss er links schneller
{
StatusLED(GREEN);
LineLeft();
}
else if ( lineData[0] < 300) // 300 ist geschätzt!!! ASURO ist zu weit rechts er muss rechts schneller
{
StatusLED(RED);
LineRight();
}
else
{
StatusLED(OFF);
speedLeft = speedRight = SPEED;
}
MotorSpeed(speedLeft,speedRight);


}




int main(void)
{
Init();
// Variablen deklarieren
int i;
unsigned char j;
unsigned char cmd;



FrontLED(ON);
for (j = 0; j < 0xFF; j++) LineData(lineData);
LineData(lineData);
ADOffset = lineData[0] - lineData[1];
speedLeft = speedRight = SPEED;




while (1) // die ganze Zeit
{

LineData(lineData);

if (LineData[0] > 800 && LineData[1] > 800) // Wenn der ASURO über weißem Grund ist...
{
ASStop(); // ...dann anhalten und auf Knopfdruck warten...
// hier könnte ein Fehler sein, da der ASURO nur über weißem Boden kurz waretn würde und dann normal weiterläuft
cmd = 0;
switch (cmd)
{
case LEFT_KEY : TurnLeft(); break; // Wenn 4 dann links halten
case RIGHT_KEY : TurnRight(); break; // Wenn 6 dann rechts halten
}
}



else
{ // Normale Linienverfolgung
i = (lineData[0] - lineData[1]) - ADOffset;
if ( i > 4)
{
StatusLED(GREEN);
LineLeft();
}
else if ( i < -4)
{
StatusLED(RED);
LineRight();
}
else
{
StatusLED(OFF);
speedLeft = speedRight = SPEED;
}


MotorSpeed(speedLeft,speedRight);


}
return 0;
}

Ceos
18.06.2009, 09:20
für das abbiegen hätte ich nen tipp, lass denasuro einfach ein stück weiter fahren, so dass er in etwa mit der antriebsachse auf dem feld steht, dann lässt du ihn mit gegenläufigen motoren rotiern und erwartest einfach folgende helligkeitswechsel
(links abbiegen z.B.)
links dunkel, rechts dunkel
links hell, rechts dunkel
links hell, rechts hell
links dunkel, rechts hell (rotationsgeschwindigkeit verringern)
links dunkel, rechts dunkel

und fährst dann einfach weiter

Valen
18.06.2009, 16:50
Bei jeder while-Schleife durchgang, gleich fur den switch(cmd), wird cmd immer auf 0 gesetzt. Weil du keine andere Funktion verwendet hast um cmd 'a' oder 'b' zu machen wird er da immer weiter fahren. Wie bekommst deine Asuro den 'a' oder 'b' zeichen/'wert'? Uber IR oder wird einer seiner taster angeprellt? Ich sehe keine Pollswitch, oder SerRead oder ähnliche funktion dafur verwendet.

Fouwe
20.06.2009, 20:52
hi leute
ich bin echt am verzweifeln hab nur noch eine woche und es klappt einfach nicht wie ich es möchte...

hab das Programm von oben um einiges erleichtert...denke ich

aber es funktioniert immernoch nicht

ich habe es jetzt mit dem SerRead gemacht aber ich verstehe nicht genau wie das funktioniert, kann mir da jemand pls helfen
die funktion heißt ja:
SerRead(&cmd,1,0xFFFE);
was bedeutet hier das &cmd und das 0xFFFE?

und wenn der knopf auf der tastatur gedrückt wurde, soll der asuro ja die ganze zeit dieentsprechende funktion ausführen, muss ich da dann noch eine while schleife reinbauen, denn sonst macht er die funktion ja nur einmal bis das nächste zeichen kommt

und was für werte soll ich für hell bzw. für dunkel einstellen
was für zahlen ungefähr? also ist 100 noch einigermaßen hell oder schon dunkel

hier nochmal der neue code, bitte bitte helft mir


#include "asuro.h"
#include "asuro.c"
#include <stdlib.h>

#define SPEED 0x8F
#define LEFT_KEY 'a' // a links abbiegen
#define MIDDLE_KEY 's' // s mittig halten
#define RIGHT_KEY 'd' // d rechts abbiegen



unsigned int data[2];

volatile unsigned char switchPressed;


SIGNAL (SIG_INTERRUPT1)
{
unsigned int i;

DDRD |= SWITCHES; // Switches as Output
SWITCH_ON; // Output HIGH for measurement
ADMUX = (1 << REFS0) | SWITCH; // AVCC reference with external capacitor
for (i = 0; i < 0xFE; i++);

ADCSRA |= (1 << ADSC); // Start conversion
while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
i = ADCL + (ADCH << 8);

// und ab gehts --- fahr zurück
MotorDir(RWD,RWD);
MotorSpeed(200,200);
FrontLED(ON);
BackLED(ON,ON);
for (i = 0; i < 0xFFFD; i++); // Sleep does not work here

switchPressed = TRUE;
SWITCH_OFF;
DDRD &= ~SWITCHES; // Switches as Input => ext. Int 1
}






void TurnRight(void) // Asuro orientiert sich rechts
{


LineData(data);

if (data[0] > 100) // 300 ist geschätzt!!! ASURO ist zu weit rechts, also muss er rechts schneller
{
StatusLED(GREEN); //green
MotorSpeed(80,130); // rechts mehr Gas geben!
}

if ( data[1] < 200) // 500 ist geschätzt!!! ASURO ist zu weit links er muss links schneller
{
StatusLED(RED); //red
MotorSpeed(130,80);
}

else
{
MotorSpeed(100,100);

}

}



void TurnLeft(void) // Asuro orientiert sich links
{


LineData(data);

if (data[1] > 100) // 300 ist geschätzt!!! ASURO ist zu weit links, also muss er links schneller
{
StatusLED(GREEN); // green
MotorSpeed(130,80); // links mehr Gas geben!
}

if ( data[0] < 200) // 500 ist geschätzt!!! ASURO ist zu weit rechts er muss rechts schneller
{
StatusLED(RED); //red
MotorSpeed(80,130);
}

else
{
MotorSpeed(100,100);

}


}


void DarkLine(void) //normale Linienverfolgung
{



LineData(data);


if (data [0] > data [1] ) // links heller als rechts...
{
MotorSpeed(130,80); // ... dann links mehr Gas geben...
}


else
{
MotorSpeed(80,130); // ... sonst rechts mehr Gas geben!
}


}




int main(void)
{

unsigned char cmd;
unsigned char cmdold;

MotorDir(FWD,FWD);
Init();
FrontLED(ON);
StartSwitch();
sei();
while (1)
{

// cmd = 0;
SerRead(&cmd,1,0xFFFE);

cmdold = cmd;
switch (cmdold)
{

case LEFT_KEY : TurnLeft(); break; // Wenn a dann links halten
case MIDDLE_KEY : DarkLine(); break; // wenn s dann mittig halten
case RIGHT_KEY : TurnRight(); break; // Wenn d dann rechts halten
}





}

return 0;
}

Valen
20.06.2009, 21:07
Ich sehe du hast Init(); hinter den anruf von Motorspeed(,). Und den interupt funktion ( SIGNAL (SIG_INTERRUPT1) ) ist sehr langweilig mit viele for-warte schleifen. Den interupt sol nur bemerken das einer taste eingedruckt is, und das in einer globalen (volatile) variabele speichern. Aber das motor-commando und led anschalten an den main oder andere funktion uberlassen. Interupts mussen schnell sein!

[edit]Die interupt fur der 'taster'-pin hat auch einer hohere prioritat als den timer interupt. Weil deine 'taster'-interupt so lange dauert wird die timer-interupt solange nicht ausgefurt. Deswegen wirkt den sleep funktion nicht.

Fouwe
21.06.2009, 10:45
ja ich hab das einfach nur reinkopiert
ich weiß nicht genau was der macht aber das ist ja auch nicht das problem

ich möchte eher wissen wie eine funktion z.b. die TurnLeft-Funktion solange hintereinander ausgeführt wird, bis ein neues Zeichen über den Transceiver gesendet wird
sonst läuft sie ja nur einmal oder?

Valen
21.06.2009, 15:05
Mit interupts spielen ist nicht sehr ge-eignet fur anfanger. Wenn du das bestimmt braucht wurde ich dich den erweiterten lib emphelen. Da ist schon einer taster eingebaut. Aber vielleicht auch nicht empholen wenn du nur einer woche dafur hast.

Den parameter fur SerRead stehen doch in dem anleitung? Aber den "&cmd" und "0xFFFE" sind etwas ungewöhn. Den & ist ein spezielles zeichen in dem C-sprache womit den speicher-platz von dem cmd variabele ubermittelt wird, und nicht den inhalt von cmd. Ein zeichenketten besteht manchmahl aus mehr bytes dan einer solcher 'zeiger' (pointer im englisch) und ist damit nicht so effizient. Ein zeiger ist nur ein wenig bytes gross.

0xFFFE ist den 'time-out' wert. Also den anzahl von zeichen er wartet bis den funktion endet, ob genug zeichen emphangen sind oder nicht. Den 1 war die gewunschte lange den zeichenketten, also ist nur ein zeichen gewunscht. Den FFFE is einer hexadezimale nummer, gleich an 65534 decimahl. Das sind 655340 bits der den USART (serielen port) abwartet. Mit nur 2400 bits pro sekunde wirt das also 4,5 minuten warten. Wiso denn so lange? Mit 1 statt xFFFE mus es besser gehen.

Mit den while-schleife wird das emphangen einer zeichen und das 'switch'-en zwischen TurnLeft, DarkLine oder TurnRight sehr schnell wiederholt. Naja, nur mit einer viel kleinere timeout-wert im SerRead. Den TurnLeft/Right und Darkline messen nur den liniehelligkeiten und andern den motorkraft. Das dauert nur ein wenig zeit. Sehr oftes wechseln der motorkraft konnte fehlerhaft sein fur den elektronic auf dauer. Deshalb konntest du später (wenn das program klappt) einer verzögerung einbauen im TurnLeft, TurnRight und DarkLine mit Sleep. Aber nur einiger milisekunden.

Aber was er in diesen TurnLeft/Right funktionen tun soll verstehen ich nicht. Was meinst du genau mit links oder rechts orientieren?

Fouwe
21.06.2009, 15:43
ok schonmal danke dass du mir hilfst!!!

Der ASURO soll auf einer schwarzen Linie entlang fahren, auf der es Verzweigungen der Strecke gibt.
Wenn ich dann eine Taste auf der Tastatur drücke soll sich der asuro rechts bzw- links orientieren.
Das Bedeutet, dass die rechte LED über weißem Boden und die linke über schwarzem boden sein soll. dies wäre bei rechts orientieren der Fall

Valen
21.06.2009, 16:39
Die rechten und linkem 'led' ist keiner LED. Das sind verkleideten (photo)transistoren. :) Die arbeiten komplet anders.

Achso, du meinst den rand einer flache, und nicht eine linie. Ob das mit deine If regeln so geht weiss ich nicht genau. Jedenfals haben die beiden fototransistoren unterschiedliche licht/spannung kurven. Den linken und rechter site muss man erst abstimmen mit einander. Damit er nicht immer zu einer seite gezogen wird. Nur schätzten von den wert konnte viel zeit kosten bis es gut ist. Besser ist es die werten zu messen und mit SerWrite zuruck zu senden. Leider muss den wert in einzelne zeichen ubersetzt werden. Sonnst ist das nicht lessbar.

Das mit den switch und cmd wiederholung wird schon gut gehen. Nur eine kleine timeout wert im SerRead setzen. Ein 0 wird es auch blockieren. Schau das mal asuro.c an.

Edit: Etwas mehr uber das "&" zeichen... es wird fur mehrere zwecken gebraucht in dem c-sprache. Nicht nur die zeiger. Es ist auch einer logische operator. Einer einzelne "&" ist einer UND operation auf jeder bit. Einer doppelte ("&&") is eine logische UND operation. Aber in deine beispiel war das die adresse von cmd.

Fouwe
21.06.2009, 16:50
hmmm ob ich das schaffe...

was meinst du mit rand einer flache?

der asuro soll schon auf einer ganz normalen linie fahren

Valen
21.06.2009, 17:14
Das Bedeutet, dass die rechte LED über weißem Boden und die linke über schwarzem boden sein soll. dies wäre bei rechts orientieren der FallWie dick ist deine linie denn? Den leds (oops, fototransistoren ;) ) stehen ja kaum 1 centimeter auseinander. Den linie sollte bestimmt dicker sein fur deiner zweck. Sonnst wurde du es nicht bemerken.

Mit den rand einer flache mein ich das links von ihn nur schwarz ist, und den andere seite nur weiss. Oder anders herum. Eigentlich das selbe was du meinst, aber eine flache sieht gleich aus wie einer ganz breite linie fur Asuro's augen.

Fouwe
21.06.2009, 17:34
die Linie ist etwa 3cm dick

ich weiß nicht wie ich die helligkeit messen kann :(

hast du icq? wäre es möglich dass ich dich adden kann?

Valen
21.06.2009, 18:49
Doch, das weisst du, mit LineData! Steht schon in dein program. Du muss nur den werten data[0] und data[1] ubermitteln zum hyperterminal oder ahnliches program im rechner.

Und sieht hier was den such funktion gefunden hat (suchen nach SerWrite ):

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=41425&highlight=serwrite

Ich habe kein ICQ mehr, seit 10 jahren oder so. Beiseits das, deutsch schreiben geht mich sehr schwierig. Hier posten kostet mir schon einer ganzen zeit. Besser ist es jemand im deutschen sprache gebiet zu finden.