C-Style の実行時間について
次のようなプログラムで1秒間に各コマンドが何回実行できるか調べる。
6行目に調査したいコマンドを入れる。
- LCDのないTJ3Bで変数の内容を確認する方法は以前にまとめた。
手元のTJ3Bでの結果は次の通り。INPUTの参照は変数の参照と変わらない回数が実行できた。
だが、PINGポートの参照は実行回数が大幅に少なく、ぶっちぎりに時間がかかっていることが確認できる。
- 74,323回 X=X+10
- 74,323回 X=CN1
- 46,123回 MT(L:50 R:50)
- 201回 MT(6ch 0,0,0,0,0,0)
- 50回 X=CN10:PING
このことをロボットに活用することを考える。
CN10に超音波センサーを接続し、
- 20cm 以上離れたら緑LEDをON
- 10cm 以上離れたら赤1LEDをON、
というプログラムを上の6行に入れて、1秒間の処理回数を調べる。処理回数が多いほど細かい制御ができる。
2つのIF文でそれぞれ距離を判断する場合、1秒間に25回の処理ができた。
IF文を入れ子にし、10cm以上離れている場合のみ20cmの判断をする場合は、距離に応じて1秒間の処理回数が変わった。
10cm未満ならば1秒間に50回、10cm以上なら25回の処理ができた。
距離が変動する場合は、25~50回の間になった。
PINGポートの参照は、変数の参照比べて数桁レベルで遅いことが上でわかっているので、処理回数をかせぐには、PINGポートの参照を減らすことが大切になる。
PINGポートを距離を変数に代入しておけば、2つのIF文がある場合でも1秒間に50回の処理ができた。
最初の例と比べると処理結果は同じにもかかわらず、処理回数が2倍(1回あたりの処理時間が半分)になっている。
当然、変数を使いかつIF文を入れ子にすれば、さらに高速化されるが、PINGポートの参照と比べれは他の処理は十分に速いので、入れ子にしてプログラムの可読性を落とすよりは、入れ子はなるべく使わず、プログラムの見やすさを保つことも大切だと思う。
C-Styleで割り込み(その3)
次のような無条件ループでプログラムする場合、ループ内で時間のかかる処理があると、センサ値を読むタイミングによっては、センサ値の変化に気づかない場合がある。
内部で50ミリ秒の時間がかかる処理があるとセンサ値を読むタイミングは50ミリ秒ごとになる。
センサ値を読んだ後の10~30ミリ秒でセンサ値が変化終了すると、次のセンサ値を見たときには変化が読み取れない。
そこで、時間のかかる処理とは別に、割り込み内でセンサ値の変化をチェックすることで読み飛ばしを防ぐ。
センサ値が大きくなる変化を読み取る場合は、次のような感じでセンサ値の最大値(グラフでは点線)を保存しておけば読み飛ばしを防げる。
- メインプログラム側でセンサ保存値をリセット
- 割り込み内でセンサ値をチェックし、センサ保存値より値が大きければ、センサ保存値を更新
- メインプログラム側でセンサ保存値を使って処理
- (以下繰り返し)
自走するロボットが秒速1mで進む場合、50ミリ秒で5cm進む。
- 秒速1mとは
- 1秒で1m (1000ミリ秒で1000mm)
- 0.1秒で10cm (100ミリ秒で100mm)
- 0.01秒で1cm (10ミリ秒で10mm)
処理に時間のかかる超音波センサなどを使う場合、その処理中にセンサ値の変化が終わり、変化を読み飛ばすことは十分考えられる。
C-Styleで割り込み(その2)
割り込みをもう少しテストしてみる。
超音波センサ(PING)は超音波を使い距離を測る。
超音波も音なので、音速を超えた処理はできず、一般的に超音波センサは遅い。
ja.wikipedia.org
センサから出た超音波が1m先の何かに反射して戻ってくる場合、往復で2m。
音速を340m/sとしたとき、2mの往復にかかる時間は約0.0059秒=5.9ミリ秒。
ja.wikipedia.org
C-StyleでPINGを使う場合にかかる時間と割り込み処理について、次のプログラムで確認する。
メインプログラムでは以下を行う。
- 変数A、Bの初期化
- タイマー1を使い、1秒間のループ
- ループ内で
- PING計測し変数Cに代入、
- 計測回数を変数Bでカウント
- 1秒のループ後に、変数A、B、Cを表示
- 変数Cは1秒間のループ中の最後に計測したPINGの値となる
割り込みで処理されるサププログラムでは
- サブプログラム実行回数を変数Aでカウント
結果は次の通り。今回PINGは未接続だったため、変数Cは0となった。
PING処理は割り込みに比べると相当遅い事がわかる。
C-Styleで割り込み
C-Styleで割り込みができるようになった。
ja.wikipedia.org
使い方は新しいマニュアル「C-Style 操作編」に追記されている。
割り込み処理中に実行できないこととして「モータ、PING、サーボモータ、I2C 等の制御」が挙げられているが、割り込みタイミング等の記載はないので調べてみる。
サンプルプログラムは次の通り。
メインプログラムでは以下を行う。
- 変数Aの初期化
- 無条件ループ内での赤1LEDの点滅
- タイマー1を使った1秒の待機
- 変数Aの表示(C-Codeブロックで「printf("%ld\r\n", gV[VAR_A]);」)
割り込みで処理されるサププログラムでは
- 赤3LEDの点灯
- 変数Aの加算。サブプログラム実行ごとに1づつ増える。
- タイマー1を使い、0.5秒ごとに赤2LEDの点滅
このプログラムで以下が確認できる。
- 赤LED3がONになるタイミングが、割り込み処理の初回実行タイミング
- 割り込み処理とメインプログラムで変数、タイマーがが共有できるか
- 変数Aを表示することで、1秒間に実行される割り込み処理の回数
変数Aを確認するにはセンサーモニタを使う。
手順は次の通り。
センサモニターのタイトル付近「センサモニタ & 出力チェック」をダブルクリック。
センサモニターのウィンドウが拡大したら、モニタ開始。
モニタ開始すると、各CNの値が表示されるので、TJ3BをSTARTさせる。
変数Aが表示され始める。
ロボット作りには欠かせない機能だと思う。