OIL
OILとは、OSEK Implementation Languageの略で、オイルと発音します。これを使って、使用するOSオブジェクトの設定ファイル(OILファイル)を作成します。
このファイルにはユーザが利用したいOSオブジェクトを定義してあり、システムジェネレータ(SG)のインプットになります。SGは、ファイルを解析後ユーザプログラムに依存する部分のOSコードを生成します。カーネルは、この生成されたコードから自分が制御すべきOSオブジェクトを知ることができるようになります。
表2に、OILで定義する代表的なOSオブジェクトを示します。
| 定義するオブジェクト | 内容 |
|---|---|
| CPU | OSEK OSの制御のもとアプリケーションを実行するCPU |
| OS | OSEK OSのこと |
| APPMODE | アプリケーションモード定義テストモードなど起動モードを変えたいときに使用する |
| RESOURCE | タスクで使用されるリソース |
| TASK | OSによって取り扱われるタスク |
| COUNTER | アラームから使用されるOSオブジェクト。アラームは指定時間の満了の検出にカウンタを利用する。ハードウエアカウンタとソフトウエアカウンタがある |
| EVENT | タスクの同期をとるためのOSオブジェクト |
| ALARM | 指定周期毎にイベントを起動したりイベントをファイアしたりするOSオブジェクト |
作成するアプリ
仕様
バンパを押すことで前進を始める。危険音(大きな音)を検出すると回避行動をとる(今回はモータ停止)。回避行動についてはリアルタイム性が求められる。
タスク設計
タスク設計の前に簡単に「スケジューリング理論」について説明します。一般的に知られているスケジューリング理論とは、以下のとおりです。
| 名前 | 内容 |
|---|---|
| レートモノトニック(RM) | 短い周期のタスクから高優先度 |
| 静的な優先度割り付け | |
| タスク間でリソースを共有しない | |
| デッドラインが周期の終わり | |
| アーリストデッドラインモノトニック(EDF) | デッドラインの近いタスクから高優先度 |
| 動的な優先度割り付け | |
| CPUを効率よく使用できるが、高負荷の時の振る舞いが予測できない | |
| デッドラインモノトニック(DM) | 基本的にはレートモノトニックと同じ。デッドラインは周期より短い |
表3の中で、レートモノトニックは静的な優先度割り付けおよびCPU高負荷時の振る舞いが予測できるという理由で、組込み分野でよく使われています。今回は、このレートモノトニックに基づいてタスク設計をしてみましょう。
レートモノトニックに基づき、以下のようにタスクを準備することにします。危険を回避するタスクを高優先度、高周期にしバンパタッチという比較的リアルタイム性の緩いタスクを低優先度、低周期に設定しています。このような周期起動による処理の実行が組込み制御の基本です。
| タスク名 | 用途 | 起動周期 | 優先順位 |
|---|---|---|---|
| PollingSoundTask | 周期的に起動する危険音を検出するタスク。危険音を検出するとモータを停止する。 | 100msec | 高 |
| PollingBumbper | 周期的に起動するバンパの状態を監視するタスク。バンパが押されたらモータを回す。 | 500msec | 低 |
また、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();
}

