インターン2023 参加報告 Bluetoothアプリ開発編

はじめに

はじめまして、nefrockの2023年度インターンシップに参加した東京工業大学修士1年の森合です。

今回は、私がインターンシップで担当させていただいたBluetoothを用いた文字列送信システムについて、その内容を紹介させていただきます。

 

インターンのテーマ

Nefrockでは「EdgeOCR」というハイスピードで文字を読み込むことのできるアプリケーションを開発・提供しています。こちらは、スマートフォン上でOCRモデルを直接推論させることで高速な文字読み取りを実現するものになっています。

 

edge-ocr.com

この「EdgeOCR」で読み取った文字列を、パソコンなどの別の端末上に送信するのが今回の開発の目的となっています。今回のインターンではこの送信のための手段としてBluetoothのキーボード機能に着目しました。Bluetoothは、さまざまなOS、機器に対応する汎用的な通信規格であり、さらにキーボード機能であれば受信側の機器に特別な準備を施すことなく簡単に利用できます。実際、現場では「EdgeOCR」の読み取り結果を直接Excelなどに入力したいというモチベーションがあり、Bluetoothキーボードでの送信はこのような問題を解決する最も手軽な手段の一つとなります。

今回のインターンでは、このBluetoothキーボード送信を既存の「EdgeOCR」アプリケーションの拡張機能のような形で実装することを担当しました。

実装方針

AndroidスマートフォンのBluetoothキーボード化

まずはAndroidスマートフォンをBluetoothキーボード化する方法を探す必要があります。これについては、私がインターンに着手した時点ですでにチューターの方がサンプルコードを探してセットアップまで済ませて下さいました。

Bluetoothは用途毎に異なるプロファイルが定義されており、AndroidのBluetooth APIではこれらのプロファイルの操作がサポートされています。今回の場合では、HID(Human Interface Device)のプロファイルを用いることで、スマートフォンからホスト側のコンピューターにキーボードのキーを押す、離すといった操作をコードとして送信することができます。

日本語の送信

Bluetoothキーボードで送信を行う関係上、直接入力ができるのはアルファベットや数字、いくつかの記号だけです。ご存知の通り、日本語をキーボードで入力する際には一般的に予測変換を用いる必要があり、Androidからこの予測変換を自動制御するのはBluetooth通信だけでは不可能です。しかしながら社長様より、この問題を解決しうる情報を提供していただきました。

qiita.com

このQiita記事に従い、WindowsのIMEを有効にした状態で「Unicodeの16進数表記+f5キー+任意のアルファベット+backspace」を送信すると、確かに任意の文字が入力できることが分かりました。また後日の調査にて同様のUnicode入力がMacの場合でも少し操作を変えることで実現できることもわかりました。

qiita.com

今回の実装では、WindowsとMacの場合のUnicode入力をサポートすることにしました。

UI

基本は「EdgeOCR」のAndroid向けデモアプリのUIを踏襲することになります。

デモアプリのUI

デモアプリでは、上記のように認識した文字列に合うようにオーバーレイボックスが表示されるような実装が施されています。最初の時点では、このオーバーレイボックスをタップした時に、その文字列を送信する構成を考えました。しかし、この構成の場合、誤タップで文字列が送信されてしまった時に修正のためにbackspaceを押す手間がかかります。また、Unicode入力のために送信するキーコードはOSごとに分ける必要があります。以上のことから、タップと送信の間にもうワンステップ手順を挟んだ方が良いという結論に至りました。

実装物

実装アプリケーションのトップ画面
Bluetooth接続部

最初の接続時と2回目の接続時で接続方法を分けました

・最初の接続時

トップ画面のStartボタンを押すとBluetoothの外部からの接続の許可を求めるホップアップが表示され、アプリケーション内部でHIDプロファイルのオブジェクトが立ち上がります。この状態でホストコンピュータ側からBluetooth接続を行うことで、Bluetooth HIDでの接続が確立します。

外部からのデバイスの発見の許可を求めるホップアップ

 

接続に成功すると、画面上部に接続されたデバイス名が表示されます。この状態でCAMERAボタンを押すことでメインのOCR+文字列送信の機能を利用できます。

