Introductory Examples - Adafruit Crickit with CPB

The Adafruit Crickit for Circuit Playground Bluefruit is a baseboard providing motor drivers and other useful I/O for a Adafruit Circuit Playground Bluefruit. It communicates with the Bluefruit using the I2C bus. The follow samples demonstrate uses of the Crickit hardware using adafruit_crickit library. For more detailed notes on the library, please see Quick Reference Guide - Adafruit Crickit with CPB.

Pulsing Motor Example

This sketch pulses a small DC motor on and off using the Crickit motor channel 1.

Direct download: pulse_motor.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
# crickit/pulse_motor.py

# Demonstrate timed activation of a DC motor connected to the Crickit motor driver.

# Related documentation:
# http://docs.circuitpython.org/projects/crickit/en/latest/
# http://docs.circuitpython.org/projects/seesaw/en/latest/
# https://learn.adafruit.com/adafruit-crickit-creative-robotic-interactive-construction-kit

# ----------------------------------------------------------------
# Import standard Python modules.
import time, math

# Import the Crickit interface library.
from adafruit_crickit import crickit

# ----------------------------------------------------------------
# Enter the main event loop.

while True:

    crickit.dc_motor_1.throttle = 1 # full speed forward
    time.sleep(2)

    crickit.dc_motor_1.throttle = 0 # stop
    time.sleep(2)

Toggling Motor Example

This sketch uses touch control to turn a small DC motor on and off using the Crickit motor channel 1.

Direct download: toggle_motor.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
# crickit/toggle_motor.py

# Demonstrate touch-activated control of a DC motor connected to the Crickit motor driver.

# Related documentation:
# http://docs.circuitpython.org/projects/crickit/en/latest/
# http://docs.circuitpython.org/projects/seesaw/en/latest/
# https://learn.adafruit.com/adafruit-crickit-creative-robotic-interactive-construction-kit

# ----------------------------------------------------------------
# Import standard Python modules.
import time, math

# Import the Crickit interface library.
from adafruit_crickit import crickit

# ----------------------------------------------------------------
# Global state
moving = False
touched_last = False

# ----------------------------------------------------------------
# Enter the main event loop.

while True:

    # Check whether the touch state changed.
    touched_now = crickit.touch_1.value

    if touched_now and not touched_last:
        # starting new touch, toggle motor state
        moving = not moving
        crickit.dc_motor_1.throttle = 1 if moving else 0

    # Save the current touch state.
    touched_last = touched_now

Hobby Servo Example

This sketch sweeps a hobby servo back and forth using the Crickit servo channel 1.

Direct download: servo_sweep.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
# crickit/servo_sweep.py

# Demonstrate oscillating movement of a hobby servo.  The Crickit supports up to
# four hobby servos; please note that the control line should be oriented toward
# the outside edge of the board, adjaced to the number marking.  On our micro
# servos, this wire is orange.

# Related documentation:
# http://docs.circuitpython.org/projects/crickit/en/latest/
# http://docs.circuitpython.org/projects/seesaw/en/latest/
# https://learn.adafruit.com/adafruit-crickit-creative-robotic-interactive-construction-kit

# ----------------------------------------------------------------
# Import the standard Python time functions.
import time

# Import the Crickit interface library.
from adafruit_crickit import crickit

# ----------------------------------------------------------------
# Begin the main processing loop.
while True:
    print("Starting cycle.")
    for angle in range(0, 180, 5):
        crickit.servo_1.angle = angle
        time.sleep(0.02)

    print("Reversing cycle.")
    for angle in range(180, 0, -5):
        crickit.servo_1.angle = angle
        time.sleep(0.02)

    print("Pausing.")
    time.sleep(0.5)
    

Tap Tempo Example

This sketch uses touch control to synchronize blinking NeoPixels. Please note that the CPB itself can also detect touch inputs, so the essence of the example could be adapted to work without the Crickit.

Direct download: tap_tempo.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
# crickit/tap_tempo.py

# Demonstrate synchronization of rhythmic output to touch activations on the
# Crickit.  Note: the CPB itself can also detect touch inputs, so the essence of
# the example could be adapted to work without the Crickit.

# Related documentation:
# http://docs.circuitpython.org/projects/crickit/en/latest/
# http://docs.circuitpython.org/projects/seesaw/en/latest/
# https://learn.adafruit.com/adafruit-crickit-creative-robotic-interactive-construction-kit

# ----------------------------------------------------------------
# Import standard Python modules.
import time, math

# Import the Crickit interface library.
from adafruit_crickit import crickit

# Import the board-specific input/output library for the CPB itself
from adafruit_circuitplayground import cp

# Configure the NeoPixel LED array for bulk update.
cp.pixels.auto_write = False

# Turn down the NeoPixel brightness, otherwise it is somewhat blinding.
cp.pixels.brightness = 0.5

# ----------------------------------------------------------------
# Each instance of the following class creates an rhythmic color display on a
# single NeoPixel.  The instance should be polled periodically from the event
# loop to update the display.

