Added PCA9685 PWM driver plugin
This commit is contained in:
parent
d7d5bcdd0c
commit
acc4f1c0e3
5 changed files with 128 additions and 0 deletions
|
@ -20,6 +20,8 @@ Given the high speed of development in the first phase, changes are being report
|
||||||
standard `joystick` system package to read the state of joysticks not compatible with
|
standard `joystick` system package to read the state of joysticks not compatible with
|
||||||
`python-inputs`.
|
`python-inputs`.
|
||||||
|
|
||||||
|
- Added PWM PCA9685 plugin.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- `switch.switchbot` plugin renamed to `switchbot.bluetooth` plugin, while the new plugin
|
- `switch.switchbot` plugin renamed to `switchbot.bluetooth` plugin, while the new plugin
|
||||||
|
|
0
platypush/plugins/pwm/__init__.py
Normal file
0
platypush/plugins/pwm/__init__.py
Normal file
120
platypush/plugins/pwm/pca9685.py
Normal file
120
platypush/plugins/pwm/pca9685.py
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import time
|
||||||
|
from typing import Optional, Dict
|
||||||
|
|
||||||
|
from platypush.plugins import Plugin, action
|
||||||
|
|
||||||
|
|
||||||
|
class PwmPca9685Plugin(Plugin):
|
||||||
|
"""
|
||||||
|
This plugin interacts with an `Adafruit PCA9685 <https://learn.adafruit.com/16-channel-pwm-servo-driver?view=all>`_
|
||||||
|
circuit, a 16-channel PWM servo driver. You can leverage this plugin to control servos and motors through Platypush.
|
||||||
|
|
||||||
|
Note that the driver for PCA9685 has been written for CircuitPython, and in order to use it on a Raspberry Pi or
|
||||||
|
similar devices you need to
|
||||||
|
`follow these steps <https://learn.adafruit.com/16-channel-pwm-servo-driver?view=all#python-circuitpython>`_::
|
||||||
|
|
||||||
|
# pip3 install --upgrade adafruit-python-shell
|
||||||
|
$ wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py
|
||||||
|
# python3 raspi-blinka.py
|
||||||
|
|
||||||
|
Then reboot and check that the following virtual devices are available::
|
||||||
|
|
||||||
|
- /dev/i2c-1
|
||||||
|
- /dev/spidev0.0
|
||||||
|
- /dev/spidev0.1
|
||||||
|
|
||||||
|
Finally, install the PCA9685 drivers::
|
||||||
|
|
||||||
|
# pip3 install --upgrade adafruit-circuitpython-pca9685
|
||||||
|
|
||||||
|
This plugin works with a PCA9685 circuit connected to the Platypush host over I2C interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
MIN_PWM_VALUE = 0
|
||||||
|
MAX_PWM_VALUE = 0xffff
|
||||||
|
|
||||||
|
def __init__(self, frequency: float, step_value: float = 0.1, step_duration: float = 0.05, **kwargs):
|
||||||
|
"""
|
||||||
|
:param frequency: Default PWM frequency to use for the driver, in Hz.
|
||||||
|
:param step_value: How much each channel value should be increased/decreased on each step.
|
||||||
|
:param step_duration: Length of each step transient when writing PWM values (default: 0.05 seconds).
|
||||||
|
"""
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.frequency = frequency
|
||||||
|
self.step_value = step_value
|
||||||
|
self.step_duration = step_duration
|
||||||
|
self._pca = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _convert_percent_to_duty_cycle(value: float) -> int:
|
||||||
|
"""
|
||||||
|
Convert a duty cycle percentage value to a PCA9685 value between 0 and `0xffff`.
|
||||||
|
|
||||||
|
:param value: Duty cycle value, between 0 and 1.
|
||||||
|
:return: Duty cycle 16-bit value, between 0 and `0xffff`.
|
||||||
|
"""
|
||||||
|
return int(value * 65535)
|
||||||
|
|
||||||
|
@action
|
||||||
|
def execute(self, channels: Dict[int, float], frequency: Optional[float] = None, step_value: Optional[float] = None,
|
||||||
|
step_duration: Optional[float] = None):
|
||||||
|
"""
|
||||||
|
Send PWM values to the specified channels.
|
||||||
|
|
||||||
|
:param channels: Map of the values to be written, as ``channel_index -> value``, where value is a real number
|
||||||
|
between 0.0 (minimum duty cycle) and 1.0 (maximum duty cycle).
|
||||||
|
:param frequency: Override default frequency.
|
||||||
|
:param step_value: Override default step value.
|
||||||
|
:param step_duration: Override default step duration.
|
||||||
|
"""
|
||||||
|
import busio
|
||||||
|
from board import SCL, SDA
|
||||||
|
from adafruit_pca9685 import PCA9685
|
||||||
|
|
||||||
|
values = {k: self._convert_percent_to_duty_cycle(v) for k, v in channels.items()}
|
||||||
|
step_value = self._convert_percent_to_duty_cycle(step_value if step_value is not None else self.step_value)
|
||||||
|
step_duration = step_duration if step_duration is not None else self.step_duration
|
||||||
|
i2c_bus = busio.I2C(SCL, SDA)
|
||||||
|
pca = self._pca or PCA9685(i2c_bus)
|
||||||
|
pca.frequency = frequency or self.frequency
|
||||||
|
self._pca = pca
|
||||||
|
done = False
|
||||||
|
|
||||||
|
while not done:
|
||||||
|
done = True
|
||||||
|
|
||||||
|
for channel, value in values.items():
|
||||||
|
if value == pca.channels[channel].duty_cycle:
|
||||||
|
continue
|
||||||
|
|
||||||
|
done = False
|
||||||
|
if value > pca.channels[channel].duty_cycle:
|
||||||
|
pca.channels[channel].duty_cycle = min(pca.channels[channel].duty_cycle + step_value,
|
||||||
|
self.MAX_PWM_VALUE)
|
||||||
|
else:
|
||||||
|
pca.channels[channel].duty_cycle = max(pca.channels[channel].duty_cycle - step_value,
|
||||||
|
self.MIN_PWM_VALUE)
|
||||||
|
|
||||||
|
time.sleep(step_duration)
|
||||||
|
|
||||||
|
@action
|
||||||
|
def deinit(self):
|
||||||
|
"""
|
||||||
|
De-initialize the PCA9685 if it was previously initialized.
|
||||||
|
"""
|
||||||
|
if not self._pca:
|
||||||
|
self.logger.warning('The PCA9685 driver is not initialized')
|
||||||
|
return
|
||||||
|
|
||||||
|
self._pca.deinit()
|
||||||
|
|
||||||
|
@action
|
||||||
|
def reset(self):
|
||||||
|
"""
|
||||||
|
Reset the PCA9685 (set all the channels to zero).
|
||||||
|
"""
|
||||||
|
if not self._pca:
|
||||||
|
self.logger.warning('The PCA9685 driver is not initialized')
|
||||||
|
return
|
||||||
|
|
||||||
|
self._pca.reset()
|
|
@ -317,3 +317,7 @@ croniter
|
||||||
|
|
||||||
# Support for file.monitor backend
|
# Support for file.monitor backend
|
||||||
#watchdog
|
#watchdog
|
||||||
|
|
||||||
|
# Support for Adafruit PCA9685 PWM controller
|
||||||
|
#adafruit-python-shell
|
||||||
|
#adafruit-circuitpython-pca9685
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -249,5 +249,7 @@ setup(
|
||||||
'smartthings': ['pysmartthings', 'aiohttp'],
|
'smartthings': ['pysmartthings', 'aiohttp'],
|
||||||
# Support for file.monitor backend
|
# Support for file.monitor backend
|
||||||
'filemonitor': ['watchdog'],
|
'filemonitor': ['watchdog'],
|
||||||
|
# Support for Adafruit PCA9685 PWM controller
|
||||||
|
'pca9685': ['adafruit-python-shell', 'adafruit-circuitpython-pca9685'],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue