PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Neuling: Odometrie



teHIngo
23.12.2007, 18:04
Hallo Robotikfreunde!

Endlich hab ich es auch mal geschafft meinen ASURO zusammenzulöten.
Es klappt auch alles so weit - außer meinem Programm...
Weil meine Kumpels, mit denen ich normalerweise baue, im moment Skifahren sind, dachte ich mir, ich poste einfach mal hier rein und wende mich mit meinen Problemen an Euch :)!

Ich habe ein Odometrieprogramm geschrieben und dachte es würde auch gut laufen, tut es aber nicht. Asuro hat immer noch einen rechtsdrall und die Drehzahlen der Räder beeinflussen sich trotz Programm nicht!

Hier einfach mal der Code:


/* Geradeausfahren */

void GeradeAus()
{
unsigned int i=0;
unsigned int OdoDataInit[2];
unsigned int OdoData[2];
unsigned int n0=0;
unsigned int n1=0;
OdometrieData(OdoDataInit);
float comp;
unsigned int old0=OdoDataInit[0];
unsigned int old1=OdoDataInit[1];
unsigned int spd0=175;
unsigned int spd1=175;
OdometrieData(OdoData);

MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);

for(i=0; i<=50; i++) // 50 mal Messen für exakteren Wert
{
/* Berechnung der Drehzahl des 0. Odosensors */

if(old0==0){old0=1;} // sonst teilt man nacher durch 0 wenns dunkel ist!

if(OdoData[0]/old0 > 2 || OdoData[0]/old0 < 0.5) // Wenn Übergang n erhöht
{
n0++;
}

old0=OdoData[0];

/* Berechnung der Drehzahl des 1. Odosensors */

if(old1==0){old1=1;} // sonst teilt man nacher durch 0 wenns dunkel ist!

if(OdoData[1]/old1 > 2 || OdoData[1]/old1 < 0.5)
{
n1++;
}

old1=OdoData[1];
}

/* Drehzahlen ins Verhältnis setzen und dann Geschw. ev. Erhöhen */

comp=n0/n1;

if(comp > 1)
{
if(spd0<255)
{
spd0++;
}
else
{
spd1--;
}
}
else if(comp < 1)
{
if(spd1<255)
{
spd1++;
}
else
{
spd0--;
}
}
}

Ich hoffe ist nicht zuuu laufzeitlastig ;) Ist mein erstes Programm!

Vielen Dank im Vorraus[/code]

liggi
23.12.2007, 18:31
willkommen im forum

als ich sehe das problem darin, das bei jedem aufruf der funktionen alle variablen auf die anfangswerte gesetzt werden.

mfg liggi

teHIngo
23.12.2007, 19:46
So, habe jetzt mal eingebaut dass er mir anzeigt ob er auch tatsächlich was macht oder nicht. Dies ist der Fall :)
Doch nach Testläufen fährt er exakt so wie ohne Odometrie Programm. Ich gucke mir jetzt mal deinen Vorschlag an, danke schonmal!

// Edit
Hmm irgendwie muss ich doch aber die Variablen initialisieren. Wie mach ich das denn ohne dass die jedes mal zurückgesetzt werden? Das scheint auch das Problem zu sein.

radbruch
23.12.2007, 20:32
Hallo teHIngo,

du solltest mal dein gesamtes Programm posten, dann könnte man dir vielleicht zeigen, wo man wie welche Variablen initialisieren könnte..

Ein Problem scheint mir schon beim Setzen der Motorpower zu bestehen: Du hast nur ein MotorSpeed(spd0,spd1); direkt nach der Initialisierung der Variablen (da haben spd0/1 den Wert 175). Nach der Auswertung der ODO-Sensoren und nach der anschliesenden Änderung von spd0/1 wird die Funktion verlassen und alles ist vergessen.

Noch ein paar Anmerkungen (vielleicht etwas schludrig wegen Spongebob):

- In deiner Schleife, die wegen <=50, genau 51 mal ausgeführt wird, werden mit OdometrieData() keine neuen Daten für OdoData eingelesen.

- Die Werte der Odometriesensoren sind in der Praxis nie 0

- Die Befehle comp=n0/n1; if(comp > 1) bzw. if(comp < 1) könnte man auch durch if (n0 > n1) bzw. if (n0 < n1) ersetzen. Das für einen AVR ungünstge float comp; könnte dann entfallen.

Zu "if(OdoData[0]/old0 > 2 || OdoData[0]/old0 < 0.5)"

Der Übergang zwischen den Hell-/Dunkelfeldern ergibt keine Wertesprünge, der Verlauf ist annähernd sinusförmig.

Mehr gibt's erst nach Shrek..

Gruß

mic

teHIngo
24.12.2007, 10:08
Hey Danke! Ich hab jetzt noch nichts korrigiert, werde mich aber gleich mal dran setzen. Erstmal hier alles festlich herrichten, ist ja auch Weihnachten ;)...

Trotzdem hier schonmal das gesamte Programm!



#include "asuro.h" // Konfigurationsdateien laden
#include <string.h>
#define ENDLOS while(1)

/* Funktionen definieren */

void schlafen(unsigned int t)
{
unsigned int i;
for(i=0; i<t; i++)
{
Sleep(72);
}
}

/* Geradeausfahren */

void GeradeAus()
{
unsigned int i=0;
unsigned int OdoDataInit[2];
unsigned int OdoData[2];
unsigned int n0=0;
unsigned int n1=0;
OdometrieData(OdoDataInit);
float comp;
unsigned int old0=OdoDataInit[0];
unsigned int old1=OdoDataInit[1];
unsigned int spd0=190;
unsigned int spd1=190;



OdometrieData(OdoData);

MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);

for(i=0; i<=100; i++) // 50 mal Messen für exakteren Wert
{
/* Berechnung der Drehzahl des 0. Odosensors */

if(old0==0){old0=1;} // sonst teilt man nacher durch 0 wenns dunkel ist!

if(OdoData[0]/old0 > 1.4 || OdoData[0]/old0 < 0.6) // Wenn Übergang n erhöht
{
n0++;
StatusLED(YELLOW);
}

old0=OdoData[0];

/* Berechnung der Drehzahl des 1. Odosensors */

if(old1==0){old1=1;} // sonst teilt man nacher durch 0 wenns dunkel ist!

if(OdoData[1]/old1 > 1.4 || OdoData[1]/old1 < 0.6)
{
n1++;
StatusLED(RED);
}

old1=OdoData[1];
}
StatusLED(GREEN);

/* Drehzahlen ins Verhältnis setzen und dann Geschw. ev. Erhöhen */

comp=n0/n1;

if(comp > 1)
{
if(spd0<255)
{
spd0++;
BackLED(ON,OFF);
}
else
{
spd1--;
}
}
else if(comp < 1)
{
if(spd1<255)
{
spd1++;
BackLED(OFF,ON);
}
else
{
spd0--;
}
}
}


/* Beginn des Hauptprogramms */

int main (void){
Init(); //Prozessor initialisieren

ENDLOS // Endlosschleife
{

GeradeAus();

}

/* Schluss ! */

return 0;
}


Heute Nachmittag werde ich vielleicht mal ein Programm schreiben dass mir die Odometerdaten zusendet, aber mit sowas hatte ich bisher immer Probleme weil nur kryptische Daten ankamen, mal schauen!

reini1305
24.12.2007, 10:28
Wenn du die Variablen nur beim Ersten Aufruf der Funktion initialisieren willst schreib einfach ein static davor. Also zb. static unsigned int spd0=190;

HTH
Reini

Weiti
24.12.2007, 13:20
kann man nicht die variablen global deklarieren wie z.B. in Java?
dann würden nach #define ENDLOS while(1) alle variablen kommen anstatt in den Funktionen zu stehen.

Ich Vermute das aber nur!

teHIngo
24.12.2007, 14:34
Sehr interessant! Ich habe mir eure Anregungen zu Herzen genommen und umgesetzt.

#include "asuro.h" // Konfigurationsdateien laden
#include <string.h>
#define ENDLOS while(1)

/* Funktionen definieren */

void schlafen(unsigned int t)
{
unsigned int i;
for(i=0; i<t; i++)
{
Sleep(72);
}
}

