Synopsis

For this assignment Team Pom Pom tested how the microcontroller’s movement while attached to the chair affected the wind chimes. It was a great success! When Helen moved her chair and sat in it the small movements triggered the wind chimes to move in a slow and jolted motion. When Helen moved her hair from side to side at a faster pace, the wind chime spun around faster in a smooth and controlled spin cycle.

Video Demo

Testing the movements of the chair through MQTT and how it affects the wind chimes.

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 a slow movement has been received, sweep twice at a constant speed
    if sweep_slow is True:
        for angle in range(0, 180, 5):
            actuator.angle = angle
            time.sleep(0.02)
        print("Reversing slow sweep.")
        for angle in range(180, 0, -5):
            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
    if sweep_fast is True:
        for angle in range(0, 180, 10):
            actuator.angle = angle
            time.sleep(0.2)
        print("Reversing fast sweep.")
        for angle in range(180, 0, -10):
            actuator.angle = angle
            time.sleep(0.2)
        print("End of fast cycle")
        sweep_fast = False

    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")

        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)