知能ロボットコンテスト’99 ロボット製作資料No1 – R.U.R.
知能ロボットコンテスト’99 ロボット製作資料
作成 de JM4LFA 99.5.27
FOR628.C または T98.C 等のソースファイルで使用されている関数について簡単な解説
関数解説
arm() | アーム制御関数です。引数は、ARM_UP,ARM_DOWN,OPEN,CLOSE,STOP_ARM
の5つです。アームはハードウエアでリミットスイッチを用いた、ドライブ回路なので、ソフトウエアで、地面に接地したかどうか判断できませんので、十分に時間を取って待ちましょう。 |
wait() | unsigned int型を用いたソフトウエアループによるウエイト関数です。よって引数は、正の数で、最大65535です。 |
pokeV25reg() | 割り込み関数をつかうことを許可するときに使用します。ロボットスタート時に呼び出します。 |
ppi_init() | 8255を初期化します。プログラムの最初あたりにこの関数を呼び出すだけでOKです。引数はなし。 |
timer_init() | これは割り込みのサンプリングレートを変えたいとき意外は、しらなくていい関数です。スタート時あたりに引数なしで呼び出すだけでOKです。なにも変更しなければ、1秒間に20回、sampling()関数が呼び出され、位置計算等が行われます。 |
sampling() | ソフトウエア割り込みによって、1秒間に20回呼び出される関数です。標準の機能は、ロータリーエンコーダーを読みとり、その値を用いて、iti()関数により、現在位置を計算させます。位置計算された結果は、グローバル変数にセットされます。そこでプログラマは、その値をもとに、目標速度を表す、グローバル変数に目標速度(1/20秒ごとのロータリーエンコーダーのカウント値)をセットさせる関数を自作し、このsampling()関数から呼び出してください。その後、speed_control()関数によって、目標速度に追従するPI制御計算され、モーターへの操作量がグローバル変数にセットされ、motor()関数によって、モータがPWM速度制御され、ロボットが動きます。詳しい説明は、後述してます。 |
speed_control() | 引数は、そのときのロータリーエンコーダーのカウント値です。PI速度制御によりモーター操作量を目標速度(iTargetVelo_r、iTargetVelo_l)をもとに計算し、グローバル変数 iMotorOut_r、iMotorOut_lにセットします。とくにこの関数については、変更の必要はないと思います。 |
motor() | 引数はint型で、-416から+416までです。マイナスならモータは逆回転します。PWM速度制御です。第1引数が左モータ、第2が右です。通常は、PI制御計算された操作量をしようするので、motor(iMotorOut_l,iMotorOut_r);のままでOKです。 |
iti() | 現在位置計算関数です。引数は、ロータリーエンコーダーカウント値です。計算結果は、グローバル変数 x,y,arg に代入されます。座標系は、スタート時のロボット位置のロータリーエンコーダー軸の中心点が(0,0)で、角度は、最初が0ラジアンです。詳しいことは現在不明。後ほど報告します。 |
なにをかんがえればいいか?
ロボットは20分の1秒ごとの現在位置、向き(多少の誤差あり)がわかっているので、それをもとに左右のモーターの目標速度を設定するだけです。(この場合、その変数に数値を代入するだけで、勝手にPI制御関数が追従してくれる)
具体的には、ある目標地点にたいして、どのようにして近づくか?です。
たとえば、目標地点と現在の位置がずれていて、まず、ロボットの角度を修正して、あとは、直進とか。(この場合、近付くにつれ、角度の誤差が拡大されるし、近付けば近付くほど、角度の修正は難しくなります。)
参考までに昨年の方法をかいておくと、ロボットがほぼ直線で数メートルすすめることを仮定して、目標地点との距離を√(x*x + y*y)でなくて、この場合なら y として、(x方向にある範囲からはみ出なければ、)、yの値を係数倍したものを左右のモーターの目標速度として、与えています。制御の言葉で言うと比例制御、P制御というのかな? で、横方向は無視できないほどはみでちゃった場合は、はみでてすぐなら、1cmくらいしかはみでてないので、はみでたほうのモーターを多めにまわすとか。(ここは、どうしてたか覚えてないです)
がんばれーーーー!! (^ ^)/
知能ロボットコンテスト98ロボット「つみたて君」のプログラムの
フローチャートみたいな。
まずは、main()関数から追っかけていくとしよう。(割り込み起動関数は後回し)
- 各種関数初期化
- アームを持ち上げて。(あげるまでの間しばらく待つ)
- 後ろのドアを閉じて。(しまるまでちょっとまつ)
- PI制御の係数を初期化
- ホストコンピュータの画面を改行しまくって、きれいにして、Start OK と表示
- コンピュータBoxの蓋にある、ロータリースイッチが1になるまで待つ(0以外になるとロボットスタート)
- ロボットが完全に静止するまで待つ(人間によって動かされている間はとまっとけ ということ)
- 割り込みを許可する
- 無限ループ(この後にも、かいてあるけど、たぶん実行されることはない)
main()関数で割り込みを許可したけど、どうなるの?
うーん、それはね、main()で初期化した関数で timer_init() って関数があるでしょ。それが、20分の1(変更可能だよ)秒ごとに、 sampling() って関数を呼び出す仕組みになってるんだ。
じゃあ、以下に sampling() 関数の流れ図(?)を示そう。4~8は重要なので、表示を変えてあります。
- ロータリーエンコーダーの値を保存する変数を宣言
- ロータリーエンコーダーのカウント値を読みとって、変数に代入
- そのカウント値をもとに、現在位置を計算する。 iti() 関数がそれ。現在位置は、グローバル変数に保存されてるよん。
4. | 行動命令実行可能状態 process==0 なら、(ちなみに命令実行中ならprocess==1だ) 次のロボット行動命令を読み込む(administ()関数) 以下の5から8は読み込んだ命令を実行、処理する |
5. | その場回転しろ という命令だったならば 回転する |
6. | 「止まれ」命令なら ロボットが完全に静止するまで待つ(正確には、瞬間速度が、0であればOKってこと) |
7. | 「アームを動かせ」命令実行中なら、 time_count変数が200になるまで アームを動かす |
8. | 上記の3つの条件分岐(5,6,7)のどれにも当てはまらなかった場合 ロボットの位置が目標位置となるよう、position_control() 関数を呼び出す。END_PHASEとなったら(目標位置に到達したら) process変数を命令受け入れ可能状態の0を代入、phaseを1つすすめる。 |
- 9.PI制御スピードコントロール関数 speed_control() を呼び出し、目標速度(グローバル変数)と、引数の現在の速度(エンコーダー読みとり値)から、モーター入力値を求める。
- 10.計算された入力値をもとに、モータを駆動する。
- 11.割り込み関数終了関数 fint() を呼び出して、割り込み関数を終了させる。
肝心の位置(x、y)の制御は?
寝る。またこんど。できれば、つくりなおしてほしいし。
回転の制御は? rotation_control() その場回転だ。
- 変数宣言だ。
- 目標角度が180度方向か、それ以外で分岐
目標角度が180度の場合
(特別扱いが必要なため)目標角度を代入する。
目標角度と現在の角度の差を取る(偏差)
それ以外の場合 目標角度を代入
偏差を取る
3.偏差が許容値以内なら、ロボットを停止させ、回転制御関数を抜ける。(戻り値は END_PHASE)
4.偏差の50倍を操作量とする。
5.回転最高速を越えていたら、設定最高速にする。
6.操作量を左右のモーターの目標速度に代入。
アーム操作関数 arm() は?
アームをそのときの引数に従って、動かす信号をだすだけ。ハードウエアでリミットスイッチをもっているので、アームが停止位置にきたら、勝手に、止まってくれます。 ただ、それだけ。
Do not copy without permission.