Help us understand the problem. What is going on with this article?

Android開発者がはじめるPepperアプリ開発

More than 3 years have passed since last update.

Android開発者がはじめるPepperアプリ開発

by smoriwani
1 / 21

はじめに

先日のGoogle I/O 2016で、Pepper SDK for Android Studioが発表されました。

今までのPepper向けアプリの開発は、ChoregrapheというPepperをはじめとするロボットアプリ開発専用のアプリケーションが使用されていましたが、今後はAndroidを用いて開発を進めることができるだけでなく、Google Playでのアプリの配布も可能になるとのことです。


Pepperについて

  • NAOqi(ナオキ)という名称のOS上で動作
  • 多数のセンサーと感情認識エンジン(とは一体)によって人間の感情を読み取り、反応する
  • 頭部に4つの指向性マイクを搭載、音源位置の特定も可能
  • 顔部分に1台の3Dカメラと2台のHDカメラを搭載
  • 3つの無指向性の車輪を搭載、最大時速3km、360度方向への移動が可能
  • バッテリーは12時間連続稼働が可能
  • Wi-Fi
  • LANポート×1
  • NAORomeoという兄弟機が存在

実機について

  • 一般販売モデルと法人向けモデルが存在
  • 一般販売モデルは、本体価格198,000円(税抜)に加えて月々24,600円(税抜)の料金が発生。詳しくはこちら
  • 法人向けモデルは月々55,000円(税抜)で運用可能。詳しくはこちら
  • Android対応Pepperについては2016年7月より開発者向けに販売開始予定。本体価格198,000円(税抜)に加えて月々21,600円(税抜)の料金が発生。詳しくはこちら
  • 実機を買うのはちょっと…という人のために、Pepperの貸し出しを行っている開発体験スペースが全国に存在します。詳しくはこちら。実際に利用される際には、Android対応モデルの貸し出しを行っているかどうかを事前に確認したほうがいいかと思います。

エミュレータについて

01.png


  • 開発ではエミュレータの使用が可能
  • 画像認識、その他センサーを用いた一部機能が使用不可
  • 音声認識については文字列を入力する形で一部擬似的に再現可能
  • その他エミュレータの制限についてはこちらに詳しくまとめられています。Androidで開発する場合、タブレット関連の制限はありません
  • エミュレータを起動すると、Pepperのエミュレータと、Pepperの胸部に設置されたタブレット用のAndroidエミュレータの2つが連動するかたちで動作する
  • あらかじめAVD Optionsをx86に設定しておかないとクソ重い
  • β版なので一部正常に動作しない節がある
  • Hello worldのサンプル動かしてるのにPepperくんが喋ってくれない!と思ったら、デフォルトのカメラ位置がPepperに寄り過ぎてて吹き出しが画面に映ってないだけだったりする

SDKの導入

Android Studio > Preferences > Plugins > Browse RepositriesからPepper SDKを検索してインストールします。

02.png


SDKのインストールが完了すると、ツールバーにSDK ManagerライクなRobot SDK Managerなるメニューが追加されているので、ここから開発に必要なAVD、Toolsをインストールします。

03.png

これでSDKの導入は完了です。


プロジェクトの作成

File > New > New Projectから新規プロジェクトを作成します。
この際、Minimum SDKはAPI22、Android5.1(Lollipop)を指定します。実際にPepperに搭載されるタブレットが5.1以上ということなんでしょうか…
プロジェクトの作成が終わったら、File > New > Robot Applicationというメニューが追加されているはずなので、こちらを選択してください。

04.png


アプリケーションの作成が完了すると、build.gradleAndroidManifest.xmlに必要な記述が追記されていると思います。

build.gradle
dependencies {
    …
    compile 'com.aldebaran:libqi-java-android:sdk-2016-05-16'
    compile 'com.aldebaran:qisdk:0.7'
    compile 'com.aldebaran:qichatplayer:1.0.1'
}
AndroidManifest.xml
<uses-feature android:name="com.softbank.hardware.pepper"/>

これでPepperアプリの開発ができるようになりました。
試しにこちらのチュートリアルを簡単にまとめたものを動かしてみました。MediaPlayer周りが雑なままですがあしからず…

