@tigerpython/robotics-libraries 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG +68 -0
- package/LICENSE +373 -0
- package/README.md +81 -0
- package/calliope/README.md +15 -0
- package/calliope/callibot.py +176 -0
- package/calliope/callibotmot.py +46 -0
- package/calliope/callimk.py +143 -0
- package/calliope/cbalarm.py +14 -0
- package/calliope/cpglow.py +76 -0
- package/calliope/cpmike.py +16 -0
- package/calliope/cprover.py +33 -0
- package/calliope/cputils.py +23 -0
- package/calliope/libraries.json +10 -0
- package/calliope/libraries.raw.json +10 -0
- package/calliope/min/callibot.py +97 -0
- package/calliope/min/callibotmot.py +23 -0
- package/calliope/min/callimk.py +47 -0
- package/calliope/min/cbalarm.py +6 -0
- package/calliope/min/cpglow.py +29 -0
- package/calliope/min/cpmike.py +8 -0
- package/calliope/min/cprover.py +9 -0
- package/calliope/min/cputils.py +7 -0
- package/dist/index.d.mts +124 -0
- package/dist/index.d.ts +124 -0
- package/dist/index.js +2896 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2862 -0
- package/dist/index.mjs.map +1 -0
- package/microbit/README.md +48 -0
- package/microbit/controller.py +212 -0
- package/microbit/huskylens.py +479 -0
- package/microbit/libraries.json +19 -0
- package/microbit/libraries.raw.json +19 -0
- package/microbit/mbalarm.py +15 -0
- package/microbit/mbbitbot.py +127 -0
- package/microbit/mbglow.py +77 -0
- package/microbit/mbled.py +56 -0
- package/microbit/mbmarsrover.py +216 -0
- package/microbit/mbminibit.py +139 -0
- package/microbit/mbrobot.py +401 -0
- package/microbit/mbrobot_legacy.py +90 -0
- package/microbit/mbrobot_plus.py +179 -0
- package/microbit/mbrobot_plusV2.py +490 -0
- package/microbit/mbrobot_plusV3.py +427 -0
- package/microbit/mbrobotmot.py +49 -0
- package/microbit/mbthetabot.py +167 -0
- package/microbit/mbwait.py +50 -0
- package/microbit/mbxgo.py +173 -0
- package/microbit/min/controller.py +42 -0
- package/microbit/min/huskylens.py +145 -0
- package/microbit/min/mbalarm.py +6 -0
- package/microbit/min/mbbitbot.py +40 -0
- package/microbit/min/mbglow.py +29 -0
- package/microbit/min/mbled.py +18 -0
- package/microbit/min/mbmarsrover.py +62 -0
- package/microbit/min/mbminibit.py +50 -0
- package/microbit/min/mbrobot.py +82 -0
- package/microbit/min/mbrobot_legacy.py +45 -0
- package/microbit/min/mbrobot_plus.py +75 -0
- package/microbit/min/mbrobot_plusV2.py +102 -0
- package/microbit/min/mbrobot_plusV3.py +194 -0
- package/microbit/min/mbrobotmot.py +25 -0
- package/microbit/min/mbthetabot.py +47 -0
- package/microbit/min/mbwait.py +23 -0
- package/microbit/min/mbxgo.py +37 -0
- package/package.json +54 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
# mbrobot_plusV2.py
|
|
2
|
+
# Date 10/09/24
|
|
3
|
+
|
|
4
|
+
from microbit import i2c, pin0, pin1, pin2, pin13, pin14, pin15, sleep
|
|
5
|
+
import gc
|
|
6
|
+
import machine
|
|
7
|
+
import music
|
|
8
|
+
import neopixel
|
|
9
|
+
|
|
10
|
+
# Motor state
|
|
11
|
+
_speedPercent = 50
|
|
12
|
+
_powerByteL = 50
|
|
13
|
+
_powerByteR = 50
|
|
14
|
+
_motorState = bytearray(5)
|
|
15
|
+
_powerBytesLUT = bytes(b'\x00\x0f\x10\x10\x11\x12\x12\x13\x13\x14\x15\x15\x16\x16\x17\x18\x18\x19\x19\x1a\x1b\x1b\x1c\x1c\x1d\x1e\x1e\x1f\x1f\x20\x21\x21\x22\x22\x23\x24\x24\x25\x25\x26\x27\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3b\x3c\x3e\x3f\x41\x43\x45\x47\x49\x4b\x4d\x50\x52\x55\x58\x5b\x5e\x61\x65\x69\x6d\x71\x75\x7a\x7f\x84\x89\x8f\x95\x9b\xa2\xa9\xb1\xb9\xc1\xca\xd3\xdd\xe8\xf3\xff')
|
|
16
|
+
|
|
17
|
+
# Calibration data
|
|
18
|
+
_powerOffset = 0
|
|
19
|
+
_powerDifferential = 0
|
|
20
|
+
_arcScaling = 0
|
|
21
|
+
_servoMinPulse = 25
|
|
22
|
+
_servoMaxPulse = 131
|
|
23
|
+
|
|
24
|
+
# Signaling objects and buffers
|
|
25
|
+
_ledState = bytearray(b'\x0B\0\0')
|
|
26
|
+
_underglowNP = neopixel.NeoPixel(pin15, 4)
|
|
27
|
+
np_rgb_pixels = _underglowNP
|
|
28
|
+
_alarmSequence = ['c5:1', 'r', 'c5,1', 'r:3']
|
|
29
|
+
|
|
30
|
+
_UNCONNECTEDERRORMSG = "Please connect to Maqueen robot and switch it on."
|
|
31
|
+
|
|
32
|
+
# Utility functions
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _setMotors(dirL, powerL, dirR, powerR):
|
|
36
|
+
# """Write Motor State via i2c
|
|
37
|
+
|
|
38
|
+
# Parameters:
|
|
39
|
+
# dirL (0/1): Direction of left Wheel. 0=forward, 1=backward
|
|
40
|
+
# powerL (int): Power of left Wheel in range [0,255].
|
|
41
|
+
# dirR (0/1): Direction of right Wheel. 0=forward, 1=backward
|
|
42
|
+
# powerR (int): Power of right Wheel in range [0,255].
|
|
43
|
+
#
|
|
44
|
+
# raises:
|
|
45
|
+
# RuntimeError: if Robot is switched off or unconnected. (replaces ENODEV error)
|
|
46
|
+
# """
|
|
47
|
+
global _motorState
|
|
48
|
+
_motorState[1] = dirL
|
|
49
|
+
_motorState[2] = powerL
|
|
50
|
+
_motorState[3] = dirR
|
|
51
|
+
_motorState[4] = powerR
|
|
52
|
+
try:
|
|
53
|
+
i2c.write(0x10, _motorState)
|
|
54
|
+
except:
|
|
55
|
+
raise RuntimeError(_UNCONNECTEDERRORMSG)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _setSingleMotor(side, dir, power):
|
|
59
|
+
# """Write Motor State of a single Motor via i2c
|
|
60
|
+
|
|
61
|
+
# Parameters:
|
|
62
|
+
# side (0/2): Selection of the Wheel. 0=left, 2=right
|
|
63
|
+
# dir (0/1): Direction for that Wheel. 0=forward, 1=backward
|
|
64
|
+
# power (int): Power for that Wheel in range [0,255].
|
|
65
|
+
#
|
|
66
|
+
# raises:
|
|
67
|
+
# RuntimeError: if Robot is switched off or unconnected. (replaces ENODEV error)
|
|
68
|
+
# """
|
|
69
|
+
global _motorState
|
|
70
|
+
_motorState[1 + side] = dir
|
|
71
|
+
_motorState[2 + side] = power
|
|
72
|
+
try:
|
|
73
|
+
i2c.write(0x10, _motorState)
|
|
74
|
+
except:
|
|
75
|
+
raise RuntimeError(_UNCONNECTEDERRORMSG)
|
|
76
|
+
|
|
77
|
+
# _getPowerByte was used to create LookUpTable (_powerBytesLUT) used in _getPowerByteLUT to reduce Memory Leaks.
|
|
78
|
+
# def _getPowerByte(speed, offset):
|
|
79
|
+
# # """Computes the power value for a given speed in %.
|
|
80
|
+
# # It accouts for the nonlinearity of motor strength.
|
|
81
|
+
# # This is the original function that generates the LUT.
|
|
82
|
+
#
|
|
83
|
+
# # Parameter:
|
|
84
|
+
# # speed (number): Desired speed of the Robot in %. Range [0,100].
|
|
85
|
+
# # offset (int): basic power offset to add to the function.
|
|
86
|
+
# # Returns:
|
|
87
|
+
# # int: Power in range [0,255] to write to the motors via i2c.
|
|
88
|
+
# # """
|
|
89
|
+
# if speed <= 0:
|
|
90
|
+
# return 0
|
|
91
|
+
# elif speed < 40:
|
|
92
|
+
# return int(0.6 * speed + 15 + offset)
|
|
93
|
+
# elif speed < 60:
|
|
94
|
+
# return int(speed + offset)
|
|
95
|
+
# elif speed < 100:
|
|
96
|
+
# return int(min(1.05546 ** speed + 34 + offset, 255))
|
|
97
|
+
# else:
|
|
98
|
+
# return 255
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _getPowerByteLUT(speed, offset):
|
|
102
|
+
# """Lookup Table version of _getPowerByte"""
|
|
103
|
+
return min(_powerBytesLUT[speed] + offset, 255)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _getArcBytes(r):
|
|
107
|
+
# """Computes the power bytes to drive an arc.
|
|
108
|
+
|
|
109
|
+
# Parameter:
|
|
110
|
+
# r (float): Radius in meters of the desired Arc.
|
|
111
|
+
# Measured from the center of the axle.
|
|
112
|
+
# Returns:
|
|
113
|
+
# (int, int): Power byte values for each motor.
|
|
114
|
+
# First the outer Wheels byte [0,255],
|
|
115
|
+
# then the inner Wheels byte [0,255].
|
|
116
|
+
# """
|
|
117
|
+
rmm = int(r * 100) # radius in mm
|
|
118
|
+
outerSpeed = _speedPercent
|
|
119
|
+
# adjust outer speed for unhealthy values
|
|
120
|
+
if outerSpeed < 25:
|
|
121
|
+
outerSpeed = 25
|
|
122
|
+
speedFix = min(abs(outerSpeed - 70), 20) / 20
|
|
123
|
+
reducedSpeed = 0
|
|
124
|
+
if rmm > 5:
|
|
125
|
+
# formula derived from data and simplified
|
|
126
|
+
n = outerSpeed * (3 * _arcScaling - outerSpeed - 9 * rmm + 220)
|
|
127
|
+
d = -14 * _arcScaling + outerSpeed - 200 + 3 * outerSpeed - 10 * rmm - 290
|
|
128
|
+
reducedSpeed = int(n/d)
|
|
129
|
+
if reducedSpeed < 2: # fix values at low radii (negative values too)
|
|
130
|
+
reducedSpeed = 2 if rmm > 15 else 1
|
|
131
|
+
innerByte = _getPowerByteLUT(int(reducedSpeed), 0)
|
|
132
|
+
outerByte = _getPowerByteLUT(int(outerSpeed), 0)
|
|
133
|
+
return (innerByte, outerByte)
|
|
134
|
+
|
|
135
|
+
# Movement functions
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def calibrate(offset, differential=0, arcScaling=0):
|
|
139
|
+
# """Adjust the driving behaviour of the robots
|
|
140
|
+
|
|
141
|
+
# Parameters:
|
|
142
|
+
# offset (int): Offsets the minimal power of the motors.
|
|
143
|
+
# Range [-10,50]. Highly affected by battery level.
|
|
144
|
+
# Adjust this value until it starts moving at speed 1%.
|
|
145
|
+
# differential (int, optional): Adjusts power difference
|
|
146
|
+
# of left and right Wheel. Range [-150, 150].
|
|
147
|
+
# Varies unpredictably with different speeds.
|
|
148
|
+
# If a Robot steers left when driving forward: negative value
|
|
149
|
+
# If a Robot steers right when driving forward: positive value
|
|
150
|
+
# Perfectly straight driving Robots can leave this at 0.
|
|
151
|
+
# arcScaling (int, optional): Adjusts the radius
|
|
152
|
+
# driven by leftArc/rightArc. Valid range [-50, 50].
|
|
153
|
+
# If the Robots radius is too large: positive value
|
|
154
|
+
# If the Robots radius is too small: negative value
|
|
155
|
+
# This then adjusts all radii for this Robot, by
|
|
156
|
+
# scaling it's internal function to the new range.
|
|
157
|
+
# """
|
|
158
|
+
global _powerDifferential
|
|
159
|
+
global _powerOffset
|
|
160
|
+
global _arcScaling
|
|
161
|
+
_powerOffset = max(min(int(offset), 50), -14)
|
|
162
|
+
_powerDifferential = max(min(int(differential), 150), -150)
|
|
163
|
+
_arcScaling = max(min(arcScaling, 50), -50)
|
|
164
|
+
setSpeed(_speedPercent)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def setSpeed(speed):
|
|
168
|
+
# """sets the speed for future motion
|
|
169
|
+
|
|
170
|
+
# Parameter:
|
|
171
|
+
# speed (int): in Range [0,100] as % of desired velocity.
|
|
172
|
+
# """
|
|
173
|
+
global _speedPercent
|
|
174
|
+
global _powerByteL
|
|
175
|
+
global _powerByteR
|
|
176
|
+
_speedPercent = int(min(max(speed, 0), 100))
|
|
177
|
+
powerByte = _getPowerByteLUT(_speedPercent, _powerOffset)
|
|
178
|
+
boost = round((1 - _speedPercent / 100) *
|
|
179
|
+
abs(_powerDifferential)) if _speedPercent > 0 else 0
|
|
180
|
+
reduction = round((_speedPercent / 100) * abs(_powerDifferential))
|
|
181
|
+
if _powerDifferential > 0:
|
|
182
|
+
_powerByteL = powerByte - reduction
|
|
183
|
+
_powerByteR = powerByte + boost
|
|
184
|
+
else:
|
|
185
|
+
_powerByteL = powerByte + boost
|
|
186
|
+
_powerByteR = powerByte - reduction
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def resetSpeed():
|
|
190
|
+
setSpeed(50)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def stop():
|
|
194
|
+
_setMotors(0, 0, 0, 0)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def forward():
|
|
198
|
+
_setMotors(0, _powerByteL, 0, _powerByteR)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def backward():
|
|
202
|
+
_setMotors(1, _powerByteL, 1, _powerByteR)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def left():
|
|
206
|
+
_setMotors(1, _powerByteL, 0, _powerByteR)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def right():
|
|
210
|
+
_setMotors(0, _powerByteL, 1, _powerByteR)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def rightArc(radius):
|
|
214
|
+
# """radius must be given in meters."""
|
|
215
|
+
inner, outer = _getArcBytes(radius)
|
|
216
|
+
_setMotors(0, outer, 0, inner)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def leftArc(radius):
|
|
220
|
+
# """radius must be given in meters."""
|
|
221
|
+
inner, outer = _getArcBytes(radius)
|
|
222
|
+
_setMotors(0, inner, 0, outer)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class Motor:
|
|
226
|
+
def __init__(self, side):
|
|
227
|
+
# """Create a single motor.
|
|
228
|
+
|
|
229
|
+
# Parameter:
|
|
230
|
+
# side (0/2): 0=left, 2=right
|
|
231
|
+
# """
|
|
232
|
+
self._side = side
|
|
233
|
+
|
|
234
|
+
def rotate(self, speed):
|
|
235
|
+
# """Controls rotation of this motor.
|
|
236
|
+
|
|
237
|
+
# Parameters:
|
|
238
|
+
# speed (int): Desired speed in %.
|
|
239
|
+
# Valid range [-100,100].
|
|
240
|
+
# Negative values are for backward turning.
|
|
241
|
+
# """
|
|
242
|
+
speedClamped = int(min(max(abs(speed), 0), 100))
|
|
243
|
+
power = _getPowerByteLUT(speedClamped, _powerOffset)
|
|
244
|
+
direction = 0 if speed > 0 else 1
|
|
245
|
+
_setSingleMotor(self._side, direction, power)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def setServo(servo, angle):
|
|
249
|
+
# """Moves the Servo to position angle.
|
|
250
|
+
# Servos must be connected to the Maqueen Plus V2's "P" connectors.
|
|
251
|
+
# They are located at the back of the robot.
|
|
252
|
+
|
|
253
|
+
# Parameters:
|
|
254
|
+
# servo (str): Desired Servo Port. Either 'P0', 'P1' or 'P2'.
|
|
255
|
+
# angle (int): Desired angle in degrees. Range [0,180].
|
|
256
|
+
|
|
257
|
+
# raises:
|
|
258
|
+
# ValueError: if arguments are out of valid range
|
|
259
|
+
# """
|
|
260
|
+
if servo == "P0" or servo == 'S1':
|
|
261
|
+
pin = pin0
|
|
262
|
+
elif servo == "P1" or servo == 'S2':
|
|
263
|
+
pin = pin1
|
|
264
|
+
elif servo == "P2":
|
|
265
|
+
pin = pin2
|
|
266
|
+
else:
|
|
267
|
+
raise ValueError("Unknown Servo. Please use 'P0', 'P1' or 'P2'.")
|
|
268
|
+
|
|
269
|
+
if angle < 0 or angle > 180:
|
|
270
|
+
raise ValueError("Invalid angle. Must be between 0 and 180")
|
|
271
|
+
|
|
272
|
+
frac = (_servoMaxPulse - _servoMinPulse) * int(angle)
|
|
273
|
+
offset = (frac >> 8) + (frac >> 10) + (frac >> 11) + (frac >> 12) # / 180
|
|
274
|
+
usPulseTime = _servoMinPulse + offset # min + (max-min) * (angle / 180)
|
|
275
|
+
pin.set_analog_period(20)
|
|
276
|
+
pin.write_analog(usPulseTime)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def setMinAngleVal(duty):
|
|
280
|
+
# """ Sets the minimal pulse duty cycle for the servo.
|
|
281
|
+
# It should match 1ms of a 20ms period, where the duty is in range [0,1024].
|
|
282
|
+
# Theoretically: 1/20*1024 = 51. Practically: Default is 25. adjust carefully in steps of 1.
|
|
283
|
+
#
|
|
284
|
+
# Parameter:
|
|
285
|
+
# duty (int): The minimal duty amount for a write_analog signal with 20ms pulse.
|
|
286
|
+
# It should approximate 1ms. 1ms/20ms*1024 = min duty = 0-degree position for the servo.
|
|
287
|
+
# """
|
|
288
|
+
global _servoMinPulse
|
|
289
|
+
_servoMinPulse = int(duty)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def setMaxAngleVal(duty):
|
|
293
|
+
# """ Sets the maximal pulse duty cycle for the servo.
|
|
294
|
+
# It should match 2ms of a 20ms period, where the duty is in range [0,1024].
|
|
295
|
+
# Theoretically: 2/20*1024 = 102. Practically: Default is 131. adjust carefully to increase range of the servo.
|
|
296
|
+
#
|
|
297
|
+
# Parameter:
|
|
298
|
+
# duty (int): The maximal duty amount for a write_analog signal with 20ms pulse.
|
|
299
|
+
# It should approximate 2ms. 2ms/20ms*1024 = max duty = 180-degree position for the servo.
|
|
300
|
+
# """
|
|
301
|
+
global _servoMaxPulse
|
|
302
|
+
_servoMaxPulse = int(duty)
|
|
303
|
+
|
|
304
|
+
# Sensor functions
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class IRSensor:
|
|
308
|
+
_address = bytes(b'\x1D')
|
|
309
|
+
|
|
310
|
+
def __init__(self, index):
|
|
311
|
+
# """Create a new IR sensor.
|
|
312
|
+
|
|
313
|
+
# Parameter:
|
|
314
|
+
# index (int): 0=R2, 1=R1, 2=M, 3=L1, 4=L2
|
|
315
|
+
# """
|
|
316
|
+
self._index = index
|
|
317
|
+
|
|
318
|
+
def read_digital(self):
|
|
319
|
+
# """Returns if the surface below is dark or bright.
|
|
320
|
+
# Result can be adjusted by putting the sensor on the dark
|
|
321
|
+
# surface and pressing the LineKey calibration button on the
|
|
322
|
+
# Robot for a few seconds, until the LED's blink.
|
|
323
|
+
|
|
324
|
+
# Returns:
|
|
325
|
+
# 0 if the surface is dark. No light was reflected (in Air).
|
|
326
|
+
# 1 if the surface is bright. A lot of light was reflected.
|
|
327
|
+
#
|
|
328
|
+
# raises:
|
|
329
|
+
# RuntimeError: if Robot is switched off or unconnected. (replaces ENODEV error)
|
|
330
|
+
# """
|
|
331
|
+
try:
|
|
332
|
+
i2c.write(0x10, IRSensor._address)
|
|
333
|
+
except:
|
|
334
|
+
raise RuntimeError(_UNCONNECTEDERRORMSG)
|
|
335
|
+
byte = ~i2c.read(0x10, 1)[0]
|
|
336
|
+
# mask out corresponding bit, from returned byte.
|
|
337
|
+
return (byte & (2 ** self._index)) >> self._index
|
|
338
|
+
|
|
339
|
+
def read_analog(self):
|
|
340
|
+
# """Returns the brightness of the surface as a byte.
|
|
341
|
+
|
|
342
|
+
# Returns:
|
|
343
|
+
# int: amount of reflection of light in range [0,255].
|
|
344
|
+
#
|
|
345
|
+
# raises:
|
|
346
|
+
# RuntimeError: if Robot is switched off or unconnected. (replaces ENODEV error)
|
|
347
|
+
# """
|
|
348
|
+
try:
|
|
349
|
+
i2c.write(0x10, IRSensor._address)
|
|
350
|
+
except:
|
|
351
|
+
raise RuntimeError(_UNCONNECTEDERRORMSG)
|
|
352
|
+
# Buffer structure:
|
|
353
|
+
# 1 Byte Bitmask (for digital redout),
|
|
354
|
+
# then 10 Bytes analog byte values (every second entry is a value).
|
|
355
|
+
buffer = i2c.read(0x10, 11)
|
|
356
|
+
return buffer[1 + self._index * 2]
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def ir_read_values_as_byte():
|
|
360
|
+
# """get single byte with bit encoding of each Infrared sensor state
|
|
361
|
+
# Bits: 0=R2, 1=R1, 2=M, 3=L1, 4=L2
|
|
362
|
+
# """
|
|
363
|
+
i2c.write(0x10, bytearray([0x1D]))
|
|
364
|
+
buf = i2c.read(0x10, 1)
|
|
365
|
+
return ~buf[0]
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def getDistance():
|
|
369
|
+
# """uses the ultrasonic sensor to measure distance
|
|
370
|
+
|
|
371
|
+
# Returns:
|
|
372
|
+
# int: valid Distance as cm in range [0,500].
|
|
373
|
+
# For measurement errors or larger distances: 255.
|
|
374
|
+
# """
|
|
375
|
+
pin13.write_digital(1)
|
|
376
|
+
pin13.write_digital(0)
|
|
377
|
+
p = machine.time_pulse_us(pin14, 1, 50000)
|
|
378
|
+
# approximate division: p / 58.2 - 0.5
|
|
379
|
+
cm = (p >> 6) + (p >> 10) + (p >> 11) + (p >> 12) + 1
|
|
380
|
+
return max(min(cm, 500), 0) if cm > 0 else 255
|
|
381
|
+
|
|
382
|
+
# Signaling functions
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def setLED(state, stateR=None):
|
|
386
|
+
# """Set the front red LED's.
|
|
387
|
+
|
|
388
|
+
# Parameters:
|
|
389
|
+
# state (0/1): Sets the state of the left LED.
|
|
390
|
+
# if stateR is omitted, then both LEDS.
|
|
391
|
+
# 0=Off, 1=On
|
|
392
|
+
# stateR (0/1/None, optional): Sets the right LED state.
|
|
393
|
+
# 0=Off, 1=On, Default=None uses "state" for right LED.
|
|
394
|
+
# """
|
|
395
|
+
global _ledState
|
|
396
|
+
stateR = stateR if stateR != None else state
|
|
397
|
+
_ledState[1] = state
|
|
398
|
+
_ledState[2] = stateR
|
|
399
|
+
i2c.write(0x10, _ledState)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def setLEDLeft(state):
|
|
403
|
+
# """state: 0=Off, 1=On"""
|
|
404
|
+
global _ledState
|
|
405
|
+
_ledState[1] = state
|
|
406
|
+
i2c.write(0x10, _ledState)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def setLEDRight(state):
|
|
410
|
+
# """state: 0=Off, 1=On"""
|
|
411
|
+
global _ledState
|
|
412
|
+
_ledState[2] = state
|
|
413
|
+
i2c.write(0x10, _ledState)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def fillRGB(red, green, blue):
|
|
417
|
+
# """Uses Neopixel to set all 4 bottom RGB LEDs color.
|
|
418
|
+
# Parameters (red,green,blue) are each a byte in Range [0,255].
|
|
419
|
+
# """
|
|
420
|
+
for i in range(4):
|
|
421
|
+
_underglowNP[i] = (red, green, blue)
|
|
422
|
+
_underglowNP.show()
|
|
423
|
+
setRGB=fillRGB
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def clearRGB():
|
|
427
|
+
_underglowNP.clear()
|
|
428
|
+
|
|
429
|
+
def posRGB(position, red, green, blue):
|
|
430
|
+
# """Uses Neopixel to set a single RGB LED of the robot.
|
|
431
|
+
|
|
432
|
+
# Parameters:
|
|
433
|
+
# position (int): position of the targeted LED.
|
|
434
|
+
# Numbers are visible at underside of Robot.
|
|
435
|
+
# 0=front left
|
|
436
|
+
# 1=back left
|
|
437
|
+
# 2=back right
|
|
438
|
+
# 3=front right
|
|
439
|
+
# red, green, blue (int): color byte value.
|
|
440
|
+
# each in range [0,255].
|
|
441
|
+
|
|
442
|
+
# raises:
|
|
443
|
+
# ValueError: if position argument is out of valid range
|
|
444
|
+
# """
|
|
445
|
+
if position < 0 or position > 3:
|
|
446
|
+
raise ValueError("invalid RGB-LED position. Must be 0,1,2 or 3.")
|
|
447
|
+
_underglowNP[position] = (red, green, blue)
|
|
448
|
+
_underglowNP.show()
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def setAlarm(state):
|
|
452
|
+
if state:
|
|
453
|
+
music.play(_alarmSequence, wait=False, loop=True)
|
|
454
|
+
else:
|
|
455
|
+
music.stop()
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def beep():
|
|
459
|
+
music.pitch(440, 200, wait=False)
|
|
460
|
+
|
|
461
|
+
# Class constants (for compatibilty)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
class LEDState:
|
|
465
|
+
ON = 1
|
|
466
|
+
OFF = 0
|
|
467
|
+
RED = 1
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
class IR:
|
|
471
|
+
R2 = 0
|
|
472
|
+
R1 = 1
|
|
473
|
+
M = 2
|
|
474
|
+
L1 = 3
|
|
475
|
+
L2 = 4
|
|
476
|
+
masks = [0x01, 0x02, 0x04, 0x08, 0x10]
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
# Default instances
|
|
480
|
+
pin2.set_pull(pin2.NO_PULL)
|
|
481
|
+
delay = sleep
|
|
482
|
+
irR2 = IRSensor(0)
|
|
483
|
+
irR1 = IRSensor(1)
|
|
484
|
+
irRight = irR1
|
|
485
|
+
irM = IRSensor(2)
|
|
486
|
+
irL1 = IRSensor(3)
|
|
487
|
+
irLeft = irL1
|
|
488
|
+
irL2 = IRSensor(4)
|
|
489
|
+
motL = Motor(0)
|
|
490
|
+
motR = Motor(2)
|