接続済みを知らせるテキスト

・2回目の接続時

再接続時には、android側から接続を行えるように、RESTARTというボタンを追加で設置しました。このボタンを押すと再接続用の画面が表示され、利用しているAndroidにペアリングされたBluetooth機器がリストで表示されます。そのリストから接続したい機器を選択してタップするとAndroid側からHIDプロファイルでの接続のリクエストが出されます。そうして接続が確立すると送信機能画面に自動で遷移します。

送信機能部

メインの送信機能部分は次のような仕上がりになりました

メイン機能のUI部

今回のアプリケーションでは、カメラ画面の上部にテキストボックスを用意し、そこにタップされた文字列を一度挿入し、送信自体は別のボタンで行うようにしました。

タップすると、その文字列がテキストボックスにセットされる

送信のボタンは基本の送信ボタンとOS別のボタンの3種用意しました。基本の送信ボタンは、小文字・大文字・数字などの基本のキーボード入力で送れる文字だけを直接送信するようになっています。OS別のボタンでは前章で紹介したようなUnicode入力を行うことができます。

カメラの向こうのWindowsにUnicode入力を行う

また画面の下部には上下左右キーとbackspaceキーに対応するボタンを配置しました。これは文字列をExcelなどの表編集ソフトに入力する際にスマートフォンの画面だけで操作が完結できるように配置しています。

 

実装中にぶつかった問題点と解決策

再接続について

上記の通り、今回の実装物では、初回と2回目以降でbluetooth接続の手法を分けました。そもそも今回利用したHIDプロファイルは、事前に確立したAndroidとWindowsの接続に後乗りする形で利用することはできず、初めからHIDプロファイルに従って接続を行う必要がありました。なので上記で示したような手順を踏んで接続行うのですが、困ったことに一度すでにペアリングされた状態でWindowsから接続の試行を行う手段がありませんでした。調べたところによると、windowsでは一度ペアリングされたHID機器はBluetoothをオンにすると再接続の処理が自動で行われるそうなのですが、今回アプリケーションではAndroidを無理やりHIDとして認識させたからかこの再接続がうまく行われませんでした。

そこで、Bluetooth HIDのAPIの機能を用いてAndroid側からホスト側に接続する機能を増設することになりました。Bluetooth HIDのAPIでは、ホスト側のBDアドレスさえ知っていれば、能動的な接続が可能です。今回の場合では、Android OSに保存されたペアリング機器の情報からBDアドレスを取得することで、能動的な接続を行なっています。

送信機能の不安定性

文字列送信機能を実装した当初、適切な文字が送信されない事態が多々発生しました。最初はパケロスのようなbluetooth側の問題によって生じた問題ではないかと疑い、調査を行なっていたのですがのちに、その原因は全く別のものであることが発覚しました。

今回のアプリでは、文字列の送信を行う際、一度送信すべきコードをキューに貯め、別スレッドからキューに貯めたコードを送信するようになっています。このスレッドでは、一つのコードが送信されてから次のコードが送信されるまでの間に10ミリ秒ほどのディレイをとることで受信側がパンクを起こさないようにする工夫が取られていました。しかしながら、このスレッドがコードの不備により複数立ち上がってしまっており、結果としてディレイの意味をなさなくなってしまっていたことがわかりました。これが前述の不安定挙動の原因でした。

この件は、自身の実装物が不具合を起こした時はまずは自身のミスを徹底的に洗うべきという強い教訓になりました。

謝辞

今回のインターンに際しまして、Android開発初心者の私にAndroid studioのセットアップから手取り足取り教えてくださり、Bluetooth HIDの初期セットアップまでしてくださったチューター様、Unicode入力についての情報をはじめとして様々なアドバイス、情報提供をしてくださった社長および社員・関係者の皆様方の皆様方に深く感謝を申し上げます

開発初心者の私が今回の開発インターンを完遂できたのは、皆様が私を暖かく迎えてくださり(なんと昼食まで皆様にめちゃくちゃ奢っていただきました!)、お忙しい中でさまざまなサポートをしてくださったおかげです。重ね重ね感謝を申し上げます。

一ヶ月間、すごく楽しいインターンでした!!