2. Maqueen module

The maqueen module is required to control the Maqueen buggy.
Download the python file maqueen.py module.
Place it in the mu_code folder: C:\Users\username\mu_code
The file needs to be copied onto the microbit.
In Mu editor, with the microbit attached by USB, click the Files icon.
Files on the microbit are shown on the left.
Files in the mu_code folder are listed on the right.
Click and drag the maqueen.py file from the right window to the left window to copy it to the microbit.
The images below are for the maqueen, but illustrate the idea.
Before copying:
../../_images/Mu_files1.png

After copying:

../../_images/Mu_files_copied1.png

2.1. Use Maqueen library

To use the maqueen module, import it via: import maqueen.
from microbit import *
import maqueen

2.2. Maqueen code

The Maqueen module is shown below.
  1# maqueen module for motors, line following and distance sensing
  2# requires microbit v2
  3# GMC-code; 2022-4
  4# The MIT License (MIT)
  5# motor uses i2c
  6# motor speeds from 0,1,2,3,4,5
  7# turn tightness from 5,4,3,2,1
  8# 5 being tightest without spinning by reversing other wheel
  9
 10from microbit import *
 11import machine
 12import utime
 13from neopixel import NeoPixel as leds
 14
 15
 16CHIP_ADDR = 0x10
 17LEFT_MOTOR = 0x00
 18RIGHT_MOTOR = 0x02
 19FORWARD = 0x00
 20BACKWARD = 0x01
 21SERVO_ONE = 0x14
 22SERVO_TWO = 0x15
 23
 24TRIGGER_PIN = pin1
 25ECHO_PIN = pin2
 26LEFT_HEADLIGHT_PIN = pin8
 27RIGHT_HEADLIGHT_PIN = pin12
 28LEFT_LINE_SENSOR_PIN = pin13
 29RIGHT_LINE_SENSOR_PIN = pin14	
 30IR_PIN = pin16
 31
 32MOTOR_SPEEDS = [0, 20, 25, 30, 60, 255]
 33MPC = len(MOTOR_SPEEDS) - 1  # Motor speed count used for tightness of turns
 34
 35
 36class MaqueenMotors:
 37
 38    def stop_left(self):
 39        buffer = bytearray(3)
 40        buffer[0] = LEFT_MOTOR
 41        buffer[1] = FORWARD
 42        buffer[2] = 0
 43        i2c.write(CHIP_ADDR, buffer, False)
 44
 45    def stop_right(self):
 46        buffer = bytearray(3)
 47        buffer[0] = RIGHT_MOTOR
 48        buffer[1] = FORWARD
 49        buffer[2] = 0
 50        i2c.write(CHIP_ADDR, buffer, False)
 51
 52    def stop(self):
 53        self.stop_left()
 54        self.stop_right()
 55
 56    @staticmethod
 57    def _analog_speed(self, speed):
 58        if speed < -MPC:
 59            return -MOTOR_SPEEDS[MPC]
 60        elif speed < 0 and speed >= -MPC:
 61            return -MOTOR_SPEEDS[abs(int(speed))]
 62        elif speed > 0 and speed <= MPC:
 63            return MOTOR_SPEEDS[int(speed)]
 64        elif speed > MPC:
 65            return MOTOR_SPEEDS[MPC]
 66        else:
 67            return 0
 68
 69    def left_motor(self, speed=1, duration=None):
 70        buffer = bytearray(3)
 71        buffer[0] = LEFT_MOTOR
 72        if (speed > 0):
 73            buffer[1] = FORWARD
 74        else:
 75            buffer[1] = BACKWARD
 76        buffer[2] = abs(self._analog_speed(self, speed))
 77        i2c.write(CHIP_ADDR, buffer, False)
 78        if duration is not None:
 79            utime.sleep_ms(duration)
 80            self.stop_left()
 81
 82    def right_motor(self, speed=1, duration=None):
 83        buffer = bytearray(3)
 84        buffer[0] = RIGHT_MOTOR
 85        if (speed > 0):
 86            buffer[1] = FORWARD
 87        else:
 88            buffer[1] = BACKWARD
 89        buffer[2] = abs(self._analog_speed(self, speed))
 90        i2c.write(CHIP_ADDR, buffer, False)
 91        if duration is not None:
 92            utime.sleep_ms(duration)
 93            self.stop_right()
 94
 95    def backwards(self, speed=1, duration=None):
 96        analog_speed = abs(self._analog_speed(self, speed))
 97        buffer = bytearray(3)
 98        buffer[0] = LEFT_MOTOR
 99        buffer[1] = BACKWARD