/* Geradeausfahren */

void GeradeAus()
{
static unsigned int i=0;
unsigned int OdoDataInit[2];
unsigned int OdoData[2];
static unsigned int n0=0;
static unsigned int n1=0;
OdometrieData(OdoDataInit);
unsigned int old0;
unsigned int old1;
static unsigned int spd0=190;
static unsigned int spd1=190;
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);

for(i=0; i<50; i++) // 50 mal Messen für exakteren Wert
{
OdometrieData(OdoData);
/* Berechnung der Drehzahl des 0. Odosensors */

if(old0==0){old0=1;} // sonst teilt man nacher durch 0 wenns dunkel ist!

if(OdoData[0]/old0 > 1.4 || OdoData[0]/old0 < 0.6) // Wenn Übergang n erhöht
{
n0++;
}

old0=OdoData[0];

/* Berechnung der Drehzahl des 1. Odosensors */

if(old1==0){old1=1;} // sonst teilt man nacher durch 0 wenns dunkel ist!

if(OdoData[1]/old1 > 1.4 || OdoData[1]/old1 < 0.6)
{
n1++;
}

old1=OdoData[1];
}
StatusLED(GREEN);

/* Drehzahlen ins Verhältnis setzen und dann Geschw. ev. Erhöhen */

if(n0<n1)
{
if(spd0<255)
{
spd0++;
StatusLED(GREEN);
}
else
{
spd1--;
StatusLED(RED);
}
}
else if(n0>n1)
{
if(spd1<255)
{
spd1++;
StatusLED(GREEN);
}
else
{
spd0--;
StatusLED(RED);
}
}
}


/* Beginn des Hauptprogramms */

int main (void){
Init(); //Prozessor initialisieren

ENDLOS // Endlosschleife
{

GeradeAus();

}

/* Schluss ! */

return 0;
}

Jetzt macht Asuro aber vollends abgefahrene Sachen!
Er gibt zunächst auf beiden Rädern gas und verringert dann beim rechten Rad abnehmend bis auf 0 die Geschwindigkeit, das linke Rad läuft mit konstanter Geschwindigkeit. Nach einiger Zeit (und ein Paar Runden auf der Stelle...) fängt das gleiche dann wieder von vorne an. Sehr seltsam!

Interessant ist auch, dass sehr schnell die StatusLED auf RED umschaltet. spd0 / spd1 müssen also sehr schnell 255 erreichen weshalb dann die Geschwindigkeit gedrosselt wird (? oder ;)).

Weiti
24.12.2007, 15:14
wenn die Geschwindigkeiten langsamer erhöht werde sollen kannst du ja nen Timer einbauen.

was gibt denn die Odometrie für werte? Nicht das einer kaputt ist, hat mich einige Zeit gekostet herauszufinden das der rechte odo bei meinem nicht geht.

radbruch
24.12.2007, 23:12
Hallo teHIngo

Du hast schon fast alles geändert was ich so auf Anhieb "bemängelt" habe ("bis auf die Werte werden nie 0"), dafür gibt's natürlich erstmal ein großes Lob von mir. Aber trotzdem finde ich in deinem aktuellen Programm nur ein MotorSpeed():

static unsigned int spd0=190;
static unsigned int spd1=190;
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);

Hab' ich da was überlesen oder ändert dein Programm die Motorpower wirklich nicht mehr nach der Berechnung der Drehzahldifferenzen? Ich hab's aber nur überflogen, weil's schon recht spät ist und ich noch im Weihnachtsrummel stecke...

Das ENDLOS würde ich wieder rausschmeissen, denn while(1) liest sich besser. Ich mag nicht erst in den #defines nachschauen, was damit gemeint ist... Mit C kann man zwar viel machen , man muss es aber nicht.

Gruß

mic

Phil23
25.12.2007, 08:36
Sorry passt zwar nicht wirklich zum Thema aber ich wollt nicht extra ne neues aufmachen. Ich hab meinen jetzt zu Weihnachten bekommen und wollt euch fragen ob man den Asuro auch mit C++ statt mit C programmieren kann, da C++ für Objektorientiertes Programmieren doch eigentlich besser ist.

Danke schonmal im Voraus

radbruch
25.12.2007, 09:47
Hallo Phil23

Willkommen im RN-Forum. Hier gibt's 'nen Thread für die Weihnachtsasuros:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=26141

Natürlich kann man den asuro auch in C++ programmieren:
https://www.roboternetz.de/wissen/index.php/Avr-gcc

Ob man einen kleinen 8-Biter allerdings mit objektorientiertem Code volldröhnen muss ist wohl eher eine philosophische Frage...

Gruß

mic

teHIngo
25.12.2007, 15:40
Ich hab euch hier mal ein Video von dem Unfug den ASURO veranstaltet gemacht!
Ich hoffe das hilft weiter :)

http://www.youtube.com/watch?v=tW8aXWY6uuU

radbruch
25.12.2007, 16:35
Hallo

Na, nun sieht's doch schon prima aus. Immerhin scheint er etwas zu regeln. So wie ich das erkennen kann, wird der rechte Motor immer langsamer bis der Wert für MotorSpeed() unter null sinkt. Weil die Werte aber nur einen Bereich von 0-255 haben, wird der nächste Wert unter 0 wieder als Vollgas interpretiert und der Motor dreht wieder voll auf. Möglicherweise sind die Seiten bzw. die Logik der Abfrage vertauscht. Deshalb wird auch die StatusLED nie mehr Grün. Die solltest du vor beginn der 50er-Schleife vielleicht auf Yellow setzen

Ach, nun hab ich's mit der MotorSpeed() auch gecheckt, du verwendest static bei den Deklarationen. Aber die Auswertung der ODO-Daten durchschaue ich immer noch nicht. Du prüfst auf einen Wertesprung von Faktor 0,4 (oder so ähnlich), beachtest aber nicht, das die Werte stetig und nicht sprunghaft geändert werden. Soweit ich noch weiß bewegen sich die Werte zwischen 150 und 650. Eine gute Strategie ist deshalb zu prüfen, ob der Wert z.B. unter 300 oder über 500 ist. Jeder Wechsel zwischen diesen Grenze bedeutet einen Wechsel zwischen den Codesegmenten. Ein anderer Ansatz, der bei mir auch wunderbar funktionierte: Man speichert ca. 4-7 aufeinanderfolgende Werte. Wenn sie alle aufsteigend bzw. abfallend sind, hat man die Mitte eines Codesegments überschritten. Viele Wege führen zum Ziel...


Gruß

mic

Weiti
25.12.2007, 16:38
sieht aus wie meiner ;)
Da hängt das Rad bei kleineren Geschwindigkeiten, folglich fährt er nicht mehr mit der einen Seite. Hast du mal die Geschwindigkeit erhöht und den Asuro mal in der Hand gehalten, sodass die Räder in der Luft stehen um zu gucken ob die Räder in Ordnung sind?

teHIngo
25.12.2007, 17:07
Danke! Ich bleibe am Ball.

Habe auch hier mal eine Analyse meiner Radsensoren hochgeladen:
http://www.gerth-ac.de/Asuro_MinMax.pdf
Interessant ist eventuell dieser regelmäßige "Einschnitt" bei Right Odometer, aber damit beschäftige ich mich dann später.

Hier die aktuelle Version:

#include "asuro.h" // Konfigurationsdateien laden

/* Funktionen definieren */

void schlafen(unsigned int t)
{
unsigned int i;
for(i=0; i<t; i++)
{
Sleep(72);
}
}

/* Geradeausfahren */

