PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Linienverfolgung für Asuro



Skank-One
26.01.2007, 08:44
Hallo Ich habe ein mittelschweres Problem.
Ich habe ein Linienverfolgungsprogramm für mein Asuro doch bekomme es nicht zum Anhalten. Ich habe es schon mit der Sleep Funktion und mit nem break versucht aber nix hilft.
Der Asuro fährt immer weiter die Linie entlang ohne irgendwie anzuhalten.
Könnt ihr mir Helfen?[/b]

damaltor
26.01.2007, 08:52
dafür ist ein linienverfolgeprogramm da.
-was genau ist das probem? wenn er anhalten soll, dann mach ihn aus.
-wie sieht dein code aus? poste mit em [code]button und beschreibe, was passieren soll.
-geh vor allem auf die funktionsweise des programms ein und sage, WAS an WELCHER STELLE passiert bzw nicht passiert, und WAS an WELCHER STELLE passieren sollte.

Skank-One
26.01.2007, 09:46
Ich habe ja ein Linienprogramm.
Mein Asuro soll die Linie entlang fahren und soll am Ende umkehren und die Linie wider zurück fahre.
Mein Quell Code für die Linien Verfolgung:

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

unsigned char speed;
int speedLeft,speedRight;
unsigned int lineData[2],zeit=0;
int x, xalt, don, doff, kp, kd, ki, yp, yd, yi, drest, y, y2, isum;
int x1, x2, x3, x4;

void FollowLine (void)
{
unsigned char leftDir = FWD, rightDir = FWD;
FrontLED(OFF);
LineData(lineData); // Messung mit LED OFF
doff = (lineData[0] - lineData[1]); // zur Kompensation des Umgebungslicht
FrontLED(ON);
LineData(lineData); // Messung mit LED ON
don = (lineData[0] - lineData[1]);
x1 = don - doff; // Regelabweichung
x = (x1+x2+x3+x4)/4; //Filter
x4=x3; x3=x2; x2=x1;
isum += x;
if (isum > 16000) isum =16000; //Begrenzung um Überlauf zu vermeiden
if (isum < -16000) isum =-16000;
yi = isum/625 * ki; //I-Anteil berechnen
yd = (x - xalt)*kd; // D-Anteil berechnen und mit
yd += drest; // nicht berücksichtigtem Rest addieren
if (yd > 255) drest = yd - 255; // merke Rest
else if (yd < -255) drest = yd + 255;
else drest = 0;
if (isum > 15000) BackLED(OFF,ON); // nur zur Diagnostik
else if (isum < -15000) BackLED(ON,OFF);
else BackLED(OFF,OFF);
yp = x*kp; // P-Anteil berechnen
y = yp + yi + yd; // Gesamtkorrektur
y2 = y/2; // Aufteilung auf beide Motoren
xalt = x; // x merken
speedLeft = speedRight = speed;
MotorDir(FWD,FWD);
if ( y > 0) { // nach rechts
//StatusLED(GREEN);
speedLeft = speed + y2; // links beschleunigen
if (speedLeft > 255) {
speedLeft = 255; // falls Begrenzung
y2 = speedLeft - speed; // dann Rest rechts berücksichtigen
}
y = y - y2;
speedRight = speed - y; // rechts abbremsen
if (speedRight < 0) {
speedRight = 0;
}
}
if ( y < 0) { // nach links
//StatusLED(RED);
speedRight = speed - y2; // rechts beschleunigen
if (speedRight > 255) {
speedRight = 255; // falls Begrenzung
y2 = speed - speedRight; // dann Rest links berücksichtigen
}
y = y - y2;
speedLeft = speed + y; // links abbremsen
if (speedLeft < 0) {
speedLeft = 0;
}
}
leftDir = rightDir = FWD;
if (speedLeft < 20) leftDir = BREAK; // richtig bremsen
if (speedRight < 20) rightDir = BREAK;
MotorDir(leftDir,rightDir);
MotorSpeed(abs(speedLeft),abs(speedRight));
}

int main(void)
{
unsigned char sw;
Init();
MotorDir(FWD,FWD);
StatusLED(GREEN);
speed = 150;
kp = 5; ki = 5; kd = 70; // Regler Parameter kd enthält bereits Division durch dt
sw = PollSwitch();
if (sw & 0x01)
{ki=5;}
if (sw & 0x02)
{speed = 200;}
if (sw & 0x04)
speed = 255;
if (sw & 0x08)
kd = 35;
if (sw & 0x10)
kd = 70;
if (sw & 0x20)
kd = 140;
FrontLED(ON);
LineData(lineData);
speedLeft = speedRight = speed;
while(1){
FollowLine();
StatusLED(GREEN); // zeigt durchlauf der Schleaife
FollowLine();
StatusLED(RED);
zeit++;
if(zeit>100) break; //

}
MotorSpeed(0,0);

return 0;
}

