PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Kollisionsprogramm über interrupt



sebär
29.10.2008, 22:06
Hi leute.

ich habe ein kleines projekt vor mit meinem asuro - und zwar für die
schule... habe noch 2 wochen zeit und nach viielen stunden vergebener arbeit
wende ich mich jetz hier an euch.

ziel: asuro soll einen beliebigen parcour mit wänden welche immer im rechten
winkel zueinander stehen durchfahren können.

lösungsansatz:

grundprogramm: asuro fährt geradeaus, registriert ein taster etwas springt er
in ein interruptprogramm

interruptprogramm: asuro macht standardmässig nach der kollision eine 90° drehung nach rechts und fährt weiter gerade aus, trifft er unmittelbar danach
wieder auf eine wand stellt er fest dass dies der falsche weg ist und dreht
sofort 180° (nicht 90°, weil er dann ja dahin zurückfahren würde woher
er zuerst kam). trifft er nach der ersten kollision nicht unmittelbar auf
etwas fährt er geradeaus weiter. die nächste kollision zählt wieder als 1.


frage: wie kann ich sowas in ein programm fassen? ich habe mit dem C+
inzwischen ein riesigen gedankenknäul und hab keine ahnung wie ich das
programm lösen soll...

wie bindet man ein interruptprogramm in ein hauptprogramm ein? und
wie löst man das problem dass er erkennt ob es das zweite mal hintereinander
ist dass er kollidiert oder ob es das erste mal ist?

hoffe auf antworten.
lg sebastian

Valen
30.10.2008, 14:14
Die lib erweiterung (sicher 2.71 und 2.8rc1,aber vielleicht auch orginal lib) hier im forum hat schön ein "interrupt service routine" fur die kollisiontaster eingestelt. Du kannst dah reinschauwen (switches.c un asuro.c) wie das gemacht ist. Die ISR setzt ein globale variable wenn er kontakt macht (und ISR wird 'abgeschaltet' fur neuere kollisionen ). Du kannst das in deiner main() program pollen und controlieren/testen mit 2xPollswitch (dannach ISR wieder reinstellen). Dan folgt deiner entscheidung links oder rechts zu drehen. Und dann wieder noch ein mall im endlos schleife reingehen.

sebär
30.10.2008, 22:26
hi danke für die hilfe.
könntest du das evt kurz skizzieren?

mit welchem befehl könnte ich das abfragen? und vor allem mit welchem befehl erkennt er das es das zweite mal in folge ist?

Valen
30.10.2008, 23:29
Im asuro.h (lib 2.8rc1) steht:


/*
* Tastsensor Wert bei Interrupt Betrieb. 0=keine Taste, 1= Taste gedrueckt
*/
/*!
* \~english
* \brief any switch pressed?
*
* is being set to TRUE by interrupt if a switch is pressed\n
* remember to set it to false again, since it is not reset automatically
* \see StartSwitch
*/
extern volatile int switched;

Also, etwas wie:


while (1) {
if (switched=True) CheckCollision();
switched=False;
StartSwitch();
if (collision)
{
...
do_something();
...
}
}
...

NOTE: CheckCollision(), do_something() und collision ist nur pseudo-code von mir... nicht im Lib zu finden.




Und fur 2 mal taster abfragen wie im KollisionTest example program:


