Code the CPX and CRICKIT for Puppeteering

Setup the CPX and CRICKIT

The Circuit Playground Express (CPX) paired with the CRICKIT is a powerful, yet simple to use combination for building animatronics! To get started, you'll want to set up the CPX for use with CircuitPython by following this guide. When you're ready, and can upload code to the board return here.

To use the CRICKIT with the CPX, follow the steps listed here to install the special build of CircuitPython, as well as the latest library bundle.

CircuitPython Code

Puppeteering Mode

A really fun, satisfying way to code the animatronic hand is in an interactive, puppeteering mode. We'll set things up so when you touch any of the four capacitive touch pads on the CRICKIT, the associated servo will rotate and actuate its connected finger.

Adafruit suggests using the Mu editor to edit your code and have an interactive REPL in CircuitPython. You can learn about Mu and installation in this tutorial.

The full code is included below -- you can copy and paste that into Mu and save it to your CPX to get it all working. After the full code is an explanation of how the various code snippets work.

#  Animatronic Hand
#  CPX with CRICKIT and four servos
#  touch four cap pads to close the fingers

import board
from digitalio import DigitalInOut, Direction, Pull
from adafruit_crickit import crickit

#################### CPX switch
# use the CPX onboard switch to turn on/off (helps calibrate)
switch = DigitalInOut(board.SLIDE_SWITCH)
switch.direction = Direction.INPUT
switch.pull = Pull.UP

#################### 4 Servos!
servos = (crickit.servo_1, crickit.servo_2, crickit.servo_3, crickit.servo_4)
for servo in servos:
    servo.angle = 180 # starting angle, open hand

#################### 4 Touch sensors!
touches = (crickit.touch_1, crickit.touch_2, crickit.touch_3, crickit.touch_4)

cap_state = [False, False, False, False]
cap_justtouched = [False, False, False, False]
cap_justreleased = [False, False, False, False]

curl_finger = [False, False, False, False]
finger_name = ['Index', 'Middle', 'Ring', 'Pinky']

while True:
    if not switch.value:  # the CPX switch is off, so do nothing
        continue
    # Check the cap touch sensors to see if they're being touched
    for i in range(4):
        cap_justtouched[i] = False
        cap_justreleased[i] = False

        if touches[i].value:
            #print("CT" + str(i + 1) + " touched!")
            if not cap_state[i]:
                cap_justtouched[i] = True
                print("%s finger bent." % finger_name[i])
                servos[i].angle = 0
            # store the fact that this pad is touched
            cap_state[i] = True

        else:
            if cap_state[i]:
                cap_justreleased[i] = True
                print("%s finger straightened." % finger_name[i])
                servos[i].angle = 180
                # print("CT" + str(i + 1) + " released!")
            # store the fact that this pad is NOT touched
            cap_state[i] = False

        if cap_justtouched[i]:
            curl_finger[i] = not curl_finger[i]

Here are the different sections of the code, and how they work.

Library Imports

First, we'll import a few libraries. DigitalInOut, Direction, and Pull are imported from digitalio in order to allow us to read the slide switch built into the CPX.

The crickit library is imported from adafruit_crickit to allow us to use the CRICKIT's onboard seesaw co-processor to read capacitive pads, to write out command signals to servos, and to communicate over the SDA and SCL pins between the CPX and the CRICKIT.

We also import the board library, which gives us convenient definitions for objects on the CPX that we can call.

Download: file
import board
from digitalio import DigitalInOut, Direction, Pull
from adafruit_crickit import crickit

Slide Switch

We'll set up the slide switch built onto the CPX, name it 'switch', setting it's direction to INPUT, and using the built-in pullup resistor.

Download: file
switch = DigitalInOut(board.SLIDE_SWITCH)
switch.direction = Direction.INPUT
switch.pull = Pull.UP

Servo Setup

We'll created a variable list called 'servos' that sets up our four servos. These are called out by their CRICKIT servo port names (1, 2, 3, 4). They are set to be controlled with pulse width modulation (PWM) with a PWM frequency of 50, and then moved to an angle of 180.

Download: file
servos = (crickit.servo_1, crickit.servo_2, crickit.servo_3, crickit.servo_4)
for servo in servos:
    servo.angle = 180 # starting angle, open hand

Capacitive Touch Setup

Next, you'll set up the capacitive touch pads. You'll create some variable lists to help with the logic of registering touches to the cap pads and moving the servos when pads are touched or released.

We also have a variable list with the friendly names of the fingers to use when debugging with print statements.

Download: file
touches = (crickit.touch_1, crickit.touch_2, crickit.touch_3, crickit.touch_4)

cap_state = [False, False, False, False]
cap_justtouched = [False, False, False, False]
cap_justreleased = [False, False, False, False]

curl_finger = [False, False, False, False]
finger_name = ['Index', 'Middle', 'Ring', 'Pinky']

Main Loop

With the setup complete, now we get into the bulk of the program, which runs over and over. This is everything that follows the while True: line.

Switch Check

The first thing that happens is we check the state of the CPX slide switch with the if not switch.value: line. In CircuitPython, this is a concise way of saying "if the switch value is 0 (which is the reading when the switch is to the right), do nothing and continue" When the switch is to the left, the value is 1 and we to proceed with the rest of the code.

Read the Capacitive Pads, Move Servos

Here we'll loop through four times, checking each capacitive pad to see if its value is above the touch threshold. 

When the values read are greater than the threshold, we check to see if we have already been touching that pad by querying the value of the cap_state[] variable. By setting this state to change when the cap pads are released, we can have the servos curl the fingers when pads are first touched, hold them in a curl while being touched, and uncurl them when the pads are released.

Download: file
    # Check the cap touch sensors to see if they're being touched
    for i in range(4):
        cap_justtouched[i] = False
        cap_justreleased[i] = False

        if touches[i].value:
            #print("CT" + str(i + 1) + " touched!")
            if not cap_state[i]:
                cap_justtouched[i] = True
                print("%s finger bent." % finger_name[i])
                servos[i].angle = 0
            # store the fact that this pad is touched
            cap_state[i] = True

        else:
            if cap_state[i]:
                cap_justreleased[i] = True
                print("%s finger straightened." % finger_name[i])
                servos[i].angle = 180
                # print("CT" + str(i + 1) + " released!")
            # store the fact that this pad is NOT touched
            cap_state[i] = False

        if cap_justtouched[i]:
            curl_finger[i] = not curl_finger[i]

That's the full code breakdown for the interactive mode of the animatronic hand -- now we'll power up the system we can have fun playing with it!

Servo motors can draw a lot of current! It's possible that your CPX will restart if you draw too much current by jamming on all four cap touch pads at once, causing all four servos to move at the same moment.
This guide was first published on May 23, 2018. It was last updated on May 23, 2018. This page (Code the CPX and CRICKIT for Puppeteering) was last updated on Dec 05, 2019.