PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Probot 128 probleme mit multithreading



sebroos
03.01.2011, 23:17
hi

ich habe mal zum test ein programm geschrieben. Dabei soll der Roboter auf händeklatschen reagieren. beim ersten klatschen sollen zwei LEDs blinken und beim 2ten mal klatschen soll der bot sich hin und her drehen. damit er beim ausführen der aktionen auch weiterhin seinen MIC eingang beobachtet habe ich hierzu Multithreading angewendet.
nun habe ich aber ein problem, da wenn ich 2 mal in die hände geklatscht habe dann bewegt sich der bot kaum von der stelle. und beim nächsten mal klatschen bewegt er sich wieder ein stück obwohl er dann komplett ewieder in ruhestellung fahren sollte. ich habe das gefühl das durch die akustische signalisierung der trtead erst wieder angestoßen wird... aber deim thread Licht klappt alle wunderbar.... könnt ihr mir helfen?

im anhang habe ich den Quelltext....

danke im vorraus..



//************************************************** ************
//
// Wackeln
// Erstes Programm 30.12.2010
// Probot lauscht:
// beim ersten klatschen -> Blinken
// zweitem klatschen -> Tanzen
// dritten klatschen -> Ruhe
//
//************************************************** ************

#define LLF 16
#define RLF 17
#define LLB 18
#define RLB 19
#define MIC 43

word x; // globale variablen erstellt
int count;
void main(void)
{
DRIVE_INIT(); // Drive initalisieren siehe PRO-BOT128_Lib
count=0; // setzte den KLatschzähler auf 0
Port_DataDirBit(LLF,1);
Port_DataDirBit(RLF,1); // initaliesiere die LEDs
Port_DataDirBit(LLB,1);
Port_DataDirBit(RLB,1);
Thread_Delay(100); //Konfiguriere die ports als ausgänge und warte ne sekund

Port_WriteBit(LLF,0);
Port_WriteBit(RLF,0);
Port_WriteBit(LLB,0);
Port_WriteBit(RLB,0);

Thread_Delay(50);
Port_WriteBit(LLF,1); //LEDs aufblinken lassen zum signalisieren das es jetzt los gehen kann
Port_WriteBit(RLF,1);
Port_WriteBit(LLB,1);
Port_WriteBit(RLB,1);

while(1==1) //endlosschleife
{
x=GetADC(3); //schreibe den Wert vom MIC in x

if (x>600) //wenn x größer 600...
{
count++; //...zähle hoch
Thread_Delay(10);
}
switch(count)
{
case 0: break; //counter = 0 nix
case 1: Thread_Start(1,Light);count++;break; //counter = 1mal geklatscht -> Thread Light starten. counter eins hoch zählen damit der thread nicht immer gestartet wird.
case 2: break;
case 3: Thread_Start(2,Fahr)/*Fahr()*/;count++;break; //counter =3 -> 2mal geklatscht. Thread Fahr
case 4: break;
default:
count=0;

Thread_Kill(1);
Thread_Kill(2); //wenn counter größer als 4 oder undefiniert dann schliße
Port_WriteBit(15,0); // beide threads und schalte alle LEDs aus
Port_WriteBit(LLF,1); //EN ausgang für motoren wird abgeschaltet
Port_WriteBit(RLF,1);
Port_WriteBit(LLB,1);
Port_WriteBit(RLB,1);
}
}

}

word GetADC(int adr) //ließt wert aus ADC eingang aus
{
ADC_Set(ADC_VREF_BG,adr);
return ADC_Read();
}

void Light(void) //Light funzt... aber LEDs sind vertauscht.... ?!
{

while(1)
{
// Port_WriteBit(LLF,1);
// Port_WriteBit(RLF,1);
Port_WriteBit(LLB,1);
Port_WriteBit(RLB,1);
Thread_Delay(250);
// Port_WriteBit(LLF,1);
// Port_WriteBit(RLF,1);
Port_WriteBit(LLB,0);
Port_WriteBit(RLB,0);
Thread_Delay(250);
}
}

void Fahr(void) //funktioniert nicht.... :(
{

Port_WriteBit(15,1); //setzte EN eingang der Motoren
while(1) //endlosschleife
{

DRIVE(1,255); //dreh dich 2,5s in eine richtung
Thread_Delay(250);
DRIVE(128,128); //bleib stehen
Thread_Delay(250);
DRIVE(255,1); //fahr in die andere richtung
Thread_Delay(250);
DRIVE(128,128); //bleib stehen
Thread_Delay(250);
}
}

shedepe
04.01.2011, 00:28
Nur eine Frage im vorraus: Machst du es dir mit Multithreading nicht unnötig kompliziert auf einem mC ? Wäre das ganze nicht mit Interrupts einfacher zu lösen ?

