Rasperry Pi Pico Macro Keyboard
by Guitarman9119 in Circuits > Raspberry Pi
4674 Views, 27 Favorites, 0 Comments
Rasperry Pi Pico Macro Keyboard
Hello everyone, I want to share a project I am working on - a Raspberry Pi Pico macro keyboard with 12 keys that you can program. Now, this is only version 1, and I plan to add more features in the future. Since this is a macro keyboard, the possibilities are endless and using the Adafruit Library you can create your own macros with just a few lines of code.
I will show two versions in this instructable a simple one using common components which you can include as many buttons you like and then the final version which includes a custom PCB.
The photo above shows the simple version and Final PCB version 1.
Supplies
To following along this instructable you will need the following:
Simple version:
- Raspberry Pi Pico - Headers soldered
- Breadboard
- Wires
- Push Buttons
Final version:
- Raspberry Pi Pico - Headers soldered
- PCB
- Mechanical key switches
Tools needed:
- Solder
- Soldering Iron
- Solder sucker
Circuit - Simple Version
Above the schematic is included for all the necessary connections that needs to be made to the Pico. You can use any of the GPIO pins but for demonstration purpose, GP0-3 will be used to connect 4 buttons. The buttons is connected to the + Voltage rail which is 3.3V power by the Pico's 3V3 output.
We will test for a HIGH input from our GPIO pins. The buttons will be pulled down to ground by internal pull-down resistors and be LOW, and when a button is pressed the 3V3 will be detected by the pin and set to HIGH and trigger an event.
All this will be explained in the coding section
Nuke Raspberry Pi Pico
There are some circumstances where you might want to make sure your Flash memory is empty. You can do this by dragging and dropping a special UF2 binary onto your Pico when it is in mass storage mode. We will do this to ensure that there is no data in memory that will cause errors.
I have included all the relevant files and code on my GitHub repository: here.
In this repository download the flash_nuke.uf2 file.
Start with your Pico unplugged from USB. Hold down the BOOTSEL button, and while continuing to hold it (don't let go!), plug the Pico into USB. A short GIF above illustrates this step. Continue to hold the BOOTSEL button until the RPI-RP2 drive appears.
You will see a new disk drive appear called RPI-RP2.
Drag the flash_nuke.uf2 file to RPI-RP2.
Installing CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. We will use a library from the adafruit libraries for CircuitPython the HID library which will allow our Pico to be a Human Interface Device making it possible for us to receive input through a button push and send custom macro keycodes to the computer.
In this repository download the adafruit-circuitpython-raspberry_pi_pico-en_US-7.2.3.uf2 file.
Start with your Pico unplugged from USB. Hold down the BOOTSEL button, and while continuing to hold it (don't let go!), plug the Pico into USB. A short GIF above illustrates this step. Continue to hold the BOOTSEL button until the RPI-RP2 drive appears.
You will see a new disk drive appear called RPI-RP2.
Drag the adafruit-circuitpython-raspberry_pi_pico-en_US-7.2.3.uf2 file to RPI-RP2.
Once you have installed CircuitPython is will show up as a flash Drive named CircuitPy, inside the folder lib copy the adafruit_hid folder and paste it in this folder.
Coding
In this first block of code, we import all the libraries we need from CircuitPython and then all the classes needed from the HID library:
import time
import board import digitalio import usb_hid from adafruit_hid.keycode import Keycode from adafruit_hid.keyboard import Keyboard from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS from adafruit_hid.consumer_control import ConsumerControl from adafruit_hid.consumer_control_code import ConsumerControlCode
We then create variables and set them equal to functions from the HID library to initialize our input and output functions.
cc - Set up Consumer Control - Control Codes can be found here
keyboard - Set up a keyboard device. - Keycode can be found here:
write_text - Set up keyboard to write strings from macro
cc = ConsumerControl(usb_hid.devices) keyboard = Keyboard(usb_hid.devices) write_text = KeyboardLayoutUS(keyboard)
In this block of code, we create a variable for each button, set it equal to the relevant pin on the Pico, define it as a digital in, and use internal resistors to make the pin pull-down keeping the logic level LOW. (This block can be written using a for loop, shown in final code)
btn1_pin = board.GP0 btn1 = digitalio.DigitalInOut(btn1_pin) btn1.direction = digitalio.Direction.INPUT btn1.pull = digitalio.Pull.DOWN btn2_pin = board.GP1 btn2 = digitalio.DigitalInOut(btn2_pin) btn2.direction = digitalio.Direction.INPUT btn2.pull = digitalio.Pull.DOWN btn3_pin = board.GP2 btn3 = digitalio.DigitalInOut(btn3_pin) btn3.direction = digitalio.Direction.INPUT btn3.pull = digitalio.Pull.DOWN btn4_pin = board.GP3 btn4 = digitalio.DigitalInOut(btn4_pin) btn4.direction = digitalio.Direction.INPUT btn4.pull = digitalio.Pull.DOWN
We create an endless loop and test if any buttons get pressed, making the input High. If the value goes from low to high, commands are sent to the computer.
while True:
In the first button, we use the keycode class to send keys. In this example, we send the control key + a, the shortcut for select all.
# Keycode class defines USB HID keycodes to send using Keyboard. if btn1.value: keyboard.send(Keycode.CONTROL, Keycode.A) time.sleep(0.1)
The second button we use, the consumer control class, to emulate consumer control devices like the multimedia keys on keyboards.
Here we send the consumercontrol.code VOLUME_INCREMENT that will increment our volume by two.
if btn2.value: cc.send(ConsumerControlCode.VOLUME_INCREMENT) time.sleep(0.1)
For our third button, we use the KeyboardLayoutUS class to allow us to send ASCII characters, and here we are writing the text - Subscribe to NerdCave - because there are awesome and somewhat useless but entertaining projects coming up.
if btn3.value: write_text.write("Subscribe to NerdCave") time.sleep(0.1)
The last button, which is our fourth, is just a combination of the different classes to open the GUI, the windows key, and we will send VLC with a new line \n which will press enter and open the VLC application.
if btn4.value: keyboard.send(Keycode.GUI) time.sleep(0.4) write_text.write('VLC\n') time.sleep(0.4)
If you have any questions please feel free to ask.
PCB
After having a working prototype, I went to easy EasyEDA to create a schematic, making all the relevant connections from the switches to the Pico.
To order these PCB will be around 2$ for 5 boards excluding shipping.
Mechanical Keys + Female Header Pins Soldering
I had an old mechanical keyboard that stopped working, which I used to desolder mechanical key switches from. After having 12 mechanical switches I tested each one to make sure that they were all working.
After testing I soldered all the switches to the PCB and Header Female Pins.
Final Code
The final code logic follows the same as the simple version.
The only thing to note is the strange placement of mechanical switches which I did not double check when making the PCB, please use the diagram below.
''' This is a pico macro keyboard based on CircuitPython adafruit_hid library The PCB is currently in version one and thus the key layout is all crazy like this: ****This will be fixed in Final version*** key[0] Key[3] Key[6] key[1] Key[4] Key[7] key[2] Key[5] Key[8] key[9] Key[10] Key[11] '''
To change the value of a button select the relevant position using the diagram above for example if I want to change the bottom right key which is indicated Key[11] the code will look as follows:
if key[11].value: keyboard.send(Keycode.THREE) time.sleep(0.1)
The button input is also done this time using a list with two For loops
# These are the corresponding GPIOs on the Pi Pico that is used for the Keys on the PCB buttons = [board.GP0, board.GP1,board.GP2,board.GP3,board.GP4,board.GP5,board.GP6,board.GP7,board.GP8,board.GP9,board.GP10,board.GP11] key = [digitalio.DigitalInOut(pin_name) for pin_name in buttons] for x in range(0,len(buttons)): key[x].direction = digitalio.Direction.INPUT key[x].pull = digitalio.Pull.DOWN
The code should be easy to follow and change so that you can make your own custom macros.
Downloads
Video and Going Forward
I have made a video on this project and would appreciate if you can take a look at it. I making a lot of content covering the Pico and will keep sharing it on platforms like YouTube and instructables.
Going forward with this I would want to include a rotary encode for more control, and design a enclosure with some flashy RGB LEDs because who does not love LEDs.