タスクを並行処理してロボットを制御する
倒立しながらライントレースをどうやって実現する?
さて、P動作による2輪倒立振子ロボットは、滑らかにライントレースをするようになりました。次は、倒立しながらライントレースをするというしくみをどうやって実現しているのか考えていきましょう。
前回の連載、マインドストーム活用のエンジニア教育「第2回 センサーを使ったロボットの自律制御」でも紹介しましたが、今回のnxtJSP(μITRON)環境では、仕事をタスクと呼ばれる小さな実行単位にまとめ、それぞれのタスクに優先度をつけて、並行に処理をするしくみでした。並列に処理をすることで、複数の処理を同時に実行できるようになっています。
タスクについて、もう一度簡単な実験をしてみましょう。
音を鳴らし続けるプログラム
ここでは実験として、一つのタスクで音を鳴らし続けるプログラムを作成しました。
※解凍したフォルダ内にあるSampleThinkIT_01というフォルダを、先ほどと同様に、Runnerフォルダの配下にコピーしてください。
sample01.c(40行目~)
sample01.cfg(5行目~)
タスクの優先度は7で、音を鳴らし続けます。これは、タスクが一つしかなく、うまく動くと思います。
液晶ディスプレーに表示しながら音を鳴らす。
音を鳴らし続けるプログラムの、同じタスク内に、タッチセンサーの状態を表示するロジックを追加しました。
※解凍したフォルダ内にあるSampleThinkIT_02というフォルダを、先ほどと同様に、Runnerフォルダの配下にコピーしてください。
すると音は鳴り続けますが、タッチセンサーを押してもすぐには表示が変わりません。反応が非常に悪いです。それもそのはず、音を鳴らすタスクは、1音鳴らした後に、100ミリ秒ずつ待っています。8個の音を鳴らし終えた後に、ようやくタッチセンサーの値を液晶ディスプレーに表示しています。
このままではタッチセンサーの値を表示する処理は800ミリ秒に一度しか実行されません。これはタスクの周期を短くしても変わりません。
sample02.c(40行目~)
このように、異なる目的で、スピードが異なる処理を一つのタスクにまとめてしまうと問題が発生することがあるということがわかりました。このような場合には、タスクを分けて、並列に処理をしなければなりません。
では、タスクを分けて実行してみましょう。
※解凍したフォルダ内にあるSampleThinkIT_03というフォルダを、先ほどと同様に、Runnerフォルダの配下にコピーしてください。
音も鳴り響いています。タッチセンサーの反応も良くなっています。
主な変更点は次の通りです。
1. Sample03.cfgファイルに、タッチセンサーの値を表示するタスクと、そのタスクを40ミリ秒周期に起動する設定を追加しました。
sample03.cfg(8行目・9行目)
2. Sample03.cファイルに、次のようなコードを追加しました。
sample03.c(72行目~)
このように、目的の違う処理は、別のタスクに切り分けて、実行します。
ロボットの処理をタスクに分けよう
では、先ほど作成した2輪倒立振子ロボットのプログラムを見てみましょう。
タスクの設定が書かれているコンフィグファイル(Runner.cfg)を見ると、次のように記述しています。
Runner.cfg
タスクが3つあることがわかります。それぞれの優先度を見ると、CRE_TSK文の「{」と「}」で囲まれた部分の後ろから3番目のパラメータがタスクの優先度です。それぞれの優先度を見ると、TSK_Balanceが一番高い優先度に設定されており、次にTSK_Action、そしてTSK_Switchという順番です。
目的別に見ると、TSK_Balanceは、バランスすることを目的にしています。このタスクは非常に重要です、4ミリ秒間隔でくり返し実行されます。1回の処理が4ミリ秒を超えるとパタンと倒れてしまいます。
TSK_Switchは、スタートスイッチの状態を40ミリ秒間隔で調べ続けて、スタートスイッチが押されるごとに、システムの状態を変更します。
TSK_Actionは、現在の状態を観察するという仕事と、現在の状態に対応した処理を実行するという仕事を担っています。具体的には、40ミリ秒間隔で現在の状態を調べて、走行中状態であったらならば、ライントレース処理をします。このライントレース処理も40ミリ秒間隔で実行されています。
このままの構造だと、例えば、ライントレースの処理速度を上げたいときに、現在の状態を調べるという処理も不必要に処理速度が上がってしまいます。
そこで、ライントレースする部分だけを別のタスクに切り出しましょう。
主な変更点は次の通りです。
1. Runner.cfgファイルに、ライントレースをするタスクと、そのタスクを20ミリ秒周期に起動する設定を追加しました。
Runner.cfg
2. Tracer.cファイルに、次のようなコードを追加しました。
Tracer.c(71行目~)
ただし、走行中状態のときのみライントレースをして、停止中状態のときはライントレースをさせないため、ライントレースをするタスクに何らかの指示を出す必要があります。現段階では、走行中状態のときに、変数にTRUEを書き込みみ、その値を参照することで対応します(Tracer.cの73行目)。
※解凍したフォルダ内にある、RunnerThinkIT_v3_Pというフォルダを、先ほどと同様に、Runnerというフォルダの配下にコピーしてください。