[BUG] LowPassFilter::operator() returns nan
Describe the bug LowPassFilter::operator() returns nan when called with zero dt and zero Tf.
I have a multi-threaded setup running where I asynchronously call FOCMotor::shaftAngle() from different threads. Occasionally my setup breaks down because the LPF returns nan. That happens because the LPF is initialized with zero Tf in the FOCMotor class and occasionally dt is also zero which then breaks the formula in LowPassFilter::operator():
float alpha = Tf/(Tf + dt);
I'm actually surprised that nobody else had this problem yet, so I'm wondering if I am doing sth wrong.
hardware setup
- Motor: GB4106
- Driver: DRV8313
- MCU: ESP32
- Sensor: AS5048
- No current sensing
IDE
- Platformio
Suggested Solution Catch the zero case by turning
if (dt < 0.0f ) dt = 1e-3f;
into
if (dt <= 0.0f ) dt = 1e-3f;
But I think that 1e-3f is actually a little too large and would suggest to go with 1e-4f or 1e-5f
Thank you for reporting it, and sorry to take a long time to get back to you.
I guess the value assigned to dt doesn't matter in this case, because alpha will be 0 when Tf is set to 0, regardless of the value of dt.
I have to think about this solution a bit, and ask some of the other developers, but I'll try to have a fix for this in the next release.
As an aside, I don't think you should be calling FOCMotor.shaftAngle() from multiple threads. One of your threads should be calling motor.move() in a fairly tight loop. motor.move() calls the shaftAngle() function for you once per call to motor.move() and set the value obtained to the field motor.shaft_angle. (See BLDCMotor.cpp line 409)
So your other threads should obtain the value from the field motor.shaft_angle, rather than calling the function. In this way I think you'll avoid the 0 dt case and won't have this error.
thank you @runger1101001 for your answer!
As an aside, I don't think you should be calling FOCMotor.shaftAngle() from multiple threads. One of your threads should be calling motor.move() in a fairly tight loop. motor.move() calls the shaftAngle() function for you once per call to motor.move() and set the value obtained to the field motor.shaft_angle. (See [BLDCMotor.cpp line 409]> (https://github.com/runger1101001/Arduino-FOC/blob/1f0be50f81f1b6151d5d629a2386a9a5a02ebd5f/src/BLDCMotor.cpp#L409))
So your other threads should obtain the value from the field motor.shaft_angle, rather than calling the function. In this way I think you'll avoid the 0 dt case and won't have this error.
Makes sense and I now understand this after I looked into the code. I'm certainly going to do it this way, thanks for the hint! However I also think this is not really the behavior one would expect from a user perspective. In a sense I would expect that function to work as a getter that I can arbitrarily call.