連載 ラズパイPicoでキーボードを作ろう サポート・ページ

Interface 2021年9月号 井田 健太;Picoで作るキーボード…カギは制御用ファームウェアKMK

KMKファームウェアのあらましと書き込み方を参考にしてもらうために掲載します.ただし,以下の記事において,●KMK本体のコピー という項目では,10月号筆者:篠田氏が提供するプログラムをフォルダごとPicoにコピーしてください.

● きっかけ…自作キーボードでも使われ始めたラズベリー・パイPico
近年,キーボードの筐体やそれを制御する電子回路を設計してオリジナルのキーボードを作成する「自作キーボード」がはやっているようです.キーボードの主な構成部品は以下の通りです.
・キーを構成するためのキー・スイッチとキー・キャップ
・キー・スイッチと制御回路を配線するためのプリント基板
・キー・スイッチの状態を読み取りホストとの通信を行うマイコン
・基板を保護するための筐体
多くの自作キーボードはホストとUSBで接続するため,自作キーボードの制御にはATmega32U4(マイクロチップ・テクノロジー)を使用したPro Micro(SparkFun Electronics)のような,小型のUSBデバイス機能付きマイコン・ボードがよく用いられます.
一方,同様の機能を持つマイコン・ボードとして,ラズベリーパイ財団が製造・販売しているラズベリー・パイPico(以降,Pico)があります.このためPicoが発売されて以降,Picoを使ってキーボードを制御するという話を見かけるようになりました.本誌2021 年8 月号のPico 特集でもCircuitPythonを用いたキーボードの作例を紹介しています.
本稿では,さらに高機能なキーボード制御用ファームウェア「KMK」とPicoを使ってキーボードを制御する方法を紹介します(写真1,写真2).

写真1 今号で紹介するKMK ファームウェアを実装するために用
意したキーボード…ベースはPiPi Gherkin

写真2 8 月号(Pico特集)で紹介したオリジナル・キーボード
CircuitPython でサッと作った

 

キーボード制御用ファームウェアKMKの機能

KMKはCircuitPythonで記述されているオープンソースのキーボード制御用ファームウェアです.GPLv3ライセンスに基いて誰でも使用できます.
CircuitPythonは組み込み向けのPython実行環境です.同じく組み込み向けのPython実行環境であるMicroPythonをベースに,Adafruit社が独自に機能を拡張しています. ESP32 やATSAMD(SAM Dxx
ファミリ)といったさまざまなマイコンを使ったマイコン・ボードに対応しており,Picoにも対応しています.KMKはCircuitPythonで記述されているため,Picoでも動作します.
KMKにはキーボードで必要となる単純なキー・スイッチの入力機能に加えて,複雑なキー入力をサポートする機能などが実装されています.ここでは主要機能の一部を紹介します.

● 分割キーボードのサポート
キーボードには,全キーが1つの筐体に収まっているものの他に,複数の筐体に分かれている分割キーボードと呼ばれるものがあります.KMKは1つの筐体のキーボードの他に,2体構成の分割キーボードに対応しています.

● Bluetooth サポート
Pico では使用できませんが,CircuitPythonがBluetooth機能をサポートしているESP32などのマイコンを使用したボードにおいて,Bluetoothによる無線接続が可能です.

● LED 制御
キーボードの中には,キー・スイッチやその裏面にLEDが設置されている品があります.KMKにはこれらのLED を制御する機能があります.

● 省キー・スイッチ数対応機能
自作キーボードの中には,市販品にないような少ないキー・スイッチ数で必要な入力を行えるようにしたものがあります.キー・スイッチ数を減らす方法は幾つかありますが,KMKは次の機能をサポートしています.
▶押し時間による機能切り替え
キー・スイッチを押下している時間の長短によっ
て,キー・スイッチの機能を切り替えることができま
す.短時間押下して離した場合はZなどの通常のアル
ファベットの文字入力,長時間押しっぱなしにした場
合はCTRL などのように,修飾キーとしての使い方が
できます.
▶レイヤ切り替え機能
特定のキーを押している間,または特定のキーを押
すごとに,キー・スイッチに対応する機能を切り替え
る機能です.例えば,デフォルトのレイヤとしてアル
ファベットのみ割り当てたキー・マップを用意してお
き,特定のキーを押している間は,数字や記号のキー・
マップに切り替えるといった使い方ができます.
▶タップ・ダンス
一定時間内に同一のキーを何度入力したかによって,キー・スイッチに対応する機能を切り替えます.通常の文字入力を入力回数に応じて切り替える他に,前述のレイヤ切り替えを複数回入力に割り当てるといったことができます.

KMKの導入

PicoにKMKを導入する手順を説明します.

