Bakulog

獏の夢日記的な何か。

.NET/C#でPepperやNaoが操縦出来るようにした話

自作ライブラリの紹介記事です。ライブラリの更新とかに合わせてたまに書き換えています。(最終更新日:2016/3/15)

2016/3/5追記: 互換性の無くなる更新をしたのでサンプルコードだけ修正しました。更新内容の詳細は新しいほうの記事を確認してください。

 

目次

  1. 概要
  2. ダウンロードと使い方
  3. ラッパーの作り方
  4. ラッパー公開後にやったこと
  5. まとめ

 

3節以降は「C#以外の言語でもラッパー作成したい!」という方向けに情報提供する目的で書いたメモです。単純にライブラリを使いたい、という方は「2. ダウンロードと使い方」くらいまで読んでもらえれば十分使えると思います。

   

1. 概要

本記事に来てくださった人にPepperやらNaoやらの入門説明は不要でしょうから基本的なことは省きます。

 

私は昨年(2015年)の3月頃からアトリエ秋葉原Softbank Pepperを触っており、おもにPCとリアルタイム通信してなんかするタイプのアプリケーションをちょいちょい作って紹介しています。

 

ソフトバンク側もROS(Robot Operating System)対応をリリースするなどして公式に「自由な遠隔操作でなんかやってみなさいよ」と態度で示しており、この雰囲気に沿ったPepperの応用事例として以前お手伝いしたHUG Projectとかも挙げることが出来るでしょう。

 

さて、そんなPepperのAPIですが、いくつかのバリエーションがあります。具体的に挙げると以下の通り。

 

言語とか メリット デメリット
Python2.7 Choregrapheとある程度コードが共有可能 ドキュメントが多く敷居が低い Python2系なので文字列の扱いが若干アレ
C++ 動作が速い ロボット上にバイナリを置くとPythonで出来ない一部の低レイヤ処理が可能 ビルド環境の整備が面倒、バイナリ配布式になるので変更も少し大変
Javascript 可搬性が高く、PC以外に対応させやすい(ハズ) 一部のコールバック関数登録処理などが出来ない、動作が遅い
Java Androidと相性がよくスマホ連携によい ドキュメントが少なめ(他の言語サンプル読めばカバー可能)
ROS 既存のROSリソースが強力 運用可能なホストPCの環境が制限される(基本Ubuntu縛り)
(Haskell) 個人のもので若干古いため動作保証が不明

 

バリエーションが豊富で良く、どれもオンリーワンな長所があります。

   

と言いたいのですが。

   

悲しい事に.NETが無いです。

 

無いというか、正確にはPepperの開発元であるAldebaran社のGithubを見ると「今はサポートしてません」的な事が書かれています。私が知る限りAldebaranってそんなに人数が多い会社では無いので、単純に忙しくて手が回ってないのでしょう。サポートの切れてるLibqi-DotNetのコントリビューターを見ても3人しかいませんし、ちょっと寂しい感じです。ついでに触れておきますがGo言語もサポート打ち切り状態みたいです。

 

しかし実際HUG ProjectとかではKinectのようなMS製品との連携をやっていたわけで、HUGの例を含めて「C#がサポートされていたらもっと楽だったのに」というシチュエーションは普通にあります。というわけで、今回ラッパーを作ってみました。

   

2. ダウンロードと使い方

ソースはGithubにあります。ソースから利用する場合はGitHubのreadmeにある指示に従ってファイルの配置やビルド、実行を行ってください。

 

「ソースは別にいいや」という方のためにパッケージ化したNuGet版も公開しています。NuGet版を使う場合は次の手順に沿ってください。

  1. NuGetのパッケージ名は"Baku.LibqiDotNet"なので、NuGetの検索とかで探してインストールするか、NuGetのコンソールでコマンド叩いて直にインストール
  2. ビルド構成マネージャでプログラムのターゲットを"x86"にする

GitHubに置いてるものと同じですが、以下にHelloWorldプログラムを示します。

using System;

using Baku.LibqiDotNet;
using Baku.LibqiDotNet.Path;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            //作業ディレクトリだけでなく"dlls"というフォルダのライブラリも実行中に参照できるよう設定を変更
            PathModifier.AddEnvironmentPath("dlls", PathModifyMode.RelativeToEntryAssembly);

            //HelloWorldの対象とするマシンのアドレスをIPとポート(ポートは通常9559)で指定
            string address = "tcp://127.0.0.1:9559";
            var session = QiSession.Create(address);

            Console.WriteLine($"Connected? {session.IsConnected}");
            if (!session.IsConnected)
            {
                Console.WriteLine("end program because there is no connection");
                return;
            }

            //最も基本的なモジュールの一つとして合成音声のモジュールを取得
            var tts = session.GetService("ALTextToSpeech");

            //"say"関数に文字列引数を指定して実行
            tts["say"].Call("this is test");

            session.Close();
            session.Destroy();
        }
    }
}

 

ひとつだけ注意として、NuGetパッケージの設定ではビルド時に"dlls"というフォルダへアンマネージライブラリを吐き出すようになっています。これを参照するため、プログラム開始時にPathModifierを利用して探索パスを追加する必要があります。dllsフォルダに含まれるアンマネージライブラリをあらかじめexeファイルと同じディレクトリにコピーした場合、この処理は不要です。

   

3. ラッパーの作り方

※本節の記述には勘違いがあるかもしれませんので、ご指摘等ありましたらコメントでお知らせください。

