RCサーボを操る

  1. サーボモータ

    1. RCサーボとは

       RCサーボは外部からの信号に応じて、一定の角度まで回転する小型モータです。大型のものはロボットの関節に、小型のものはラジコン飛行機の翼の角度制御などに利用されています。RCはラジコン、サーボは主人の命令に従う召使の意味のようです。

    2. サーボモータの制御

      サーボモータの端子は3本で、内2本(赤、黒)は電源です。ここでは、5Vの電源をそのまま利用します。他の1本が制御信号で、一定間隔のパルス信号です。このパルス幅がサーボモータの角度を設定します。パルス幅1.0〜2.0mSがモータの角度-70〜70に対応します。この値は、サーモモータにより若干変化します。
       角度に対応する幅のパルスを 20mS 周期で送ります。

    3. 使用する小型RCサーボの仕様

      サーボを特徴づける特性は、トルク(回転力)と、早さです。回転力は kg*m であらわし、中心から1cmでの力をあらわします。速度は角度当たりの時間で表します。ここで利用する サーボMIniS RB90 の仕様は以下のようです。サーボの仕様以上のトルクを加えるとサーボは角度を維持できずに回転してしまいますが、力を抜けば元の角度に戻ります。

      寸法: 22.5x11.5x27 (mm3)  
      トルク:1.6 kg*cm(4.8V)
      速度:  0.12s/60度(4.8V)
      ギア:プラスチック
      重量: 9g 

      また、電気的特性は以下のようです。
      電源電圧:4.8V
      動作可能範囲:±70°程度
      制御パルスHigh電圧:3-5V(矩形波)
      パルス幅:0.8-2.4ms 程度
      信号周期:15〜20ms
      端子列機能:黒・赤・白=接地

    4. 標準型サーボの仕様

      参考のため、標準型のサイズのRCサーボの例を紹介します。少し遅くなりますが、トルクは4倍以上です。

      トルク  4.8V時:7.2kg-cm
      スピード  4.8V時:0.33sec/60°
      ギア  プラスチック
      方式  アナログ
      サイズ  39.5×20.0×39.6mm
      重量  46g

  2. タイマー機能

    1. PICのタイマー機能

       PICには3種のタイマー機能が内蔵されています。タイマーは基本的には計数器で、指定された信号のパルスの数を計数します。タイマーの基本機能は、以下のようになります。

       計数する信号を設定する
       計数値を取得する
       計数値を設定する

      計数する信号が1マイクロ秒に1回の周期的なパルス信号なら、1000個のパルスを計数すると1ミリ秒の時間になります。逆に1秒間に1000を計数した場合、計数した信号の周波数は1kHz(Hz:ヘルツと読み周波数の単位)になります。
    2. タイマーのプログラム

       タイマーは計数信号の種類(モード)とプロスケーラを指定します。タイマー0を内部クロックで利用し(RTCC_INTERNAL) 1/128 のプリスケーラを利用する場合(RTCC_DIV_128)は以下の設定です。プリスケーラは内部クロックをあらかじめ、指定した値だけ分周します。たとえば、1000個の内部クロックを受け取った場合、1000/128 の値をタイマー0は計数します。プリスケーラは8ビットですから、RTCC_DIV_32、RTCC_DIV_64、RTCC_DIV_256、などが利用できます。
           setup_timer_0(RTCC_INTERNAL | RTCC_DIV_128)
      タイマー1の場合も同様ですが、定数の名前が異なります。T1のプリスケーラは3ビットなので、T1_DIV_BY_4、T1_DIV_BY_2、T1_DIV_BY_1、のみになります。
           setup_timer_1(T1_INTERNAL | T1_DIV_BY_8)
      タイマーの値は、次の値で設定できます。
           SET_TIMER0(1バイト値)
       SET_TIMER1(2バイト値)
       この値以後、計数信号からのパルスで値が増加します。現在のタイマーの値は、
           val = get_timer0();
       val = get_timer1();
      で取得できます。タイマー0は1バイト、タイマー1は2バイトの値になります。タイマーの値は計数信号により読み取るごとに値が増加します。

    3. タイマーの割り込み

       タイマー0の場合は255、タイマー1の場合は65536で最大になります。続けて計数をすると値は0に戻ります。この現象をオーバーフローといいます。タイマーのオーバーフローは割り込み要因になります。したがって、次のように割り込み許可がされていると
          enable_interrupts(INT_TIMER1); //タイマ1割込み許可
       enable_interrupts(GLOBAL);//グローバル割込み許可
      以下のように定義された割り込み関数を実行します。
          #INT_TIMER1 //タイマー割り込み関数の宣言
      timer1_isr(){
       割り込み処理
      }
      割り込みについては、こちらを参照してください。ここでは、タイマー1を20mS間隔でオーバーフローさせて割り込みを発生させ、割り込み処理で、RCサーボの回転角に対応した幅のパルスを生成します。 この割り込み処理により、プログラムで20mSを計数する必要がなくなります。

  3. 回路設計

    1. 部品

       可変抵抗は、上側の黄色の丸い部分を回転すると、抵抗値が変化する部品です。端子(下)側から見たとき、左右の両端子が固定抵抗、上側の端子と片側の端子の抵抗が回転とともに変化します。写真の端子は側面から見ています。左の上下の端子が固定で、右の端子が可変です。テスタで抵抗値を測定し動作を確認してください。

       押ボタンスイッチは、上のボタンを押すと側面から出ている二つの端子が短絡します。端子は両側から出ていますが、2回路ではなく、同時にオン/オフします。


    2. 構成

       ここでは、可変抵抗器を利用し、この抵抗値をAD変換して読み取り、この値でRCサーボを回転させます。RCサーボへの制御信号は、ポートAのA2を利用します。RCサーボのコネクタは白が制御線で赤が電源、黒がグランドです。コネクタはピンへダでパッチボードに接続します。ピンへダの長いほうをコネクタに差込、短いほうにパッチボードの線を半田付けします。
       シリアル通信を マイクロローダとハイパーターミナルで共有するため、CLR端子への接続に押しボタンスイッチを付加します。マイクロローダでプログラムを送るとき、このスイッチをオンにする必要があります。
       回路にはありませんが、B1にLEDを接続するとランプが点滅します。動作確認に利用してください。


  4. プログラム

    1. プログラム

      AD変換をした値を表示するため #use RS232() でRS232C の利用を宣言します。BAUD= は通信速度 xmit= は送信信号の端子、rcv= は受信信号の端子です。#INT_TIMER1 はタイマー1割り込み処理の宣言です。タイマー1がオーバーフローすると、続く関数が実行されます。ここで、可変抵抗器の値を1/3した値の時間だけ、RCサーボ(PIN_A2)にパルスを送ります。
       main()では、AD変換と、タイマー0、1、の設定、ターマー1の割り込み許可、を行います。繰り返しの中で、AD変換と、変換値の表示を行います。printf() のLu は2バイト符号なし整数データの表示を指定します。

      //Servo Test
      //パルス周期 15-20mS
      //パルス幅 0.8-2.4mS
      #include <16F873A.h>
      
      #fuses HS,NOWDT,NOLVP,NOPROTECT
      #use delay(clock = 20000000)
      #use RS232(BAUD=9600,xmit=PIN_C6,rcv=PIN_C7)
      
      
      long vd,loop;
      
      #INT_TIMER1  //タイマ1割込みの指定
      timer1_isr(){  //タイマ1割込み処理関数
        set_timer1(53000);
        
        set_timer0(0);
        output_high(PIN_A2);
        while (get_timer0() < vd/3) {};
        output_low(PIN_A2);   
      }
      
      void main() {
      
        setup_adc_ports(AN0);
        setup_adc(ADC_clock_div_32); 
        set_adc_channel(0);
              
        setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);//タイマ0のモード設定
              
        setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);//タイマ1のモード設定
        set_timer1(2500);
        set_timer0(100);
      
        enable_interrupts(INT_TIMER1);  //タイマ1割込み許可
        enable_interrupts(GLOBAL);//グローバル割込み許可
        loop=0;
        
        while(1){//割込み待ち
              output_low(PIN_B1);
              vd=read_adc();  
              delay_ms(20); 
              output_high(PIN_B1);
              delay_ms(30);
              loop++;
              if (loop>20){
               printf("%3Lu\r\n",vd); 
               loop=0;
              }  
        }    
      }

    2. 実行上の注意

       PC側のRS232Cをマイクロローダとハイパーターミナルで共有するため、注意が必要です。マイクロローダでプログラムを送るとき、PICのリセット(CLR)回路にあるスイッチをオンにします。
       printf() の値を表示するには、ハイパーターミナルで接続しますが、再度マイクロローダを利用する場合、ハイパーターミナルの接続を一時的に切断する必要があります。
       サーボモータを無理に回すとプラスチックのギア(歯車)が破損します。やさしく扱ってください。

    3. 正転、逆転を繰り返すプログラム

       参考のため、正転、逆転を繰り返すプログラムを紹介します。正回を行うには、次第にパルス幅を広げればよく、逆転をするには、パルス幅を縮小します。タイマー0のクロックは、0.2*128=25.6 μ秒になります。vdとして、30〜80とすると、サーボへのパルス幅は 0.75mS から 2mS になります。
       set_timer1(53036);
      の53036 は20mSの周期を作ります。main() の繰り返しの中の delay() はパルス幅を変更する間隔です。PB2 で動作チェック用のLEDを点灯するため、前後の二つの値の合計が、同じパルス幅を時間となります。この値を小さくすると、回転が速くなります。

      //Servo Test
      //パルス周期 15-20mS
      //パルス幅 0.8-2.4mS
      #include <16F873A.h>
      
      #fuses HS,NOWDT,NOLVP,NOPROTECT
      #use delay(clock = 20000000)
      
      long vd;
      
      #INT_TIMER1  //タイマ1割込みの指定
      timer1_isr(){  //タイマ1割込み処理関数
        set_timer1(53036);
        
        set_timer0(0);
        output_high(PIN_A2);
        while (get_timer0() < vd) {};
        output_low(PIN_A2);   
      }
      
      void main() {
              
        setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);//タイマ0のモード設定
              
        setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);//タイマ1のモード設定
        set_timer1(53000);
      
        enable_interrupts(INT_TIMER1);  //タイマ1割込み許可
        enable_interrupts(GLOBAL);//グローバル割込み許可
        
        while(1){
                
          for(vd=30;vd<=80;vd +=5){//正回転
              output_high(PIN_B2); //動作確認用
              delay_ms(50); 
              output_low(PIN_B2);
              delay_ms(100);
          }
          
          for(vd=80;vd>=30;vd-=5){//逆回転
              output_high(PIN_B2); //動作確認用
              delay_ms(100); 
              output_low(PIN_B2);
              delay_ms(200);
          }   
          delay_ms(500);//休止
        }    
      }

  5. 課題


    1. 二つのサーボ

       二つ以上のサーボを同時に動かしてください。main() でvd1とvd2の二つのパルス幅を指定し、ターマー1の割込み処理で、順に二つのサーボの制御信号のパルス幅を設定します。

    2. アームロボット

      二つのサーボーを腕木の関節に組み込み、体操のような運動をさせてみましょう。