● CircuitPythonの導入
KMKを導入する前に,以下の手順でPico にCircuitPythonの実行環境を書き込む必要があります.
▶ステップ1
CircuitPythonの公式サイトからPico用のCircuitPython 6.3.0のファームウェアをダウンロードします.
https://circuitpython.org/board/raspberry_pi_pico/
▶ステップ2
PicoのBOOTSELボタンを押しながらUSBケーブルを接続し,Picoに対応するドライブにステップ1でダウンロードした.uf2ファイルをドラッグ&ドロップします.
● KMK本体のコピー
KMKのCircuitPythonスクリプトはGitHub 上で公開されており,これらのCircuitPythonスクリプトをPicoに書き込むことによってKMKを使用できる状態になります.
▶ステップ1
以下のKMKのGitHubリポジトリからKMKの本体をダウンロードします.
https://github.com/KMKfw/kmk_firmware/archive/7a30cc8ccea4111d9b953033599f176579b8091b.zip
▶ステップ2
ダウンロードしたZipファイルを展開し,中にあるkmkディレクトリをPicoのlibディレクトリの下に丸ごとコピーします(図1).

図1 KMK 本体のコピー
展開したZip ファイルからkmkディレクトリをPico に丸ごとコピーする

ここまででPico へのCircuitPythonとKMKの導入が完了したので,実際にPicoを使ったキーボードを制御してみます.今回はPicoを使ったキーボードとして,組み立て済みのPiPi Gherkin(写真1)を借りられたので,こちらで動作を確認します.

● キーボード PiPi Gherkin
PiPi Gherkin は,3× 10 の配列でキー・スイッチを隙間なく並べた形状のPicoで制御できるキーボードです(図2).

図2 Pico とキーとの接続図

もともとは同じ作者によるGherkinキーボードがあり,Gherkinの制御ボードをPro MicroからPicoに置き換えた構成となっています.開発者のブログ(2)上で基板発注に必要なガーバ・ファイルが公開されており,誰でも基板を発注して組み立てることができます.

● キー・スイッチの配線
PiPi Gherkinの基板上のキー・スイッチの配列は3×10ですが,内部の接続としては5×6のマトリクスとなっています(図3).

図3 PiPi Gherkin 基板のキー配置とPico の端子との関係

 

各キーは列方向のGPIOからスイッチとダイオードを介して行方向のGPIOに接続されています.従って,あるキー・スイッチが接続さ
れている列方向のGPIOの出力を‘1’とした状態で行方向のGPIOの値を読み取り,その値が‘1’であればキーが押されていることが分かります.
● KMKの設定の作成
KMKを動かすにはキーボードのハードウェア構成やキー・スイッチと入力内容の対応関係を設定する必要があります.通常,これらの設定はCircuitPythonが起動直後に自動実行するcode.pyに記述します.PiPi Gherkin用の設定は開発者のサイトで公開されていますが,執筆時点のKMKで動かすには数カ所の修正が必要です.リスト1 にcode.pyの内容を示します.

 

リスト1 キー・スイッチと入力内容の対応関係を設定するcode.pyの内容

# PiPi-keyboard – Raspberry Pi PICO ported for KMK revision 7a30cc8ccea4111d9b953033599f176579b8091b
# The original file is here – https://git.40percent.club/di0ib/Misc/src/branch/master/PiPi%20Gherkin/code.py
import board
from kmk.keys import KC
from kmk.kmk_keyboard import KMKKeyboard
from kmk.matrix import DiodeOrientation
from kmk.hid import HIDModes
from kmk.modules.layers import Layers
from kmk.modules.modtap import ModTap

keyboard = KMKKeyboard()

# モジュールの追加
modtap = ModTap() # ModTapモジュール
layers_ext = Layers() # Layersモジュール
keyboard.modules = [layers_ext, modtap]

# 列ピンの定義
keyboard.col_pins = (board.GP2, board.GP3, board.GP4, board.GP5, board.GP6, board.GP7)
# 行ピンの定義
keyboard.row_pins = (board.GP8, board.GP9, board.GP10, board.GP11, board.GP12)
# USBコネクタを右向きにしたい場合は、行・列のピンの順序を反転してキー配列を180度回転する
# keyboard.col_pins = tuple(reversed(keyboard.col_pins))
# keyboard.row_pins = tuple(reversed(keyboard.row_pins))
# ダイオードの方向 = 列→行
keyboard.diode_orientation = DiodeOrientation.COLUMNS
# デバッグ無効 (Trueにするとターミナルにデバッグメッセージが出力される)
keyboard.debug_enabled = False

