111.最適なPWMの周期を探る


2001/08/23 【ソフトウエア編TOPに戻る】

またまたPWMのお話です。DCモーターの制御にはPWMの手法が欠かせません。PWMの動作を決定するパラメータには、周期とデューティー比と印加電圧がありますが、具体的にはどのように決定すれば良いのでしょう?印加電圧については、DCモーターの規格で決められているので、基本的にはそれに従うことになります。またデューティー比はベースとなる周期が決まれば自由に設定できます。では、周期はどうやって決めましょうか。


111−1.モーター固有の時定数をもとにして決める。

モーターには機械的時定数と電気的時定数があります。細かな説明をご紹介するときりが無く、またかなり難しい話になるので、かいつまんでご紹介することにします。(トラ技ORIGINAL No.7 マイコン&メカトロニクスの誕生 CQ出版社の受け売りです。)

 

機械的時定数

回転しているモーターの電源を単純にOFFした場合、ある一定時間だけ惰性で動いてから完全に停止します。また逆に、完全に停止しているモーターに定格の電圧を加えた場合、一定の回転数に達するまでには、やはりある一定の時間を要します。この時間はモーターによって異なり、慣性(イナーシャ)によって左右されます。

DCモーターにフライホイール(オモリの円盤)を取り付けるとイナーシャが大きくなり、始動にも停止にも長い時間を要します。逆に、軽いローターのコアレスモーターなどは非常にイナーシャが小さく、回転も停止も短い時間ですみます。つまり応答性が高くなります。

機械的な時定数は、以下の関係式で表されます。

Tm = J/D (単位 ms)

 J:慣性率(単位 g・cm2) イナーシャ。

 D:制動定数(単位 g・cm2/rpm) 1回転減速するのにどれくらいの力が必要かを示す。

実際には完全に停止しているモーターが設定された回転数の約63.2%に達するまでの時間でしめすことが多く、大体2〜30msだそうです。

 

電気的時定数

モーターの電気回路はどうなっているかというと、要は電磁石と同じでコイルから出来ています。つまりただ電線をコアに巻きつけているだけです。なので、電気的な特性としては、L(インダクタンス)成分と、電線の抵抗成分が影響します。

モーターに発生するトルクは、基本的にはコイルに流れる電流の大きさに比例して大きくなりますが、インダクタンス成分のために電流位相が遅れ、ベクトル的に考えると実際にはその分だけトルクの発生が遅れ、トルクの絶対値も小さくなります。つまり、モーターに電圧を加えた時に、電流の位相(時間)遅れを表すのが電気的時定数となり、以下の関係式で表されます。

Te = L/R (単位 ms)

 L:コイルのインダクタンス(単位 H)

 R:コイルの直流抵抗(単位 Ω)

電気的時定数は小さければ小さいほどよいのですが、大体0.2〜10msくらいになるそうです。

 

実際のモーターではその用途に応じて、機械的時定数と電気的時定数の関係が最適になるように設計されますが、TmTe10倍以上になるように決定されるようです。

 

で、PWMの周期は?

結論から言うと、電気的時定数Te1/5以下の周期に設定するそうです。(理由は聞かないで下さい。本の受け売りなので力弥はよく分かりません...) 上記のTeの値からすると、大体25KHz〜500Hzの間ということになります。機械的時定数は、直接PWMの決定要因にはならないようです。ただし、始動や停止の際の応答性に影響することは言うまでもありません。

ならば、実際に制御したいDCモーターの電気的時定数Teがわかれば、最適なPWMの周期が決まるということです。ところが、一般工作用のDCモーターは、データ表に電気的時定数Teが明記されていません。マブチモーターのホームページを覗いて見ても、特に公開されている様子はありません。

結局、どうやって最適なPWM周期を決定したら良いのでしょう... 正直言って、良く分かりません。

 

【先頭に戻る】


111−2.実際に動かし、具合をみて決める。

色々と学術的なこと(?)をひも解いてみても結局よく分かりませんし、実際に動かさないと気が付かない点もありますよね。やっぱりいろんな周期で実際に動かして見るのが一番です。(安易)

というわけで、周期とデューティー比が簡単に可変できて、モーターの動作の様子を手軽に確認できるプログラムを作りましたので、ご紹介します。

 

111−2−1.プログラム動作説明

このプログラムは6個のレンジ切替により、周期が約125KHz〜約4Hzの間のPWM波形を発生します。A/D変換機能を利用し、ボリューム(可変抵抗器)によってレンジ内でのPWM周期とデューティー比を連続可変させることができます。

以下の写真が、そのハードウエアのセッティングの様子です。

ハード接続

写真左から、小型ギヤードモータ、DCモータードライバ基板、可変抵抗器x2、そしてAKI-H8開発ボードです。なお、ハードウエアについては電子回路編 3.AKI-H8開発キットの回路4.DCモーター駆動回路を参照して下さい。

 

このプログラムは以下のような動作を行ないます。

■各レンジでサポートするPWM周期

以下の6個のレンジを切替えて、それぞれに対応したPWM出力を得ることができます。