sebroos
04.01.2011, 08:02
ja mit interrups wäre es wahrscheinlich auch gegangen =)

aber mein programm ist ja nur ein vorreiter um den probot zu testen... später soll er mittels multithreading noch ganz andere aufgaben erledigen, die mit interrupts nicht zu realisieren wären.
=)

sebroos
05.01.2011, 12:49
hat keiner eine idee?

wie würdest das mit interrups aussehen?

shedepe
05.01.2011, 19:59
So, ich hab mir grad noch mal dein Programm angeschaut.
Wie wäre es wenn du bei case 1: Einfach nur die LED anmachst anstatt einen neuen Thread zu starten und bei case 2: die Motoren anschaltest.

sebroos
05.01.2011, 20:47
ich ich möchte ja gerne multithreading verstehen... und das problem nicht einfach umgehen....

sebroos
05.01.2011, 23:50
nungut ich hab folgendes jetzt festgestellt... wenn ich die Motoren abklemme funktioniert das programm einwandfrei... sobald ich einen motor anschließe funktioniert es leider nichtmehr... woran könnte das liegen?
habe die akkus schon getauscht... alle kontakte nachgelötet...

shedepe
06.01.2011, 00:40
Ich kenne dir Motorfunktion zwar nicht. Aber wenn die mit Encodern und Interrupts arbeitet könnte dein simuliertes Multithreading da Probleme bereiten.

sebroos
06.01.2011, 00:43
hmm das versteh ich jetzt nicht? welche interrups? encoder benutze ich nicht...

dariegel
06.01.2011, 12:23
Habe mir jetzt Deinen Code einmal angeschaut und habe dazu mehrere Sachen anzumerken:

1. Wie gesagt, viel Erfahrung mit Threads habe ich nicht, aber eines ist mir aufgefallen. Du rufst Thread_Start() in deiner main-Routine auf, sorgst aber nicht dafür, dass aus den Threads auch wieder herausgesprungen wird. Wie soll main() denn mitbekommen, dass Du erneut geklatscht hast? Ich glaube, an dieser Stelle liegt der Hund begraben. Vielleicht kommst Du mit Thread_Start()/Thread_Wait() weiter? Wäre jetzt eine Idee, vielleicht liege ich aber auch mangels Erfahrung daneben.


2. An einigen Stellen rufst Du Funktionen der Pro-Bot-Library auf, an anderen Stellen änderst Du direkt einzelne PortBits unter Benutzung der PortBit-Nummer oder eigens festgelegter #define-Bezeichnungen. Die meisten davon sind in der Pro-Bot-Library bereits definiert, wie etwa die LEDs oder die Funktionen zum Ein- und Auschalten des Antriebs (DRIVE_ON()/DRIVE_OFF()).
Das ist teils sehr verwirrend und lenkt das Auge evtl. vom eigentlichen Problem ab. Vielleicht fällt Dir ja beim Bereinigen der ein oder andere dadurch entstehende Fehler im Programmablauf auf.

Öffne mal die Datei C:\Programme\C-Control Pro\Libraries\PRO-BOT128_Lib.cbas und schau Dir an, was dort drinsteht. Das war für mich jedenfalls sehr aufschlussreich.


3. Du hast sehr viele teils sehr lange Verzögerungen (~2,5 s) durch Thread_Delay() eingebaut. Das behindert das Mitverfolgen des Roboterablaufs. Den ein oder anderen Aufruf kannst Du entfernen, IMO muss man dem Mikroprozessor keine 1 s geben, um seine Ports zu stellen. :)


Wenn ich demnächst Zeit habe, steppe ich vielleicht Deinen Code mal durch. Habe ihn bei mir in ein neues Projekt kopiert, ein wenig bereinigt und Blut geleckt. :)


Hoffe, ich konnte ein wenig weiterhelfen.

sebroos
06.01.2011, 14:02
hi!

wenn du blut geleckt hast bringe ich dich gerne mal auf meinen stand =)

also wenn du multithreading benutzt dann musst du im IDE unter projekt->optionen auf multithreading gehen und den Thread 1 und 2 aktivieren... stack ist die größe die diese threads nutzen dürfen und cycles sind die ablaufzeiten... also die befehle die er abwartet bis er zum nächsten thread wechselt.
thread 0 ist das main programm... somit ist punkt eins auch erklärt.

nun fängt meine vorlesung an... deswegen erkläre ich den rest... ähm später weiter....;)

dariegel
06.01.2011, 14:06
hi!

wenn du blut geleckt hast bringe ich dich gerne mal auf meinen stand =)

