WebSocket サーバーを NAO 上で稼働させる
Android や iPhone と NAO を連携させたい。方法はいくつもありますが、NAO 本体で WebSocket サーバーを立ち上げてしまうというのはその中の一つ、比較的簡単に実現できるので、サンプルプログラムを作ってみました。
(なお、サンプルプログラムは NAO でしか動作確認をしていませんが、Pepper でも同様に動くと思います)
WebSocket サーバーを NAO 本体内で立ち上げるサンプルプログラム:
サンプルプログラムでは WebSocket サーバーが 9091 番ポートでリクエストを待っています。
サンプルプログラムの使い方
ChoregrapheProject 内のアプリ、NAOWebSocketServerSample を NAO で実行(これで WebSocketサーバーが立ち上がります)
↓
sample.html をPC のブラウザーなどから開く
↓
ロボットの IP アドレス:9091 を NAO IP Address に入力
↓
[Connect] ボタンを押す。
↓
Say にテキストを入力して [Say] ボタンを押すと、NAO が発話、また NAOの接触センサーを触ると、それに応じて From NAO テキストボックスにメッセージが表示さる。
sample.html のスクリーンショット:
サンプルプログラムの実装のについて
WebSocket サーバーは SRNAOWebSocketService というカスタムサービスで稼働させています。 実装コードはコレグラフプロジェクトの services/SRNAOWebSocketSerivce.py にあります。サービスは クライアントからのメッセージを ALMemory のキー SRNAOWebSocket/from で通知、また SRNAOWebSocket/to にイベントを投げることでクライアントにメッセージを伝播します。
カスタムサービスとして実装する利点は、専用のプロセスが立ち上げるので、何か不具合が発生した場合も NAOqi 本体へ致命的な影響を与えないことです。Choregrapheで普通に作ったプログラムは NAOqi 本体内で実行されるため、特定の処理が致命的な障害を起こすと NAOqi 自体が止まってしまいます。 常駐処理系はカスタムサービス化するのがオススメです。
カスタムサービスの起動、停止はサンプルプロジェクト内「Start Service」ボックスで行っています。
( カスタムサービスについては次も参考:
qiita.com )
まとめ
クライアント連携の手法としてはこれ以外にも qimessaging を使う方法などありますが、普通に使う場合 NAO 本体のパスワードで basic 認証を通す必要があったりと使い勝手が良くない場面もあるかと思います。サンプルでは認証系の処理は入れませんでしたが、NAO に接続するために独自の認証手順を取らせたい場合などに今回の手法、使えるのではと思います。
参考になれば幸いです!
NAOqi マイク -> PCスピーカ サンプルコードの改善
で紹介していたサンプルプログラムのマイク音声処理側の実装を大幅に書き換えました。
最新のコードは同じ github にアップしています。
音声の遅延の問題は大幅に改善されました。結局これまで Qt のライブラリの使い方がよくありませんでした。これを改めることで実装がシンプルになるとともに遅延のかなり改善しました。音切れがときどき発生するのがまだ改善したい部分ではあります。
と組み合わせて、ストリーミングサーバーにつなげれば遠隔と Pepper/NAO を通してお話ができるようになりそうです。
ストリーミングサーバーとの接続部分あまり詳しくないので、このあたりは知人の協力を得つつチャレンジしたいと思っています。
PC のマイク音声をライブで Pepper/NAO のスピーカーに送るサンプル
PC のマイク音声をライブで Pepper/NAO のスピーカーに送るサンプルを作ってみました。
NAOqi API の ALAudioDeviceProxy::sendRemoteBufferToOutput() を使っています。
ソースコードを次に公開しています。
実装してみたインプレッションとしては、遅延が結構あります。2秒ぐらい遅れてスピーカーから音声が再生されます。NAOqi 側のバッファリングの問題かと思うのですが、この遅延を短くする方法はまだ見つかっていません。
クロスプラットフォームな Qt ならびに NAOqi SDK を使っていますので、理屈上 Windows, Mac, Linux で動くはずです。ただ現状 Mac でしか動作確認はしていません。
ソースコードはコンパイル、実行する上で幾つか注意があります。
C++ SDK Installation — Aldebaran 2.1.3.3 documentation
- 開発ツールは Qt Creator を使いました。NAOqi は内部で Qt フレームワークを使っています。Qt Creator が使う Qt フレームワークのバージョンは NAOqi が利用している Qt ライブラリーとバージョンを一致させてください。 NAOqi が利用している Qt ライブラリーのバージョンは NAOqi SDK のディレクトリの中の lib ディレクトリのの中を調べればわかるかと思います。
- NAOqi と連携するところは別ライブラリとしてコンパイルします。ビルドをするためのバッチを buildNAOqiInterface.sh というスクリプトで用意しました。Qt Creator でプロジェクトをビルドする前に、このスクリプトを実行し、NAOqi と連携するライブラリを生成しておきます。
- 実行するには Mac の場合、環境件数 DYLD_LIBRARY_PATH を編集します。Qt Creator の プロジェクト設定で環境変数を追加することで対応できます。DYLD_LIBRARY_PATH にNAOqi C++ SDK をインストールしているディレクトリ配下の /lib ディレクトリとプロジェクトディレクトリの NAOqi 配下の build/lib ディレクトリを追加します。(アプリとしてパッケージするときには install_name_tool を使うことでこのあたりの煩わしさを解消できるようです。)
Pepper/NAO で ローカル SQLite ファイルにアクセス
Pepper, NAO の Python から SQLite の機能に直接アクセスできるようなので、ちょっとサンプルを作ってみた。
Python の SQLite モジュールは複数のスレッドで一つのコネクションを共有することができないようで、SQLite 処理専用のスレッドを作り、これが SQL リクエストを受けるようにしています。
サンプルの概要は以下のスクリーンショットの通り。SQLite query ボックスをコピー、いろいろな用途で再利用できるかと。
入力で渡された文字列を SQL コマンドとして実行するので、理屈的には更新系の処理も実行できそうですが、アプリ内のデータベースファイルがロボット本体内で書き換えられたとしても、それを外部からメインテナンスするのが若干面倒なので、基本はあらかじめ用意された DB ファイルをアプリ内でQクエリ実行して利用するというのが使い道かと思っています。
参考まで。
バーチャルロボットで Pepper のタブレットをエミュレート
バーチャルロボットでもタブレットのテストができるようにという挑戦です。
次の方法で実現しています
- Pepper 内部と同じ Web サーバー nginx を PC にインストールして、Pepper 内部と同様の設定を行う
- ShowImage などをまかなう ALTabletService が バーチャルロボットにはついてこないので、これと同名のサービスをオリジナルで作ってサービスに登録、各メソッドを PC 内部で動かすよう独自実装する
- タブレット画面はとりあえずブラウザーで代用。将来、より洗練された方法を検討
- qimessaging はゲートウェイサービスが動いていないと使えないようなので、これも PC 上で稼働させる。
まずは Mac で実現させています。他のプラットフォームも各種依存するソフトのインストールの手順さえわかれば対応可能かと思います。
とりあえず ShowImage, loadApplication ボックス、 loadUrl での特定の URL の読み込みなどできるようにしています。qimessaging API も動きます。ALTabletService からのイベントにはまだ対応できていません。ページを開く処理が要求されるたびに新しく ブラウザーのタブが開かれるなどまだまだ改善の余地はありますが、まずはコンセプトとして公開します。
提供ファイルの「インストール手順」に従い設定、「エミュレータ起動手順」に従いエミュレータを起動、起動できていれば、バージャルロボットでタブレットサービスを使ったアプリを実行してもエラーになりませんし、showImage ボックスなどはブラウザーが対応します。
開発と言える開発はまだしていません。とりあえずセットアップ方法を導き出すまでやってみたということで。
一つのアプローチとして参考にしていただけると幸いです。また開発部分助けてくれる方いれば歓迎です。
Pepper 狭いところを通れるように
Pepper はレーザーセンサー、3D深度センサーなどで周囲を確認、移動中ぶつかりそうになると自動停止します。
この限界距離 40センチですが、この距離が原因で狭い場所を通れない場合があります。
解決方法の一つはこの限界距離を短くするということ。こんな感じの Python ボックスを作ってあげることで簡単に変えることができます。
class MyClass(GeneratedClass): def __init__(self): GeneratedClass.__init__(self) self.initialized = False def _resetTheSecurityDistance(self): if self.initialized : self.logger.info("セキュリティー距離を元にもどします") self.motion.setOrthogonalSecurityDistance(self.od) self.motion.setTangentialSecurityDistance(self.td) def onLoad(self): self.motion = ALProxy("ALMotion") self.od = self.motion.getOrthogonalSecurityDistance() self.td = self.motion.getTangentialSecurityDistance() self.initialized = True def onUnload(self): self.logger.info("Unloading script box") #put clean-up code here self._resetTheSecurityDistance() def onInput_onStart(self): msg = "変更前:直行安全距離 %.2f 接線安全距離 %.2f" % (self.od,self.td) self.logger.info(msg) self.motion.setOrthogonalSecurityDistance(float(self.getParameter("Orthogonal Security Distance"))) self.motion.setTangentialSecurityDistance(float(self.getParameter("Tangental Security Distance"))) newod = self.motion.getOrthogonalSecurityDistance() newtd = self.motion.getTangentialSecurityDistance() msg = "変更後:直行安全距離 %.2f 接線安全距離 %.2f" % (newod,newtd) self.logger.info(msg) self.ready() def onInput_onStop(self): self._resetTheSecurityDistance() self.onStopped() #activate the output of the box
ボックスには 「Orthogonal Security Distance」、と「Tangental Security Distance」というパラメータを持たせます。
ボックスへのパラメータの追加の仕方は
http://tkawata.hatenablog.com/entries/2015/04/02
を参考に。
「Orthogonal Security Distance」は前方の障害物までの距離でデフォルト 0.4、「Tangental Security Distance」は周辺の障害物までの距離でデフォルト 0.1。
なお、上記ボックスはアンロードされる時に元の設定値に距離を戻すようにしています。