void GeradeAus()
{
static unsigned int i=0;
unsigned int OdoDataInit[2];
unsigned int OdoData[2];
static unsigned int n0=0;
static unsigned int n1=0;
OdometrieData(OdoDataInit);
unsigned int old0;
unsigned int old1;
static unsigned int spd0=200;
static unsigned int spd1=200;

for(i=0; i<50; i++) // 50 mal Messen für exakteren Wert
{
OdometrieData(OdoData);
/* Berechnung der Drehzahl des 0. Odosensors */

if(OdoData[0]/old0 > 1.4 || OdoData[0]/old0 < 0.7) // Wenn Übergang n erhöht
{
n0++;
}

old0=OdoData[0];

/* Berechnung der Drehzahl des 1. Odosensors */

if(OdoData[1]/old1 > 1.4 || OdoData[1]/old1 < 0.7)
{
n1++;
}

old1=OdoData[1];
}
StatusLED(GREEN);

/* Drehzahlen ins Verhältnis setzen und dann Geschw. ev. Erhöhen */

if(n0<n1)
{
if(spd0<255)
{
spd0++;
}
else
{
spd1--;
}
}
else if(n0>n1)
{
if(spd1<255)
{
spd1++;
}
else
{
spd0--;
}
}
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);
}


/* Beginn des Hauptprogramms */

int main (void){
Init(); //Prozessor initialisieren

while(1) // Endlosschleife
{

GeradeAus();

}

/* Schluss ! */

return 0;
}

Räder und Odometrie sind definitiv in Ordnung ;)

Möchte hier generell nochmal anmerken dass ich es echt klasse findet dass ihr hier Anfängern wie mir so unter die Arme greift
Wenn ich wa mehr draufhab werd ich mich auch bemühen ;)


// Edit!
Jetzt habe ich auch deine Editierung gesehen. Werde ich heute noch angehen ;)

teHIngo
25.12.2007, 22:25
Odometrie ist schon eine spannende Sache. Ich bleibe hartnäckig ;).

Jetzt habe ich mir ein Programm nach Radbruchs zweitem Vorschlag (Zwischenspeicherung) geschrieben, das eigentlich komplett logisch ist (/sein sollte ;)) aber natürlich nicht läuft. Schade, dachte es sähe so schon aus!

Hier der Code:

#include "asuro.h" // Konfigurationsdateien laden

/* Funktionen definieren */

/* Geradeausfahren */

void GeradeAus()
{
char e,f,h,i,j; // Zähler
unsigned int OdoData[2]; // Array für Odo Werte
unsigned int save[5]; // Zwischenspeicher für Odo Wertereihe
unsigned int wahr[5]; // Zähler
static unsigned int spd0=170; // Geschwindigkeit
static unsigned int spd1=170; // Geschwindigkeit
unsigned int n[2]; // Zähler

for(e=0; e<10; e++) // Anzahl der Messungen die durchgeführt werden
{
for(f=0; f<2; f++) // Messung für links/rechts
{
for(h=0; h<2; h++) // Zwei mal messen: Absteigend oder Aufsteigend?
{
for(i=0; i<5; i++) // Fünf mal messen pro Variable
{
OdometrieData(OdoData);
save[i]=OdoData[f];
if(i==4) // Wenn Array voll: Checken ob Ab oder Auf
{
for(j=0; j<4; j++)
{
if(h==0 && save[i]<save[i+1]) // Alter Wert kleiner als neuer? (Auf)
{
wahr[h]++;
}
else if(h==1 && save[i]>save[i+1]) // Neuer Wert größer als alter? (Ab)
{
wahr[h]++;
}
}
}
}
}
if(wahr[0]>2 && wahr[1]>2) // Umdrehung fand statt wenn beides zutraf!
{
n[f]++;
}
}
}

if(n[0]>n[1]) // gleiches Spiel wie immer!
{
if(spd0<255)
{
spd1++;
}
else
{
spd0--;
}
}
else if(n[0]<n[1])
{
if(spd1<255)
{
spd0++;
}
else
{
spd1--;
}
}
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);
}

/* Beginn des Hauptprogramms */

int main (void){
Init(); //Prozessor initialisieren

while(1) // Endlosschleife
{

GeradeAus();

}

/* Schluss ! */

return 0;
}

ASURO fährt jetzt immer 8en, also quasi das gleiche wie im Video nur dass er nach einmal stehen bleiben bei dem einen rad und der darauf folgenden Beschleunigung da spd1=0 wird, das andere Rad bis auf 0 drosselt und das gleiche Spiel wieder von vorne beginnt. Das kann er schon ganz gut ;)
Würde mich freuen wenn ihr mal drüber guckt :) Gute Nacht!

radbruch
25.12.2007, 23:01
Hallo teHIngo


Würde mich freuen wenn ihr mal drüber guckt ... Gute Nacht!
Na, du machst es dir einfach. Stellst deinen voll komplizierten Code rein und gehst ins Bett. Und wir können uns nun quälen. Da brauche ich etwas länger, bis ich da durchblicke. Meine Lösung zur Prüfung der aufsteigenden/abfallenden Wertefolgen sah mal so aus:


unsigned int data[2], count_l, count_r;

void count(void){
static unsigned int o1_l, o2_l,o3_l,o4_l, o1_r, o2_r, o3_r, o4_r;
static unsigned char odo_bit_l, odo_bit_r;

OdometrieData(data);
if ((data[0]<o1_l) && (o1_l<o2_l) && (o2_l<o3_l) && (o3_l<o4_l)) {
if (!odo_bit_l) { count_l ++; odo_bit_l=(1==1); StatusLED(YELLOW); }
}
if ((data[0]>o1_l) && (o1_l>o2_l) && (o2_l>o3_l) && (o3_l>o4_l)) {
if (odo_bit_l) { count_l ++; odo_bit_l=(1==0); StatusLED(OFF); }
}
if ((data[1]<o1_r) && (o1_r<o2_r) && (o2_r<o3_r)) {
if (!odo_bit_r) { count_r ++; odo_bit_r=(1==1); StatusLED(RED); }
}
if ((data[1]>o1_r) && (o1_r>o2_r) && (o2_r>o3_r)) {
if (odo_bit_r) { count_r ++; odo_bit_r=(1==0); StatusLED(OFF); }
}
o4_l=o3_l; o3_l=o2_l; o2_l=o1_l; o1_l=data[0];
o3_r=o2_r; o2_r=o1_r; o1_r=data[1];
}

count_l/r sind die Zähler, odo_bit_l/r der letze Status, ox_l/r die Werte der letzten Daten. Das ist sicher auch nicht das Ei des Kolumbus, funktioniert aber halbwegs zuverlässig. Im Stillstand ohne drehende Motoren kann man am Rad drehen und die Segmentwechsel an der StatusLED erkennen.


ASURO fährt jetzt immer 8en
Das liegt wohl daran, dass immer noch ein Überlauf der Werte stattfindet. Nun eben im Wechsel einmal links und einmal rechts. Ich schau mir morgen mal deinen Code genauer an. Ebenfalls gute Nacht.

Gruß

mic

radbruch
26.12.2007, 23:37
Hallo

So scheint es halbwegs zu funktionieren. Allerdings dürften ein paar Segmentwechsel verlorengehen, weil wir die Seiten nacheinander prüfen(f-Schleife):

#include "asuro.h" // Konfigurationsdateien laden

/* Funktionen definieren */

/* Geradeausfahren */

void GeradeAus(void)
{
unsigned char e,f,i,j; // Zähler
unsigned int OdoData[2]; // Array für Odo Werte
unsigned int save[5]; // Zwischenspeicher für Odo Wertereihe
unsigned int wahr[2]; // Zähler
unsigned int richtung[2]; // letze Flanke auf- oder absteigend?
static unsigned int spd0=170; // Geschwindigkeit
static unsigned int spd1=170; // Geschwindigkeit
unsigned int n[2]; // Zähler

for(e=0; e<10; e++) // Anzahl der Messungen die durchgeführt werden
{
for(f=0; f<2; f++) // Messung für links/rechts
{
wahr[f]=0; // Löschen nicht vergessen
for(i=0; i<5; i++) // Fünf mal messen pro Variable
{
OdometrieData(OdoData);
save[i]=OdoData[f];
if(i==4) // Wenn Array voll: Checken ob Ab oder Auf
{
for(j=0; j<4; j++)
{
if(richtung[f] && (save[i]<save[i+1])) // Werte aufsteigend?
{
wahr[f]++;
}
else if(!richtung[f] && (save[i]>save[i+1])) // Werte Abfallend?
{
wahr[f]++;
} // if richtung
} //j
} // if i==4
} //i
if(wahr[f]==5) // richtungwechsel fand statt wenn alle Werte auf/absteigend!
{
n[f]++;
richtung[f]=!richtung[f]; //letzte Werterichtung merken
}
} //f
} //e
if (n[0] == n[1]) // bei Zählergleichstand
{
spd0=spd1=170; // starten wir neu
n[0]=n[1]=0;
}
else if(n[0]<n[1]) // gleiches Spiel wie immer!
{
if(spd0<255)
{
spd0++;
}
else if(spd1>1) // aber nun vorsichtshalber mit Begrenzung
{
spd1--;
}
} else
{
if(spd1<255)
{
spd1++;
}
else if(spd0>1)
{
spd0--;
}
}
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);
}

