Refactored integration between ZeroBorg and distance sensor plugin
This commit is contained in:
parent
58b0b48393
commit
bdfe48fe32
3 changed files with 98 additions and 57 deletions
|
@ -36,5 +36,9 @@ class GpioSensorPlugin(Plugin):
|
||||||
|
|
||||||
return self.get_measurement(*args, **kwargs).output
|
return self.get_measurement(*args, **kwargs).output
|
||||||
|
|
||||||
|
@action
|
||||||
|
def close(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
|
@ -15,67 +15,76 @@ class GpioSensorDistancePlugin(GpioPlugin, GpioSensorPlugin):
|
||||||
* ``RPi.GPIO`` (``pip install RPi.GPIO``)
|
* ``RPi.GPIO`` (``pip install RPi.GPIO``)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, trigger_pin, echo_pin, *args, **kwargs):
|
def __init__(self, trigger_pin: int, echo_pin: int,
|
||||||
|
timeout: float = 1.0, warmup_time: float = 2.0, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param trigger_pin: GPIO PIN where you connected your sensor trigger PIN (the one that triggers the sensor to perform a measurement).
|
:param trigger_pin: GPIO PIN where you connected your sensor trigger PIN (the one that triggers the
|
||||||
:type trigger_pin: int
|
sensor to perform a measurement).
|
||||||
|
|
||||||
:param echo_pin: GPIO PIN where you connected your sensor echo PIN (the one that will listen for the signal to bounce back and therefore trigger the distance calculation).
|
:param echo_pin: GPIO PIN where you connected your sensor echo PIN (the one that will listen for the
|
||||||
:type echo_pin: int
|
signal to bounce back and therefore trigger the distance calculation).
|
||||||
|
|
||||||
|
:param timeout: The echo-wait will terminate and the plugin will return null if no echo has been
|
||||||
|
received after this time (default: 1 second).
|
||||||
|
|
||||||
|
:param warmup_time: Number of seconds that should be waited on plugin instantiation
|
||||||
|
for the sensor to be ready (default: 2 seconds).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
GpioPlugin.__init__(self, *args, **kwargs)
|
GpioPlugin.__init__(self, *args, **kwargs)
|
||||||
self.trigger_pin = trigger_pin
|
self.trigger_pin = trigger_pin
|
||||||
self.echo_pin = echo_pin
|
self.echo_pin = echo_pin
|
||||||
self._is_probing = False
|
self.timeout = timeout
|
||||||
|
self.warmup_time = warmup_time
|
||||||
|
self._initialized = False
|
||||||
|
self._init_gpio()
|
||||||
|
|
||||||
def _init_gpio(self):
|
def _init_gpio(self):
|
||||||
|
if self._initialized:
|
||||||
|
return
|
||||||
|
|
||||||
import RPi.GPIO as gpio
|
import RPi.GPIO as gpio
|
||||||
gpio.setmode(self.mode)
|
gpio.setmode(self.mode)
|
||||||
gpio.setup(self.trigger_pin, gpio.OUT)
|
gpio.setup(self.trigger_pin, gpio.OUT)
|
||||||
gpio.setup(self.echo_pin, gpio.IN)
|
gpio.setup(self.echo_pin, gpio.IN)
|
||||||
gpio.output(self.trigger_pin, False)
|
gpio.output(self.trigger_pin, gpio.LOW)
|
||||||
|
|
||||||
|
self.logger.info('Waiting {} seconds for the sensor to be ready'.format(self.warmup_time))
|
||||||
|
time.sleep(self.warmup_time)
|
||||||
|
self.logger.info('Sensor ready')
|
||||||
|
self._initialized = True
|
||||||
|
|
||||||
def _get_data(self):
|
def _get_data(self):
|
||||||
import RPi.GPIO as gpio
|
import RPi.GPIO as gpio
|
||||||
|
|
||||||
|
pulse_start = pulse_end = pulse_on = pulse_off = time.time()
|
||||||
|
|
||||||
self._init_gpio()
|
self._init_gpio()
|
||||||
|
gpio.output(self.trigger_pin, gpio.HIGH)
|
||||||
gpio.output(self.trigger_pin, True)
|
|
||||||
time.sleep(0.00001) # 1 us pulse to trigger echo measurement
|
time.sleep(0.00001) # 1 us pulse to trigger echo measurement
|
||||||
gpio.output(self.trigger_pin, False)
|
gpio.output(self.trigger_pin, gpio.LOW)
|
||||||
read_timeout = False
|
|
||||||
|
|
||||||
pulse_start = time.time()
|
|
||||||
pulse_on = pulse_start
|
|
||||||
|
|
||||||
while gpio.input(self.echo_pin) == 0:
|
while gpio.input(self.echo_pin) == 0:
|
||||||
pulse_on = time.time()
|
pulse_on = time.time()
|
||||||
if pulse_on - pulse_start > 0.5:
|
if pulse_on - pulse_start > self.timeout:
|
||||||
self.logger.warning('Distance sensor echo timeout: 0')
|
raise TimeoutError('Distance sensor echo timeout after {} seconds: 0'.
|
||||||
read_timeout = True
|
format(self.timeout))
|
||||||
break
|
|
||||||
|
|
||||||
pulse_start = pulse_on
|
pulse_start = pulse_on
|
||||||
pulse_end = time.time()
|
pulse_end = pulse_off = time.time()
|
||||||
pulse_off = pulse_end
|
|
||||||
|
|
||||||
while gpio.input(self.echo_pin) == 1:
|
while gpio.input(self.echo_pin) == 1:
|
||||||
pulse_off = time.time()
|
pulse_off = time.time()
|
||||||
if pulse_off - pulse_end > 0.5:
|
if pulse_off - pulse_end > self.timeout:
|
||||||
self.logger.warning('Distance sensor echo timeout: 1')
|
raise TimeoutError('Distance sensor echo timeout after {} seconds: 1'.
|
||||||
read_timeout = True
|
format(self.timeout))
|
||||||
break
|
|
||||||
|
|
||||||
if read_timeout:
|
|
||||||
return None
|
|
||||||
|
|
||||||
pulse_end = pulse_off
|
pulse_end = pulse_off
|
||||||
pulse_duration = pulse_end - pulse_start
|
pulse_duration = pulse_end - pulse_start
|
||||||
|
|
||||||
# s = vt where v = avg speed of sound
|
# s = vt where v = 1/2 * avg speed of sound in mm/s
|
||||||
return round(pulse_duration * 171500.0, 2)
|
return round(pulse_duration * 171500.0, 2)
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_measurement(self):
|
def get_measurement(self):
|
||||||
"""
|
"""
|
||||||
|
@ -83,12 +92,28 @@ class GpioSensorDistancePlugin(GpioPlugin, GpioSensorPlugin):
|
||||||
|
|
||||||
:returns: Distance measurement as a scalar (in mm):
|
:returns: Distance measurement as a scalar (in mm):
|
||||||
"""
|
"""
|
||||||
import RPi.GPIO as gpio
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self._get_data()
|
return self._get_data()
|
||||||
finally:
|
except TimeoutError as e:
|
||||||
|
self.logger.warning(str(e))
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.close()
|
||||||
|
raise e
|
||||||
|
|
||||||
|
@action
|
||||||
|
def close(self):
|
||||||
|
import RPi.GPIO as gpio
|
||||||
|
if self._initialized:
|
||||||
gpio.cleanup()
|
gpio.cleanup()
|
||||||
|
self._initialized = False
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self._init_gpio()
|
||||||
|
|
||||||
|
def __exit__(self):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
|
@ -129,6 +129,10 @@ class GpioZeroborgPlugin(Plugin):
|
||||||
value = self._get_measurement(plugin=plugin, timeout=sensor['timeout'])
|
value = self._get_measurement(plugin=plugin, timeout=sensor['timeout'])
|
||||||
threshold = sensor['threshold']
|
threshold = sensor['threshold']
|
||||||
|
|
||||||
|
if value is None:
|
||||||
|
self.logger.warning('Read timeout from sensor {}'.format(sensor['plugin']))
|
||||||
|
return Direction.DIR_AUTO.value
|
||||||
|
|
||||||
if value >= threshold and 'above_threshold_direction' in sensor:
|
if value >= threshold and 'above_threshold_direction' in sensor:
|
||||||
direction = sensor['above_threshold_direction']
|
direction = sensor['above_threshold_direction']
|
||||||
elif 'below_threshold_direction' in sensor:
|
elif 'below_threshold_direction' in sensor:
|
||||||
|
@ -156,6 +160,7 @@ class GpioZeroborgPlugin(Plugin):
|
||||||
self.logger.info('Received ZeroBorg drive command: {}'.format(direction))
|
self.logger.info('Received ZeroBorg drive command: {}'.format(direction))
|
||||||
|
|
||||||
def _run():
|
def _run():
|
||||||
|
try:
|
||||||
while self._can_run and self._direction:
|
while self._can_run and self._direction:
|
||||||
if self._direction == Direction.DIR_AUTO_TOGGLE.value:
|
if self._direction == Direction.DIR_AUTO_TOGGLE.value:
|
||||||
if self.auto_mode:
|
if self.auto_mode:
|
||||||
|
@ -168,25 +173,30 @@ class GpioZeroborgPlugin(Plugin):
|
||||||
if self._direction == Direction.DIR_AUTO.value:
|
if self._direction == Direction.DIR_AUTO.value:
|
||||||
self.auto_mode = True
|
self.auto_mode = True
|
||||||
|
|
||||||
|
motor_1_power = motor_2_power = motor_3_power = motor_4_power = 0.0
|
||||||
|
|
||||||
|
try:
|
||||||
if self.auto_mode:
|
if self.auto_mode:
|
||||||
self._direction = self._get_direction_from_sensors()
|
self._direction = self._get_direction_from_sensors()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
motor_1_power = motor_2_power = motor_3_power = motor_4_power = 0.0
|
if self._direction in self.directions and self._direction != Direction.DIR_AUTO.value:
|
||||||
if self._direction in self.directions:
|
|
||||||
motor_1_power = self.directions[self._direction]['motor_1_power']
|
motor_1_power = self.directions[self._direction]['motor_1_power']
|
||||||
motor_2_power = self.directions[self._direction]['motor_2_power']
|
motor_2_power = self.directions[self._direction]['motor_2_power']
|
||||||
motor_3_power = self.directions[self._direction]['motor_3_power']
|
motor_3_power = self.directions[self._direction]['motor_3_power']
|
||||||
motor_4_power = self.directions[self._direction]['motor_4_power']
|
motor_4_power = self.directions[self._direction]['motor_4_power']
|
||||||
elif self._direction:
|
else:
|
||||||
self.logger.warning('Invalid direction {}, stopping motors'.format(self._direction))
|
self.logger.warning('Invalid direction {}: stopping motors'.format(self._direction))
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error('Error on _get_direction_from_sensors: {}'.format(str(e)))
|
||||||
|
break
|
||||||
|
|
||||||
self.zb.SetMotor1(motor_1_power)
|
self.zb.SetMotor1(motor_1_power)
|
||||||
self.zb.SetMotor2(motor_2_power)
|
self.zb.SetMotor2(motor_2_power)
|
||||||
self.zb.SetMotor3(motor_3_power)
|
self.zb.SetMotor3(motor_3_power)
|
||||||
self.zb.SetMotor4(motor_4_power)
|
self.zb.SetMotor4(motor_4_power)
|
||||||
|
finally:
|
||||||
self.auto_mode = False
|
self.stop()
|
||||||
|
|
||||||
self._drive_thread = threading.Thread(target=_run)
|
self._drive_thread = threading.Thread(target=_run)
|
||||||
self._drive_thread.start()
|
self._drive_thread.start()
|
||||||
|
@ -200,6 +210,8 @@ class GpioZeroborgPlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._can_run = False
|
self._can_run = False
|
||||||
|
self.auto_mode = False
|
||||||
|
|
||||||
if self._drive_thread and threading.get_ident() != self._drive_thread.ident:
|
if self._drive_thread and threading.get_ident() != self._drive_thread.ident:
|
||||||
self._drive_thread.join()
|
self._drive_thread.join()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue