PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Kalibrierung der Motoren



BeeWee
14.07.2007, 21:20
Hi,

ich habe ein Programm für Asuro geschrieben, das die Unterschiede der Drehgeschwindigkeiten der beiden Motoren rausfinden und ausgleichen soll. Beim Ausprobieren fährt Asuro nach der Kalibrierung aber nur im Kreis und ich komme nicht drauf, woran das liegen könnte :/
Das ist mein Code:

#include "asuro.h"

int main(void)
{
unsigned int wheel_factor;

Init();

wheel_factor = CalibrateWheels();

MotorSpeed(120, 120 * wheel_factor);

while(1);
return 0;
}

float CalibrateWheels(void) {
Write("Start calibration");

// counter
unsigned int i;
// odometry data
unsigned int data[2];

// rotation count of the wheels
unsigned int count_left = 0;
unsigned int count_right = 0;

// contains the last brightness state for the wheels
unsigned int last_state[2];
OdometrieData(data);
last_state[2] = is_bright(data[0]), is_bright(data[1]);

// the relation between the left amd the right wheel's rotation count
float relation;

// start driving
MotorDir(FWD, FWD);
MotorSpeed(120, 120);

// 5 seconds
for (i = 0; i < 100; i++) {
OdometrieData(data);

// if a wheel's brightness changed, increase the counter
if (is_bright(data[0]) != last_state[0]) {
count_left++;
}

if (is_bright(data[1]) != last_state[1]) {
count_right++;
}

last_state[2] = is_bright(data[0]), is_bright(data[1]);

TimeSleep(50);
}

relation = count_right / count_left;

// done testing, stop wheels
MotorSpeed(0, 0);

Write("Finished calibration");

return relation;
}

unsigned int is_bright(unsigned int darkness) {
if (darkness > 512) {
return 0;
} else {
return 1;
}
}

void Write(char msg) {
// Send a string via IR without having to think about the length of the string
SerWrite(msg, strlen(msg));
}

void TimeSleep(unsigned int time) {
// Sleep for ``time`` miliseconds
unsigned int i;

for (i = 0; i < time; i++) {
Sleep(72);
}
}


Die Odometriesensoren funktionieren beide, habe sie mit dem SelfTest getestet.
Weiß jemand, woran das liegen könnte?

BeeWee[fade:e7bfbc102e][/fade:e7bfbc102e]

Werner++
14.07.2007, 22:52
Hallo BeeWee,

ändere mal die Zeile
unsigned int wheel_factor;
nach
float wheel_factor;
Gruß
Werner

BeeWee
14.07.2007, 23:06
Hallo,

danke für die Begrüßung :) edit: <-- bezieht sich auf einen gelöschten Beitrag :/

ich habe die Zeile von Werner geändert und den Schwellwert herabgesetzt aber Asuro dreht sich leider immer noch im Kreis (linkes Rad fährt, rechtes steht völlig).

BeeWee

radbruch
14.07.2007, 23:26
Hallo BeeWee

Ups

Ich musste meinen Beitrag zurückziehen, weil ich mich nicht zu sehr blamieren wollte. Das mit dem int erschien mir so richtig, dass mein Schwellwertverdacht unmöglich stimmen konnte. Aber trotzdem nochmals ein herzliches Willkommen und ein großes Lob für das pfiffige und unkonvensionelle Programm.

Jetzt traue ich mich kaum noch was anders vorzuschlagen. Ich vermute, er dreht nach rechts, weil hier bei MotorSpeed(120, 120 * wheel_factor); irgendwas nicht stimmt. Ich verwende in meinen Programmen keine floats, deshalb kann ich nicht sagen, ob MotorSpeed() das Ergebniss dieser Multiplikation akzeptiert. Vielleicht sollte man das mal vorsichtshalber mit z.B.

float testfloat=1,001;
MotorSpeed(120, 120 * testfloat);

überprüfen.

[Edit]
Ne, daran liegts auch nicht, hab's inzwischen probiert. :(

Gruß

mic

Sternthaler
15.07.2007, 13:16
Hallo BeeWee,
hast schon einmal probiert, ob dein Asuro überhaupt mit 120, 120 fährt?
Meiner fährt immer erst so mit Werten um 140, 160 an.
Wie du an dem Unterschied siehst habe ich auch das Problem, dass ein Motor (rechts) bei mir 'etwas' schlecht ist.

Es kann ja auch noch sein, dass der bei dir berechnete Wert für wheel_factor kleiner als 1 wird, dann würde natürlich dein 'Start'-Wert 120 noch kleiner werden und, zumindest mein Asuro, würde dann tatsächlich nicht mehr den einen Motor zum Rollen bringen.

BeeWee
15.07.2007, 13:24
@radbruch: :)
@Sternthaler: Ja, bei 120 fährt mein Asuro. Auch wenn ich überall 120 durch 255 ersetze ist es so, dass nach der Kalibrierung sich das linke Rad viel schneller dreht, als das rechte :/

BeeWee

radbruch
15.07.2007, 14:11
Hallo