/* Beginn des Hauptprogramms */

int main (void){
Init(); //Prozessor initialisieren

while(1) // Endlosschleife
{

GeradeAus();

}

/* Schluss ! */

return 0;
}
Die Warnungen sind nun auch weg, die Indexe waren char, unsigned char war richtig.

Gruß und gute Nacht

mic

teHIngo
27.12.2007, 17:08
Hallo radbruch

herzlichen Dank für Deine Hilfe! Ich wollte mit meinem letzten Post keineswegs vorlaut oder fordernd sein, ich war nur etwas verzweifelt weil es wiedermal nicht klappte ;) Aber ich bleibe natürlich am Ball und wenn ihr möchtet halte ich euch auf dem laufenden.

Die Überarbeitung des Programmes hat mir sehr gefallen! Ich kann deine Korrekturen nachvollziehen, nur das richtung[f] und !richtung[f] ist mir nicht ganz klar, wohl aber, dass du damit eine Schleife umgehst.

Allerdings muss ich dir - leider! - mitteilen, dass das Programm bei meinem Asuro immer noch nicht klappt. Er fährt nun im Kreis und hört damit auch nicht mehr auf, was aufgrund deiner guten Idee mit der if-Abfrage der Fall ist (spd wird niemals 0).
Mir ist das ganz unerklärlich ehrlichgesagt, werde es mir aber noch mal durch den Kopf gehen lassen. Irgendwo muss ja ein logischer Fehler sein!
Wenn mir einfällt warum es nicht klappt werde ich das hier sofort posten. Vielleicht setze ich mich mal an deinen ersten Vorschlag (Schwellwerte), aber erstmal habe ich den erhgeiz das hier endlich zum laufne zu bringen ;).

Vielen Dank übrigens auch für deinen Tipp roboterheld. [... ohne Worte]

Gruß
tehingo

radbruch
27.12.2007, 18:41
Hallo teHIngo


Ich wollte mit meinem letzten Post keineswegs vorlaut oder fordernd sein
Das habe ich auch nicht so aufgefasst. Ich war nur im ersten Moment überrascht von dem recht eigenständigen Lösungsansatz und von den vielen verschachtelten Schleifen verwirrt. Bei genauerer Betrachtung wurde mir die Funktion dann klarer, allerdings weiß ich auch noch nicht sicher, wo der Denkfehler liegt.

Richtung[] dient dazu, das Programm etwas mit den Codescheiben zu syncronisieren. In deiner Version hätte die selbe ansteigende oder abfallende Flanke mehrfach hintereinander erkannt werden können. Jetzt wird nach erkannter Flanke nur die nächste in der Gegenrichtung als gültig zugelassen. spd0/1 werden sehr wohl zu 0, aber eben nicht kleiner als 0. Allerdings bleiben die Motoren schon deutlich früher stehen.

Ich vermute, die f-Schleife ist ein Problem, denn wir prüfen j*i*warten_auf_Flanke_in_der_richtigen_Richtung lang nur eine Seite und verpassen dabei alle Segmentwechsel auf der anderen Seite. Vielleicht sollte man anstelle der f-Schleife innerhalb der j-schleife beide Seiten gleichzeitig auswerten. Die ODO-Daten werden ja sowieso gleichzeitig eingelesen, aber immer nur für f-Seite ausgewertet. Dazu müste man aber alle [f]-Indizies(?) nach [0] und [1] auflösen.

Ein anderes Problem könnte die Schrittweite von spd0/1 sein. Wenn der Drehzahlunterschied zu schnell größer wird, kann man ihn nicht einholen, wenn nur nach allen 10 e-Schleifendurchgängen die Werte für MotorSpeed() nur um einen Punkt geändert werden. Vielleicht sollten spd0/1 in 5er oder gar 10er-Schritten geändert werden. Man könnte die e-Schleife vielleicht auch ganz löschen, dann würde häufiger ein neuer MotorSpeed()-Wert ermittelt und gesetzt.

Wichtig bei der Odometrie sind auch noch die Optimierungen der Sensorik: Ausrichtung der Bauteile, Verringerung des axialen Spiels der Codescheiben und Schutz vor Fremdlichteinflüssen.


...aber erstmal habe ich den ehrgeiz das hier endlich zum laufen zu bringen
Die meisten hier verwenden Codes die sie irgendwo kopiert haben oder nutzen die aktuelle Library und wissen nicht, wie das im Hintergrund gemacht wird. Deinen Weg das selbst zu ergründen halte ich aber für sehr viel besser.

Gruß

mic

radbruch
29.12.2007, 10:30
Hallo

Ich habe noch einen großen Mangel entdeckt der wohl den jetzigen Ansatz völlig unbrauchbar macht. Wir wollen ja prüfen, ob die Werte auf- oder absteigend sind. Mit dieser Schleifenlösung prüfen wir aber nicht kontinuierlich alle Werte, sondern werfen nach der Prüfung die alten Werte weg und beginnen komplett von vorne. Wir wissen deshalb nie genau, an welcher Stelle der Wertereihe wir uns wirklich befinden.

Die Lösung wäre wohl eine Art Ringspeicher bei dem immer der aktuellste Wert den ältesten überschreibt. Zudem sollte nach jedem neuen Wert die Folge geprüft werden um möglichst schnell zu erkennen, ob die nächste Flanke schon erreicht ist.

Ich habe das oben mit einem FiFo-Speicher schon angedeutet, der zwar mehr Aufwand beim Hinzufügen neuer Werte bedeutet, aber zum Auswerten immer den selben Code verwendet. Ringspeicher arbeiten mit Schreib- und Lesezeiger und sind deshalb eher für größere Datenmengen geeignet, weil dann das Umkopieren eines FiFos deulich mehr Aufwand ist als die Zeiger zu verwalten.

Gruß

mic

teHIngo
29.12.2007, 11:47
Danke nochmal an dieser Stelle, doch ich muss mich hiermit kurz verabschieden, denn ich bin gerade im Reisestress. Heute Nachmittag gehts los zum Skifahrn :).

Ich melde mich sobald ich zurück bin wieder!

Guten Rutsch
tehingo

teHIngo
15.03.2008, 12:59
*räusper* *hust* ... bin wieder aus dem Urlaub zurück ;).
Nein, Spaß bei Seite, ich hatte Abiturtechnisch relativ wenig Zeit für den ASURO.

Also da mein voriges Programm kompletter murks war (müsst ihr euch nicht anschauen), habe ich einen komplett neuen Ansatz gewählt.
Im folgenden werde ich das Prinzip kurz umreißen:

ASURO nimmt drei Odometrie-Messwerte auf. Dabei überprüft er permanent ob bei den Werten ein neues Maximum oder Minimum vorliegt.
Anhand dieser Werte wird dann, um einen Referenzwert für Übergänge zu erhalten, die Hälfte der Amplitude bestimmt ((max+min)/2).
Die Bestimmung ob es einen Übergang von Schwarz nach Weiß oder umgekehrt gegeben hat funktioniert nun so: Wenn alle drei Messwerte auf/absteigend sind, und sich der mittlere Messwert in der Umgebung des Referenzwertes/der Hälfte der Amplitude befindet, wird ein Zähler erhöht.
Unterscheiden sich die beiden Zähler für links und rechts, wird dementsprechend die Geschwindigkeit der Motoren angepasst.
Um Messwerte für die Funktion zu erhalten wird das ganze initialisiert.

