Prototyping the Wind Chime Unit

During class Elle and I began making pom poms and experimenting with different sizes and lengths while Helen continued to flesh out the code. We decided to make each wind chime unit personal to each team member using different color combinations, bells, and beads to accent the pendulums. We met with Garth & Olivia to share some important concerns that Elle brought up, such as how to keep the pendulums from getting tangled together and how using different bells might be to our advantage. After class, I moved forward with creating the first wind chime unit for Helen.

I experimented with different lengths and found that keeping the pom poms on the larger side helped the pendulums “bounce” off one another and make the twirling action of the wind chime unit more dynamic. By keeping three of the pendulums long and the other three short, it made the movement and sound of the bells energizing. All together, I think it proved to be an excellent and successful prototype!

Testing out the wind chime unit by hand to test out movement and sound.

Once the prototype proved successful, Helen and I met up and used the table top stand she created to hold the servo unit upside down. We did some sample tests after assembling and tested the prototype again.

Attaching the wind chimes to the table top unit and sampling out code.

Moving Forward

  1. For Helen’s wind chimes I am going to trim down the pom poms a little bit so they have more room to twirl around.
  2. For my wind chime unit I am going to experiment with different types of bells and find another way to stagger the lengths of the pendulums to add a bit of individuality and flair 💕

Code

"""
Project 1: Ambient Proxy Body

Team Pom Pom
Helen Yu (heleny1), Celia Kasberg (ckasberg), Elle Smith

Written by Helen Yu
Last Updated: 3/28/21

Summary: As your partner fidgets in their chair, your wind chimes spin 
in reaction to your partner's presence. Small and slow movements trigger 
a sweeping motion in the servo. Fast and sharp movements trigger a stepping 
sweep in the servo.

Inputs: Accelerometer
Outputs: Hobby Servo on SD A5
"""

# ----------------------------------------------------------------
# Import any needed standard Python modules.
import time, math, sys

# Import the board-specific input/output library.
from adafruit_circuitplayground import cp

# Import the low-level hardware libraries.
import board
import digitalio
import analogio
import pwmio

# Import the Adafruit helper library.
from adafruit_motor import servo

# Import the runtime for checking serial port status.
import supervisor

# ----------------------------------------------------------------
# Initialize hardware.

# Create a PWMOut object on pad SDA A5 to generate control signals.
pwm = pwmio.PWMOut(board.A5, duty_cycle=0, frequency=50)

# Create a Servo object which controls a hobby servo using the PWMOut.
actuator = servo.Servo(pwm, min_pulse=50, max_pulse=3000)

# ----------------------------------------------------------------
# Initialize global variables for the main loop.

# The remote move state can be updated via serial port messages.
remote_moves = [0, 0, 0, 0, 0]

# Measure the time since the last remote move message, and reset after a period without data.
remote_moves_timer = False

# Convenient time constant expressed in nanoseconds.
second = 1000000000

# Integer time stamp for the next console output.
sensing_timer = time.monotonic()

# Integer time stamp for next behavior activity to begin.
next_activity_time = time.monotonic_ns() + 2 * second

# Flag to trigger motion.
sweep_slow = False
sweep_fast = False

phase_angle = 0.0
phase_rate  = 2*math.pi / 6.0  # one cycle per six seconds, in radians/second

# Integer time stamp for next servo update.
next_servo_update = time.monotonic_ns()

# The serial port output rate is regulated using the following timer variables.
serial_timer    = 0.0
serial_interval = 0.5

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

    # Read the current integer clock.
    now = time.monotonic()

    # Measure and define local acceleration
    x, y, z = cp.acceleration
    l_x = abs(int(x))
    l_y = abs(int(y))
    l_z = abs(int(z))
    local_moves = l_x, l_y, l_z

    # Check the serial input for new line of remote data
    if supervisor.runtime.serial_bytes_available:
        line = sys.stdin.readline()
        tokens = line.split()
        if len(tokens) == 5:
            try:
                remote_moves = [int(token) > 0 for token in tokens]
                remote_move_timer = 4.0
            except ValueError:
                pass

    #---- periodic console output -----------------------------------
    # Poll the time stamp to decide whether to emit console output.
    if now >= sensing_timer:
        sensing_timer += 100000000 #0.1sec

    if any(local_moves):
        remote_moves_timer = now + 4000000000 # 4 sec timeout

    if now >= serial_timer:
        serial_timer += serial_interval
        moves = ["1" if 1 < l_x < 3 else "0", "1" if l_y &gt; 1 else "0", "1" if 1 < l_z < 3 else "0", "1" if l_x &gt; 3 else "0", "1" if l_z &gt; 3 else "0"]
        print(" ".join(moves))

    if any(remote_moves):
        # Check whether there was any remote movement
        if remote_moves[0] or remote_moves[2]:
            if remote_moves[1]:
                sweep_slow = True
                print("Entering slow cycle.")
        
        if remote_moves[3] or remote_moves[4]:
            if remote_moves[1]:
                sweep_fast = True
                print("Entering fast cycle")
        
        # If a slow movement has been received, sweep twice at a constant speed
        elif sweep_slow is True: #new code moves these if statements out of the if(any local_moves) statement
            for angle in range(0, 180, 3):
                actuator.angle = angle
                time.sleep(0.02)
            print("Reversing slow sweep.")
            for angle in range(180, 0, -3):
                actuator.angle = angle
                time.sleep(0.02)
            print("End of slow cycle")
            sweep_slow = False
        
        # If a fast movement has been received, sweep twice in a stepping motion
        elif sweep_fast is True:
            for angle in range(0, 180, 10):
                actuator.angle = angle
                time.sleep(0.1)
            print("Reversing fast sweep.")
            for angle in range(180, 0, -10):
                actuator.angle = angle
                time.sleep(0.1)
            print("End of fast cycle")
            sweep_fast = False
        
        remote_moves = [False]*5

    #---- periodic servo motion commands ----------------------------
    # If the time has arrived to update the servo command signal:
    if now &gt;= next_servo_update:
        next_servo_update += 20000000  # 20 msec in nanoseconds (50 Hz update)