Encoder skips pulses

I’m controlling a brushless motor with an arduino nano and a custom motor driver board. I’m using the 6PWM driver and a 600ppm encoder. I am running the motor in closed loop position control and setting the target angle to 5 rad, waiting a few seconds, then setting the target angle to -5 rad.

After a few cycles the motor draws far more current when spinning in one direction and eventually slows down and stops.
I hooked up another arduino to the encoder lines and noticed that the position of the target angles slowly drifted. I believe this is caused by the driver missing encoder pulses and the motor phase becoming missaligned with the driver phase.

I am using software interrupts as the 6PWM driver uses one of the hardware interrupt pins.

Is there anything I can do to debug/fix this?

Welcome to SimpleFOC, @varun_dixit !

You might be able to optimize it, but I’m doubtful…

Software interrupts are a bit problematic to begin with, and the Nano is a slow 8bit MCU…

If you switch to a faster 32 bit MCU my guess is it will work much better (and you probably won’t need software interrupts in the first place)

Thanks for the welcome and quick response!

I have since switched to a raspberry pi pico from your advice. The encoder inputs are now on a hardware interrupt pin.

The problem has gotten better after the switch, however I still notice that the at higher speeds, the motor slows down and draws more current before stopping completely. I am now certain that the issue is the driver missing encoder pulses.

I toggle a pin in one of the encoder pin’s interrupt function and monitiored its switching vs the encoder pin. After a while of running the motor, I noticed that the interrupt function, while usually only delayed ~10us from the encoder pin, can be delayed by over 100us after the encoder pin changes. I have also noticed it missing encoder pulses of 120us completely.

Is there anything that could be blocking the interrupt function from being called? This issue seems strange to me.

Hi,

Yes, interrupts execute one at a time and when they happen at the same time, one goes first and the other gets delayed. If it gets delayed so much that the next interrupt of the same type happens, then it can be skipped entirely, I believe. I’d have to dig into the details of the Pico Datasheet to say for sure, as MCU types can differ in the way they handle interrupts.
But for sure it is possible to overload any MCU with interrupts and cause them to become unreliable.

On the other hand the Pico is a fairly fast MCU, so I have to say I am surprised you can overload it with encoder interrupts. Perhaps it is due to some other interrupt routine, for example involved in SPI, Serial comms or similar?

I think the problem may be related to the way the Encoder class is implemented: the current implementation receives the interrupt call, but “doesn’t trust it”. Instead, it checks again the state of the pin within the interrupt routine. However, if the interrupt is delayed, the pin state may no longer correspond to the one that generated the interrupt - and the encoder class “miscounts” even though the interrupt was received.

We could try to remove this double-checking in the Encoder class - it is helpful in situations where there is noise on the encoder signals and the speed is not very high, but it does not work when speeds increase…
Out of interest, what speeds are you running at before you get problems?

Another good option might be to instead use our “GenericSensor” class and combine it with an existing Pico implementation for Encoders based on hardware, perhaps the PIO? Something like this:

Another option can be to switch MCU again - for STM32 MCUs we have a STM32HardwareEncoder class that uses these chip’s timer hardware to implement the encoder counting with no interrupts or MCU overhead…