/Test_you

電子工作やプログラミングなど、やってみたことのメモ

Processingで、学戦都市アスタリスクのクレジット表示を真似してみた

アニメ「学戦都市アスタリスク」の2期オープニングのクレジット表示をProcessingで真似してみました

このアニメのCGなどによるエフェクトは、結構気に入っています。その中で目をひかれた、2期オープニングのクレジットタイトル(監督、出演者、スタッフ名など)の表現を、Processingで真似してみました。公式の動画は見当たらず直接紹介できませんが、気になる方はYouTubeなどで探してみてください。

環境

  • Processing 3.5.4

ソースコード

プロジェクト一式は、こちら(asterisk_op2_credit.zip)

ポイント

1.アニメーションの作り方

Processingの時計関数 millis() を使って現在時刻を取得。時間経過によって draw() 関数の描画内容を変化させる事で、アニメーションを行います。
6角形Haxagonクラスを例にとって説明すると、下記の通りです。

  • start()関数は、アニメーション開始を指示する関数です。
    この関数では time_start_ 変数にアニメーション開始時間を保存しておきます。
  void start(int delay_ms, int priod_show_ms, int priod_hide_ms ) {
    time_start_ = millis();
 ・・・
  }
  • draw()関数は、各フレーム毎に呼び出す描画関数です。
    1. time = millis() - time_start_ で、アニメーション開始からの時間経過を取得(a)
    2. 時間経過に応じて、表示内容を4通りに変更
      (b)表示なし→(c)6角形表示(塗りつぶしあり)→(d)6角形表示(枠のみ)→(e)消去
    // (a) アニメーション開始指示からの時間経過を取得
    int time = millis() - time_start_;

    // 時間経過に応じた処理
    // (b) 表示なし
    if ( time < time_disp_ ) {
    }
    // (c) 6角形表示(塗りつぶしあり)
    else if (time < time_hide_ ) {
      ・・・
    }
    // (d) 6角形表示(枠のみ)
    else if (time < time_end_ ) {
      ・・・
    }
    // (e) 消去
    else {
    }

以上で、start()関数を呼び出すと、時間経過によってdraw()関数の描画内容が変化し、6角形が表示・消滅するアニメーションになります。
この6角形クラスを複数個まとめたものが HexagonLine クラスで、各6角形の表示位置・アニメーション開始タイミングをずらす事でライン状にスキャンするアニメーションとしてます。

2.サイバーテキストの利用

スローで再生するとわかるのですが、クレジットの名前は一時的に違う文字が表示され、徐々に正しい名前に置き換わっていく表現になっています。

尚→釘→小野敦→小野学

今回は、類似表現を工学ナビさんのサイトにあるWatch Dogs Profilerで見つけたので、これを改造して利用しました。ただ、表示速度を早くした結果、ほとんど効果が分からなくなってしまいました・・・オリジナルは、かなりカッコいいです。

参考にした情報

  1. deconbatch さん - ぼんやり光る効果を出す簡単な方法 その2 : Processing Tips
  2. 工学ナビ さん - BACK YARD
  3. おもちゃラボ さん - はてなブログでソースコードを折りたたむ方法

RXマイコンで、Unityを使ってハードウェアの動作確認をしてみた

前回記事「RXマイコンで、Unityを使って単体テストをやってみた」のおまけとして、ハードウェアの動作確認のテストを書いてみました。

  • Unityを使った単体テスト環境のセットアップについては、こちら
  • プロジェクト一式は、こちら(rx231_unit_test_3.zip - Google ドライブ)
    インポート方法
    1. メニュー >ファイル > インポート でインポートのダイアログを表示
    2. 既存プロジェクトをワークスペースへを選択
    3. アーカイブ・ファイルの選択でファイルを選択し、終了ボタンでインポート

環境

お題

ターゲットボードには、下記仕様のLEDとSWがあるので、これらのIOチェックを作ります。

port name dir L H
PD6 LED0 out 点灯 消灯
PD7 LED1 out
PB1 SW1 in 押す 離す

ターゲットボード環境でのテスト

1. テストファイルを用意する

以前の記事で、下記のテストファイルを/srt/test/以下に用意しています。

  • Test0.c - テストグループの定義、および、各テストケースを記述
  • AllTests.c - テストで実行するテストグループを記述

このうち、Test0.cを修正してテストを用意します。

ハードウェアの動作確認では、人がLEDの点灯状態をチェックしたり、SWを操作する必要があります。このため、チェック結果を入力させたり、操作メッセージを表示する補助関数を用意します。

  • MANUAL_CHECK(question)
    確認メッセージを表示し、チェック結果のキー入力y(es)もしくはn(o)を受け取ります。その結果によって、テストをPASS/FAILさせます。FAIL時に行番号がわかるようにマクロで記述しています。
#define MANUAL_CHECK(question)  _ManualCheck(question, __LINE__)
static void _ManualCheck(const char *question, int line)
{
    printf("\nManual Check> %s -> press <y/n>: ", question);
    if ( getchar() == 'y' ) {
        // 手動判定:PASS
    } else {
        // 手動判定:FAIL
        char msg[100];
        sprintf(msg, "Manual Check(line:%d)", line);
        TEST_FAIL_MESSAGE(msg);
    }
}
  • ManualOperation(const char *operation)
    操作メッセージを表示し、キー入力y(es)を受けとると、処理を継続します。
static void ManualOperation(const char *operation){
    printf("\nManual Operation> %s -> press <y>: ", operation);
    getchar();
}

これらを利用すると、テストコードは下記になります。

#include "../unity/unity_fixture.h"
#include <stdio.h>
#include "../io.h"

// 各テストケースの前に実行する共通処理(初期化)
TEST_SETUP(Test0)
{
    LED0 = LED_OFF;
    LED1 = LED_OFF;
}

// テストケース(LED0 の IOチェック)
TEST(Test0, Led0_IoCheck)
{
    LED0 = LED_ON;
    MANUAL_CHECK("Is LED0 on?");
    LED0 = LED_OFF;
    MANUAL_CHECK("Is LED0 off?");
}

