Raspberry Pi Picoで自作キーボード(KMK FirmwareとPRK Firmware)


Raspberry Pi Picoをコントローラーに使ったキーボードを作ってみました。
以前からRaspberry Pi Picoを使ったキーボードに興味があって、KMK FirmwarePRK Firmwareを試してみたいと思い、前回つくったキーボードと一緒に基板を注文していました。(前回のキーボードのコントローラーをPro MicroからRaspberry Pi Picoに変えただけです。)
私がKMK FirmwarePRK Firmwareファームウェアの設定を行う際に調べたことを備忘録として書いてみます。
(KMK Firmwareは2022/03/16時点の最新バージョン(CircuitPythonは7.2.1)、PRK Firmwareは0.9.11を使用しました。)

キーマトリックスとキーレイアウト

今回のキーボードはキーレイアウトは4行10列です。しかし、キーマトリックスは8行5列で作りました。
(Pro Microからの流用なのでピン数を節約するためにキーマトリックスは4行10列ではなく、8行5列にしていたためです。Raspberry Pi PicoはPro Microよりピン数が多いので素直に作ったほうが良かったかもしれません。)



QMK Firmwareでは以下のようなマクロ定義でキーマトリックスとキーレイアウトを紐づけることができます。
キーマトリックスとキーレイアウトを紐づけることで、キーマップを実際のキーボードのレイアウトで設定することができるようになります。

#define LAYOUT( \
    k04, k03, k02, k01, k00, k40, k41, k42, k43, k44, \
    k14, k13, k12, k11, k10, k50, k51, k52, k53, k54, \
    k24, k23, k22, k21, k20, k60, k61, k62, k63, k64, \
              k32, k31, k30, k70, k71, k72 \
) { \
    { k00, k01, k02, k03, k04 }, \
    { k10, k11, k12, k13, k14 }, \
    { k20, k21, k22, k23, k24 }, \
    { k30, k31, k32, KC_NO, KC_NO }, \
    { k40, k41, k42, k43, k44 }, \
    { k50, k51, k52, k53, k54 }, \
    { k60, k61, k62, k63, k64 }, \
    { k70, k71, k72, KC_NO, KC_NO }, \
}

KMK Firmwareではcoording_mappingでキーマトリックスとキーレイアウトを紐づけすることができるようです。
https://github.com/KMKfw/kmk_firmware/blob/master/docs/porting_to_kmk.md#coord-mappinggithub.com
スイッチのない交点もカウントされているので注意。(18, 19, 38, 39は未接続)

import board

from kmk.kmk_keyboard import KMKKeyboard as _KMKKeyboard
from kmk.matrix import DiodeOrientation


class KMKKeyboard(_KMKKeyboard):
    row_pins = (board.GP12, board.GP13, board.GP14, board.GP15, board.GP19, board.GP18, board.GP17, board.GP16)
    col_pins = (board.GP9, board.GP10, board.GP11, board.GP21, board.GP20)
    diode_orientation = DiodeOrientation.COLUMNS

    coord_mapping = [
     4,  3,  2,  1,  0, 20, 21, 22, 23, 24, 
     9,  8,  7,  6,  5, 25, 26, 27, 28, 29,
    14, 13, 12, 11, 10, 30, 31, 32, 33, 34,
            17, 16, 15, 35, 36, 37,
    ]

PRK Firmwareではinit_matrix_pinsでキーマトリックスとキーレイアウトを紐づけすることができるようです。
github.com

kbd = Keyboard.new

r0 = 12
r1 = 13
r2 = 14
r3 = 15
r4 = 19
r5 = 18
r6 = 17
r7 = 16
c0 = 9
c1 = 10
c2 = 11
c3 = 21
c4 = 20

kbd.init_matrix_pins(
    [
        [ [r0, c4], [r0, c3], [r0, c2], [r0, c1], [r0, c0], [r4, c0], [r4, c1], [r4, c2], [r4, c3], [r4, c4] ],
        [ [r1, c4], [r1, c3], [r1, c2], [r1, c1], [r1, c0], [r5, c0], [r5, c1], [r5, c2], [r5, c3], [r5, c4] ],
        [ [r2, c4], [r2, c3], [r2, c2], [r2, c1], [r2, c0], [r6, c0], [r6, c1], [r6, c2], [r6, c3], [r6, c4] ],
        [    nil,        nil,    [r3, c2], [r3, c1], [r3, c0], [r7, c0], [r7, c1], [r7, c2],     nil,        nil     ]
    ]
)

タップとホールド

1つのキーで通常のキー(タップ、短押し)と修飾キー(ホールド、長押し)を切り替えることができます。
キー数の少ないキーボードではよく使用する機能です。
KMK Firmware

RAISE_ENT = KC.LT(1, KC.ENTER, prefer_hold=True, tap_interrupted=False, tap_time=150)

PRK Firmware

kbd.define_mode_key :RAISE_ENT,   [ :KC_ENTER, :raise, 150, 150 ]

まだ自分に合ったタップのタイムアウト時間を見つけられていません😋

ロータリーエンコーダ

KMK Firmware

encoder_handler.map = (
    ((KC.MW_UP, KC.MW_DOWN),),
    ((KC.AUDIO_VOL_UP, KC.AUDIO_VOL_DOWN),),
)

レイヤー毎にロータリーエンコーダの動作を切り替えることができます。
PRK Firmware
レイヤー毎にロータリーエンコーダの動作を切り替える方法は分かりませんでした。

RGB LED

LEDにはSK6812MINIを使用しました。
KMK Firmware
CircuitPythonの場合、別途NeoPixelのライブラリが必要です。
https://github.com/KMKfw/kmk_firmware/blob/master/docs/rgb.md#circuitpythongithub.com
github.com
PRK Firmware
ドキュメントに従い、設定することで使用できました。
github.com

KMK FirmwareでModuleを使って機能を追加してみる

キーを押したときにRaspberry Pi Pico上に実装されているLEDを点灯させる機能を追加してみます。

import board
import digitalio

from kmk.modules import Module


class Lchika(Module):
    def __init__(self):
        self.led = digitalio.DigitalInOut(board.GP25)
        self.led.direction = digitalio.Direction.OUTPUT

    def process_key(self, keyboard, key, is_pressed, int_coord):
        if is_pressed:
            self.led.value = True
        else:
            self.led.value = False

        return key

    def during_bootup(self, keyboard):
        return

    def before_matrix_scan(self, keyboard):
        return

    def after_matrix_scan(self, keyboard):
        return
        
    def before_hid_send(self, keyboard):
        return

    def after_hid_send(self, keyboard):
        return

    def on_powersave_enable(self, keyboard):
        return

    def on_powersave_disable(self, keyboard):
        return

Moduleを継承したクラスを作り、キーの押下の状態が取得できるprocess_keyメソッドを実装することで実現できました。

まとめ

Raspberry Pi Picoを使ったキーボードを作って、KMK FirmwarePRK Firmwareを試してみました。
QMK Firmwareと違ってビルド不要で、ファイルをRaspberry Pi Picoへコピーするだけで設定が反映されるのはとても新鮮かつお手軽でした。
ファームウェアのビルド環境の構築も必要なく、PythonRubyですぐ記述できるのでとっつきやすいです。
キーボードの機能だけではなく、ロータリーエンコーダやRGB LEDの機能も使ってみたいと思って基板を作成しましたが、Gherkin for the Raspberry Pi Picoならお手軽にRaspberry Pi Picoの自作キーボードを楽しむことができます。
OLEDディスプレイなどはまだリリースされているバージョンでは対応していないので、実装されたら試してみたいと思います。
talpkeyboard.net