Doch, wer hätte es gedacht: Es klappt natürlich nicht :-k ! Und ein weiteres mal ist es mir unerklärlich und ich frage mich warum!

Es wäre klasse wenn ihr mir helfen könntet. n>2 Augen sehen mehr als n=2 Augen!
Vielen Dank im Voraus! ;)


#include "asuro.h" // Konfigurationsdateien laden
#define MITTER 145 // Die ca. Hälfte der Amplitude
#define MITTEL 160 // für die ersten Anpassungen

/* Funktionen definieren */

/* Globale Variablen */
unsigned char i; // Zähler
char alr=0; // schon (already) gelaufen?
int cntsL=0; // Zähler (counts)
int cntsR=0; // Zähler
char cnts=0; // Zähler
unsigned int odoData[2]; // Array für Odo Werte
unsigned int lrHi[2]={MITTER, MITTER}; // left right highest
unsigned int lrLo[2]={MITTER, MITTER}; // left right lowest
unsigned int spd0=190; // Geschwindigkeit (speed)
unsigned int spd1=190; // Geschwindigkeit
unsigned int odoMemL[3]; // Ododaten zwischenspeichern (ododmetrie memory)
unsigned int odoMemR[3]; // Ododaten zwischenspeichern
unsigned int testErg[2]; // Ergebnisse des Durchlaufes (test ergebnis)
// 0=low, 1=hi

void schlafen(int wert){
for(i=0; i<=wert; i++){
Sleep(72);}
}

/* Geradeausfahren Initialisieren */

char InitFwd(void){

schlafen(250);
StatusLED(RED);
schlafen(250);
StatusLED(YELLOW);

MotorDir(FWD,FWD); // zunächst gasgeben damit er fährt und Werte sammelt, Vortest
MotorSpeed(190,190);

while(cnts<100){ // 20 mal zählen
OdometrieData(odoData);

for(i=0; i<3; i++){ // 3 durchläufe für OdoWerte
OdometrieData(odoData);
odoData[0]=odoMemL[i];
odoData[1]=odoMemR[i];

if(odoMemL[i]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoMemL[i];
}
else if(odoMemL[i]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoMemL[i];
}

if(odoMemR[i]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoMemL[i];
}
else if(odoMemR[i]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoMemL[i];
}
}

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
/* links */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && ((odoMemL[1]/MITTEL)<1.02 && (odoMemL[1]/MITTEL)>0.98)){
cntsL++;
}
else if((odoMemL[0]<odoMemL[1] && odoMemL[1]<odoMemL[2]) && ((odoMemL[1]/MITTEL<1.02) && (odoMemL[1]/MITTEL)>0.98)){
cntsL++;
}

/* rechts */
if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && ((odoMemR[1]/MITTER<1.02) && (odoMemR[1]/MITTER>0.98))){
cntsR++;
}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && ((odoMemR[1]/MITTER)<1.02 && (odoMemR[1]/MITTER)>0.98)){
cntsR++;
}

if(cntsL>70 && cntsR>70){
alr=1;
StatusLED(RED);
schlafen(250);
StatusLED(GREEN);
}
cnts++;
if(cntsR > 2000 || cntsL > 2000){
cntsL=0;
cntsR=0;
}
}//while cnts

testErg[0]=(lrHi[0]+lrLo[0])/2; // Test Ergebnisse zuweisen,
testErg[1]=(lrHi[1]+lrLo[1])/2; // Mitte der Funktion bei Hälfte der Amplitue

MotorDir(BREAK,BREAK);
MotorSpeed(0,0);

schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);

return alr;

}

/* Geradeausfahren */

void Forward(void){

MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);

if(alr == 1){ // Falls Vorprüfung stattgefunden hat, ausführen
for(i=0; i<3; i++){ // 3 durchläufe für OdoWerte
OdometrieData(odoData);
odoData[0]=odoMemL[i];
odoData[1]=odoMemR[i];

if(odoMemL[i]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoMemL[i];
}
else if(odoMemL[i]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoMemL[i];
}

if(odoMemR[i]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoMemL[i];
}
else if(odoMemR[i]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoMemL[i];
}
}

testErg[0]=(lrHi[0]+lrLo[0])/2; // Test Ergebnisse zuweisen,
testErg[1]=(lrHi[1]+lrLo[1])/2; // Mitte der Funktion bei Hälfte der Amplitue

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && ((odoMemL[1]/testErg[0])<1.02 && (odoMemL[1]/testErg[0])>0.98)){
cntsL++;
}
else if((odoMemL[0]<odoMemL[1] && odoMemL[1]<odoMemL[2]) && ((odoMemL[1]/testErg[0]<1.02) && (odoMemL[1]/testErg[0])>0.98)){
cntsL++;
}

if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && ((odoMemR[1]/testErg[1])<1.02 && (odoMemR[1]/testErg[1])>0.98)){
cntsR++;
}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && ((odoMemR[1]/testErg[1])<1.02 && (odoMemR[1]/testErg[1])>0.98)){
cntsR++;
}

if(spd1==255 || spd0==255){
spd1=spd1-10;
spd0=spd0-10;
}

if(cntsL>cntsR){
spd1++;
}

if(cntsL<cntsR){
spd0++;
}

if(cntsR > 2000 || cntsL > 2000){
cntsL=0;
cntsR=0;
}

MotorDir(FWD,FWD); // und go!!
MotorSpeed(spd0,spd1);

}// if alr
}

/* Beginn des Hauptprogramms */

int main (void){

Init(); //Prozessor initialisieren
InitFwd(); // Odo Initialisieren

while(1) // Endlosschleife
{
Forward();
}

/* Schluss ! */

return 0;
}

radbruch
15.03.2008, 13:24
Ächz, das wird wohl etwas dauern bis man da durchgestiegen ist. Vielleicht solltest du dir angewöhnen Probleme aufs wesentliche zu reduzieren und dafür dann einen Testcode schreiben. Ich habe mich trotzdem mal rangewagt, der Code wird fehler- und warnungsfrei übersetzt, prima ;) Erwartungsgemäss fährt meine asuro damit auch eine Kurve.

Was mir sofort ins Auge gesprungen ist: In der Funktion InitFwd() liest du nur einen kurzen Augenblick lang die Werte ein, quasi noch im Stillstand. Bevor ich mich nun weiter in deine gedanklichen Untiefen stürze, war das vielleicht schon das Problem?

gruß

mic

teHIngo
16.03.2008, 13:32
Das war leider nicht das Problem. Ich habe jetzt an mehreren Stellen Sleep Funktionen zum beschleunigen eingebaut, damit er Zeit zum Beschleunigen hat und erst dann anfängt zu messen.
Das klappt auch ganz gut. Manchmal korrigiert er was, fährt ein stück relativ gerade aus, doch dann - wie die meiste Zeit - fährt er wieder ne Kurve.
Daher habe ich den Eindruck dass irgendwas mit meiner Logik nicht funktioniert - vielleicht ist es aber auch nur das Finetuning der Werte, ihr habt da mehr Erfahrung. Zur Logik habe ich mal kurz eine Skizze gemacht.

Das folgende Programm wurde an einigen Stellen überarbeitet, also besser dieses anschauen : ). Ich wäre euch sehr dankbar wenn ihr mir helfen könntet diese Hürde endlich mal zu bewältigen ; )!

Danke und Gruß!


#include "asuro.h" // Konfigurationsdateien laden
#define MITTER 155 // Die ca. Hälfte der Amplitude
#define MITTEL 140 // für die ersten Anpassungen

/* Funktionen definieren */

/* Globale Variablen */
unsigned char i; // Zähler
unsigned char alr=0; // schon (already) gelaufen?
unsigned char alr2=0; // schon (already) gelaufen?
unsigned int cntsL=0; // Zähler (counts)
unsigned int cntsR=0; // Zähler
unsigned int cnts=0; // Zähler
unsigned int odoData[2]; // Array für Odo Werte
unsigned int lrHi[2]={MITTEL, MITTER}; // left right highest
unsigned int lrLo[2]={MITTEL, MITTER}; // left right lowest
unsigned int spd0=190; // Geschwindigkeit (speed)
unsigned int spd1=190; // Geschwindigkeit
unsigned int odoMemL[3]; // Ododaten zwischenspeichern (ododmetrie memory)
unsigned int odoMemR[3]; // Ododaten zwischenspeichern
unsigned int testErg[2]; // Ergebnisse des Durchlaufes (test ergebnis)
// 0=low, 1=hi