MainActivity.java
public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

    private MediaPlayer mediaPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
        }
    }

    /**
     * Hello, World!と話す
     * <p/>
     * https://android.aldebaran.com/doc/say_tutorial.html
     */
    @OnClick(R.id.button_say)
    void sayHelloWorld() {
        Say say = new Say(this);
        say.run("Hello, world!").then(new QiCallback<Void>() {
            @Override
            public void onResult(Void ignore) {
                Log.d(TAG, "result on thread " + Thread.currentThread().getName());
            }

            @Override
            public void onError(Throwable error) {
                Log.e(TAG, "error", error);
            }

            @Override
            public void onCancel() {
                Log.w(TAG, "cancel");
            }
        });
    }

    /**
     * 1m進む
     * <p/>
     * https://android.aldebaran.com/doc/goto_tutorial.html
     */
    @OnClick(R.id.button_go)
    void goToOneMeterForward() {
        Quaternion r = new Quaternion(0, 0, 0, 1);
        Vector3 t = new Vector3(1, 0, 0);
        Transform tf = new Transform(r, t);
        Frame robotFrame = Actuation.get(this).robotFrame();
        Frame robotAtStart = robotFrame.makeDetachedFrame(System.currentTimeMillis());
        Frame targetFrame = robotAtStart.makeStaticChildFrame(tf);

        Log.d(TAG, "running goto...");
        new GoTo(this).run(targetFrame).then(new QiCallback<Void>() {
            @Override
            public void onResult(Void ignore) {
                Log.d(TAG, "goto done");
            }

            @Override
            public void onError(Throwable error) {
                Log.e(TAG, "goto error", error);
            }

            @Override
            public void onCancel() {
                Log.w(TAG, "goto cancel");
            }
        });
    }

    /**
     * 象の真似
     * <p/>
     * https://android.aldebaran.com/doc/elephant_tutorial.html#elephant-tutorial
     */
    @OnClick(R.id.button_mimic)
    void mimicTheElephant() {
        mediaPlayer = MediaPlayer.create(this, R.raw.elephant_sound);
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = MediaPlayer.create(this, R.raw.elephant_sound);
        }
        Animation animation = Animation.fromResources(this, R.raw.elephant);
        Animate animate = new Animate(this);
        animate.setOnStartedListener(new Animate.OnStartedListener() {
            @Override
            public void onStarted() {
                mediaPlayer.start();
            }
        });
        animate.run(animation);
    }

    /**
     * Pepperと周りの人間との距離を表示
     * エミュレータでは動作確認できず
     * <p/>
     * https://android.aldebaran.com/doc/humans_around_tutorial.html
     */
    @OnClick(R.id.button_display)
    void displayHumansAroundDistances() {
        final Actuation actuation = Actuation.get(this);
        Interaction.get(this).setHumansAroundListener(new Interaction
                .HumansAroundListener() {
            @Override
            public void onHumansAroundChanged(List<Human> humansAround) {
                Log.v(TAG, humansAround.size() + " humans around");
                // signals callbacks are called from a qi thread
                displayHumansInfo(actuation, humansAround);
            }
        });
    }

    private void displayHumansInfo(Actuation actuation, List<Human> humans) {
        try {
            Frame robotFrame = actuation.robotFrame();
            int i = 0;
            for (Human human : humans) {
                Frame humanFrame = human.getHeadFrame();
                // currently, lastKnowTransform never returns (the future never finishes)
                TransformTime tf = humanFrame.lastKnownTransform(robotFrame).get();
                double distance = distance(tf.getTransform());
                Log.v(TAG, "human " + i++ + " at " + distance);
            }
        } catch (ExecutionException e) {
            Log.e(TAG, "Cannot display humans infos", e);
        }
    }

    private static double distance(Transform transform) {
        Vector3 t = transform.getT();
        double x = t.getX();
        double y = t.getY();
        return Math.sqrt(x * x + y * y);
    }
}

05.png

象の真似をしています。
ソースコードにも記載しましたが、4つ目のチュートリアルはエミュレータでは動作が確認できませんでした。


各種ドキュメントについて

APIのドキュメントについては、あくまで概要、あとはJavaDoc見てイカよろしく〜な印象を受けました。今後は、もう少し利用シーンを想定したチュートリアルが増えるといいなーと思ってます。


QiChatについて

QiChatというのが、どうやらPepperのキラーコンテンツっぽかったので、少しだけ触ってみました。いわゆるbotを作るようなものだと捉えてもらえればいいと思います。

まず、File > New > Chat Topicからチャットのファイルを作成します。

06.png

この時、作成するファイルの言語を問われるので、各種言語を選択してください。現状では英語、日本語、フランス語、中国語に対応しているそうです。作成されたファイルは、/res/rawフォルダに配置されます。
このChatTopicファイルは独自の構文によって構成され、Pepperにbotのような受け答えをさせることができるようです。構文の詳細についてはこちら。もしくはこちらでも詳しくまとめられています。


作ってみたサンプルがこちらです。

chat_sample.top
topic: ~chat_sample()
language: ja

u:(おはよう) おはよう

#^randをつけると落ちる。つけない場合もgreetingsと表示されてしまう
#concept:(greetings) ^rand[やあ こんにちは どうも]
#u:(~greetings) ~greetings

u:(喉が渇いた) オレンジジュースとりんごジュース、どちらにしますか?
    u1:(オレンジジュース) オレンジジュースですね
        u2:(ああ、ついでに氷も入れてくれ。コップは透明なのがいいな。ストローもあったらつけてな) ドクンン
    u1:(りんごジュース) りんごジュースですね

このサンプルファイルをAndroid側で呼び出します。

MainActivity.java
public class MainActivity extends AppCompatActivity {

    private QiChatPlayer qiChatPlayer;

    ...

    @Override
    protected void onStart() {
        super.onStart();
        initQiChatPlayer();
    }

    @Override
    protected void onPause() {
        super.onPause();
        qiChatPlayer.stopTalk();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        qiChatPlayer.destroy();
    }

    private void initQiChatPlayer() {
        // Instantiate a QiChatPlayer
        qiChatPlayer = new QiChatPlayer(this);

        // Register QiChatPlayer listener.
        qiChatPlayer.init(new QiChatPlayerListener() {

            /**
             * Complete to connected to QiChatPlayerService
             */
            @Override
            public void onQiChatPlayerServiceConnected() {
                // Load the topic file.
                qiChatPlayer.loadTopicFile("chat_sample");
            }

            /**
             * Complete to load the topic file.
             */
            @Override
            public void onLoadCompleted() {
                // The player is ready to play!
                qiChatPlayer.startTalk();
            }

            /**
             * Error handler
             * @param error Error code
             */
            @Override
            public void onError(int error) {
            }
        });
    }
}

実際にエミュレータで動かしてみた結果がこちらです。

07.png


実機の場合は、Pepperに話しかければ応答してくれるようですが、エミュレータの場合はDialog Viewを通して擬似的にPepperに話しかけます。
エミュレータ画面の下部にDialog Viewのボタンがあると思うので、そちらを選択してください。また非常にわかりにくいですが、Dialog View部分の最下部が入力エリアになっていますので、そちらにカーソルを合わせれば文字列の入力が可能になります。
さらにハマりポイントですが、ChatTopicファイル作成時に日本語を選択された場合は、Androidエミュレータの言語設定を日本語に設定しないと反応してくれません。


また、今回QiChatの構文サンプルをいくつか試していたのですが、エミュレータ上では期待通りの結果が得られなかったり、アプリが落ちてしまうことが何度かありました。QiChatについては、まだAndroid版ではうまく動いていないというのが現状のようです。


おわりに

まだβ版ということでSDKやドキュメントなど、まだまだこれからといったかんじでしたが、とはいえAndroidで開発できるということに、とても可能性を感じました。
ただAndroidをはじめとするスマートフォンアプリの考えをどこまで持ち込んでいいのか、例えばUIについてタブレットを操作させるのがいいのか、音声で操作させるのがいいのかなど、そのあたりについての知見がまったくと言っていいほど無いので、機会があれば勉強させていただきたいと思いました。
そうなるとやはり実機が、という話になってくるので…個人での開発となると、なかなか道は険しそうですね。


参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした