forked from idg10/4tronix-rover-simulator
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrover_web_driver.py
More file actions
365 lines (294 loc) · 12.7 KB
/
rover_web_driver.py
File metadata and controls
365 lines (294 loc) · 12.7 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#!/usr/bin/python
#
# rover_web_driver.py
#
# Core implementation for controlling a rover via HTTP (either simulator or real hardware)
# This module provides the same API as the real rover.py but sends commands via HTTP.
#
#======================================================================
# General Functions
# (Both versions)
#
# init(brightness). Initialises GPIO pins, switches motors and LEDs Off. If brightness is 0, no LEDs are initialised
# cleanup(). Sets all motors and LEDs off and sets GPIO to standard values
# version(). Returns 4 for M.A.R.S. Rover. Invalid until after init() has been called
#======================================================================
#======================================================================
# Motor Functions
#
# stop(): Stops both motors
# forward(speed): Sets both motors to move forward at speed. 0 <= speed <= 100
# reverse(speed): Sets both motors to reverse at speed. 0 <= speed <= 100
# spinLeft(speed): Sets motors to turn opposite directions at speed. 0 <= speed <= 100
# spinRight(speed): Sets motors to turn opposite directions at speed. 0 <= speed <= 100
# turnForward(leftSpeed, rightSpeed): Moves forwards in an arc by setting different speeds. 0 <= leftSpeed,rightSpeed <= 100
# turnreverse(leftSpeed, rightSpeed): Moves backwards in an arc by setting different speeds. 0 <= leftSpeed,rightSpeed <= 100
#======================================================================
#======================================================================
# FIRELED Functions
#
# setColor(color): Sets all LEDs to color - requires show()
# setPixel(ID, color): Sets pixel ID to color - requires show()
# show(): Updates the LEDs with state of LED array
# clear(): Clears all LEDs to off - requires show()
# rainbow(): Sets the LEDs to rainbow colors - requires show()
# fromRGB(red, green, blue): Creates a color value from R, G and B values
# toRGB(color): Converts a color value to separate R, G and B
# wheel(pos): Generates rainbow colors across 0-255 positions
#======================================================================
#======================================================================
# UltraSonic Functions
#
# getDistance(). Returns the distance in cm to the nearest reflecting object. 0 == no object
#======================================================================
#======================================================================
# Servo Functions
#
# getLight(Sensor). Returns the value 0..1023 for the selected sensor, 0 <= Sensor <= 3
# getLightFL(). Returns the value 0..1023 for Front-Left light sensor
# getLightFR(). Returns the value 0..1023 for Front-Right light sensor
# getLightBL(). Returns the value 0..1023 for Back-Left light sensor
# getLightBR(). Returns the value 0..1023 for Back-Right light sensor
# getBattery(). Returns the voltage of the battery pack (>7.2V is good, less is bad)
#======================================================================
#======================================================================
# Keypad Functions
#
# getSwitch(). Returns the value of the tact switch: True==pressed
#======================================================================
import sys
from time import sleep, time
import requests
class RoverWebDriver:
"""
Web-based rover driver that sends commands via HTTP.
Can be used with either the simulator UI or real rover server.
"""
def __init__(self, base_url="http://127.0.0.1:8523/"):
"""
Initialize the rover web driver.
Args:
base_url: Base URL of the rover server (simulator or real hardware)
"""
self.base_url = base_url
# A session means that after the first connection, we should remain
# connected to the server so it shouldn't be so slow
self.request_session = requests.Session()
# Define RGB LEDs
self.leds = None
self._brightness = 40
self.numPixels = 4
self.lDir = 0
self.rDir = 0
def _send_command(self, message):
"""Helper method to send commands with error handling."""
try:
self.request_session.post(self.base_url, json=message, timeout=2)
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout):
# Silently ignore connection errors
pass
#======================================================================
# General Functions
#
# init(). Initialises GPIO pins, switches motors and LEDs Off, etc
def init(self, brightness, PiBit=False):
if self.leds is None and brightness > 0:
self._brightness = brightness
print("Initialized")
# cleanup(). Sets all motors and LEDs off and sets GPIO to standard values
def cleanup(self):
try:
self.stop()
if self.leds is not None:
self.clear()
self.show()
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout):
# Silently ignore connection errors during cleanup
pass
# End of General Functions
#======================================================================
#======================================================================
# Motor Functions
#
# stop(): Stops both motors - coasts slowly to a stop
def stop(self):
self.lDir = 0
self.rDir = 0
message = {'command': 'stop'}
self._send_command(message)
# brake(): Stops both motors - regenerative braking to stop quickly
def brake(self):
self.lDir = 0
self.rDir = 0
message = {'command': 'stop'}
self._send_command(message)
# forward(speed): Sets both motors to move forward at speed. 0 <= speed <= 100
def forward(self, speed):
self.lDir = 1
self.rDir = 1
message = {'command': 'forward', 'speed': speed}
self._send_command(message)
# reverse(speed): Sets both motors to reverse at speed. 0 <= speed <= 100
def reverse(self, speed):
self.lDir = -1
self.rDir = -1
message = {'command': 'reverse', 'speed': speed}
self._send_command(message)
# spinLeft(speed): Sets motors to turn opposite directions at speed. 0 <= speed <= 100
def spinLeft(self, speed):
self.lDir = -1
self.rDir = 1
message = {'command': 'spinLeft', 'speed': speed}
self._send_command(message)
# spinRight(speed): Sets motors to turn opposite directions at speed. 0 <= speed <= 100
def spinRight(self, speed):
self.lDir = 1
self.rDir = -1
message = {'command': 'spinRight', 'speed': speed}
self._send_command(message)
# turnForward(leftSpeed, rightSpeed): Moves forwards in an arc by setting different speeds. 0 <= leftSpeed,rightSpeed <= 100
def turnForward(self, leftSpeed, rightSpeed):
self.lDir = 1
self.rDir = 1
message = {'command': 'turnForward', 'leftSpeed': leftSpeed, 'rightSpeed': rightSpeed}
self._send_command(message)
# turnReverse(leftSpeed, rightSpeed): Moves backwards in an arc by setting different speeds. 0 <= leftSpeed,rightSpeed <= 100
def turnReverse(self, leftSpeed, rightSpeed):
self.lDir = -1
self.rDir = -1
message = {'command': 'turnReverse', 'leftSpeed': leftSpeed, 'rightSpeed': rightSpeed}
self._send_command(message)
# steerLeft(degrees, seconds): Steers left while moving forward at given angle for duration
def steerLeft(self, degrees, seconds):
self.lDir = 1
self.rDir = 1
message = {'command': 'steerLeft', 'degrees': degrees, 'seconds': seconds}
self._send_command(message)
# steerRight(degrees, seconds): Steers right while moving forward at given angle for duration
def steerRight(self, degrees, seconds):
self.lDir = 1
self.rDir = 1
message = {'command': 'steerRight', 'degrees': degrees, 'seconds': seconds}
self._send_command(message)
# End of Motor Functions
#======================================================================
#======================================================================
# Wheel Sensor Functions
def stopL(self):
pass
def stopR(self):
pass
def lCounter(self, pin):
pass
def rCounter(self, pin):
pass
# stepForward(speed, steps): Moves forward specified number of counts, then stops
def stepForward(self, speed, counts):
pass
# stepReverse(speed, steps): Moves backward specified number of counts, then stops
def stepReverse(self, speed, counts):
pass
# stepSpinL(speed, steps): Spins left specified number of counts, then stops
def stepSpinL(self, speed, counts):
pass
# stepSpinR(speed, steps): Spins right specified number of counts, then stops
def stepSpinR(self, speed, counts):
pass
# End of Wheel Sensor Functions
#======================================================================
#======================================================================
# IR Sensor Functions
#
# irLeft(): Returns state of Left IR Obstacle sensor
def irLeft(self):
return True
# irRight(): Returns state of Right IR Obstacle sensor
def irRight(self):
return True
# irAll(): Returns true if either of the Obstacle sensors are triggered
def irAll(self):
return True
# irLeftLine(): Returns state of Left IR Line sensor
def irLeftLine(self):
return True
# irRightLine(): Returns state of Right IR Line sensor
def irRightLine(self):
return True
# End of IR Sensor Functions
#======================================================================
#======================================================================
# UltraSonic Functions
#
# getDistance(). Returns the distance in cm to the nearest reflecting object. 0 == no object
#
def getDistance(self):
# This would need to be returned from the server response
return 0
# End of UltraSonic Functions
#======================================================================
#======================================================================
# RGB LED Functions
#
def setColor(self, color):
for i in range(self.numPixels):
self.setPixel(i, color)
def setPixel(self, ID, color):
if ID <= self.numPixels:
pass # Would need to track LED state and send in show()
def show(self):
pass # Would send LED state to server
def clear(self):
for i in range(self.numPixels):
self.setPixel(i, 0)
def rainbow(self):
for x in range(self.numPixels):
self.setPixel(x, int(self.wheel(x * 256 / self.numPixels)))
def fromRGB(self, red, green, blue):
return ((int(red) << 16) + (int(green) << 8) + blue)
def toRGB(self, color):
return (((color & 0xff0000) >> 16), ((color & 0x00ff00) >> 8), (color & 0x0000ff))
def wheel(self, pos):
"""Generate rainbow colors across 0-255 positions."""
if pos < 85:
return self.fromRGB(255 - pos * 3, pos * 3, 0) # Red -> Green
elif pos < 170:
pos -= 85
return self.fromRGB(0, 255 - pos * 3, pos * 3) # Green -> Blue
else:
pos -= 170
return self.fromRGB(pos * 3, 0, 255 - pos * 3) # Blue -> Red
# End of RGB LED Functions
#======================================================================
#======================================================================
# Servo Functions
def setServo(self, Servo, Degrees):
message = {'servos': {Servo: Degrees}}
self._send_command(message)
def stopServos(self):
for i in range(16):
pass # Would need server support
# End of Servo Functions
#======================================================================
#======================================================================
# EEROM Functions
# First 16 bytes are used for servo offsets (signed bytes)
# Low level read function. Reads data from actual Address
def rdEEROM(self, Address):
return 0
# Low level write function. Writes Data to actual Address
def wrEEROM(self, Address, Data):
pass
# General Read Function. Ignores first 16 bytes
def readEEROM(self, Address):
return self.rdEEROM(Address + 16)
# General Write Function. Ignores first 16 bytes
def writeEEROM(self, Address, Data):
self.wrEEROM(Address + 16, Data)
# Load all servo Offsets
def loadOffsets(self):
pass
# Save all servo Offsets
def saveOffsets(self):
pass
# End of EEROM Functions
#======================================================================