...
while (1)
{
t1 = PollSwitch();
t2 = PollSwitch();
if (t1 == 0 && t2 == 0) /* keine Taste */
{
MotorFwd(); /* vorwärts fahren */
FrontLED(ON);
BackLED(OFF,OFF);
}
else if (t1 && t2 && t1 == t2)
{
MotorStop();
if (t1 & 0x07) /* Tasten links gedrückt? */
{
MotorRwdL(); /* Rückwärtskurve links fahren */
FrontLED(OFF);
BackLED(ON,OFF);
}
if (t1 & 0x38) /* Tasten rechts gedrückt? */
{
MotorRwdR(); /* Rückwärtskurve rechts fahren */
FrontLED(OFF);
BackLED(OFF,ON);
}
Msleep(1000); /* 1 Sekunde fahren */

}
...


Schau mal die Quell code an. Du muss nur selbst raus finden wie du die drehungen organisiert wenn ein kollision sicher erkannt ist.

nil.at
01.11.2008, 23:01
Sorry für die Frage, aber warum muss es eine Interruptroutine sein?
Ich würde es so machen:
while(true)
Asuro fährt
wenn Kollision
-> Stop und Drehen + Kontrollvariable setzen, eventuell kurz warten.
Danach wieder von vorne, das heisst Asuro fährt wieder los.
Falls es jetzt wieder zu einer Kollision kommt muss Asuro schaun ob die Kontrollvariable noch gesetzt ist. Wenn ja, 180° Drehung.
Wenn nein, 90° Drehung.
Die Kontrollvariable müsstest du nach einem gewissen Durchlauf wieder zurücksetzen. Mit sleeps würde ich nicht arbeiten, da für die "sleep-Zeit" der Programmablauf blockiert ist und somit auf eine eventuelle Kollision nicht reagiert werden kann.

Sternthaler
03.11.2008, 19:17
Hi sebär,

für M1.R hatte ich mal im Thread "Der ASURO als Wecker" eine 'kleine' Erklärung zusammengestellt wie man mit Interrupts umgeht.
Eventuell hilft dir die Beschreibung unter: https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=336794#336794
Es ist keine Lösung für ein bestimmtes Problem, sondern beschreibt allgemein, wie man vorgehen muss/sollte wenn man Interrupts nutzen will.

Viel Erfolg, und herzlich willkommen im Forum.
Gruß Sternthaler

sebär
09.11.2008, 09:49
so hab mich jetz endlich mal am sonntag morgen in ner freien stunde hingesetzt und das interruptzeugs mal durchgeackert. so sieht der quellcode jetz aus.

aktuelle funktion: fährt wo rein und dreit dann rechts zurück.


#include "asuro.h"

#define FULL_L 240
#define FULL_R 220



void Fahren(void) /* Vorwärts fahren */
{
StatusLED(GREEN);
BackLED(OFF,OFF);
MotorDir(FWD,FWD);
MotorSpeed(FULL_L,FULL_R);

}


void Zurueck(void) /* Zurück fahren */
{
StatusLED(YELLOW);
BackLED(ON,ON);
MotorDir(RWD,RWD);
MotorSpeed(FULL_L,FULL_R);
}


void KurveLR(void) /* Kurve rückwärts Links */
{
StatusLED(YELLOW);
BackLED(ON,OFF);
MotorDir(RWD,RWD);
MotorSpeed(FULL_L,0);
}


void KurveRR(void) /* Kurve rückwärts Rechts */
{
StatusLED(YELLOW);
BackLED(OFF,ON);
MotorDir(RWD,RWD);
MotorSpeed(0, FULL_R);
}


void Anhalten(void) /* Anhalten */
{
StatusLED(RED);
BackLED(OFF,OFF);
MotorSpeed(0,0);
}



int main (void)
{
Init ();
switched = 0;
StartSwitch ();
while (1)
{
if (switched == 1)
{
Anhalten();
Msleep(250);

Zurueck();
Msleep(250);

Anhalten();
Msleep(250);

KurveRR();
Msleep(1000);

Anhalten();
Msleep(250);

switched = 0;
StartSwitch ();
}

else

Fahren();
}

return 0;

}


sodele. soweit so gut - habs noch nicht testen können - asuro is in der schule und ned bei mir zuhause, aber weiter im text!

folgendes problem: wie kann asuro entscheiden ob er zum ersten mal wo reingefahren ist oder ob er unmittelbar zuvor schon eine kollision hatte?

das ziel ist, dass falls es das erste mal war, dass er die 90° zurück macht standardmässig. falls es das zweite mal ist soll er eine 180° drehung machen.

ich bitte um ziemlich ausführliche erklärungen :S bin noch absoluter noob was C angeht.

danke schon im voraus

lg sebastian

nil.at
09.11.2008, 23:02
Also in normalen C würdest du das am Besten mit nem Thread lösen. Sowas gibts bei µC aber nicht, also kannst du nur "hintereinander" statt "gleichzeitig" Kollisionen abfragen. Allgemeine Lösung wäre eine Kontrollvariable, siehe dazu meinen Lösungsansatz weiter oben.
Problem bei der Abfragung "hintereinander": Der weitere Programmablauf wird blockiert. Bei Threads könnte das normale Programm weiterlaufen während die Abfrage durchgeführt wird.
Bitte um Entschuldigung falls die Beschreibung etwas umständlich war, bin hunde müde.
Also im Prinzip nochmal kurz gefasst, einfach ne Variable nach dem zusammenstoss setzen, den Ausweichvorgang durchführen, dann wieder losfahren und nen "time" abwärtszählen lassen. Wenn er auf 0 ist, die Kontrollvariable rücksetzen, was einen zusammenstoss nach längerer Zeit bedeuten würde. Falls der Zusammenstoss erfolgt während die Variable noch gesetzt ist, war es ein direkt nach dem ersten Kontakt folgender Zusammenstoss. Und das angesprochene Problem dabei: Wenn der Zusammenstoss genau dann erfolgt, während die Routine wartet (um die Variable runterzuzählen) kann nicht darauf reagiert werden, weil das Programm blockiert.
So, ab ins Bett :)

