first commit bricktunes code
This commit is contained in:
parent
ecc5d4dba7
commit
3a650b6d04
1 changed files with 142 additions and 0 deletions
142
Bricktunes_LEGO_Color_Synth/code.py
Normal file
142
Bricktunes_LEGO_Color_Synth/code.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# SPDX-FileCopyrightText: 2023 John Park for Adafruit
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Bricktunes LEGO Color Synth
|
||||
# Feather RP2040 Prop-Maker + AS7341 Color Sensor
|
||||
# Color comparison code and chime library by CGrover
|
||||
|
||||
import time
|
||||
import math
|
||||
import board
|
||||
import digitalio
|
||||
import audiobusio
|
||||
from adafruit_as7341 import AS7341, Gain
|
||||
import audiomixer
|
||||
from cedargrove_chime import Chime, Voice, Material, Striker
|
||||
|
||||
DEBUG = False # Useful for tuning reference color values by printing them
|
||||
TOLERANCE = 800 # The color matching tolerance index (0 to 8 * max_sensor_count)
|
||||
|
||||
sensor = AS7341(board.STEMMA_I2C())
|
||||
sensor.astep = 128 # (999) The integration time step size in 2.78 microsecond increments
|
||||
sensor.atime = 50 # The integration time step count.
|
||||
sensor.gain = Gain.GAIN_256X
|
||||
sensor.led_current = 4 # increments in units of 4
|
||||
sensor.led = True
|
||||
max_sensor_count = (sensor.astep + 1) * (sensor.atime + 1)
|
||||
|
||||
# ===================================================
|
||||
# color lists as 8-channel tuples (channels[0:8])
|
||||
brick_full_spectrum_values = [
|
||||
(94, 1310, 1736, 1075, 592, 437, 497, 383), # Blue
|
||||
(148, 324, 838, 2577, 2363, 1259, 929, 819), # Bright Green
|
||||
(381, 576, 850, 1619, 3688, 5532, 6291, 4250), # Bright Lt Orange
|
||||
(404, 2300, 2928, 2385, 2679, 3804, 5576, 4284), # Bright Pink
|
||||
(545, 1276, 1513, 1178, 2291, 6579, 6579, 6486), # Coral
|
||||
(136, 1055, 1223, 745, 748, 768, 1205, 1100), # Dark Purple
|
||||
(85, 731, 1375, 1604, 1019, 557, 533, 370), # Dark Turquoise
|
||||
(451, 2758, 3786, 2880, 3007, 3064, 4539, 3656), # Lavender
|
||||
(214, 300, 771, 1811, 3245, 2897, 2051, 1392), # Lime
|
||||
(188, 341, 435, 507, 625, 1703, 4361, 3692), # Red
|
||||
(182, 870, 1455, 1799, 2149, 1879, 1702, 1273), # Sand Green
|
||||
(461, 497, 878, 2412, 4699, 5935, 6579, 4677) # Yellow
|
||||
]
|
||||
|
||||
brick_color_names = [
|
||||
"Blue",
|
||||
"Bright Green",
|
||||
"Bright Light Orange",
|
||||
"Bright Pink",
|
||||
"Coral",
|
||||
"Dark Purple",
|
||||
"Dark Turquoise",
|
||||
"Lavender",
|
||||
"Lime",
|
||||
"Red",
|
||||
"Sand Green",
|
||||
"Yellow"
|
||||
]
|
||||
|
||||
brick_states = [False] * (len(brick_color_names))
|
||||
gap_state = False
|
||||
|
||||
# ===================================================
|
||||
# audio setup
|
||||
power = digitalio.DigitalInOut(board.EXTERNAL_POWER)
|
||||
power.switch_to_output(value=True)
|
||||
audio_output = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA)
|
||||
|
||||
mixer = audiomixer.Mixer(sample_rate=11020, buffer_size=4096, voice_count=1, channel_count=1)
|
||||
audio_output.play(mixer)
|
||||
mixer.voice[0].level = 0.50 # adjust this for overall volume
|
||||
|
||||
brickscale = [
|
||||
"C5", "D5", "E5", "F5", "G5", "A5", "B5",
|
||||
"C6", "D6", "E6", "F6", "G6", "A6", "B6",
|
||||
"C7", "D7", "E7", "F7", "G7", "A7", "B7",
|
||||
]
|
||||
|
||||
# Instantiate the chime synthesizer with custom parameters
|
||||
chime = Chime(
|
||||
mixer.voice[0],
|
||||
scale=brickscale,
|
||||
material=Material.Brass, # SteelEMT, Ceramic, Wood, Copper, Aluminum, Brass
|
||||
striker=Striker.HardWood, # Metal, Plexiglas, SoftWood, HardWood
|
||||
voice=Voice.Tubular, # bell, perfect, tubular
|
||||
scale_offset=-16
|
||||
)
|
||||
|
||||
# Play scale notes sequentially
|
||||
for index, note in enumerate(chime.scale):
|
||||
chime.strike(note, 1.0)
|
||||
time.sleep(0.1)
|
||||
time.sleep(1)
|
||||
|
||||
def compare_n_channel_colors(color_1, color_2, tolerance=0):
|
||||
"""Compares two integer multichannel count tuples using an unweighted linear
|
||||
Euclidean difference. If the color value difference is within the tolerance
|
||||
band of the reference, the method returns True.
|
||||
The difference value index `tolerance` is used to detect color similarity.
|
||||
Value range is an integer value from 0 to
|
||||
(maximum_channel_count * number_of_channels). Default is 0 (detects a
|
||||
single color value)."""
|
||||
# Create list of channel deltas using list comprehension
|
||||
deltas = [((color_1[idx] - count) ** 2) for idx, count in enumerate(color_2)]
|
||||
# Resolve squared deltas to a Euclidean difference
|
||||
# pylint: disable=c-extension-no-member
|
||||
delta_color = math.sqrt(sum(deltas))
|
||||
return bool(delta_color <= tolerance)
|
||||
|
||||
print("Bricktunes ready")
|
||||
|
||||
|
||||
while True:
|
||||
sensor_color = sensor.all_channels
|
||||
# don't bother to check comparison when we're looking at a gap between bricks
|
||||
if sensor_color[0] <= 70: # this checks for a minimum value on one channel
|
||||
if gap_state is False:
|
||||
print("no brick...")
|
||||
for i in range(len(brick_color_names)):
|
||||
brick_states[i] = False
|
||||
gap_state = True
|
||||
|
||||
else:
|
||||
if DEBUG:
|
||||
print(sensor_color)
|
||||
for i in range(len(brick_full_spectrum_values)):
|
||||
color_match = compare_n_channel_colors(
|
||||
sensor_color,
|
||||
brick_full_spectrum_values[i],
|
||||
TOLERANCE
|
||||
)
|
||||
|
||||
if color_match is True:
|
||||
if brick_states[i] is False:
|
||||
for n in range(5):
|
||||
chime.strike(chime.scale[i+(n*2)], 1.0)
|
||||
time.sleep(0.1)
|
||||
brick_states[i] = True
|
||||
gap_state = False
|
||||
print("sensor color:", sensor_color, "| ref:", brick_full_spectrum_values[i])
|
||||
print(brick_color_names[i])
|
||||
break
|
||||
Loading…
Reference in a new issue