動作説明
サーボモーターのドライブ

 20msec毎にタイマー0で割り込みを発生させます。内部クロックは4MHzですので、1マシンサイクルは1μsecです。タイマー0のプリスケーラーを256にし、タイマーの初期値を178にすると、1μsec×(256−178)×256=19968μsec≒20msec になります。サーボモーターに与える制御パルスはタイマー1で生成します。1500μsecを中心に±900μsec変化させ約180度回転させます。PICのアナログ入力、制御出力は2系統になります。タイマー1は、16ビットですのでカウント値は65536になります。タイマー1の割込みフラグは0C番地のPIRレジスタのbit0にあります。

 サーボモーターは自身で発生させたパルスのパルス幅と、外部からのパルス幅とを比較し、同じ幅になるまで回転し続けます。PICを使用し2個のスライドボリュームをスライドさせて、サーボモーターでヘッドを上下左右に動かせるロボットアームです。使用したモーターはTower ProのSG90です。

 サーボモーターの内部では、駆動軸につけられた可変抵抗器の抵抗値に応じたパルスが発生し、制御用のパルスとの幅が同じになるように駆動軸が回転します。PICは制御用のパルスを発生させます。制御用のパルスの幅は、PICに取り付けたスライドボリュームを動かすと変わるようにしています。電源電圧は5VでPICは12F675を使用します。内部発振回路を使用しますので、PICの周辺回路はシンプルです。制御用のパルスの周期は約20msec、サーボモーターの駆動軸角度はパルス幅が約0.6msec〜2.4msecに設定します。
 参考のために、SG90をばらしてみました。中身はギヤボックス、モーター、両面実装基板で、この基板にFZMOS−2と記されたSOP8と、無印のSOP8が各々各面に実装されていました。この型番で検索してみたのですが、何も引っ掛かりませんでした。検索一覧の中に、TIのLM5110がありましたが、このICの英文のタイトルを直訳すると「負の出力電圧機能を備えたデュアル5-A複合ゲートドライバ」となっていました。更に検索を進めると、ロームのBD6210Fに突き当りましたが、このICは、ブラシ付きモーター用Hブリッジドライバでした。どうやらこちらの方が近いようです。

ソフトの説明

 上図について、横軸はPICのAD変換が8ビット、最大電圧がVccの5V(5000mV)ですので、ビットステップとそれに対する電圧を表しています。このPICのAD変換は8ビットと10ビットの選択ができますが、ここでは8ビットにしています。縦軸はPWMの幅を時間で表しています。PWMの周期は20msecで、パルス幅は600μsecから2400μsecまで変化します。変化幅は1800μsecです。0Vのときは600μsecで、5Vのときは2400μsecです。これらの関係を式で表すと
パルス幅=(1800/255)*V+600 となります。
#byte PIR1=0x0cは#byteがプリプロセッサで、12F675のBank0の0ch番地にマッピングされており、TMR1IFビットのあるアドレスを指しています。PIR1はInterval関数の中で、クリアしておく必要あります。

回路図
トップページへ戻る

#include <12F675.h>
#byte PIR1=0x0c           
//各モジュールの割込制御レジスタ
#fuses INTRC_IO,NOWDT,PUT,NOPROTECT,NOMCLR

                       //
内部クロック使用
#DEVICE ADC=8           
//AD変換8ビット
#use delay(clock=4000000)     
 //クロック4M

Long haba0;
Long haba1;
int V0;
int V1;

#int_timer0             
//タイマー0割込みルーティン
void Interval(void)
 {
  output_Low(PIN_A4);       
//サーボ1初期設定
  output_Low(PIN_A5);       
//サーボ2初期設定
  set_timer0(176);         
//タイマー0数値設定

  haba0=(1800/255)*V0+600;    
//パルス幅と電圧の関係
  PIR1=0;             
//割込み制御レジスタのリセット
  set_timer1(65536-haba0);    
//タイマー1数値設定
  output_high(PIN_A5);       
//タイマー1の割込みフラグが
  while((PIR1 & 0x01)==0){ };    
//1になるまでサーボ1を動かす
  output_Low(PIN_A5);

  haba1=(1800/255)*V1+600;
  PIR1=0;
  set_timer1(65536-haba1);
  output_high(PIN_A4);
  while((PIR1 & 0x01)==0){ };
  output_Low(PIN_A4);
  PIR1=0;             
//割込み制御レジスタのリセット
  }

void main()
{
  setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
                  
 //タイマー0設定
     
                 //内部クロック使用、プリスケーラ―256
  set_timer0(178);          
//タイマー0の設定
  enable_interrupts(INT_TIMER0);
  //タイマー0の割込みをイネーブル  

  setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); 
                      //内部クロック使用、プリスケールなし

  setup_adc_ports(sAN0 | sAN1 | VSS_VDD);
 
                      //アナログ入力に設定

  setup_adc(ADC_CLOCK_DIV_8);
  // クロック4Mのときは2μsec
  enable_interrupts(GLOBAL);  
  //全体割込み許可   

  while(1)
   {
    set_adc_channel(0);     
//チャンネル0をアナログ入力とする
    delay_us(50);
    V0=read_adc();       
//アナログデータを読み込む

    set_adc_channel(1);
       //チャンネル1をアナログ入力とする
    delay_us(50);
    V1=read_adc();       
//アナログデータを読み込む
   }
}

ソースリスト