Rasperry Pi Pico Macro Keyboard

by Guitarman9119 in Circuits > Raspberry Pi

4551 Views, 27 Favorites, 0 Comments

Rasperry Pi Pico Macro Keyboard

ezgif-5-a96858cf04.gif
vlcsnap-2022-04-03-08h54m08s746.png
vlcsnap-2022-04-03-08h51m54s487.png

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

Screenshot 2022-04-02 152025.png

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

ezgif-5-b4a7828239.gif
Screenshot 2022-04-02 162546.png

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

ezgif-5-11ff62507c.gif

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

Screenshot 2022-04-02 191401.png
Screenshot 2022-04-02 191447.png

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

ezgif-2-67b6a6d9cf.gif

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

Raspberry Pi Macro Keyboard

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.