|
| 1 | +# Pimoroni Inventor 2040/2350 W - Library Reference <!-- omit in toc --> |
| 2 | + |
| 3 | +This is the library reference for the [Pimoroni Inventor 2040/2350 W](https://shop.pimoroni.com/products/inventor-2350-w), an all-in-one board for making battery powered contraptions that can move, (optionally) make noise, and talk to the internet! |
| 4 | + |
| 5 | +## Table of Content <!-- omit in toc --> |
| 6 | +- [Getting Started](#getting-started) |
| 7 | + - [Different Gear Ratio](#different-gear-ratio) |
| 8 | + - [What Gets Initialised](#what-gets-initialised) |
| 9 | +- [Reading the User Button](#reading-the-user-button) |
| 10 | +- [Connecting Qw/ST Devices](#connecting-qwst-devices) |
| 11 | +- [Controlling Motors](#controlling-motors) |
| 12 | +- [Controlling Servos](#controlling-servos) |
| 13 | +- [Setting the RGB LEDs](#setting-the-rgb-leds) |
| 14 | +- [Audio](#audio) |
| 15 | +- [Wireless](#wireless) |
| 16 | +- [Program Lifecycle](#program-lifecycle) |
| 17 | +- [`inventor` Module Reference](#inventor-module-reference) |
| 18 | + - [Constants](#constants) |
| 19 | + - [IO Pin](#io-pin) |
| 20 | + - [Index](#index) |
| 21 | + - [Count](#count) |
| 22 | +- [`Inventor` Class Reference](#inventor-class-reference) |
| 23 | + - [Constants](#constants-1) |
| 24 | + - [Variables](#variables) |
| 25 | + - [Functions](#functions) |
| 26 | + |
| 27 | + |
| 28 | +## Getting Started |
| 29 | + |
| 30 | +To start coding your Inventor board, you will need to add the following lines to the start of your code file. |
| 31 | + |
| 32 | +```python |
| 33 | +from inventor import Inventor |
| 34 | + |
| 35 | +board = Inventor() |
| 36 | +``` |
| 37 | + |
| 38 | +This will create an `Inventor` class called `board` that initialises all the features of Inventor and will be used in the rest of the examples going forward. |
| 39 | + |
| 40 | + |
| 41 | +### Different Gear Ratio |
| 42 | + |
| 43 | +By default the Inventor class initialises the motors and encoders with a 50:1 gear ratio, matching the pre-assembled [Micro Metal Motor Encoders](https://shop.pimoroni.com/products/micro-metal-gearmotor-with-micro-metal-motor-encoder) that we sell. |
| 44 | + |
| 45 | +If you are soldering up your own motors with encoders that have a different gear ratio, then add the `motor_gear_ratio` parameter during class creation, like so: |
| 46 | + |
| 47 | +```python |
| 48 | +board = Inventor(motor_gear_ratio=<new ratio here>) |
| 49 | +``` |
| 50 | + |
| 51 | +:information_source: The Inventor class assumes the connected motor's encoders have the same 12 counts per revolution as our MMME's. If yours are different you will need adjust your ratio to account for this. |
| 52 | + |
| 53 | + |
| 54 | +### What Gets Initialised |
| 55 | + |
| 56 | +To make the starting experience of Inventor easier, the class initialises all of the board features. For some advanced uses though this may not be wanted. To give this flexibility, several steps of the initialisation can be turned off during class creation: |
| 57 | + |
| 58 | +```python |
| 59 | +board = Inventor(init_motors=True, init_servos=True, init_encoders=True, init_i2c=True) |
| 60 | +``` |
| 61 | + |
| 62 | +Example uses: |
| 63 | +* `init_motors=False` - Lets you drive different kinds of magnetic loads, such as solenoids or stepper motors (with the appropriate code), via the new 1x4 header of Inventor 2350 W. |
| 64 | +* `init_servos=False` - Lets you use the 6 servo headers as additional digital GPIO. Note these pins are not 5V tolerant so be careful when using the neighbouring 5V pins for powering devices. |
| 65 | +* `init_encoders=False` - Lets you use the 4 encoder pins as additional digital GPIO. These are handily broken out to pads on the new Inventor 2350 W. |
| 66 | +* `init_i2c=False` - Lets you use the 2 Qw/ST pins as additional digital GPIO for UART or similar. |
| 67 | + |
| 68 | + |
| 69 | +## Reading the User Button |
| 70 | + |
| 71 | +Inventor has one user button, labelled **User**. This can be read using the `switch_pressed()` function: |
| 72 | + |
| 73 | +```python |
| 74 | +state = board.switch_pressed() |
| 75 | +``` |
| 76 | + |
| 77 | +A common use for this would be to control your program's main loop, so that a press of the button causes it to exit: |
| 78 | + |
| 79 | +```python |
| 80 | +while not board.switch_pressed(): |
| 81 | + # Do some stuff here |
| 82 | + |
| 83 | +# Shut the program down cleanly |
| 84 | +``` |
| 85 | + |
| 86 | +## Connecting Qw/ST Devices |
| 87 | + |
| 88 | +Inventor 2040/2350 W features two Qw/ST connectors for attaching I2C-based sensors and devices. These connectors are automatically initialised during class creation (unless `init_i2c=False` was supplied), removing the worry of specifying the wrong pins. The I2C bus can then be accessed by calling `board.i2c`. |
| 89 | + |
| 90 | +Here is an example of setting up our [BME280 breakout](https://shop.pimoroni.com/products/bme280-breakout) on Inventor. |
| 91 | + |
| 92 | +```python |
| 93 | +from inventor import Inventor |
| 94 | +from breakout_bme280 import BreakoutBME280 |
| 95 | + |
| 96 | +# Constants |
| 97 | +ADDRESS = 0x76 # Or 0x77 if the trace on rear of the breakout has been cut |
| 98 | + |
| 99 | +# Variables |
| 100 | +board = Inventor() |
| 101 | +bme = BreakoutBME280(board.i2c, ADDRESS) |
| 102 | +``` |
| 103 | + |
| 104 | +## Controlling Motors |
| 105 | + |
| 106 | +Inventor features a DRV8833 dual-channel motor driver that it suitable for driving small motors. These motor channels are set up as `Motor` objects during class creation (unless `init_motors=False` was supplied). # |
| 107 | + |
| 108 | +:information_source: **For details of what `Motor` objects can do, refer to the [Motor Library](/micropython/modules/motor/README.md#motor)** |
| 109 | + |
| 110 | +The created `Motor` objects can be accessed in two ways, either through the `motor_a` and `motor_b` properties, or by the `motors` list. |
| 111 | + |
| 112 | +```python |
| 113 | +# Access the first motor by property |
| 114 | +motor = board.motor_a |
| 115 | + |
| 116 | +# Access the first motor by list |
| 117 | +motor = board.motors[0] |
| 118 | + |
| 119 | +# Access the first motor by list and constant |
| 120 | +from inventor import MOTOR_A |
| 121 | +motor = board.motors[MOTOR_A] |
| 122 | +``` |
| 123 | + |
| 124 | +Accessing by property is convenient when you know the specific motor you wish to perform a motion, whereas accessing by list can be useful if you need to perform the same operation across both motors within a loop. |
| 125 | + |
| 126 | +Here are examples of how the list may be looped through: |
| 127 | + |
| 128 | +```python |
| 129 | +# Loop through all motors |
| 130 | +for motor in board.motors: |
| 131 | + # Do something with motor here |
| 132 | + |
| 133 | +# Loop through all motors via an index |
| 134 | +from inventor import NUM_MOTORS |
| 135 | +for i in range(NUM_MOTORS): |
| 136 | + motor = board.motors[i] |
| 137 | + # Do something with motor here |
| 138 | +``` |
| 139 | + |
| 140 | + |
| 141 | +## Controlling Servos |
| 142 | + |
| 143 | + |
| 144 | + |
| 145 | +## Setting the RGB LEDs |
| 146 | + |
| 147 | +Inventor 2040/2350 W has twelve addressable RGB LEDs, positioned alongside its servo and GPIO/ADC pins. These make use of our `Plasma` library. |
| 148 | + |
| 149 | +```python |
| 150 | +board.leds.set_rgb(0, 255, 255, 255) |
| 151 | +``` |
| 152 | + |
| 153 | +## Audio |
| 154 | + |
| 155 | +## Wireless |
| 156 | + |
| 157 | +## Program Lifecycle |
| 158 | + |
| 159 | +When writing a program for Inventor 2040/2350 W, there are a number of steps that should be included to make best use of the board's capabilities. |
| 160 | + |
| 161 | + |
| 162 | +```python |
| 163 | +# Perform system level imports here |
| 164 | +# e.g. import math |
| 165 | + |
| 166 | +from inventor import Inventor |
| 167 | + |
| 168 | +""" |
| 169 | +This is a boilerplate example for Inventor 2040/2350 W. Use it as a base for your own programs. |
| 170 | +
|
| 171 | +Press "User" to exit the program. |
| 172 | +""" |
| 173 | + |
| 174 | +# Constants |
| 175 | +# e.g. SLEEP_TIME = 0.1 |
| 176 | + |
| 177 | +# Variables |
| 178 | +board = Inventor() # Create a new Inventor object. These optional keyword parameters are supported: |
| 179 | + # `init_motors`, `init_servos`, `init_encoders`, and `init_i2c`. All are True by default |
| 180 | + |
| 181 | +# Pull out any variables for easy access. E.g |
| 182 | +motor = board.motor_a # or board.motors[MOTOR_A] |
| 183 | +encoder = board.encoder_a # or board.encoders[ENCODER_A] |
| 184 | +servo = board.servo1 # or board.servos[SERVO_1] |
| 185 | + |
| 186 | + |
| 187 | +# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt) |
| 188 | +try: |
| 189 | + # Set up your motors, servos, LEDs, and audio here |
| 190 | + |
| 191 | + # Loop until the "User" button is pressed |
| 192 | + while not board.switch_pressed(): |
| 193 | + ####################### |
| 194 | + # Put your program here |
| 195 | + ####################### |
| 196 | + pass |
| 197 | + |
| 198 | +finally: |
| 199 | + # Stop your motors, servos, LEDs, and audio here |
| 200 | +``` |
| 201 | + |
| 202 | +## `inventor` Module Reference |
| 203 | + |
| 204 | +### Constants |
| 205 | + |
| 206 | +These are accessible by `from inventor import *`, where star is one or more of the below values, separated by commas. |
| 207 | + |
| 208 | +#### IO Pin |
| 209 | + |
| 210 | +```python |
| 211 | +GP0 = 0 |
| 212 | +GP1 = 1 |
| 213 | +GP2 = 2 |
| 214 | + |
| 215 | +A0 = 26 |
| 216 | +A1 = 27 |
| 217 | +A2 = 28 |
| 218 | + |
| 219 | +GPIOS = (GP0, GP1, GP2, A0, A1, A2) |
| 220 | +ADCS = (A0, A1, A2) |
| 221 | +``` |
| 222 | + |
| 223 | +#### Index |
| 224 | + |
| 225 | +```python |
| 226 | +MOTOR_A = 0 |
| 227 | +MOTOR_B = 1 |
| 228 | + |
| 229 | +SERVO_1 = 0 |
| 230 | +SERVO_2 = 1 |
| 231 | +SERVO_3 = 2 |
| 232 | +SERVO_4 = 3 |
| 233 | +SERVO_5 = 4 |
| 234 | +SERVO_6 = 5 |
| 235 | + |
| 236 | +LED_GP0 = 0 |
| 237 | +LED_GP1 = 1 |
| 238 | +LED_GP2 = 2 |
| 239 | +LED_A0 = 3 |
| 240 | +LED_A1 = 4 |
| 241 | +LED_A2 = 5 |
| 242 | +LED_SERVO_1 = 6 |
| 243 | +LED_SERVO_2 = 7 |
| 244 | +LED_SERVO_3 = 8 |
| 245 | +LED_SERVO_4 = 9 |
| 246 | +LED_SERVO_5 = 10 |
| 247 | +LED_SERVO_6 = 11 |
| 248 | +``` |
| 249 | + |
| 250 | +#### Count |
| 251 | + |
| 252 | +```python |
| 253 | +NUM_GPIOS = 6 |
| 254 | +NUM_ADCS = 3 |
| 255 | +NUM_MOTORS = 2 |
| 256 | +NUM_ENCODERS = 2 |
| 257 | +NUM_SERVOS = 6 |
| 258 | +NUM_LEDS = 12 |
| 259 | +``` |
| 260 | + |
| 261 | + |
| 262 | +## `Inventor` Class Reference |
| 263 | + |
| 264 | +### Constants |
| 265 | + |
| 266 | +These are accessible after having imported `Inventor` class from the `inventor` module. E.g. `Inventor.SERVO_1_PIN`. |
| 267 | + |
| 268 | +```python |
| 269 | +AMP_EN_PIN = 3 |
| 270 | +I2C_SDA_PIN = 4 |
| 271 | +I2C_SCL_PIN = 5 |
| 272 | +MOTOR_A_PINS = (6, 7) |
| 273 | +MOTOR_B_PINS = (8, 9) |
| 274 | +ENCODER_A_PINS = (19, 18) |
| 275 | +ENCODER_B_PINS = (17, 16) |
| 276 | + |
| 277 | +SERVO_1_PIN = 10 |
| 278 | +SERVO_2_PIN = 11 |
| 279 | +SERVO_3_PIN = 12 |
| 280 | +SERVO_4_PIN = 13 |
| 281 | +SERVO_5_PIN = 14 |
| 282 | +SERVO_6_PIN = 15 |
| 283 | + |
| 284 | +LED_DATA_PIN = 20 |
| 285 | +PWM_AUDIO_PIN = 21 |
| 286 | +USER_SW_PIN = 22 |
| 287 | + |
| 288 | +AMP_CORRECTION = 4 |
| 289 | +DEFAULT_VOLUME = 0.2 |
| 290 | +``` |
| 291 | + |
| 292 | + |
| 293 | +### Variables |
| 294 | +```python |
| 295 | +# If init_motors was True |
| 296 | +motors: list[Motor] |
| 297 | + |
| 298 | +# If init_encoders was True |
| 299 | +encoders: list[Encoder] |
| 300 | + |
| 301 | +# If init_servos was True |
| 302 | +servos: list[Servo] |
| 303 | + |
| 304 | +# If init_i2c was True |
| 305 | +i2c: PimoroniI2C |
| 306 | + |
| 307 | +audio_pwm: PWM |
| 308 | + |
| 309 | +leds: WS2812 |
| 310 | +``` |
| 311 | + |
| 312 | + |
| 313 | +### Functions |
| 314 | + |
| 315 | +```python |
| 316 | +# Initialisation |
| 317 | +Inventor(motor_gear_ratio: int|float=50, |
| 318 | + init_motors: bool=True, |
| 319 | + init_servos: bool=True, |
| 320 | + init_encoders: bool=True, |
| 321 | + init_i2c: bool=True) |
| 322 | + |
| 323 | +# Interaction |
| 324 | +switch_pressed() -> bool |
| 325 | + |
| 326 | +# Motor Access (only usable if init_motors was True) |
| 327 | +@property |
| 328 | +motor_a -> Motor |
| 329 | +@property |
| 330 | +motor_b -> Motor |
| 331 | + |
| 332 | +# Encoder Access (only usable if init_encoders was True) |
| 333 | +@property |
| 334 | +encoder_a -> Encoder |
| 335 | +@property |
| 336 | +encoder_b -> Encoder |
| 337 | + |
| 338 | +# Servo Access (only usable if init_servos was True) |
| 339 | +@property |
| 340 | +servo1 -> Servo |
| 341 | +@property |
| 342 | +servo2 -> Servo |
| 343 | +@property |
| 344 | +servo3 -> Servo |
| 345 | +@property |
| 346 | +servo4 -> Servo |
| 347 | +@property |
| 348 | +servo5 -> Servo |
| 349 | +@property |
| 350 | +servo6 -> Servo |
| 351 | + |
| 352 | +# Audio |
| 353 | +play_tone(frequency: float): |
| 354 | +play_silence() -> None |
| 355 | +stop_playing() -> None |
| 356 | +volume() -> float |
| 357 | +volume(volume: float) -> None |
| 358 | +mute_audio() -> None |
| 359 | +unmute_audio() -> None |
| 360 | +``` |
0 commit comments