@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,401 @@
|
|
|
1
|
+
# mbrobot.py
|
|
2
|
+
# Date 10/09/24
|
|
3
|
+
|
|
4
|
+
from microbit import i2c, pin1, pin2, pin8, pin12, 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 = 40
|
|
13
|
+
_powerByteR = 40
|
|
14
|
+
_motorState = bytearray(5)
|
|
15
|
+
_servoBytes = bytearray(2)
|
|
16
|
+
_powerBytesLUT = bytes(b'\x00\x0b\x0b\x0c\x0c\x0d\x0d\x0d\x0e\x0e\x0f\x0f\x0f\x10\x10\x11\x11\x11\x12\x12\x13\x13\x13\x14\x14\x15\x15\x15\x16\x16\x17\x17\x17\x18\x19\x1a\x1b\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x36\x38\x3a\x3c\x3f\x41\x44\x46\x49\x4c\x4f\x53\x56\x5a\x5e\x62\x67\x6b\x70\x75\x7b\x81\x87\x8d\x94\x9b\xa3\xab\xb4\xbd\xc6\xd0\xdb\xe6\xf2\xff')
|
|
17
|
+
|
|
18
|
+
# Calibration data
|
|
19
|
+
_powerOffset = 0
|
|
20
|
+
_powerDifferential = 0
|
|
21
|
+
_arcScaling = 0
|
|
22
|
+
|
|
23
|
+
# signaling objects
|
|
24
|
+
_underglowNP = neopixel.NeoPixel(pin15, 4)
|
|
25
|
+
np_rgb_pixels = _underglowNP
|
|
26
|
+
_alarmSequence = ['c5:1', 'r', 'c5:1', 'r:3']
|
|
27
|
+
|
|
28
|
+
_UNCONNECTEDERRORMSG = "Please connect to Maqueen robot and switch it on."
|
|
29
|
+
|
|
30
|
+
# Utility functions
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _setMotors(dirL, powerL, dirR, powerR):
|
|
34
|
+
# """Write Motor State via i2c
|
|
35
|
+
|
|
36
|
+
# Parameters:
|
|
37
|
+
# dirL (0/1): Direction of left Wheel. 0=forward, 1=backward
|
|
38
|
+
# powerL (int): Power of left Wheel in range [0,255].
|
|
39
|
+
# dirR (0/1): Direction of right Wheel. 0=forward, 1=backward
|
|
40
|
+
# powerR (int): Power of right Wheel in range [0,255].
|
|
41
|
+
#
|
|
42
|
+
# raises:
|
|
43
|
+
# RuntimeError: if Robot is switched off or unconnected. (replaces ENODEV error)
|
|
44
|
+
# """
|
|
45
|
+
global _motorState
|
|
46
|
+
_motorState[1] = dirL
|
|
47
|
+
_motorState[2] = powerL
|
|
48
|
+
_motorState[3] = dirR
|
|
49
|
+
_motorState[4] = powerR
|
|
50
|
+
try:
|
|
51
|
+
i2c.write(0x10, _motorState)
|
|
52
|
+
except:
|
|
53
|
+
raise RuntimeError(_UNCONNECTEDERRORMSG)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _setSingleMotor(side, dir, power):
|
|
57
|
+
# """Write Motor State of a single Motor via i2c
|
|
58
|
+
|
|
59
|
+
# Parameters:
|
|
60
|
+
# side (0/2): Selection of the Wheel. 0=left, 2=right
|
|
61
|
+
# dir (0/1): Direction for that Wheel. 0=forward, 1=backward
|
|
62
|
+
# power (int): Power for that Wheel in range [0,255].
|
|
63
|
+
#
|
|
64
|
+
# raises:
|
|
65
|
+
# RuntimeError: if Robot is switched off or unconnected. (replaces ENODEV error)
|
|
66
|
+
# """
|
|
67
|
+
global _motorState
|
|
68
|
+
_motorState[1 + side] = dir
|
|
69
|
+
_motorState[2 + side] = power
|
|
70
|
+
try:
|
|
71
|
+
i2c.write(0x10, _motorState)
|
|
72
|
+
except:
|
|
73
|
+
raise RuntimeError(_UNCONNECTEDERRORMSG)
|
|
74
|
+
|
|
75
|
+
# _getPowerByte was used to create LookUpTable (_powerBytesLUT) used in _getPowerByteLUT to reduce Memory Leaks.
|
|
76
|
+
# def _getPowerByte(speed, offset):
|
|
77
|
+
# # """Computes the power value for a given speed in %.
|
|
78
|
+
# # It accouts for the nonlinearity of motor strength.
|
|
79
|
+
# # This is the original function that generates the LUT.
|
|
80
|
+
#
|
|
81
|
+
# # Parameter:
|
|
82
|
+
# # speed (number): Desired speed of the Robot in %. Range [0,100].
|
|
83
|
+
# # offset (number): basic power offset to add to the function.
|
|
84
|
+
# # Returns:
|
|
85
|
+
# # int: Power in range [0,255] to write to the motors via i2c.
|
|
86
|
+
# # """
|
|
87
|
+
# if speed <= 0:
|
|
88
|
+
# return 0
|
|
89
|
+
# if speed <= 33:
|
|
90
|
+
# return int(0.4 * speed + 11 + offset)
|
|
91
|
+
# elif speed <= 63:
|
|
92
|
+
# return int(0.89 * speed - 5 + offset)
|
|
93
|
+
# elif speed < 100:
|
|
94
|
+
# return int(min(1.0561 ** speed + 20 + offset, 255))
|
|
95
|
+
# else:
|
|
96
|
+
# return 255
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _getPowerByteLUT(speed, offset):
|
|
100
|
+
# """Lookup Table version of _getPowerByte"""
|
|
101
|
+
return min(_powerBytesLUT[speed] + offset, 255)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _getArcBytes(r):
|
|
105
|
+
# """Computes the power bytes to drive an arc.
|
|
106
|
+
|
|
107
|
+
# Parameter:
|
|
108
|
+
# r (float): Radius in meters of the desired Arc.
|
|
109
|
+
# Measured from the center of the axle.
|
|
110
|
+
# Returns:
|
|
111
|
+
# (int, int): Power byte values for each motor.
|
|
112
|
+
# First the outer Wheels byte [0,255],
|
|
113
|
+
# then the inner Wheels byte [0,255].
|
|
114
|
+
# """
|
|
115
|
+
outerSpeed = _speedPercent
|
|
116
|
+
rCm = int(r * 100) # r in cm instead of meters
|
|
117
|
+
# adjust outer speed for unhealthy combinations
|
|
118
|
+
# That is: too low speeds and big arcs.
|
|
119
|
+
threshold = outerSpeed - max(rCm + 20, 40)
|
|
120
|
+
if threshold <= 0:
|
|
121
|
+
outerSpeed = min(max(rCm + 40, 40), 100)
|
|
122
|
+
reducedSpeed = 0
|
|
123
|
+
if rCm >= 4: # minimal radius is half the axle size: 3.5 cm rounded.
|
|
124
|
+
flattening = (100 - outerSpeed) // 2
|
|
125
|
+
reducedSpeed = (rCm * 10 - 35) / \
|
|
126
|
+
(rCm * (11 + (_arcScaling-4)/10) + 90 + flattening)
|
|
127
|
+
reducedSpeed = reducedSpeed * outerSpeed
|
|
128
|
+
innerByte = _getPowerByteLUT(int(reducedSpeed), 0)
|
|
129
|
+
outerByte = _getPowerByteLUT(int(outerSpeed), 0)
|
|
130
|
+
return (innerByte, outerByte)
|
|
131
|
+
|
|
132
|
+
# Movement Functions
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def calibrate(offset, differential=0, arcScaling=0):
|
|
136
|
+
# """Adjust the driving behaviour of the robots
|
|
137
|
+
|
|
138
|
+
# Parameters:
|
|
139
|
+
# offset (int): Offsets the minimal power of the motors.
|
|
140
|
+
# Range [-10,50]. Highly affected by battery level.
|
|
141
|
+
# Adjust this value until it starts moving at speed 1%.
|
|
142
|
+
# differential (int, optional): Adjusts power difference
|
|
143
|
+
# of left and right Wheel. Range [-150, 150].
|
|
144
|
+
# Varies unpredictably with different speeds.
|
|
145
|
+
# If a Robot steers left when driving forward: negative value
|
|
146
|
+
# If a Robot steers right when driving forward: positive value
|
|
147
|
+
# Perfectly straight driving Robots can leave this at 0.
|
|
148
|
+
# arcScaling (int, optional): Adjusts the radius
|
|
149
|
+
# driven by leftArc/rightArc. Valid range [-50, 50].
|
|
150
|
+
# If the Robots radius is too large: positive value
|
|
151
|
+
# If the Robots radius is too small: negative value
|
|
152
|
+
# This then adjusts all radii for this Robot, by
|
|
153
|
+
# scaling it's internal function to the new range.
|
|
154
|
+
# """
|
|
155
|
+
global _powerDifferential
|
|
156
|
+
global _powerOffset
|
|
157
|
+
global _arcScaling
|
|
158
|
+
_powerOffset = max(min(int(offset), 50), -10)
|
|
159
|
+
_powerDifferential = max(min(int(differential), 150), -150)
|
|
160
|
+
_arcScaling = max(min(arcScaling, 50), -15)
|
|
161
|
+
setSpeed(_speedPercent)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def setSpeed(speed):
|
|
165
|
+
# """sets the speed for future motion
|
|
166
|
+
|
|
167
|
+
# Parameter:
|
|
168
|
+
# speed (int): in Range [0,100] as % of desired velocity.
|
|
169
|
+
# """
|
|
170
|
+
global _speedPercent
|
|
171
|
+
global _powerByteL
|
|
172
|
+
global _powerByteR
|
|
173
|
+
_speedPercent = int(min(max(speed, 0), 100))
|
|
174
|
+
powerByte = _getPowerByteLUT(_speedPercent, _powerOffset)
|
|
175
|
+
boost = round((1 - _speedPercent / 100) *
|
|
176
|
+
abs(_powerDifferential)) if _speedPercent > 0 else 0
|
|
177
|
+
reduction = round((_speedPercent / 100) * abs(_powerDifferential))
|
|
178
|
+
if _powerDifferential > 0:
|
|
179
|
+
_powerByteL = powerByte - reduction
|
|
180
|
+
_powerByteR = powerByte + boost
|
|
181
|
+
else:
|
|
182
|
+
_powerByteL = powerByte + boost
|
|
183
|
+
_powerByteR = powerByte - reduction
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def resetSpeed():
|
|
187
|
+
setSpeed(50)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def stop():
|
|
191
|
+
_setMotors(0, 0, 0, 0)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def forward():
|
|
195
|
+
_setMotors(0, _powerByteL, 0, _powerByteR)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def backward():
|
|
199
|
+
_setMotors(1, _powerByteL, 1, _powerByteR)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def left():
|
|
203
|
+
_setMotors(1, _powerByteL, 0, _powerByteR)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def right():
|
|
207
|
+
_setMotors(0, _powerByteL, 1, _powerByteR)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def rightArc(radius):
|
|
211
|
+
# """radius must be given in meters."""
|
|
212
|
+
inner, outer = _getArcBytes(radius)
|
|
213
|
+
_setMotors(0, outer, 0, inner)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def leftArc(radius):
|
|
217
|
+
# """radius must be given in meters."""
|
|
218
|
+
inner, outer = _getArcBytes(radius)
|
|
219
|
+
_setMotors(0, inner, 0, outer)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Motor:
|
|
223
|
+
def __init__(self, side):
|
|
224
|
+
# """Create a single motor.
|
|
225
|
+
|
|
226
|
+
# Parameter:
|
|
227
|
+
# side (8/2): 0=left, 2=right
|
|
228
|
+
# """
|
|
229
|
+
self._side = side
|
|
230
|
+
|
|
231
|
+
def rotate(self, speed):
|
|
232
|
+
# """Controls rotation of this motor.
|
|
233
|
+
|
|
234
|
+
# Parameters:
|
|
235
|
+
# speed (int): Desired speed in %.
|
|
236
|
+
# Valid range [-100,100].
|
|
237
|
+
# Negative values are for backward turning.
|
|
238
|
+
# """
|
|
239
|
+
speedClamped = int(min(max(abs(speed), 0), 100))
|
|
240
|
+
power = _getPowerByteLUT(speedClamped, _powerOffset)
|
|
241
|
+
direction = 0 if speed > 0 else 1
|
|
242
|
+
_setSingleMotor(self._side, direction, power)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def setServo(servo, angle):
|
|
246
|
+
# """Moves the Servo to position angle.
|
|
247
|
+
# Servos must be connected to the Maqueen Lite's Servo connectors.
|
|
248
|
+
# They are located in front of the left wheel.
|
|
249
|
+
|
|
250
|
+
# Parameters:
|
|
251
|
+
# servo (str): Desired Servo Port. Either 'S1' or 'S2'.
|
|
252
|
+
# angle (int): Desired angle in degrees. Range [0,180].
|
|
253
|
+
|
|
254
|
+
# raises:
|
|
255
|
+
# ValueError: if arguments are out of valid range
|
|
256
|
+
# RuntimeError: if Robot is switched off or unconnected.
|
|
257
|
+
# """
|
|
258
|
+
global _servoBytes
|
|
259
|
+
# Acceptance of "P0" and "P1" is for compatibility with V2.
|
|
260
|
+
if servo == 'S1' or servo == 'P0':
|
|
261
|
+
_servoBytes[0] = 0x14
|
|
262
|
+
elif servo == 'S2' or servo == 'P1':
|
|
263
|
+
_servoBytes[0] = 0x15
|
|
264
|
+
else:
|
|
265
|
+
raise ValueError("Unknown Servo. Please use 'S1' or 'S2'.")
|
|
266
|
+
|
|
267
|
+
if angle < 0 or angle > 180:
|
|
268
|
+
raise ValueError("Invalid angle. Must be between 0 and 180")
|
|
269
|
+
|
|
270
|
+
_servoBytes[1] = angle
|
|
271
|
+
try:
|
|
272
|
+
i2c.write(0x10, _servoBytes)
|
|
273
|
+
except:
|
|
274
|
+
raise RuntimeError(_UNCONNECTEDERRORMSG)
|
|
275
|
+
|
|
276
|
+
# Sensor functions
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class IRSensor():
|
|
280
|
+
def __init__(self, pin):
|
|
281
|
+
# """Create a new IR sensor.
|
|
282
|
+
|
|
283
|
+
# Parameter:
|
|
284
|
+
# pin (object): pin13=left, pin14=right
|
|
285
|
+
# """
|
|
286
|
+
self._pin = pin
|
|
287
|
+
|
|
288
|
+
def read_digital(self):
|
|
289
|
+
# """Returns if the surface below is dark or bright.
|
|
290
|
+
# Result can be adjusted by putting the sensor on the dark
|
|
291
|
+
# surface and pressing the LineKey calibration button on the
|
|
292
|
+
# Robot for a few seconds, until the LED's blink.
|
|
293
|
+
|
|
294
|
+
# Returns:
|
|
295
|
+
# 0 if the surface is dark. No light was reflected (in Air).
|
|
296
|
+
# 1 if the surface is bright. A lot of light was reflected.
|
|
297
|
+
# """
|
|
298
|
+
return self._pin.read_digital()
|
|
299
|
+
|
|
300
|
+
def read_analog(self):
|
|
301
|
+
raise NameError(
|
|
302
|
+
"Maqueen Lite does not support reading analog sensor values.")
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def getDistance():
|
|
306
|
+
# """uses the ultrasonic sensor to measure distance
|
|
307
|
+
|
|
308
|
+
# Returns:
|
|
309
|
+
# int: valid Distance as cm in range [0,500].
|
|
310
|
+
# For measurement errors or larger distances: 255.
|
|
311
|
+
# """
|
|
312
|
+
pin1.write_digital(1)
|
|
313
|
+
pin1.write_digital(0)
|
|
314
|
+
p = machine.time_pulse_us(pin2, 1, 50000)
|
|
315
|
+
# approximate division: cm = p / 57.5
|
|
316
|
+
cm = (p >> 6) + (p >> 10) + (p >> 11) + (p >> 12) + 1
|
|
317
|
+
return max(min(cm, 500), 0) if cm > 0 else 255
|
|
318
|
+
|
|
319
|
+
# Signaling functions
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def setLED(state, stateR=None):
|
|
323
|
+
# """Set the front red LED's.
|
|
324
|
+
|
|
325
|
+
# Parameters:
|
|
326
|
+
# state (0/1): Sets the state of the left LED.
|
|
327
|
+
# if stateR is omitted, then both LEDS.
|
|
328
|
+
# 0=Off, 1=On
|
|
329
|
+
# stateR (0/1/None, optional): Sets the right LED state.
|
|
330
|
+
# 0=Off, 1=On, Default=None uses "state" for right LED.
|
|
331
|
+
# """
|
|
332
|
+
stateR = stateR if stateR != None else state
|
|
333
|
+
pin8.write_digital(state)
|
|
334
|
+
pin12.write_digital(stateR)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def setLEDLeft(state):
|
|
338
|
+
# """state: 0=Off, 1=On"""
|
|
339
|
+
pin8.write_digital(state)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def setLEDRight(state):
|
|
343
|
+
# """state: 0=Off, 1=On"""
|
|
344
|
+
pin12.write_digital(state)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def fillRGB(red, green, blue):
|
|
348
|
+
# """Uses Neopixel to set all 4 bottom RGB LEDs color.
|
|
349
|
+
# Parameters (red,green,blue) are each a byte in Range [0,255].
|
|
350
|
+
# """
|
|
351
|
+
for i in range(4):
|
|
352
|
+
_underglowNP[i] = (red, green, blue)
|
|
353
|
+
_underglowNP.show()
|
|
354
|
+
setRGB = fillRGB
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def clearRGB():
|
|
358
|
+
_underglowNP.clear()
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def posRGB(position, red, green, blue):
|
|
362
|
+
# """Uses Neopixel to set a single RGB LED of the robot.
|
|
363
|
+
|
|
364
|
+
# Parameters:
|
|
365
|
+
# position (int): position of the targeted LED.
|
|
366
|
+
# Numbers are visible at underside of Robot.
|
|
367
|
+
# 0=front left
|
|
368
|
+
# 1=back left
|
|
369
|
+
# 2=back right
|
|
370
|
+
# 3=front right
|
|
371
|
+
# red, green, blue (int): color byte value.
|
|
372
|
+
# each in range [0,255].
|
|
373
|
+
|
|
374
|
+
# raises:
|
|
375
|
+
# ValueError: if position argument is out of valid range
|
|
376
|
+
# """
|
|
377
|
+
if position < 0 or position > 3:
|
|
378
|
+
raise ValueError("invalid RGB-LED position. Must be 0,1,2 or 3.")
|
|
379
|
+
_underglowNP[position] = (red, green, blue)
|
|
380
|
+
_underglowNP.show()
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def setAlarm(state):
|
|
384
|
+
# """state: 0=Off, 1=On"""
|
|
385
|
+
if state:
|
|
386
|
+
music.play(_alarmSequence, wait=False, loop=True)
|
|
387
|
+
else:
|
|
388
|
+
music.stop()
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def beep():
|
|
392
|
+
music.pitch(440, 200, wait=False)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
# Default instances
|
|
396
|
+
pin2.set_pull(pin2.NO_PULL)
|
|
397
|
+
delay = sleep
|
|
398
|
+
irLeft = IRSensor(pin13)
|
|
399
|
+
irRight = IRSensor(pin14)
|
|
400
|
+
motL = Motor(0)
|
|
401
|
+
motR = Motor(2)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import gc
|
|
2
|
+
from microbit import i2c, pin1, pin2, pin8, pin12, pin13, pin14, sleep
|
|
3
|
+
import machine
|
|
4
|
+
|
|
5
|
+
_axe = 0.097
|
|
6
|
+
def w(d1, d2, s1, s2):
|
|
7
|
+
try:
|
|
8
|
+
i2c.write(0x10, bytearray([0, d1, s1]))
|
|
9
|
+
i2c.write(0x10, bytearray([2, d2, s2]))
|
|
10
|
+
except:
|
|
11
|
+
print("Please switch on mbRobot!")
|
|
12
|
+
while True:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
def setSpeed(speed):
|
|
16
|
+
global _v
|
|
17
|
+
if speed < 20:
|
|
18
|
+
_v = speed + 5
|
|
19
|
+
else:
|
|
20
|
+
_v = speed
|
|
21
|
+
|
|
22
|
+
def forward():
|
|
23
|
+
w(0, 0, _v, _v)
|
|
24
|
+
|
|
25
|
+
def backward():
|
|
26
|
+
w(1, 1, _v, _v)
|
|
27
|
+
|
|
28
|
+
def stop():
|
|
29
|
+
w(0, 0, 0, 0)
|
|
30
|
+
|
|
31
|
+
def right():
|
|
32
|
+
w(0 if _v > 0 else 1, 1 if _v > 0 else 0, int(_v * 0.9), int(_v * 0.9))
|
|
33
|
+
|
|
34
|
+
def left():
|
|
35
|
+
w(1 if _v > 0 else 0, 0 if _v > 0 else 1, int(_v * 0.9) , int(_v * 0.9))
|
|
36
|
+
|
|
37
|
+
def rightArc(r):
|
|
38
|
+
v = abs(_v)
|
|
39
|
+
if r < _axe:
|
|
40
|
+
v1 = 0
|
|
41
|
+
else:
|
|
42
|
+
f = (r - _axe) / (r + _axe) * (1 - v * v / 200000)
|
|
43
|
+
v1 = int(f * v)
|
|
44
|
+
if _v > 0:
|
|
45
|
+
w(0, 0, v, v1)
|
|
46
|
+
else:
|
|
47
|
+
w(1, 1, v1, v)
|
|
48
|
+
|
|
49
|
+
def leftArc(r):
|
|
50
|
+
v = abs(_v)
|
|
51
|
+
if r < _axe:
|
|
52
|
+
v1 = 0
|
|
53
|
+
else:
|
|
54
|
+
f = (r - _axe) / (r + _axe) * (1 - v * v / 200000)
|
|
55
|
+
v1 = int(f * v)
|
|
56
|
+
if _v > 0:
|
|
57
|
+
w(0, 0, v1, v)
|
|
58
|
+
else:
|
|
59
|
+
w(1, 1, v, v1)
|
|
60
|
+
|
|
61
|
+
exit = stop
|
|
62
|
+
delay = sleep
|
|
63
|
+
|
|
64
|
+
def getDistance():
|
|
65
|
+
pin1.write_digital(1)
|
|
66
|
+
pin1.write_digital(0)
|
|
67
|
+
p = machine.time_pulse_us(pin2, 1, 50000)
|
|
68
|
+
cm = int(p / 58.2 + 0.5)
|
|
69
|
+
return cm if cm > 0 else 255
|
|
70
|
+
|
|
71
|
+
def setLED(on):
|
|
72
|
+
pin8.write_digital(on)
|
|
73
|
+
pin12.write_digital(on)
|
|
74
|
+
|
|
75
|
+
def setServo(S, Angle):
|
|
76
|
+
if S == "S1":
|
|
77
|
+
Servo = 0x14
|
|
78
|
+
if S == "S2":
|
|
79
|
+
Servo = 0x15
|
|
80
|
+
buf = Servo, Angle
|
|
81
|
+
i2c.write(0x10, bytes(buf))
|
|
82
|
+
|
|
83
|
+
pin2.set_pull(pin2.NO_PULL)
|
|
84
|
+
_v = 50 # entspricht default 50
|
|
85
|
+
irLeft = pin13
|
|
86
|
+
irRight = pin14
|
|
87
|
+
ledLeft = pin8
|
|
88
|
+
ledRight = pin12
|
|
89
|
+
|
|
90
|
+
forward()
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# mbrobot_plus.py
|
|
2
|
+
# Version 1.4 (1.10.2022)
|
|
3
|
+
|
|
4
|
+
from microbit import i2c,pin0,pin1,pin2,sleep
|
|
5
|
+
import machine
|
|
6
|
+
import gc
|
|
7
|
+
import music
|
|
8
|
+
|
|
9
|
+
_v = 50
|
|
10
|
+
_axe = 0.082
|
|
11
|
+
|
|
12
|
+
def w(d1, d2, s1, s2):
|
|
13
|
+
try:
|
|
14
|
+
i2c.write(0x10, bytearray([0x00,d1, d2, s1, s2]))
|
|
15
|
+
except:
|
|
16
|
+
print("Please switch on mbRobot!")
|
|
17
|
+
|
|
18
|
+
def setSpeed(speed):
|
|
19
|
+
global _v
|
|
20
|
+
if speed < 30 and speed != 0:
|
|
21
|
+
setPID(1)
|
|
22
|
+
_v = speed + 30
|
|
23
|
+
elif speed >= 30 and speed < 32:
|
|
24
|
+
setPID(0)
|
|
25
|
+
_v = speed + 2
|
|
26
|
+
else:
|
|
27
|
+
setPID(0)
|
|
28
|
+
_v = speed
|
|
29
|
+
|
|
30
|
+
def setPID(pd):
|
|
31
|
+
i2c.write(0x10, bytearray([0x0A, pd]))
|
|
32
|
+
|
|
33
|
+
def stop():
|
|
34
|
+
setPID(0)
|
|
35
|
+
w(0, 0, 0, 0)
|
|
36
|
+
|
|
37
|
+
def resetSpeed():
|
|
38
|
+
setPID(0)
|
|
39
|
+
_v = 50
|
|
40
|
+
|
|
41
|
+
def forward():
|
|
42
|
+
w(1, _v, 1, _v)
|
|
43
|
+
|
|
44
|
+
def backward():
|
|
45
|
+
w(2, _v, 2, _v)
|
|
46
|
+
|
|
47
|
+
def left():
|
|
48
|
+
m = 1.825 -0.0175 * _v
|
|
49
|
+
w(2, int(_v * m), 1, int(_v * m))
|
|
50
|
+
|
|
51
|
+
def right():
|
|
52
|
+
m = 1.825 -0.0175 * _v
|
|
53
|
+
w(1, int(_v * m), 2, int(_v * m))
|
|
54
|
+
|
|
55
|
+
def rightArc(r):
|
|
56
|
+
v = abs(_v)
|
|
57
|
+
if r < _axe:
|
|
58
|
+
v1 = 0
|
|
59
|
+
else:
|
|
60
|
+
f = (r - _axe) / (r + _axe) * (1 - v * v / 200000)
|
|
61
|
+
v1 = int(f * v)
|
|
62
|
+
if _v > 0:
|
|
63
|
+
w(1, v, 1, v1)
|
|
64
|
+
else:
|
|
65
|
+
w(2, v1, 2, v)
|
|
66
|
+
|
|
67
|
+
def leftArc(r):
|
|
68
|
+
v = abs(_v)
|
|
69
|
+
if r < _axe:
|
|
70
|
+
v1 = 0
|
|
71
|
+
else:
|
|
72
|
+
f = (r - _axe) / (r + _axe) * (1 - v * v / 200000)
|
|
73
|
+
v1 = int(f * v)
|
|
74
|
+
if _v > 0:
|
|
75
|
+
w(1, v1, 1, v)
|
|
76
|
+
else:
|
|
77
|
+
w(2, v, 2, v1)
|
|
78
|
+
|
|
79
|
+
def getDistance():
|
|
80
|
+
pin1.write_digital(1)
|
|
81
|
+
pin1.write_digital(0)
|
|
82
|
+
p = machine.time_pulse_us(pin2, 1, 50000)
|
|
83
|
+
cm = int(p / 58.2 - 0.5)
|
|
84
|
+
return cm if cm > 0 else 255
|
|
85
|
+
|
|
86
|
+
class Motor:
|
|
87
|
+
def __init__(self, id):
|
|
88
|
+
self._id = 2 * id
|
|
89
|
+
|
|
90
|
+
def _w(self, d, s):
|
|
91
|
+
try:
|
|
92
|
+
i2c.write(0x10, bytearray([self._id, d, s]))
|
|
93
|
+
except:
|
|
94
|
+
print("Please switch on mbRobot!")
|
|
95
|
+
while True:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
def rotate(self, s):
|
|
99
|
+
p = abs(s)
|
|
100
|
+
if s > 0:
|
|
101
|
+
self._w(1, p)
|
|
102
|
+
elif s < 0:
|
|
103
|
+
self._w(2, p)
|
|
104
|
+
else:
|
|
105
|
+
self._w(0, 0)
|
|
106
|
+
|
|
107
|
+
class LEDState:
|
|
108
|
+
OFF = 0
|
|
109
|
+
RED = 1
|
|
110
|
+
GREEN = 2
|
|
111
|
+
YELLOW = 3
|
|
112
|
+
BLUE = 4
|
|
113
|
+
PINK = 5
|
|
114
|
+
CYAN = 6
|
|
115
|
+
WHITE = 7
|
|
116
|
+
|
|
117
|
+
def setLED(state, stateR=None):
|
|
118
|
+
stateR = stateR or state
|
|
119
|
+
i2c.write(0x10, bytearray([0x0B, state, stateR]))
|
|
120
|
+
|
|
121
|
+
def setLEDLeft(state):
|
|
122
|
+
i2c.write(0x10, bytearray([0x0B, state]))
|
|
123
|
+
|
|
124
|
+
def setLEDRight(state):
|
|
125
|
+
i2c.write(0x10, bytearray([0x0C, state]))
|
|
126
|
+
|
|
127
|
+
def setAlarm(on):
|
|
128
|
+
if on:
|
|
129
|
+
music.play(_m, wait = False, loop = True)
|
|
130
|
+
else:
|
|
131
|
+
music.stop()
|
|
132
|
+
|
|
133
|
+
def beep():
|
|
134
|
+
music.pitch(2000, 200, wait = False)
|
|
135
|
+
|
|
136
|
+
def ir_read_values_as_byte():
|
|
137
|
+
i2c.write(0x10, bytearray([0x1D]))
|
|
138
|
+
buf = i2c.read(0x10, 1)
|
|
139
|
+
return ~buf[0]
|
|
140
|
+
|
|
141
|
+
def setServo(S, Angle):
|
|
142
|
+
if S == "S1":
|
|
143
|
+
Servo = 0x14
|
|
144
|
+
if S == "S2":
|
|
145
|
+
Servo = 0x15
|
|
146
|
+
buf = Servo, Angle
|
|
147
|
+
i2c.write(0x10, bytes(buf))
|
|
148
|
+
|
|
149
|
+
class IR:
|
|
150
|
+
L3 = 0
|
|
151
|
+
L2 = 1
|
|
152
|
+
L1 = 2
|
|
153
|
+
R1 = 3
|
|
154
|
+
R2 = 4
|
|
155
|
+
R3 = 5
|
|
156
|
+
masks = [0x01,0x02,0x04,0x08,0x10,0x20]
|
|
157
|
+
|
|
158
|
+
class IRSensor:
|
|
159
|
+
def __init__(self, index):
|
|
160
|
+
self.index = index
|
|
161
|
+
|
|
162
|
+
def read_digital(self):
|
|
163
|
+
byte = ir_read_values_as_byte()
|
|
164
|
+
return (byte & IR.masks[self.index]) >> self.index
|
|
165
|
+
|
|
166
|
+
irLeft = IRSensor(IR.L1)
|
|
167
|
+
irRight = IRSensor(IR.R1)
|
|
168
|
+
irL1 = IRSensor(IR.L1)
|
|
169
|
+
irR1 = IRSensor(IR.R1)
|
|
170
|
+
irL2 = IRSensor(IR.L2)
|
|
171
|
+
irR2 = IRSensor(IR.R2)
|
|
172
|
+
irL3 = IRSensor(IR.L3)
|
|
173
|
+
irR3 = IRSensor(IR.R3)
|
|
174
|
+
pin2.set_pull(pin2.NO_PULL)
|
|
175
|
+
motL = Motor(0)
|
|
176
|
+
motR = Motor(1)
|
|
177
|
+
delay = sleep
|
|
178
|
+
_m = ['c6:1', 'r', 'c6,1', 'r', 'r', 'r']
|
|
179
|
+
|