-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathadafruit_crickit.py
executable file
·408 lines (327 loc) · 12.6 KB
/
adafruit_crickit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_crickit`
==========================
Convenience library for using the Adafruit Crickit robotics boards.
* Author(s): Dan Halbert
Implementation Notes
--------------------
**Hardware:**
`Adafruit Crickit for Circuit Playground Express <https://www.adafruit.com/3093>`_
`Adafruit Crickit FeatherWing <https://www.adafruit.com/3343>`_
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
import sys
import board
from micropython import const
# pylint: disable=wrong-import-position
try:
lib_index = sys.path.index("/lib") # pylint: disable=invalid-name
if lib_index < sys.path.index(".frozen"):
# Prefer frozen modules over those in /lib.
sys.path.insert(lib_index, ".frozen")
except ValueError:
# Don't change sys.path if it doesn't contain "lib" or ".frozen".
pass
from adafruit_seesaw.seesaw import Seesaw
from adafruit_seesaw.crickit import Crickit_Pinmap
from adafruit_seesaw.pwmout import PWMOut
from adafruit_seesaw.neopixel import NeoPixel
from adafruit_motor.servo import Servo, ContinuousServo
from adafruit_motor.motor import DCMotor
from adafruit_motor.stepper import StepperMotor
try:
from typing import Any, Tuple, Type, Union
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Crickit.git"
_SERVO1 = const(17)
_SERVO2 = const(16)
_SERVO3 = const(15)
_SERVO4 = const(14)
_MOTOR1 = (22, 23)
_MOTOR2 = (19, 18)
# Order as needed for steppers.
_MOTOR_STEPPER = _MOTOR1 + _MOTOR2
_DRIVE1 = const(13)
_DRIVE2 = const(12)
_DRIVE3 = const(43)
_DRIVE4 = const(42)
# Order as needed for steppers.
_DRIVE_STEPPER = (_DRIVE1, _DRIVE3, _DRIVE2, _DRIVE4)
_TOUCH1 = const(4)
_TOUCH2 = const(5)
_TOUCH3 = const(6)
_TOUCH4 = const(7)
_NEOPIXEL = const(20)
_SS_PIXEL = const(27)
# pylint: disable=too-few-public-methods
class CrickitTouchIn:
"""Imitate touchio.TouchIn."""
def __init__(self, seesaw: Seesaw, pin: int):
self._seesaw = seesaw
self._pin = pin
self.threshold = self.raw_value + 100
@property
def raw_value(self) -> int:
"""The raw touch measurement as an `int`. (read-only)"""
return self._seesaw.touch_read(self._pin)
@property
def value(self) -> bool:
"""Whether the touch pad is being touched or not. (read-only)"""
return self.raw_value > self.threshold
# pylint: disable=too-many-public-methods
class Crickit:
"""Represents a Crickit board. Provides a number of devices available via properties, such as
``servo_1``. Devices are created on demand the first time they are referenced.
It's fine to refer a device multiple times via its property, but it's faster and results
in more compact code to assign a device to a variable.
.. code-block:: python
import time
from adafruit_crickit import crickit
# This is fine:
crickit.servo_1.angle = 0
time.sleep(1)
crickit.servo_1.angle = 90
time.sleep(1)
# This is slightly faster and more compact:
servo_1 = crickit.servo_1
servo_1.angle = 0
time.sleep(1)
servo_1.angle = 90
time.sleep(1)
"""
SIGNAL1 = 2
"""Signal 1 terminal"""
SIGNAL2 = 3
"""Signal 2 terminal"""
SIGNAL3 = 40
"""Signal 3 terminal"""
SIGNAL4 = 41
"""Signal 4 terminal"""
SIGNAL5 = 11
"""Signal 5 terminal"""
SIGNAL6 = 10
"""Signal 6 terminal"""
SIGNAL7 = 9
"""Signal 7 terminal"""
SIGNAL8 = 8
"""Signal 8 terminal"""
def __init__(self, seesaw: Seesaw):
self._seesaw = seesaw
self._seesaw.pin_mapping = Crickit_Pinmap
# Associate terminal(s) with certain devices.
# Used to find existing devices.
self._devices = {}
self._neopixel = None
self._onboard_pixel = None
@property
def seesaw(self) -> Seesaw:
"""The Seesaw object that talks to the Crickit. Use this object to manipulate the
signal pins that correspond to Crickit terminals.
.. code-block:: python
from adafruit_crickit import crickit
ss = crickit.seesaw
ss.pin_mode(crickit.SIGNAL4, ss.OUTPUT)
ss.digital_write(crickit.SIGNAL4], True)
"""
return self._seesaw
@property
def servo_1(self) -> Servo:
"""``adafruit_motor.servo.Servo`` object on Servo 1 terminal"""
return self._servo(_SERVO1, Servo)
@property
def servo_2(self) -> Servo:
"""``adafruit_motor.servo.Servo`` object on Servo 2 terminal"""
return self._servo(_SERVO2, Servo)
@property
def servo_3(self) -> Servo:
"""``adafruit_motor.servo.Servo`` object on Servo 3 terminal"""
return self._servo(_SERVO3, Servo)
@property
def servo_4(self) -> Servo:
"""``adafruit_motor.servo.Servo`` object on Servo 4 terminal"""
return self._servo(_SERVO4, Servo)
@property
def continuous_servo_1(self) -> ContinuousServo:
"""``adafruit_motor.servo.ContinuousServo`` object on Servo 1 terminal"""
return self._servo(_SERVO1, ContinuousServo)
@property
def continuous_servo_2(self) -> ContinuousServo:
"""``adafruit_motor.servo.ContinuousServo`` object on Servo 2 terminal"""
return self._servo(_SERVO2, ContinuousServo)
@property
def continuous_servo_3(self) -> ContinuousServo:
"""``adafruit_motor.servo.ContinuousServo`` object on Servo 3 terminal"""
return self._servo(_SERVO3, ContinuousServo)
@property
def continuous_servo_4(self) -> ContinuousServo:
"""``adafruit_motor.servo.ContinuousServo`` object on Servo 4 terminal"""
return self._servo(_SERVO4, ContinuousServo)
def _servo(self, terminal: int, servo_class: Type) -> Any:
device = self._devices.get(terminal, None)
if not isinstance(device, servo_class):
pwm = PWMOut(self._seesaw, terminal)
pwm.frequency = 50
device = servo_class(pwm)
self._devices[terminal] = device
return device
@property
def dc_motor_1(self) -> DCMotor:
"""``adafruit_motor.motor.DCMotor`` object on Motor 1 terminals"""
return self._motor(_MOTOR1, DCMotor)
@property
def dc_motor_2(self) -> DCMotor:
"""``adafruit_motor.motor.DCMotor`` object on Motor 2 terminals"""
return self._motor(_MOTOR2, DCMotor)
@property
def stepper_motor(self) -> StepperMotor:
"""``adafruit_motor.motor.StepperMotor`` object on Motor 1 and Motor 2 terminals"""
return self._motor(_MOTOR_STEPPER, StepperMotor)
@property
def drive_stepper_motor(self) -> StepperMotor:
"""``adafruit_motor.motor.StepperMotor`` object on Drive terminals"""
return self._motor(_DRIVE_STEPPER, StepperMotor)
@property
def feather_drive_stepper_motor(self) -> StepperMotor:
"""``adafruit_motor.motor.StepperMotor`` object on Drive terminals on Crickit FeatherWing"""
return self._motor(tuple(reversed(_DRIVE_STEPPER)), StepperMotor)
def _motor(self, terminals: Tuple[int, ...], motor_class: Type) -> Any:
device = self._devices.get(terminals, None)
if not isinstance(device, motor_class):
device = motor_class(
*(PWMOut(self._seesaw, terminal) for terminal in terminals)
)
self._devices[terminals] = device
return device
@property
def drive_1(self) -> PWMOut:
"""``adafruit_seesaw.pwmout.PWMOut`` object on Drive 1 terminal, with ``frequency=1000``"""
return self._drive(_DRIVE1)
@property
def drive_2(self) -> PWMOut:
"""``adafruit_seesaw.pwmout.PWMOut`` object on Drive 2 terminal, with ``frequency=1000``"""
return self._drive(_DRIVE2)
@property
def drive_3(self) -> PWMOut:
"""``adafruit_seesaw.pwmout.PWMOut`` object on Drive 3 terminal, with ``frequency=1000``"""
return self._drive(_DRIVE3)
@property
def drive_4(self) -> PWMOut:
"""``adafruit_seesaw.pwmout.PWMOut`` object on Drive 4 terminal, with ``frequency=1000``"""
return self._drive(_DRIVE4)
feather_drive_1 = drive_4
"""``adafruit_seesaw.pwmout.PWMOut`` object on Crickit Featherwing Drive 1 terminal,
with ``frequency=1000``
"""
feather_drive_2 = drive_3
"""``adafruit_seesaw.pwmout.PWMOut`` object on Crickit Featherwing Drive 2 terminal,
with ``frequency=1000``
"""
feather_drive_3 = drive_2
"""``adafruit_seesaw.pwmout.PWMOut`` object on Crickit Featherwing Drive 3 terminal,
with ``frequency=1000``
"""
feather_drive_4 = drive_1
"""``adafruit_seesaw.pwmout.PWMOut`` object on Crickit Featherwing Drive 4 terminal,
with ``frequency=1000``
"""
def _drive(self, terminal: int) -> PWMOut:
device = self._devices.get(terminal, None)
if not isinstance(device, PWMOut):
device = PWMOut(self._seesaw, terminal)
device.frequency = 1000
self._devices[terminal] = device
return device
@property
def touch_1(self) -> CrickitTouchIn:
"""``adafruit_crickit.CrickitTouchIn`` object on Touch 1 terminal"""
return self._touch(_TOUCH1)
@property
def touch_2(self) -> CrickitTouchIn:
"""``adafruit_crickit.CrickitTouchIn`` object on Touch 2 terminal"""
return self._touch(_TOUCH2)
@property
def touch_3(self) -> CrickitTouchIn:
"""``adafruit_crickit.CrickitTouchIn`` object on Touch 3 terminal"""
return self._touch(_TOUCH3)
@property
def touch_4(self) -> CrickitTouchIn:
"""``adafruit_crickit.CrickitTouchIn`` object on Touch 4 terminal"""
return self._touch(_TOUCH4)
def _touch(self, terminal: int) -> CrickitTouchIn:
touch_in = self._devices.get(terminal, None)
if not touch_in:
touch_in = CrickitTouchIn(self._seesaw, terminal)
self._devices[terminal] = touch_in
return touch_in
@property
def neopixel(self) -> NeoPixel:
"""```adafruit_seesaw.neopixel`` object on NeoPixel terminal.
Raises ValueError if ``init_neopixel`` has not been called.
"""
if not self._neopixel:
raise ValueError("Call init_neopixel first")
return self._neopixel
def init_neopixel(
self,
n: int,
*,
bpp: int = 3,
brightness: float = 1.0,
auto_write: bool = True,
pixel_order: Union[str, Tuple] = None
) -> None:
"""Set up a seesaw.NeoPixel object
.. note:: On the CPX Crickit board, the NeoPixel terminal is by default
controlled by CPX pin A1, and is not controlled by seesaw. So this object
will not be usable. Instead, use the regular NeoPixel library
and specify ``board.A1`` as the pin.
You can change the jumper connection on the bottom of the CPX Crickit board
to move control of the NeoPixel terminal to seesaw pin #20 (terminal.NEOPIXEL).
In addition, the Crickit FeatherWing always uses seesaw pin #20.
In either of those cases, this object will work.
.. code-block:: python
from adafruit_crickit.crickit import crickit
crickit.init_neopixel(24)
crickit.neopixel.fill((100, 0, 0))
"""
self._neopixel = NeoPixel(
self._seesaw,
_NEOPIXEL,
n,
bpp=bpp,
brightness=brightness,
auto_write=auto_write,
pixel_order=pixel_order,
)
@property
def onboard_pixel(self) -> NeoPixel:
"""```adafruit_seesaw.neopixel`` object on the Seesaw on-board NeoPixel.
Initialize on-board NeoPixel and clear upon first use.
"""
if not self._onboard_pixel:
self._onboard_pixel = NeoPixel(
self._seesaw,
_SS_PIXEL,
1,
bpp=3,
brightness=1.0,
auto_write=True,
pixel_order=None,
)
self._onboard_pixel.fill((0, 0, 0))
return self._onboard_pixel
def reset(self) -> None:
"""Reset the whole Crickit board."""
self._seesaw.sw_reset()
crickit = None # pylint: disable=invalid-name
"""A singleton instance to control a single Crickit board, controlled by the default I2C pins."""
# Sphinx's board is missing real pins so skip the constructor in that case.
if "I2C" in dir(board):
crickit = Crickit(Seesaw(board.I2C())) # pylint: disable=invalid-name