100        buffer[2] = analog_speed
101        i2c.write(CHIP_ADDR, buffer, False)
102        buffer = bytearray(3)
103        buffer[0] = RIGHT_MOTOR
104        buffer[1] = BACKWARD
105        buffer[2] = analog_speed
106        i2c.write(CHIP_ADDR, buffer, False)
107        if duration is not None:
108            utime.sleep_ms(duration)
109            self.stop()
110
111    def forwards(self, speed=1, duration=None):
112        analog_speed = abs(self._analog_speed(self, speed))
113        buffer = bytearray(3)
114        buffer[0] = LEFT_MOTOR
115        buffer[1] = FORWARD
116        buffer[2] = analog_speed
117        i2c.write(CHIP_ADDR, buffer, False)
118        buffer = bytearray(3)
119        buffer[0] = RIGHT_MOTOR
120        buffer[1] = FORWARD
121        buffer[2] = analog_speed
122        i2c.write(CHIP_ADDR, buffer, False)
123        if duration is not None:
124            utime.sleep_ms(duration)
125            self.stop()
126
127    @staticmethod
128    def _inner_turn_speed(self, tightness=MPC):
129        return MOTOR_SPEEDS[MPC - tightness]
130
131    def left(self, tightness=MPC, duration=None):
132        # right motor faster than left
133        inner_turn_speed = self._inner_turn_speed(self, tightness)
134        buffer = bytearray(3)
135        buffer[0] = LEFT_MOTOR
136        buffer[1] = FORWARD
137        buffer[2] = inner_turn_speed
138        i2c.write(CHIP_ADDR, buffer, False)
139        utime.sleep_ms(2)
140        buffer = bytearray(3)
141        buffer[0] = RIGHT_MOTOR
142        buffer[1] = FORWARD
143        buffer[2] = 255
144        i2c.write(CHIP_ADDR, buffer, False)
145        if duration is not None:
146            utime.sleep_ms(duration)
147            self.stop()
148
149    def right(self, tightness=MPC, duration=None):
150        # left motor faster than right
151        inner_turn_speed = self._inner_turn_speed(self, tightness)
152        buffer = bytearray(3)
153        buffer[0] = LEFT_MOTOR
154        buffer[1] = FORWARD
155        buffer[2] = 255
156        i2c.write(CHIP_ADDR, buffer, False)
157        utime.sleep_ms(2)
158        buffer = bytearray(3)
159        buffer[0] = RIGHT_MOTOR
160        buffer[1] = FORWARD
161        buffer[2] = inner_turn_speed
162        i2c.write(CHIP_ADDR, buffer, False)
163        if duration is not None:
164            utime.sleep_ms(duration)
165            self.stop()
166
167    def spin_left(self, speed=1, duration=None):
168        analog_speed = abs(self._analog_speed(self, speed))
169        buffer = bytearray(3)
170        buffer[0] = LEFT_MOTOR
171        buffer[1] = BACKWARD
172        buffer[2] = analog_speed
173        i2c.write(CHIP_ADDR, buffer, False)
174        buffer[0] = RIGHT_MOTOR
175        buffer[1] = FORWARD
176        buffer[2] = analog_speed
177        i2c.write(CHIP_ADDR, buffer, False)
178        if duration is not None:
179            utime.sleep_ms(duration)
180            self.stop()
181
182    def spin_right(self, speed=1, duration=None):
183        analog_speed = abs(self._analog_speed(self, speed))
184        buffer = bytearray(3)
185        buffer[0] = LEFT_MOTOR
186        buffer[1] = FORWARD
187        buffer[2] = analog_speed
188        i2c.write(CHIP_ADDR, buffer, False)
189        buffer[0] = RIGHT_MOTOR
190        buffer[1] = BACKWARD
191        buffer[2] = analog_speed
192        i2c.write(CHIP_ADDR, buffer, False)
193        if duration is not None:
194            utime.sleep_ms(duration)
195            self.stop()
196
197    # angle: {0-180}
198    def servo_one(self, angle=0):
199        buffer = bytearray(2)
200        buffer[0] = SERVO_ONE
201        buffer[1] = angle
202        i2c.write(CHIP_ADDR, buffer, False)
203
204    # angle: {0-180}
205    def servo_two(self, angle=0):
206        buffer = bytearray(2)
207        buffer[0] = SERVO_TWO
208        buffer[1] = angle
209        i2c.write(CHIP_ADDR, buffer, False)
210
211
212class MaqueenLineSensors:
213
214    def line_sensor_read(self, sensor):
215        if sensor == 'left':
216            return LEFT_LINE_SENSOR_PIN.read_digital()
217        elif sensor == 'right':
218            return RIGHT_LINE_SENSOR_PIN.read_digital()
219
220
221class MaqueenDistanceSensor:
222
223    def distance(self):
224        ECHO_PIN.set_pull(ECHO_PIN.NO_PULL)
225        TRIGGER_PIN.write_digital(0)
226        utime.sleep_us(2)
227        TRIGGER_PIN.write_digital(1)
228        utime.sleep_us(10)
229        TRIGGER_PIN.write_digital(0)
230        distance = machine.time_pulse_us(ECHO_PIN, 1, 1160000)
231        if distance > 0:
232            # distance in cm
233            return round(distance/58)
234        else:
235            return 0
236
237
238class MaqueenIR:
239
240    def get_IR(self):
241        IR_PIN.set_pull(IR_PIN.PullUp)
242
243
244class MaqueenHeadLights:
245
246    def set_headlight(self, headlight='left', on=1):
247        # value = 1 for on and 0 for off
248        if headlight == 'left':
249            if on == 1:
250                LEFT_HEADLIGHT_PIN.write_digital(1)
251            else:
252                LEFT_HEADLIGHT_PIN.write_digital(0)
253        elif headlight == 'right':
254            if on == 1:
255                RIGHT_HEADLIGHT_PIN .write_digital(1)
256            else:
257                RIGHT_HEADLIGHT_PIN .write_digital(0)
258
259    def set_headlights(self, left=1, right=1):
260        # value = 1 for on and 0 for off
261        LEFT_HEADLIGHT_PIN.write_digital(left)
262        RIGHT_HEADLIGHT_PIN .write_digital(right)
263
264
265class MaqueenNeoPixels:
266
267    def __init__(self, front=(20, 20, 20), indicator=(35, 25, 0), rear=(20, 0, 0)):
268        self.np = leds(pin15, 4)
269        self.front = front
270        self.indicator = indicator
271        self.rear = rear
272
273    # rgb: (red: {0-255}, green: {0-255}, blue: {0-255})
274    # front left = 0; rear left = 1; rear right = 2; front right = 3
275
276    def set_front(self, rgb=(20, 20, 20)):
277        self.front = rgb
278
279    def set_indicator(self, rgb=(35, 25, 0)):
280        self.indicator = rgb
281
282    def set_rear(self, rgb=(20, 0, 0)):
283        self.rear = rgb
284
285    def set_led(self, led_number, rgb=(20, 20, 20)):
286        self.np[led_number] = rgb
287        self.np.show()
288
289    def set_leds(self, rgb=(20, 20, 20)):
290        for led_number in range(4):
291            self.np[led_number] = rgb
292        self.np.show()
293
294    def rear_lights(self):
295        self.np[1] = self.rear
296        self.np[2] = self.rear
297
298    def all_lights(self, left, right):
299        self.np[0] = left
300        self.np[3] = right
301        self.rear_lights()
302        self.np.show()
303
304    def front_lights(self):
305        self.all_lights(self.front, self.front)
306
307    def left_indicator(self):
308        self.all_lights(self.indicator, self.front)
309
310    def right_indicator(self):
311        self.all_lights(self.front, self.indicator)
312
313    def both_indicators(self):
314        self.all_lights(self.indicator, self.indicator)
315