PaPeRo iをRaspberry Pi上のアプリから操作する場合、カメラ画像を高レートで取得したり音声をリアルタイムで送受信することは出来ませんでしたが、PaPeRo i上で画像・音声用のサーバ(CameraServer)を動かしアプリではそのサーバと通信する事でそれを可能にする方法が考えられます。
(ラズパイに限らずPCなど別ホストで動かすパペロアプリ全般で使用できます。)
PaPeRo iのカメラAPI
PaPeRo iでカメラ画像を取得するAPIには2種類あります。
(1) send_take_picutre() : 画像データは/tmp以下のファイルに書かれる
(2) send_start_capturing() + send_get_capture_data() : 画像データは共有メモリに書かれる
(1)では指定のJPEGまたはBMPファイルが/tmpディレクトリに作成されますが遅いので、今回は(2)を利用してカメラ画像を取得し、WebSocketで連続して別ホストに送信できる様にします。
カメラ画像取得シーケンス
少々分かり辛いですが今回作成したCameraServerにおけるカメラ画像取得のシーケンスをMarkdownの表で表してみました。
共有メモリ | CameraServer | robot_platform | (WebSocket) *1 | アプリ |
---|---|---|---|---|
↓ | ←(camctrl)← | ← 共有メモリID要求 *2 | ||
↓ | ← 共有メモリ確保 | |||
→ | 共有メモリID → | →(camctrl)→ | → 共有メモリID取得 | |
↓ | ←(papero)← | ← startCapturing *3 | ||
response → | →(papero)→ | → response | ||
画像データ1 ← | ←↓ | ←(papero)← | ← getCaptureData *4 | |
response → | →(papero)→ | → response | ||
↓ | ←(camctrl)← | ← リード要求 *5 | ||
↓ | ← 共有メモリリード | |||
画像データ1 → | 画像データ1送信 → | →(camdata)→ | → 画像データ1取得 | |
画像データ2 ← | ←↓ | ←(papero)← | ← getCaptureData *6 | |
response → | →(papero)→ | → response | ||
↓ | ←(camctrl)← | ← リード要求 | ||
↓ | ← 共有メモリリード | |||
画像データ2 → | 画像データ2送信 → | →(camdata)→ | → 画像データ2取得 | |
: | : | : | : | : |
(1) (WebSocket)の左がPaPeRo i、右がラズパイなど別ホストです。
(2) アプリはPaPeRo i上のCameraServerにカメラ制御用WebSocketコネクション(camctrl)を通じて画像の取得に必要な共有メモリIDの取得を要求します。
(3) アプリはパペロ制御用WebSocketコネクション(papero)を通じてrobot_platformにキャプチャ開始を要求します。以後カメラデータは連続してキャプチャされます。
(4) アプリはパペロ制御用WebSocketコネクションを通じてrobot_platformにカメラデータを要求します。robot_platformは最新の画像データを共有メモリに書き込みます。
(5) アプリはCameraServerに画像データ取得を要求します。CameraServerは共有メモリから読んだ画像データをカメラデータ用WebSocketコネクション(camdata)を通じてアプリに送信します。
(6) アプリはこれを連続して行います。
なお画像APIの仕様によりこの様なアプリとCameraServerの分離が可能なのですが、加速度センサーはデータリードがAPI提供なのでこの方法が使えません。
マイク音声の取得
マイク音声はrobot_platformと無関係にarecordコマンドで取得できるため、シーケンスは簡単です。
arecord | CameraServer | (WebSocket) | アプリ |
---|---|---|---|
↓ | ←(camctrl)← | ← 録音開始要求 *1 | |
↓ | ← 起動 | ||
起動 | response → | →(camctrl)→ | → response |
音声データ1 | → | →(audiodata)→ | → 音声データ1 *2 |
音声データ2 | → | →(audiodata)→ | → 音声データ2 |
: | : | : | : |
(1) アプリはPaPeRo i上のCameraServerにカメラ制御用WebSocketコネクションを通じて録音開始を要求します。
(2) 以後CameraServerは音声データが一定量取得できるごとに音声データ用WebSocketコネクション(audiodata)を通じてアプリに送信します。
音声データをスピーカーから流す
CameraServerにはアプリ側から送った音声データをスピーカーから流す機能も実装しました。スピーカを鳴らすのもrobot_platformと無関係にaplayコマンドで可能なため、録音同様簡単なシーケンスです。
aplay | CameraServer | (WebSocket) | アプリ |
---|---|---|---|
↓ | ←(camctrl)← | ← 再生開始要求 *1 | |
↓ | ← 起動 | ||
起動 | response → | →(camctrl)→ | → response |
音声データ1 | ← | ←(audiodata)← | ← 音声データ1 *2 |
音声データ2 | ← | ←(audiodata)← | ← 音声データ2 |
: | : | : | : |
(1) アプリはPaPeRo i上のCameraServerにカメラ制御用WebSocketコネクションを通じて再生開始を要求します。
(2) 以後アプリが音声データ用WebSocketコネクションを通じて送った音声データをCameraServerはaplayコマンドに標準入力経由で送り、スピーカーを鳴らします。
なお音声データの先頭4バイトでサンプルレートを送る仕様としています。
CameraServerの実装
CameraServerは以下の開発Tipsで作成したプログラムを結合し、パペロ制御通信機能を削除し、カメラ(+音声)制御通信機能を追加したものになっています(Golang使用)。
なおVGAカメラの画像データは変換が必要ですが、試した結果最も負荷が低く音切れが発生しづらかった、PaPeRo i上でffmpegコマンドにより変換する方法を採用しています。
動作確認
(1) こちらからファイル一式をダウンロードし、cameraserverをパペロにダウンロードして任意の場所で実行してください。
(2) パペロの画像と音声をブラウザから確認できるサンプルアプリcameracliをラズパイに転送し実行するか、cameracli32.exeまたはcameracli64.exeをWindows PCで実行してください。
(3) ブラウザでcameracliを実行したホストのIPアドレス:8865/camconfを開き、”デフォルトに戻す”ボタンと”保存”ボタンをクリックし、一度cameracliを終了し、再度実行して下さい。
(4) ブラウザでcameracliを実行したホストのIPアドレス:8865/cameraを開き、パペロのIPアドレスを入力して”接続”ボタンをクリックし、”切断”ボタン右のstatus表示が”open”になることを確認して下さい。
(5) カメラ画像とマイク画像にチェックを入れるとパペロのカメラ画像と音声が再生されます。
(6) ボタンで発話や頭を動かす事ができます。
試した限りで画像の表示レートはVGAが約2~3fps、SXGAでは約10~12fps程度、但しSXGAでは音声の音途切れが頻発します。VGAであれば音途切れは数十秒に1回(約4秒)程度でした。