├── LICENSE ├── README.md ├── kitronik-reference-file-robotics-TOO-LARGE.py └── robotics.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kitronik Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # micropython-microbit-kitronik-robotics 2 | Example MicroPython (for BBC micro:bit) code for the Kitronik All-in-one Robotics Board ( www.kitronik.co.uk/5641 ) 3 | 4 | ## Note: 5 | There are 2 python files in this repo. The one which is named: kitronik-reference-file-robotics-TOO-LARGE.py contains explanatory comments, which increase the file size. This makes it too large to run on a micro:bit. The other file (robotics.py) contains the same code, but without the large comments. This enables the file to function in the limited footprint available. 6 | 7 | ## Motors 8 | 9 | This package contains a function for driving standard motors forwards and backwards, with a speed setting of 0-100%: 10 | ```blocks 11 | KitronikRoboticsBoard.motorOn(KitronikRoboticsBoard, 3, "forward", 10) 12 | KitronikRoboticsBoard.motorOn(KitronikRoboticsBoard, 4, "reverse", 100) 13 | ``` 14 | There are also functions for driving stepper motors forwards and backwards by either a set number of steps, or to an angle relative to the start position: 15 | ```blocks 16 | KitronikRoboticsBoard.stepperMotorTurnAngle(KitronikRoboticsBoard, "Stepper1", "forward", 180) 17 | KitronikRoboticsBoard.stepperMotorTurnSteps(KitronikRoboticsBoard, "Stepper1", "reverse", 100) 18 | ``` 19 | Individual motor outputs can also be turned off: 20 | ```blocks 21 | KitronikRoboticsBoard.motorOff(KitronikRoboticsBoard, 3) 22 | ``` 23 | 24 | ## Servos 25 | 26 | This package contains a function for driving both 180 and continuous rotation servos, with the ability to set the drive angle between 0 and 180 degrees: 27 | ```blocks 28 | KitronikRoboticsBoard.servoWrite(KitronikRoboticsBoard, 4, 180) 29 | KitronikRoboticsBoard.servoWrite(KitronikRoboticsBoard, 5, 0) 30 | ``` 31 | (Note: For continuous rotation servos, setting the drive angle to 0 will turn the servo at max speed in one direction, and setting it to 180 will turn it at max speed in the other direction) 32 | 33 | ## Other 34 | 35 | This package also contains an 'emergency stop' function which turns off all motor and all servo outputs at the same time: 36 | ```blocks 37 | KitronikRoboticsBoard.allOff(KitronikRoboticsBoard) 38 | ``` 39 | 40 | ## License 41 | 42 | MIT 43 | 44 | ## Supported Targets 45 | 46 | BBC micro:bit 47 | -------------------------------------------------------------------------------- /kitronik-reference-file-robotics-TOO-LARGE.py: -------------------------------------------------------------------------------- 1 | ######################################## 2 | ## ## 3 | ## THIS FILE IS FOR REFERENCE ONLY ## 4 | ## USE OF COMMENTS MAKES FILE TOO BIG ## 5 | ## FOR UPLOADING TO BBC MICROBIT ## 6 | ## USE 'robotics.py' FOR ACTUAL USE ## 7 | ## ## 8 | ######################################## 9 | from microbit import * 10 | #Class for driving the Kitronik All-in-one Robotics Board 11 | class KitronikRoboticsBoard: 12 | PRESCALE_REG = 0xFE #The prescale register address 13 | MODE_1_REG = 0x00 #The mode 1 register address 14 | # If you wanted to write some code that stepped through 15 | # the servos or motors then this is the Base and size to do that 16 | SRV_REG_BASE = 0x08 17 | MOT_REG_BASE = 0x28 18 | REG_OFFSET = 4 19 | # To get the PWM pulses to the correct size and zero 20 | # offset these are the default numbers. 21 | SERVO_MULTIPLIER = 226 22 | SERVO_ZERO_OFFSET = 0x66 23 | 24 | #The Robotics board can be configured to use different I2C addresses: 0x6C, 0x6D, 0x6E, 0x6F. 25 | #0x6C is the default value for the All-in-one Robotics Board (set as the chipAddress) 26 | chipAddress = 0x6C 27 | #A flag to allow us to initialise without explicitly calling the secret incantation 28 | initialised = False 29 | #a flag to establish whether a stepper motor call has been made before 30 | stepInit = False 31 | #Initialise stepStage, used along with stepInit for initialising the stepper motor function 32 | stepStage = 0 33 | stepper1Steps = 200 #Default value for the majority of stepper motors; can be altered if neccessary for a particular stepper motor 34 | stepper2Steps = 200 #Default value for the majority of stepper motors; can be altered if neccessary for a particular stepper motor 35 | 36 | #This initialisation function sets up the PCA9865 I2C driver chip to be running at 50Hz pulse repetition, and then sets the 16 output registers 0. 37 | #It should not need to be called directly be a user - the first servo or motor write will call it automatically. 38 | def __init(self): 39 | 40 | buf = bytearray(2) 41 | 42 | #First set the prescaler to 50 hz 43 | buf[0] = self.PRESCALE_REG 44 | buf[1] = 0x7D #50Hz 45 | i2c.write(self.chipAddress, buf, False) 46 | #Block write via the all leds register to turn off all outputs 47 | 48 | for blockReg in range(0xFA, 0xFE, 1): 49 | buf[0] = blockReg 50 | buf[1] = 0x00 51 | i2c.write(self.chipAddress, buf, False) 52 | #Set the mode 1 register to come out of sleep 53 | buf[0] = self.MODE_1_REG 54 | buf[1] = 0x01 55 | i2c.write(self.chipAddress, buf, False) 56 | #set the initalised flag so we dont come in here again automatically 57 | self.initialised = True 58 | 59 | #sets the requested servo to the reguested angle. 60 | #if the PCA has not yet been setup calls the initialisation routine 61 | def servoWrite(self, servo, degrees): 62 | if self.initialised is False: 63 | self.__init(self) 64 | buf = bytearray(2) 65 | calcServo = self.SRV_REG_BASE + ((servo - 1) * self.REG_OFFSET) 66 | HighByte = False 67 | PWMVal = (degrees * 100 * self.SERVO_MULTIPLIER) / (10000 + self.SERVO_ZERO_OFFSET) 68 | 69 | if (PWMVal > 0xFF): 70 | HighByte = True 71 | buf[0] = calcServo 72 | buf[1] = int(PWMVal) 73 | i2c.write(self.chipAddress, buf, False) 74 | buf[0] = calcServo + 1 75 | if (HighByte): 76 | buf[1] = 0x01 77 | else: 78 | buf[1] = 0x00 79 | i2c.write(self.chipAddress, buf, False) 80 | 81 | #Function to set the requested motor running in chosen direction at a set speed. 82 | #if the PCA chip has not yet been initialised calls the initialisation routine. 83 | def motorOn(self, motor, direction, speed): 84 | if self.initialised is False: 85 | self.__init(self) 86 | buf = bytearray(2) 87 | motorReg = self.MOT_REG_BASE + (2 * (motor - 1) * self.REG_OFFSET) 88 | HighByte = False 89 | OutputVal = speed * 40 90 | 91 | if direction == "forward": 92 | if OutputVal > 0xFF: 93 | HighByte = True 94 | HighOutputVal = int(OutputVal/256) 95 | buf[0] = motorReg 96 | buf[1] = int(OutputVal) 97 | i2c.write(self.chipAddress, buf, False) 98 | buf[0] = motorReg + 1 99 | if HighByte: 100 | buf[1] = HighOutputVal 101 | else: 102 | buf[1] = 0x00 103 | i2c.write(self.chipAddress, buf, False) 104 | 105 | for offset in range(4, 6, 1): 106 | buf[0] = motorReg + offset 107 | buf[1] = 0x00 108 | i2c.write(self.chipAddress, buf, False) 109 | 110 | elif direction == "reverse": 111 | if OutputVal > 0xFF: 112 | HighByte = True 113 | HighOutputVal = int(OutputVal/256) 114 | buf[0] = motorReg + 4 115 | buf[1] = int(OutputVal) 116 | i2c.write(self.chipAddress, buf, False) 117 | buf[0] = motorReg + 5 118 | if HighByte: 119 | buf[1] = HighOutputVal 120 | else: 121 | buf[1] = 0x00 122 | i2c.write(self.chipAddress, buf, False) 123 | 124 | for offset2 in range(0, 2, 1): 125 | buf[0] = motorReg + offset2 126 | buf[1] = 0x00 127 | i2c.write(self.chipAddress, buf, False) 128 | 129 | #Function to turn off the specified motor. 130 | def motorOff(self, motor): 131 | buf = bytearray(2) 132 | motorReg = self.MOT_REG_BASE + (2 * (motor - 1) * self.REG_OFFSET) 133 | 134 | for offset3 in range(0, 2, 1): 135 | buf[0] = motorReg + offset3 136 | buf[1] = 0x00 137 | i2c.write(self.chipAddress, buf, False) 138 | 139 | for offset4 in range(4, 6, 1): 140 | buf[0] = motorReg + offset4 141 | buf[1] = 0x00 142 | i2c.write(self.chipAddress, buf, False) 143 | 144 | #Function to turn off all motors and servos. 145 | def allOff(self): 146 | buf = bytearray(2) 147 | servoOffCount = 0 148 | servoRegCount = 0 149 | 150 | for motors in range(1, 5, 1): 151 | self.motorOff(self, motors) 152 | 153 | while servoOffCount < 8: 154 | for offset5 in range(0, 2, 1): 155 | buf[0] = self.SRV_REG_BASE + servoRegCount + offset5 156 | buf[1] = 0x00 157 | i2c.write(self.chipAddress, buf, False) 158 | 159 | servoRegCount += 4 160 | servoOffCount += 1 161 | 162 | #Sets the requested stepper motor to a chosen angle relative to the start position. 163 | #if the PCA chip has not yet been initialised calls the initialisation routine. 164 | def stepperMotorTurnAngle(self, stepper, direction, angle): 165 | angleToSteps = 0 166 | 167 | if self.initialised is False: 168 | self.__init(self) 169 | 170 | #convert angle to motor steps, depends on which stepper is being turned to set the number of steps for a full rotation 171 | if stepper == "Stepper1": 172 | angleToSteps = ((angle - 1) * (self.stepper1Steps - 1)) / (360 - 1) + 1 173 | else: 174 | angleToSteps = ((angle - 1) * (self.stepper2Steps - 1)) / (360 - 1) + 1 175 | 176 | angleToSteps = int(angleToSteps) 177 | self._turnStepperMotor(self, stepper, direction, angleToSteps) 178 | 179 | #Sets the requested stepper motor to turn a set number of steps. 180 | #if the PCA chip has not yet been initialised calls the initialisation routine. 181 | def stepperMotorTurnSteps(self, stepper, direction, stepperSteps): 182 | if self.initialised is False: 183 | self.__init(self) 184 | 185 | self._turnStepperMotor(self, stepper, direction, stepperSteps) 186 | 187 | #The function called to actually turn the stepper motor a set number of steps 188 | #This function uses a finite state machine (stepStage) to set each motor output to energise the coils of the stepper motor 189 | #in the correct sequence in order to continuously drive the stepper motor in a set direction 190 | #Each stepStage value (1-4) corresponds to particular motor outputs and directions being active (for either stepper output) 191 | def _turnStepperMotor(self, stepper, direction, steps): 192 | stepCounter = 0 193 | #This sets stepStage to 1 the FIRST time _turnStepperMotor is called - every other time it will 'remember' the previous position 194 | if self.stepInit is False: 195 | self.stepStage = 1 #stepStage determines which coils in the stepper motor will be energised (order is very important to ensure actual turning) 196 | self.stepInit = True 197 | 198 | #Loop to run until the number of motor steps set by the user is reached 199 | while stepCounter < steps: 200 | #This section uses the current stepStage and user selected Stepper motor to set which Robotics Board motor Output Address should be used 201 | if stepStage == 1 or stepStage == 3: 202 | if stepper == "Stepper1": 203 | currentMotor = 1 204 | else: 205 | currentMotor = 3 206 | else: 207 | if stepper == "Stepper1": 208 | currentMotor = 2 209 | else: 210 | currentMotor = 4 211 | 212 | #This section uses the current stepStage to set which direction the Robotics Board motor Output should be driven 213 | if stepStage == 1 or stepStage == 4: 214 | currentDirection = "forward" 215 | else: 216 | currentDirection = "reverse" 217 | 218 | #Function call for the Robotics Board motor drive with the previously set currentmotor and currentDirection 219 | self.motorOn(self, currentMotor, currentDirection, 100) 220 | sleep(20) 221 | 222 | #This section progresses the stepStage depending on the user selected Stepper motor direction and previous stepStage 223 | if direction == "forward": 224 | if stepStage == 4: 225 | stepStage = 1 226 | else: 227 | stepStage += 1 228 | elif direction == "reverse": 229 | if stepStage == 1: 230 | stepStage = 4 231 | else: 232 | stepStage -= 1 233 | 234 | stepCounter += 1 235 | 236 | #Test program will run forever 237 | #On pressing button A on the micro:bit: 238 | # A stepper motor connected to motor outputs 1 & 2 will turn 180 degrees 239 | # Motors connected to outputs 3 & 4 will turn in opposite directions at different speeds 240 | # 4 servos will turn one direction, 4 will turn the other 241 | #On pressing button B on the micro:bit: 242 | # A stepper motor connected to motor outputs 1 & 2 will turn 100 steps in the opposite direction to button A 243 | # Motors connected to outputs 3 & 4 will turn off 244 | # 8 servos will set to the 90 degree position 245 | #On pressing button A+B on the micro:bit: 246 | # All motor and servo outputs will be turned off 247 | while True: 248 | theBoard = KitronikRoboticsBoard 249 | if button_a.is_pressed(): 250 | theBoard.stepperMotorTurnAngle(theBoard, "Stepper1", "forward", 180) 251 | theBoard.motorOn(theBoard, 3, "forward", 10) 252 | theBoard.motorOn(theBoard, 4, "reverse", 100) 253 | theBoard.servoWrite(theBoard, 1, 180) 254 | theBoard.servoWrite(theBoard, 2, 180) 255 | theBoard.servoWrite(theBoard, 3, 180) 256 | theBoard.servoWrite(theBoard, 4, 180) 257 | theBoard.servoWrite(theBoard, 5, 0) 258 | theBoard.servoWrite(theBoard, 6, 0) 259 | theBoard.servoWrite(theBoard, 7, 0) 260 | theBoard.servoWrite(theBoard, 8, 0) 261 | if button_b.is_pressed(): 262 | theBoard.stepperMotorTurnSteps(theBoard, "Stepper1", "reverse", 100) 263 | theBoard.motorOff(theBoard, 3) 264 | theBoard.motorOff(theBoard, 4) 265 | theBoard.servoWrite(theBoard, 1, 90) 266 | theBoard.servoWrite(theBoard, 2, 90) 267 | theBoard.servoWrite(theBoard, 3, 90) 268 | theBoard.servoWrite(theBoard, 4, 90) 269 | theBoard.servoWrite(theBoard, 5, 90) 270 | theBoard.servoWrite(theBoard, 6, 90) 271 | theBoard.servoWrite(theBoard, 7, 90) 272 | theBoard.servoWrite(theBoard, 8, 90) 273 | if button_a.is_pressed() and button_b.is_pressed(): 274 | theBoard.allOff(theBoard) 275 | -------------------------------------------------------------------------------- /robotics.py: -------------------------------------------------------------------------------- 1 | # microbit-module: KitronikRoboticsBoard@1.0.0 2 | # Copyright (c) Kitronik Ltd 2022. 3 | # 4 | # The MIT License (MIT) 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | from microbit import * 24 | 25 | class KitronikRoboticsBoard: 26 | PRESCALE_REG = 0xFE 27 | MODE_1_REG = 0x00 28 | SRV_REG_BASE = 0x08 29 | MOT_REG_BASE = 0x28 30 | REG_OFFSET = 4 31 | SERVO_MULTIPLIER = 226 32 | SERVO_ZERO_OFFSET = 0x66 33 | 34 | chipAddress = 0x6C 35 | initialised = False 36 | stepInit = False 37 | stepStage = 0 38 | stepper1Steps = 200 39 | stepper2Steps = 200 40 | 41 | def __init__(self): 42 | buf = bytearray(2) 43 | buf[0] = self.PRESCALE_REG 44 | buf[1] = 0x7D #50Hz 45 | i2c.write(self.chipAddress, buf, False) 46 | 47 | for blockReg in range(0xFA, 0xFE, 1): 48 | buf[0] = blockReg 49 | buf[1] = 0x00 50 | i2c.write(self.chipAddress, buf, False) 51 | 52 | buf[0] = self.MODE_1_REG 53 | buf[1] = 0x01 54 | i2c.write(self.chipAddress, buf, False) 55 | 56 | def servoWrite(self, servo, degrees): 57 | buf = bytearray(2) 58 | calcServo = self.SRV_REG_BASE + ((servo - 1) * self.REG_OFFSET) 59 | HighByte = False 60 | PWMVal = degrees * 100 * self.SERVO_MULTIPLIER 61 | PWMVal /= 10000 62 | PWMVal += self.SERVO_ZERO_OFFSET 63 | 64 | if (PWMVal > 0xFF): 65 | HighByte = True 66 | 67 | buf[0] = calcServo 68 | buf[1] = int(PWMVal) 69 | i2c.write(self.chipAddress, buf, False) 70 | buf[0] = calcServo + 1 71 | 72 | if (HighByte): 73 | buf[1] = 0x01 74 | else: 75 | buf[1] = 0x00 76 | 77 | i2c.write(self.chipAddress, buf, False) 78 | 79 | def motorOn(self, motor, direction, speed): 80 | buf = bytearray(2) 81 | motorReg = self.MOT_REG_BASE + (2 * (motor - 1) * self.REG_OFFSET) 82 | HighByte = False 83 | OutputVal = speed * 40 84 | HighOutputVal = 0 85 | 86 | if direction == "forward": 87 | if OutputVal > 0xFF: 88 | HighByte = True 89 | HighOutputVal = int(OutputVal / 256) 90 | 91 | buf[0] = motorReg 92 | buf[1] = int(OutputVal) 93 | i2c.write(self.chipAddress, buf, False) 94 | buf[0] = motorReg + 1 95 | 96 | if HighByte: 97 | buf[1] = HighOutputVal 98 | else: 99 | buf[1] = 0x00 100 | 101 | i2c.write(self.chipAddress, buf, False) 102 | 103 | for offset in range(4, 6, 1): 104 | buf[0] = motorReg + offset 105 | buf[1] = 0x00 106 | i2c.write(self.chipAddress, buf, False) 107 | 108 | elif direction == "reverse": 109 | if OutputVal > 0xFF: 110 | HighByte = True 111 | HighOutputVal = int(OutputVal/256) 112 | 113 | buf[0] = motorReg + 4 114 | buf[1] = int(OutputVal) 115 | i2c.write(self.chipAddress, buf, False) 116 | buf[0] = motorReg + 5 117 | 118 | if HighByte: 119 | buf[1] = HighOutputVal 120 | else: 121 | buf[1] = 0x00 122 | 123 | i2c.write(self.chipAddress, buf, False) 124 | 125 | for offset2 in range(0, 2, 1): 126 | buf[0] = motorReg + offset2 127 | buf[1] = 0x00 128 | i2c.write(self.chipAddress, buf, False) 129 | 130 | def motorOff(self, motor): 131 | buf = bytearray(2) 132 | motorReg = self.MOT_REG_BASE + (2 * (motor - 1) * self.REG_OFFSET) 133 | 134 | for offset3 in range(0, 2, 1): 135 | buf[0] = motorReg + offset3 136 | buf[1] = 0x00 137 | i2c.write(self.chipAddress, buf, False) 138 | 139 | for offset4 in range(4, 6, 1): 140 | buf[0] = motorReg + offset4 141 | buf[1] = 0x00 142 | i2c.write(self.chipAddress, buf, False) 143 | 144 | def allOff(self): 145 | buf = bytearray(2) 146 | servoOffCount = 0 147 | servoRegCount = 0 148 | 149 | for motors in range(1, 5, 1): 150 | self.motorOff(motors) 151 | 152 | while servoOffCount < 8: 153 | for offset5 in range(0, 2, 1): 154 | buf[0] = self.SRV_REG_BASE + servoRegCount + offset5 155 | buf[1] = 0x00 156 | i2c.write(self.chipAddress, buf, False) 157 | 158 | servoRegCount += 4 159 | servoOffCount += 1 160 | 161 | def stepperMotorTurnAngle(self, stepper, direction, angle): 162 | angleToSteps = 0 163 | 164 | if stepper == "Stepper1": 165 | angleToSteps = ((angle - 1) * (self.stepper1Steps - 1)) / (360 - 1) + 1 166 | else: 167 | angleToSteps = ((angle - 1) * (self.stepper2Steps - 1)) / (360 - 1) + 1 168 | 169 | angleToSteps = int(angleToSteps) 170 | self._turnStepperMotor(stepper, direction, angleToSteps) 171 | 172 | def stepperMotorTurnSteps(self, stepper, direction, stepperSteps): 173 | self._turnStepperMotor(stepper, direction, stepperSteps) 174 | 175 | def _turnStepperMotor(self, stepper, direction, steps): 176 | stepCounter = 0 177 | 178 | if self.stepInit is False: 179 | self.stepStage = 1 180 | self.stepInit = True 181 | 182 | while stepCounter < steps: 183 | if self.stepStage == 1 or self.stepStage == 3: 184 | if stepper == "Stepper1": 185 | currentMotor = 1 186 | else: 187 | currentMotor = 3 188 | else: 189 | if stepper == "Stepper1": 190 | currentMotor = 2 191 | else: 192 | currentMotor = 4 193 | 194 | if self.stepStage == 1 or self.stepStage == 4: 195 | currentDirection = "forward" 196 | else: 197 | currentDirection = "reverse" 198 | 199 | self.motorOn(currentMotor, currentDirection, 100) 200 | sleep(20) 201 | 202 | if direction == "forward": 203 | if self.stepStage == 4: 204 | self.stepStage = 1 205 | else: 206 | self.stepStage += 1 207 | elif direction == "reverse": 208 | if self.stepStage == 1: 209 | self.stepStage = 4 210 | else: 211 | self.stepStage -= 1 212 | 213 | stepCounter += 1 214 | 215 | theBoard = KitronikRoboticsBoard() 216 | 217 | while True: 218 | if button_a.is_pressed(): 219 | theBoard.stepperMotorTurnAngle("Stepper1", "forward", 180) 220 | theBoard.motorOn(3, "forward", 10) 221 | theBoard.motorOn(4, "reverse", 100) 222 | 223 | for servo in range(8): 224 | theBoard.servoWrite(servo, 0) 225 | 226 | if button_b.is_pressed(): 227 | theBoard.stepperMotorTurnSteps("Stepper1", "reverse", 100) 228 | theBoard.motorOff(3) 229 | theBoard.motorOff(4) 230 | 231 | for servo in range(8): 232 | theBoard.servoWrite(servo, 180) 233 | 234 | if button_a.is_pressed() and button_b.is_pressed(): 235 | theBoard.allOff() 236 | 237 | sleep(100) 238 | --------------------------------------------------------------------------------