Silberstreifen
Active member
Ich bin vor einiger Zeit auf ein Thema gestoßen, dass ich mit Euch teilen möchte. Bei der Portierung der Hardware von der Ardumower PCB auf eine PICO-Version ist mir aufgefallen, dass die Drehzahlermittlung sehr ungenau ist.
In Sunray wir die Drehzahl durch Zählen der Impulse in einer festen Zeitspanne ermittelt. Dabei ist die Zeitspanne mit 50ms sehr kurz. Was zur Folge hat, dass nur sehr wenige Impulse gezählt werden. Bei einer Geschwindigkeit von 0,1m/s sind das beim Ardumower mit brushed Motoren lediglich 2 Impulse. Dabei entspricht ein Impuls 0,045m/s. Feiner kann die Drehzahl in Sunray nicht aufgelöst werden.
Bei den brushless Motoren mit 650 Ticks pro Umdrehung sieht es etwas besser aus. Ein Impuls entspricht 0,024m/s. Beim Alfred sind es 304 Ticks pro Umdrehung. Hier entspricht ein Impuls durch die kleineren Räder 0,042m/s.
Wenn der PID nun die Geschwindigkeit beim Ardumower mit brushed Motor bei 0,1m/s konstant halten soll, dann springt die ermittelte Drehzahl ständig zwischen 0,09 und 0,135m/s. Und der PID regelt entsprechend gegen. Was durchaus einen Beitrag zum drunken-Pilot-Verhalten leisten kann. Bei höheren Geschwindigkeiten springt die ermittelte Drehzahl genauso. Der PID muss also ständig gegenregeln.
Aus diesem Grunde habe ich die Drehzahlermittlung vom Zählen der Impulse auf das Messen der Zeitspanne zwischen den Impulsen umgestellt. Dadurch steigt die Auflösung und damit die Genauigkeit der Drehzahlermittlung von 0,045m/s auf 0,0009m/s. Wem das noch nicht reicht, der kann die Zeitspanne in Microsekunden messen. Was die Auflösung nochmals vertausendfacht.
Die erforderliche Änderung im Code ist nicht allzu aufwändig. In der AmRobotDriver.cpp muss folgendes angepasst werden
und
Mit dieser Änderung fahre ich jetzt seit 2 Wochen. Mein Eindruck ist, dass der Ardumower jetzt sehr viel ruhiger läuft und auch in der manuellen Steuerung sehr viel präziser geworden ist.
Vielleicht ist das ja etwas für die Mod-Version von @Mr. Tree
In Sunray wir die Drehzahl durch Zählen der Impulse in einer festen Zeitspanne ermittelt. Dabei ist die Zeitspanne mit 50ms sehr kurz. Was zur Folge hat, dass nur sehr wenige Impulse gezählt werden. Bei einer Geschwindigkeit von 0,1m/s sind das beim Ardumower mit brushed Motoren lediglich 2 Impulse. Dabei entspricht ein Impuls 0,045m/s. Feiner kann die Drehzahl in Sunray nicht aufgelöst werden.
Bei den brushless Motoren mit 650 Ticks pro Umdrehung sieht es etwas besser aus. Ein Impuls entspricht 0,024m/s. Beim Alfred sind es 304 Ticks pro Umdrehung. Hier entspricht ein Impuls durch die kleineren Räder 0,042m/s.
Wenn der PID nun die Geschwindigkeit beim Ardumower mit brushed Motor bei 0,1m/s konstant halten soll, dann springt die ermittelte Drehzahl ständig zwischen 0,09 und 0,135m/s. Und der PID regelt entsprechend gegen. Was durchaus einen Beitrag zum drunken-Pilot-Verhalten leisten kann. Bei höheren Geschwindigkeiten springt die ermittelte Drehzahl genauso. Der PID muss also ständig gegenregeln.
Aus diesem Grunde habe ich die Drehzahlermittlung vom Zählen der Impulse auf das Messen der Zeitspanne zwischen den Impulsen umgestellt. Dadurch steigt die Auflösung und damit die Genauigkeit der Drehzahlermittlung von 0,045m/s auf 0,0009m/s. Wem das noch nicht reicht, der kann die Zeitspanne in Microsekunden messen. Was die Auflösung nochmals vertausendfacht.
Die erforderliche Änderung im Code ist nicht allzu aufwändig. In der AmRobotDriver.cpp muss folgendes angepasst werden
void AmMotorDriver::getMotorEncoderTicks(int &leftTicks, int &rightTicks, int &mowTicks, double &leftTickTime, double &rightTickTime, double &mowTickTime){
leftTicks = odomTicksLeft;
rightTicks = odomTicksRight;
mowTicks = odomTicksMow;
// reset counters
leftTickTime = ((double)odoLastTickTimeLeft - (double)odoFirstTickTimeLeft) / 1000.0 / 1000.0;
if(odomTicksLeft != 0)odoFirstTickTimeLeft = odoLastTickTimeLeft;
odomTicksLeft = 0;
rightTickTime = ((double)odoLastTickTimeRight - (double)odoFirstTickTimeRight) / 1000.0 / 1000.0;
if(odomTicksRight != 0)odoFirstTickTimeRight = odoLastTickTimeRight;
odomTicksRight = 0;
mowTickTime = ((double)odoLastTickTimeMow - (double)odoFirstTickTimeMow) / 1000.0 / 1000.0;
if(odomTicksMow != 0)odoFirstTickTimeMow = odoLastTickTimeMow;
odomTicksMow = 0;
}
und
In der motor.cpp sieht die Drehzahlermittlung dann so ausvoid OdometryMowISR(){
if (digitalRead(pinMotorMowRpm) == LOW) return;
if (millis() < motorMowTicksTimeout) return; // eliminate spikes
motorMowTicksTimeout = millis() + 1;
odoLastTickTimeMow = micros();
odomTicksMow++;
asm("dsb");
}
void OdometryLeftISR(){
if (digitalRead(pinOdometryLeft) == LOW) return;
if (millis() < motorLeftTicksTimeout) return; // eliminate spikes
motorLeftTicksTimeout = millis() + 1;
odoLastTickTimeLeft = micros();
odomTicksLeft++;
asm("dsb");
}
void OdometryRightISR(){
if (digitalRead(pinOdometryRight) == LOW) return;
if (millis() < motorRightTicksTimeout) return; // eliminate spikes
motorRightTicksTimeout = millis() + 1;
odoLastTickTimeRight = micros();
odomTicksRight++;
asm("dsb");
#ifdef TEST_PIN_ODOMETRY
testValue = !testValue;
digitalWrite(pinKeyArea2, testValue);
#endif
}
if(ticksLeft != 0) motorLeftRpmCurr = (60.0 / (tickTimeLeft / (double)ticksLeft * (double)ticksPerRevolution));
if(ticksRight != 0) motorRightRpmCurr = (60.0 / (tickTimeRight / (double)ticksRight * (double)ticksPerRevolution));
if(ticksMow != 0) motorMowRpmCurr = (60.0 / (tickTimeMow / (double)ticksMow * (double)6.0));
Mit dieser Änderung fahre ich jetzt seit 2 Wochen. Mein Eindruck ist, dass der Ardumower jetzt sehr viel ruhiger läuft und auch in der manuellen Steuerung sehr viel präziser geworden ist.
Vielleicht ist das ja etwas für die Mod-Version von @Mr. Tree