Once you've finished setting up your Feather RP2040 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download as a zipped folder.
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT import time import board from adafruit_motor import servo from adafruit_pca9685 import PCA9685 import usb_midi import adafruit_midi from adafruit_midi.note_on import NoteOn # MIDI input setup midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], in_channel=0) # i2c PCA9685 setup i2c = board.STEMMA_I2C() pca = PCA9685(i2c) pca.frequency = 50 # create the servo objects and add them to the servos array servos = [servo.Servo(pca.channels[i]) for i in range(16)] # array of midi notes, high to low midi_notes = [83, 81, 79, 77, 76, 74, 72, 71, 69, 67, 65, 64, 62, 60, 59, 57] angle0 = 20 angle1 = 70 # set servos to the same angle on boot # easier to adjust angles of the horns if needed print("setting servos") for i in range(16): s = servos[i] s.angle = angle1 time.sleep(0.05) print("servos set") while True: # msg holds MIDI messages msg = midi.receive() for i in range(16): # iterate through servos array & midi notes array servo = servos[i] note_played = midi_notes[i] # if a noteon msg comes in that matches a note in the midi notes array.. if isinstance(msg, NoteOn) and msg.note == note_played: # print(servo) # print(note_played) # servo moves # angle alternates between angle0 and angle1 if servo.angle <= angle0: servo.angle = angle1 else: servo.angle = angle0 # print(servo.angle)
Upload the Code and Libraries to the Feather RP2040
After downloading the Project Bundle, plug your Feather RP2040 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Feather RP2040's CIRCUITPY drive.
- lib folder
- code.py
Your Feather RP2040 CIRCUITPY drive should look like this after copying the lib folder and the code.py file:
How the CircuitPython Code Works
The code begins by creating a midi
object over USB as a MIDI input. This means that the Feather will take in, or receive, MIDI messages from another source. The source could be your computer or an external MIDI device.
# MIDI input setup midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], in_channel=0)
Servos Over I2C
The STEMMA QT port on the Feather is setup as the default i2c
object. The PCA9685 servo driver is instantiated over I2C. Then, the servo objects are created and added to the servos
array with a Python list comprehension.
# i2c PCA9685 setup i2c = board.STEMMA_I2C() pca = PCA9685(i2c) pca.frequency = 50 servos = [servo.Servo(pca.channels[i]) for i in range(16)]
Arrays of Servos and Notes
An array is created for the MIDI note numbers. This array will correspond with the servos
array. Both will be iterated through in the loop. If you want to change which MIDI notes are assigned to each servo, you can edit the midi_notes
array. By default, it lists a C major scale.
# array of midi notes, high to low midi_notes = [83, 81, 79, 77, 76, 74, 72, 71, 69, 67, 65, 64, 62, 60, 59, 57]
Angles
The servos will move back and forth between two set angles. These angles are defined with angle0
and angle1
. Before the loop, all of the servos are set to angle1
. This makes it easier to adjust the servo horns if needed.
angle0 = 20 angle1 = 70 # set servos to the same angle on boot # easier to adjust angles of the horns if needed print("setting servos") for i in range(16): s = servos[i] s.angle = angle1 time.sleep(0.05) print("servos set")
The Loop
In the loop, the Feather listens for incoming MIDI messages with midi.receive()
. If a NoteOn
message comes in containing a note number that is defined in the midi_notes
array, then the corresponding servo will move to either angle0
or angle1
depending on the current angle of the servo.
while True: # msg holds MIDI messages msg = midi.receive() for i in range(16): # iterate through servos array & midi notes array servo = servos[i] note_played = midi_notes[i] # if a noteon msg comes in that matches a note in the midi notes array.. if isinstance(msg, NoteOn) and msg.note == note_played: # print(servo) # print(note_played) # servo moves # angle alternates between angle0 and angle1 if servo.angle <= angle0: servo.angle = angle1 else: servo.angle = angle0 # print(servo.angle)
Text editor powered by tinymce.