Distance-Based Tones with UNIHIKER

0 417 Easy

In this tutorial, we'll explore how to create an interactive audio system using the versatile UNIHIKER device. By integrating an ultrasonic sensor and a USB speaker, we'll produce sounds that vary based on the distance detected. This project is a fun and educational way to learn about sensors, audio generation, and programming with PyAudio.

 

By the end of this tutorial, you'll have a working prototype that responds to distance with sound, sparking ideas for further projects and explorations. Whether you're interested in music, electronics, or coding, this project offers something for everyone.

HARDWARE LIST
1 UNIHIKER
1 Ultrasonic Distance Sensor
1 USB Speaker
STEP 1
Assembling

Connect the Ultrasonic Sensor: Attach the sensor to the UNIHIKER.

 

Attach the USB Speaker: Plug the speaker into the UNIHIKER's USB port.

 

Power On: Once everything is connected, power up the UNIHIKER.

 

STEP 2
Coding

With the hardware setup complete, it's time to dive into the code. Using Python and the PyAudio library, we'll write a program that:

 

Read distance data from the ultrasonic sensor.

 

Map the distance to a frequency range, creating a tone that changes as the distance varies.

 

Play the corresponding tone through the USB speaker.

CODE
from threading import Thread, Lock
from time import sleep
import numpy as np
from pinpong.board import Board
from pinpong.libs.dfrobot_urm09 import URM09
from pyaudio import PyAudio, paFloat32, Stream


RATE: int = 44100
AMPLITUDE: float = 0.5
FREQUENCY_MIN: int = 50
FREQUENCY_MAX: int = 2000
BUFFER_SIZE: int = 1024
DELAY: float = .5


def calculate_frequency(value: float) -> float:
    """
    Calculate frequency based on a given value.

    :param value: The value used to calculate the frequency.
    :type value: float
    :return: The calculated frequency.
    """
    return FREQUENCY_MAX - (value / 150.0) * (FREQUENCY_MAX - FREQUENCY_MIN)


def generate_tone_thread(output_stream: Stream) -> None:
    """
    Generate tone and write it to the output stream.

    :param output_stream: The output stream to write the generated tone to.
    :type output_stream: Stream
    :return: None
    """
    global current_value

    t = np.arange(BUFFER_SIZE) / RATE
    prev_frequency = calculate_frequency(current_value)

    while True:
        with value_lock:
            frequency = calculate_frequency(current_value)

        if frequency != prev_frequency:
            samples = (np.sin(2 * np.pi * frequency * t)).astype(np.float32)
            prev_frequency = frequency
        else:
            samples = (np.sin(2 * np.pi * prev_frequency * t)).astype(np.float32)

        output_stream.write((AMPLITUDE * samples).tobytes())
        t += BUFFER_SIZE / RATE

def input_thread(input_sensor: URM09) -> None:
    """
    Continuously reads the distance from the sensor and updates the current_value variable.

    :param input_sensor: The URM09 sensor instance.
    :type input_sensor: URM09
    :return: None
    """
    global current_value

    while True:
        distance = float(input_sensor.distance_cm())
        if 0 <= distance <= 120:
            current_value = distance


if __name__ == '__main__':
    Board("UNIHIKER").begin()

    sensor = URM09()
    sensor.set_mode_range(sensor._MEASURE_MODE_AUTOMATIC, sensor._MEASURE_RANG_150)

    p = PyAudio()
    stream = p.open(format=paFloat32,
                    channels=1,
                    rate=RATE,
                    frames_per_buffer=BUFFER_SIZE,
                    output=True,
                    input=False)

    value_lock = Lock()
    current_value = 75

    tone_thread = Thread(target=generate_tone_thread, args=(stream,))
    tone_thread.daemon = True
    tone_thread.start()

    input_thread = Thread(target=input_thread, args=(sensor,))
    input_thread.daemon = True
    input_thread.start()

    try:
        while True:
            sleep(DELAY)
    except KeyboardInterrupt:
        print("Shutting down...")
    finally:
        stream.stop_stream()
        stream.close()
        p.terminate()
STEP 3
Upload to UNIHIKER

Now upload your file to UNIHIKER. You can use different methods like SSH or SMB.

STEP 4
Applications and Ideas

This example can be used in various creative and practical applications:

 

Theremin-like Instrument: Create an electronic instrument that changes pitch based on hand distance.

 

Parking Assist System: Implement a simple audio-based parking aid that alerts drivers as they approach an obstacle.

 

Interactive Art Installation: Use the setup to make interactive installations where sounds respond to viewers' movements.

License
All Rights
Reserved
licensBg
0