pico-micropython-examples icon indicating copy to clipboard operation
pico-micropython-examples copied to clipboard

Add PIO example for servo control

Open zeroflow opened this issue 3 years ago • 8 comments

Controls one servo at GP16 and additionally the onboard LED This demonstrates use of two servos.

zeroflow avatar Apr 08 '21 10:04 zeroflow

Could you add a README.adoc file and accompanying wiring diagram, similar to that found in other examples, e.g. see the NeoPixel ring example.

aallan avatar Apr 08 '21 10:04 aallan

Nice PIO example :slightly_smiling_face: Just a couple of queries: a) the comments talk about "IRQ4", but the code seems to be using relative IRQs? b) is there a reason for using relative IRQs, or would it make sense to use an absolute IRQ so that a single ServoTrigger could be used for multiple Servos?

lurch avatar Apr 08 '21 11:04 lurch

I will add a readme.

Regarding IRQs: Sharing the IRQ did not work, so I used relative IRQs. That way, the Trigger needs to be the SM before the output program, so the IRQs match.

zeroflow avatar Apr 08 '21 12:04 zeroflow

Regarding IRQs: Sharing the IRQ did not work, so I used relative IRQs. That way, the Trigger needs to be the SM before the output program, so the IRQs match.

Sounds like this should be in the README! :)

aallan avatar Apr 08 '21 12:04 aallan

Regarding IRQs: Sharing the IRQ did not work, so I used relative IRQs.

I hope you don't mind, but I had a bit of a fiddle.... :wink: (I'm still getting to grips with PIO myself)

I was able to get it working with only a single Servo_Trigger object by changing servo_trigger() to do:

    irq(clear, 4)         # Clear IRQ4, allows servo code to run again
    irq(4)                # Set IRQ4 again, ready for the wait in servo code

(which I guess then means I need to change the trig_ctr calculation to trig_ctr = (trig_frq // 1000 * trig_target) - 4), and changing servo_prog() to do:

    wait(0, "irq", 4) .side(0) # Wait here for IRQ to be released by trigger SM

:grinning:

Other comments:

  • As this is purely an example, it might be more useful to change the for _ in range(2): to while True: ?
  • IMHO the Servo_Trigger class ought to be renamed ServoTrigger (which is the typical Python convention)
  • Given the wide variability of servos, it's probably worth adding min_pulse and max_pulse arguments to your Servo init-method, and then doing
self.base_pulse = min_pulse
self.free_pulse = max_pulse - min_pulse

But of course these are only suggestions, I'll leave the final decision up to you.

lurch avatar Apr 08 '21 14:04 lurch

I don't mind - I'll check your suggestions later. During my testing, the 1-Trigger 2-Servo code compiled, but the output was garbage.

zeroflow avatar Apr 08 '21 14:04 zeroflow

Thanks! The replacement with IRQ/Clear + Wait did work.

zeroflow avatar Apr 08 '21 14:04 zeroflow

When testing the changes that I mentioned above, I had three separate servos all running from a single trigger :) But I had to insert some sleeps between moving each servo individually, because if I tried moving multiple servos at the same time, it tried to pull too much current from my computer's USB port and the Pico reset. (this is fixable by powering the servos from a separate PSU, but I couldn't be bothered to wire that up!)

lurch avatar Apr 08 '21 14:04 lurch