Skip to the content
2 layers99.1 × 59.7 mmLaserHarp3 - Rev3.1, the printed circuit board in 3D

LaserHarp3 - Rev3.1

amonbenson/laserharp1

Setup a virtual environment and install the dependencies:

Size
99.1 × 59.7 mm
Copper layers
2
Thickness
1.6 mm
Parts
134
Nets
122
Pads
432
Tracks, vias
708, 146
Pours
3
Routed
Yes
KiCad
KiCad 8.0 (file 20240108)
Created
5 Oct 2023
Updated
26 Jun 2025

Overview

LaserHarp3 - Rev3.1 is an open-source printed circuit board by amonbenson, from the amonbenson/laserharp repository on GitHub. It is a 2-layer board of 99.1 × 59.7 mm with 134 parts on 122 nets, routed with 708 tracks and 146 vias.

It is built around the STM32F103C8T6, 74HC595 and AMS1117-3.3, with the 1N4148WS, AO3401A and ZMM5V6 among its other parts. Its parts include 38 resistors, 25 transistors, 15 capacitors, 11 connectors and 6 ICs. It belongs with the STM32 boards of this library.

Main components

6

README

README.md

Backend Tests Frontend Tests Firmware Tests

Development Setup

Backend

Setup a virtual environment and install the dependencies:

bash
python3 -m venv .venv --system-site-packages
source .venv/bin/activate
pip install -r requirements.txt

Run the server in development mode:

bash
source .venv/bin/activate
python -m laserharp.server

Frontend

Install node js and yarn:

bash
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
nvm install --lts
nvm use --lts
npm install -g yarn

Install all dependencies:

bash
cd frontend
yarn install

Run the development server:

bash
yarn dev

Raspberry Pi Performance Improvements:

see https://wiki.linuxaudio.org/wiki/raspberrypi

bash
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do echo -n performance \
| sudo tee $cpu/cpufreq/scaling_governor; done

Raspberry Pi Reduce Power Consumption

see https://www.jeffgeerling.com/blog/2023/reducing-raspberry-pi-5s-power-consumption-140x

bash
# sudo rpi-eeprom-config -e
[all]
BOOT_UART=1
WAKE_ON_GPIO=0
POWER_OFF_ON_HALT=1

Midi uart

  • do a rpi-update to get the latest kernel firmware
  • add to /boot/firmware/config.txt:
text
dtoverlay=uart2-pi5
dtoverlay=midi-uart2-pi5

Power via GPIO header

http://blog.dddac.com/wp-content/uploads/Flash-RPi5-and-adding-5000mA-Line-tutorial.pdf

Allow current user to shutdown

bash
sudo chmod u+s /sbin/poweroff /sbin/reboot /sbin/shutdown

Diode to Note Mapping

  • Root note: C3 (midi note 48, one octave below middle C)

  • Global transpose setting

  • Modes:

    • Pedal Harp: For each note, choose one of:
      • flat
      • natural
      • sharp
    • Custom Scale:
      • each diode can be assigned to a specific midi note
  • The harp is divided into three horizontal sections resulting in 3 different octave ranges

Transmitted MIDI Messages

:heavy_check_mark: – Implemented
:x: – Not implemented

Note On :heavy_check_mark:

text
Laserharp -> Host: 0x90 <note> <velocity>

Sent when a laser is intercepted. The note value is determined by the diode and section that was intercepted. The velocity is fixed at 127.

Note Off :heavy_check_mark:

text
Laserharp -> Host: 0x80 <note> <velocity>

Sent immediately after a laser was plucked. The velocity is fixed at 127.

Pitch Bend :x:

text
Laserharp -> Host: 0xe0 <pitch_bend_msb> <pitch_bend_lsb>

Sent during interception when the hand is moved along the laser beam.

Received MIDI Messages

:heavy_check_mark: – Implemented
:x: – Not implemented

Set Laser Brightness Directly (Note On / Note Off) :heavy_check_mark: (set all lasers :x:)

text
Host -> Laserharp: 0x80 <note> <velocity>

Turn off the laser corresponding to the note. A note value of 127 will turn off all lasers at once.

text
Host -> Laserharp: 0x90 <note> <velocity>

Turn on the laser corresponding to the note. A note value of 127 will turn on all lasers at once. The velocity determines the brightness of the laser.

The brightness is restored automatically after 1s. Note that interceptions will not be detected when the laser is turned off or too dim.