Sternthaler
10.11.2008, 19:33
Hi sebär,

wenn du immer abwechseln mal 90° und 180° drehen möchtest, benötigst du eine Variable, die einfach nur hochzählt, wenn du ein Hindernis findest und drehen willst/musst.
Ist der Wert gerade, dann 180°, sonst 90°.

Such mal im angepassten Code nach 'zaehler'.

#include "asuro.h"

#define FULL_L 240
#define FULL_R 220



void Fahren (void) /* Vorwärts fahren */
{
StatusLED (GREEN);
BackLED (OFF, OFF);
MotorDir (FWD, FWD);
MotorSpeed (FULL_L, FULL_R);
}


void Zurueck (void) /* Zurück fahren */
{
StatusLED (YELLOW);
BackLED (ON, ON);
MotorDir (RWD, RWD);
MotorSpeed (FULL_L, FULL_R);
}


void KurveLR (void) /* Kurve rückwärts Links */
{
StatusLED (YELLOW);
BackLED (ON, OFF);
MotorDir (RWD, RWD);
MotorSpeed (FULL_L, 0);
}


void KurveRR (void) /* Kurve rückwärts Rechts */
{
StatusLED (YELLOW);
BackLED (OFF, ON);
MotorDir (RWD, RWD);
MotorSpeed (0, FULL_R);
}


void Anhalten (void) /* Anhalten */
{
StatusLED (RED);
BackLED (OFF, OFF);
MotorSpeed (0 ,0);
}



int main (void)
{
unsigned char zaehler = 0;

Init ();
switched = 0;

StartSwitch ();

while (1)
{
if (switched == 1)
{
zaehler++;

Anhalten ();
Msleep (250);

Zurueck ();
Msleep (250);

Anhalten ();
Msleep (250);

KurveRR ();
if (zaehler & 0b00000001)
Msleep (1000);
else
Msleep (2000);

Anhalten ();
Msleep (250);

switched = 0;
StartSwitch ();
}
else
Fahren ();
}

return 0;
}
Das "if (zaehler & 0b00000001)" prüft nur, ob das letzte Bit in der Variablen gesetzt ist. Das reicht aus um entscheiden zu können ob die Zahl gerade oder ungerade ist.
Du brauchst auch keine Angst vor dem "zaehler++" zu haben. Damit wird nur folgendes gemacht "zaehler = zaehler + 1;"
Und wenn der Wert in zaehler von 255 nochmal um eins erhoeht wird, dann passiert in C kein Fehler, obwohl der Wert ja eigentlich auf 256 gehen will, die Variable aber nur von 0 bis 255 geht.
Der Wert wird einfach wieder auf 0 gesetzt und schon geht es weiter.

Viel Erfolg und
Gruß Sternthaler

P.S.: Wenn du demnächst selber wieder Programmcode posten möchtest, schreib bitte ein [ code ] vorher und hinterher ein [ /code ]
ABER OHNE die Leerzeichen in den Klammern.
Dann bekommst du auch so ein schönes Kästchen wie hier gerade, und die Formatierung bleibt erhalten.

hai1991
11.11.2008, 15:16
hallo zusammen

@sternthaler:
also wenn ich das richtig verstanden habe muss sebär nicht einmal 90°, 180°, 90°... sondern nur dann 180° wenn innerhalb einer best. zeit ein taster gedrückt wird.
daher glaube ich, dass dein version nicht wirklich passt (sry)

sondern man müsste irgend wie eine zeit abfage einbauen. ich weiß nur nicht, ob es solch eine möglichkeit gibt, wie ich sie mir grade vorstelle.
da müsste ich nämlich nach einer kollision und erfolgter 90°-kurve die aktuelle zeit abrufen (hoffe es gibt eine funktion die die zeit zurückliefern kann, welche seit dem letzten einschalten vergangen ist), diese in eine variable speichern und bei der nächsten kollision wieder die aktuelle zeit abrufen und schauen ob es noch in einer vorgegebenen zeit ist ( dh. 2. kollison mit wand, daher 180°dreheung), oder ob schon zu viel zeit vergangen ist und er wieder mit einer 90°drehung "anfangen" soll.

ich hoffe das war verständlich

sebär
11.11.2008, 16:46
hai1991 hat das erkannt: ich ha bne skizze gemacht damit das ganz klar ersichtlich wird :-)

er soll prinzipiell zwischen rechts und linkskurve unterscheiden können.

die skizze ist im anhang zum download frei :-)


http://s2b.directupload.net/images/081111/mdd9ot7f.jpg

Sternthaler
12.11.2008, 20:37
Hi, zusammen,

ja, bei dieser Konstellation, muss ich euch Recht geben.
Na, dann bleibt ja noch der Timer-Interrupt, der so lustig vor sich hinzählt.

Da Msleep() benutzt wird, sehe ich, dass die Asuro-LIB benutzt wird.
Dort gibt es eine Funktion á la "HoleZeitInMSSekunden".
Hier ein ganz, ganz grober Rahmen. (Ich muss noch Arbeiten. hoffe es sieht jetzt kein Chef rein ;-))

long letzter_kontakt = 0;
long vor_letzter_kontakt;

if (switched == 1)
{
vor_letzter_kontakt = letzter_kontakt;
letzter_kontakt = "HoleZeitInMSSekunden";
if (letzter_kontakt > (ODER <??) vor_letzter_kontakt + (ODER -??) 100bisNochMehrMillisekunden)
variable_fuer_grad = 90; (Oder besser hier 180)
else
variable_fuer_grad = 180; (und dafuer hier nur 90?? ;-))

...
...
}

Gruß Sternthaler

P.S.: Schöne Zeichnung sebär. Nun schaffe ich es auch dein Problem zu 'sehen'. Hab leider nur schlamperlich deinen Text gelesen.

sebär
12.11.2008, 21:52
wir haben das problem anders lösen können :-)
werde morgen den quelltext posten, damit ihr auch was davon habt, hab ihn aktuell nur aufm laptop in der schule und nicht hier zuhause ;)

danke für die viele hilfe!!
lg

sebär
14.11.2008, 14:46
sooo, hier unser finaler quellcode!
einige extras (z.b. Disco-funktion) haben wir zusätzlich noch eingebaut.


