Hi everyone,
I’m working on my first Raspberry Pi project and could use some guidance. I’m building a theremin-like digital instrument using two SHARP GP2Y0A51SK0F IR sensors. Each sensor is supposed to trigger one of five audio clips based on distance.
Here’s what I’ve done so far:
- I’ve set distance thresholds for each audio clip (e.g., 14-15cm triggers Clip 1, 11-13cm triggers Clip 2, etc.).
- I’ve written code to handle sensor input and play the clips accordingly.
However, I’m encountering a few issues:
- Erratic Playback: The audio clips play erratically and seem to be cut off at the low and high ends of the distance range.
- Persistent Playback: When no object is in front of the sensors, one clip plays continuously until something comes into range.
I’m wondering if:
- There might be improvements or adjustments I can make in the code to address these issues.
- The IR sensors might not be ideal for this application, and if alternatives like ultrasonic or Time-of-Flight sensors could be better (ideally want to solve with coding before buying new hardware)
Here’s my code for reference:
import RPi.GPIO as GPIO
import time
import spidev
from subprocess import call
import threading
import statistics
# Setup SPI
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1350000
# MCP3008 channel configuration
sensor1_channel = 0
sensor2_channel = 1
# Distance to audio mapping with updated intervals
distance_ranges = [(14, 15), (11, 13), (8, 10), (5, 7), (2, 4)]
audio_files_sensor1 = [f"/home/jss/audio_clips/s1_clip{i+1}.m4a" for i in range(len(distance_ranges))]
audio_files_sensor2 = [f"/home/jss/audio_clips/s2_clip{i+1}.m4a" for i in range(len(distance_ranges))]
# Smoothing parameters
smoothing_window_size = 5
sensor1_data = []
sensor2_data = []
def read_adc(channel):
adc = spi.xfer2([1, (8 + channel) << 4, 0])
data = ((adc[1] & 3) << 8) + adc[2]
return data
def get_distance(sensor_channel, sensor_data):
adc_value = read_adc(sensor_channel)
distance = (adc_value * 3.3 / 1024) * 30
# Smoothing the distance using a simple moving average
sensor_data.append(distance)
if len(sensor_data) > smoothing_window_size:
sensor_data.pop(0)
smoothed_distance = statistics.mean(sensor_data)
print(f"Smoothed distance from sensor {sensor_channel}: {smoothed_distance}") # Debugging
return smoothed_distance
def play_audio(file):
try:
print(f"Playing audio file: {file}") # Debugging
call(["mpv", file])
except Exception as e:
print(f"Error playing audio file: {file}. Error: {e}")
def handle_sensor(sensor_channel, audio_files, sensor_data):
last_played_index = -1
while True:
distance = get_distance(sensor_channel, sensor_data)
for i, (low, high) in enumerate(distance_ranges):
if low <= distance <= high:
if i != last_played_index:
play_audio(audio_files[i])
last_played_index = i
break
time.sleep(0.1)
def main():
print("Script started...") # Debugging
# Create and start threads for each sensor
sensor1_thread = threading.Thread(target=handle_sensor, args=(sensor1_channel, audio_files_sensor1, sensor1_data))
sensor2_thread = threading.Thread(target=handle_sensor, args=(sensor2_channel, audio_files_sensor2, sensor2_data))
sensor1_thread.start()
sensor2_thread.start()
# Wait for both threads to finish (they won't in this case)
sensor1_thread.join()
sensor2_thread.join()
if __name__ == "__main__":
main()