今から始める TOPPERS/HRP3


TOPPERSプロジェクトは LEGO MINDSTORMS EV3 向けにリアルタイムOS環境 EV3RT を提供しています。EV3RT は TOPPERS/HRP2 カーネル をベースとしていますが、TOPPERS/HRP3 カーネル をベースにしたソースが既に GitHub に公開されています

本日のネタは、この HRP3 版をインストールして使ってみることです。現行の(HRP2ベースの) EV3RT 開発環境は構築済みで、git コマンドも使えるようになっていることを前提に話を進めます。

Windows を使っている場合は Cygwin 環境に ruby もインストールしておいてください。configure や cfg が HRP3 では ruby スクリプトになったせいで、ruby コマンドが必須になっています。

ソースの取得とダイナミックローダのビルド

まずは、ソース取得のために git clone します。

$ git clone https://github.com/ev3rt-git/ev3rt-hrp3

ソースを取得できたら、以下の手順で HRP3 のダイナミックローダをビルドします。

$ cd ev3rt-hrp3
$ git submodule init
$ git submodule update
$ cd sdk/firmware
$ make img=loader

ビルドが完了すると uImage という名前でダイナミックローダができています。これを HRP2 版 EV3RT で作成した SD カード内にある uImage ファイルと入れ替えます。

できた SD カードを EV3 にセットして起動して、以下の画面が現れたら EV3 側のセットアップは完了です。

helloev3 アプリのビルド

取得したソースには SDK も含まれているので、HRP2 の場合と同様にアプリをビルドできます。

$ cd ev3rt-hrp3/sdk/workspace
$ make app=helloev3

macOS の場合、実害は無いようですが、ビルド中に以下のメッセージが何度も出てきます。

find: illegal option -- t
usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]
       find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]

これは、HRP3 のビルド環境が GNU の find コマンドを前提としているため、macOS の find コマンドに無いオプション(ファイル/ディレクトリの種別を指定するオプション)でエラーになっています。ちょっとメッセージがうるさいので、私は Homebrew で findutils を入れて GNU の find を使うようにしました。

ビルドしてできた app ファイルを HRP2 と同様に EV3 に転送して起動すると以下の画面になります。このアプリでセンサーやモータの動作を確認できます。

C++ で書かれたアプリのビルド

GitHub から取得したソースには C++ API が含まれていないので、HRP2版からコピーします。

$ cp -pr hrp2/sdk/common/library/libcpp-ev3 ev3rt-hrp3/sdk/common/library/

これだけで C++ API が使えるようになります。HackEV を使って5秒おきに前進/更新を繰り返す簡単なアプリケーションを書いてみます。

$ cd ev3rt-hrp3/sdk/workspace
$ mkdir walker

以下4つのファイルを作成します。

  • walker/app.h:
#ifdef __cplusplus
extern "C" {
#endif

#include "ev3api.h"

#define MAIN_PRIORITY    TMIN_APP_TPRI + 1
#define WALKER_PRIORITY    TMIN_APP_TPRI + 2

#ifndef STACK_SIZE
#define STACK_SIZE      4096
#endif /* STACK_SIZE */

#ifndef TOPPERS_MACRO_ONLY

extern void main_task(intptr_t exinf);
extern void walker_task(intptr_t exinf);

#endif /* TOPPERS_MACRO_ONLY */

#ifdef __cplusplus
}
#endif
  • walker/app.cpp:
#include "app.h"
#include "Motor.h"
#include "TouchSensor.h"

using namespace ev3api;

bool isForwarding = true;

Motor* leftWheel;
Motor* rightWheel;
TouchSensor* touchSensor;

void walker_task(intptr_t exinf) {
    if (touchSensor->isPressed()) {  // 左ボタン押下でメインを起こす
        wup_tsk(MAIN_TASK);
    } else {  // 走行
        if(isForwarding) {
            leftWheel->setPWM(25);
            rightWheel->setPWM(25);
            isForwarding = false;
        } else {
            leftWheel->setPWM(-25);
            rightWheel->setPWM(-25);
            isForwarding = true;
        }
    }
    ext_tsk();
}

void main_task(intptr_t unused)
{
    leftWheel = new Motor(PORT_C);
    rightWheel = new Motor(PORT_B);
    touchSensor = new TouchSensor(PORT_1);

    sta_cyc(WALKER_CYC);
    slp_tsk();  // 起きたら、走行をやめる
    stp_cyc(WALKER_CYC);
    leftWheel->stop();
    rightWheel->stop();
    ext_tsk();
}
  • walker/app.cfg:
INCLUDE("app_common.cfg");

#include "app.h"

DOMAIN(TDOM_APP) {
CRE_TSK( MAIN_TASK, { TA_ACT,  0, main_task,   MAIN_PRIORITY,   STACK_SIZE, NULL } );

CRE_CYC( WALKER_CYC, { TA_NULL, { TNFY_ACTTSK, WALKER_TASK }, 2000U * 1000U, 1U * 1000U });
CRE_TSK( WALKER_TASK, { TA_NULL,  0, walker_task, WALKER_PRIORITY, STACK_SIZE, NULL });
}

ATT_MOD("app.o");
  • walker/Makefile.inc:
mkfile_path := $(dir $(lastword $(MAKEFILE_LIST)))

APPL_COBJS +=

SRCLANG := c++

ifdef CONFIG_EV3RT_APPLICATION

# Include libraries
include $(EV3RT_SDK_LIB_DIR)/libcpp-ev3/Makefile

endif

以下でビルドします。

$ make app=walker

ビルドしてできた app ファイルを EV3 に転送して起動すると、以下のように前進と更新を繰り返します。止めるにはタッチセンサを押下します。

おわりに

今のところ、HRP2 ベースの EV3 アプリを HRP3 ベースに移植する上で修正が必要だったのは以下2点です。

  • タイマーの時間指定が msec から usec になったので、従来の時間指定を 1000 倍する必要あり
  • EV3_CRE_CYC は無くなった。ユーザドメインの周期処理がサポートされたので、代わりにこれを使う
  • Makefile.inc で APPL_DIR へのフォルダ追加は、HRP3 ではエラーになるので、代わりに APPL_DIRS を使う