#nomenubar
#navi(NQC入門)

このページは作成中です

* task について [#u2b9500e]

タスクは、サブルーチンや関数と違って、そのタスクを開始した親のタスクとは独立して処理が実行されます (並列処理)。

複数のタスク(task)を扱うプログラムはすでにこれまでも登場してきました。
「[[NQC入門/6. サウンド機能を使う]]」では、曲を演奏するタスクをメインのタスクから起動して、曲を演奏しながらロボットを動かす、という例を紹介しました。
その例の場合には、main のタスクがモータ出力を制御、play_music というタスクが音声出力を制御、ということで個々のタスクが別の出力を制御していたので、出力を取り合いすることはありませんでした。
その例の場合には、main のタスクがモータ出力を制御、play_music というタスクが音声出力を制御、ということで個々のタスクが別の出力(モータやスピーカ)を制御していたので、出力を取り合いすることはありませんでした。

しかし、複数のタスクが同時に同一のモータやサウンド出力に命令を出した場合、いったいどちらのタスクの命令が優先されるのでしょうか?
実は、このことをあまり考えずにプログラムを作成した場合、ロボットは不可解な動きをします。つまり、あるタスクはモータAを正回転、別のタスクはモータAを逆回転するような状態になった場合、正確にモータAの動きを予測するのはとても難しいです。
したがって、思い通りにロボットを動かすためには、どのタスクの命令を優先すべきか、あらかじめプログラムに記述しておかなければなりません。以下では、そのための方法を説明します。

例として、ライントレースをしながら障害物に接触したら2秒間停止するロボットのプログラムを作成してみましょう。

以下の例では、センサ1とセンサ3に光センサ、センサ2にタッチセンサを取り付けて、2つの光センサが黒い線を跨いで走行するロボットを考えてみます。

* 優先順位の低いタスクを一旦止める [#r254fc8a]

この方法ではライントレースをするタスクを follow_line という名前で定義し、バンパーが反応した場合には main のタスクから follow_line を一旦停止させた上で、モータに Off の命令を出し、2秒経った後に再び follow_line を開始しています。

 #define EYE_L SENSOR_1
 #define EYE_R SENSOR_3
 #define BUMPER SENSOR_2
 #define THRESHOLD 50
 
 task main()
 {
 
     SetSensor(EYE_L,SENSOR_LIGHT);
     SetSensor(EYE_R,SENSOR_LIGHT);
     SetSensor(BUMPER,SENSOR_TOUCH);
 
     while( true ) {
         start follow_line;     // ライントレースを開始
 
         until (BUMPER == 1);   // バンパーが反応したら
         stop follow_line;      // 一旦 follow_line のタスクを停止
         Off(OUT_A+OUT_C); Wait(200);   // 2秒間停止 (この時、main のタスクのみがモータを制御)
     }
 }
 
 task follow_line()
 {
     while (true) {
         if ((EYE_L >= THRESHOLD) && (EYE_R >= THRESHOLD)) {
             OnFwd(OUT_A+OUT_C);
         } else if ((EYE_L >= THRESHOLD) && (EYE_R <= THRESHOLD)) {
             OnFwd(OUT_A); OnRev(OUT_C);
         } else if ((EYE_L <= THRESHOLD) && (EYE_R >= THRESHOLD)) {
             OnRev(OUT_A); OnFwd(OUT_C);
         } else {
             Off(OUT_A+OUT_C); Wait(100);
             OnFwd(OUT_A+OUT_C); Wait(20);
         }
         Wait(1);
     }
 }

この方法は、確かに簡単な方法なのですが、タスクの数が増えてくると、どのタスクがどのタスクを始動・停止しているのかややこしくなり、プログラムの構造自体が非常に複雑になってきます。

* タスクの優先順位を指定する [#td75a235]

ここではモータを制御する優先権をそれぞれのタスクに指定する方法を紹介します。


 #define EYE_L SENSOR_1
 #define EYE_R SENSOR_3
 #define BUMPER SENSOR_2
 #define THRESHOLD 50
 
 task main() {
 
     SetPriority(1);   // タスクの優先順位を0〜255で指定 (最大は0 最低は255)
 
     SetSensor(EYE_L,SENSOR_LIGHT);
     SetSensor(EYE_R,SENSOR_LIGHT);
     SetSensor(BUMPER,SENSOR_TOUCH);
 
     start follow_line;
 
     while( true ) {
         until (BUMPER == 1);
 
         // モータAとモータCのアクセス権を獲得する
 
         acquire(ACQUIRE_OUT_A+ACQUIRE_OUT_C){
             Off(OUT_A+OUT_C);
             Wait(200);
         }
     }
 }
 
 task follow_line(){
     SetPriority(2);   // タスクの優先順位を main より下げておく
 
     while (true) {
         acquire(ACQUIRE_OUT_A+ACQUIRE_OUT_C) {  //
 
             if ((EYE_L >= THRESHOLD) && (EYE_R >= THRESHOLD)) {
                 OnFwd(OUT_A+OUT_C);
             } else if ((EYE_L >= THRESHOLD) && (EYE_R <= THRESHOLD)) {
                 OnFwd(OUT_A); OnRev(OUT_C);
             } else if ((EYE_L <= THRESHOLD) && (EYE_R >= THRESHOLD)) {
                 OnRev(OUT_A); OnFwd(OUT_C);
             } else {
                 Off(OUT_A+OUT_C); Wait(100);
                 OnFwd(OUT_A+OUT_C); Wait(20);
             }
             Wait(1);
         }
     }
 }

#navi(NQC入門)

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS