๐Ÿ”ฆ Level 2 โ€“ Sensors & IR Control

Project 2.11: "Interactive Musical Instrument"

๐Ÿš€ Project 2.11 โ€“ Interactive Musical Instrument

ย 

๐ŸŽฏ What youโ€™ll learn

  • Goals: Change instrument modes with IR, play scales with touch, add sound effects, record/playback, and run a lightโ€‘andโ€‘sound concert.
  • Skills: Inputs (IR, TouchPad), outputs (buzzer, RGB via PWM), mode switching, lists, loops, and conditionals.
  • Outcomes: A fun, playable instrument where students practice timing, mapping inputs to sounds, and creating performances.

๐Ÿงฑ Blocks glossary

  • IR receive: ir_rx = irremote.NEC_RX(pin, buffer) โ†’ Create IR receiver and read button codes.
  • IR code: ir_rx.code[0] โ†’ Access the first code captured from the remote.
  • Touch input: tcX = machine.TouchPad(machine.Pin(X)) โ†’ Read touch value (lower = pressed).
  • Buzzer: midi = music.MIDI(26) โ†’ Play tones/effects on pin 26.
  • RGB PWM: pwmX = machine.PWM(machine.Pin(X)) and pwmX.duty(value) โ†’ Control LED brightness.
  • Loop and flow: while True: and if/elif/else: โ†’ Continuous play and decision logic.
  • Serial: print("...") โ†’ Feedback for students and instructors.

๐Ÿงฐ What you need

PartHow many?Pins
D1 R321USB
IR receiver118
Touch sensors312, 13, 14
Buzzer126
RGB LED12 (R), 4 (G), 5 (B)
  • Wiring tip: Keep grounds common; place touch pads where students can press comfortably; secure RGB orientation (R=2, G=4, B=5).

โœ… Before you start

print("Ready!")  # Print startup message to confirm serial monitor works

๐ŸŽฎ Microprojects (1โ€“5)


๐ŸŽฎ Microproject 2.11.1 โ€“ Instrument modes via IR

Goal: Switch between Piano and Drum modes using the IR remote.

# Instrument modes via IR                                   # Title: change instrument modes with remote

import irremote, music, time                                # Import IR for codes, music for buzzer, time for delays

ir_rx = irremote.NEC_RX(18,8)                               # Setup IR receiver on pin 18 with buffer size 8
midi = music.MIDI(26)                                       # Setup buzzer on pin 26
mode = "Piano"                                              # Start in Piano mode by default

print("Instrument modes ready")                             # Serial confirmation for students

while True:                                                 # Infinite loop to keep reading remote and acting
    if ir_rx.any():                                         # Check if any IR signal was received
        code = ir_rx.code[0]                                # Read the first code from the IR buffer
        if code == 0xA90:                                   # Example code for Piano mode
            mode = "Piano"                                  # Switch to Piano mode
            print("Mode:", mode)                            # Print current mode
        elif code == 0xA91:                                 # Example code for Drum mode
            mode = "Drum"                                   # Switch to Drum mode
            print("Mode:", mode)                            # Print current mode

    if mode == "Piano":                                     # If Piano mode is active
        midi.pitch_time(440, 200)                           # Play note A (440 Hz) for 200 ms
    elif mode == "Drum":                                    # If Drum mode is active
        midi.play(midi.DADADADUM)                           # Play predefined drum-like effect
    time.sleep(1)                                           # Delay to avoid constant rapid playback
  • Reflection: IR buttons can change how the instrument behaves in real time.
  • Challenge: Add a third mode โ€œGuitarโ€ with midi.pitch_time(659, 200) for a bright tone.

๐ŸŽฎ Microproject 2.11.2 โ€“ Musical scales

Goal: Play notes C, D, and E using touch sensors.

# Musical scales                                            # Title: play notes with touch sensors

import machine, music, time                                 # Import machine for TouchPad, music for buzzer, time for delays