Ich lass nicht locker 8-[ Wenn das rechte Rad schwergängiger wäre, würden beim Kalibrieren weniger Impulse gezählt und der Faktor deshalb größer 1 sein. Das wiederrum könnte bei MotorSpeed(255,255) kritisch werden, weil die Parameter 8Bit-Werte sind und deshalb die errechnete Power modulo 256 ist. Auch wieder Quatsch, weil weniger rechte als linke Impulse den Faktor kleiner machen:

relation = count_right / count_left;

Andersrum wäre richtig. Jetzt hab ich's aber, oder? O:)

Gruß

mic

Sternthaler
15.07.2007, 14:40
@radbruch
Ich finde, dass das als Lösung zu einfach wäre. ;-)
(Hoffentlich war es das aber!)

BeeWee
15.07.2007, 14:45
tut mir Leid, aber das war immer noch nicht die Lösung :/

Jetzt wird es seltsam (imho):
Ich habe zum Test dieses Script geschrieben:

#include "asuro.h"

int main(void)
{
float wheel_factor;

Init();

wheel_factor = Abc();
MotorSpeed(255, 255 * wheel_factor);

// Sleep 5 seconds
TimeSleep(5000);

MotorSpeed(255, 255 * 1.00);

while(1);
return 0;
}

float Abc(void) {
return 1.00;
}

void TimeSleep(unsigned int time) {
// Sleep for ``time`` miliseconds
unsigned int i;

for (i = 0; i < time; i++) {
Sleep(72);
}
}


Wenn ich das ausführe, fährt er erst 5 Sekunden im Kreis, danach aber relativ gerade. Hat jemand eine Ahnung, wie das geht? :-)

BeeWee

radbruch
15.07.2007, 15:35
Hallo

Ein gutes Testprogramm, du hast das echt drauf. Ich hingegen bin immer noch C-Einsteiger, aber aus diversen Gründen komme ich einfach nicht dazu, mir das besser anzueignen. Hier mein nächster Versuch:

MotorSpeed(255, 255 * 1.00);

Das 1.00 wird vermutlich vom Komplier erkannt und nach int umgewandelt und/oder durch einen konstanten Wert ersetzt, weil das Ergebniss der Multiplikation beim Programmlauf ja immer gleich ist. Das müsste man mal im Assemblerlisting kontrollieren. Oder mit anderen Werten ungleich 1.00 versuchen. Aber es dürfte schwierig sein, den Kompiler hier auszutricksen.

Vielleicht sollte man auf eine globale Variable ausweichen und diese in der Funktion ändern. Damit würde man alle eventuellen Typkonvertierungen bei Return umgehen. Das eigentliche Problem ist dann zwar immer noch nicht erkannt, aber das Programm würde dann vielleicht funktionieren.

gruß

mic

Werner++
15.07.2007, 15:36
Wenn ich das ausführe, fährt er erst 5 Sekunden im Kreis, danach aber relativ gerade. Hat jemand eine Ahnung, wie das geht?
Hallo BeeWee,

nein, da habe ich auch keine Idee. Aber um nochmal auf Dein ursprüngliches Programm zurückzukommen. Mit der Funktion CalibrateWheels stellst Du das Verhältnis der Geschwindigkeiten von rechtem zu linken Rad fest. Warum sollte der Asuro gerade aus fahren, wenn man den linken Wert bei Motorspeed damit multipliziert?
Da der Nullpunkt der Geschwindigkeit nicht bei 0 liegt, sondern bei einem Wert für MotorSpeed ca. um die 100 oder mehr, so kann das gewählte Verfahren im Grunde nie zu einer Geradeausfahrt führen.

Gruß
Werner

Sternthaler
15.07.2007, 15:41
Oh, oh,
wer hat denn da all die schönen warnings vom Compiler übersehen?

Ich habe den Code nun auch mal übersetzt und die warnings gesehen.
Das übersetzen vom Programm, mit der Abc()-Funktion, liefert einen Output mit:
"test.c:9: warning: implicit declaration of function `Abc'"

Was macht der Compiler da den raus?
Oh, schade, das wird ein int-Typ. Danach ist alles irgendwie falsch.

So geht es nun:
(Im ersten Programm fehlt auch noch ein "#include <string.h>", und dan sind da immer noch warnings)"


#include "asuro.h"

/* DAS HIER IST WICHTIG */
float Abc(void);
void TimeSleep (unsigned int time);

int main (void)
{
float wheel_factor;

Init ();

wheel_factor = Abc ();

MotorSpeed (255, 255 * wheel_factor);
TimeSleep (2000);

MotorSpeed (255, 255 * 1.00);
TimeSleep (2000);

MotorSpeed (0, 0);

while (1);
return 0;
}

float Abc(void)
{
return 1.00;
}

void TimeSleep (unsigned int time)
{
// Sleep for ``time`` miliseconds
unsigned int i;

for (i = 0; i < time; i++)
Sleep(72);
}

radbruch
15.07.2007, 15:48
Man seid ihr schnell. Ein Lösungsversuch ohne float:


int8_t CalibrateWheels(int8_t power_right) {
....

return power_right * count_left / count_right ;
}

