SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

[組込み開発入門] ロボットを作ろう

【第3回】NTXでRTOSを動かそう


OIL

 OILとは、OSEK Implementation Languageの略で、オイルと発音します。これを使って、使用するOSオブジェクトの設定ファイル(OILファイル)を作成します。

 このファイルにはユーザが利用したいOSオブジェクトを定義してあり、システムジェネレータ(SG)のインプットになります。SGは、ファイルを解析後ユーザプログラムに依存する部分のOSコードを生成します。カーネルは、この生成されたコードから自分が制御すべきOSオブジェクトを知ることができるようになります。

 表2に、OILで定義する代表的なOSオブジェクトを示します。

表2:OILで定義する代表的なOSオブジェクト
定義するオブジェクト 内容
CPU OSEK OSの制御のもとアプリケーションを実行するCPU
OS OSEK OSのこと
APPMODE アプリケーションモード定義テストモードなど起動モードを変えたいときに使用する
RESOURCE タスクで使用されるリソース
TASK OSによって取り扱われるタスク
COUNTER アラームから使用されるOSオブジェクト。アラームは指定時間の満了の検出にカウンタを利用する。ハードウエアカウンタとソフトウエアカウンタがある
EVENT タスクの同期をとるためのOSオブジェクト
ALARM 指定周期毎にイベントを起動したりイベントをファイアしたりするOSオブジェクト

作成するアプリ

仕様

 バンパを押すことで前進を始める。危険音(大きな音)を検出すると回避行動をとる(今回はモータ停止)。回避行動についてはリアルタイム性が求められる。

タスク設計

 タスク設計の前に簡単に「スケジューリング理論」について説明します。一般的に知られているスケジューリング理論とは、以下のとおりです。

表3:スケジューリング理論
名前 内容
レートモノトニック(RM) 短い周期のタスクから高優先度
静的な優先度割り付け
タスク間でリソースを共有しない
デッドラインが周期の終わり
アーリストデッドラインモノトニック(EDF) デッドラインの近いタスクから高優先度
動的な優先度割り付け
CPUを効率よく使用できるが、高負荷の時の振る舞いが予測できない
デッドラインモノトニック(DM) 基本的にはレートモノトニックと同じ。デッドラインは周期より短い

 表3の中で、レートモノトニックは静的な優先度割り付けおよびCPU高負荷時の振る舞いが予測できるという理由で、組込み分野でよく使われています。今回は、このレートモノトニックに基づいてタスク設計をしてみましょう。

 レートモノトニックに基づき、以下のようにタスクを準備することにします。危険を回避するタスクを高優先度、高周期にしバンパタッチという比較的リアルタイム性の緩いタスクを低優先度、低周期に設定しています。このような周期起動による処理の実行が組込み制御の基本です。

表4:使用するタスクの内容
タスク名 用途 起動周期 優先順位
PollingSoundTask 周期的に起動する危険音を検出するタスク。危険音を検出するとモータを停止する。 100msec
PollingBumbper 周期的に起動するバンパの状態を監視するタスク。バンパが押されたらモータを回す。 500msec
図2:処理のシーケンス
図2:処理のシーケンス

 また、RTOS上ではタスクは優先順位に従ってOSにより制御され、実行中のタスクは常に1つとなります。この「優先順位」「1タスク実行」の考えのもと、処理がタスクに割り付けられるため、デッドラインを考慮した設計が容易になります。この設計の容易さが、RTOSを使用するメリットの1つです。

OILファイル

 ユーザが使用するタスクやイベントのOSタスクをOILファイルに定義します。ここで定義してるOSオブジェクトは、Cソースで宣言し使用します。

#include "implementation.oil"