void schlafen(unsigned int wert){
for(i=0; i<=wert; i++){
Sleep(72);}
}

/* Geradeausfahren */

char InitFwd(void){

schlafen(250);
StatusLED(RED);
schlafen(250);
StatusLED(YELLOW);

MotorDir(FWD,FWD); // zunächst gasgeben damit er fährt und Werte sammelt, Vortest
MotorSpeed(190,190);
schlafen(250);

while(cnts<500){ // 200 mal zählen
OdometrieData(odoData);

for(i=0; i<3; i++){ // 3 durchläufe für OdoWerte
OdometrieData(odoData);

odoData[0]=odoMemL[i];
odoData[1]=odoMemR[i];

if(odoData[0]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoData[0];}
else if(odoData[0]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoData[0];}

if(odoData[1]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoData[1];}
else if(odoData[1]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoData[1];}
}

testErg[0]=(lrHi[0]+lrLo[0])/2; // Test Ergebnisse zuweisen,
testErg[1]=(lrHi[1]+lrLo[1])/2; // Mitte der Funktion bei Hälfte der Amplitue

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
/* links */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && (((odoMemL[1]/MITTEL)<1.05) && ((odoMemL[1]/MITTEL)>0.95))){
cntsL++;}
else if((odoMemL[0]<odoMemL[1] && odoMemL[1]<odoMemL[2]) && (((odoMemL[1]/MITTEL)<1.05) && ((odoMemL[1]/MITTEL)>0.95))){
cntsL++;}

/* rechts */
if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && (((odoMemR[1]/MITTER)<1.05) && ((odoMemR[1]/MITTER)>0.95))){
cntsR++;}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && (((odoMemR[1]/MITTER)<1.05) && ((odoMemR[1]/MITTER)>0.95))){
cntsR++;}

if(cntsL>420 && cntsR>420){
alr=1;
StatusLED(RED);
schlafen(250);
StatusLED(GREEN);}
cnts++;
}//while cnts

MotorDir(BREAK,BREAK);
MotorSpeed(0,0);

schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);

return alr;

}


void Forward(void){

if(alr2 == 0){ // Beschleunigen damit er in Fahrt Werte sammelt
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);
schlafen(250);
alr2 = 1;}


if(alr == 1){ // Falls Vorprüfung stattgefunden hat, ausführen

for(i=0; i<3; i++){ // 3 durchläufe für OdoWerte
OdometrieData(odoData);

odoData[0]=odoMemL[i];
odoData[1]=odoMemR[i];

if(odoData[0]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoData[0];}
else if(odoData[0]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoData[0];}

if(odoData[1]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoData[1];}
else if(odoData[1]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoData[1];}
}

testErg[0]=(lrHi[0]+lrLo[0])/2; // Test Ergebnisse zuweisen,
testErg[1]=(lrHi[1]+lrLo[1])/2; // Mitte der Funktion bei Hälfte der Amplitue

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
/* links */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95))){
cntsL++;}
else if((odoMemL[0]<odoMemL[1] && odoMemL[1]<odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95))){
cntsL++;}

/* rechts */
if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && (((odoMemR[1]/testErg[1])<1.05) && ((odoMemR[1]/testErg[1])>0.95))){
cntsR++;}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && (((odoMemR[1]/testErg[1])<1.05) && ((odoMemR[1]/testErg[1])>0.95))){
cntsR++;}


if(spd1==255 || spd0==255){ // Falls Maximalspd erreicht Spielraum schaffen
spd1=spd1-10;
spd0=spd0-10;}

if(cntsL>cntsR){ // Korrektur!
spd1++;
StatusLED(RED);}

if(cntsL<cntsR){
spd0++;
StatusLED(GREEN);}

if((cntsR > 10000 || cntsL > 10000) && (cntsR>7000 && cntsL>7000)){ // aufpassen dass Variable nicht überläuft
cntsL=cntsL-7000;
cntsR=cntsR-7000;}

MotorDir(FWD,FWD); // und go!!
MotorSpeed(spd0,spd1);

}// if alr
}

/* Beginn des Hauptprogramms */

int main (void){

Init(); //Prozessor initialisieren
InitFwd(); // Odo Initialisieren

while(1) // Endlosschleife
{
Forward();
}

/* Schluss ! */

return 0;
}

// EDIT:
Mittlerweile bin ich mir relativ sicher dass das Problem beim Messen liegt. Durch die Schleife
for(i=0; i<3; i++){ // 3 durchläufe für OdoWerte
OdometrieData(odoData);

odoData[0]=odoMemL[i];
odoData[1]=odoMemR[i];wird der Fall wie in der Skizze dargestellt nur sehr selten auftreten. Ein neuer Algorithmus muss her :-k

// EDIT die 2.:

So, jetzt habe ich einen neuen Algorithmus entwickelt. ASURO arbeitet jetzt mit durchlaufenden Werten und es sollten daher alle Übergänge verzeichnet werden.
/* Neuer Algorithmus: "Durchlaufende Werte" */
OdometrieData(odoData);

odoMemL[0]=odoMemL[1];
odoMemL[1]=odoMemL[2];
odoMemL[2]=odoData[0];

odoMemR[0]=odoMemR[1];
odoMemR[1]=odoMemR[2];
odoMemR[2]=odoData[1];

Klappen tut es allerdings noch nicht.... :( Ein bisschen Sorgen macht es mir, dass er bei folgender Kontrollfunktion auch niemals etwas ans Terminal sendet!!
if(cntsL>cntsR){ // Korrektur!
spd1++;
StatusLED(RED);
SerWrite("L groesser R",12);}
else if(cntsL<cntsR){
spd0++;
StatusLED(GREEN);
SerWrite("R groesser L",12);}
else if(cntsL==cntsR){
spd0++;
StatusLED(GREEN);
SerWrite("R gleich L",10);}


Irgendeine Idee warum es immer noch nicht klappt? Hier nochmal das komplette Program:
#include "asuro.h" // Konfigurationsdateien laden
#define MITTER 155 // Die ca. Hälfte der Amplitude
#define MITTEL 140 // für die ersten Anpassungen

/* Funktionen definieren */

/* Globale Variablen */
unsigned char i; // Zähler
unsigned char alr=0; // schon (already) gelaufen?
unsigned char alr2=0; // schon (already) gelaufen?
unsigned int cntsL=0; // Zähler (counts)
unsigned int cntsR=0; // Zähler
unsigned int cnts=0; // Zähler
unsigned int odoData[2]; // Array für Odo Werte
unsigned int lrHi[2]={MITTEL, MITTER}; // left right highest
unsigned int lrLo[2]={MITTEL, MITTER}; // left right lowest
unsigned int spd0=190; // Geschwindigkeit (speed)
unsigned int spd1=190; // Geschwindigkeit
unsigned int odoMemL[3]; // Ododaten zwischenspeichern (ododmetrie memory)
unsigned int odoMemR[3]; // Ododaten zwischenspeichern
unsigned int testErg[2]; // Ergebnisse des Durchlaufes (test ergebnis)
// 0=low, 1=hi

void schlafen(unsigned int wert){
for(i=0; i<=wert; i++){
Sleep(72);}
}

/* Geradeausfahren */

char InitFwd(void){

schlafen(250);
StatusLED(RED);
schlafen(250);
StatusLED(YELLOW);

MotorDir(FWD,FWD); // zunächst gasgeben damit er fährt und Werte sammelt, Vortest
MotorSpeed(190,190);
schlafen(250);

while(cnts<500){ // XXX mal zählen

/* Neuer Algorithmus: "Durchlaufende Werte" */
OdometrieData(odoData);

odoMemL[0]=odoMemL[1];
odoMemL[1]=odoMemL[2];
odoMemL[2]=odoData[0];

odoMemR[0]=odoMemR[1];
odoMemR[1]=odoMemR[2];
odoMemR[2]=odoData[1];

if(odoData[0]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoData[0];}
else if(odoData[0]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoData[0];}

if(odoData[1]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoData[1];}
else if(odoData[1]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoData[1];}

testErg[0]=(lrHi[0]+lrLo[0])/2; // Test Ergebnisse zuweisen,
testErg[1]=(lrHi[1]+lrLo[1])/2; // Mitte der Funktion bei Hälfte der Amplitue

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
/* links */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && (((odoMemL[1]/MITTEL)<1.05) && ((odoMemL[1]/MITTEL)>0.95))){
cntsL++;}
else if(((odoMemL[0]<odoMemL[1]) && odoMemL[1]<odoMemL[2]) && (((odoMemL[1]/MITTEL)<1.05) && ((odoMemL[1]/MITTEL)>0.95))){
cntsL++;}

/* rechts */
if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && (((odoMemR[1]/MITTER)<1.05) && ((odoMemR[1]/MITTER)>0.95))){
cntsR++;}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && (((odoMemR[1]/MITTER)<1.05) && ((odoMemR[1]/MITTER)>0.95))){
cntsR++;}

if(cntsL>420 && cntsR>420){
alr=1;
StatusLED(RED);
schlafen(250);
StatusLED(GREEN);}
cnts++;
}//while cnts

