BLEキーボードをつくって、iPadを制御しよう
ESP32を使って、BLEキーボードを作りました。
iPadを制御します↓。
関連記事
bleマウスも作りました。
😟困ったこと
iPadで電子書籍を読むことが多いのですが、持っていると疲れます。
また、ページをめくるのにスワイプ動作操作がいるため、面倒です。
楽な姿勢で、ページめくりができないかというのが悩みでした。
💡やったこと
- 利用者は、ジョイスティック/スイッチを操作する
- スイッチには、複数ある
- ※ジョイスティック/スイッチの概要は後述
- マイコンボード(ESP32)は、スイッチ状態を監視している
- スイッチの変化に応じて、BLEキーボードコマンドを送信する
- iPadは、キーボードコマンドを受け制御される
今回は、ESP32を使用して作成しました。
仕様検討
電子書籍のページめくりがメインなので、ページめくりのために、矢印が必要になります。
また、Kindleの立ち上げもできるようにします。
以下としました。
デバイス | 動作 | iPad側への送信 |
---|---|---|
🕹X軸 | ←操作 | キーボード Arrow Left |
🕹X軸 | →操作 | キーボード Arrow Right |
🕹Y軸 | ↑操作 | キーボード Arrow Up |
🕹Y軸 | ↓操作 | キーボード Arrow Down |
🕹スイッチ1 | 押下 | Kindleアプリの起動 |
スイッチ2 | 押下 | ホーム画面 |
スイッチ3 | 押下 | キーボード Arrow Left |
スイッチ4 | 押下 | キーボード Arrow Right |
🔧パーツ一覧
機材名 | 備考 |
---|---|
ESP32評価ボード | ESP32-WROVER 開発ボード/ESP32-WROOM 開発ボードのどちらでも可 |
🕹ボード | ジョイスティックおよびスイッチセット - Amazonで購入 |
タクトスイッチ | 3つ使用 |
接続図
MPU側でプルアップ設定を行うため、抵抗は不要です。
💻環境
VScode - PlatformIOを使用します。
PlatformaIOの環境構築は、↓にまとめておきました。
ライブラリ - ESP32 BLE Keyboard
ESP32をBLEキーボードにするために、下記のライブラリを使用します。
インストール手順は、以下となります。
- PlatformIO - Librariesを選択し、ESP32-BLE-Keyboardを検索
- ESP32-BLE-Keyboardを選択
- "Add to Project"を選択
- プロジェクトを指定 - 今回は、"ipadBleKbd"というプロジェクトを指定
- "Add"を選択
-
lib_deps = t-vk/ESP32 BLE Keyboard@^0.3.2
これで、インクルードできるようになります。
#include <BleKeyboard.h>
📝手順
以下を記載します。
- 筐体の作成
- ソフト設計/コード
筐体の作成
3Dプリンタで筐体を作成しました。
親指で、🕹を制御できるように上に配置しました。
スイッチは、側面に配置しました。
ソフト設計/コード
最初はシングルタスクで書いたのですが、後々拡張していきたいと思い、マルチタスクで書き直しました。
FreeRTOSを使用しています。
タスク構成
タスク名 | 役割 |
---|---|
スイッチ監視タイマー | スイッチのDOWN/UPの変化を監視する |
ジョイスティック監視タイマー | ジョイスティックの変化を監視する |
メッセージ管理タスク | スイッチ/ジョイスティックのイベントをキーボード管理に通知 |
キーボード管理タスク | メッセージ管理から受けたイベントをBleキーボード制御を送信 |
コード関連
コード自体は、githubにアップしてあります。
ポイントを記載します。
bleキーボードライブラリ
初期化は以下のように行います。
#include <BleKeyboard.h>
static BleKeyboard s_xBleKbd;
s_xBleKbd.begin();
beginの後で、ペアリングできる状態になります。
iPadからペアリングを実施できます。
接続しているかどうかは以下で判定できます。
if (s_xBleKbd.isConnected())
{
// !!!接続中!!!
}
キーボードの送信する場合は、以下となります。
// 矢印←を送信
s_xBleKbd.write(KEY_LEFT_ARROW);
// Commandキー(Windowsキー)を押しながら、"h"を送信
s_xBleKbd.press(KEY_LEFT_GUI);
delay(10);
s_xBleKbd.print("h");
delay(10);
s_xBleKbd.release(KEY_LEFT_GUI);
delay(50);
Kindleの起動は以下となります。
速すぎる送信は、iPad側で取りこぼします。
実機動作を見ながら、delay関数を入れています。
/**
* @brief kindle appの起動
*/
static void vProcSw_StartKindle(void)
{
// ->home (Cmd + h)
s_xBleKbd.press(KEY_LEFT_GUI);
delay(10);
s_xBleKbd.print("h"); //文字を送信
delay(10);
s_xBleKbd.release(KEY_LEFT_GUI);
delay(50);
// ->command (Cmd + Space)
s_xBleKbd.press(KEY_LEFT_GUI);
delay(50);
s_xBleKbd.print(" "); // space
delay(50);
s_xBleKbd.release(KEY_LEFT_GUI);
delay(50);
// Erase the string with backspace
for (int i = 0; i < 10; i++)
{
s_xBleKbd.write(KEY_BACKSPACE);
delay(50);
}
// input - "kindle"
delay(500);
s_xBleKbd.print("kindle");
delay(50);
// input - "enter"
s_xBleKbd.write(KEY_RETURN);
delay(50);
return;
}
ジョイスティック監視(/スイッチ監視)
ジョイスティック監視を例に説明します。
25msec毎に、コールされるタイマーを使用しました。
xTimerCreate()/xTimerReset()は、FreeRTOS - APIとなります。
#define JS_CHECK_TIME (25) // JoyStickチェック間隔:25msec
...
static TimerHandle_t s_xTimerJs = NULL;
...
ErType_t xInitJs(void)
{
...
// text name, timer period, auto-reload, number of times, callback
s_xTimerJs = xTimerCreate(cName, JS_CHECK_TIME, pdTRUE, (void *)0, vTimerCallbackJs);
if (NULL == s_xTimerJs)
{
Serial.printf("%s : error - xTimerCreate\n", __func__);
return ER_FAIL;
}
if (pdTRUE != xTimerReset(s_xTimerJs, JS_CHECK_TIME))
{
Serial.printf("%s : error - xTimerReset\n", __func__);
return ER_FAIL;
}
下記の関数が25msec毎にコールされます。
static void vTimerCallbackJs( TimerHandle_t xTimer)
{
int32_t x = analogRead(JS_ASGN_AXIS_X);
int32_t y = analogRead(JS_ASGN_AXIS_Y);
...
x, yには、0-4095の値で取得されます。
今回の接続だと以下のような値が取得されます。
ジョイスティック状態 | x値 | y値 |
---|---|---|
Idle | 2048付近 | 2048付近 |
左[←] | 0付近 | 2048付近 |
右[→] | 4095付近 | 2048付近 |
上[↑] | 2048付近 | 4095付近 |
下[↓] | 2048付近 | 0付近 |
コード全体
さいごに
久しぶりにライフハック的なものが作れてよかったです。
デバッカなしで、RTOSのデバックはなかなか大変でした。
同じ仕組みでBleマウスもつくったので、後日紹介できればと思います。
参考URL
Discussion