################################################## ##########################################
### - FloBa Productions Inc. proudly presents: ASURO Parcourprogramm - ###
### - Ausgelegt für Parcours mit rechten Winkeln - ###
### - Asuro sollte auf einer hellen Fläche fahren um Ziellinie zu erkennen - ###
### - Programm zur öffentlichen Verwendung, Missbrauch* wird geahndet - ###
### - * zum Beispiel schlechte Kritik - ###
### - Fehler sind ausschliesslich auf Hardware und Batterie zurückzuführen - ###
### - Viel Vergnügen beim Spielspass wünscht das Asuro-Care-Team - ###
################################################## ##########################################




#include "asuro.h"

#define FULL_L 200
#define FULL_R 202


volatile unsigned int i;

void Fahren(void) /* Vorwärts fahren */
{
StatusLED(GREEN);
BackLED(OFF,OFF);
MotorDir(FWD,FWD);
MotorSpeed(FULL_L,FULL_R);
}

void Anhalten(void) /* Anhalten */
{
StatusLED(RED);
BackLED(OFF,OFF);
MotorDir(BREAK,BREAK);
}

void Zurueck(void) /* Zurück fahren */
{
StatusLED(YELLOW);
BackLED(ON,ON);
MotorDir(RWD,RWD);
MotorSpeed(FULL_L,FULL_R);
}


void KurveLR(void) /* Kurve rückwärts Links */
{
StatusLED(YELLOW);
BackLED(ON,OFF);
MotorDir(RWD,RWD);
MotorSpeed(FULL_L,0);
}


void KurveRR(void) /* Kurve rückwärts Rechts */
{
StatusLED(YELLOW);
BackLED(OFF,ON);
MotorDir(RWD,RWD);
MotorSpeed(0, FULL_R);
}

void KurveRF(void) /* Kurve vorwärts Rechts */
{
StatusLED(YELLOW);
BackLED(OFF,OFF);
MotorDir(BREAK,FWD);
MotorSpeed(0,FULL_R);
}

void Firstcol(void) /* Programm Rechtskurve im Parcour 1. Kollision */
{
Anhalten();
Msleep(250);

Zurueck();
Msleep(15);

Anhalten();
Msleep(10);

KurveRR();
Msleep(400);

Anhalten();
Msleep(250);

switched = 0;
StartSwitch ();
}

void Secondcol(void) /* Programm Linkskurve im Parcour, 2. Kollision */
{
Anhalten();
Msleep(250);

Zurueck();
Msleep(10);

Anhalten();
Msleep(250);

KurveLR();
Msleep(355);

Anhalten();
Msleep(250);

KurveRF();
Msleep(355);

Anhalten();
Msleep(250);

switched = 0;
StartSwitch();
}

void Thirdcol(void) /* Programm Sackgasse im Parcour, 3. Kollision */
{
Anhalten();
Msleep(250);

Zurueck();
Msleep(10);

KurveLR();
Msleep(310);

Anhalten();
Msleep(250);

switched = 0;
StartSwitch();

}

void Disco(void) /* PARTYTIME! -15mal blinken/piepsen-*/
{

for(i = 0; i < 16; i++)
{
MotorDir(FWD,FWD);
MotorSpeed(50,50);
BackLED(OFF,OFF);
StatusLED(OFF);
FrontLED(OFF);
Msleep(200);

MotorDir(BREAK,BREAK);
BackLED(ON,ON);
StatusLED(RED);
FrontLED(ON);
Msleep(200);
}


}