// テストケース(LED1 の IOチェック)
TEST(Test0, Led1_IoCheck)
{
    LED1 = LED_ON;
    MANUAL_CHECK("Is LED1 on?");
    LED1 = LED_OFF;
    MANUAL_CHECK("Is LED1 off?");
}

// テストケース(SW1 の IOチェック)
TEST(Test0, SW1_IoCheck)
{
    ManualOperation("push sw1.");
    TEST_ASSERT_EQUAL(SW1_PUSH, SW1);
    ManualOperation("release sw1.");
    TEST_ASSERT_EQUAL(SW1_RELEASE, SW1);
}

// テストグループで、実行するテストケースを列挙する
TEST_GROUP_RUNNER(Test0)
{
    RUN_TEST_CASE(Test0, Led0_IoCheck);
    RUN_TEST_CASE(Test0, Led1_IoCheck);
    RUN_TEST_CASE(Test0, SW1_IoCheck);
}
#define LED_ON          (0)
#define LED_OFF         (1)
#define SW1_PUSH        (0)
#define SW1_RELEASE     (1)

/* Switches */
#define SW1             (PORTB.PIDR.BIT.B1)

/* LED port settings */
#define LED0            (PORTD.PODR.BIT.B6)
#define LED1            (PORTD.PODR.BIT.B7)

2. ターゲットボード環境でのテスト実行

  • ターゲットボードをPCに接続しておく
  • ビルド構成 としてHardwareDebug(Debug on hardware)を選択し、ビルド
  • デバックの構成 として~ HardwareDebugを選択し、デバック開始&プログラム実行
  • Renesas Debug Virtual Consoleの表示に従い、SW操作とキーボードを押下し、テストを進める。
  • 最終的に、下記表示となればOK。
Unity test run 1 of 1
TEST(Test0, Led0_IoCheck)
Manual Check> Is LED0 on? -> press <y/n>: y
Manual Check> Is LED0 off? -> press <y/n>: y PASS
TEST(Test0, Led1_IoCheck)
Manual Check> Is LED1 on? -> press <y/n>: y
Manual Check> Is LED1 off? -> press <y/n>: y PASS
TEST(Test0, SW1_IoCheck)
Manual Operation> push sw1. -> press <y>: y
Manual Operation> release sw1. -> press <y>: y PASS

-----------------------
3 Tests 0 Failures 0 Ignored 
OK

ちなみに、NG時は下記です。手動判定でのNG行番号はManual Check(line:XX)と表示されます。

Unity test run 1 of 1
TEST(Test0, Led0_IoCheck)
Manual Check> Is LED0 on? -> press <y/n>: n../src/test/Test0.c:19::FAIL: Manual Check(line:49)
TEST(Test0, Led1_IoCheck)
Manual Check> Is LED1 on? -> press <y/n>: n../src/test/Test0.c:19::FAIL: Manual Check(line:59)
TEST(Test0, SW1_IoCheck)
Manual Operation> push sw1. -> press <y>: y../src/test/Test0.c:69::FAIL: Expected 0 Was 1

-----------------------
3 Tests 3 Failures 0 Ignored 
FAIL

最後に

今回は、テストフレームワークをハードウェアの動作確認として使ってみました。
ハードウェアの動作確認というと、PCからターゲットボードにコマンドを投げて確認するとか、デバックポートでCUIを作ったりとか、になりそうですが、既存のIDE環境で手をかけずに作れるのはメリットと思いました。また、項目が増えてきた時、確認項目(テストケース)をテストフレームワークの管理方法で整理しておくと、保守しやすいかも知れないです。

RXマイコンで、Unityによる単体テストをやってみた

Qiitaの「TDDによるマイコンのLチカ開発」を、ルネサス製のRXマイコンIDE(e2studio)の組み合わせで、真似してみました。

  1. RXマイコンで、Unityを使って単体テストをしてみる。
  2. シミュレータ環境、ターゲットボード環境の2通り。
  3. 元の記事にあった、ホスト環境は省略。
  • Unityを使った単体テスト環境のセットアップについては、こちら
  • プロジェクト一式は、こちら(rx231_unit_test_2.zip - Google ドライブ)
    インポート方法
    1. メニュー >ファイル > インポート でインポートのダイアログを表示
    2. 既存プロジェクトをワークスペースへを選択
    3. アーカイブ・ファイルの選択でファイルを選択し、終了ボタンでインポート

環境

お題

ハードウェアを絡めた一番簡単なお題を設定します。ターゲットボードには、LED2つとSW1つがあります。これを利用して、次の機能を持つ関数IO_CotrolLedBySw()を作ります。

  • SW1 を押すと、LED0が点灯
  • SW1 を離すと、LED0が消灯

LEDとSWの仕様は下記の通りです。

port name dir L H
PD6 LED0 out 点灯 消灯
PD7 LED1 out
PB1 SW1 in 押す 離す

シミュレータ環境でのテスト

1. テストファイルを用意する

以前の記事で、下記のテストファイルを/srt/test/以下に用意しています。

  • Test0.c - テストグループの定義、および、各テストケースを記述
  • AllTests.c - テストで実行するテストグループを記述

このうち、Test0.cを修正してテストを用意します。

シミュレータ環境の特徴として、ReadOnlyの入力データレジスタ(PIDR)にも書き込み可能です。
このため、SW1 のボタンを押した状態にするには、

// SW1 のボタンを押した状態にする
SW1 = SW1_PUSH;           // PORTB.PIDR.BIT.B1 = 0;

で済みます。これを利用すると、テストコードは下記になります。

#include "../unity/unity_fixture.h"
#include "../io.h"

・・・

// テストケース(IO_CotrolLedBySw() - SW1 を押すと、LED0が点灯)
TEST(Test0, IO_CotrolLedBySw_SW1Push)
{
    // まず、LED0をOFFしておく
    LED0 = LED_OFF;

    // SW1 のボタンを押した状態にする
    // シミュレータ環境では、入力データレジスタに値を書き込める
    SW1 = SW1_PUSH;

    // テスト対象関数を呼ぶ
    IO_CotrolLedBySw();

    // LED0がONに変化した事をチェック
    TEST_ASSERT_EQUAL(LED_ON, LED0);
}