tc12 = machine.TouchPad(machine.Pin(12))                    # Touch sensor on pin 12 for note C
tc13 = machine.TouchPad(machine.Pin(13))                    # Touch sensor on pin 13 for note D
tc14 = machine.TouchPad(machine.Pin(14))                    # Touch sensor on pin 14 for note E
midi = music.MIDI(26)                                       # Buzzer setup on pin 26
threshold = 300                                             # Touch threshold (lower values mean pressed)

print("Musical scales ready")                               # Serial confirmation

while True:                                                 # Continuous loop for input
    if tc12.read() < threshold:                             # If C touch pressed
        midi.pitch_time(261, 200)                           # Play note C (261 Hz) for 200 ms
        print("Note C")                                     # Feedback for students
    if tc13.read() < threshold:                             # If D touch pressed
        midi.pitch_time(293, 200)                           # Play note D (293 Hz) for 200 ms
        print("Note D")                                     # Feedback for students
    if tc14.read() < threshold:                             # If E touch pressed
        midi.pitch_time(329, 200)                           # Play note E (329 Hz) for 200 ms
        print("Note E")                                     # Feedback for students
    time.sleep(0.1)                                         # Short delay to stabilize reading
  • Reflection: Touch inputs map cleanly to musical notes.
  • Challenge: Expand to a full pentatonic scale by adding two more touch pads.

๐ŸŽฎ Microproject 2.11.3 โ€“ Sound effects

Goal: Play simple effects to enrich performance.

# Sound effects                                             # Title: quick buzzer effects

import music                                                # Import music for buzzer control

midi = music.MIDI(26)                                       # Setup buzzer on pin 26

print("Sound effects ready")                                # Serial confirmation

midi.play(midi.DADADADUM)                                   # Play drum-like effect
midi.pitch_time(880, 100)                                   # Play high beep (880 Hz) for 100 ms
midi.pitch_time(220, 400)                                   # Play low beep (220 Hz) for 400 ms
  • Reflection: Effects add texture and variety to songs.
  • Challenge: Create your own โ€œcomboโ€ effect by chaining three tones with different durations.

๐ŸŽฎ Microproject 2.11.4 โ€“ Recording and playback

Goal: Record a short sequence of notes and replay them.

# Recording and playback                                    # Title: store notes and replay

import machine, music, time                                 # Import TouchPad, buzzer, and timing

tc12 = machine.TouchPad(machine.Pin(12))                    # Touch for note C
tc13 = machine.TouchPad(machine.Pin(13))                    # Touch for note D
tc14 = machine.TouchPad(machine.Pin(14))                    # Touch for note E
midi = music.MIDI(26)                                       # Buzzer setup
threshold = 300                                             # Touch threshold for presses

recorded = []                                               # Empty list to store recorded notes

print("Recording ready")                                    # Serial confirmation

while True:                                                 # Main loop
    if tc12.read() < threshold:                             # If C pressed
        recorded.append(261)                                # Store frequency for C (261 Hz)
        midi.pitch_time(261, 200)                           # Play C to confirm
        print("Recorded C")                                 # Log recording step
    if tc13.read() < threshold:                             # If D pressed
        recorded.append(293)                                # Store D (293 Hz)
        midi.pitch_time(293, 200)                           # Play D to confirm
        print("Recorded D")                                 # Log recording step
    if tc14.read() < threshold:                             # If E pressed
        recorded.append(329)                                # Store E (329 Hz)
        midi.pitch_time(329, 200)                           # Play E to confirm
        print("Recorded E")                                 # Log recording step

    if len(recorded) >= 3:                                  # If three notes are recorded
        print("Playback:", recorded)                        # Show the recorded notes list
        for note in recorded:                               # Iterate through recorded notes
            midi.pitch_time(note, 200)                      # Play each note with 200 ms duration
            time.sleep(0.3)                                 # Pause between notes for clarity
        recorded = []                                       # Clear list after playback
    time.sleep(0.1)                                         # Small delay for stability
  • Reflection: Students see input โ†’ memory โ†’ output clearly.
  • Challenge: Increase capacity to 5 notes and add a โ€œclearโ€ IR button to reset.

๐ŸŽฎ Microproject 2.11.5 โ€“ Interactive concert

Goal: Combine RGB lights and tones into a short performance loop.

