2018-02-25 23:45:31 +01:00
|
|
|
import enum
|
|
|
|
import logging
|
|
|
|
import threading
|
|
|
|
import time
|
|
|
|
|
|
|
|
from platypush.message.response import Response
|
|
|
|
from platypush.plugins import Plugin
|
2018-02-26 11:31:06 +01:00
|
|
|
from platypush.context import get_plugin
|
|
|
|
from platypush.config import Config
|
2018-02-25 23:45:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
class Direction(enum.Enum):
|
|
|
|
DIR_UP = 'up'
|
|
|
|
DIR_DOWN = 'down'
|
|
|
|
DIR_LEFT = 'left'
|
|
|
|
DIR_RIGHT = 'right'
|
2018-02-26 11:31:06 +01:00
|
|
|
DIR_AUTO = 'auto'
|
2018-02-25 23:45:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
class GpioZeroborgPlugin(Plugin):
|
|
|
|
_drive_thread = None
|
|
|
|
_can_run = False
|
|
|
|
_direction = None
|
2018-02-26 01:01:07 +01:00
|
|
|
_power_offsets = {
|
|
|
|
Direction.DIR_LEFT: {
|
2018-03-04 17:55:48 +01:00
|
|
|
Direction.DIR_UP: 0.315,
|
2018-02-26 01:01:07 +01:00
|
|
|
Direction.DIR_DOWN: 0.285,
|
|
|
|
},
|
2018-02-25 23:45:31 +01:00
|
|
|
|
2018-02-26 01:01:07 +01:00
|
|
|
Direction.DIR_RIGHT: {
|
|
|
|
Direction.DIR_UP: 0,
|
|
|
|
Direction.DIR_DOWN: 0.242,
|
|
|
|
},
|
|
|
|
}
|
2018-02-25 23:45:31 +01:00
|
|
|
|
2018-02-26 01:01:07 +01:00
|
|
|
|
|
|
|
def __init__(self, v_in=8.4, v_out=6.0):
|
2018-02-25 23:45:31 +01:00
|
|
|
import platypush.plugins.gpio.zeroborg.lib as ZeroBorg
|
|
|
|
|
|
|
|
self.v_in = v_in
|
|
|
|
self.v_out = v_out
|
|
|
|
self.max_power = v_out / float(v_in)
|
2018-02-26 11:31:06 +01:00
|
|
|
self.auto_mode = False
|
2018-03-03 03:24:08 +01:00
|
|
|
self._direction = None
|
2018-02-25 23:45:31 +01:00
|
|
|
|
|
|
|
self.zb = ZeroBorg.ZeroBorg()
|
|
|
|
self.zb.Init()
|
|
|
|
self.zb.SetCommsFailsafe(True)
|
|
|
|
self.zb.ResetEpo()
|
|
|
|
|
|
|
|
|
2018-02-26 11:31:06 +01:00
|
|
|
def get_distance(self):
|
2018-03-02 16:02:04 +01:00
|
|
|
distance_sensor = get_plugin('gpio.sensor.distance')
|
|
|
|
if not distance_sensor:
|
2018-02-26 11:31:06 +01:00
|
|
|
raise RuntimeError('No gpio.sensor.distance configuration found')
|
|
|
|
|
2018-03-02 16:02:04 +01:00
|
|
|
return distance_sensor.get_distance()
|
2018-02-26 11:31:06 +01:00
|
|
|
|
|
|
|
|
2018-02-25 23:45:31 +01:00
|
|
|
def drive(self, direction):
|
2018-03-03 03:24:08 +01:00
|
|
|
prev_direction = self._direction
|
|
|
|
|
2018-02-25 23:45:31 +01:00
|
|
|
self._can_run = True
|
|
|
|
self._direction = direction.lower()
|
|
|
|
logging.info('Received ZeroBorg drive command: {}'.format(direction))
|
|
|
|
|
|
|
|
def _run():
|
|
|
|
while self._can_run and self._direction:
|
|
|
|
left = 0.0
|
|
|
|
right = 0.0
|
|
|
|
|
2018-02-26 11:31:06 +01:00
|
|
|
if self._direction == Direction.DIR_AUTO.value:
|
|
|
|
self.auto_mode = True
|
|
|
|
|
|
|
|
if self.auto_mode:
|
|
|
|
distance = None
|
|
|
|
while distance is None:
|
|
|
|
distance = self.get_distance()
|
2018-03-04 17:55:48 +01:00
|
|
|
print(distance)
|
2018-02-26 11:31:06 +01:00
|
|
|
|
2018-03-04 17:55:48 +01:00
|
|
|
if distance > 300.0: # distance in mm
|
2018-02-26 11:31:06 +01:00
|
|
|
self._direction = Direction.DIR_UP.value
|
|
|
|
else:
|
2018-03-03 03:24:08 +01:00
|
|
|
logging.info('Physical obstacle detected at {} mm'.
|
|
|
|
format(distance))
|
2018-02-26 11:31:06 +01:00
|
|
|
self._direction = Direction.DIR_LEFT.value
|
|
|
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
2018-02-25 23:45:31 +01:00
|
|
|
if self._direction == Direction.DIR_UP.value:
|
2018-02-26 01:01:07 +01:00
|
|
|
left = 1.0 + self._power_offsets[Direction.DIR_LEFT][Direction.DIR_UP]
|
|
|
|
right = 1.0 + self._power_offsets[Direction.DIR_RIGHT][Direction.DIR_UP]
|
2018-02-25 23:45:31 +01:00
|
|
|
elif self._direction == Direction.DIR_DOWN.value:
|
2018-02-26 01:01:07 +01:00
|
|
|
left = -1.0 - self._power_offsets[Direction.DIR_LEFT][Direction.DIR_DOWN]
|
|
|
|
right = -1.0 - self._power_offsets[Direction.DIR_RIGHT][Direction.DIR_DOWN]
|
2018-02-25 23:45:31 +01:00
|
|
|
elif self._direction == Direction.DIR_LEFT.value:
|
2018-02-26 01:01:07 +01:00
|
|
|
left = -1.25 - self._power_offsets[Direction.DIR_LEFT][Direction.DIR_DOWN]
|
2018-02-26 11:31:06 +01:00
|
|
|
right = 2.0 + self._power_offsets[Direction.DIR_RIGHT][Direction.DIR_UP]
|
2018-03-04 17:55:48 +01:00
|
|
|
elif self._direction == Direction.DIR_RIGHT.value:
|
|
|
|
left = 2.0 + self._power_offsets[Direction.DIR_LEFT][Direction.DIR_UP]
|
|
|
|
right = -1.25 - self._power_offsets[Direction.DIR_RIGHT][Direction.DIR_DOWN]
|
2018-02-25 23:45:31 +01:00
|
|
|
elif self._direction is not None:
|
|
|
|
logging.warning('Invalid direction: {}'.format(direction))
|
2018-02-26 11:31:06 +01:00
|
|
|
self.stop()
|
2018-02-25 23:45:31 +01:00
|
|
|
|
2018-03-04 17:55:48 +01:00
|
|
|
power = 0.75 # Still debugging the right power range
|
2018-03-03 03:24:08 +01:00
|
|
|
|
|
|
|
self.zb.SetMotor1(power * left * self.max_power)
|
|
|
|
self.zb.SetMotor2(power * left * self.max_power)
|
|
|
|
self.zb.SetMotor3(power * -right * self.max_power)
|
|
|
|
self.zb.SetMotor4(power * -right * self.max_power)
|
2018-02-25 23:45:31 +01:00
|
|
|
|
2018-02-26 11:31:06 +01:00
|
|
|
self.auto_mode = False
|
|
|
|
|
2018-02-25 23:45:31 +01:00
|
|
|
|
|
|
|
self._drive_thread = threading.Thread(target=_run)
|
|
|
|
self._drive_thread.start()
|
|
|
|
|
|
|
|
return Response(output={'status': 'running', 'direction': direction})
|
|
|
|
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
self._can_run = False
|
|
|
|
if self._drive_thread and threading.get_ident() != self._drive_thread.ident:
|
|
|
|
self._drive_thread.join()
|
|
|
|
|
|
|
|
self.zb.MotorsOff()
|
|
|
|
self.zb.ResetEpo()
|
2018-02-26 11:31:06 +01:00
|
|
|
|
2018-02-25 23:45:31 +01:00
|
|
|
return Response(output={'status':'stopped'})
|
|
|
|
|
|
|
|
|
|
|
|
# vim:sw=4:ts=4:et:
|
|
|
|
|