diff --git a/.travis.yml b/.travis.yml index b3b7c11..45bf216 100755 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ install: - pip install -r requirements.txt - pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme script: -- pylint adafruit_crickit/*.py +- pylint adafruit_crickit.py - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py) - circuitpython-build-bundles --filename_prefix adafruit-circuitpython-crickit --library_location diff --git a/README.rst b/README.rst index 32ee96f..07a8c97 100644 --- a/README.rst +++ b/README.rst @@ -37,54 +37,46 @@ In most cases you just need a couple of imports. # This is a mock example showing typical usage of the library for each kind of device. - # crickit is a singleton object - from adafruit_crickit.crickit import crickit - - # Terminals have simple names like SIGNAL1, SERVO2, TOUCH3, MOTOR1A, NEOPIXEL, - # CPX_DRIVE1, and FEATHER_DRIVE2. - # Because the Drive terminals are numbered in reverse on the CPX Crickit vs the FeatherWing Crickit, - # there are separate DRIVE names for CPX and FeatherWing Drive terminals. - from adafruit_crickit.terminals import (SERVO1, - MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B, - CPX_DRIVE1, NEOPIXEL, SIGNAL1, SIGNAL2, TOUCH1) + from adafruit_crickit import crickit # Add this import if using stepper motors. # It will expose constants saying how to step: stepper.FORWARD, stepper.BACKWARD, etc. from adafruit_motor import stepper - servo1 = crickit.servo(SERVO1) - servo1.angle = 90 + # Set servo 1 to 90 degrees + crickit.servo_1.angle = 90 - cservo1 = crickit.continuous_servo(SERVO1) - cservo1.throttle = -0.5 + # Change servo settings. + crickit.servo_1.actuation_range = 135 + crickit.servo_1.set_pulse_widths(min_pulse=850, max_pulse=2100) - motor = crickit.dc_motor(MOTOR1A, MOTOR1B) - motor.throttle = 0.5 + # You can assign a device to a variable to get a shorter name. + servo_2 = crickit.servo_2 + servo_2.throttle = 0 - drive1 = crickit.pwm_out(CPX_DRIVE1) - drive1.fraction = 1.0 + # Run a continous servo on Servo 2 backwards at half speed. + crickit.continuous_servo_2.throttle = -0.5 - # Note: On CPX Crickit, NeoPixel pin is normally connected to A1, not to seesaw, - # so this demo would not control the NeoPixel terminal. + # Run the motor on Motor 1 terminals at half speed. + crickit.dc_motor_1.throttle = 0.5 - # Strip or ring of 8 NeoPixels - neopixels = crickit.neopixel(NEOPIXEL, 8) - neopixels.fill((100, 100, 100)) + # Set Drive 1 terminal to 3/4 strength. + crickit.drive_1.fraction = 0.75 - # Write Signal terminal 1 and read Signal terminal 2. - ss = crickit.seesaw - ss.pin_mode(SIGNAL1, ss.OUTPUT) - ss.pin_mode(SIGNAL2, ss.INPUT) - ss.digital_write(SIGNAL1, True) - print(ss.digital_read(SIGNAL2)) + if crickit.touch_1.value: + print("Touched terminal Touch 1") # A single stepper motor uses up all the motor terminals. - stepper_motor = crickit.stepper_motor(MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B) - stepper_motor.onestep(direction=stepper.FORWARD) + crickit.stepper_motor.onestep(direction=stepper.FORWARD) - touch1 = crickit.touch(TOUCH1) - if touch1.value: - print("Touched terminal Touch 1") + # You can also use the Drive terminals for a stepper motor + crickit.drive_stepper_motor.onestep(direction=stepper.BACKWARD) + + # Note: On CPX Crickit, NeoPixel pin is normally connected to A1, not to seesaw, + # so this part of the demo cannot control the NeoPixel terminal. + # Strip or ring of 8 NeoPixels + crickit.init_neopixel(8) + crickit.neopixel.fill((100, 100, 100)) Contributing diff --git a/adafruit_crickit.py b/adafruit_crickit.py new file mode 100755 index 0000000..1f1874f --- /dev/null +++ b/adafruit_crickit.py @@ -0,0 +1,370 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Dan Halbert for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`adafruit_crickit` +========================== + +Convenience library for using the Adafruit Crickit robotics boards. + +* Author(s): Dan Halbert + +Implementation Notes +-------------------- + +**Hardware:** + + `Adafruit Crickit for Circuit Playground Express `_ + `Adafruit Crickit FeatherWing `_ + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://github.com/adafruit/circuitpython/releases +""" + +import sys + +import board +import busio + +from micropython import const + +#pylint: disable=wrong-import-position +sys.path.insert(0, ".frozen") # Prefer frozen modules over local. + +from adafruit_seesaw.seesaw import Seesaw +from adafruit_seesaw.pwmout import PWMOut +from adafruit_motor.servo import Servo, ContinuousServo +from adafruit_motor.motor import DCMotor +from adafruit_motor.stepper import StepperMotor + +__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) +_MOTOR_ALL = _MOTOR1 + _MOTOR2 + +_DRIVE1 = const(13) +_DRIVE2 = const(12) +_DRIVE3 = const(43) +_DRIVE4 = const(42) + +_DRIVE_ALL = (_DRIVE1, _DRIVE2, _DRIVE3, _DRIVE4) + +_TOUCH1 = const(4) +_TOUCH2 = const(5) +_TOUCH3 = const(6) +_TOUCH4 = const(7) + +_NEOPIXEL = const(20) + +#pylint: disable=too-few-public-methods +class CrickitTouchIn: + """Imitate touchio.TouchIn.""" + def __init__(self, seesaw, pin): + self._seesaw = seesaw + self._pin = pin + self.threshold = self.raw_value + 100 + + @property + def raw_value(self): + """The raw touch measurement as an `int`. (read-only)""" + return self._seesaw.touch_read(self._pin) + + @property + def value(self): + """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): + self._seesaw = seesaw + # Associate terminal(s) with certain devices. + # Used to find existing devices. + self._devices = dict() + self._neopixel = None + + @property + def seesaw(self): + """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): + """``adafruit_motor.servo.Servo`` object on Servo 1 terminal""" + return self._servo(_SERVO1, Servo) + + @property + def servo_2(self): + """``adafruit_motor.servo.Servo`` object on Servo 2 terminal""" + return self._servo(_SERVO2, Servo) + + @property + def servo_3(self): + """``adafruit_motor.servo.Servo`` object on Servo 3 terminal""" + return self._servo(_SERVO3, Servo) + + @property + def servo_4(self): + """``adafruit_motor.servo.Servo`` object on Servo 4 terminal""" + return self._servo(_SERVO4, Servo) + + @property + def continuous_servo_1(self): + """``adafruit_motor.servo.ContinuousServo`` object on Servo 1 terminal""" + return self._servo(_SERVO1, ContinuousServo) + + @property + def continuous_servo_2(self): + """``adafruit_motor.servo.ContinuousServo`` object on Servo 2 terminal""" + return self._servo(_SERVO2, ContinuousServo) + + @property + def continuous_servo_3(self): + """``adafruit_motor.servo.ContinuousServo`` object on Servo 3 terminal""" + return self._servo(_SERVO3, ContinuousServo) + + @property + def continuous_servo_4(self): + """``adafruit_motor.servo.ContinuousServo`` object on Servo 4 terminal""" + return self._servo(_SERVO4, ContinuousServo) + + def _servo(self, terminal, servo_class): + 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): + """``adafruit_motor.motor.DCMotor`` object on Motor 1 terminals""" + return self._motor(_MOTOR1, DCMotor) + + @property + def dc_motor_2(self): + """``adafruit_motor.motor.DCMotor`` object on Motor 2 terminals""" + return self._motor(_MOTOR2, DCMotor) + + @property + def stepper_motor(self): + """``adafruit_motor.motor.StepperMotor`` object on Motor 1 and Motor 2 terminals""" + return self._motor(_MOTOR_ALL, StepperMotor) + + @property + def drive_stepper_motor(self): + """``adafruit_motor.motor.StepperMotor`` object on Drive terminals""" + return self._motor(_DRIVE_ALL, StepperMotor) + + @property + def feather_drive_stepper_motor(self): + """``adafruit_motor.motor.StepperMotor`` object on Drive terminals on Crickit FeatherWing""" + return self._motor(reversed(_DRIVE_ALL), StepperMotor) + + def _motor(self, terminals, motor_class): + 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): + """``adafruit_seesaw.pwmout.PWMOut`` object on Drive 1 terminal, with ``frequency=1000``""" + return self._drive(_DRIVE1) + + @property + def drive_2(self): + """``adafruit_seesaw.pwmout.PWMOut`` object on Drive 2 terminal, with ``frequency=1000``""" + return self._drive(_DRIVE2) + + @property + def drive_3(self): + """``adafruit_seesaw.pwmout.PWMOut`` object on Drive 3 terminal, with ``frequency=1000``""" + return self._drive(_DRIVE3) + + @property + def drive_4(self): + """``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): + 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): + """``adafruit_crickit.CrickitTouchIn`` object on Touch 1 terminal""" + return self._touch(_TOUCH1) + + @property + def touch_2(self): + """``adafruit_crickit.CrickitTouchIn`` object on Touch 2 terminal""" + return self._touch(_TOUCH2) + + @property + def touch_3(self): + """``adafruit_crickit.CrickitTouchIn`` object on Touch 3 terminal""" + return self._touch(_TOUCH3) + + @property + def touch_4(self): + """``adafruit_crickit.CrickitTouchIn`` object on Touch 4 terminal""" + return self._touch(_TOUCH4) + + def _touch(self, terminal): + 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): + """```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, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=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)) + """ + from adafruit_seesaw.neopixel import NeoPixel + return NeoPixel(self._seesaw, _NEOPIXEL, n, bpp=bpp, + brightness=brightness, auto_write=auto_write, + pixel_order=pixel_order) + + def reset(self): + """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 "SCL" in dir(board): + crickit = Crickit(Seesaw(busio.I2C(board.SCL, board.SDA))) # pylint: disable=invalid-name diff --git a/adafruit_crickit/crickit.py b/adafruit_crickit/crickit.py deleted file mode 100755 index 63049aa..0000000 --- a/adafruit_crickit/crickit.py +++ /dev/null @@ -1,310 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2018 Dan Halbert for Adafruit Industries -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -""" -`adafruit_crickit.crickit` -========================== - -Convenience library for using the Adafruit Crickit robotics boards. - -* Author(s): Dan Halbert - -Implementation Notes --------------------- - -**Hardware:** - - `Adafruit Crickit for Circuit Playground Express `_ - `Adafruit Crickit FeatherWing `_ - -**Software and Dependencies:** - -* Adafruit CircuitPython firmware for the supported boards: - https://github.com/adafruit/circuitpython/releases -""" - -import sys - -import board -import busio - -#pylint: disable=wrong-import-position -sys.path.insert(0, ".frozen") # Prefer frozen modules over local. - -from adafruit_seesaw.seesaw import Seesaw -# This is very common so import it in advance. -# Takes less memory to import PWMOut once than have multiple import statements. -# Each import statement is about 60 bytes. -from adafruit_seesaw.pwmout import PWMOut - -from adafruit_crickit.terminals import (NEOPIXEL, _SIGNAL_SET, - _MOTOR1_SET, _MOTOR2_SET, _MOTOR_SET, - _DRIVE_SET, _PWM_SET, _TOUCH_SET) - -__version__ = "0.0.0-auto.0" -__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Crickit.git" - -# Exception strings -_TERMINALS_IN_USE = "Terminal(s) already in use" -_TERMINALS_NOT_VALID = "Terminal(s) can't be used for this kind of device" - -#pylint: disable=too-few-public-methods - -class CrickitTouchIn: - """Imitate touchio.TouchIn.""" - def __init__(self, seesaw, pin): - self._seesaw = seesaw - self._pin = pin - self.threshold = self.raw_value + 100 - - @property - def raw_value(self): - """The raw touch measurement as an `int`. (read-only)""" - return self._seesaw.touch_read(self._pin) - - @property - def value(self): - """Whether the touch pad is being touched or not. (read-only)""" - return self.raw_value > self.threshold - - -class Crickit: - """Represents a Crickit board.""" - def __init__(self, seesaw): - self._seesaw = seesaw - - @property - def seesaw(self): - """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.terminals import SIGNAL4 - from adafruit_crickit.crickit import crickit - - ss = crickit.seesaw - ss.pin_mode(SIGNAL4, ss.OUTPUT) - ss.digital_write(SIGNAL4], True) - """ - - return self._seesaw - - def servo(self, terminal, *, actuation_range=180, min_pulse=750, max_pulse=2250): - """Create an ``adafruit_motor.servo.Servo object``. - - :param terminal - :param int actuation_range: The physical range of motion of the servo in degrees, \ - for the given ``min_pulse`` and ``max_pulse`` values. - :param int min_pulse: The minimum pulse width of the servo in microseconds. - :param int max_pulse: The maximum pulse width of the servo in microseconds. - - The specified pulse width range of a servo has historically been 1000-2000us, - for a 90 degree range of motion. But nearly all modern servos have a 170-180 - degree range, and the pulse widths can go well out of the range to achieve this - extended motion. The default values here of ``750`` and ``2250`` typically give - 135 degrees of motion. You can set ``actuation_range`` to correspond to the - actual range of motion you observe with your given ``min_pulse`` and ``max_pulse`` - values. - - .. warning:: You can extend the pulse width above and below these limits to - get a wider range of movement. But if you go too low or too high, - the servo mechanism may hit the end stops, buzz, and draw extra current as it stalls. - Test carefully to find the safe minimum and maximum. - - .. code-block:: python - - import time - from adafruit_crickit.terminals import SERVO1 - from adafruit_crickit.crickit import crickit - - servo1 = crickit.servo(SERVO1) - # Set to 90 degrees. - servo1.angle = 90 - - # Set all the way one way, then the other. - servo1.fraction = 0.0 - time.sleep(1.0) - servo.fraction = 1.0 - """ - if terminal not in _PWM_SET: - raise ValueError(_TERMINALS_NOT_VALID) - - from adafruit_motor.servo import Servo - - pwm = PWMOut(self._seesaw, terminal) - pwm.frequency = 50 - return Servo(pwm, actuation_range=actuation_range, min_pulse=min_pulse, max_pulse=max_pulse) - - def continuous_servo(self, terminal, *, min_pulse=750, max_pulse=2250): - """Create an ``adafruit_motor.servo.ContinuousServo`` object - - .. code-block:: python - - from adafruit_crickit.terminals import SERVO1 - from adafruit_crickit.crickit import crickit - - continuous_servo1 = crickit.continuous_servo1(SERVO1) - # Start spinning backwards at half speed. - servo1.throttle = -0.5 - """ - if terminal not in _PWM_SET: - raise ValueError(_TERMINALS_NOT_VALID) - - from adafruit_motor.servo import ContinuousServo - - pwm = PWMOut(self._seesaw, terminal) - pwm.frequency = 50 - return ContinuousServo(pwm, min_pulse=min_pulse, max_pulse=max_pulse) - - def dc_motor(self, terminal1, terminal2): - """Create an ``adafruit_motor.motor.DCMotor`` object. - - .. code-block:: python - - from adafruit_crickit.terminals import MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B - from adafruit_crickit.crickit import crickit - - # Create dc_motor objects. - motor1 = crickit.dc_motor(MOTOR1A, MOTOR1B) - motor2 = crickit.dc_motor(MOTOR2A, MOTOR2B) - - # Run both motors at half-speed. - motor1.throttle = 0.5 - motor2.throttle = 0.5 - """ - - # Make sure pins are valid and both are either MOTOR1 or MOTOR2. - # Use set comparison to ignore order. - if set((terminal1, terminal2)) not in (_MOTOR1_SET, _MOTOR2_SET): - raise ValueError(_TERMINALS_NOT_VALID) - - from adafruit_motor.motor import DCMotor - - return DCMotor(PWMOut(self._seesaw, terminal1), - PWMOut(self._seesaw, terminal2)) - - def stepper_motor(self, terminal1, terminal2, terminal3, terminal4): - """Create an ``adafruit_motor.motor.StepperMotor`` object. - The four Motor or four Drive terminals are used all together - to drive a single StepperMotor. - - .. code-block:: python - - from adafruit_crickit.terminals import DRIVE1, DRIVE2, DRIVE3, DRIVE4 - from adafruit_crickit.terminals import MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B - from adafruit_crickit.crickit import crickit - - stepper_d = crickit.stepper_motor(DRIVE1, DRIVE2, DRIVE3, DRIVE4) - stepper_d.onestep(direction=stepper.FORWARD) - stepper_m = crickit.stepper_motor(MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B) - stepper_m.onestep(direction=stepper.BACKWARD) - - """ - terminals = (terminal1, terminal2, terminal3, terminal4) - if set(terminals) not in (_DRIVE_SET, _MOTOR_SET): - raise ValueError(_TERMINALS_NOT_VALID) - - from adafruit_motor.stepper import StepperMotor - return StepperMotor(*(PWMOut(self._seesaw, terminal) for terminal in terminals)) - - def pwm_out(self, terminal, duty_cycle=0, frequency=1000): - """Create an ``adafruit_seesaw.pwmout.PWMOut`` object. - - Note that the default ``frequency`` is 1000, not 500, which is the default - for `pulseio.PWMOut`. 1000 is a better default for the Drive terminals. - - .. code-block:: python - - from adafruit_crickit.terminals import CPX_DRIVE2 - from adafruit_crickit.crickit import crickit - - # Create general PWM on CPX_DRIVE2 terminal. - drive2 = crickit.pwm_out(CPX_DRIVE2) - - # Turn on 50% duty cycle for CPX_DRIVE2 - drive2.fraction = 0.5 - """ - if terminal not in _PWM_SET: - raise ValueError(_TERMINALS_NOT_VALID) - - pwm = PWMOut(self._seesaw, terminal) - pwm.duty_cycle = duty_cycle - pwm.frequency = frequency - return pwm - - def touch(self, terminal): - """Create a `CrickitTouchIn` object. Used for the four Capacitive Touch terminals - and also for Signal terminals that have touch capability (`SIGNAL1` through `SIGNAL4`). - - .. code-block:: python - - from adafruit_crickit.terminals import TOUCH1 - from adafruit_crickit.crickit import crickit - - touch1 = crickit.touch(TOUCH1) - if touch1.value: - print("Touch 1 touched") - """ - if terminal not in _TOUCH_SET: - raise ValueError(_TERMINALS_NOT_VALID) - return CrickitTouchIn(self._seesaw, terminal) - - def neopixel(self, terminal, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): - """Create a seesaw.NeoPixel object for the given terminal. - - .. 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.terminals import NEOPIXEL - from adafruit_crickit.crickit import crickit - - neopixels = crickit.neopixel(NEOPIXEL, 24) - - neopixels.fill((100, 0, 0)) - """ - from adafruit_seesaw.neopixel import NeoPixel - - if terminal not in _SIGNAL_SET and terminal != NEOPIXEL: - raise ValueError(_TERMINALS_NOT_VALID) - return NeoPixel(self._seesaw, terminal, n, bpp=bpp, - brightness=brightness, auto_write=auto_write, - pixel_order=pixel_order) - - def reset(self): - """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 "SCL" in dir(board): - crickit = Crickit(Seesaw(busio.I2C(board.SCL, board.SDA))) # pylint: disable=invalid-name diff --git a/adafruit_crickit/terminals.py b/adafruit_crickit/terminals.py deleted file mode 100644 index af73bcb..0000000 --- a/adafruit_crickit/terminals.py +++ /dev/null @@ -1,121 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2018 Dan Halbert for Adafruit Industries -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -""" -`adafruit_crickit.terminals` -============================ - -Mapping of terminal names on an Adafruit Crickit board to their seesaw pin numbers. - -* Author(s): Dan Halbert -""" - -from micropython import const - -__version__ = "0.0.0-auto.0" -__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Crickit.git" - -SIGNAL1 = const(2) -"""Signal 1 terminal""" -SIGNAL2 = const(3) -"""Signal 2 terminal""" -SIGNAL3 = const(40) -"""Signal 3 terminal""" -SIGNAL4 = const(41) -"""Signal 4 terminal""" -SIGNAL5 = const(11) -"""Signal 5 terminal""" -SIGNAL6 = const(10) -"""Signal 6 terminal""" -SIGNAL7 = const(9) -"""Signal 7 terminal""" -SIGNAL8 = const(8) -"""Signal 8 terminal""" - -_SIGNAL_SET = set((SIGNAL1, SIGNAL2, SIGNAL3, SIGNAL4, SIGNAL5, SIGNAL6, SIGNAL7, SIGNAL8)) - -SERVO1 = const(17) -"""Servo 1 terminal""" -SERVO2 = const(16) -"""Servo 2 terminal""" -SERVO3 = const(15) -"""Servo 3 terminal""" -SERVO4 = const(14) -"""Servo 4 terminal""" - -_SERVO_SET = set((SERVO1, SERVO2, SERVO3, SERVO4)) - -MOTOR1A = const(22) -"""Motor 1 terminal A (The A and B terminals are not differentiated on the board)""" -MOTOR1B = const(23) -"""Motor 1 terminal B (The A and B terminals are not differentiated on the board)""" -MOTOR2A = const(19) -"""Motor 2 terminal A (The A and B terminals are not differentiated on the board)""" -MOTOR2B = const(18) -"""Motor 2 terminal B (The A and B terminals are not differentiated on the board)""" - -_MOTOR1_SET = set((MOTOR1A, MOTOR1B)) -_MOTOR2_SET = set((MOTOR2A, MOTOR2B)) -_MOTOR_SET = _MOTOR1_SET | _MOTOR2_SET - -# Drive terminal numbers on the FeatherWing Crickit are the reverse of those on the CPX Crickit. - -CPX_DRIVE1 = const(42) -"""Drive 1 terminal on CPX Crickit (CPX and FeatherWing are different)""" -CPX_DRIVE2 = const(43) -"""Drive 2 terminal on CPX Crickit""" -CPX_DRIVE3 = const(12) -"""Drive 3 terminal on CPX Crickit""" -CPX_DRIVE4 = const(13) -"""Drive 4 terminal on CPX Crickit""" - -FEATHER_DRIVE1 = const(13) -"""Drive 1 terminal on Crickit FeatherWing (CPX and FeatherWing are different)""" -FEATHER_DRIVE2 = const(12) -"""Drive 2 terminal on Crickit FeatherWing""" -FEATHER_DRIVE3 = const(43) -"""Drive 3 terminal on Crickit FeatherWing""" -FEATHER_DRIVE4 = const(42) -"""Drive 4 terminal on Crickit FeatherWing""" - -_DRIVE_SET = set((CPX_DRIVE1, CPX_DRIVE2, CPX_DRIVE3, CPX_DRIVE4)) - -_PWM_SET = _MOTOR_SET | _SERVO_SET | _DRIVE_SET - -TOUCH1 = const(4) -"""Capacitive Touch 1 terminal""" -TOUCH2 = const(5) -"""Capacitive Touch 2 terminal""" -TOUCH3 = const(6) -"""Capacitive Touch 3 terminal""" -TOUCH4 = const(7) -"""Capacitive Touch 4 terminal""" - -_TOUCH_SET = set((TOUCH1, TOUCH2, TOUCH3, TOUCH4)) - -NEOPIXEL = 20 -"""NeoPixel terminal. -On the CPX Crickit board, the NeoPixel terminal is by default controlled by CPX pin A1, -and is not controllable by this library. (There is a jumper to override this.) -Instead, use the regular NeoPixel library and specify ``board.A1`` as the pin. -On the Crickit FeatherWing, the NeoPixel terminal is set up to be controlled by -the Crickit board. -""" diff --git a/docs/api.rst b/docs/api.rst index 42e5341..cc8689a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,8 +4,5 @@ .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) .. use this format as the module name: "adafruit_foo.foo" -.. automodule:: adafruit_crickit.terminals - :members: - -.. automodule:: adafruit_crickit.crickit +.. automodule:: adafruit_crickit :members: diff --git a/docs/conf.py b/docs/conf.py index f237bbe..1daa9fb 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,7 @@ 'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} # Libraries we depend on but don't need for generating docs. -autodoc_mock_imports = [] +autodoc_mock_imports = ['board', 'busio', 'micropython', 'adafruit_seesaw', 'adafruit_motor'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/examples/crickit_continuous_servo_simpletest.py b/examples/crickit_continuous_servo_simpletest.py index 8a5d53f..c08e9ba 100644 --- a/examples/crickit_continuous_servo_simpletest.py +++ b/examples/crickit_continuous_servo_simpletest.py @@ -1,9 +1,6 @@ # Crickit library demo - Continuous servo -from adafruit_crickit.terminals import SERVO1 -from adafruit_crickit.crickit import crickit +from adafruit_crickit import crickit -cservo1 = crickit.continuous_servo(SERVO1) - -# Start spinning backwards at half speed. -cservo1.throttle = -0.5 +# Start spinning continuous servo on Servo 1 terminal backwards at half speed. +crickit.continuous_servo_1.throttle = -0.5 diff --git a/examples/crickit_dc_motor_simpletest.py b/examples/crickit_dc_motor_simpletest.py index 0e3b008..3e4dd02 100644 --- a/examples/crickit_dc_motor_simpletest.py +++ b/examples/crickit_dc_motor_simpletest.py @@ -1,13 +1,11 @@ # Crickit library demo - DC motor import time -from adafruit_crickit.terminals import MOTOR1A, MOTOR1B -from adafruit_crickit.crickit import crickit +from adafruit_crickit import crickit -motor = crickit.dc_motor(MOTOR1A, MOTOR1B) -# Run motor forward at full speed and then backward at half speed. +# Run motor on Motor 1 terminals forward at full speed and then backward at half speed. while True: - motor.throttle = 1.0 + crickit.dc_motor_1.throttle = 1.0 time.sleep(1) - motor.throttle = -0.5 + crickit.dc_motor_1.throttle = -0.5 time.sleep(1) diff --git a/examples/crickit_drive_simpletest.py b/examples/crickit_drive_simpletest.py index aff03d2..22279de 100644 --- a/examples/crickit_drive_simpletest.py +++ b/examples/crickit_drive_simpletest.py @@ -2,15 +2,11 @@ import time -from adafruit_crickit.terminals import CPX_DRIVE1 -from adafruit_crickit.crickit import crickit - -# Create general PWM on CPX_DRIVE1 terminal. -drive1 = crickit.pwm_out(CPX_DRIVE1) +from adafruit_crickit import crickit # Turn on Drive 1 for 1 second and then off for 1 second while True: - drive1.fraction = 1.0 + crickit.drive_1.fraction = 1.0 time.sleep(1) - drive1.fraction = 0.0 + crickit.drive_1.fraction = 0.0 time.sleep(1) diff --git a/examples/crickit_multi_example.py b/examples/crickit_multi_example.py index ffd9bb1..9237c05 100644 --- a/examples/crickit_multi_example.py +++ b/examples/crickit_multi_example.py @@ -1,50 +1,42 @@ # This is a mock example showing typical usage of the library for each kind of device. -# crickit is a singleton object -from adafruit_crickit.crickit import crickit - -# Terminals have simple names like SIGNAL1, SERVO2, TOUCH3, MOTOR1A, NEOPIXEL, -# CPX_DRIVE1, and FEATHER_DRIVE2. -# Because the Drive terminals are numbered in reverse on the CPX Crickit vs the FeatherWing Crickit, -# there are separate DRIVE names for CPX and FeatherWing Drive terminals. -from adafruit_crickit.terminals import (SERVO1, - MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B, - CPX_DRIVE1, NEOPIXEL, SIGNAL1, SIGNAL2, TOUCH1) +from adafruit_crickit import crickit # Add this import if using stepper motors. # It will expose constants saying how to step: stepper.FORWARD, stepper.BACKWARD, etc. from adafruit_motor import stepper -servo1 = crickit.servo(SERVO1) -servo1.angle = 90 +# Set servo 1 to 90 degrees +crickit.servo_1.angle = 90 -cservo1 = crickit.continuous_servo(SERVO1) -cservo1.throttle = -0.5 +# Change servo settings. +crickit.servo_1.actuation_range = 135 +crickit.servo_1.set_pulse_widths(min_pulse=850, max_pulse=2100) -motor = crickit.dc_motor(MOTOR1A, MOTOR1B) -motor.throttle = 0.5 +# You can assign a device to a variable to get a shorter name. +servo_2 = crickit.servo_2 +servo_2.throttle = 0 -drive1 = crickit.pwm_out(CPX_DRIVE1) -drive1.fraction = 1.0 +# Run a continous servo on Servo 2 backwards at half speed. +crickit.continuous_servo_2.throttle = -0.5 -# Note: On CPX Crickit, NeoPixel pin is normally connected to A1, not to seesaw, -# so this demo would not control the NeoPixel terminal. +# Run the motor on Motor 1 terminals at half speed. +crickit.dc_motor_1.throttle = 0.5 -# Strip or ring of 8 NeoPixels -neopixels = crickit.neopixel(NEOPIXEL, 8) -neopixels.fill((100, 100, 100)) +# Set Drive 1 terminal to 3/4 strength. +crickit.drive_1.fraction = 0.75 -# Write Signal terminal 1 and read Signal terminal 2. -ss = crickit.seesaw -ss.pin_mode(SIGNAL1, ss.OUTPUT) -ss.pin_mode(SIGNAL2, ss.INPUT) -ss.digital_write(SIGNAL1, True) -print(ss.digital_read(SIGNAL2)) +if crickit.touch_1.value: + print("Touched terminal Touch 1") # A single stepper motor uses up all the motor terminals. -stepper_motor = crickit.stepper_motor(MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B) -stepper_motor.onestep(direction=stepper.FORWARD) +crickit.stepper_motor.onestep(direction=stepper.FORWARD) -touch1 = crickit.touch(TOUCH1) -if touch1.value: - print("Touched terminal Touch 1") +# You can also use the Drive terminals for a stepper motor +crickit.drive_stepper_motor.onestep(direction=stepper.BACKWARD) + +# Note: On CPX Crickit, NeoPixel pin is normally connected to A1, not to seesaw, +# so this part of the demo cannot control the NeoPixel terminal. +# Strip or ring of 8 NeoPixels +crickit.init_neopixel(8) +crickit.neopixel.fill((100, 100, 100)) diff --git a/examples/crickit_neopixel_simpletest.py b/examples/crickit_neopixel_simpletest.py index 4dbc5ed..a3a276e 100644 --- a/examples/crickit_neopixel_simpletest.py +++ b/examples/crickit_neopixel_simpletest.py @@ -3,19 +3,26 @@ # so this demo would not control the NeoPixel terminal. # On the Crickit FeatherWing, the NeoPixel terminal is controlled by seesaw. +# pylint can't figure out "np" can be indexed. +# pylint: disable=unsupported-assignment-operation + import time -from adafruit_crickit.terminals import NEOPIXEL -from adafruit_crickit.crickit import crickit +from adafruit_crickit import crickit # Strip or ring of 8 NeoPixels -neopixels = crickit.neopixel(NEOPIXEL, 8) +crickit.init_neopixel(8) + +crickit.neopixel.fill(0) + +# Assign to a variable to get a short name and to save time. +np = crickit.neopixel while True: - neopixels.fill(0) + np.fill(0) time.sleep(1) - neopixels[0] = (100, 0, 0) - neopixels[1] = (0, 100, 0) - neopixels[2] = (0, 0, 100) + np[0] = (100, 0, 0) + np[1] = (0, 100, 0) + np[2] = (0, 0, 100) time.sleep(1) - neopixels.fill((100, 100, 100)) + np.fill((100, 100, 100)) time.sleep(1) diff --git a/examples/crickit_servo_simpletest.py b/examples/crickit_servo_simpletest.py index a446ee6..7527601 100644 --- a/examples/crickit_servo_simpletest.py +++ b/examples/crickit_servo_simpletest.py @@ -1,14 +1,11 @@ # Crickit library demo - servos import time -from adafruit_crickit.terminals import SERVO1 -from adafruit_crickit.crickit import crickit - -servo1 = crickit.servo(SERVO1) +from adafruit_crickit import crickit # Move servo back and forth 180 degrees. while True: - servo1.angle = 0 + crickit.servo_1.angle = 0 time.sleep(1) - servo1.angle = 180 + crickit.servo_1.angle = 180 time.sleep(1) diff --git a/examples/crickit_signal_simpletest.py b/examples/crickit_signal_simpletest.py index 486392a..7783717 100644 --- a/examples/crickit_signal_simpletest.py +++ b/examples/crickit_signal_simpletest.py @@ -1,14 +1,13 @@ # Crickit library demo - Signal terminals -from adafruit_crickit.terminals import SIGNAL1, SIGNAL2 -from adafruit_crickit.crickit import crickit +from adafruit_crickit import crickit # Write Signal terminal 1 and read Signal terminal 2. ss = crickit.seesaw -ss.pin_mode(SIGNAL1, ss.OUTPUT) -ss.pin_mode(SIGNAL2, ss.INPUT) +ss.pin_mode(crickit.SIGNAL1, ss.OUTPUT) +ss.pin_mode(crickit.SIGNAL2, ss.INPUT) -ss.digital_write(SIGNAL1, True) -print(ss.digital_read(SIGNAL2)) +ss.digital_write(crickit.SIGNAL1, True) +print(ss.digital_read(crickit.SIGNAL2)) diff --git a/examples/crickit_stepper_motor_simpletest.py b/examples/crickit_stepper_motor_simpletest.py index 95053ea..de98fad 100644 --- a/examples/crickit_stepper_motor_simpletest.py +++ b/examples/crickit_stepper_motor_simpletest.py @@ -1,16 +1,13 @@ # Crickit library demo - stepper motor import time -from adafruit_crickit.terminals import MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B -from adafruit_crickit.crickit import crickit -# A single stepper motor uses up all the motor terminals. - -stepper = crickit.stepper_motor(MOTOR1A, MOTOR1B, MOTOR2A, MOTOR2B) +from adafruit_crickit import crickit +from adafruit_motor import stepper # Step motor forward and then backward. while True: - stepper.onestep(direction=stepper.FORWARD) + crickit.stepper_motor.onestep(direction=stepper.FORWARD) time.sleep(1) - stepper.onestep(direction=stepper.BACKWARD) + crickit.stepper_motor.onestep(direction=stepper.BACKWARD) time.sleep(1) diff --git a/examples/crickit_touch_simpletest.py b/examples/crickit_touch_simpletest.py index 426ae6c..a3a6a76 100644 --- a/examples/crickit_touch_simpletest.py +++ b/examples/crickit_touch_simpletest.py @@ -1,13 +1,10 @@ # Crickit library demo - Capacitive touch import time -from adafruit_crickit.terminals import TOUCH1 -from adafruit_crickit.crickit import crickit -# Create touch object. -touch1 = crickit.touch(TOUCH1) +from adafruit_crickit import crickit while True: - if touch1.value: + if crickit.touch_1.value: print("Touched terminal Touch 1") time.sleep(0.25)