// テストケース(IO_CotrolLedBySw() - SW1 を離すと、LED0が消灯)
TEST(Test0, IO_CotrolLedBySw_SW1Release)
{
    // まず、LED0をONしておく
    LED0 = LED_ON;

    // SW1 のボタンを離した状態にする
    SW1 = SW1_RELEASE;

    // テスト対象関数を呼ぶ
    IO_CotrolLedBySw();

    // LED0がOFFに変化した事をチェック
    TEST_ASSERT_EQUAL(LED_OFF, LED0);
}

// テストグループで、実行するテストケースを列挙する
TEST_GROUP_RUNNER(Test0)
{
    RUN_TEST_CASE(Test0, IO_CotrolLedBySw_SW1Push);
    RUN_TEST_CASE(Test0, IO_CotrolLedBySw_SW1Release);
}

2. テスト対象コードの用意

実際はTDD的に実装を進めるのですが、記事の都合上、最終コードを掲載します。

#ifndef IO_H_
#define IO_H_
#include "r_smc_entry.h"    // iodefine.h を使用するために記載

#define LED_ON          (0)
#define LED_OFF         (1)
#define SW1_PUSH        (0)
#define SW1_RELEASE     (1)

/* Switches */
#define SW1             (PORTB.PIDR.BIT.B1)

/* LED port settings */
#define LED0            (PORTD.PODR.BIT.B6)
#define LED1            (PORTD.PODR.BIT.B7)

void IO_CotrolLedBySw(void);

#endif /* IO_H_ */
#include "io.h"

void IO_CotrolLedBySw(void)
{
    if ( SW1 == SW1_RELEASE ) {
        LED0 = LED_OFF;
    } else {
        LED0 = LED_ON;
    }
}

3. シミュレータ環境でのテスト実行

  • ターゲットボードをPCから外しておく
  • ビルド構成としてDebug(Debug)を設定し、ビルド
  • デバックの構成として~ Debugを選択し、デバック開始&プログラム実行
  • Renesas Debug Virtual Consoleに下記が表示されればOK
Unity test run 1 of 1
TEST(Test0, IO_CotrolLedBySw_SW1Push) PASS
TEST(Test0, IO_CotrolLedBySw_SW1Release) PASS

-----------------------
2 Tests 0 Failures 0 Ignored 
OK

ターゲットボード環境でのテスト

1. テストファイルを用意する

ターゲットボード環境では、SW1 を人に操作してもらいます。このため、メッセージを表示する補助関数を用意します。

// 手動操作の補助関数
static void ManualOperation(const char *operation){
    printf("\nManual Operation> %s -> press <y>: ", operation);
    getchar();
}

これを利用すると、テストコードは下記になります。

USE_SIMULATORはシミュレータ環境のみ定義されるマクロです。

#include "../unity/unity_fixture.h"
#include "../io.h"

・・・

// テストケース(IO_CotrolLedBySw() - SW1 を押すと、LED0が点灯)
TEST(Test0, IO_CotrolLedBySw_SW1Push)
{
    // まず、LED0をOFFしておく
    LED0 = LED_OFF;

    // SW1 のボタンを押した状態にする
#ifdef USE_SIMULATOR
    // シミュレータ環境では、入力データレジスタに値を書き込める
    SW1 = SW1_PUSH;
#else
    // ターゲットボード環境では、手動でSW1を操作し、状態をチェックして進む
    do {
        ManualOperation("push sw1.");
    } while( !(SW1 == SW1_PUSH) );
#endif

    // テスト対象関数を呼ぶ
    IO_CotrolLedBySw();

    // LED0がONに変化した事をチェック
    TEST_ASSERT_EQUAL(LED_ON, LED0);
}

// テストケース(IO_CotrolLedBySw() - SW1 を離すと、LED0が消灯)
TEST(Test0, IO_CotrolLedBySw_SW1Release)
{
    // まず、LED0をONしておく
    LED0 = LED_ON;

    // SW1 のボタンを離した状態にする
#ifdef USE_SIMULATOR
    SW1 = SW1_RELEASE;
#else
    do {
        ManualOperation("release sw1.");
    } while( !(SW1 == SW1_RELEASE) );
#endif

    // テスト対象関数を呼ぶ
    IO_CotrolLedBySw();

    // LED0がOFFに変化した事をチェック
    TEST_ASSERT_EQUAL(LED_OFF, LED0);
}

// テストグループで、実行するテストケースを列挙する
TEST_GROUP_RUNNER(Test0)
{
    RUN_TEST_CASE(Test0, IO_CotrolLedBySw_SW1Push);
    RUN_TEST_CASE(Test0, IO_CotrolLedBySw_SW1Release);
}

2. ターゲットボード環境でのテスト実行

  • ターゲットボードをPCに接続しておく
  • ビルド構成 としてHardwareDebug(Debug on hardware)を選択し、ビルド
  • デバックの構成 として~ HardwareDebugを選択し、デバック開始&プログラム実行
  • Renesas Debug Virtual Consoleの表示に従い、SW操作とキーボードを押下し、テストを進める。
  • 最終的に、下記表示となればOK。
Unity test run 1 of 1
TEST(Test0, IO_CotrolLedBySw_SW1Push)
Manual Operation> push sw1. -> press <y>: y PASS
TEST(Test0, IO_CotrolLedBySw_SW1Release)
Manual Operation> release sw1. -> press <y>: y PASS

-----------------------
2 Tests 0 Failures 0 Ignored 
OK

3. 作った関数を動作させる

メイン関数を書き換えて、関数IO_CotrolLedBySw()を呼び出します。 ターゲットボード環境でビルド・実行。SW1押下に応じて、LED0が点灯・消灯すればOKです。

#include "r_smc_entry.h"
#include "io.h"

void main(void)
{
    LED0 = LED_OFF;
    LED1 = LED_OFF;
    while(1) {
        IO_CotrolLedBySw();
    }
}

最後に