int main (void) /* Hauptprogrammbeginn */
{
unsigned int data[2]; /* Speicherplpatz für Helligkeitswert */
unsigned int Summe;
Init ();
switched = 0; /* Kollisionserkennung auf 0 setzen */
StartSwitch (); /* Taster-Interrupt aktivieren */
FrontLED(ON);
LineData(data); /* Speichern von Helligkeitswert in data[0,1] */
Summe = data[0]+data[1]; /* Summe der Werte beider Fototransistoren */


while (1)
{
if (switched == 1) /* Wenn 1. Kollision, dann Rechtskurve 90° aus */
{

Firstcol();

for(i = 0; i < 25000; i++) /* Setze Zeitschlaufe für 2. Kollision */
{
if (switched == 1) /* Wenn 2. Kollision, dann Drehung 180° */
{
Secondcol();

for(i = 0; i < 25000; i++) /* Setze Zeitschlaufe für dritte Kollision */
{
if (switched == 1) /* Wenn 3. Kollision, dann Linksdrehung 90° */
{
Thirdcol();
}

else /* Keine 3. Kollision, Fahre normal */
{
Fahren();
}


}

}

else /* Keine 2. Kollision, Fahre normal */
{
Fahren();
}


}



}

else /* gar keine Kollision, Fahre normal, Stopp bei Linie */
{
LineData(data);
if(data[0]+data[1]+10 > Summe) /* Untergrundhelligkeitsdifferenz feststellen */
{
Fahren();
}
else
{
Disco(); /* Party gut - Alles gut */
while(1)
{} /* Endlosschleife - Ende des Programmes */
}
}
}

return 0;

}



danke für die ganze hilfe :-)
lg

ezo2k3
06.01.2009, 18:49
wollte den code mal testen .. kriege folgende fehlermeldung .. kann mir wer weiter helfen



>Session Environment Variables:
AF_AVRDIR=C:\WinAVR
AF_PROJECT=Project1
AF_SOURCE_FILES=new.c
AF_ASM_SRC_FILES=
AF_PRGDIR=C:\Program Files\AsuroFlash
AF_PRJDIR=C:\ProgramData\AsuroFlash
AF_LIB_PATH=%AllUsersProfile%/AsuroFlash/asuro-lib/lib
File new.c saved.
>Default make_all.cmd file created.
>Default makefile created.
Make
C:\ProgramData\AsuroFlash>C:\WinAVR\utils\bin\make all
set -e; avr-gcc -MM -mmcu=atmega168 -DF_CPU=8000000UL -I. -g -Os -IC:\ProgramData/AsuroFlash/asuro-lib/lib/inc -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-ahlms=new.lst new.c \
| sed 's,\(.*\)\.o[ :]*,\1.o \1.d : ,g' > new.d; \
[ -s new.d ] || rm -f new.d
-------- begin --------
avr-gcc --version
avr-gcc (WinAVR 20081205) 4.3.2
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

avr-gcc -c -mmcu=atmega168 -DF_CPU=8000000UL -I. -g -Os -IC:\ProgramData/AsuroFlash/asuro-lib/lib/inc -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-ahlms=new.lst new.c -o new.o
avr-gcc -mmcu=atmega168 -DF_CPU=8000000UL -I. -g -Os -IC:\ProgramData/AsuroFlash/asuro-lib/lib/inc -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-ahlms=new.o new.o --output Project1.elf -Wl,-Map=Project1.map,--cref -LC:\ProgramData/AsuroFlash/asuro-lib/lib -lm -lasuro168
new.o: In function `main':
C:\ProgramData\AsuroFlash/new.c:152: undefined reference to `Init'
make: *** [Project1.elf] Error 1


ExitCode 2
>Ready.

Sternthaler
06.01.2009, 19:48
Hallo ezo2k3,

als erstes solltest du einmal die '\'-Zeichen in deinen Pfadangaben gegen das '/'-Zeichen tauschen.
Möglicherweise gibt es ein Problem, wenn eine Mischform, wie bei:
-IC:\ProgramData/AsuroFlash/asuro-lib/lib/inc
-LC:\ProgramData/AsuroFlash/asuro-lib/lib
entsteht.

Auch immer seeeehhhhr Kritisch sind Pfadangaben mit Leerzeichen im Namen.
Das hast du bei der Variablen AF_PRGDIR=C:\Program Files\AsuroFlash
Du solltest Verzeichnisse mit Sonderzeichen im Namen in dieser Umgebung unbedingt vermeiden.

Viel Erfolg und Gruß
Sternthaler