class NeoOscillator:
    def __init__(self, led_index):
        self.led = led_index
        self.phase = 0                    # oscillator phase angle between 0 and 2 pi
        self.phase_rate = 0.5 * math.pi   # oscillation rate in phase/second
        self.intensity = 0
        
    def set_tempo(self, bpm):
        """Set the oscillator tempo in beats per minute."""
        # (beats/minute) * (minutes/second) * (radians/beat) -> radians/second
        self.phase_rate = bpm * (1.0/60.0) * (2*math.pi)

    def tap_event(self):
        """Process a synchronizing tap event by adjusting the phase rate."""

        # The output has been set up so the perceived start of the beat is in the middle of the phase
        # cycle.  Calculate the error in phase and apply feedback to the phase rate.
        # If the oscillator is running ahead of the tap, slow down the rate, else speed it up.
        phase_error = math.pi - self.phase
        self.phase_rate += 0.25 * phase_error
        
    def poll(self, elapsed):
        """Polling function to be called as frequently as possible from the event loop
        with the nanoseconds elapsed since the last cycle."""

        # advance the phase based on the elapsed time
        self.phase = math.fmod(self.phase + self.phase_rate * (1e-9*elapsed), 2*math.pi)

        # calculate new RGB values
        self.intensity = min(max(int(-255*math.sin(self.phase)), 0), 255)
        cp.pixels[self.led] = (self.intensity, self.intensity, self.intensity)

# ----------------------------------------------------------------
# Each instance of the following class processes touch inputs from a single
# capacitive touch input on the Crickit.  The instance should be polled
# periodically from the event loop to update the state.

class CrickitTouch:
    def __init__(self, touch_input):
        self.input  = touch_input  # the object to consult for touch state
        self.state  = False        # most recently observed input state

        # flags which are set for just one polling cycle to indicate events.
        self.tapped = False

    def poll(self, elapsed):
        """Polling function to be called as frequently as possible from the event loop
        with the nanoseconds elapsed since the last cycle."""

        # Reset any transient flags.
        self.tapped = False

        # Read the touch input and detect events.
        new_input = self.input.value
        if new_input != self.state:

            if new_input is True:
                self.tapped = True
                print("Tapped.")

            self.state = new_input

# ----------------------------------------------------------------
# Global state
moving = False
touched_last = False
last_timestamp = time.monotonic_ns()

# Initialize the oscillators and slightly perturb the initial tempos.
oscillators = [NeoOscillator(led) for led in range(10)]
for n, osc in enumerate(oscillators):
    osc.set_tempo(60 + 0.2 * n)

# Initialize the touch inputs.
touches = [CrickitTouch(crickit.touch_1), CrickitTouch(crickit.touch_4)]

# ----------------------------------------------------------------
# Enter the main event loop.

while True:

    # Calculate the time elapsed since last cycle (in nanoseconds).
    now = time.monotonic_ns()
    elapsed = now - last_timestamp
    last_timestamp = now

    # Update the oscillation outputs.
    for osc in oscillators:
        osc.poll(elapsed)

    # Send new data to the physical LED chain.
    cp.pixels.show()

    # Update the touch detectors.
    for touch in touches:
        touch.poll(elapsed)

    # If tapped, apply a phase correction to a set of oscillators.
    if touches[0].tapped:
        for osc in oscillators[0:5]:
            osc.tap_event()
            # print(f"phase: {osc.phase} rate: {osc.phase_rate} intensity: {osc.intensity}")
            
    if touches[1].tapped:
        for osc in oscillators[5:]:
            osc.tap_event()

Soft Sensor Example

This sketch reads an analog voltage from Signal 1 as a demonstration of connecting a soft sensor. A similar example without the Crickit can be seen on Soft Sensing Examples - Adafruit Circuit Playground Bluefruit.

Direct download: soft_analog.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
# soft_analog.py

# Demonstrate measurement of an analog soft sensor input using the Crickit.
# This is intended to attach to an external soft touch sensor hand-fabricated
# using conductive fabric and Velostat.  The electrical resistance of the sensor
# varies with pressure.

# The wiring for this is as follows:
#  1. One half of sensor connected to GND (either half).
#  2. Other half of sensor connected to Signal 1.
#  3. External resistor connects between Signal 1 and 3.3V.

# This example uses three pins from the Signal I/O section of the Cricket:
# Signal 1, +3.3V, and GND.  An external resistor (typically 10K) should be
# connected between the 3.3V pin and Signal 1, and the conductive sensor between
# Signal 1 and GND.  The resistor will provide a small current to create a
# voltage across the sensor which will vary with pressure.  E.g., it will form
# one leg of a voltage divider with the sensor.

# As mechanical pressure is applied, the sensor resistance drops along with the
# voltage across the sensor.  Please note that the sensor voltage follows an
# inverse logic: when not pressed, the input value will be midrange, and when
# pressed, it will drop (possibly to zero).

# ----------------------------------------------------------------
# Import the standard Python time functions.
import time

# Import the Crickit interface library.
from adafruit_crickit import crickit

# Calculate the scaling coefficient to translate the raw analog value into volts.
scaling = 3.3 / (2**10)

# ----------------------------------------------------------------
# Begin the main processing loop.
while True:

    # Read the integer sensor value and scale it to a value in Volts.
    volts = crickit.seesaw.analog_read(crickit.SIGNAL1) * scaling
    
    # Every handmade sensor will have different properties, so the
    # interpretation of the voltage value will usually need to be individually
    # calibrated.  One way to accomplish this is by measuring the voltage
    # response under different conditions, then applying additional scaling and
    # offset to produce a normalized signal (possibly inverted).  For example,
    # if the observed voltage ranges between 1.4 and 0.1 Volts, the input signal
    # could be normalized to a [0,1] range as follows:
    pressure = (1.4 - volts) / (1.4 - 0.1)

    # Print the voltage reading and normalized value on the console.
    print(f"({volts}, {pressure})")
    
    # Limit the rate of the main loop.
    time.sleep(0.1)