4. BitBotXL module
The BitBotXL module is required to control the BitBotXL buggy.
Download the python file
BitBotXL.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 BitBotXL.py file from the right window to the left window to copy it to the microbit.
The images below are for the MOVEmotor, but illustrate the idea.
Before copying:
After copying:
4.1. Use BitBotXL library
To use the BitBotXL module, import it via:
import BitBotXL
.from microbit import *
import BitBotXL
4.2. BitBotXL code
The BitBotXL module is shown below.
1# bitBotXL module for motors, line following and distance sensing
2# requires microbit v2
3# GMC-code; 2022-4
4# The MIT License (MIT)
5
6# A microbit v2 micropython module
7# line sensors use i2c
8# speed from -10 to 10
9
10
11from microbit import *
12import neopixel
13import utime
14
15# constants
16RIGHT_LIGHT_SENSOR_PIN = pin1
17LEFT_LIGHT_SENSOR_PIN = pin2
18DISTANCE_SENSOR_PIN = pin15
19LEFT_FWD_PIN = pin16
20LEFT_BWD_PIN = pin8
21RIGHT_FWD_PIN = pin14
22RIGHT_BWD_PIN = pin12
23LEDS_PIN = pin13
24BUZZER_PIN = pin0
25__I2CADDR = 0x1C # address of PCA9557
26
27leds = neopixel.NeoPixel(LEDS_PIN, 12)
28
29
30class BitBotXLMotors:
31 def __init__(self):
32 # left and right motor adjustments
33 self.dec_left = 1
34 self.dec_right = 1
35
36 def stop_left(self):
37 LEFT_FWD_PIN.write_digital(0)
38 LEFT_BWD_PIN.write_digital(0)
39
40 def stop_right(self):
41 RIGHT_FWD_PIN.write_digital(0)
42 RIGHT_BWD_PIN.write_digital(0)
43
44 def stop(self):
45 self.stop_left()
46 self.stop_right()
47
48 def set_bias_correction(self, direction="left", percent=0):
49 """Set left/right bias to match motors."""
50 factor = (percent + 100) / 100
51 if direction == "left":
52 self.dec_left = factor
53 elif direction == "right":
54 self.dec_right = factor
55
56 @staticmethod
57 def _analog_speed(speed):
58 # input speed = -10 to 0 to 10
59 # output = 0 to 1023
60 if speed < 0 and speed >= -10:
61 return -int((speed * 100) - 23)
62 elif speed > 0 and speed <= 10:
63 return int((speed * 100) + 23)
64 else:
65 return 0
66
67 def left_motor(self, speed=2, duration=None):
68 an_speed = self._analog_speed(speed / self.dec_left)
69 # an_speed = self._analog_speed(speed)
70 # display.scroll(an_speed, delay=60)
71 if speed > 0:
72 LEFT_FWD_PIN.write_analog(an_speed)
73 LEFT_BWD_PIN.write_digital(0)
74 else:
75 LEFT_FWD_PIN.write_digital(0)
76 LEFT_BWD_PIN.write_analog(an_speed)
77 if duration is not None:
78 utime.sleep_ms(duration)
79 self.stop_left()
80
81 def right_motor(self, speed=2, duration=None):
82 an_speed = self._analog_speed(speed / self.dec_right)
83 # an_speed = self._analog_speed(speed)
84 # display.scroll(an_speed, delay=60)
85 if speed > 0:
86 RIGHT_FWD_PIN.write_analog(an_speed)
87 RIGHT_BWD_PIN.write_digital(0)
88 else:
89 RIGHT_FWD_PIN.write_digital(0)
90 RIGHT_BWD_PIN.write_analog(an_speed)
91 if duration is not None:
92 utime.sleep_ms(duration)
93 self.stop_right()
94
95 def forwards(self, speed=2, duration=None):
96 self.right_motor(speed)
97 self.left_motor(speed)
98 if duration is not None:
99 utime.sleep_ms(duration)
100 self.stop()
101
102 def backwards(self, speed=2, duration=None):
103 self.right_motor(-speed)
104 self.left_motor(-speed)
105 if duration is not None:
106 utime.sleep_ms(duration)
107 self.stop()
108
109 @staticmethod
110 def _inner_turn_speed(speed, tightness=2):
111 return speed / tightness
112
113 def left(self, speed=2, tightness=2, duration=None):
114 # right motor faster than left
115 # display.scroll(outer_speed)
116 # display.scroll(tightness)
117 inner_speed = self._inner_turn_speed(speed, tightness)
118 # display.scroll(inner_speed)
119 self.left_motor(inner_speed)
120 self.right_motor(speed)
121 if duration is not None:
122 utime.sleep_ms(duration)
123 self.stop()
124
125 def right(self, speed=2, tightness=2, duration=None):
126 # left motor faster than right
127 inner_speed = self._inner_turn_speed(speed, tightness)
128 self.left_motor(speed)
129 self.right_motor(inner_speed)
130 if duration is not None:
131 utime.sleep_ms(duration)
132 self.stop()
133
134 def spin_left(self, speed=2, duration=None):
135 self.left_motor(-speed)
136 self.right_motor(speed)
137 if duration is not None:
138 utime.sleep_ms(duration)
139 self.stop()
140
141 def spin_right(self, speed=2, duration=None):
142 self.left_motor(speed)
143 self.right_motor(-speed)
144 if duration is not None:
145 utime.sleep_ms(duration)
146 self.stop()
147
148
149class BitBotXLDistanceSensor:
150 def distance(self):
151 DISTANCE_SENSOR_PIN.write_digital(1)
152 utime.sleep_us(10)
153 DISTANCE_SENSOR_PIN.write_digital(0)
154
155 while DISTANCE_SENSOR_PIN.read_digital() == 0:
156 pulse_start = utime.ticks_us()
157 while DISTANCE_SENSOR_PIN.read_digital() == 1:
158 pulse_end = utime.ticks_us()
159
160 pulse_duration = pulse_end - pulse_start
161 distance = int(0.01715 * pulse_duration)
162 return distance
163
164
165class BitBotXLBuzzer:
166 def buzz(self, duration):
167 """Sound a buzz for duration milliseconds."""
168 BUZZER_PIN.write_digital(1)
169 sleep(duration)
170 BUZZER_PIN.write_digital(0)
171
172
173class BitBotXLLineSensor:
174 def linesensor(self, direction):
175 """Read line sensor."""
176
177 dir = direction
178 if dir == "LEFT":
179 return self._getLine(0)
180 elif dir == "RIGHT":
181 return self._getLine(1)
182
183 def _getLine(self, bit):
184 """Reads value of left or right line sensor."""
185
186 mask = 1 << bit
187 value = 0
188 try:
189 value = i2c.read(__I2CADDR, 1)[0]
190 except OSError:
191 pass
192 if (value & mask) > 0:
193 return 1
194 else:
195 return 0