Restore Laser Brightness (CC 102) :heavy_check_mark:

text
Host -> Laserharp: 0xb0 102 <value>

Restores the laser brightness to the previous value immediately. Value must be ≥ 64.

Set Unplucked Laser Brightness (CC 103) :heavy_check_mark:

text
Host -> Laserharp: 0xb0 103 <brightness>

Set the brightness for unplucked lasers.

Set Plucked Laser Brightness (CC 104) :heavy_check_mark:

text
Host -> Laserharp: 0xb0 104 <brightness>

Set the brightness when a laser is plucked.

Set Muted Laser Brightness (CC 105) :heavy_check_mark:

text
Host -> Laserharp: 0xb0 105 <brightness>

Sets the brightness when a laser is muted.

Set Pedal Position And Mutes (CC 110 - 116) :heavy_check_mark:

text
Host -> Laserharp: 0xb0 <pedal_cc> <position>

Sets the position and mute of a pedal. The pedals are mapped as follows:

  • CC 110 – C pedal
  • CC 111 – D pedal
  • CC 112 – E pedal
  • CC 113 – F pedal
  • CC 114 – G pedal
  • CC 115 – A pedal
  • CC 116 – B pedal

The value is divided into the ranges:

  • 0 – 31 – muted
  • 32 – 63 – lower position (sharp)
  • 64 – 95 – middle position (natural)
  • 96 – 127 – upper position (flat)

IPC Protocol

:heavy_check_mark: – Implemented
:x: – Not implemented

USB Midi :x:

text
Bidirectional: 0x0N <byte0> <byte1> <byte2>

These packets are equivalent to the USB Midi Protocol with CN = 1.

Din Midi :x:

text
Bidirectional: 0x1N <byte0> <byte1> <byte2>

Note: With the current version, Din Midi is handled directly by the Raspberry Pi, so this message won't be used.

These packets are equivalent to the USB Midi Protocol with CN = 1.

Set Brightness of a Single Laser :heavy_check_mark:

text
RPi -> STM: 0x80 <diode_index> <brightness> <fade_duration>

Set the brightness of a single laser diode. The fade duration is given in tenths of a second. E.g. a value of 20 will fade the laser to the new brightness over 2 seconds. A duration of 0 will set the brightness immediately.

Set Brightness of All Lasers :heavy_check_mark:

text
RPi -> STM: 0x81 <brightness> <fade_duration> <unused>

Set the brightness of all laser diodes. The fade duration is given in tenths of a second. E.g. a value of 20 will fade the lasers to the new brightness over 2 seconds. A duration of 0 will set the brightness immediately.

Get Brightness of a Single Laser :heavy_check_mark:

text
RPi -> STM: 0x82 <diode_index> <unused> <unused>
STM -> RPi: 0x82 <diode_index> <brightness> <unused>

Play Animation :heavy_check_mark:

text
RPi -> STM: 0x83 <animation_id> <duration> <follow_action>

Play one of the predefined animations.

Animation Ids:
0 – Boot animation – Played during powerup of the Raspberry Pi
1 – Flip animation – Played when flipping the harp view
2 – Test animation – Used for internal testing, alternates between diodes 4 and 5

Duration: Given in tenths of a second. E.g. a value of 20 will play the animation for 2 seconds.

Follow Actions:
0 – Loop – Loop the animation indefinitely
1 – Freeze – Play the animation once and stop on the last frame
2 – Off – Play the animation once and stop with all lasers off
3 – Restore – Play the animation once and restore the laser brightnesses

Stop Animation :heavy_check_mark:

text
RPi -> STM: 0x84 <unused> <unused> <unused>

Stop the current animation from playing and execute the follow action immediately. If the follow action was set to 0 (loop indefinitely), the animation will stop and the lasers will remain in their current state.

Calibration Button Pressed :heavy_check_mark:

text
STM -> RPi: 0x90 <state_0> <state_1> <state_2>

Sent when the calibration button is pressed. The states are given as follows: 0 – released
1 – short press
2 – long press

For example, if the button is short-pressed, then long-pressed, and then released, the states will be 0x01 0x02 0x00.

Get Voltage :heavy_check_mark:

text
RPi -> STM: 0x91 <00> <unused> <unused>
STM -> RPi: 0x91 <00> <voltage_int> <voltage_frac>

