速率单调调度

在NXT上开发一个高速实时控制应用程序时,你可能会遇到一些在有限时间内响 应外部刺激的程序设计问题。(比如,如果你想要设计一个实速线跟踪机器人,你需要考虑很多问题,特别是对线方向的实时控制,机器人位置的控制...)。

nxtOSEK提供基于速率单调调度的OSEK Alarm, 从而完成在实时多速率/多任务环境下的执行NXT应用程序。

这项技术与工业实时控制系统基本一致,特别是自动系统。

以下是一些使用nxtOSEK设计速率单调调度的关键点:

  • 最短任务执行周期为1msec,所有任务执行周期为1msec的整数倍
  • 较短周期/时限的任务被赋予更高的优先级(数值越大优先级越高)
  • 所有周期性任务OSEK Alarm Counter执行
  • 所有周期性任务有相同的ALARMTIME
  • (共有的全局资源由GetResource和ReleaseResource保护)

在rms.c和rms.oil中定义了三个周期性执行任务并且这些任务有以下特性。Task1和Task2分别控制伺服电机A和B,并且当触觉传感器被触摸,电机就会停止。

  • Task1: 周期 = 1msec, 优先级 = 3,ALARMTIME = 1
  • Task2: 周期 = 500msec, 优先级 = 2,ALARMTIME = 1
  • TaskLCD: 周期 = 500msec , 优先级 =1, ALARMTIME = 1

为了在NXT上测试这个速率单调调度示例,你必需要有以下NXT设备:

  • 两个伺服电机分别接在端口A和端口B上
  • 一个接在端口S1上的触觉传感器

samples\rms\rms.c

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

/* OSEKdeclarations */
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;
    };
  };
};

 

 

 

返回示例程序