PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Odometrie die 1002te(Problem gelöst)



ADR
29.03.2007, 03:05
Hi,
Ich habe mich mal an einem Programm zur synchronisation der Drehzahlen versucht. Nach langem probieren war es dann vorgestern endlich soweit, dass mein Asuro geradeaus fuhr und nicht immer nur Linkskurven. Habe mich gefreut und ersteinmal das Programm etwas gerafft (Überflüssige Schleifen und Variablen entfernt alles etwas schöner gemacht).
Das dumme ist nur, es funktioniert jetzt nicht mehr. Das Programm in der Form in der es funktionierte habe ich nicht mehr und ich finde den Fehler nicht.
Vielleicht hat ja jemand Zeit mal drüber zu schauen, und etwas zu entdecken das immer übersehe. Oder das Ganze mal auf den eigenen Asuro laden um zu schauen wie es sich da benimmt.
Vielen Dank schon mal.


#include <asuro.h>

#define STARTSPEEDL 180
#define STARTSPEEDR 180
#define STARTODOZYKLEN 1000
#define ODOZYKLEN 1000
#define MITTELWERTPUFFER 0
#define TRUE 1
#define FALSE 0
int n; //zählvariable
int Lmotorspeed=STARTSPEEDL,Rmotorspeed=STARTSPEEDR; //motorgeschw.
unsigned long int odomittelwertL,odomittelwertR;//mittlere helligkeit der ododaten
unsigned long int odosummeL=0,odosummeR=0;//aufsummierte ododaten eines zyklus
unsigned int ododata[2]; //nimmt die ododaten auf
short int Luebermittelwert=FALSE,Ruebermittelwert=FALSE;


void start() //initialisiere
{
Init();
StatusLED(RED);
MotorSpeed(Lmotorspeed,Rmotorspeed);
for(n=0;n<STARTODOZYKLEN;n++) //erstmal werden die ododaten
{ //aufsummiert
OdometrieData(ododata);
odosummeL=odosummeL+ododata[0];
odosummeR=odosummeR+ododata[1];
}
odomittelwertL=(odosummeL/STARTODOZYKLEN);//erster Mittelwert wird ermittelt
odomittelwertR=(odosummeR/STARTODOZYKLEN);

odosummeL=0; //...wir wollen ja gleich eine neue summe bilden
odosummeR=0;

if (ododata[0]>odomittelwertL) //weisses oder schwarzes Feld vor dem Sensor
Luebermittelwert=TRUE;
if (ododata[1]>odomittelwertR)
Ruebermittelwert=TRUE;

StatusLED(GREEN);
}

void reglespeed()
{
unsigned int Lswcount=0,Rswcount=0;//zähler für schwarzweissÜbergänge

//Schleife um Übergänge zu zählen
//FOR SCHLEIFE BEGINN++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++
for(n=0;n<ODOZYKLEN;n++)
{
OdometrieData(ododata);
//****************************************LINKE SEITE
if ( (ododata[0]>(odomittelwertL+MITTELWERTPUFFER)) && (Luebermittelwert!=TRUE) ) //wenn ein schwarzes feld vor dem sensor ist...
{ //..und eben nicht auch schon war..
Lswcount++; // zähle einen übergang
Luebermittelwert=TRUE; //und merke dirs für nächste runde
}

if ( (ododata[0]<(odomittelwertL-MITTELWERTPUFFER)) && (Luebermittelwert!=FALSE) )
{
Lswcount++;
Luebermittelwert=FALSE;
}

//****************************************RECHTE SEITE
if ( (ododata[1]>(odomittelwertR+MITTELWERTPUFFER)) && (Ruebermittelwert!=TRUE) )
{
Rswcount++;
Ruebermittelwert=TRUE;
}

if ( (ododata[1]<(odomittelwertR-MITTELWERTPUFFER)) && (Ruebermittelwert!=FALSE) )
{
Rswcount++;
Ruebermittelwert=FALSE;
}
//***************************************Aufsummiere n
odosummeL=odosummeL+ododata[0];
odosummeR=odosummeR+ododata[1];
}
//FORSCHLEIFE ENDE++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++

odomittelwertL=odosummeL/ODOZYKLEN; //neuer Mittelwert wird ermittelt
odomittelwertR=odosummeR/ODOZYKLEN;
odosummeL=0; //...nächste runde neue summe
odosummeR=0;

//Geschwindigkeit des rechten Motors wird angepasst
//(der rechte meines Asuros ist stärker)
//der Linke bleibt immer auf Anfangsgeschw.
if (Lswcount>Rswcount) Rmotorspeed=(Rmotorspeed+5);
if (Lswcount<Rswcount) Rmotorspeed=(Rmotorspeed-5);

if (Rmotorspeed<100) Rmotorspeed=100; //obere und untere grenze
if (Rmotorspeed>250) Rmotorspeed=250;

MotorSpeed(Lmotorspeed,Rmotorspeed);
}


