simplefoc / Arduino-FOC-drivers

Drivers and support code for SimpleFOC
https://docs.simplefoc.com/drivers_library
MIT License
146 stars 63 forks source link

stm32hwencoder off-by-one #6

Closed sDessens closed 1 year ago

sDessens commented 2 years ago

There appears to be an off-by-one error in the timer code. Modifying this code:

    // set up timer for encoder
    encoder_handle.Init.Period = ticks_per_overflow;

to this:

    // set up timer for encoder
    encoder_handle.Init.Period = ticks_per_overflow - 1;

seems to fix it. Not sure if this is the best solution.

Testcase: move the motor to position 20000. Before change:

image

After change: image

By my calculations, the angle is off by 1/4096 rev every 15 revolutions. At position 14000 the angle is off by 159/4096 or (7 pole pairs) 0.25 electrical revolutions. i.e., the motor stops spinning exactly when the angle between the measured electrical angle and true electrical angle is 90°, that sounds about right.

@conroy-cheers

runger1101001 commented 2 years ago

Thanks a lot for reporting this. Looks like my test here (comparing ABI to SPI on the same AS5047) has the same result, the encoder is off by a small amount. Your suggestion fixes it. Makes perfect sense if you look at how the STM32 counters work, counting from 0 to the period value, inclusive, and then overflowing. So a period of 3 means 4 counts. So for 4096 counts we need to set a period of 4095.

runger1101001 commented 2 years ago

I pushed a fix to the dev branch, and will merge it into master ASAP.

askuric commented 2 years ago

Just one more remark regarding the this class. I am not sure if this is just in my case but I've had to first do the motor.init() and then call sensor.init(). in order for the encoder to work. I guess that in the driver low level code we do some manipulation that misconfigures the timers.

Maybe it would be a good idea to provide a small example code or to stress this fact in the readme.

runger1101001 commented 2 years ago

Hmmmm... interesting - my encoder is wired to the pins of TIM4... which pins/MCU or timer are you using @askuric ? In my setup I am initialising the encoder before the motor, and both are working.

sDessens commented 2 years ago

I did not have any problems with encoder initialization on the B-G431B-ESC1.

runger1101001 commented 2 years ago

I've now run it for about 36h, going back and forth at different speeds, to 50k+ radians and back the other way and the SPI and ABI are still completely aligned, so I will consider the off by 1 solved.

@askuric your issue still needs investigation.

conroy-cheers commented 2 years ago

Nice fix, thanks guys, and thanks @runger1101001 for documenting this and bringing it over here! Thinking back, I actually do remember the motor losing torque after continuously running for a while, but never managed to find the cause. Good to know it was a software bug :)

I didn't have to do anything specific with encoder initialisation, but I was also using the B-G431B-ESC1. The STM's timers are used for various things including PWM, and not all features are available on all timers. It does seem strange that everything still works correctly when reconfiguring the encoder timer after running the motor initialisation, though. Maybe motor.init() is reconfiguring some timers that it doesn't actually end up using?

Igitigit2 commented 1 year ago

Is there a trick to get the hardware encoder running on a B-G431B-ESC1 board? I am using the STM32HWEncoder from the dev branch of the drivers repo. I would like to try it since I am loosing pulses with the software encoder class although my signals look really good. Using the HW encoder class, no pulses are registered at all however. From what I see, usage should be more than trivial (declare it, call init(), that's it), so I am surprised it doesn't work. Maybe I am running into the same issue as @askuric, although I tried the sensor isolated without any motor code too, same thing. Is there any solution to it yet? Anything non-obvious I can do wrong here?

askuric commented 1 year ago

@Igitigit2, make sure to use the A and B channel of the encoder on the pins that belong to the same timer. Not all pin combinations will be allowed for the hardware encoder.

The best way, to my knowledge, to verify this is by downloading stm32CubeMX software. Then choose your board stm32g431 and declare the timer of your choice ans counter and see which pins correspond to the channels 1 and 2. You should be able to find some alternative combinations as well, but not any combination. I don't have the CubeMX at the moment, so I could not verify for you, but it is pretty straightforward to use.

Igitigit2 commented 1 year ago

Dear @askuric, that is exactly what I did. I use the H1 and H2 pins of the board as inputs, these are connected to PB6/7, which in turn are available for TIM4 Chan 1/2. I had a look at the code too, but it is not clear to me how it is decided which timer will be used. I guess, this is hidden somewhere in the function pinmap_peripheral(). One day I'll have to dig deeper into arduino-stm32...

Igitigit2 commented 1 year ago

Ok, I solved it. Problems were, that TIM4 still had to be enabled in PeripheralPins_B_G431B_ESC1.c for PB6 and PB7 and that STM32HWEncoder does not allow specifying any pins which are defined as alternate functions (e.g. PB_7_ALT1). After fixing that, I could use the hardware encoder class, but it did not solve my problem, I am still missing pulses. I will now go the hard way and try SPI on the B_G431B_ESC1.

runger1101001 commented 1 year ago

I'm sorry to hear this, I wonder what the problem is in your case...

SPI, IIRC, will not work on G431B-ESC1, because not all the pins are available. But I think SSI (no MOSI) can be made to work. So a sensor like the MT6701 or AS5048A or some others can be an option.

Igitigit2 commented 1 year ago

I wonder too! The plan is to verify it with the SPI interface of the sensor (in SSI mode). I already modified a broken board to have SPI3 available and use USART1 for debugging. Still need to hookup the sensor and get it to work in SSI mode, but USART1 works already. Let‘s see..

Am 14.11.2022 um 12:59 schrieb runger1101001 @.***>:



I'm sorry to hear this, I wonder what the problem is in your case...

SPI, IIRC, will not work on G431B-ESC1, because not all the pins are available. But I think SSI (no MOSI) can be made to work. So a sensor like the MT6701 or AS5048A or some others can be an option.

— Reply to this email directly, view it on GitHubhttps://github.com/simplefoc/Arduino-FOC-drivers/issues/6#issuecomment-1313569369, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AGCTSTO24KXYCPGRR5JQSWTWIISR7ANCNFSM5JFUYETA. You are receiving this because you were mentioned.Message ID: @.***>

runger1101001 commented 1 year ago

The originally reported issue is long solved, so I think we can close this ticket.