Flying Trapeze

Feel the excitement, the thrill, the rushing air beneath your wings - without having to leave home or run any risk of injury or sweating!

This Flying Trapeze bot uses a servo claw to grip onto a willing gymnast, and release it into the air when the detected acceleration has reached a sufficient peak!

Parts List

The servo claw we used had a built in metal gear servo that could draw significant current when actuated! We found a 4xAA battery pack with good NiMH batteries would last a while but 3xNiMH couldn't power it sufficiently

Adafruit CRICKIT for Circuit Playground Express

PRODUCT ID: 3093
Sometimes we wonder if robotics engineers ever watch movies. If they did, they'd know that making robots into slaves always ends up in a robot rebellion. Why even go down that...
$29.95
IN STOCK

Circuit Playground Express

PRODUCT ID: 3333
Circuit Playground Express is the next step towards a perfect introduction to electronics and programming. We've taken the original Circuit Playground Classic and...
$24.95
IN STOCK

4 x AA Battery Holder with On/Off Switch

PRODUCT ID: 830
Make a nice portable power pack with this 4 x AA battery holder. It fits any alkaline or rechargeable AA batteries in series. There's a snap on cover and an on/off switch which can...
$2.95
IN STOCK

Male DC Power adapter - 2.1mm plug to screw terminal block

PRODUCT ID: 369
If you need to connect a battery pack or wired power supply to a board that has a DC jack - this adapter will come in very handy! There is a 2.1mm DC plug on one end, and a screw...
$2.00
IN STOCK

Wiring

Boot.py

Since we want to have the ability to data log the accelerometer, we need to put the CPX into 'filesystem write mode' - this boot.py will let you use the switch on the CPX to select whether you want to log data or go into trapeze-release mode

# Save as boot.py to turn on/off datalogging capability

import digitalio
import board
import storage

switch = digitalio.DigitalInOut(board.D7)  # For Circuit Playground Express
switch.direction = digitalio.Direction.INPUT
switch.pull = digitalio.Pull.UP

# If the switch pin is connected to ground CircuitPython can write to the drive
storage.remount("/", switch.value)

CircuitPython Code

Our Python code is dual use. You can use the slide switch to select whether you want to log the accelerometer data to the onboard storage. If you do, its easy to plot it and see the magnitude of the forces on your trapeze artist!

We mostly used data log mode to calibrate how 'hard' we required the person to push the trapeze to make the servo release the gymnast-stand-in.

We also have two buttons on the CPX we use for different tasks. In logging mode, you use button A to turn on/off logging. The red LED blinks to let you know logging is occuring. In trapeze mode, A and B let you manually open/close the servo gripper so you can have it grab the gymnasts head. Hey life's tough all around!

Finally, if we're in trapeze mode, we look for when we're at the beginning of a swing, that's when the Z axis acceleration drops below 3 m/s2 and the Y axis has positive acceleration (we used the data log info to figure this out!) If so, the next time we reach max-acceleration, at the lowest point of the swing, we start opening the gripper, which takes a little time so that when we are at the end of the swing, it's opened enough for the gymnast to be released!

We change the NeoPixel colors to help debug, by flashing when we reach the different sensor states, since we don't have wireless data transfer on the CPX.

import time
from digitalio import DigitalInOut, Direction, Pull
import adafruit_lis3dh
from busio import I2C
from adafruit_seesaw.seesaw import Seesaw
from adafruit_seesaw.pwmout import PWMOut
from adafruit_motor import servo
import neopixel
import board

# create accelerometer
i2c1 = I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c1, address=0x19)
lis3dh.range = adafruit_lis3dh.RANGE_8_G

# Create seesaw object
i2c = I2C(board.SCL, board.SDA)
seesaw = Seesaw(i2c)

# Create servo object
pwm = PWMOut(seesaw, 17)    # Servo 1 is on s.s. pin 17
pwm.frequency = 50          # Servos like 50 Hz signals
my_servo = servo.Servo(pwm) # Create my_servo with pwm signal

# LED for debugging
led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT

# two buttons!
button_a = DigitalInOut(board.BUTTON_A)
button_a.direction = Direction.INPUT
button_a.pull = Pull.DOWN
button_b = DigitalInOut(board.BUTTON_B)
button_b.direction = Direction.INPUT
button_b.pull = Pull.DOWN

# NeoPixels!
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=1)
pixels.fill((0,0,0))

#################### log file for logging mode!
logfile = "/log.csv"
# check that we could append if wanted to
try:
    fp = None
    fp = open(logfile, "a")
    print("File system writable!")
# pylint: disable=bare-except
except:
    print("Not logging, trapeeze mode!")

# If we log, have some helper variables
logging = False
logpoints = 0
outstr = ""

# When its time to release the trapeze
release = False

while True:
    if button_a.value: # A pressed
        while button_a.value:	# wait for release
            pass
        if fp:  # start or stop logging
            logging = not logging
            print("Logging: ", logging)
            time.sleep(0.25)
        else:
            my_servo.angle = 180      # open

    if button_b.value: # B pressed
        while button_b.value:	# wait for release
            pass
        my_servo.angle = 0      # close

    x, y, z = lis3dh.acceleration

    # To keep from corrupting the filesys, take 25 readings at once
    if logging and fp:
        outstr += "%0.2F, %0.2F, %0.2F\n" % (x, y, z)
        logpoints += 1

        if logpoints > 25:
            led.value = True
            #print("Writing: "+outstr)
            fp.write(outstr+"\n")
            fp.flush()
            led.value = False
            logpoints = 0
    else:
        # display some neopixel output!
        if z > 20:
            # MAXIMUM EFFORT!
            pixels.fill((0, 255, 0))
            if release:
                my_servo.angle = 180

        elif z < 3 and y > 0: # means at the outer edge
            release = True
            # flash red when we peak
            pixels.fill((255, 0, 0))

        else:
            pixels.fill((0,0,int(abs(z)*2)))

    time.sleep(0.05)

For the curious, our data log file is here!

This guide was first published on May 16, 2018. It was last updated on May 16, 2018. This page (Flying Trapeze) was last updated on Dec 12, 2018.