Servo update unexpectedly slow?

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Servo update unexpectedly slow?

Post by BooleanMattock »

I am using CircuitPython on a Raspberry Pi Pico to control 4 servos. The servos are connected to GP0-GP3 and I'm using the servo class from adafruit_motor. Functionally, everything works perfectly, but the code is running much slower than I expected. I used time.monotonic_ns() to get some approximate timing measurements, and

Code: Select all

    time1 = time.monotonic_ns()
    servos[servoIndex].angle = angle
    time2 = time.monotonic_ns()
gives a value of time2 - time1 of about 15mS. Even allowing a small amount of time (much less than 1mS) for the time.monotonic_ns() calls, this means that setting servo.angle is taking more than 14mS. Even on a modest processor like the Pico, this seems a very long time for a call that as far as I know has to:
- do a simple angle-to-PWM calculation
- write a new PWM value to the PWM registers for the output pin

Can anyone help explain either why the servo update is so slow, or what I'm doing wrong?

Thank you in advance for any help!

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

PS - one other thought, can anyone point me to the source code for this library so I can take a look at what's going on?

User avatar
tannewt
 
Posts: 3298
Joined: Thu Oct 06, 2016 8:48 pm

Re: Servo update unexpectedly slow?

Post by tannewt »


User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

tannewt wrote: Wed Nov 16, 2022 1:48 pm The source is here: https://github.com/adafruit/Adafruit_Ci ... ruit_motor
Thank you, most appreciated!

Looks like there's some simple code to calculate the pulse width, then a call to the underlying PWM channel code...do you happen to know where the code for that is? I presume that would be in a hardware-specific library.

User avatar
tannewt
 
Posts: 3298
Joined: Thu Oct 06, 2016 8:48 pm

Re: Servo update unexpectedly slow?

Post by tannewt »

The native PWMOut implementation for the RP2040 is here: https://github.com/adafruit/circuitpyth ... o/PWMOut.c

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

Thank you again!

OK, so in the code for setting PWM duty cycle I found this:

Code: Select all

    // Wait for wrap so that we know our new cc value has been applied. Clear
    // the internal interrupt and then wait for it to be set. Worst case, we
    // wait a full cycle.
    pwm_hw->intr = 1 << self->slice;
    while ((pwm_hw->en & (1 << self->slice)) != 0 &&
           (pwm_hw->intr & (1 << self->slice)) == 0 &&
           !mp_hal_is_interrupted()) {
    }
 
So, if your PWM frequency is 1kHz or more, waiting a whole PWM cycle is probably not a big deal. But servos run at 50Hz, which means this code could cause a delay of up to 20mS, which is a big deal when running multiple servos.

Have I understood the code correctly?

Do the people who write the drivers look at this forum?

User avatar
tannewt
 
Posts: 3298
Joined: Thu Oct 06, 2016 8:48 pm

Re: Servo update unexpectedly slow?

Post by tannewt »

BooleanMattock wrote: Wed Nov 16, 2022 8:42 pm So, if your PWM frequency is 1kHz or more, waiting a whole PWM cycle is probably not a big deal. But servos run at 50Hz, which means this code could cause a delay of up to 20mS, which is a big deal when running multiple servos.

Have I understood the code correctly?
Yup, I think so!
BooleanMattock wrote: Wed Nov 16, 2022 8:42 pm Do the people who write the drivers look at this forum?
I wrote it. :-)
2022-11-17_10-05.png
2022-11-17_10-05.png (47.76 KiB) Viewed 146 times
I agree that this is less than ideal. It looks like I added it to fix a couple issues: https://github.com/adafruit/circuitpyth ... -887631842 We should probably fix it a differently. Feel free to file a new issue and we can get it fixed.

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

Wow, awesome!

Quietly blown away by how quick and positive the response has been to my first ever forum post!

Thank you so much!

I'll file a new issue - this will be my first ever experience with GitHub so apologies in advance if I don't do it very skillfully...

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

Issue #7224. Hope I did it right, let me know if not!

User avatar
tannewt
 
Posts: 3298
Joined: Thu Oct 06, 2016 8:48 pm

Re: Servo update unexpectedly slow?

Post by tannewt »

Yup! Issue looks good. Thanks! Here is a link for other folks: https://github.com/adafruit/circuitpython/issues/7224

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

So the feedback on the bug report is that it won't be fixed in 8.0.0 but will be fixed in 8.x.x. I'm not familiar with the release cycles of CircuitPython - any feel for how long this means it will take for it to be fixed? Just trying to get a feel for whether it's likely to be weeks/months/years...

In the meantime, any suggestions on possible workarounds? Since it's in the hardware specific PWM code it seems like it would be hard to bypass?

Many thanks in advance for any help/thoughts.

User avatar
tannewt
 
Posts: 3298
Joined: Thu Oct 06, 2016 8:48 pm

Re: Servo update unexpectedly slow?

Post by tannewt »

My guess would be months unless someone from the community picks it up and fixes it. (I'm happy to give pointers to do that.) We (Adafruit funded folks) are focused on getting 8.0 done now and I didn't want to block it on this issue.

I'd encourage you to dig in and try to fix it. You found the exact spot to change already. We have the build process for CircuitPython documented on Learn: https://learn.adafruit.com/building-circuitpython

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

That sounds like an excellent idea, I'll give it a shot and come back to you for pointers if I get stuck!

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

OK, managed to do a rough/dirty build of the latest 8.0.0 files with the offending line in the driver commented out.

Props to the writers of the "Build CircuitPython" documentation, the whole setup of tools and initial build was pretty painless, with only one weird glitch.

Initial test without real servos connected seems to run ok. Updating servo position now happening in much less than 1mS. Will hopefully test tomorrow driving real hardware.

User avatar
BooleanMattock
 
Posts: 49
Joined: Wed Nov 16, 2022 8:14 am

Re: Servo update unexpectedly slow?

Post by BooleanMattock »

Tested with real servos - can now drive 7 servos simultaneously without the delay issues!

I assume my fix (just commenting out the busy-wait code) breaks something else, however. I was unable to find the code that calls common_hal_pwmio_pwmout_set_duty_cycle() that needs the busy-wait - the HAL interface is a bit difficult to follow for a newbie. Is it possibly common_hal_pulseio_pulseout_construct() in PulseOut.c?

Locked
Please be positive and constructive with your questions and comments.

Return to “Adafruit CircuitPython”