Mit der Status LED wollte ich anzeigen lassen ob er die Schleife auch wirklich durchläuft.
Macht er auch.
Blos mit dem break Befehl das funktioniert nicht.
Wie gesagt mit Sleep habe ich es auch schon probiert aber das ging auch nicht.
Ich weis jetzt auch nicht mehr.

damaltor
26.01.2007, 10:24
also was mir spontan auffällt, ist dass die main funktion nur ein einziges mal durchlaufen wird, wenigstens der teil mit den tastern. ist das absicht? warum? wofür sind die tasterabfragen da? eine einfache abfrage der PollSwitch.Funktion, ganz besonders kurz nach dem einschalten, ist sehr ungenau. meist werden falsche werte zurückgeliefert. verschiedene lösungen: mehrfahce abfragen, kurze pause davor (Sleep(216) ist etwa 3 ms), den kondensator bei den tastern (ich glaub c6) entfernen..

vielleicht schaffst du es, eine funktion LinieVerloren() zu schreiben, die durch kurzes, vorsichtiges hin- und herdrehen prüft, ob noch eine linie vorhanden ist. wenn ja, dann wieder FollowLine(), wenn nein, dann so lange drehen bis die linie wieder vorhanden ist.
in der while schleife würde dann sowas stehen:

StatusLED(GREEN);
FollowLine();
StatusLED(RED);
LinieVerloren();

dann weisst du, wenn die lampe grün ist, dann folgt er ihr ein stück, und wenn sie rot ist, prüft er ob sie nicht schon zu ende ist.
die funktion LinieVerloren() müsste
- den asuro eine FESTE zeit nach LINKS drehen, und dann wieder zurück, und prüfen ob in dieser zeit der RECHTE fototransistor einen sehr niedrigen wert geliefert hat (also über die linie gekommen ist).
- dann den asuro die GLEICHE ZEIT nach RECHTS drehn und dann prüfen, ob auch der LINKE fototransistor die linie "gesehen" hat (doppelte abfrage, ich weiss, aber doppelt hält besser =)
- wenn offensichtlich eine linie vorhanden ist, dann kann die funktion verlassen werden, in der while(1) schleife wird ja dann wieder FollowLine aufgerufen.
- wenn keine linie mehr vorhanden ist, dann muss der asuro sich so lange drehen, BIS wieder eine linie vorhanden ist. dann wird die schleife beendet, und mit FollowLine wird zurückgefahren.

wenn es dir nur darum geht, aus der while(1) schleife rauszukommen, dann mach doch einfach while(zeit<100) hin. sowie zeit>100 ist, wird die schleife dann beendet.
ABER:
vor dem return(0); muss dann nochmal while(1); hin (mit dem semikolon), damit das programm nie "beendet" wird. es kann sonst passieren, dass alte code-inhalte des speichers ausgeführt werden. der asuro sollte am ende, wenn er seine aufgabe erledigt hat, immer in einer while(1); schleife "eingefangen" werden.

Die Sleep-Funktion lässt den asuro einfach einige millisekunden den aktuellen zustand beibehalten, wenn er fährt, dann fährt er weiter, wenn er steht, dann bleibt er stehen. sie hat nichts mit "schlafen" im sinne von "anhalten" zu tun. die zeit, die er während dieser funktion nichts (neues) macht kannst du so ausrechnen:
Sleep(x);
x=anzahl der 72000stel sekunden
also z.B. Sleep(216) ist:
216*(1/72000)=216/72000=3/1000 also 3 tausendstel sekunden(millisekunden)

allerdings darf der wert in der funktion 255 nicht übersteigen. um also eine sekunde zu warten, würde folgendes gehn:
for(i=0;i<500;i++)
{Sleep(144)}
er wartet dann 500*144*1/72000 sekunden, also 1000 millísekunden, also eine sekunde. (aber auch nur ungefähr... eine sekunde reine wartezeit, plus "rechenzeit").

alternative:

lade dir die neue asuro lib runter, mit der funktion Msleep() kannst einfach die anzahl der zu wartenden millisekunden angeben.