Returns the current voltage. Currently only the Laser Diode voltage (index 0) can be measured. The result is given as a decimal number with a resolution of 0.01V and can be calculated as follows:

python
voltage = voltage_int + voltage_frac / 100

Firmware Version Inquiry :heavy_check_mark:

text
RPi -> STM: 0xf0 <unused> <unused> <unused>
STM -> RPi: 0xf0 <major> <minor> <patch>

Reboot STM :heavy_check_mark:

text
RPi -> STM: 0xf1 <unused> <unused> <unused>

Enter Standby :heavy_check_mark:

text
RPi -> STM: 0xf2 <fade_delay> <fade_duration> <unused>

Starts by playing the boot animation, waits for the fade delay, and then fades the lasers to black over the fade duration. Both delay and duration are given in tenths of a second.

Important: This is intended to be used when the harp is turned off. It will block any further IPC commands and the STM will not respond until it is power cycled.

TODO Software

Pedal Mutes

  • Each Pedal Switch should have a "mute" button. If a string is muted, its corresponding laser will be turned on very dimly and no sound will be produced for that string.

Direct Laser Control

  • The brightness of each laser should be directly controllable via Note On Messages.
  • Velocity 1 will map to 0% brightness, velocity 127 will map to 100% brightness.
  • Velocity 0 / Note Off will return to normal operation and use the internally calculated laser brightness
  • If a laser is currently in "normal operation" mode, the color will be determined by the "unplucked", "plucked", and "muted" brightness settings.

Section Mode / Section Transpose (formally Section Octave Spacing)

  • Sections can be set to different modes.
    • Off – There are no different sections. Each laser will produce a single note.
    • Alterate – The upper section will play one semitone higher while the lower section will play one semitone lower.
    • Single Octave – The upper section will play one octave higher while the lower section will play one octave lower.
    • Double Octave – The upper section will play two octaves higher while the lower section will play two octaves lower.
  • Internally, the section mode is stored as a number of semitones.
  • This should also be controllable via a Control Change Message

Global Transpose

  • Instead of setting the root note, a fixed root note (e.g. C3) will be used and a global transpose setting will offset that root note.

Direct Pedal/Mute Control

  • Using Control Change Messages, the pedal position and mutes can be controlled.

Predefined Scales

  • Each predefined scale controls the pedal positions and mutes for each note.

  • Can be selected using Bank Change Messages (CC 0).

  • Additional custom scales can be defined and stored internally.

  • For each scale, choose:

Parts

134
QtyValueFootprintReferences
2510kResistor_SMD:R_0603_1608MetricR12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26, R27 +9
242N7002Package_TO_SOT_SMD:SOT-23Q2, Q10, Q11, Q12, Q13, Q14, Q15, Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24 +8
24Laser_DiodeLED_THT:LED_D5.0mmLD1, LD2, LD10, LD11, LD12, LD13, LD14, LD15, LD16, LD17, LD18, LD19, LD20, LD21, LD22, LD23 +8
8100nCapacitor_SMD:C_0603_1608MetricC4, C5, C7, C8, C9, C10, C15, C16
410pCapacitor_SMD:C_0603_1608MetricC11, C12, C13, C14
4MountingHoleMountingHole:MountingHole_2.7mmH1, H2, H3, H4
3100kResistor_SMD:R_0603_1608MetricR3, R10, R11
374HC595Package_SO:SO-16_3.9x9.9mm_P1.27mmU4, U5, U6
21N5819Diode_SMD:D_SOD-323D1, D3
222uCapacitor_THT:C_Radial_D6.3mm_H5.0mm_P2.50mmC1, C2
247Resistor_SMD:R_0603_1608MetricR6, R7
25.1kResistor_SMD:R_0603_1608MetricR1, R2
11.5kResistor_SMD:R_0603_1608MetricR36
110uCapacitor_THT:C_Radial_D6.3mm_H5.0mm_P2.50mmC3
11N4148WSDiode_SMD:D_SOD-323D4
11kResistor_SMD:R_0603_1608MetricR8
1220Resistor_SMD:R_0603_1608MetricR4
1220kResistor_SMD:R_0603_1608MetricR37
132.768 KHzCrystal:Crystal_SMD_3215-2Pin_3.2x1.5mmY2
1330kResistor_SMD:R_0603_1608MetricR38
13V3 PowerConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ6
1470Resistor_SMD:R_0603_1608MetricR5
16N137Package_SO:SSO-8_6.7x9.8mm_P2.54mm_Clearance8mmU3
18 MHzCrystal:Crystal_SMD_HC49-SDY1
1AMS1117-3.3Package_TO_SOT_SMD:SOT-223-3_TabPin2U2
1AO3401APackage_TO_SOT_SMD:SOT-23Q1
1BootButton_Switch_THT:SW_PUSH_6mmSW3
1CalButton_Switch_THT:SW_Tactile_SPST_Angled_PTS645Vx39-2LFSSW1
1DebugConnector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_VerticalJ9
1GPIOConnector_PinHeader_2.54mm:PinHeader_2x02_P2.54mm_VerticalJ11
1Midi_Inw_conn_av:din-5J4
1Midi_Outw_conn_av:din-5J5
1PowerConnector_BarrelJack:BarrelJack_CUI_PJ-102AH_HorizontalJ2
1Raspberry PiConnector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_VerticalJ8
1ResetButton_Switch_THT:SW_PUSH_6mmSW2
1STM32F103C8T6Package_QFP:LQFP-48_7x7mm_P0.5mmU1
1STM_Midi_InConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJP3
1STM_Midi_OutConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJP4
1UARTConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ7
1USB PowerConnector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_VerticalJ10
1USB Type CConnector_USB:USB_C_Receptacle_Palconn_UTC16-GJ1
1VIN PowerConnector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_VerticalJ3
1ZMM5V6Diode_SMD:D_MiniMELFD2