実際に試すことで、シミュレータ環境とターゲットボード環境の差が理解できました。シミュレータ環境では、ReadOnlyのレジスタにライト可能であり、入力信号を任意に設定にできます。同様に、CPUペリフェラルのエラーも任意に設定できるので、テスト作成で大きな助けとなりそうです。
このレジスタ設定の自由度は、Unity作者様の記事"WHICH BUILD METHOD?"でも、シミュレータ環境のメリットとして紹介されています。ただ、ターゲットボード環境も、ハードウェアの動作確認やエージングで活用できるのでは?と思っています。

参考にした情報

  1. Qiita - @iwatake2222 さん

    ⇒ 今回やってみる動機となった記事です。

  2. Throw The Switch - Unity作者様のサイト

    単体テスト環境として、シミュレータ、ホスト(Windowsなど)、ターゲットボードを比較しています。

  3. 書籍 - テスト駆動開発による組み込みプログラミング―C言語とオブジェクト指向で学ぶアジャイルな設計

RXマイコンで、Unityによる単体テスト環境を作ってみた(後編)

Qiitaの記事「TDDによるマイコンのLチカ開発」を、ルネサス製のRXマイコンIDE(e2studio)の組み合わせで、真似してみました。

  1. RXマイコンで、Unityによる単体テスト環境をセットアップする。
  2. シミュレータ環境、ターゲットボード環境の2通りを用意する。
  3. 元の記事にあった、ホスト環境の構築、CMockの導入は省略。
  • 後編では、テストフレームワークUnityを導入し、テストを行います。
  • 前編はこちら。RXマイコンのプロジェクト生成とprintf()での文字出力を行います。
  • プロジェクト一式は、こちら(rx231_unit_test_1.zip - Google ドライブ)
    インポート方法
    1. メニュー >ファイル > インポート でインポートのダイアログを表示
    2. 既存プロジェクトをワークスペースへを選択
    3. アーカイブ・ファイルの選択でファイルを選択し、終了ボタンでインポート

環境

テストフレームワークの導入

元の記事と同様に、Unityを導入していきます。

1.マイコンIDE上でフォルダを作成する


プロジェクト・エクスプローラーで、新規>フォルダーを選択。以下の構造を作ります。

src/
    - smc_gen/              // 自動生成されたコードが格納されている
    - test/                 // テストファイルを格納 <追加>
    - unity/                // Unityのソースを格納 <追加>
    - rx231_unit_test.c     // メインのソースコード

2. Unityのソースコードをコピー


