Choreographic Intent:
I created a pattern of oscillation to the main line of the song “I will always love you” by Whitney Houston. My main intent was to recreate the beat of this song using the sound of the servo motions.
Code:
print(“Starting servo_sweep script.”)
import math, time
import board
import pwmio
——————————————————————————–
class Servo():
def init(self, pin, pulse_rate=50):
self.pwm = pwmio.PWMOut(board.GP0, duty_cycle=0, frequency=pulse_rate)
# Save the initialization arguments within the object for later reference.
self.pin = pin
self.pulse_rate = pulse_rate
# Initialize the other state variables.
self.target = None # target angle; None indicates the "OFF" state
self.debug = False # flag to control print output
def write(self, angle):
# calculate the desired pulse width in units of seconds
if angle is None:
pulse_width = 0.0
else:
pulse_width = 0.001 + angle * (0.001 / 180.0)
# calculate the duration in seconds of a single pulse cycle
cycle_period = 1.0 / self.pulse_rate
# calculate the desired ratio of pulse ON time to cycle duration
duty_cycle = pulse_width / cycle_period
# convert the ratio into a 16-bit fixed point integer
duty_fixed = int(2**16 * duty_cycle)
# limit the ratio range and apply to the hardware driver
self.pwm.duty_cycle = min(max(duty_fixed, 0), 65535)
# save the target value in the object attribute (i.e. variable)
self.target = angle
# if requested, print some diagnostics to the console
if self.debug:
print(f"Driving servo to angle {angle}")
print(f" Pulse width {pulse_width} seconds")
print(f" Duty cycle {duty_cycle}")
print(f" Command value {self.pwm.duty_cycle}\n")
——————————————————————————–
def linear_move(servo, start, end, speed=60, update_rate=50):
# Calculate the number of seconds to wait between target updates to allow
# the motor to move.
# Units: seconds = 1.0 / (cycles/second)
interval = 1.0 / update_rate
# Compute the size of each step in degrees.
# Units: degrees = (degrees/second) * second
step = speed * interval
# Output the start angle once before beginning the loop. This guarantees at
# least one angle will be output even if the start and end are equal.
angle = start
servo.write(angle)
# Loop once for each incremental angle change.
while angle != end:
time.sleep(interval) # pause for the sampling interval
# Update the target angle. The positive and negative movement directions
# are treated separately.
if end >= start:
angle += step; # movement in the positive direction
if angle > end:
angle = end # end at an exact position
else:
angle -= step # movement in the negative direction
if angle < end:
angle = end # end at an exact position
servo.write(angle) # update the hardware
——————————————————————————–
def ringing_move(servo, q_d, q=0.0, qd=0.0, k=4math.pimath.pi, b=2.0,
update_rate=50, duration=2.0, debug=False):
interval = 1.0 / update_rate
while duration > 0.0:
# Calculate the acceleration.
# qdd acceleration in angles/sec^2
# k spring constant relating the acceleration to the angular displacement
# b damping constant relating the acceleration to velocity
qdd = k * (q_d - q) - b * qd
# integrate one time step using forward Euler integration
q += qd * interval # position changes in proportion to velocity
qd += qdd * interval # velocity changes in proportion to acceleration
# update the servo command with the new angle
servo.write(q)
# print the output for plotting if requested
if debug:
print(q)
time.sleep(interval)
duration -= interval
——————————————————————————–
Create an object to represent a servo on the given hardware pin.
print(“Creating servo object.”)
servo = Servo(board.GP0)
print(“Starting main script.”)
while True:
# initial pause
time.sleep(2.0)
print("Starting ringing motions.")
#and
ringing_move(servo, 90.0, duration=1)
#i
ringing_move(servo, 45.0, duration=1)
#e
ringing_move(servo, 90.0, duration=1)
print("Starting linear motions.")
#i
linear_move(servo, 0.0, 180.0, speed=45)
#will
ringing_move(servo, 90.0, duration=1)
#al
ringing_move(servo, 45.0, duration=1)
#ways
linear_move(servo, 180.0, 0.0, speed=45)
#love
ringing_move(servo, 90.0, duration=1)
#you
linear_move(servo, 0.0, 180.0, speed=45)
# final pause
time.sleep(2.0)
Leave a Reply
You must be logged in to post a comment.