Added PWM3901 optical motion/flow sensor plugin
This commit is contained in:
parent
a580cc93eb
commit
7e92f59d44
6 changed files with 143 additions and 0 deletions
|
@ -223,6 +223,7 @@ autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers',
|
|||
'envirophat',
|
||||
'gps',
|
||||
'picamera',
|
||||
'pwm3901',
|
||||
]
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
|
|
0
platypush/backend/sensor/motion/__init__.py
Normal file
0
platypush/backend/sensor/motion/__init__.py
Normal file
32
platypush/backend/sensor/motion/pwm3901.py
Normal file
32
platypush/backend/sensor/motion/pwm3901.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
from platypush.backend.sensor import SensorBackend
|
||||
|
||||
|
||||
class SensorPwm3901Backend(SensorBackend):
|
||||
"""
|
||||
Backend to poll an `PWM3901 <https://github.com/pimoroni/pmw3901-python>`_
|
||||
optical flow and motion sensor
|
||||
|
||||
Requires:
|
||||
|
||||
* ``pwm3901`` (``pip install pwm3901``)
|
||||
"""
|
||||
|
||||
def __init__(self, absolute=True, relative=True, **kwargs):
|
||||
"""
|
||||
:param absolute: Enable absolute motion sensor events (default: true)
|
||||
:param relative: Enable relative motion sensor events (default: true)
|
||||
"""
|
||||
|
||||
enabled_sensors = {
|
||||
'motion_rel_x': relative,
|
||||
'motion_rel_y': relative,
|
||||
'motion_rel_mod': relative,
|
||||
'motion_abs_x': absolute,
|
||||
'motion_abs_y': absolute,
|
||||
'motion_abs_mod': absolute,
|
||||
}
|
||||
|
||||
super().__init__(plugin='gpio.sensor.motion.pwm3901', enabled_sensors=enabled_sensors, **kwargs)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
0
platypush/plugins/gpio/sensor/motion/__init__.py
Normal file
0
platypush/plugins/gpio/sensor/motion/__init__.py
Normal file
107
platypush/plugins/gpio/sensor/motion/pwm3901.py
Normal file
107
platypush/plugins/gpio/sensor/motion/pwm3901.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
import enum
|
||||
import math
|
||||
|
||||
# noinspection PyUnresolvedReferences,PyPackageRequirements
|
||||
from pmw3901 import PMW3901, BG_CS_FRONT_BCM, BG_CS_BACK_BCM
|
||||
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.gpio.sensor import GpioSensorPlugin
|
||||
|
||||
|
||||
class Rotation(enum.IntEnum):
|
||||
ROTATE_0 = 0
|
||||
ROTATE_90 = 90
|
||||
ROTATE_180 = 180
|
||||
ROTATE_270 = 270
|
||||
|
||||
|
||||
class SPISlot(enum.Enum):
|
||||
FRONT = 'front',
|
||||
BACK = 'back'
|
||||
|
||||
|
||||
class GpioSensorMotionPwm3901Plugin(GpioSensorPlugin):
|
||||
"""
|
||||
Plugin to interact with an `PWM3901 <https://github.com/pimoroni/pmw3901-python>`_
|
||||
optical flow and motion sensor
|
||||
|
||||
Requires:
|
||||
|
||||
* ``pwm3901`` (``pip install pwm3901``)
|
||||
"""
|
||||
|
||||
def __init__(self, rotation=Rotation.ROTATE_0.value, spi_slot=SPISlot.FRONT.value, spi_port=0, **kwargs):
|
||||
"""
|
||||
:param rotation: Rotation angle for the captured optical flow. Possible options: 0, 90, 180, 270 (default: 0)
|
||||
:type rotation: int
|
||||
|
||||
:param spi_slot: SPI slot where the sensor is connected if you're using a Breakout Garden interface.
|
||||
Possible options: 'front', 'back' (default: 'front')
|
||||
:type spi_slot: str
|
||||
|
||||
:param spi_port: SPI port (default: 0)
|
||||
:type spi_slot: int
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
self.spi_port = spi_port
|
||||
self._sensor = None
|
||||
(self.x, self.y) = (0, 0)
|
||||
|
||||
try:
|
||||
if isinstance(rotation, int):
|
||||
rotation = [r for r in Rotation if r.value == rotation][0]
|
||||
self.rotation = rotation
|
||||
except IndexError:
|
||||
raise ValueError('{} is not a valid value for rotation - possible values: {}'.format(
|
||||
rotation, [r.value for r in Rotation]))
|
||||
|
||||
try:
|
||||
if isinstance(spi_slot, str):
|
||||
spi_slot = [s for s in SPISlot if s.value == spi_slot][0]
|
||||
|
||||
self.spi_slot = BG_CS_FRONT_BCM if spi_slot == SPISlot.FRONT else BG_CS_BACK_BCM
|
||||
except IndexError:
|
||||
raise ValueError('{} is not a valid value for spi_slot - possible values: {}'.format(
|
||||
spi_slot, [s.value for s in SPISlot]))
|
||||
|
||||
def _get_sensor(self):
|
||||
if not self._sensor:
|
||||
self._sensor = PMW3901(spi_port=self.spi_port,
|
||||
spi_cs=1,
|
||||
spi_cs_gpio=self.spi_slot)
|
||||
self._sensor.set_rotation(self.rotation)
|
||||
|
||||
return self._sensor
|
||||
|
||||
@action
|
||||
def get_measurement(self):
|
||||
"""
|
||||
:returns: dict. Example::
|
||||
|
||||
output = {
|
||||
"motion_rel_x": 0, # Detected relative motion vector X-coord
|
||||
"motion_rel_y": 1, # Detected relative motion vector Y-coord
|
||||
"motion_abs_x": 3, # Detected absolute motion vector X-coord
|
||||
"motion_abs_y": 3, # Detected absolute motion vector Y-coord
|
||||
"motion_rel_mod": 1, # Detected relative motion vector module
|
||||
"motion_abs_mod": 5 # Detected absolute motion vector module
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
sensor = self._get_sensor()
|
||||
x, y = sensor.get_motion()
|
||||
self.x += x
|
||||
self.y += y
|
||||
|
||||
return {
|
||||
'motion_rel_x': x,
|
||||
'motion_rel_y': y,
|
||||
'motion_abs_x': self.x,
|
||||
'motion_abs_y': self.y,
|
||||
'motion_rel_mod': math.sqrt(x * x + y * y),
|
||||
'motion_abs_mod': math.sqrt(self.x * self.x + self.y * self.y),
|
||||
}
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
|
@ -162,3 +162,6 @@ pyScss
|
|||
# Support for VL53L1X laser ranger/distance sensor
|
||||
# smbus2
|
||||
# vl53l1x
|
||||
|
||||
# Support for PWM3901 2-Dimensional Optical Flow Sensor
|
||||
# pwm3901
|
||||
|
|
Loading…
Reference in a new issue