Encoder bugs
Posted: Thu Mar 10, 2022 2:52 pm
I have been using the Encoder class in inc_encoder.h/cpp as the basis of a resolver encoder for my Tesla M3 project. I've run into a couple of bugs in the way the class works that probably need looking at.
1) The first problem is an off by one error in the calculation of Encoder::GetFullTurns(). The poleCounter value that is in Encoder::UpdateRotorAngle() is updated by 1 more than the number of resolver pole pairs. So respolepairs = 1 it goes 0 then 1. For respolepairs = 3 it goes 0, 1, 2, 3. The number of turns is only incremented when poleCounter == 0. poleCounter should be reset with Param::GetInt(Param::respolepairs) - 1; The impact appears minimal as GetFullTurns() appears to be used for only for information purposes.
2) The turnsSinceLastSample variable is racily updated by both the main control loop through Encoder::UpdateRotorAngle() as well as the 100ms interrupt calling UpdateRotorFrequency(). I believe this will result in occasional glitches in the frequency calculation. Given the frequency calculation is fairly simple would it not be better to do this all in UpdateRotorAngle()? A counter could use the pwmFrq to calculate at the desired frequency. This would ensure that all accesses from outside of PWM motor control context are reads.
I'd offer to fix the code but I haven't got an STM32 inverter and motor HW so it would be pretty difficult to test.
1) The first problem is an off by one error in the calculation of Encoder::GetFullTurns(). The poleCounter value that is in Encoder::UpdateRotorAngle() is updated by 1 more than the number of resolver pole pairs. So respolepairs = 1 it goes 0 then 1. For respolepairs = 3 it goes 0, 1, 2, 3. The number of turns is only incremented when poleCounter == 0. poleCounter should be reset with Param::GetInt(Param::respolepairs) - 1; The impact appears minimal as GetFullTurns() appears to be used for only for information purposes.
2) The turnsSinceLastSample variable is racily updated by both the main control loop through Encoder::UpdateRotorAngle() as well as the 100ms interrupt calling UpdateRotorFrequency(). I believe this will result in occasional glitches in the frequency calculation. Given the frequency calculation is fairly simple would it not be better to do this all in UpdateRotorAngle()? A counter could use the pwmFrq to calculate at the desired frequency. This would ensure that all accesses from outside of PWM motor control context are reads.
I'd offer to fix the code but I haven't got an STM32 inverter and motor HW so it would be pretty difficult to test.