Ich versuche, eine einfache Odometrie-Berechnungsschleife zu implementieren. Was in einer While-Schleife ausgeführt wird. Nachfolgend der Code:
double dx=0,dy=0,dw=0;
double v,w;
void computeOdom(){
uint32_t ticknow=ticksms; //global timer variable (gives current ticks in milliseconds)
v=0.0;
w=0.0;
double dt = (ticknow - tickprev)/1000.0; //time elapsed since last odom update
double res = (double)ENCODER_RESOLUTION; //Encoder Resolution ticks per revolution
double leftvel = (double) ((((Left.position)/res) * 2 * M_PI))/dt; // Angular velocity of left wheel (rad/s)
Left.position=0;
double rightvel=(((double)Right.position)/ENCODER_RESOLUTION)* 2 * M_PI/dt; //Angular velocity of right wheel (rad/s)
Right.position=0;
double r_L= 0.260/2;
double r_R= 0.260/2;
v += (r_L/2.0) * leftvel; //Linear velocity of the robot
v += (r_R/2.0) * rightvel;
w += (r_R/0.610) * rightvel; //Angular velocity of the robot
w -= (r_L/0.610) * leftvel;
double tempx=0.0,tempy=0.0,tempz=0.0;
if(!(w==0.0f)){
dx += (double)(dt * v * arm_cos_f32(dw + dt*(w/2.0))); //The line where dx becomes NaN
dy += (double)(dt * v * arm_sin_f32(dw + dt*(w/2.0))); //The line where dy becomes NaN
dw += (dt * w);
}
else{
dx += (double)(dt * v * arm_cos_f32(dw));
dy += (double)(dt * v * arm_sin_f32(dw));
}
tickprev = ticknow;
printf("prev_x: %f\n\r",dx);
}
Ich habe den Code mit GDB debuggt. Ich habe nach Ausnahmen gesucht, die ausgelöst werden, aber alles sieht gut aus. Und wenn ich den Code so ändere:
dx = (double)(dt * v * arm_cos_f32(dw + dt*(w/2.0)));
dy = (double)(dt * v * arm_sin_f32(dw + dt*(w/2.0)));
Das NaN verschwindet. Ich habe versucht, temporäre lokale Variablen zu verwenden. cos
Ich habe die Funktionen und überprüft sin
, indem ich sie auf lokalen Variablen ausgeführt habe, und sie funktionieren wie beabsichtigt. Da gibt es keine Probleme. Nur wenn ich die globalen Variablen inkrementieren möchte, tritt das Problem auf. dx
, dy
und dw
sind persistente globale Variablen, die die Position verfolgen.
Dies ist die Version von arm-gcc, die ich verwende.
arm-none-eabi-gcc 5.4.1 20160609 (Veröffentlichung) [ARM/embedded-5-branch revision 237715]
Ich verwende das STM32F429 Discovery Board mit Arm-gcc-Toolchain und FPU wurde aktiviert. Das Deaktivieren der FPU hat keinerlei Auswirkung.
Irgendwelche Hinweise oder Vorschläge?
@MarkoBursic Vielen Dank, dass Sie darauf hingewiesen haben, Mann. Weißt du, tatsächlich habe ich seit gestern so viele Änderungen an diesem winzigen Stück Code vorgenommen, dass ich anfing, den Überblick über die Idiotizität zu verlieren :). Jedenfalls habe ich es irgendwie geschafft, das Problem zu lösen. Gedulde dich eine Weile mit mir. Mit gdb ging ich den Code noch einmal durch und überprüfte jede Variable vor und nach jeder Ausführungszeile. leftvel war ursprünglich ein nan (0x400000), als dt null war, da während der ersten Iteration tickprev und ticknow gleich waren (0). Da leftvel und rightvel lokale Variablen sind, blieben die nan-Werte nicht erhalten. Und dieser Nan-Wert wurde mit meinen globalen Variablen multipliziert, die persistent sind. Also habe ich diese Zeile hinzugefügt:
if(isnan(leftvel) || isnan(rightvel))
return;
Kurz vor der Multiplikation mit dx,dy und dw. Vielen Dank für Ihre Vorschläge @MarcoBursic @BenceKaulics
Lesen Sie es als längeren Kommentar:
Warum analysieren Sie die Ergebnisse ständig, um sie zu verdoppeln? Viele Zwischenergebnisse könnten auf const gesetzt werden.
double res = (double)ENCODER_RESOLUTION;
?? 1. Zeitverschwendung,
double rightvel=(((double)Right.position)/ENCODER_RESOLUTION)* 2 * M_PI/dt;
2. Zeitverschwendung,
Das sollte das gleiche sein, aber es ist:
double leftvel = (double) ((((Left.position)/res) * 2 * M_PI))/dt;
2 * M_PI/ENCODER_RESOLUTION könnte eine Konstante sein.
uint32_t ticknow=ticksms;
double dt = (ticknow - tickprev)/1000.0; //time elapsed since last odom update
Sieh mal, du hast uint32 , dann dividierst du durch Float-Nummer 1000.0 und du erwartest das Doppelte. double((ticknow - tickprev))/1000.0
. Sie parsen wo nicht unbedingt, aber Sie vergessen zu parsen wo Sie sollten.
(ticknow - tickprev)/1000.0
. Die Subtraktion erfolgt auf uint32_t, was in Ordnung zu sein scheint. Das Ergebnis der Subtraktion ist vom Typ uint32_t. Dies wird dann auf doppelt ausgeglichen, da 1000.0
es sich um ein doppeltes Literal handelt (nicht float
). Sie müssen nichts ändern. Und ich habe keine Ahnung, was das double((ticknow - tickprev))/1000.0
bedeuten soll, aber es ist kein gültiges C.
Asusrog
Bence Kaulics
float
notdouble
, wenn Sie FPU haben.double
ist kein Fließkommawert, deshalb hat FPU keine Wirkung.Bence Kaulics
double
in geändert habenfloat
.m.Alin
double
kann auch 32-Bit-Single-Precision sein; Der Compiler könnte den C-Standard umgehen unddouble
dasselbe wie implementierenfloat
.Bence Kaulics
m.Alin
Bence Kaulics
Asusrog
Bence Kaulics
float
Typen verwenden sollten, um die Vorteile der FPU zu nutzen.