keyboard.keymap = [
[ # デフォルトのレイヤ (レイヤ0)
KC.Q, KC.W, KC.E, KC.R, KC.T, KC.Y, KC.U, KC.I, KC.O, KC.P,
KC.A, KC.S, KC.D, KC.F, KC.G, KC.H, KC.J, KC.K, KC.L, KC.ESC,
KC.MT(KC.Z, KC.LCTRL), KC.MT(KC.X, KC.LALT), KC.LT(3, KC.C), KC.LT(4, KC.V), KC.LT(2, KC.BSPC),
KC.LT(1, KC.SPC), KC.LT(5, KC.B), KC.MT(KC.N, KC.RALT), KC.MT(KC.M, KC.RCTRL), KC.MT(KC.ENT, KC.RSFT),
],
[ # レイヤ1
KC.N1, KC.N2, KC.N3, KC.N4, KC.N5, KC.N6, KC.N7, KC.N8, KC.N9, KC.N0,
KC.F1, KC.F2, KC.F3, KC.F4, KC.F5, KC.F6, KC.F7, KC.F8, KC.F9, KC.F10,
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.DEL, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS,
],
[ # レイヤ2
KC.EXLM, KC.AT, KC.HASH, KC.DLR, KC.PERC, KC.CIRC, KC.AMPR, KC.ASTR, KC.LPRN, KC.RPRN,
KC.F11, KC.F12, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.GRV,
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS,
],
[ # レイヤ3
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.MINS, KC.EQL, KC.LBRC, KC.RBRC, KC.BSLS,
KC.TAB, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.COMM, KC.DOT, KC.SLSH, KC.SCLN, KC.QUOT,
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.LEFT, KC.DOWN, KC.UP, KC.RGHT,
],
[ # レイヤ4
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.UNDS, KC.PLUS, KC.LCBR, KC.RCBR, KC.PIPE,
KC.TAB, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.LABK, KC.RABK, KC.QUES, KC.COLN, KC.DQUO,
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.HOME, KC.PGDN, KC.PGUP, KC.END,
],
[ # レイヤ5
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS,
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS,
KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS, KC.TRNS,
],
]

if __name__ == ‘__main__’:
keyboard.go(hid_type=HIDModes.USB) # USB HID有効

 

基本的な流れは次の通りです.
1. KMKの各モジュールをインポートする
2. KMKのメイン・クラス(KMKKeyboard)のインスタンスを作成する
3. 必要に応じてモジュールのインスタンスを作成し,KMKKeyboardのmodulesにモジュールのリストを設定する
4. col_pins,row_pinsにそれぞれ列のピン,行のピンを設定する
5. KMKKeyboardのdiode_orientationをハードウェアのマトリクスのダイオードの向きに合わせて設定する.列側がアノードならDiodeOrientation.COLUMNS,行側がアノードならDiodeOrientation.ROWS
6. KMKKeyboardのkeymapにキー・スイッチに対応するキー・コードのマッピングを設定する.Layersモジュールで複数レイヤを使う場合は使いたい分のレイヤを設定する
7. keyboard.go(hid_type=HIDModes.USB)を呼び出してキーボードの処理を開始する

keymapに設定しているキーコードのうち,KC.LT()の形式のキー・コードは,押している間はレイヤを切り替えることを表します.例えば,KC.LT(1,KC.SPC)の場合,短時間押下して離せばKC.SPC,つまりスペースを入力します.一方,押しっぱなしにした状態にするとレイヤ1に切り替わります.このキーを押している状態で左上のキーを押すと,KC.QではなくKC.N1,つまり,数字の1 が入力されます.
KC.MT()形式のキー・コードは,押しっぱなしにしている間は第2引数で指定した修飾キーを押しているものとして動作します.また,押してから離すまでの時間が短時間の場合はキーを離したときに第1引数に指定したキー・コードを入力したものとします.これにより,通常のキーとCTRLやALTといった修飾キーのキーを共用できます.
● code.pyの配置
Picoのルート・ディレクトリにcode.pyをコピーします.書き込みが完了すると自動的にリセットがかかります.
● キー配列のカスタマイズ
code.pyのkeymap設定部分を書き換えることにより,自分の好きなキー配列に設定できます.
*  *  *
Picoにキーボード制御用ファームウェアKMKを導入するのはかなり簡単で,また,キーボードを制御するのに十分な機能を持っていることが分かりました.今後,Picoの入手性が改善されれば,PicoとKMKを使用した自作キーボードが増えてくるのではないかと思われます.

▪参考文献▪
(1) KMK: Clackety Keyboards Powerd by Python,GitHub.
https://github.com/KMKfw/kmk_firmware
(2) 40% KEYBOARDS,PiPi Gherkin.
https://www.40percent.club/2021/02/pipigherkin.
html
いだ・けんた