どれほど需要があるのか分かりませんが「自分が普段使ってるプログラミング言語用にもラッパー書きたい!」という人が居る可能性もゼロではないハズなので、ラッパーライブラリを作った手順を簡単に書いておきます。

 

3-1. 予習

上の方でも単語レベルで触れていますが、ラッパーライブラリでラップすべき相手は普段PepperやNaoのアプリケーション作成で用いる"ALTextToSpeech"や"ALMemory"といったモジュールを一つ下のレイヤーで支えているqi Frameworkというメッセージングライブラリです。このqi Frameworkは次のような処理をサポートしています。

  • 「サービス」というクラス定義のようなものをコードで定め、それをローカルエリアネットワーク上にAPIライクに公開する(サーバ的な処理)
  • サービスに接続して定義済みの関数を叩いたり、イベントハンドラを登録したりする(クライアント的な処理)

普段使っている"ALSpeechToText"などはサーバであるロボットが「サービス」として登録、公開しており、それを通常のアプリがクライアントとして利用する、という図式です。

んで。qi Frameworkに関するAldebaranの公開物としてはC++製のコアであるlibqiと、ラッパーであるその他の"libqi-hoge"系のレポジトリがあります。その中でもC言語/Java/Pythonあたりが「いかにもラッパーらしいラッパー」として整備されています。また実装が面白い例としてはJavascriptでPepperと通信するためのlibqi-jsがあり、以下の指針で実装されています。

  1. PC/ロボット上にPythonでwebサーバを立てる(libqi-jsのqimessaging-jsonがそう)
  2. JavascriptPythonが立ててるwebサーバとsocket.ioでやり取りしてJSONのデータをやり取り
  3. Python側ではJSONを適切にパースし、Python用のライブラリで各種の高レイヤサービスの関数を使用する

 

Javascript用プログラムは「JSではデータ構造だけを薄っぺらく再現してPythonにデータを投げ、肝心の処理は全てPythonに肩代わりしてもらう」という方針で実装されており、これは実装効率の面で非常に優秀な作りになっています(JSのラッパーは実質200行もない程度)。

 

3-2. 実際に作る

上記を踏まえるとラッパー作成の選択肢はおよそ4種類に分かれます。

  • Javascriptの真似をしてsocket.ioクライアント的なものを作る
  • socket.io以外の方法でPythonプロセスとC#が通信するような仕組みを作る
  • C言語/Python/Javaと同じようにlibqiを直接ラップする
  • libqiのラッパーを更にラップする(今回採用した方法)

 

どれを選んでもラッパーは多分作れますが、私が採用した方針は4番目の選択肢で、具体的にはC言語APIであるlibqi-capiをラップする形でもともとのlibqiにアクセスできるようにしました。C言語用のAPIは作りが単純なのでラッパー作成に向いているのです1

 

調査段階ではそれなりに苦労しましたが、調べる事を調べた後は以下の3ステップで案外トントン拍子にラッパーの初期版が完成しました。

  1. Python用のSDKを入れ、PythonのパッケージディレクトリからC言語APIのライブラリにあたる"qic.dll"というdllを発掘
  2. VS 2015などに付属のdumpbin.exeで"qic.dll"が外部へ公開してる関数を調べつつlibqi-capiのヘッダも確認し、かたっぱしからラップ
  3. テストコードを見ると関数の使われ方が分かるため、実装言語(今回ならC#)の特徴に応じて使いやすいようラップを分厚くする

   

4. ラッパー公開後にやったこと

ラッパーの初期版が完成したあとで、重要と言える整備を3つほど行っています。

 

4-1. C言語APIに未実装な機能があったので追加

タイトルの通りですが、C言語APIではAPIの一部が未実装であり、バイナリデータをロボットとやり取り出来ないという地味にキツい問題がありました。音声や画像をやり取りするにはバイナリ形式への対応が必須です。

対策としては、Aldebaranが公開してるソースを持ってきて書き直してビルドしたらどうにかなりました。この件についてはGithubのissueに載せてます。

 

4-2. UnityEngineに対応させてみる

C#のライブラリなんだからUnityEngineへ移植出来るでしょ、と思って試したら普通にできたという話です。詳細は「UnityEngine用のPepper操作ライブラリを公開しました」をご覧ください。

 

4-3. NuGetパッケージにして公開する

すでに上で紹介した内容と被りますが、C#ではライブラリの配布機構としてVisual Studio/NuGetパッケージマネージャが便利なので、実際にパッケージとして公開しておきました。VSの扱いに慣れているのであればAldebaranの公式配布物を取ってくるよりNuGetからパッケージを拾う方が簡単ですし、けっこう便利に出来たんじゃないかと思います。

   

5. まとめ

ともかく無事にC#/.NETでPepperやNaoが動かせるようになりました。C#が万能だという気はありませんが、今までのラッパー言語には無いメリットを持っているのは間違いないので、状況に合わせてうまく使って貰えればと思います。

 

最後になりますがバグ報告、機能リクエスト、実装の質問などありましたら本記事のブログやGitHubのissueやTwitter等までご一報ください。

   

   


  1. 実はJavascriptの方式を真似しなかったデメリットとして「UnityEngineには対応したけどクロスプラットフォームにしづらい」という欠点が生じています。ただしJS方式だとそもそもqi Frameworkの機能の一部が全く使えないという別の致命的な欠点があり、どっちが良いかは判断に迷う所です。