adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.04k stars 1.2k forks source link

Set PWM frequency and duty cycle in microseconds #85

Closed deshipu closed 7 years ago

deshipu commented 7 years ago

The current nativeio.PWMOut is pretty nice for things like controlling LED dimming or motor speed. However it's hopelessly inadequate for controlling hobby servos or BLDC ESCs.

For controlling hobby servos I need to be able to specify the frequency (for instance, most analog servos expect 50Hz, digital servos and ESCs may go up to 300Hz or maybe even higher).

Setting the duty cycle as percentage of the total period (converted to 0-255) is also fine for LEDs, but for servos, which typically expect duty cycles between 1000µs and 2000µs with period of 20000µs that gives very poor resolution, makes it harder to calculate the right value, and gives an opportunity for rounding errors. It would be much nicer to be able to set the duty cycle in terms of absolute time units, like microseconds.

tannewt commented 7 years ago

Frequency already is covered in #13 . Handling microseconds is a good point and I'll leave this open for that.

tannewt commented 7 years ago

After implementing frequency and switching duty_cycle to 16 bit I think setting these based on milliseconds is best done in a library. Adding it the core will take extra space even when its not needed. You shouldn't have any trouble with resolution now that its 16 bit.

bart commented 5 years ago

@deshipu and @dhalbert How did you solve it? Could you please give an example? Having the same issue now and want to control an ESC with a pulse width between 1000 and 2000 µs

tannewt commented 5 years ago

While it's for Servos you should be able to use this for ESCs as well: https://github.com/adafruit/Adafruit_CircuitPython_Motor/blob/master/adafruit_motor/servo.py

bart commented 5 years ago

Thank you sir, I'm already using this library. But which method would you suggest? angle() doesn't sound correct to me for an ESC.

chrisalbertson commented 1 year ago

What did I do? In Micropython there is method called "duty()" about like in Ciruitpyton but they also have "duty_ns(pulse_len)" where pulse_len is an integer in nanoseconds. So I used Micropython. This is the only solution that avoids round off errors.

Their library code, then converts the nanoseconds into "timer counts". There is are numeric issues like we are stuck with here.

What is not understood by Circuitpython authors is PWM is many times used to transmit numeric data, where the value is encoded in the length of the pulse. This is very different from when PWM is used to create a pseudo-analog voltage on a wire. If y need to specify an exact number of uSeconds, then you need to move to Micropython.