S5 DIP-SW設定 モード名称

(約) PWM周期

256段階

(約)デューティー比

3(bit2) 2(bit1) 1(bit0)
ON ON ON clock = x2 125KHz〜488Hz 0.00〜1.00 (256段階)
ON ON OFF clock = 1 62.5KHz〜244Hz 0.00〜1.00 (256段階)
ON OFF ON clock = 1/2 31.2KHz〜122Hz 0.00〜1.00 (256段階)
ON OFF OFF clock = 1/4 15.6KHz〜61Hz 0.00〜1.00 (256段階)
OFF - - clock = 1/8 7.8KHz〜30Hz 0.00〜1.00 (256段階)
4(bit3) を OFF clock = 1mS wait 32Hz〜4Hz 0.03〜1.00   (32段階)
5(bit4) を OFF S1 PUSH MODE S1を押した期間だけON -

AKI-H8開発ボードのディップスイッチS5を上記の設定にしてリセット(電源入れ直し)すると、設定されたモードで動作を開始します。設定された動作モードの名称は、液晶表示器に表示されます。

PWM周期を可変させるボリュームはAN1チャンネル、デューティー比を可変させるボリュームはAN0チャンネルにそれぞれ接続します。ボリュームを回すと、連続的に周期とデューティー比が変化します。

PWM波形は、ITU0チャンネルから出力されます。 (PORT2 のBIT2と共用)

S1 PUSH MODEの場合、開発ボードのタクトスイッチS1を押している期間だけ、デューティー比100%を出力します。

 

■周期とデューティー比のパラメータ値の読み取り

最適なポイントが見つかったら、その設定値が知りたくなります。現在の周期とデューティ比を表すパラメータは、PORT1に接続してある8ビットのLEDで読み取ります。

8ビットのLEDに表示させる内容は、ディップスイッチS5の8(bit7)で切替えます。

S5 DIP-SW設定

PORT1  8ビットLEDの表示内容

8(bit7) を ON  現在ボリュームで設定されているデューティー比パラメータ値
8(bit7) を OFF   現在ボリュームで設定されている周期パラメータ値

ここで表示されるパラメータを基に、以下の計算式で動作させています。

 

【clock = x1 から 1/8 の各モード時】

H8のITU0チャンネルを使ってPWM出力をおこなっていますので、以下の計算式でGRAとGRBを設定しています。

周期設定               ITU0.GRB = (0x00ff*周期パラメータ値)+0x0101
デューティー比設定  ITU0.GRA = (ITU0.GRB/0x00ff)*デューティー比パラメータ値

 

【clock = 1mS wait のモード時】

H8のPWM機能は使わず、タイマーによる時間稼ぎとPIO出力の組み合わせでPWM波形を作っています。なので、

周期パラメータ値は、そのまま周期(mS)を表し、デューティー比パラメータ値は、出力が0(ゼロ)の期間(mS)を表します。

 

その他の細かい動作は、プログラムを見て頂くとわかるかと思います。

【先頭に戻る】


111−3.プログラム pwmtest3.c のご紹介

ソースプログラムは、ここをクリックするとダウンロードできます。(pwmtest3.c) 以下に掲載しているプログラムでは、ヘッダファイルとしてmyfunc.hを読み込んでいます。ヘッダファイルについては、201.自分の関数をヘッダファイルにするを参照して下さい。

なお、スタートアップオブジェクトは、今回割込みを利用していないので、startup.marで結構です。

今回のプログラムでは、特に新しいことはしていません。なので、プログラムの説明は手抜きさせて頂きますので、ソース中のコメントと、ソフトウエア編 基礎実験のお話の101から108までを参照して下さい。

/*****************************************/
/* PWMテスト3 RIKIYA 2001/08/22          */
/* pwmtest3.c                            */
/* H8-3048F                              */
/* ITU0を使ったPWM基本動作テスト         */
/* A/D入力によって、PWMの周期とデューティ*/
/* を連続的に可変させる                  */
/*****************************************/

#include <3048f.h>
#include <myfunc.h>

/* メイン関数 ********************************************/

