バンバン制御

制御とは、

機械・化学反応電子回路などを目的の状態にするために適当な操作・調整をすること。「運転を自動的に―するシステム
                                                            by デジタル大辞林

 マイコンを用いて制御を実現する手法には、色々な手法があるが、今回は、実装が簡単なバンバン制御(Bang Bang Control)
と、ライントレースロボットへの応用について説明する。

 バンバン制御とは、下図の様に、モータの回転数が目標値を下回ったら、モータのスイッチをONにし、目標値を上回ったら出力をOFFにする制御方法である。(実際には、目標値に幅を持たせて目標値+αでモータOFF、目標値-αでモータONという形にすることもある。この±αをヒステリシスと呼ぶ)
 モータへの出力電流は、PWMでdutyを設定して与えてもよいが、一般にその必要はない。むしろ、IOポートを使ってOn/Offした方が、モータのトルクも最大限活用できるので、良い方法である。

○ヒステリシスなしのバンバン制御

                   

○ヒステリシスありのバンバン制御
                   


回転量の読み取り

 モータの回転数を読み取るには、一般的にロータリーエンコーダを用いることが多い。ロータリエンコーダとは、モータのロータ(もしくは減速ギヤ等)に直結して、その回転数(回転角)に応じたパルスを出力する装置である。ライントレースロボットのロータリエンコーダは、以下のような構造になっている。
          

 歯車の回転に伴い、歯車の山と谷によって、赤外LEDの赤外光が通過/遮蔽を繰り返すことになる。
          
 受光センサは、赤外光の有無によって、1または0(5V or 0V)を出力する。従って、センサはセンサ前を通過する歯車の山の有無を調べている事になる。
               
 このON/OFF信号をカウントしてやれば、歯車の回転角(つまり、タイヤのスリップなどを考慮しない場合のロボットの移動距離)を調べる事が出来る。

 ロータリエンコーダ(速度センサ)の接続については、プルアップ抵抗を3.3kΩに変更して、下図の例の様に接続する事。この例では、INT2(PD2)とINT3(PD3)にロータリエンコーダを接続している。また、INT2、INT3に対するマイコン内部のプルアップは不要である事に注意。

     


 カウントした値は、移動した距離なので、これを速度(回転速度)に変えるには、時間で割ってやる必要がある。具体的には、単位時間当たりのパルス数という事になる。それがモータの回転速度に相当する事になる。

 ところで、この受光センサの出力をカウントするには、例えばセンサ出力がPB0に繋がっていたとすると、

while (1) {
   // 何らかの処理     ---- ①
   if (PB0 & 0b00000001) {  // 受光センサの出力を調べて....         -----②
        cnt++;   // 出力が1だったら、カウント
   }
  // なた、何かの処理    ------ ③
}

 ...とかしたくなる人が多いであろう。(そこのあなた、そうでしょう?)

 ループ等の中で、繰り返してセンサなどの出力を監視する手法を、業界では「ポーリング」と呼ぶ。
 ーリングじゃないよ。カッコつけて言うと、思いっきり恥をかくので要注意!)

 ポーリングは、実装が簡単で応用も利くので有効な手法ではあるが、大きな問題点もある。それは、

  1. 信号を取りこぼす可能性がある
  2. サンプリング周期が一定しない

 ということである。
 どういう事かというと、上記のプログラムでは、センサ出力の監視(②)以外に①や③の処理も順番に実行されている。この順番という奴が曲者で、センサの出力が高速に変化する場合、プログラムの実行速度が追いつかなくて、以下の様に、3回、データをサンプリングしたいのに、1回しか取り込めていないといった状況になる可能性がある。

             
      (「マイコンは高速だから、そんなことあるわけないじゃん」と思う人は、どうぞ、自分の道を突き進んでください。馬鹿を見るのは自分ですから。まぁ、なんでも経験ですけどね。)

  サンプリング周期についても、基本的には同じ現象なのであるが、②の処理中しかデータを取り込めないので、以下の様にサンプリングの時間間隔にバラつきが発生する。これでも問題無いアプリケーションは沢山あるのではあるが、時間間隔がバラつくと問題が発生する物もある。例えば音楽・音声の録音再生などでは、音程が変わってしまったり、変な音が紛れてしまったりする。モータの定速度制御では、振動や異音が生じることもある。

             
 このように時間に関する制約が厳しい用途では、割り込みを使う事が一般的である。割り込みを用いると、割り込みハンドラの起動に若干の時間が必要だが、この時間は常に一定なので、実用上は問題は生じない。
               
 ただし、割り込みハンドラの中で、if文などの条件判断の後でデータのサンプルを行うと、時間間隔が一定しない可能性があるので、そのような記述は出来るだけしない方が良い。(そうしなければ実装できない場合もある。そういう場合は極力影響が少なくなるように考慮すること)

// 割り込みハンドラの悪い書き方
ISR (TIMER1_COMPA_vect)        //マッチするとここに飛んで来る
{
    if (なんちゃらかんちゃら) {  // これが、いかん。でも避けられない場合は、なるべく短時間で終わるように
           // さのよいよい
     }

      cnt++;  // センサの出力でカウントアップ!
}


回転速度(=車体の速度)への変換

  ここまでで、歯車の回転量を計る事は出来るようになった。このままでは、速度の制御は出来ないので、回転量(つまり歯車がどれだけ回転したかの積算量)を回転速度に変換してやる必要がある。
 速度とは、単位時間当たりの移動量(回転量)の事なので、一定時間の間にどれだけ受光センサが反応したかを調べてやればよい。具体的には、

  • 受光センサが反応した回数をカウントして、変数に保管する。(例えば cnt++ とか)
  • タイマを使って一定時間ごとに割り込みハンドラを呼び出す
  • この時のcntの値が速度になる。cntの値はどこかの変数に取っておいて、cntは0にする。

という事をやればよい。

 時間を計測するには、タイマ機能を用いるのが良い。以下の様にプログラミングすると、タイマ機能(タイマ1のCTCモード)を使用する事が出来る。CTCモードとは、比較一致レジスタ(OCR1A)とTCNT1の値が一致した時に、TCNT1が0となり設定されていれば、割り込みハンドラの呼び出しも行われる。

// timer1を動作。CTCモード。OCR1Aにコンペアマッチで割り込み
    OCR1A  = 20000;            // OCR1A=20000
                            // この値は、エンコーダ出力・モータの時定数を考慮して決めること。(100Hz程度が良い)
                            //  なお、
                            //   割り込みの周期が長いと、モータがビビる
                            //   割り込みの周期が短いと、エンコーダの積算値が少なく、回転精度が落ちる
    TCCR1B |= _BV(WGM12);   // CTCモード(TCCR1"A"ではなく TCCR1"B" であることに注意)
    TIMSK1 |= _BV(OCIE1A);  // キャプチャA 割り込みを設定
    TCCR1B |= _BV(CS11);    //プリスケーラ 1/8 これによりタイマ作動 16MHz / 8 = 2MHz

割り込みハンドラは以下の様に記述される。

ISR (TIMER1_COMPA_vect)        //マッチするとここに飛んで来る
{
  // 必要な処理
}


仕上げ

 これまでの議論で、モータの回転速度(つまり車速)を計測する事が出来るようになった。あとは、目標値と比較して、モータのON/OFFを行う処理を追加すれば良い。

 以上、健闘を祈る!
 

最終更新:2015年07月24日 15:00