MotorDir(BREAK,BREAK);
MotorSpeed(0,0);

schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);

return alr;

}


void Forward(void){

if(alr2 == 0){ // Beschleunigen damit er in Fahrt Werte sammelt
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);
schlafen(250);
alr2 = 1;}


if(alr == 1){ // Falls Vorprüfung stattgefunden hat, ausführen

/* Neuer Algorithmus: "Durchlaufende Werte" */
OdometrieData(odoData);

odoMemL[0]=odoMemL[1];
odoMemL[1]=odoMemL[2];
odoMemL[2]=odoData[0];

odoMemR[0]=odoMemR[1];
odoMemR[1]=odoMemR[2];
odoMemR[2]=odoData[1];

if(odoData[0]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoData[0];}
else if(odoData[0]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoData[0];}

if(odoData[1]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoData[1];}
else if(odoData[1]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoData[1];}

testErg[0]=(lrHi[0]+lrLo[0])/2; // Test Ergebnisse zuweisen,
testErg[1]=(lrHi[1]+lrLo[1])/2; // Mitte der Funktion bei Hälfte der Amplitue

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
/* links */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95))){
cntsL++;}
else if((odoMemL[0]<odoMemL[1] && odoMemL[1]<odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95))){
cntsL++;}

/* rechts */
if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && (((odoMemR[1]/testErg[1])<1.05) && ((odoMemR[1]/testErg[1])>0.95))){
cntsR++;}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && (((odoMemR[1]/testErg[1])<1.05) && ((odoMemR[1]/testErg[1])>0.95))){
cntsR++;}


if(spd1==255 || spd0==255){ // Falls Maximalspd erreicht Spielraum schaffen
spd1=spd1-10;
spd0=spd0-10;}

if(cntsL>cntsR){ // Korrektur!
spd1++;
StatusLED(RED);
SerWrite("L groesser R",12);}
else if(cntsL<cntsR){
spd0++;
StatusLED(GREEN);
SerWrite("R groesser L",12);}
else if(cntsL==cntsR){
spd0++;
StatusLED(GREEN);
SerWrite("R gleich L",10);}

if((cntsR > 10000 || cntsL > 10000) && (cntsR>7000 && cntsL>7000)){ // aufpassen dass Variable nicht überläuft
cntsL=cntsL-7000;
cntsR=cntsR-7000;}

MotorDir(FWD,FWD); // und go!!
MotorSpeed(spd0,spd1);

}// if alr
}

/* Beginn des Hauptprogramms */

int main (void){

Init(); //Prozessor initialisieren
InitFwd(); // Odo Initialisieren

while(1) // Endlosschleife
{
Forward();
}

/* Schluss ! */

return 0;
}

teHIngo
21.03.2008, 16:17
Zwischenbericht: Überarbeitet, klappt immer noch nicht. : (
Soll ich vielleicht einfach nochmal alles schön ordentlich kurz und präzise hinschreiben und einen neuen Thread eröffnen? Wirkt vielleicht nicht so abschreckend und es würde evtl. mal jemand antworten ; )
/* ################################################## ##### */
/* ############# FUNKTIONEN DEFINIEREN ################### */
/* ################################################## ##### */

#include "asuro.h" // Konfigurationsdateien laden

#define MITTER 155 // ca. die Hälfte der Amplitude
#define MITTEL 140 // der Odometriewerte. Benötigt für
// Initialisierung

/* ################################################## ##### */
/* ############# FUNKTIONEN DEFINIEREN ################### */
/* ################################################## ##### */

/* Globale Variablen */
unsigned char i; // Zähler
char alr=0; // schon (already) gelaufen?
char alr2=0; // schon (already) gelaufen?
unsigned int cntsL=0; // Zähler (counts)
unsigned int cntsR=0; // Zähler
unsigned int cnts=0; // Zähler
unsigned int odoData[2]; // Array für Odo Werte
unsigned int lrHi[2]={MITTEL, MITTER}; // left right highest
unsigned int lrLo[2]={MITTEL, MITTER}; // left right lowest
unsigned char spd0=190; // Geschwindigkeit (speed)
unsigned char spd1=190; // Geschwindigkeit
unsigned int odoMemL[3]={0,0,0};; // Ododaten zwischenspeichern (ododmetrie memory)
unsigned int odoMemR[3]={0,0,0};; // Ododaten zwischenspeichern
unsigned int testErg[2]={MITTEL, MITTER}; // Ergebnisse des Durchlaufes (Testergebnis)
// 0=low, 1=hi

/* --- Verbesserte Sleep Funktion --- */
void schlafen(unsigned int wert){
for(i=0; i<=wert; i++) Sleep(72);
}

/* - Geradeausfahren Initialisieren - */
char InitFwd(void){

schlafen(250);
StatusLED(RED);
schlafen(250);
StatusLED(YELLOW);

MotorDir(FWD,FWD); // Zunächst gasgeben damit er fährt und Werte sammelt
MotorSpeed(190,190);
schlafen(250); // Zeit zum Beschleunigen geben

/* Messung beginnen */
while(cnts<500){ // 500 Durchläufe zur Bestimmung der Hälfte
// der Amplitude

/* Neuer Algorithmus: "Durchlaufende Werte" */
OdometrieData(odoData);

odoMemL[0]=odoMemL[1];
odoMemL[1]=odoMemL[2];
odoMemL[2]=odoData[0];

odoMemR[0]=odoMemR[1];
odoMemR[1]=odoMemR[2];
odoMemR[2]=odoData[1];

if(odoData[0]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoData[0];}
else if(odoData[0]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoData[0];}

if(odoData[1]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoData[1];}
else if(odoData[1]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoData[1];}

testErg[0]=(lrHi[0]+lrLo[0])/2; // Test Ergebnisse zuweisen,
testErg[1]=(lrHi[1]+lrLo[1])/2; // Mitte der Funktion bei Hälfte der Amplitue

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
/* links */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && (((odoMemL[1]/MITTEL)<1.05) && ((odoMemL[1]/MITTEL)>0.95)))
{
cntsL++;
}
else if(((odoMemL[0]<odoMemL[1]) && odoMemL[1]<odoMemL[2]) && (((odoMemL[1]/MITTEL)<1.05) && ((odoMemL[1]/MITTEL)>0.95)))
{
cntsL++;
}

/* rechts */
if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && (((odoMemR[1]/MITTER)<1.05) && ((odoMemR[1]/MITTER)>0.95)))
{
cntsR++;
}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && (((odoMemR[1]/MITTER)<1.05) && ((odoMemR[1]/MITTER)>0.95)))
{
cntsR++;
}

if(cntsL>420 && cntsR>420){
alr=1;
StatusLED(RED);
schlafen(250);
StatusLED(GREEN);}
cnts++;
}//while cnts

MotorDir(BREAK,BREAK);
MotorSpeed(0,0);

schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);
StatusLED(YELLOW);
schlafen(250);
StatusLED(GREEN);
schlafen(250);

return alr;
}


void Forward(void){

if(!alr2){ // Beschleunigen damit er in Fahrt Werte sammelt
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);
schlafen(250); // Zeit zum Beschleunigen
alr2 = 1;
}


if(alr)
{ // Falls Vorprüfung stattgefunden hat, ausführen

/* Dieser Programmteil ist weitestgehend identisch mit InitFwd(); */
/* Neuer Algorithmus: "Durchlaufende Werte" */
OdometrieData(odoData);

odoMemL[0]=odoMemL[1];
odoMemL[1]=odoMemL[2];
odoMemL[2]=odoData[0];

odoMemR[0]=odoMemR[1];
odoMemR[1]=odoMemR[2];
odoMemR[2]=odoData[1];

if(odoData[0]>lrHi[0]){ // die Höchstwerte ermitteln LINKS
lrHi[0]=odoData[0];}
else if(odoData[0]<lrLo[0]){ // die Tiefstwerte ermitteln
lrLo[0]=odoData[0];}

if(odoData[1]>lrHi[1]){ // die Höchstwerte ermitteln RECHTS
lrHi[1]=odoData[1];}
else if(odoData[1]<lrLo[1]){ // die Tiefstwerte ermitteln
lrLo[1]=odoData[1];}

testErg[0]=((lrHi[0]+lrLo[0])/2); // Testergebnisse zuweisen,
testErg[1]=((lrHi[1]+lrLo[1])/2); // Mitte der Odometriewertekurve

/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
/* links */
if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95)))
{
cntsL++;
}
else if((odoMemL[0]<odoMemL[1] && odoMemL[1]<odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95)))
{
cntsL++;
}

/* rechts */
if((odoMemR[0]>odoMemR[1] && odoMemR[1]>odoMemR[2]) && (((odoMemR[1]/testErg[1])<1.05) && ((odoMemR[1]/testErg[1])>0.95)))
{
cntsR++;
}
else if((odoMemR[0]<odoMemR[1] && odoMemR[1]<odoMemR[2]) && (((odoMemR[1]/testErg[1])<1.05) && ((odoMemR[1]/testErg[1])>0.95)))
{
cntsR++;
}

/* Dies ist ein neuer Programmteil. */
if(spd1==255 || spd0==255) // Falls Maximalspd erreicht Spielraum schaffen
{
spd1=spd1-10;
spd0=spd0-10;
}

/* Hier wird die Geschwindigkeit angepasst. */
if (cntsL>cntsR) spd1++;
else if(cntsL<cntsR) spd0++;

/* Variable darf nicht überlaufen */
if((cntsR>5000 || cntsL>5000) && (cntsR>3000 && cntsL>3000))
{
cntsL=cntsL-2000;
cntsR=cntsR-2000;
}

/* Und losfahren! */
MotorDir(FWD,FWD);
MotorSpeed(spd0,spd1);

}
}

/* ################################################## ##### */
/* ############ BEGINN DES HAUPTPROGRAMMS ################ */
/* ################################################## ##### */

int main (void){

Init(); // Prozessor initialisieren
InitFwd(); // Odo Initialisieren

while(1)
{
Forward();
}

return 0;
}

/* ################################################## ##### */
/* ############### ENDE DES PROGRAMMS #################### */
/* ################################################## ##### */

damaltor
22.03.2008, 18:17
wozu einen neuen thread für das gleiche thema öfnen? fasse deine erkenntnisse nochmal in einem post zusammen. dann kannst du wenn du möchtest "überabeitet" an den thread-titel anhängen (indem du bei deinem ersten beitrag auf edit klickst).

radbruch
22.03.2008, 18:50
Hallo teHIngo

Mit der Zeit ist dein Programm einfach zu umfangreich um es mal "auf die Schnelle" zu korrigieren. Wir haben alle unsere eigenen Projekte mit denen wir uns beschäftigen und es kostet eben viel Zeit sich in fremde Programme einzudenken.

Wenn es nicht funktioniert must du das selbe machen wie wir auch: Das Programm zerlegen und die einzelnen Teile testen. Stück für Stück, Zeile für Zeile, Befehl für Befehl. Alles nochmal überdenken, Formulierungen, Klammern, Indexe, Grenzwerte, Datentypen... eben alles. Klar, das dauert Zeit und ist Mühselig, aber anders geht es nicht.

Inzwischen habe auch gemerkt dass beim Ermitteln der Startwerte ein Feldwechsel stattgefunden hat, der asuro sich also auch bewegte. Aber obwohl du recht umfangreiche Kommentare eingefügt hast, man muss sich echt bemühen um die Zusammenhänge zu verstehen. Ein Beispiel:


/* Hier wird geschaut, ob die Schwelle übertreten wird, falls ja hat Umdrehung stattgefunden */
Aha. Und dann kommt das:

if((odoMemL[0]>odoMemL[1] && odoMemL[1]>odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95)))
{
cntsL++;
}
else if((odoMemL[0]<odoMemL[1] && odoMemL[1]<odoMemL[2]) && (((odoMemL[1]/testErg[0])<1.05) && ((odoMemL[1]/testErg[0])>0.95)))
{
cntsL++;
}(Brauchst du nicht erklären, soll nur ein Beispiel sein ;)

Denn Rest können wir uns selbst erarbeiten. Woher soll ich wissen, was du dir gedacht hast? OK, auf- oder absteigende steigende Werte, Unterschied um einen Faktor 0,05. Aber warum? Warum drei Werte? Warum 0,05? Das ist bei dir gewachsen, wir müssen das nachvollziehen und dann noch erkennen, was an deiner Idee nicht funzt.

Ich mache nochmal einen Anlauf, aber ich befürchte, du mußt das letztlich selbst lösen. Die Grundlagen dazu hast du ja offensichlich, die Hilfsmittel auch. Viel Erfolg

Gruß

mic

teHIngo
23.03.2008, 12:10
Hey zusammen,
kein Problem, ich kann natürlich verstehen dass es Zeitraubend ist mir dabei zu helfen und dass man dann nicht unbedingt soo Lust dazu hat. : ) Am besten löst man so ein Problem wohl in einer Gruppe, leider sind hier aber alle in den Osterurlaub verschwunden da dachte ich mir ich kontaktiere mal die Profis vom RoboterNetz in meiner Not.
Ich habe meine Programm bisher immer so konzipiert, dass ich mir ein umfangreiches Konzept mit Papier und Bleistift überlegt habe und dann auf dem PC alles abgewandelt und korrigiert habe bis es klappt. Vielleicht ist das ja nicht die optimale Lösung und ich werde das nächste mal alles in kleinere Projekte aufspalten ; ). Von dem her Vielen Dank!
Gruß

radbruch
23.03.2008, 14:09
So, ich glaube, ich habe was gefunden:


Wenn alle drei Messwerte auf/absteigend sind, und sich der mittlere Messwert in der Umgebung des Referenzwertes/der Hälfte der Amplitude befindet, wird ein Zähler erhöht.
Wenn z.B. der Zähler bei der aufsteigenden Flanke erhöht wurde, muss auf die nächste abfallende Flanke geprüft werden. Wenn das nicht beachtet wird, könnte während einer Flanke mehrmals ein odoMemx[1] auftreten das "in der Umgebung" von testErg[x] liegt und der Zähler zu häufig erhöht werden.

Das Prüfen auf auf- oder absteigende Werte habe ich zu Beginn des Threads schon mal angesprochen. Wenn man mehr Werte (5-7 vielleicht) prüft, kann man davon ausgehen, dass beim ersten Auftreten einer Reihe eine neue Flanke beginnt. Dann kann man sich die ganze Mittelwertbildung schenken. [Link (https://www.roboternetz.de/phpBB2/viewtopic.php?p=337851#337851)]

Übrigends habe ich festgestellt, dass permanente Bildung der Min-/Maxwerte Probleme bereitet. Besser funktionierte es bei meinen eigenen Versuchen sie nur einmal zu Beginn der Fahrt festzulegen.


die Profis vom RoboterNetz
Ich in auch nur Laie...

Gruß

mic