# Interactive concert                                       # Title: lights and sounds performance

import machine, music, time                                 # Import PWM for RGB, music for buzzer, time for delays

pwm2 = machine.PWM(machine.Pin(2))                          # Red LED PWM on pin 2
pwm4 = machine.PWM(machine.Pin(4))                          # Green LED PWM on pin 4
pwm5 = machine.PWM(machine.Pin(5))                          # Blue LED PWM on pin 5
midi = music.MIDI(26)                                       # Buzzer setup on pin 26

print("Concert ready")                                      # Serial confirmation

for i in range(3):                                          # Repeat the performance three times
    pwm2.duty(800); midi.pitch_time(440, 200)               # Red ON + note A (440 Hz)
    time.sleep(0.3)                                         # Pause to separate events
    pwm4.duty(800); midi.pitch_time(523, 200)               # Green ON + note C (523 Hz)
    time.sleep(0.3)                                         # Pause to separate events
    pwm5.duty(800); midi.pitch_time(659, 200)               # Blue ON + note E (659 Hz)
    time.sleep(0.3)                                         # Pause to separate events
    pwm2.duty(0); pwm4.duty(0); pwm5.duty(0)                # Turn all LEDs OFF
    time.sleep(0.5)                                         # Short rest before next loop
  • Reflection: Visual rhythm helps students feel musical structure.
  • Challenge: Make a longer pattern and add a final โ€œapplauseโ€ jingle with three quick beeps.

โœจ Main project โ€“ Interactive musical instrument (complete)

Goal: Merge IR modes, touch scales, effects, recording/playback, and RGB feedback into one instrument.

# Project 2.11 โ€“ Interactive Musical Instrument             # Title: full interactive instrument

import machine, time, music, irremote                        # Import pins/timing/buzzer/IR libraries

ir_rx = irremote.NEC_RX(18,8)                                # IR receiver on pin 18 (buffer size 8)
midi = music.MIDI(26)                                        # Buzzer on pin 26

pwm2 = machine.PWM(machine.Pin(2))                           # Red LED PWM on pin 2
pwm4 = machine.PWM(machine.Pin(4))                           # Green LED PWM on pin 4
pwm5 = machine.PWM(machine.Pin(5))                           # Blue LED PWM on pin 5

tc12 = machine.TouchPad(machine.Pin(12))                     # Touch sensor on pin 12 (C)
tc13 = machine.TouchPad(machine.Pin(13))                     # Touch sensor on pin 13 (D)
tc14 = machine.TouchPad(machine.Pin(14))                     # Touch sensor on pin 14 (E)

mode = "Piano"                                               # Default mode at start
recorded = []                                                # Storage for recorded notes
threshold = 300                                              # Touch threshold (classroom-calibrated)

print("Interactive Musical Instrument ready")                # Serial start message for teachers/students