CPU ATMEL_AT91SAM7S256
{
    OS LEJOS_OSEK
    {
        STATUS = EXTENDED;
        STARTUPHOOK = FALSE;
        ERRORHOOK = FALSE;
        SHUTDOWNHOOK = FALSE;
        PRETASKHOOK = FALSE;
        POSTTASKHOOK = FALSE;
        USEGETSERVICEID = FALSE;
        USEPARAMETERACCESS = FALSE;
        USERESSCHEDULER = FALSE;
      };

      APPMODE appmode1{}; 

      RESOURCE lcd
      {
          RESOURCEPROPERTY = STANDARD;
      };

    /**
     * 音センサをポーリングするタスクの定義
     */
      TASK PollingSoundTask
      {
        AUTOSTART = FALSE;
        SCHEDULE = FULL;
        PRIORITY = 5;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
        RESOURCE = lcd;
      };

    /**
     * タッチセンサをポーリングするタスクの定義
     */
      TASK PollingBumperTask
      {
        AUTOSTART = FALSE;
        PRIORITY = 2;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
        RESOURCE = lcd;
      };

      COUNTER SysTimerCnt
      {
        MINCYCLE = 1;
        MAXALLOWEDVALUE = 10000;
        TICKSPERBASE = 1;
      };

    /**
     * 音センサを監視するタスクを起床するアラーム
     */
      ALARM cyclic_alarm1
      {
        COUNTER = SysTimerCnt;
        ACTION = ACTIVATETASK
        {
              TASK = PollingSoundTask;
        };
        AUTOSTART = TRUE
        {
              ALARMTIME = 1000;
              CYCLETIME = 100;
              APPMODE = appmode1;
        };
      };

    /**
     * タッチセンサを監視するタスクを起床するアラーム
     */
      ALARM cyclic_alarm2
      {
        COUNTER = SysTimerCnt;
        ACTION = ACTIVATETASK
        {
              TASK = PollingBumperTask;
        };
        AUTOSTART = TRUE
        {
              ALARMTIME = 1000;
              CYCLETIME = 500;
              APPMODE = appmode1;
        };
      };
};
コーディング

 OILで定義したOSオブジェクトを使用してコーディングします。以下は、OSオブジェクトの宣言部分とタスク部分のみの抜粋です。

/** OILで定義したOSオブジェクトを宣言します */
DeclareCounter(SysTimerCnt);
DeclareResource(lcd);
DeclareTask(PollingBumperTask);
DeclareTask(PollingSoundTask);
.
.
. 
/**
 * PollingSoundTask
 *
 * サウンドセンサをポーリングします.
 * 優先度:高
 *
 * 100msecで起動してサウンドセンサの状態をチェックします。
 */
TASK(PollingSoundTask)
{

    /** 危険音を検出したらモータを停止します */
    if (ecrobot_get_sound_sensor(NXT_PORT_S2) < DANGER_SOUND) {
        stopWheel();
    }

    /** タスクを終了します */
    TerminateTask();

}

/**
 * PollingBumperTask
 *
 * バンパが押されたらモータを回転します。
 * 優先度:低
 *
 * 500msecで起動してタッチセンサの状態をチェックします。
 *
 */
TASK(PollingBumperTask)
{
    /** バンパが押されたらモータを回転します */
    if ( TOUCHED == ecrobot_get_touch_sensor(NXT_PORT_S1) ) {
        startWheel();
    }

    /** タスクを終了します */
    TerminateTask();
}

次のページ
コラム:ビジネス向けソフトウェア開発と組込みソフトウェア開発の違い(開発編)

この記事は参考になりましたか?

[組込み開発入門] ロボットを作ろう連載記事一覧

もっと読む

この記事の著者

藤井 律行(フジイ ノリユキ)

(株)永和システムマネジメント所属。組込み・計測制御システム開発、Webアプリ開発を経て、現在は再び組込み開発に従事。元々はメカエンジニアで、かつてはコーディングより機械図面を引く方が速かった。チームマイナス6%会員。会社までの往復30Kmを愛車ビアンキ号で通勤する自転車人。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3703 2009/03/16 19:10

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー