DMM.comラボエンジニアブログ

DMM.comラボのエンジニアブログです。DMM.comを支える技術について書いています。

DMM insideに引っ越しました。 移転先はこちら -> https://inside.dmm.com/

Palmi 電車遅延を教えて!

f:id:dmmlabotech:20160622194627j:plain

どうも、DMM.comラボシステム本部事業サービス開発部玄武課ロボットチームのコーイチです。

弊社では様々なロボットを売っていますが、特に Palmi は以前紹介した通り、ユーザーがプログラムを書くことで機能を拡張していくことができるエンジニア向けなものとなっています。

とはいえ、対応言語はC++、ライブラリの情報は荒野、であり、昨今のアプリケーションでは当たり前のようにできることを行う環境がどうにも整っていません。

わたくしも開発者の方からの「こういうことやりたいんですがどうすればいいんですか?」的な問い合わせ回答に苦労(それが仕事なんですが)しております。

ここでは、そうした車輪をどう実装するのか紹介することで、エンジニア目線から Palmi の魅力に迫っていきたいと思います。

Palmi に関しては今更説明する必要もないかとは思うのですが「???」という方は以下のページを見ていただければよいでしょう。

robots.dmm.com

今回やること

昨今、何かしらのアプリケーションを開発するにあたって、インターネット上のリソースを取得するという動作は極一般的です。

初回である今回はそれを題材としました。

そんなわけで、とにかくインターネットにアクセスした結果を喋るネタがないかなぁ? とインターネットをさまよっていたら 鉄道遅延情報のjson さんといういい感じのサイトがありました。

Palmi に「電車遅延を教えて」というと、遅延情報を教えてくれたらいいんじゃない? というわけで、教えてもらいました。

youtu.be

実装サンプル

実装は非常にシンプルで、単に特定のURLにGETリクエストして、レスポンスをPalmiに発話させるだけのものです。

とはいえ、インターネット上のJSONリソースを取得して加工するというド基本要素はフォローできているかと思います。

#include "spc/spcbase2.h"
#include "SpcBaseCode.h"

#include "tinycurl.h"
#include <curl/curl.h>
#include "picojson.h"

using namespace std;
using namespace spc;

// Palmi の SPC の基本は、起動したら Palmi が何かして、終了する、です。
// なので、onInitialize() で何か処理して、終了してしまえばいいのです。
/**
* @brief アプリケーション初期化イベント。
*
* アプリケーションの実行開始時に呼び出されます。
*/
void spc_libcurl_sample::onInitialize()
{
    SPC_LOG_INFO("onInitialize");

    long callResult;

    // おまじない
    // アプリケーションでネットワーク機能を使えるようにします。
    callResult = enableNetwork();
    SPC_LOG_INFO("enableNetwork: %d", callResult);

    try
    {
        // https://rti-giken.jp/fhc/api/train_tetsudo/
        string url = "https://rti-giken.jp/fhc/api/train_tetsudo/delay.json";

        SPC_LOG_INFO("url: %s", url.c_str());
        speak("鉄道遅延情報のジェイソンにアクセスします。");

        // libcurl を直接使うと相当量のコードが必要ですが、ラッパーを使えば GET は2行です。
        // https://github.com/asashnov/tinycurl
        TinyCurl ob(url);
        string result = ob.fetch();

        // JSONのパーシングはとても書けないので、実績あるライブラリを使わせてもらいます。
        // https://github.com/kazuho/picojson
        picojson::value v;
        string err = picojson::parse(v, result);
        if (!err.empty()) {
            speak(err);
        }
        else {
            picojson::value::array resultList = v.get<picojson::value::array>();
            int count = 0;

            // GET結果をループさせながら発話させます。
            // フィルタや加工するような場合は、1度構造体やクラスにパーシングしたほうが良いと思います。
            for (picojson::value::array::const_iterator it = resultList.begin(); it != resultList.end(); ++it) {
                //{"name":"池袋線", "company" : "西武鉄道", "lastupdate_gmt" : 1456225502, "source" : "鉄道com RSS"},
                picojson::value::object resultRecord = it->get<picojson::object>();
                speak(resultRecord["company"].get<string>() + " の " + resultRecord["name"].get<string>());
                count++;
            }
            // GET結果を処理し終わった後には気の利いたことを発話させます。
            // Palmiは気配りを忘れません。
            if (count == 0) {
                speak("遅延情報はありませんでした。");
            }
            else {
                speak("が遅れているようです。大丈夫でしたか?");
            }
        }
    }
    catch (const TinyCurl::Exception &e)
    {
        // 例外を処理しなかった場合、SPCが無言で終了します。
        SPC_LOG_ERROR("Exception thrown: %s", e.what());
        speak(string("エラー。") + e.what() + "です。");
    }

    // おまじない
    // ネットワークの有効化、SDカードのマウントなど、リソースを確保した後は確実に開放するようにしてください。
    callResult = disableNetwork();
    SPC_LOG_INFO("disableNetwork: %d", callResult);

    // アプリケーションを終了します。
    exitComponent();
}

実は重要な参照設定

Palmi には各種ライブラリがインストールされています。 それらを使うコンパイルやリンクオプション設定をプロジェクトのプロパティに行います。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
<!-- 略 -->
    <IncludePath>
    </IncludePath>
    <CompileDef>
    </CompileDef>
    <LinkFlags>-Wl,--no-as-needed -Wl,-rpath-link /usr/arm-linux-gnueabi/lib/arm-linux-gnueabi</LinkFlags>
    <LinkPath>
    </LinkPath>
    <LinkAddLib>/usr/arm-linux-gnueabi/lib/arm-linux-gnueabi/libcurl.so.4.2.0</LinkAddLib>
<!-- 略 -->
  </PropertyGroup>
<!-- 略 -->

これらは Visual Studio 上からプロジェクトのプロパティを選択することで設定できます。

f:id:dmmlabotech:20160615122851p:plain f:id:dmmlabotech:20160615122827p:plain

参照リンク

鉄道遅延情報のjson さんには何の話も通しておりませんが、ありがとうございます、と念を送っています。

ソースコードはGitHubで公開しています。

github.com

そして、ロボットアプリケーション開発に興味はある方はこちらへどうぞ。

robots.dmm.com

まとめ

今回は Palmi に電車遅延を教えてもらいました。

何気ないことも、ロボットを通して伝えてもらうと独特の趣があります。

今後も随時開発ネタを紹介していく予定です。 記事を読んだ人のロボットアプリ開発意欲を煽っていきたいと思います。

それではまた会う日まで。