作成した/src/unity/フォルダに、Unity(https://github.com/ThrowTheSwitch/Unity)の下記ソースをドラック&ドロップで追加します。

  • Unity-master/src
    unity.c, unity.h, unity_internals.h
  • Unity-master/extras/fixture/src
    unity_fixture.c, unity_fixture.h, unity_fixture_internals.h, unity_fixture_malloc_overrides.h

3. テストファイルを用意する


テストファイルを/srt/test/以下に用意します。それぞれ次の用途です。

  • Test0.c - テストグループの定義、および、各テストケースを記述
  • AllTests.c - テストで実行するテストグループを記述
#include "../unity/unity_fixture.h"

// テストグループを定義
TEST_GROUP(Test0);

// 各テストケースの前に実行する共通処理(初期化)
TEST_SETUP(Test0)
{
}

// 各テストケースの後に実行する共通処理(後片付け)
TEST_TEAR_DOWN(Test0)
{
}

// テストケース
TEST(Test0, AlwaysFail)
{
    // 何もせず、テストを失敗させて、メッセージを出力する
    TEST_FAIL_MESSAGE("This test always fails.");
}

// テストグループで、実行するテストケースを列挙する
TEST_GROUP_RUNNER(Test0)
{
    RUN_TEST_CASE(Test0, AlwaysFail);
}
#include "../unity/unity_fixture.h"

// 実行するテストグループを列挙する
void RunAllTests(void)
{
    RUN_TEST_GROUP(Test0);
}

4. main関数からテストを呼ぶ


main関数からテストを呼びます。UnityMain()にはコマンドラインオプションが指定できます。ここでは"-v"を渡し、各テストの実行前にテスト名を出力します。

#include "r_smc_entry.h"
#include "unity/unity_fixture.h"

void main(void)
{
#if 1
    // コマンドラインオプション "-v" を指定。
    // -v   詳細(verbose)モード。各テストの実行前にテスト名を出力する。
    int argc = 2;
    const char *argv[] = {"program name", "-v"};
    extern void RunAllTests(void);
    UnityMain(argc, argv, RunAllTests);
#endif
    while(1);
}

5. プロジェクト設定


  • プロジェクトの設定で、math.h のライブラリを生成するよう変更します1
    • プロジェクトエクスプローラから、プロパティ > C/C++ ビルド > 設定 を選択
    • ツール設定のタブより、Library Generator > 構成を選択
    • 構成を[全ての構成]に変更した後、math.hをチェック

    f:id:sonoka_gi:20190623234354p:plain

6. 実行してみる


ターゲットボード環境、シミュレータ環境のそれぞれでビルド・デバック実行し、下記が出力さればOK。

Unity test run 1 of 1
TEST(Test0, AlwaysFail)../src/test/Test0.c:23::FAIL: This test always fails.

-----------------------
1 Tests 1 Failures 0 Ignored 
FAIL

f:id:sonoka_gi:20190623234409p:plain

最後に

シミュレータとRenesas Debug Virtual Consoleのおかげで単体テスト環境構築は簡単です。いつものIDE環境に+αで気軽にテストを始められるのは良いと思います 。(これから先が大変なんでしょうけど・・・)
シミュレータ環境は通常の単体テストに。ターゲットボード環境はハードウェアの動作確認に利用できそうです。

参考にした情報

  1. Qiita - @iwatake2222 さん

    ⇒ 今回やってみる動機となった記事です。

  2. 書籍 - テスト駆動開発による組み込みプログラミング―C言語とオブジェクト指向で学ぶアジャイルな設計

  3. ルネサスのドキュメント - e2 studioでのUnityの使用方法(R20AN0313JJ0100)
    ⇒ 今回は参考にしてませんが、以前、アプリケーションノートを発行していたようです。


  1. これを設定しないと_FDxxxxが見当たらないというエラーがでました。

RXマイコンで、Unityによる単体テスト環境を作ってみた(前編)

Qiitaの記事「TDDによるマイコンのLチカ開発」を、ルネサス製のRXマイコンIDE(e2studio)の組み合わせで、真似してみました。

  1. RXマイコンで、Unityによる単体テスト環境をセットアップする。
  2. シミュレータ環境、ターゲットボード環境の2通りを用意する。
  3. 元の記事にあった、ホスト環境の構築、CMockの導入は省略。 f:id:sonoka_gi:20190629201139p:plain

環境

プロジェクト作成とprintf()での文字出力

e2studio(V7.3.0以降)では、プロジェクトを生成時に「Renesasデバック仮想コンソールを使用する」をチェックすると、IDE内の専用コンソールを標準出力として使えます。※但し、かなりの出力遅延あり。

1. プロジェクト作成


メニュー > ファイル > 新規 > C/C++プロジェクト から作成し、下記を設定。

  • Templete for New C/C++ Project

    • Renesas RX > Renesas CC-RX C/C++ Executable Projectを選択
  • Select toolchain, device&debug settings

    • Device Settingsのターゲット・デバイスは、RX231-100pin>R5F52318AxFPを選択
    • Configrationsの Hardware Debug構成を生成Debug構成を生成 の2つにチェック
      ※それぞれ、ターゲットボード環境、シミュレータ環境に相当
  • コーディングアシストツールの選択

    • スマートコンフィグレータを使用するにチェック
  • 生成する初期化ルーチンの選択

    • Renesasデバック仮想コンソールを使用するをチェック

    f:id:sonoka_gi:20190622235532p:plain

2. ハードウェア初期化コードの生成


スマートコンフィグレータによるコード生成を利用し、クロックとGPIOの初期化コードを生成します。

  • [クロック]タブ

    • メインクロックのチェックを外す(実装されていないので)
    • 高速オンチップオシレータHOCOクロック(54MHz)を選択

    f:id:sonoka_gi:20190623000117p:plain

  • [コンポーネント]タブ

    • コンポーネントの追加ボタンで、ソフトウェアコンポーネントの選択ダイアログを表示。
    • コンポーネント[ポート]を追加

    f:id:sonoka_gi:20190623000137p:plain

  • コンポーネントConfig_PORTを選択。LED出力2点(PD6,7)、SW入力1点(PB1)のGPIOを設定

    f:id:sonoka_gi:20190623000201p:plain

  • 右上にあるコードの生成ボタンを押すと、初期化コードが生成される

3. コード修正


プロジェクトの構成は下記のようになっています。ここでは2か所のコードを修正します。

f:id:sonoka_gi:20190623015542p:plain

  • main関数に、printf() と Unityで使う putchar() の動作確認コードを追加。
#include "r_smc_entry.h"
#include <stdio.h>

void main(void)
{
    printf("Hello World!\n");
    putchar('p');
    while(1);
}
  • Debug構成(シミュレータ環境)に、コンパイルスイッチUSE_SIMULATORを追加し、クロック初期化コードを一部無効にします1
static void clock_source_select (void)
{
    ・・・・
    /* Make sure HOCO is stopped before changing frequency. */
    SYSTEM.HOCOCR.BYTE = 0x01;

    /* Set frequency for the HOCO. */
    SYSTEM.HOCOCR2.BIT.HCFRQ = BSP_CFG_HOCO_FREQUENCY;

    /* HOCO is chosen. Start it operating. */
    SYSTEM.HOCOCR.BYTE = 0x00;
    /* WAIT_LOOP */
#ifndef USE_SIMULATOR
    // シミュレータでは、ここでハードウェアの変化を無限に待ってしまう
    while (SYSTEM.OSCOVFSR.BIT.HCOVF != 1)
    {
        ;   // wait for stabilization
    }
#endif
    ・・・・
}
  • プロジェクトエクスプローラから、プロパティ > C/C++一般 > パスおよびシンボルを選択。
    • 構成:を、Debugに変更
    • #シンボルタブより、コンパイルスイッチUSE_SIMULATORを追加

    f:id:sonoka_gi:20190623014916p:plain

4. ターゲットボード環境でのビルドと動作確認


  • ターゲットボードをPCに接続しておく

  • ビルドする

    • プロジェクトエクスプローラから、ビルド構成 > アクティブにする > HardwareDebug(Debug on hardware)を選択。その後、プロジェクトのビルドを選択。
  • デバック設定とデバックの開始

    • メニュー > 実行 > デバックの構成 より、~ HardwareDebug の構成を選択し、Debuggerタブを開く
    • Debugger hardware をE2 Lite(RX) に設定
    • 電源 > エミュレータから電源を供給する を いいえ に設定
    • デバックのボタンを押下して、デバックを開始する。(再度デバックするときはF11で可)

    f:id:sonoka_gi:20190630185555p:plain

  • ターゲットへの接続・ダウンロードが完了したら、Renesas Debug Virtual Consoleのウィンドウを開く。見当たらない時はメニュー > Renesas Views > デバック > Renesas Debug Virtual Consoleで表示。

    • ウィンドウをドラックして、コンソールと同時に表示したほうが使いやすい感じです。 f:id:sonoka_gi:20190623001423p:plain
      f:id:sonoka_gi:20190623001426p:plain
  • プログラム実行(F8を押下)。コンソールに"Hello World!"と"p"が表示されればOK f:id:sonoka_gi:20190623001405p:plain

5.シミュレータ環境の設定と動作確認


  • ターゲットボードをPCから外しておく

  • ビルドする

    • プロジェクトエクスプローラから、ビルド構成 > アクティブにする > Debug(Debug)を選択。その後、プロジェクトのビルドを選択。
  • デバック設定とデバックの開始

    • メニュー > 実行 > デバックの構成 より、~ Debug の構成を選択。(特に設定項目なし)
    • デバックのボタンを押下して、デバックを開始する。(再度デバックするときはF11で可)

    f:id:sonoka_gi:20190623001043p:plain

  • プログラム実行(F8を押下)。Renesas Debug Virtual Consoleに"Hello World!"と"p"が表示されればOK

    f:id:sonoka_gi:20190623001030p:plain

最後に

e2studioのバージョンアップでRenesas Debug Virtual Consoleが簡単に使えるようになりました。このため、IDE上でのprintf()出力まではスムーズです。次は、Unityを導入して、単体テスト環境を構築します。

参考にした情報

  1. ルネサスのドキュメント

  2. ルネサスのFAQ


  1. シミュレータでは、CPUの周辺ハードウェア動作はサポートされないため、ハードウェアの変化を待つループがあると、無限待ちになります。最初にシミュレータを利用した時、main()関数が呼ばれなくて困りました・・・

Androidで、Vuforiaの Positional Device Tracker を使ってみた

Vuforia の"Positional Device Tracker"を試してみました。この機能を有効にすると、マーカーが見えなくなっても、マーカーのトラッキングを継続してくれます。(動画でEXTENED_TRACKED と表示されている期間が相当)

※マーカーは、石畳のマーカーを1つだけ使用してます。周囲のマーカーは位置ずれ確認用の目印です。

この機能は、以前は"Extended Tracking API"として提供されていましたが、Vuforia V7.2以降は"Positional Device Tracker"に置き換えられました。また、"Device Tracker"は内部でARKit やARCore を利用可能になっています。ARCoreを利用する場合、少しだけ設定が必要です。(参考:Extended Tracking の説明)


~ 目次 ~


環境

  • Unity 2018.2.18f1(64-bit)
  • Vuforia V7.5.26 ※上記のUnityに同梱のバージョンを利用
  • Windows10(64bit)
  • Galaxy S8 SCV36(au) ※Android 8.0.0, ARCore V1.5.180910096 をインストール済み

手順

Android で、Positional Device Tracker (ARCore利用) を有効にする手順です。

  1. Vuforiaを使ってマーカー上にオブジェクトを表示するシーンを作成する。下記では、石畳のマーカー上に、Cubeと方眼のテクスチャを張ったPlaneを配置してます。

    下記のサイトなどを参考に、、、

  2. ARCoreのライブラリを導入する(参考:Using ARCore with Vuforia)

  3. Device Tracker を設定する

    • メニューから Window > Vuforia Configuration を選択し、VuforiaConfigrationのパネルを開く
    • "Device Tracker"の項目にある "Track Device Pose" をチェックする
    • Tracking Mode を POSITIONAL にする
    • Fusion Mode を Optimize for Image Targets and VuMarks にする
  4. メニューから Edit > Project Settings > Player を選択し、PlayerSettingsのパネルを開く

    • Other Settings のAndroid TV Compatiblity のチェックを外す。
      ※このチェックが有効だと、"Vuforia does not support Android TV. Please disable the Android TV compatibility in the Player Settings."というエラーが出ます。

    • ARCore用のビルド設定をする
      ※念のため、ARCoreビルド時の設定をしておく。Vuforiaのサイトに言及ないので不要かも

      • Other Settings のMultithreaded Rendering のチェックを外す
      • Other Settings のMinimum/Target API Level をAndroid 7.0 以上に設定
    • XR Settings のVuforia Augmented Reality のチェックを確認

  5. メニューから File > Build And Run を選択し、ビルドする
    タイトルの動画へ

補足

  1. Device Trackerで使用しているテクノロジの確認
    Device Trackerが、現在どのテクノロジを利用しているかは、VuforiaRuntimeUtilitiesクラスのstatic FusionProviderType GetActiveFusionProvider()メソッドで取得できます。

    FusionProviderTypeの値 意味
    PLATFORM_SENSOR_FUSION Use the Platform-provided technology for Fusion
    ※ARKitやARCoreなどを利用している場合は、これになる
    VUFORIA_SENSOR_FUSION Use the Vuforia provided sensor fusion
    VUFORIA_VISION_ONLY Vision based tracking only
    ※試しに、AndroidからARCoreをアンインストールして実行すると、これになりました

    参考:GetActiveFusionProvider() メソッドenum値 FusionProviderType

  2. ラッキング状態の取得
    動画で表示しているトラッキング状態は、ImageTargetオブジェクトにアタッチされているDefaultTrackableEventHandler.csTrackableBehaviour.Status m_NewStatus の値を表示しました。

    public class DefaultTrackableEventHandler : MonoBehaviour, ITrackableEventHandler
    {
        #region PROTECTED_MEMBER_VARIABLES

        protected TrackableBehaviour mTrackableBehaviour;
        protected TrackableBehaviour.Status m_PreviousStatus;
        protected TrackableBehaviour.Status m_NewStatus;        

参考にした情報

  1. Vuforia 7.2 への移行説明
    Migrating Unity Projects to Vuforia 7.2
    How To Migrate Native Projects to Vuforia Engine 7.2

  2. Device Tracker の設定
    Using the Positional Tracker for AR

ARCoreを使って、ユニティちゃんを地面で歩かせてみた

ARCoreで地面(平面)を検出し、その上でユニティちゃんを歩かせてみました
※正確には、地面に配置した透明なPlaneの上を歩いています。また、Planeを外れるとユニティちゃんが落下するため、移動できる範囲は5mくらいです


~ 目次 ~


環境

  • Galaxy S8 SCV36(au) ※Android 8.0.0, ARCore V1.5.180910096 をインストール済み
  • Windows10(64bit)
  • Unity 2018.1.1f1(64-bit)
  • ARCore SDK for Unity v1.5.0
  • "Unity-chan!" Model(V1.1)

手順1. Unity-Chan!を導入して、PC上でユニティちゃんを動かす

※この作業はPC単体で行います

  • Asset Store より"Unity-Chan!" Model をインポート

  • Assets/UnityChan/Prefabs/unitychanをHierarchyに追加

  • unitychan のInspectorで下記を実施

    • Animator の Controller をUnityChanARPose からUnityChanLocomotions に変更
    • IdleChangerFaceUpdateを削除
    • スクリプトAssets/UnityChan/Scripts/UnityChanControlScriptWithRgidBodyを追加
    • Rigidbody 設定で、Constraints > Freeze Rotation の X,Y,Z にチェックを入れる
    • Capsule Collider 設定で、CenterのYを0.75、Heightを1.5 にして、ユニティちゃんの大きさに合わせる
  • メニューからGameObject > 3D Object > Plane を選択して、Planeを生成。Transform 設定で、Poisiton を (0, 0, 0) に

  • PC上で実行(Play)。カーソルキーでユニティちゃんの前後移動と旋回操作ができればOK

手順2. ARCoreを導入し、Android上でユニティちゃんを表示

※この作業はPCとAndroid端末を接続して行います

  • 下記より ARCore SDK for Unity arcore-unity-sdk-v1.5.0.unitypackage をダウンロードし、インポート
    Releases · google-ar/arcore-unity-sdk · GitHub

  • Assets/GoogleARCore/Prefabs/ARCore DeviceをHierarchyに追加し、Main Cameraを削除

  • 下記を参考に、Android および ARCore用のビルド設定をする
    ARCore 取扱説明書 - Qiita

    • Build Settings を開き、Platform をAndroid に変更(Switch Platformを忘れずに)
    • PlayerSettings を開く
      • Product Name と、Other Settings のPackage Name を設定
      • Other Settings のMultithreaded Rendering のチェックを外す
      • Other Settings のMinimum/Target API Level をAndroid 7.0 以上に設定
      • XR Settings のARCore Supported をチェック
  • Build&Runする。アプリが起動したら後ろに移動して、Planeに乗ったユニティちゃんが見えればOK

手順3. ARCoreを設定し、平面を検出できるようにする

※この作業はPCとAndroid端末を接続して行います

  • Aseetsで右クリック。Create>GoogleARCore>SessionConfig を選択

  • 生成されたARCoreSessionConfigを選択。Plane Finding Mode をHorizontal に設定
    ※今回は地面を検出したいので、水平面のみ検出するよう設定

  • Hierarchy からARCore Device を選択。AR Core Session 設定のSession Config にARCoreSessionConfigをセット

  • メニューより、GameObject>Create Empty を選択。生成されたGameObjectに、スクリプト Assets/GoogleARCore/Examples/Common/Scripts/DetectedPlaneGeneratorを追加

  • DetectedPlaneGenerator 設定のDetected Plane Prefab に、Assets/GoogleARCore/Examples/Common/Prefabs/DetectedPlaneVisualizerをセット

  • Hierarchy からPlane を選択。Mesh Renderer横のチェックを外して、Plane を透明にする
    ※最後に透明にする予定でしたが、実行時に邪魔になるので、ここで透明にしておきます

  • Build&Runする。アプリが起動したら床を見渡して、メッシュが表示されたらOK
    ※動画では赤いメッシュになってますが、通常は最初に白いメッシュが表示されます

手順4. ARCoreで検出した平面に、ユニティちゃんを配置

※この作業はPCとAndroid端末を接続して行います

  • GameObject に新規スクリプトPutUnityChan.csを追加

  • スクリプトを記述。大まかに下記を行っています

    • 画面タッチを検出
    • タッチ位置を、ARCore が検出した平面上での位置に変換
    • 平面上に、ユニティちゃんとPlane を配置
    • Anchorを設置し、ユニティちゃんとPlane をその子にする
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using GoogleARCore;

public class PutUnityChan : MonoBehaviour {

    // 平面上に配置する ユニティちゃん と Plane を指定する
    public GameObject UnityChan;
    public GameObject Plane;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        // タッチしていないなら、何もしない
        if (Input.touchCount < 1) return;

        // GUIに対するタッチであれば無視する
        // ※この条件は、後で追加するGUI操作を意識した物。GUIを追加しない場合は不要。
        if (EventSystem.current != null &&
            EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) return;

        // タッチ点の取得
        Touch touch = Input.GetTouch(0);

        // タッチの開始以外は、無視する
        if (touch.phase != TouchPhase.Began) return;

        // タッチした先に、ARCoreが検出した平面があるかチェック
        // PlaneWithinPolygon:延長線上の点が「平面を構成するポリゴン境界内」に交差する点を探す
        TrackableHit hit;
        if (Frame.Raycast(touch.position.x, touch.position.y, TrackableHitFlags.PlaneWithinPolygon, out hit))
        {
            // 平面上にオブジェクトを配置
            if (hit.Trackable is DetectedPlane)
            {
                // UnityChan の位置・姿勢を指定
                // ※hit.Pose.rotationは、Z+方向がカメラの向きになる
                //   そのままだと後ろを向いてしまうので、Y軸回りに180度回転
                UnityChan.transform.position = hit.Pose.position;
                UnityChan.transform.rotation = hit.Pose.rotation;
                UnityChan.transform.Rotate(0, 180, 0, Space.Self);

                // Plane の位置・姿勢を指定
                Plane.transform.position = hit.Pose.position;
                Plane.transform.rotation = hit.Pose.rotation;

                // Anchorを生成し、各オブジェクトをAnchorの子にする
                // ※ARCoreで位置関係を維持するには、Anchorを生成し、その子に入れる必要がある
                Anchor anchor = hit.Trackable.CreateAnchor(hit.Pose);
                UnityChan.transform.parent = anchor.transform;
                Plane.transform.parent = anchor.transform;
            }
        }
    }
}
  • PutUnityChan 設定の Unity Chan と Plane に、unitychanPlaneをセット

  • unitychan にアタッチされているスクリプトUnityChanControlScriptWithRgidBody.csを修正(2か所)

////// 1. キャラクターを移動させる(100行付近)を、ローカル座標からワールド座標に変更

        // 上下のキー入力でキャラクターを移動させる
#if false
        transform.localPosition += velocity * Time.fixedDeltaTime;
#else
        // ワールド座標系で移動するように変更
        // ※オブジェクトをAnchorの子オブジェクトとしている関係で
        //   ローカル座標系で移動させると、おかしな方向に移動してしまう。
        transform.position += velocity * Time.fixedDeltaTime;
#endif
////// 2. GUI表示(190行付近)を、コメントアウト

    void OnGUI()
    {
#if false
        // GUI表示は無効にする
        GUI.Box(new Rect(Screen.width -260, 10 ,250 ,150), "Interaction");
        GUI.Label(new Rect(Screen.width -245,30,250,30),"Up/Down Arrow : Go Forwald/Go Back");
        GUI.Label(new Rect(Screen.width -245,50,250,30),"Left/Right Arrow : Turn Left/Turn Right");
        GUI.Label(new Rect(Screen.width -245,70,250,30),"Hit Space key while Running : Jump");
        GUI.Label(new Rect(Screen.width -245,90,250,30),"Hit Spase key while Stopping : Rest");
        GUI.Label(new Rect(Screen.width -245,110,250,30),"Left Control : Front Camera");
        GUI.Label(new Rect(Screen.width -245,130,250,30),"Alt : LookAt Camera");
#endif
    }
  • Build&Runする
    • アプリが起動したら床を見渡して、メッシュを表示させる
    • メッシュ内をタップし、ユニティちゃんが表示されればOK
    • もし、ゲームパッドやキーボードが使える状態なら、ユニティちゃんを操作できます
      ※DualShock4なら左スティック(環境依存かも)、キーボードならカーソルキーで操作

手順5. GUIを追加して、ユニティちゃんを動かす

※この作業はPCとAndroid端末を接続して行います

  • メニューより、Assets > Import Package > CrossPlatformInput を選択、CrossPlatformInputをインポート

  • Assets/Standard Assets/CrossPlatformInput/Prefabs/MobileAircraftControlsをHierarchyに追加

  • MobileAircraftControls以下を修正

    • Throttle, TiltSteerInputV, TiltSteerInputH を削除
      ※ 最初の削除時に、Brake Prefab instance のメッセージが出るがContinue を押す
    • メニューより、GameObject>UI>Panel を選択し、Panel を追加。MobileAircraftControlsの一番上に配置
    • Brake を右クリックしてDuplicate(複製)を選択し、Brake(1)を作成
    • Brake の名称をWalkに変更。Brake(1)の名称をStopに変更

    ~ 修正内容の補足 ~

    • Left, Rightボタン: 左右旋回用のボタン
    • Walk, Stopボタン: 歩く、停止用のボタン
    • Panel: ボタン周辺を触ったときに画面タッチが誤動作するのを防ぐために設置
  • 各オブジェクトのInspector を修正

    • 各オブジェクトのRect Transfom 設定で、Anchorsを変更して、配置を修正
    • WalkStopのEvent Trigger 設定にて
      • ButtonHandler.SetAxisPositiveStateButtonHandler.SetDownState に変更
      • ButtonHandler.SetAxisNegativeStateButtonHandler.SetUpState に変更
    • WalkStopのButton Handler 設定にて、Name を"Walk"と"Stop"に変更
    • WalkStopの子に入っているTextの設定にて、Textを"Walk"と"Stop"に変更

    ~ 修正内容の補足 ~

    • Left, Rightボタンは、Name: "Horizontal"と設定。CrossPlatformInputManager.GetAxis("Horizontal") で、2つのボタン押下に応じた値(-1, 0, +1)を取得できる
    • Walk, Stopボタンは、Name: "Walk","Stop"と設定。それぞれのボタン押下を CrossPlatformInputManager.GetButtonDown("Walk" or "Stop")で取得できる
  • unitychan にアタッチされているスクリプトUnityChanControlScriptWithRgidBody.csを修正(3か所)

////// 1. CrossPlatformInputを使うための using ディレクティブ 追加(10行付近)

using UnityEngine;
using System.Collections;
#if true
using UnityStandardAssets.CrossPlatformInput;
#endif
////// 2. 前後移動を記憶するためのメンバ変数を追加(40行付近)

    private GameObject cameraObject;    // メインカメラへの参照

#if true
    private float vertical_ = 0.0f;     // 前後移動を記憶
#endif

    // アニメーター各ステートへの参照
    static int idleState = Animator.StringToHash("Base Layer.Idle");
////// 3. 移動操作(70行付近)で、CrossPlatformInputを使うように修正

    void FixedUpdate ()
    {
#if false
        float h = Input.GetAxis("Horizontal");  // 入力デバイスの水平軸をhで定義
        float v = Input.GetAxis("Vertical");    // 入力デバイスの垂直軸をvで定義
#else
        // CrossPlatformInputによる操作
        // 左右移動は、バーチャルパッドの水平軸([Left],[Right]ボタン操作)をそのまま反映
        float h = CrossPlatformInputManager.GetAxis("Horizontal");
        // 前後移動は、[Walk],[Stop]ボタン押下に応じて、前方移動・停止を切り替え
        if (CrossPlatformInputManager.GetButtonDown("Walk"))
        {
            vertical_ = 0.15f;
        }
        else if (CrossPlatformInputManager.GetButtonDown("Stop"))
        {
            vertical_ = 0.0f;
        }
        float v = vertical_;
#endif
  • UnityChanControlScriptWithRgidBody の設定で、移動速度を遅くする
    ※デフォルトの速度だと、操作しにくいため

    • Anim Speed: 1
    • Foward Speed: 3.5
    • Rotate Speed: 1.5
  • Build&Runする

    • アプリが起動したら床を見渡して、メッシュを表示させる
    • メッシュ内をタップすると、ユニティちゃんが表示される
    • Leftボタン, Rightボタン で、ユニティちゃんが旋回する
    • Walkボタン, Stopボタン で、ユニティちゃんの歩く・止まるを操作できればOK

    タイトルの動画へ

参考にした情報

  1. ヽ|∵|ゝ(Fantom) の 開発blog? - 【Unity】ARCore を使って現実世界にプロ生ちゃんを召喚してみる
    ⇒ こちらを見たのがきっかけで、自分でも試してみました

  2. tks_yoshinagaの日記 - ARCore対応コンテンツ開発入門
    ARコンテンツ作成勉強会資料 - はじめようArcore (修正版)
    ⇒ ARCoreの導入、検出した平面へのオブジェクト配置は、こちらの資料に従って進めました

  3. Qiita @taptappun さん - ARCore 取扱説明書
    ⇒ ARCoreの情報は、よくこちらを参照します

  4. おもちゃラボ - 【Unity】ボタンを押したときに画面クリックは無視する



この作品はユニティちゃんライセンス条項の元に提供されています