@Werner++

Mit der Funktion CalibrateWheels stellst Du das Verhältnis der Geschwindigkeiten von rechtem zu linken Rad fest.
Es werden die Impulse innerhalb einer bestimmten Zeit gemessen. Daraus könnte man dann schon die Geschwindigkeit berechen, aber das braucht man nicht. Das wird auch sehr ungenau, weil der Hochlauf der Motoren noch nicht berücksichtigt ist. Auch andere Faktoren wie mechanische Ungenauigkeiten der Räder, der Untergrund und die Traktion spielen hier noch rein. Vereinfacht kann man aber sagen: Gleiche Impulszahl auf beiden Seiten bedeutet geradeaus.

Sternthaler
15.07.2007, 15:54
Und dann hier auch noch die Lösung für den letzten warning aus dem eigendlichen Programm:

void Write (char *msg); // Die Variable msg bitte mit * als Pointer uebergeben.

Und nun, alle zusammen: Juchu

@radbruch
Pfiffige Lösung zum umgehen des Problems!

ehenkes
15.07.2007, 16:48
Ihr seid ja richtig fix bei der Hitze. ;-)
Ich habe in der Zwischenzeit doch noch mit float herum gespielt, zum Geradeausfahren reicht das leider noch nicht, mal dreht er nach links, mal nach rechts ab.


#include "asuro.h"
#include <string.h> //strlen

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

void Write(char * msg)
{
SerWrite( msg, strlen(msg));
}

unsigned int is_bright(unsigned int darkness)
{
if (darkness > 512)
return 0;
else
return 1;
}

float CalibrateWheels(void)
{
Write("Start calibration");

unsigned int i; // counter
unsigned int data[2]; // odometry data

// rotation count of the wheels
unsigned int count_left = 0;
unsigned int count_right = 0;

// contains the last brightness state for the wheels
unsigned int last_state[2];
OdometrieData(data);
last_state[0] = is_bright(data[0]);
last_state[1] = is_bright(data[1]);

// the relation between the left amd the right wheel's rotation count
float relation;

// start driving
MotorDir(FWD, FWD);
MotorSpeed(120, 120);
TimeSleep(500); //Zum Hochfahren

// 5 seconds
for (i = 0; i < 100; ++i)
{
OdometrieData(data);

// if a wheel's brightness changed, increase the counter
if (is_bright(data[0]) != last_state[0])
count_left++;
if (is_bright(data[1]) != last_state[1])
count_right++;

last_state[0] = is_bright(data[0]);
last_state[1] = is_bright(data[1]);

TimeSleep(50);
}

relation = (float) count_right / (float) count_left;

// done testing, stop wheels
MotorSpeed(0, 0);

Write("Finished calibration");
return relation;
}

int main(void)
{
Init();

MotorSpeed(120, 120.0f * CalibrateWheels());

while(1);
return 0;
}


Hat jemand einen Tipp dazu aus euren bisherigen Überlegungen?

Sternthaler
15.07.2007, 22:18
Im Moment fällt mir nur folgendes ein:

Drum prüfe, was der Linker bindet, ob sich nicht noch ein warning findet. :lol:

Und auch von mir ein Willkommen an BeeWee und Werner++
Tut mit leid, hatte ich in der Hitze des Tages und der Fehlersuche übersehen, dass es euch neu in's Roboternetz gebracht hat.

datobbs
16.07.2007, 14:30
hi ehenks,

und von mir ebenfalls ein Willkommen an BeeWee und Werner++

ich habe noch nicht allzuviel ahnung,
aber ich würde mir mal am ende der calibration count_left und count_right ausgeben lassen, weil ich einfach mal spekulieren würde dass die nicht sonderlich hoch sind...vielleicht täusch ich mich auch...

gruß tobi

ehenkes
16.07.2007, 17:39
Der ASURO fährt während der Kalibrierung besser gerade aus als danach. Laughing


Drum prüfe, was der Linker bindet, ob sich nicht noch ein warning findet.Süßer Spruch! Den kannte ich noch gar nicht. ;-)

damaltor
16.07.2007, 19:42
Sagt mal fahren euro asuros echt erst so spät los? meiner fährt bei (70,70) schon (solage es nicht bergauf geht =)

Sternthaler
16.07.2007, 19:47
@damaltor
Bei 70? Wahnsinn!!! Fährst du mit Batterien? Alles geölt? Oder normaler Asuro?

@ehenkes
Hatte ich im Überschwang des Glück's gestern mal so erfunden. Meine Mutter hatte in meiner Sturm- und Drangzeit immer etwas Ähnliches auf den Lippen. Allerdings hatte sie keine Linker im Sinn. Und ich auch nicht ;-)

radbruch
17.07.2007, 00:48
http://www.yellowmap.de/images/blank.gif

ehenkes
17.07.2007, 00:53
Schade, der Thread hatte so einen ergeizigen Start und nun verliert er sich wieder im OffToppic und Smalltalk. Ich kann Dir genug Threads zeigen, in denen Du Dich in "Off Topic" verlierst. *lol*