also wenn du multithreading benutzt dann musst du im IDE unter projekt->optionen auf multithreading gehen und den Thread 1 und 2 aktivieren... stack ist die größe die diese threads nutzen dürfen und cycles sind die ablaufzeiten... also die befehle die er abwartet bis er zum nächsten thread wechselt.
thread 0 ist das main programm... somit ist punkt eins auch erklärt.

nun fängt meine vorlesung an... deswegen erkläre ich den rest... ähm später weiter....;)

Die Multithreading-Optionen sind mir bekannt. Mit "Punkt 1 geklärt" meinst Du, dass Dein Code so funktionieren müsste (bzgl. Threadabfolge)?

dariegel
06.01.2011, 15:44
So, ich habe die Lösung. Nicht das Multithreading ist das Problem, sondern das Eigengeräusch des Antriebs. Es löst nämlich sofort wieder ein count++; aus, was zur Deaktivierung nach wenigen Millisekunden führt. Deshalb fährt der Antrieb nur wenige Millimeter.

Lass in Thread 2 mal irgendetwas Geräuschloses ausführen bspw. wie in Thread 1 ein LED-Blinken. Dann funktioniert es wunderbar.

Hier mein bereinigter Code, der beim ersten Mal Fingerschnippen die vorderen zwei LEDs blinken lässt (Thread 1), beim zweiten Mal Schnippen kommen die hinteren beiden LEDs hinzu (Thread 2). Das dritte Mal deaktiviert beendet beide Threads und man kann mit erneutem Schnippen von vorne beginnen.


word x;
int count;

void main(void)
{
PRO_BOT128_INIT();
count = 0;


while(1)
{
x = GetADC(3);

if (x > 700)
{
count++;
Msg_WriteInt(count);
Msg_WriteChar(13);

Thread_Delay(10);

switch(count)
{
case 1:
Thread_Start(1, Light);
break;
case 2:
Thread_Start(2, Fahr);
break;
case 3:
count = 0;

Thread_Kill(1);
Thread_Kill(2);
// DRIVE_OFF();
FLL_OFF();
FLR_OFF();
BLL_OFF();
BLR_OFF();
break;
}
}
}

}

word GetADC(int adr)
{
ADC_Set(ADC_VREF_BG, adr);
return ADC_Read();
}

void Light(void)
{
while(1)
{
Port_ToggleBit(FLL);
Port_ToggleBit(FLR);
Thread_Delay(50);
}
}

void Fahr(void)
{
while(1)
{
Port_ToggleBit(BLL);
Port_ToggleBit(BLR);
Thread_Delay(50);
}
}



Zudem siehst Du im Ausgabefenster den aktuellen Wert von count.

Ich habe den switch-Baum in die if-Anweisung zur Mikroabfrage verfrachtet, dann kannst Du Dir nämlich die umständliche Zwischenerhöhung von count sparen, damit Dir nicht derselbe Thread mehrfach gestartet wird.
So wird die switch-Verzweigung nur durchlaufen, wenn der Schallpegel am Mikro auch ausreicht. Ich denke 700 ist ein guter Wert. Mir war 600 etwas zu empfindlich. :)


Um jetzt beim zweiten Schnippen doch den Antrieb laufen zu lassen, musst Du Dir was überlegen, damit das Mikro nicht versehentlich durch das Getriebegeräusch auslöst. Entweder noch ein bisschen mit dem x-Wert spielen oder den "Hörbereich" des Mikros mit einer Art Papiertrichter eingrenzen. Vielleicht funktioniert das.

Vielen Dank, denn ich habe auch etwas über Multithreading bei der Sache gelernt. :)

sebroos
06.01.2011, 15:56
hmm wenn ich mir das so überlege kann das durchaus sein...
aber ich muss es mal versuchen...

vielen dank... melde dich auch gerne bei mir wenn du ein problem mit dem pürobot hast... wenn ich weiß wie dann helf ich immer gerne =)

ich melde mich nochmal wenn es mal ausprobiert habe.

lg

sebroos
06.01.2011, 18:32
sooo nun hab ich mal folgendes gemacht... ich habe die eingabe statt über das microphon über denn Taster SW2 (Boot) laufen lassen. und tatsächlich funktioniert das besser...
allerdings fängt der mC auch oft nochmal das programm von ganz von vorne an wenn er motoren starten will.... also er springt nochmal ganz am anfang vom programm (also auch aus der while schleife raus) und steuert alle 4 LEDs wieder an.
kann das sein das multithreading enorm auf die batterien geht, so das nach 5 minuten testen und neuprogrammieren die batterien leer sind? oder hat mein mC nen schuss?
ich habe schon mehrmals die batterien getauscht... aber immer nach gefühlten 5 min fing der mC an das programm öffters neu zu starten... nach einem battwechsel gehts wieder.... 2-3 mal...
ich kann mir das nur erklären das die spannung irgendwie zusammen bricht...

danke für alles