秒数をカウントするだけの関数を作成せよ.そして,mainの中でそれを呼び出してセンサーラボ起動直後に3秒間何もしないまま待たせてからモータ回転を始めるようにmainを変更せよ.
msec | n | タイマn回分の時間(待ち時間) |
---|---|---|
1 | 2 | 10 |
2 | 4 | 20 |
3 | 6 | 30 |
4 | 8 | 40 |
5 | 10 | 50 |
... | ... | ... |
n | 2*n | n*10 |
int wait(int millisec10) { for(;;){ if(タイマフラグ(ir_ta0ic)が立った) { タイマフラグを戻す カウントを増やす if(カウントとmillisec10の関係式を使って,指定された時間が立ったかどうか判定) break; //時間が立っていたらfor文を脱出 } } return 0; //for文を脱出してここまできたら,そのまま終了 }
前回のmainに残っているfor文の部分を新しい関数として独立させ,次に説明するように書き換えよ.新しい関数は,次の関数プロトタイプに従うものとする.これは,返値がint型で,int型の引数を2持つ関数であることを示している.
int driveMotor(int target_R, int target_L);
この関数は,引数に指定されたふたつの値を,それぞれ右と左のモータの目的速度として参照することにさせる.そして5ミリ秒に一回ずつ現在のモータの回転速度を変更して,その目的速度に合致するまで増やしたり減らしたりさせるものとする.また,現在のモータの回転速度を記憶するために次の2つの大域変数を用意しておくこと.大域変数にする理由は,他の関数(例えばmain関数)からも参照することがあるためである.
int dutydata_R; //右モータの現在の回転速度(を記憶しておくための変数) int dutydata_L; //左モータの現在の回転速度(を記憶しておくための変数)
もっと具体的に説明すれば,右モータの回転速度を現在のdutydata_Rを5ミリ秒に1回ずつ+1だけ増やして(あるいは減らして)target_Rになるまで繰り返し,そして左モータの回転速度は,同様にdutydata_Lをtarget_Lになるまで徐々に変化させる.
int driveMotor(int target_R, int target_L) { /* 最初に引数が適切な値かどうかチェックすること. */ if(右の目標速度(target_R)が最高速度よりも小さい) //(注意: 小さい方が速いので) 右目標速度を最高速度に書き換え else if(右の目標速度(target_R)が最低速度よりも大きい) 右目標速度を最低速度に書き換え ※左も同様に処理 for(;;){ if(タイマフラグが立った(※wait()と同様)) { タイマフラグを戻す(※wait()と同様) if(現在の右モータ速度(dutydata_R)が右の目標速度(target_R)より小さい) dutydata_Rを+1するか-1するか; else if(現在の右モータ速度(dutydata_R)が右の目標速度(target_R)より大きい) dutydata_Rを+1するか-1するか; if(現在の左モータ速度(dutydata_L)が左の目標速度(target_L)より小さい) dutydata_Lを+1するか-1するか; else if(現在の左モータ速度(dutydata_L)が左の目標速度(target_L)より大きい) dutydata_Lを+1するか-1するか; ※dutydataとtargetが同じ値の場合には何もさせないことに注意せよ. ※この行でモータ速度とサイクルタイムから計算した値でモータ速度のレジスタを設定変更すること. (モータの速度を設定するためのレジスタは何か,課題5を思い出せ) if(両方のモータ速度が目標と一致した) break; //for文を脱出 } } return 0; }
作成したwait()とdriveMotor()を使用する次のテスト用関数を作成し,mainから呼び出して動作確認を行う.
/* 関数プロトタイプのリスト */ void stop(void); void go(void); /* メインプログラム */ void main(void) { initTimer(); initMotor(); tabsr = 0x0d; //タイマA0と左右のモータの3つをスタート for(;;){//無限に繰り返し stop(); //ストップ go(); //加速 wait(100); //そのまま指定時間走りつづける } } /* 関数stopの本体 */ void stop(void){ driveMotor(LOWERLIMIT,LOWERLIMIT); 右,左モータとも最低速(停止)にする } /* 関数goの本体 */ void go(void){ driveMotor(UPPERLIMIT,UPPERLIMIT); 右,左モータとも最高速にする } ※この他に,課題のwait()とdriveMotor()の本体など,その他の必要な部分を自分で追加すること
このプログラムが動作すれば,「かえる飛び」のように停止と最高速の状態を無限に繰り返すような動作をする.
上記のdriveMotorでは,右と左の目標速度を異ならせれば,その比に応じてカーブすることになる.
しかし,右と左の目標速度が異なったり,右と左の初期速度が異なったりすると,右と左のモータがそれぞれの目標速度に到達するまでの時間がずれてしまう.その理由は,速度調整に必ず一段階ずつ速度を増減するため,目標速度が違えば目標速度までに必要な段階数が異なるためである.
このように,左右の到達時間が異なると,初期速度の状態から目標速度に到達するまでの状態の間に,SensorLABOの車体は時間とともに回転半径を変化させながら微妙に回転してしまい,制御が難しくなる.どのような目標速度を与えても,左右の目標速度に到達するまでの時間を一致させれば,すなわち,常に一定の回転半径で安定して回転するようにすれば,制御が楽になる.
そこで,次のように目標速度に応じて速度調整の増分値を適切に調整し必ず100段階で速度を変更する(緑部分)driveMotor2を作成し,driveMotorと置き換えてみよ.
int driveMotor2(int target_R, int target_L) { int i; int dutydata_R100,dutydata_L100; /* 最初に引数が適切な値かどうかチェックすること. */ if(右の目標速度(target_R)が最高速度よりも小さい) //(注意: 小さい方が速いので) 右目標速度を最高速度に書き換え else if(右の目標速度(target_R)が最低速度よりも大きい) 右目標速度を最低速度に書き換え ※左も同様に処理 右の速度調整幅=右の目標速度-右の現在速度 左の速度調整幅=左の目標速度-左の現在速度 dutydata_R100 = dutydata_R*100; //dutydataの100倍の値 dutydata_L100 = dutydata_L*100; for(i=0;i<100;i++){ //いかなる速度でも5m秒×100段階=0.5秒で調整するようにする if(タイマフラグが立った(※wait()と同様)) { タイマフラグを戻す(※wait()と同様) dutydata_R100+=右の速度調整幅; //相手が100倍なので,1/100分だけ調整したことになる dutydata_L100+=左の速度調整幅; //※100倍スケールで計算すれば,浮動小数点演算をしなくて済む(M16Cでは非常に遅い) dutydata_R = dutydata_R100/100; dutydata_L = dutydata_L100/100; // 100倍スケールを100で割って元に戻す ※この行でモータ速度とサイクルタイムから計算した値でモータ速度のレジスタを設定変更すること. } } //端数が出たときのため,最終的には強引に目標値に一致させておく. dutydata_R = target_R; dutydata_L = target_L; ※この行でモータ速度とサイクルタイムから計算した値でモータ速度のレジスタを設定変更すること. return 0; }
早めに終わった人は,次の課題08に挑戦してみよ.