Fixup factories to support environment variables
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,4 +16,5 @@
|
|||||||
**_pb2*
|
**_pb2*
|
||||||
**.egg-info*
|
**.egg-info*
|
||||||
**/dist/*
|
**/dist/*
|
||||||
build
|
build
|
||||||
|
__pycache__
|
||||||
22
car/src/car/control/gpio/factory.py
Normal file
22
car/src/car/control/gpio/factory.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from .mockvehicle import MockVehicle
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def get_vehicle(motor_pin=19, steering_pin=18):
|
||||||
|
ENV_CAR = None
|
||||||
|
try:
|
||||||
|
ENV_CAR = os.environ['CAR_VEHICLE']
|
||||||
|
except KeyError:
|
||||||
|
print('Failed to find CAR_VEHICLE environment variable. Using mock.')
|
||||||
|
return MockVehicle()
|
||||||
|
if ENV_CAR == "CAR_2D":
|
||||||
|
try:
|
||||||
|
from .vehicle import Vehicle
|
||||||
|
return Vehicle(motor_pin, steering_pin)
|
||||||
|
except ImportError:
|
||||||
|
print(
|
||||||
|
'Could not import CAR_2D vehicle. Have you installed the GPIOZERO package?')
|
||||||
|
elif ENV_CAR == "CAR_MOCK":
|
||||||
|
return MockVehicle(motor_pin, steering_pin)
|
||||||
|
else:
|
||||||
|
print('No valid vehicle found. Have you set the CAR_VEHICLE environment variable?')
|
||||||
@@ -5,6 +5,7 @@ class MockVehicle:
|
|||||||
def __init__(self, motor_pin=19, servo_pin=18):
|
def __init__(self, motor_pin=19, servo_pin=18):
|
||||||
self.motor_pin = motor_pin
|
self.motor_pin = motor_pin
|
||||||
self.steering_pin = servo_pin
|
self.steering_pin = servo_pin
|
||||||
|
print('Using Mock Vehicle')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def throttle(self):
|
def throttle(self):
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ def _safely_set_servo_value(servo, value):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _is_pin_valid(pin):
|
def _is_pin_valid(pin):
|
||||||
if isinstance(pin, int):
|
if isinstance(pin, int):
|
||||||
if pin < 2 or pin > 21:
|
if pin < 2 or pin > 21:
|
||||||
@@ -26,6 +27,8 @@ def _is_pin_valid(pin):
|
|||||||
|
|
||||||
# TODO: Allow a vector to be set to change the throttle/steering, for vehicles that don't use
|
# TODO: Allow a vector to be set to change the throttle/steering, for vehicles that don't use
|
||||||
# two servos for controls (e.g. drone, dog)
|
# two servos for controls (e.g. drone, dog)
|
||||||
|
|
||||||
|
|
||||||
class Vehicle:
|
class Vehicle:
|
||||||
def __init__(self, motor_pin=19, servo_pin=18):
|
def __init__(self, motor_pin=19, servo_pin=18):
|
||||||
subprocess.call(['sudo', 'pigpiod'])
|
subprocess.call(['sudo', 'pigpiod'])
|
||||||
@@ -39,7 +42,8 @@ class Vehicle:
|
|||||||
def initialise_motor(self):
|
def initialise_motor(self):
|
||||||
self._motor_servo = Servo(
|
self._motor_servo = Servo(
|
||||||
self._motor_pin, pin_factory=Device.pin_factory)
|
self._motor_pin, pin_factory=Device.pin_factory)
|
||||||
self._steering_servo = Servo(self._steering_pin, pin_factory=Device.pin_factory)
|
self._steering_servo = Servo(
|
||||||
|
self._steering_pin, pin_factory=Device.pin_factory)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def throttle(self):
|
def throttle(self):
|
||||||
@@ -73,11 +77,13 @@ class Vehicle:
|
|||||||
|
|
||||||
@steering_pin.setter
|
@steering_pin.setter
|
||||||
def steering_pin(self, value):
|
def steering_pin(self, value):
|
||||||
self._steering_pin = value if _is_pin_valid(value) else self._steering_pin
|
self._steering_pin = value if _is_pin_valid(
|
||||||
|
value) else self._steering_pin
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.throttle = 0
|
self.throttle = 0
|
||||||
self.steering = 0
|
self.steering = 0
|
||||||
|
|
||||||
def change_with_vector(self, vector):
|
def change_with_vector(self, vector):
|
||||||
|
# TBD how this will work. Could just be (magnitude,angle) change
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import time
|
|||||||
import grpc
|
import grpc
|
||||||
|
|
||||||
import car.control.motorService_pb2_grpc as motorService_pb2_grpc
|
import car.control.motorService_pb2_grpc as motorService_pb2_grpc
|
||||||
from car.control.gpio.vehicle import Vehicle
|
import car.control.gpio.factory as vehicle_factory
|
||||||
from car.control.motor_servicer import MotorServicer
|
from car.control.motor_servicer import MotorServicer
|
||||||
from car.slam.slam_servicer import SlamServicer
|
from car.slam.slam_servicer import SlamServicer
|
||||||
import car.slam.SlamController_pb2_grpc as SlamController_pb2_grpc
|
import car.slam.SlamController_pb2_grpc as SlamController_pb2_grpc
|
||||||
@@ -22,12 +22,14 @@ class CarServer():
|
|||||||
|
|
||||||
def start_server(self):
|
def start_server(self):
|
||||||
server = grpc.server(futures.ThreadPoolExecutor(max_workers=8))
|
server = grpc.server(futures.ThreadPoolExecutor(max_workers=8))
|
||||||
motorService_pb2_grpc.add_CarControlServicer_to_server(self.create_motor_servicer(), server)
|
motorService_pb2_grpc.add_CarControlServicer_to_server(
|
||||||
|
self.create_motor_servicer(), server)
|
||||||
SlamController_pb2_grpc.add_SlamControlServicer_to_server(
|
SlamController_pb2_grpc.add_SlamControlServicer_to_server(
|
||||||
self.create_slam_servicer(), server)
|
self.create_slam_servicer(), server)
|
||||||
lidar_tracker_pb2_grpc.add_PersonTrackingServicer_to_server(
|
lidar_tracker_pb2_grpc.add_PersonTrackingServicer_to_server(
|
||||||
self.create_lidar_servicer(), server)
|
self.create_lidar_servicer(), server)
|
||||||
# Disable tls for local testing.
|
|
||||||
|
# Disable tls for local testing for now.
|
||||||
# server.add_secure_port('[::]:50051', self.create_credentials())
|
# server.add_secure_port('[::]:50051', self.create_credentials())
|
||||||
server.add_insecure_port('[::]:50051')
|
server.add_insecure_port('[::]:50051')
|
||||||
server.start()
|
server.start()
|
||||||
@@ -44,7 +46,7 @@ class CarServer():
|
|||||||
return LidarServicer()
|
return LidarServicer()
|
||||||
|
|
||||||
def create_credentials(self):
|
def create_credentials(self):
|
||||||
# Relativise this stuff.
|
# Relativise this stuff. Should add to source directory.
|
||||||
pvtKeyPath = '/home/pi/tls/device.key'
|
pvtKeyPath = '/home/pi/tls/device.key'
|
||||||
pvtCertPath = '/home/pi/tls/device.crt'
|
pvtCertPath = '/home/pi/tls/device.crt'
|
||||||
|
|
||||||
@@ -55,8 +57,7 @@ class CarServer():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
vehicle = Vehicle()
|
server = CarServer(vehicle_factory.get_vehicle())
|
||||||
server = CarServer(vehicle)
|
|
||||||
|
|
||||||
# Can't remember why I do this, is it even needed?
|
# Can't remember why I do this, is it even needed?
|
||||||
service_thread = Thread(target=server.start_server)
|
service_thread = Thread(target=server.start_server)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import car.slam.SlamController_pb2_grpc as grpc
|
import car.slam.SlamController_pb2_grpc as grpc
|
||||||
import car.slam.SlamController_pb2 as proto
|
import car.slam.SlamController_pb2 as proto
|
||||||
|
import car.empty_pb2 as empty
|
||||||
import car.slam.slam_streamer as slam
|
import car.slam.slam_streamer as slam
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
|
|
||||||
@@ -21,11 +22,11 @@ class SlamServicer(grpc.SlamControlServicer):
|
|||||||
self.slam.map_meters = request.map_size_meters
|
self.slam.map_meters = request.map_size_meters
|
||||||
self.slam_thread = Process(target=self.slam.start)
|
self.slam_thread = Process(target=self.slam.start)
|
||||||
self.slam_thread.start()
|
self.slam_thread.start()
|
||||||
return proto.Empty()
|
return empty.Empty()
|
||||||
|
|
||||||
def stop_streaming(self, request, context):
|
def stop_streaming(self, request, context):
|
||||||
if self.slam_thread is not None:
|
if self.slam_thread is not None:
|
||||||
self.slam.stop_scanning()
|
self.slam.stop_scanning()
|
||||||
self.slam_thread.join()
|
self.slam_thread.join()
|
||||||
self.slam = None
|
self.slam = None
|
||||||
return proto.Empty()
|
return empty.Empty()
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
from car.tracking.devices.mock_lidar import MockLidar
|
from .mock_lidar import MockLidar
|
||||||
import car.tracking.lidar_loader as loader
|
from .. import lidar_loader as loader
|
||||||
|
import os
|
||||||
|
|
||||||
# connection = "TEST"
|
MOCK_DEVICE = "LIDAR_MOCK"
|
||||||
connection = '/dev/ttyUSB0'
|
RPLIDAR = "LIDAR_RPLIDAR"
|
||||||
|
|
||||||
def get_lidar():
|
|
||||||
# Need a way to configure this, maybe with environment variables
|
def get_lidar(device=None, connection='/dev/ttyUSB0'):
|
||||||
if connection == 'TEST':
|
actual_device = None
|
||||||
return MockLidar(loader.load_scans_bytes_file("tracking/out.pickle"))
|
try:
|
||||||
else:
|
actual_device = device if device is not None else os.environ["CAR_LIDAR"]
|
||||||
|
except KeyError:
|
||||||
|
print(
|
||||||
|
'No lidar device specified and the CAR_LIDAR environment variable is not set.')
|
||||||
|
if actual_device == MOCK_DEVICE:
|
||||||
|
return MockLidar(loader.load_scans_bytes_file("car/tracking/out.pickle"))
|
||||||
|
elif actual_device == RPLIDAR:
|
||||||
try:
|
try:
|
||||||
from rplidar import RPLidar
|
from rplidar import RPLidar
|
||||||
return RPLidar(connection)
|
return RPLidar(connection)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print('Could not import RPLidar, using mock with testing data.')
|
print('Could not import RPLidar. Have you downloaded rplidar?')
|
||||||
return MockLidar(loader.load_scans_bytes_file("tracking/out.pickle"))
|
else:
|
||||||
|
print('No valid lidar device found. Please choose one of ' +
|
||||||
|
MOCK_DEVICE + ' or ' + RPLIDAR)
|
||||||
|
return None
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ As such, it is useful for testing, to create real lidar
|
|||||||
data that can be reused later, without needing to connect the lidar.
|
data that can be reused later, without needing to connect the lidar.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rplidar import RPLidar
|
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
def get_scans(num_scans, device='/dev/ttyUSB0', measurements_per_scan=100):
|
def get_scans(num_scans, device='/dev/ttyUSB0', measurements_per_scan=100):
|
||||||
|
from rplidar import RPLidar
|
||||||
lidar = RPLidar(device)
|
lidar = RPLidar(device)
|
||||||
scans = lidar.iter_scans(measurements_per_scan)
|
scans = lidar.iter_scans(measurements_per_scan)
|
||||||
return [next(scans) for i in range(0, num_scans)]
|
return [next(scans) for i in range(0, num_scans)]
|
||||||
|
|||||||
Reference in New Issue
Block a user