while True:                                                  # Main loop runs forever
    if ir_rx.any():                                          # If an IR signal is available
        code = ir_rx.code[0]                                 # Read the first received code
        if code == 0xA90:                                    # Example code to set Piano mode
            mode = "Piano"                                   # Update current mode
            print("Mode:", mode)                             # Print mode change
        elif code == 0xA91:                                  # Example code to set Drum mode
            mode = "Drum"                                    # Update current mode
            print("Mode:", mode)                             # Print mode change
        elif code == 0xA92:                                  # Example code to set Record mode
            mode = "Record"                                  # Update current mode
            print("Mode:", mode)                             # Print mode change

    if mode == "Piano":                                      # If Piano mode is selected
        if tc12.read() < threshold:                          # If C pad is pressed
            midi.pitch_time(261, 200)                        # Play C (261 Hz) for 200 ms
            pwm2.duty(800); time.sleep(0.2); pwm2.duty(0)    # Flash Red LED to confirm
            print("Note C")                                  # Log note
        if tc13.read() < threshold:                          # If D pad is pressed
            midi.pitch_time(293, 200)                        # Play D (293 Hz) for 200 ms
            pwm4.duty(800); time.sleep(0.2); pwm4.duty(0)    # Flash Green LED to confirm
            print("Note D")                                  # Log note
        if tc14.read() < threshold:                          # If E pad is pressed
            midi.pitch_time(329, 200)                        # Play E (329 Hz) for 200 ms
            pwm5.duty(800); time.sleep(0.2); pwm5.duty(0)    # Flash Blue LED to confirm
            print("Note E")                                  # Log note

    elif mode == "Drum":                                     # If Drum mode is selected
        if tc12.read() < threshold:                          # If first pad is hit
            midi.play(midi.DADADADUM)                        # Play drum effect pattern
            print("Drum hit 1")                              # Log drum hit
        if tc13.read() < threshold:                          # If second pad is hit
            midi.pitch_time(100, 300)                        # Play low drum tone (100 Hz)
            print("Drum hit 2")                              # Log drum hit
        if tc14.read() < threshold:                          # If third pad is hit
            midi.pitch_time(200, 150)                        # Play snare-like short tone (200 Hz)
            print("Drum hit 3")                              # Log drum hit

    elif mode == "Record":                                   # If Record/Playback mode is selected
        if tc12.read() < threshold:                          # If C is pressed
            recorded.append(261)                             # Store C (261 Hz)
            midi.pitch_time(261, 200)                        # Play C to confirm
            print("Recorded C")                              # Log recording step
        if tc13.read() < threshold:                          # If D is pressed
            recorded.append(293)                             # Store D (293 Hz)
            midi.pitch_time(293, 200)                        # Play D to confirm
            print("Recorded D")                              # Log recording step
        if tc14.read() < threshold:                          # If E is pressed
            recorded.append(329)                             # Store E (329 Hz)
            midi.pitch_time(329, 200)                        # Play E to confirm
            print("Recorded E")                              # Log recording step

        if len(recorded) >= 3:                               # If we have three notes recorded
            print("Playback:", recorded)                     # Show what will be played
            for note in recorded:                            # Iterate through stored notes
                midi.pitch_time(note, 200)                   # Play each note
                time.sleep(0.3)                              # Pause between notes
            recorded = []                                    # Clear recording after playback

    time.sleep(0.1)                                          # Small delay to keep system stable

๐Ÿ“– External explanation

  • What it teaches: Mode switching via IR, mapping touch inputs to notes/effects, feedback with LEDs, and simple recording with lists.
  • Why it works: Each input (IR or touch) triggers a clear output (sound/light), and mode logic changes behavior without changing hardware.
  • Key concept: Same sensors can do different jobs depending on the active mode.

โœจ Story time

You step onto your mini stage. A button press turns your robot into a piano, another into a drum kit. Touch pads are your keys, LEDs dance with the music, and your recorded melody gets a proud replay. Encore!


๐Ÿ•ต๏ธ Debugging (2)

๐Ÿž Offโ€‘key notes

  • Symptom: Notes sound wrong or mismatched to labels.
  • Cause: Frequencies not aligned with intended notes.
  • Fix: Use correct values: C=261 Hz, D=293 Hz, E=329 Hz; verify typing accuracy in code.

๐Ÿž Modes do not change

  • Symptom: Pressing remote buttons doesnโ€™t switch modes.
  • Cause: IR codes donโ€™t match actual remote values.
  • Fix: Run the IR Configuration microproject to print codes, then update if code == ... to match your buttons.

โœ… Final checklist

  • IR remote switches reliably between Piano, Drum, and Record modes.
  • Touch pads trigger the correct notes/effects with consistent thresholds.
  • LEDs flash as visual feedback for played notes.
  • Recording stores notes and playback replays them clearly.
  • Serial prints show mode changes and actions for easy classroom debugging.

๐Ÿ“š Extras

  • Student tip: Add a โ€œChordโ€ by pressing two pads quickly; experiment with timing for layered sounds.
  • Instructor tip: Have learners design a themed concert (e.g., space sounds) using specific tones and LED colors.
  • Glossary: IR code, mode, pitch (Hz), PWM duty, threshold, recording list.
  • Mini tips: Calibrate touch thresholds; keep delays short; map LEDs to notes for instant recognition.
On this page