More from amonbenson/laserharp

1
  • 2 layers79.8 × 99.1 mmLaserHarp3 - V1, the printed circuit board in 3D

    LaserHarp3 - V1

    amonbenson/laserharp

    Setup a virtual environment and install the dependencies:

    133 parts1

Similar boards

  • 4 layers189.4 × 59.1 mmFlippyDriver, the printed circuit board in 3D

    FlippyDriver

    NietoSkunk/FlippyDriver

    Driver board for Luminator MAX3000 Flip Dot Panels

    344 parts10MIT
  • 2 layers175 × 60 mmUsb rs485 switch, the printed circuit board in 3D

    Usb rs485 switch

    ucw-gadgets/usb-rs485_switch

    8x RS-485 switch and USB convertor

    357 parts
  • 2 layers55 × 20 mmTPS5430, the printed circuit board in 3D

    TPS5430

    swayerloren/KICAD_ENGINE

    AI-assisted KiCad PCB design workflow for schematics, PCB layouts, DRC, BOM/CPL, and fabrication outputs using Codex or Claude.

    44 parts10MIT
  • 4 layersSTM32F405RGT6-Breakout, the printed circuit board in 3D

    STM32F405RGT6-Breakout

    MURPHYENGINEERING/STM32F405RGT6-Breakout

    Following along with Phil's Lab: https://www.youtube.com/watch?v=t5phi3nT8OU

    62 parts1
  • 4 layers100 × 82 mm6S BMS, the printed circuit board in 3D

    6S BMS

    NTURacingTeam/nturt_kicad

    kicad files

    228 parts4
  • 4 layers50 × 50 mmSTMF103C8T6 Dev Board, the printed circuit board in 3D

    STMF103C8T6 Dev Board

    hackclub/OnBoard

    💡 Join 1,000 teenagers and make your first PCB with a $100 grant!

    52 parts915
  • 2 layers56.1 × 86.1 mmMemdump hw, the printed circuit board in 3D

    Memdump hw

    Derisis13/memdump

    One device to dump them all

    81 parts
  • 4 layers90 × 80 mmSteering Panel, the printed circuit board in 3D

    Steering Panel

    NTURacingTeam/nturt_kicad_EP7

    247 parts

Questions

How big is the LaserHarp3 - Rev3.1 PCB?

It measures 99.1 × 59.7 mm and has 2 copper layers, 1.6 mm thick.

What parts does the LaserHarp3 - Rev3.1 use?

134 parts, built around the STM32F103C8T6, 74HC595, AMS1117-3.3 and 1N4148WS. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the LaserHarp3 - Rev3.1 KiCad files?

From the amonbenson/laserharp repository on GitHub, at the commit this page was made from: the board is hardware/pcb/LaserHarp3 - Rev3.1.kicad_pcb and its schematic hardware/pcb/Diode_Array.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the LaserHarp3 - Rev3.1 design in my own project?

Its repository states no licence, so its author keeps all rights: ask amonbenson before reusing the design.