レートモノトニック スケジューリング

 

NXTに限らずリアルタイム制御アプリケーションの開発中は様々な問題に直面します。特にある外部入力(例, センサ入力)に対して、想定される時間内に処理を完了しなければならない場合が多々あります。例えばライントレースロボットを開発する場合、ライントレース走行性能を競技レベルまで向上させようとすると、ライン検出および車体の操舵/駆動制御等を数msecの高速周期でおこなう必要が出てきます。処理が複雑になればなるほど実行時間が長くなるため、各処理を複数の実行タイミングに分散する必要も出てきます。
nxtOSEKでは、OSEK Alarm機能をベースとしたレートモノトニック スケジューラ を容易に構築することができます。レートモノトニック スケジューラは航空宇宙や自動車業界などの本物のリアルタイム制御アプリケーションにおいて、最も幅広く使用されているスケジューリング方法です。
nxtOSEKにおけるレートモノトニック スケジューリングを実現するためには、次の条件について満たす必要があります:

  • 周期タスクの最小起動周期は1msecでかつ、他の周期タスクの周期は最小周期タスクの周期の整数倍であること
  • 周期の短いタスクほど高いタスク優先順位が設定されていること(優先順位値が大きいほど、高いタスク優先度が与えられます)
  • 全ての周期タスクはOSEK Alarm Counter機能によって起動されること
  • 全ての周期タスクの起動タイミング位相のずれがないように、同じALARMTIME値が設定されていること
  • (タスク間の排他制御にはGetResource/ReleaseResource APIを使用すること)

rms.cファイルおよびrms.oilファイルには次の3つの周期起動タスクが定義されています。Task1とTask2ではサーボモータAとサーボモータBをそれぞれ独立に制御しています。もし、タッチセンサをONにすると2つのサーボモータは停止します。

  • Task1: 起動周期 = 1msec, タスク優先度 = 3, ALARMTIME = 1
  • Task2: 起動周期 = 500msec, タスク優先度 = 2, ALARMTIME = 1
  • TaskLCD: 起動周期 = 500msec , タスク優先度 = 1, ALARMTIME = 1

このサンプルプログラムの振る舞いを確認するためには次のハードウェア設定が必要になります:

  • ポートAおよびポートBにサーボモータを接続する
  • ポートS1にタッチセンサを接続する

samples\rms\rms.c

/* rms.c */
#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

/* OSEK declarations */
DeclareCounter(SysTimerCnt);
DeclareTask(Task1);
DeclareTask(Task2);
DeclareTask(TaskLCD);

/* nxtOSEK hooks */
void ecrobot_device_initialize(void)
{
  nxt_motor_set_speed(NXT_PORT_A, 0, 1);
  nxt_motor_set_speed(NXT_PORT_B, 0, 1);
}

void ecrobot_device_terminate(void)
{
  nxt_motor_set_speed(NXT_PORT_A, 0, 1);
  nxt_motor_set_speed(NXT_PORT_B, 0, 1);
}

/* nxtOSEK hook to be invoked from an ISR in category 2 */
void user_1ms_isr_type2(void)
{
  StatusType ercd;

  ercd = SignalCounter(SysTimerCnt); /* Increment OSEK Alarm Counter */
  if (ercd != E_OK)
  {
    ShutdownOS(ercd);
  }
}

/* Task1 executed every 1msec */
TASK(Task1)
{
  if (ecrobot_get_touch_sensor(NXT_PORT_S1))
  {
    nxt_motor_set_speed(NXT_PORT_A, 0, 1);
  }
  
else
  {

    nxt_motor_set_speed(NXT_PORT_A, 50, 1);
  }

  TerminateTask();
}

/* Task2 executed every 500msec */
TASK(Task2)
{
  if (ecrobot_get_touch_sensor(NXT_PORT_S1))
  {
    nxt_motor_set_speed(NXT_PORT_B, 0, 1);
  }
  
else
  {

    nxt_motor_set_speed(NXT_PORT_B, 50, 1);
  }

  TerminateTask();
}

/* TaskLCD executed every 500msec */
TASK(TaskLCD)
{
  ecrobot_status_monitor("RMS");

  TerminateTask();
}

samples\rms\rms.oil

#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;
  };

  /* Definition of application mode */
  APPMODE appmode1{};

  /* Definition of Task1 */
  TASK Task1
  {
    AUTOSTART = FALSE;
    PRIORITY = 3;
    ACTIVATION = 1;
    SCHEDULE = FULL;
    STACKSIZE = 512; /* Stack size */
  };

  /* Definition of Task2 */
  TASK Task2
  {
    AUTOSTART = FALSE;
    PRIORITY = 2;
    ACTIVATION = 1;
    SCHEDULE = FULL;
    STACKSIZE = 512; /* Stack size */
  };

  /* Definition of TaskLCD */
  TASK TaskLCD
  {
    AUTOSTART = FALSE;
    PRIORITY = 1;
    ACTIVATION = 1;
    SCHEDULE = FULL;
    STACKSIZE = 512; /* Stack size */
  };

  /* Definition of OSEK Alarm Counter */
  COUNTER SysTimerCnt
  {
    MINCYCLE = 1;
    MAXALLOWEDVALUE = 10000;
    TICKSPERBASE = 1; /* One tick is equal to 1msec */
  };

  /* Definition of Task1 execution timing */
  ALARM cyclic_alarm1
  {
    COUNTER = SysTimerCnt;
    ACTION = ACTIVATETASK
    {
      TASK = Task1;
    };
    AUTOSTART = TRUE
    {
      ALARMTIME = 1;
      CYCLETIME = 1; /* Task1 is executed every 1msec */
      APPMODE = appmode1;
    };
  };

  /* Definition of Task2 execution timing */
  ALARM cyclic_alarm2
  {
    COUNTER = SysTimerCnt;
    ACTION = ACTIVATETASK
    {
      TASK = Task2;
    };
    AUTOSTART = TRUE
    {
      ALARMTIME = 1;
      CYCLETIME = 500; /* Task2 is executed every 500msec */
      APPMODE = appmode1;
    };
  };

  /* Definition of TaskLCD execution timing */
  ALARM cyclic_alarmLCD
  {
    COUNTER = SysTimerCnt;
    ACTION = ACTIVATETASK
    {
      TASK = TaskLCD;
    };
    AUTOSTART = TRUE
    {
      ALARMTIME = 1;
      CYCLETIME = 500; /* TaskLCD is executed every 500msec */
      APPMODE = appmode1;
    };
  };
};

 

 

 

Back to Samples