Ik besloot de overgebleven onderdelen van mijn mechanische toetsenbord en een Raspberry Pi Pico nuttig te gebruiken door er een MacroPad mee te bouwen. Dat is een klein toetsenblok waarop je elke schakelaar met een bepaalde toets of toetsencombinatie kunt programmeren, zodat je vaak gebruikte sneltoetsen snel kunt uitvoeren. Streamers gebruiken zo’n toestel vaak om in OBS van scène te wisselen of een animatie te activeren, waardoor ze dikwijls StreamDecks worden genoemd.
Benodigdheden
Voor dit project had ik veel onderdelen al bij de hand. De schakelaars, leds en toetsdoppen waren over van mijn toetsenbordproject. Als je helemaal van nul wilt beginnen, is dit het boodschappenlijstje.
- 1x MacroPad-behuizing (3D-geprint, STL hier)
- 1x Raspberry Pi Pico
- 9x mechanische toetsenbordschakelaar (Gateron, Cherry MX, Kailh … ze zouden allemaal moeten passen)
- een set toetsdoppen (bijvoorbeeld voor de toetsen van een numeriek toetsenblok)
- 9x 1,8mm-led van 2 V (stroomsterkte 15–20 mA) (optioneel)
- 9x weerstand van 82 ohm (optioneel)
- 1x opener voor schakelaars (optioneel)
- 4x M3-bout (14–16 mm lang; ik heb bouten van 20 mm ingekort)
- wat krimpkous
- draad, met een enkele kern en soepel
- soldeergereedschap
- een derde hand
- een hetelijmpistool
- een micro-USB-kabel
De behuizing ontwerpen en printen
Omdat er geen 3x3-MacroPad-behuizingen bestonden waarin een Raspberry Pi Pico paste, combineerde ik met Blender twee ontwerpen tot een geschikte behuizing. Ik begon met een ontwerp met een Pro Micro als kern en verving de onderdelen die de Pro Micro vasthouden door het binnenste van een Pico-behuizing. Daarnaast maakte ik de behuizing wat hoger omdat er meer draden in moeten passen. Het resultaat is een mooie behuizing met een plaats waarin een Raspberry Pi Pico perfect past. Ik geef de voorkeur aan PETG, geprint met deze instellingen, maar PLA werkt ook prima.
Als je ze zelf wilt printen, haal je mijn ontwerp van Thingiverse of download je de STL-bestanden rechtstreeks hier.
De behuizing afwerken
Ik wilde de behuizing laten passen bij mijn huidige toetsenbord, dat een donkergrijze behuizing van geanodiseerd aluminium heeft. Na het schuren en aanbrengen van grondverf kreeg de behuizing daarom een zwarte basislaag. Daarna depte ik er met een spons wat Vallejo Gun Metal op (acrylverf voor miniaturen). Ten slotte bracht ik enkele lagen blanke lak aan om de verf af te sluiten en voor een duurzame afwerking te zorgen die ook prettiger aanvoelt.
De schakelaars voorbereiden
(Als je geen leds gebruikt, kun je deze stap overslaan.)
Voor dit project gebruikte ik mechanische Gateron Green-schakelaars. Daarin is plaats voor een led van 1,8 mm, maar je moet de schakelaar openen om die te installeren. Dat kan met speciaal gereedschap dat je kunt 3D-printen. Ik gebruikte dit exemplaar, dat vrij goed werkte. Sommige schakelaars, zoals die van Kailh, zijn aan één kant open. Daarin kun je dus leds plaatsen zonder de behuizing te openen.
De schakelaars met de hand bedraden
Installeer eerst de schakelaars in de behuizing. Ze klikken vast, maar let op de oriëntatie. Ik koos voor een north-facing configuratie waarbij de leds zich bovenaan de schakelaar bevinden. Dat ziet er beter uit met doorschijnende toetsdoppen. Op elke schakelaar plaatste ik een weerstand tussen de massa van de led en een pin van de schakelaar (zie hieronder). Die aansluitingen werden vervolgens voor alle negen schakelaars met leds aan elkaar en aan de massa van de Pi Pico gekoppeld. Aan de andere pinnen van de schakelaars en leds soldeerde ik telkens een draad. Die gingen elk naar een eigen GPIO-pin, zodat alle leds afzonderlijk kunnen worden aangestuurd en de schakelaars rechtstreeks kunnen worden uitgelezen.
De foto hierboven toont hoe elke weerstand met de massa van de led en de schakelaar werd verbonden. Vervolgens werden alle massa-aansluitingen met een lange draad aan elkaar gesoldeerd en verbonden met het GND-contactpunt van de Pico. De andere twee pinnen (hier met rode draden) werden met GPIO-pinnen verbonden. Het volledige schema staat hieronder.
De Raspberry Pi Pico voorbereiden
Voordat er Python-code kan draaien, moeten we de juiste firmware op de Pico installeren. De Adafruit HID-bibliotheek, waarmee je toetsaanslagen kunt nabootsen, is alleen beschikbaar voor CircuitPython. (Ik kon geen equivalent vinden voor MicroPython.) Om alles in te stellen, raad ik aan enkele video’s van Novatech Spirit te bekijken. Hij heeft uitstekende instructies om de Thonny IDE, CircuitPython en de Adafruit HID-bibliotheek in te stellen. Een andere video op zijn kanaal legt uit hoe je een eenvoudige MacroPad maakt. De onderstaande code is op dat project gebaseerd. Waar hij code voor elke knop kopieert en plakt, staat hier een elegantere oplossing. Bovendien zijn enkele extra trucs nodig om de knoppen met geanimeerde leds te laten werken.
Kort samengevat download je eerst het .UF2-bestand van CircuitPython. Houd de BOOT_SEL-knop op de Pi Pico ingedrukt
terwijl je hem met de pc verbindt. De Pi verschijnt als een schijf. Kopieer het .UF2-bestand naar die schijf, waarna het
apparaat opnieuw opstart. Zodra het opnieuw verschijnt, is het zoals voordien als een schijf gekoppeld, maar staan er
nieuwe bestanden op. Download de code van Adafruit HID en kopieer de map adafruit_hid naar de map lib op
de Pi. De onderstaande code moet als code.py op de Pico worden geplaatst.
De code
De code bestaat uit twee belangrijke delen. Het eerste deel bevat na het importeren van de bibliotheken de
configuratie. Het bepaalt welke GPIO-pinnen met leds en knoppen verbonden zijn en welke toetsen we aan de knoppen willen
koppelen. Het is belangrijk dat alles in deze lijsten in de juiste volgorde staat. Daarna worden ook het toetsenbord,
de knoppen en de PWM-cycli voor de leds geïnitialiseerd. Twee arrays, duty_cycles en last_pressed, houden de
huidige helderheid van elke led bij en hoelang geleden een toets voor het laatst werd ingedrukt.
Daarna volgt de code die de microcontroller vertelt welke hardware verbonden is, hoe hij naar toetsaanslagen moet luisteren en hoe hij erop moet reageren. Omdat CircuitPython op de Pi Pico geen multithreading of interrupts lijkt te ondersteunen, moet alles in de hoofdlus gebeuren. Die bestaat uit enkele stappen die telkens opnieuw worden uitgevoerd …
- Controleer of een knop (op de MacroPad) werd ingedrukt, stel indien nodig een waarde in
last_pressedin en zet de led van de knop induty_cyclesop volle helderheid - Boots indien nodig toetsaanslagen na als HID-apparaat
- Boots indien nodig het loslaten van toetsen na als HID-apparaat
- Verlaag
last_pressed - Werk de duty cycles van de leds bij en verlaag de waarden in
duty_cylcesom ze te laten uitdoven - Wacht een minimale tijd
import board
import digitalio
import pwmio
import time
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
# Configuration, which LED pins are used, which buttons, how buttons map to macros
led_pins = [board.GP18,board.GP17,board.GP16,board.GP21,board.GP20,board.GP19, board.GP27, board.GP26,board.GP22]
button_pins = [board.GP13,board.GP14,board.GP15, board.GP10,board.GP11,board.GP12,board.GP7,board.GP8,board.GP9]
button_mapping = [
[Keycode.LEFT_CONTROL, Keycode.F1],
[Keycode.LEFT_CONTROL, Keycode.F2],
[Keycode.LEFT_CONTROL, Keycode.F3],
[Keycode.LEFT_CONTROL, Keycode.F4],
[Keycode.LEFT_CONTROL, Keycode.F5],
[Keycode.LEFT_CONTROL, Keycode.F6],
[Keycode.LEFT_CONTROL, Keycode.F7],
[Keycode.LEFT_CONTROL, Keycode.F8],
[Keycode.LEFT_CONTROL, Keycode.F9]]
keyboard = Keyboard(usb_hid.devices)
# Set up buttons
buttons = [digitalio.DigitalInOut(bp) for bp in button_pins]
for btn in buttons:
btn.direction = digitalio.Direction.INPUT
btn.pull = digitalio.Pull.UP
# Set up LEDs
leds = [pwmio.PWMOut(lp, frequency=1000, duty_cycle=0) for lp in led_pins]
# Set Initial Duty Cycles to 0 for each LED
duty_cycles = [0 for _ in led_pins]
# Last Pressed
last_pressed = [0 for _ in button_pins]
while True:
for ix, btn in enumerate(buttons):
if not btn.value:
duty_cycles[ix] = 65025
last_pressed[ix] = 25 if last_pressed[ix] <= 1 else last_pressed[ix]
for ix, lp in enumerate(last_pressed):
if lp == 25:
# print("button %d pressed" % ix)
keyboard.press(*button_mapping[ix])
for ix, lp in enumerate(last_pressed):
if lp == 1:
# print("button %d released" % ix)
keyboard.release(*button_mapping[ix])
last_pressed = [max(0, lp - 1) for lp in last_pressed]
for ix, led in enumerate(leds):
led.duty_cycle = duty_cycles[ix]
duty_cycles[ix] = max(duty_cycles[ix] - 900, 0)
time.sleep(0.01)
Met deze code licht de led onder elke knop op zodra je de knop indrukt en dooft hij daarna snel uit. Je kunt de
uitdoofsnelheid aanpassen door 900 in duty_cycles[ix] = max(duty_cycles[ix] - 900, 0) te vervangen door een
hogere of lagere waarde om de led respectievelijk sneller of trager te laten uitdoven.
In mijn configuratie koppelde ik knoppen 1 tot 9 aan CTRL+F1 tot CTRL+F9. Dat zijn veelgebruikte sneltoetsen in verschillende programma’s (CTRL+F4 sluit bijvoorbeeld het huidige tabblad in Chrome en CTRL+F5 voert een harde vernieuwing uit, …). Je kunt ze ook aan snelkoppelingen op het bureaublad koppelen. Uiteindelijk kan het om het even wat zijn: pas gewoon de koppeling in de code aan en klaar.
De behuizing sluiten
Zodra je zeker weet dat alles werkt, plaats je alles voorzichtig in de behuizing. Soldeerverbindingen kunnen breekbaar zijn, dus wees voorzichtig met de bedrading en oefen geen kracht uit, want daardoor kunnen verbindingen breken. Je hebt enkele puntjes hete lijm nodig om de Pi Pico op zijn plaats te houden in de onderste helft van de behuizing. Gebruik de M3-bouten om de behuizing dicht te schroeven. Er is geen schroefdraad, maar het zou goed genoeg moeten werken doordat de bout grip krijgt op de ribbels in de 3D-geprinte gaten. Open en sluit de behuizing alleen niet vaker dan nodig, want die ribbels slijten snel.
Conclusie
Doordat ik de behuizing 3D-printte en reserveschakelaars en -toetsdoppen gebruikte, was dit voor mij een vrij goedkoop project. Het werkt ook behoorlijk goed: er is weinig tot geen vertraging wanneer je op een knop drukt. Het zou leuk zijn om de software complexer te maken. Meerdere configuraties hebben en ertussen wisselen met toetsencombinaties zou een handige functie kunnen zijn, maar voorlopig zullen negen extra knoppen moeten volstaan. Iets complexers is voor een toekomstige post.
Links
Vond je dit artikel interessant? Trakteer me op een koffie