-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdriver.py
115 lines (99 loc) · 3.81 KB
/
driver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""Drives the Tamiya Grasshopper."""
from messaging.async_logger import AsyncLogger
THROTTLE_GPIO_PIN = 18
THROTTLE_NEUTRAL_US = 1500
THROTTLE_DIFF = 500
THROTTLE_FORWARD_US = THROTTLE_NEUTRAL_US + THROTTLE_DIFF
THROTTLE_REVERSE_US = THROTTLE_NEUTRAL_US - THROTTLE_DIFF
STEERING_GPIO_PIN = 4
STEERING_NEUTRAL_US = 1650
STEERING_DIFF = 300
STEERING_LEFT_US = STEERING_NEUTRAL_US - STEERING_DIFF
STEERING_RIGHT_US = STEERING_NEUTRAL_US + STEERING_DIFF
class Driver(object):
"""Class that implements the Driver interface."""
def __init__(self, telemetry):
self._telemetry = telemetry
self._logger = AsyncLogger()
self._throttle = 0.0
self._steering = 0.0
self._max_throttle = 1.0
with open('/dev/pi-blaster', 'w') as blaster:
blaster.write(
'{pin}={throttle}\n'.format(
pin=THROTTLE_GPIO_PIN,
throttle=self._get_throttle(0.0)
)
)
blaster.write(
'{pin}={steering}\n'.format(
pin=STEERING_GPIO_PIN,
steering=self._get_steering(0.0)
)
)
def drive(self, throttle_percentage, steering_percentage):
"""Sends a command to the RC car. Throttle should be a float between
-1.0 for reverse and 1.0 for forward. Turn should be a float between
-1.0 for left and 1.0 for right.
"""
assert -1.0 <= throttle_percentage <= 1.0
assert -1.0 <= steering_percentage <= 1.0
self._telemetry.process_drive_command(
throttle_percentage,
steering_percentage
)
self._logger.debug(
'throttle = {throttle}, turn = {turn}'.format(
throttle=throttle_percentage,
turn=steering_percentage,
)
)
self._throttle = throttle_percentage
self._steering = steering_percentage
self._logger.debug(
'Throttle: {}, steering: {}'.format(
throttle_percentage,
steering_percentage
)
)
if throttle_percentage > 0.0:
throttle = min(self._max_throttle, throttle_percentage)
else:
# Reverse is slower than forward, so allow 2x
throttle = max(-2 * self._max_throttle, throttle_percentage, -1.0)
with open('/dev/pi-blaster', 'w') as blaster:
blaster.write(
'{pin}={throttle}\n'.format(
pin=THROTTLE_GPIO_PIN,
throttle=self._get_throttle(throttle)
)
)
blaster.write(
'{pin}={steering}\n'.format(
pin=STEERING_GPIO_PIN,
steering=self._get_steering(steering_percentage)
)
)
def get_throttle(self):
"""Returns the current throttle."""
return self._throttle
def get_turn(self):
"""Returns the current turn."""
return self._steering
@staticmethod
def _get_throttle(percentage):
"""Returns the throttle value."""
# Purposely limit the reverse in case we try to go back while still
# rolling - prevent damage to the gear box
if not (-0.5 <= percentage <= 1.0):
raise ValueError('Bad throttle: {}'.format(percentage))
return round((THROTTLE_NEUTRAL_US + THROTTLE_DIFF * percentage) * 0.0001, 3)
@staticmethod
def _get_steering(percentage):
"""Returns the steering value."""
if not (-1.0 <= percentage <= 1.0):
raise ValueError('Bad steering')
return round((STEERING_NEUTRAL_US + STEERING_DIFF * percentage) * 0.0001, 3)
def set_max_throttle(self, max_throttle):
"""Sets the maximum throttle."""
self._max_throttle = min(1.0, max_throttle)