int main()
{
start();
while(1)
{
reglespeed();
}
return(0);
}

Achja das Problem ist, dass der rechte Motor(den linken regle ich nicht) entweder konsequent schneller gemacht wird oder eben langsamer, abhängig davon wie der wert MITTELWERTPUFFER definiert ist. Für 0 wie im Code oben geht er auf maximalspeed für werte ab 40 wird er langsamer. Auch werte dazwischen bringen keine abhilfe, der Fehler muss woanders sein. Dankeschön.
EDIT:meine kommentare etwas an die größe des codefensters angepasst und Titel geändert

damaltor
29.03.2007, 12:20
hmm... ich kann spontan keine fehler finden. weisst du ungefähr welche "überflüssigen schleifen" du entfernt hast? war evtl eine nicht so ganz überflüssige dabei?

radbruch
29.03.2007, 12:30
Hallo

Das sieht ja auf den ersten Blick recht ordentlich aus. Hier mal meine Kommentare:

Wie viele hell/dunkel-Wechsel erkennst du bei 1000 Messzyklen?

Ein MotorDir(FWD,FWD) ist zwar überflüssig, weils so in Init() gesetzt wird, würde aber auch nicht schaden.

Ich glaube, der generelle Denkfehler ist folgender:

Die hell/dunkel-Verteilung ist nicht gleichmässig, soll heisen, dein Mittelwert den du bildest, liegt nicht in der Mitte der möglichen Werte.

Ob das dein Problem ist, kann ich dir noch nicht sagen, ich muss deinen Code erst noch etwas "verinnerlichen"

Ich löse das etwa so:

Eine Kalibrierungsfahrt mit default-Startwerten speichert die Min- und Max-Werte je Seite(bei dir (start()). Die Differenz zwischen Max und Min teile ich durch drei und lege die Schwelle für low auf min+diff/3, für high auf max-diff/3. Neu eingelesene Werte vergleiche ich dann mit meinen Schwellwerten und zähle in Äbhängigkeit vom letzten Pegel bei Bedarf den jeweiligen Zähler hoch. Ein Wert im mittleren Drittel wird generell ignoriert. Das ist quasi ein Filter, der Fehllesungen ausfiltert.

Gruß

mic

DGS
29.03.2007, 14:08
Also was mir da nur einfällt als Tipp:
Erhöhe die Anzahl der Zyklen. Ich glaub, 1000 Zyklen sind zu wenig.
Ich würde jeden Zyklus die LED blinken lassen. So kannst du sehen wann ein Zyklus vorbeigeht. Wenn die zu oft blinkt, können starke Messungenauigkeiten auftreten.

Wieso es früher funktioniert hat:
Früher hattest wohl mehr Schleifen, mehr unnötigen Code -> ein Zyklus dauerte länger, wodurch du virtuell die Zyklenzahl grösser hattest.

damaltor
29.03.2007, 14:27
naja da die 1000 zyklen ohne zeitverzögerung durchgeführt werden, dürfte die haupt-bremse wohl der ADwandler sein. trotzdem wird man von der led nicht viel sehen. 1000 zyklen gehen SEHR schnell vorbei. vielleichtg ist gerade das das problem, weil dann nur ein bis 2 felder des odo-rades gemessen werden. tu mal in den initialisierungs-for-schleife (die mit den 1000 zyklen) ein Sleep(72) rein, dann dauert die initialisierung etwa eine sekunde und in dieser zeit ziehen mehr felder am sensor vorbei. so werden zwar nicht mehr, aber wenigstens "verschiedenere" punkte der odo scheibe vermessen.

ADR
29.03.2007, 16:14
Vielen Dank schon mal.
Eine Erhöhung der Messungen für eine Zählung führt zu keiner Verbesserung. Ich werde dann heute abend mal versuchen ein paar Daten von Asuro zu bekommen was er den da eigentlich zählt. Auserdem gefällt mir Radbruchs Methode die unsicheren Werte in der Mitte herauszufiltern.
Gruß ADR

radbruch
29.03.2007, 19:17
Hallo


die unsicheren Werte in der Mitte herauszufiltern
Hier liegt wohl auch der "Fehler" in deinem Programm. Nachdem ich nun noch etwas darüber nachgedacht habe, halte ein mehrfaches Zählen ein und derselben Flanke für die Ursache der Fehlfunktion. Generell sollten vielleicht die Ausrutscher rausgefiltert werden. (z.B. mittelwerte der letzten drei..)

Ich hab früher schon mal versucht die Flanken zu erkennen. Dabei habe ich mehrere Werte auf steigende oder sinkende Folge (odo0<odo1<odo2<odo3 bzw. odo0>odo1>odo2>odo3) geprüft. Ab einem Vergleich mit 4-5 Werten funktionierte das gut:


OdometrieData(data);
if ((data[0]<o1_l) && (o1_l<o2_l) && (o2_l<o3_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)) {
if (odo_bit_l) {
count_l ++;
odo_bit_l=(1==0);
StatusLED(OFF);
}
}
o3_l=o2_l;
o2_l=o1_l;
o1_l=data[0];
Wenn sich das Rad dreht, blinkt die StatusLED im Rythmus der Flanken und der Counter wird erhöht.

_HP_
30.03.2007, 10:11
Hi ADR,

Versuche doch erst einmal Deine Odometriedaten zu analysieren. Das kanst Du z.B. so machen:



#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define POINTS 100
#define SPEED 100


int main(void)
{
unsigned int data_array[2][POINTS] = {{0}};
unsigned char sw;
unsigned int data[2] = {0}, iLinks =0 , iRechts=0, i=0;
unsigned char cWert[25] = {0};

Init();

SerWrite("Odometrie Test\n\r",16);

BackLED(OFF,OFF);
MotorDir(FWD,FWD);
MotorSpeed(SPEED,SPEED);

for (i=0; i<500; i++)
Sleep(255);

for (i=0; i<POINTS; i++) {
OdometrieData(data);
data_array[0][i] = data[0];
data_array[1][i] = data[1];
}
MotorDir(BREAK,BREAK);
MotorSpeed(0,0);
BackLED(ON,ON);

while(TRUE) {
sw = PollSwitch();
if (sw & 0xFF) {
for (i=0; i<POINTS; i++) {
iLinks = data_array[0][i];
iRechts = data_array[1][i];
sprintf(cWert,"\n\rLinks %3u Rechts %3u",iLinks, iRechts);
SerWrite(cWert, strlen(cWert));
}
}
}

return 0;
}


Damit kannst Du ASURO fahren lassen und danach durch Betätigung eines Tasters die gemessenen Werte mit HyperTerminal auslesen. Die Zahlenreihen dann mit Copy and Paste in Excel übernehmen und darstellen lassen. Du solltest saubere Sinusschwingungen bekommen - ohne "Ausrutscher". Mache den Test auch bei unterschiedlichem Umgebungslicht, um dessen Einfluß zu ermitteln.

Ich habe meine Odometriesensoren mit kleinen, schwarzen Pappgehäusen umgeben und die Motoren entstört. Das hat sehr geholfen.
Anhand der Excelkurven kannst Du dann auch einen oberen und unteren Wert für die Zählschwelle festlegen und brauchst sie dann nicht immer neu zu ermitteln.

Viel Erfolg...

Gruß,

_HP_

ADR
12.06.2007, 17:42
Hi,
ich wollt mich wollt mich nur noch mal für eure hilfe bedanken hab mich ja damals aus verschiedensten Gründen nicht mehr gemeldet.
Mein Asuro läuft jetzt wieder zu meiner vollsten zufriedenheit, mit dem Programm das ich damals hier reingestellt hab. War so wies aussieht ein hardwareproblem.
Also vielen Dank nochmal O:)