void main(void){

     int data_a,data_b,data_c;

     timer_init();                     /* タイマーの初期化        */
     lcd_init();                       /* 液晶表示器の初期化      */

     PA.DDR = 0xff;                    /* portA出力に設定         */
     PA.DR.BIT.B3 = 1;                 /* portA bit3を0固定とする */
     P1.DDR = 0xff;                    /* port1出力に設定         */
     P2.DDR = 0x00;                    /* port2入力に設定         */
     P2.PCR.BYTE = 0xff;               /* port2全てプルアップ     */
     P4.DDR = 0x00;                    /* port4入力に設定         */
     P4.PCR.BYTE = 0xff;               /* port4全てプルアップ     */

     AD.CSR.BYTE = 0x31;               /* SCAN MODE / CH0〜1      */
     while(AD.CSR.BIT.ADF == 0){}      /* 2CH分の変換終了を待つ   */

/**********************************************************/
/* H8のPWM機能によるPWM制御 周期125KHz〜30Hzに対応する
/**********************************************************/
     if((P2.DR.BIT.B3 == 0) && (P2.DR.BIT.B4 == 0)){

          switch ((P2.DR.BYTE) & 0x07){ /*下位3BITの状態を判定*/
               case 0: /* クロック両エッジでカウント*/
                    lcd_locate(0,0);
                    lcd_print("clock = x2 ");
                    ITU0.TCR.BYTE = 0x50;
                    break;
               case 1: /* クロックφでカウント */
                    lcd_locate(0,0);
                    lcd_print("clock = 1 ");
                    ITU0.TCR.BYTE = 0x40;
                    break;
               case 2: /* クロックφ/2でカウント */
                    lcd_locate(0,0);
                    lcd_print("clock = 1/2 ");
                    ITU0.TCR.BYTE = 0x41;
                    break;
               case 3: /* クロックφ/4でカウント */
                    lcd_locate(0,0);
                    lcd_print("clock = 1/4 ");
                    ITU0.TCR.BYTE = 0x42;
                    break;
               default: /* クロックφ/8でカウント */
                    lcd_locate(0,0);
                    lcd_print("clock = 1/8 ");
                    ITU0.TCR.BYTE = 0x43;
                    break;
          }

          ITU0.GRA = 65534;             /* GRAを65534に設定      */
          ITU0.GRB = 65533;             /* GRBを65533に設定      */
          ITU.TMDR.BIT.PWM0 = 1;        /* ITU0 PWMモード        */
          ITU.TSTR.BIT.STR0 = 1;        /* カウント開始          */

          while(1){

               data_b = (AD.DRB>>8) & 0x00ff;     /* A/D CH1 8BIT化  */
               data_a = (AD.DRA>>8) & 0x00ff;     /* A/D CH0 8BIT化  */

               ITU0.GRB = (0x00ff*data_b)+0x0101; /* 周期を設定      */
               ITU0.GRA = (ITU0.GRB/0x00ff)*data_a; /*デューティー比 */

               switch (P2.DR.BIT.B7){
                    case 0: /* デューティー比パラメータ表示*/
                         P1.DR.BYTE = (ITU0.GRA>>8) & 0x00ff;
                         break;
                    case 1: /* 周期パラメータ表示 */
                         P1.DR.BYTE = (ITU0.GRB>>8) & 0x00ff;
               }
          }
     }
/**********************************************************/
/* タイマ待機によるPWM制御 周期32Hz〜4Hzに対応する
/**********************************************************/
     else if((P2.DR.BIT.B3 == 1) && (P2.DR.BIT.B4 == 0)){

          lcd_locate(0,0);
          lcd_print("clock = 1mS wait");

          while(1){

               data_b = (AD.DRB>>8) & 0x00ff;     /* A/D CH1 8BIT化     */
               data_a = (AD.DRA>>11) & 0x001f;    /* A/D CH0 5BIT化     */

               if (data_b < 0x001f) {data_b = 0x001f;} /*data_b制限     */
               data_c = (data_b/0x001f)*data_a;   /* 出力0の期間を計算  */

               PA.DR.BIT.B2 = 0;                  /* portA bit2を0とする*/
               wait(data_c);                      /* 出力0の期間        */

               PA.DR.BIT.B2 = 1;                  /* portA bit2を1とする*/
               wait(data_b-data_c);               /* 出力1の期間        */

               switch (P2.DR.BIT.B7){
                    case 0: /* デューティー比パラメータ表示*/
                         P1.DR.BYTE = data_c;
                         break;
                    case 1: /* 周期パラメータ表示 */
                         P1.DR.BYTE = data_b;
               }
          }
     }
/**********************************************************/
/* タクトスイッチを押した時にONする。手動動作
/**********************************************************/
     else if((P2.DR.BIT.B3 == 0) && (P2.DR.BIT.B4 == 1)){

          lcd_locate(0,0);
          lcd_print("S1 PUSH MODE ");

          while(1){
               switch (P4.DR.BIT.B4){
                    case 0:
                         PA.DR.BIT.B2 = 0;       /* portA bit2を0とする*/
                         P1.DR.BYTE = 0x55;
                         break;
                    case 1:
                         PA.DR.BIT.B2 = 1;       /* portA bit2を1とする*/
                         P1.DR.BYTE = 0xaa;
               }
          }
     }
}

 

【先頭に戻る】


PWMの周期とデューティ比がボリューム操作で簡単に可変できるので、それなりに便利です。その他のモーター制御にも応用できそうです。

これを使って実際にDCモーターを動かして見ると、回転時に振動が発生しなくなるポイントや、デューティ比によってスムーズに速度制御ができる周期とできない周期のポイントなどが良く分かります。ただし、DCモーターはかなり広範囲な周期にわたって比較的安定に動作するため、あまり根を詰めて「最も最適なポイントが知りたい!」といっても、やっぱり良くはわかりません。

とりあえず、このプログラムでしっかりと動作するポイントを掴む、という程度で考えましょうか。

 

【ソフトウエア編TOPに戻る】


【表紙に戻る】