サーボモータを駆動する

著者:Ben Roloff、最終更新日:2019年1月22日

はじめに

DCサーボモータは、簡単に駆動できるように作られており、今ではただドロップインするだけで使える装置です。追加の回路を必要とする通常のDCモータとは異なります。DCモータにHブリッジ回路を内蔵し、さらにフィードバックループも搭載しています。これにより、連続運転が簡単に運転できるDCモータ、または任意の角度に移動できる位置決めモータにすることができます。単純なサーボモータの良いところは、通常、3本の配線が付属していることです。1本は電源、1本はグランド、3本目は信号です。角度、方向、および速度の制御は、単純なPWM(パルス幅変調)信号で実行されます。そのため、手軽に始められるモータとなっています。

サーボモータ

サーボモータで最初に見るべきものはデータシートです。データシートには、より多くのデータが記載されているものもありますが、最も重要なのはPWM信号に関する情報です。多くのサーボモータのPWM信号は、周期21.5ms、デューティサイクル7%程度です。つまり、約1.5msの間オン、20msの間オフということです。これは通常、サーボモータの90度位置または停止位置にあたります。オンの時間を 1.5msより長くすると、サーボが 180度に近づく、つまり時計回りに動くようになります。逆に1.5msより短くすると、反対方向の、0度に向かって反時計回りに動きます。その両極端は、通常2.25msと0.75ms程度です。 この値はサーボモータによって異なります。 もう1つの重要なポイントは、コードを書いた後、それがどの程度正確にms値に対応しているかをテストする必要があり、正しいゼロ点(停止位置)を得るために調整する必要があるかもしれないことです。

ソフトウェア

Arduino

ほとんどのマイクロコントローラには、PWM信号を生成できるように設定されたタイマが搭載されています。Arduinoを使用している場合、こちらに示すように、ArduinoのIDEを使用して必要な信号を作成するのは非常に簡単です。Arduinoにはサーボライブラリが内蔵されており、サンプルプログラムもいくつか用意されているので、すぐに使い始めることができます。ほとんどのマイクロコントローラは、そのような非常に簡単な設定はありませんが、一般的にPWM信号は非常に短い簡単なコードです。

SCTimer

LPC 812は、カウンタとPWM信号にSCTimerを使用しています。LPC 812を使い始めるには、こちらをご覧ください。このタイマは、異なるステートを使用できることを考えると、他のものより少し優れています。このタイマのもう1つの良いところは、32ビットタイマを使うことも、16ビットタイマを2つ使うこともできることです。信号を発生させるためにマッチとイベントを使用します。これにより、簡単に好きな信号を作ることができ、入力に応じたプリセットの変化を持たせることができます。コードにあるように、イベントとマッチを設定することが大きなポイントですが、それが終われば簡単に使うことができます。マッチの値を変更したい場合は、reload変数を使用することを確認してください。下のオシロスコープの写真で、目的のPWM信号の出力されているのが確認できます。

Servo_Init()

#define Count_ms 0.001*SystemCoreClock              // global variable for getting a ms value from the System Clock

void Servo_Init()
{
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8);           // enable the clock for the SCT
LPC_SYSCON->PRESETCTRL |= (1<<8);              // disable reset
LPC_SWM->PINASSIGN6 = 0x6ffffff;                 // assign SCT output 0 to pin 6
LPC_IOCON->PIO0_6 |= (1<<5);                       // this enables hysteresis

LPC_SCT->CONFIG |= 1;                            // use one 32 bit timer
LPC_SCT->CONFIG |= (1<<17);                    // autolimit with match 0
LPC_SCT->REGMODE_L = (0);                        // this makes all the match registers match and not capture registers
 LPC_SCT->MATCH[0].U = 21.5*Count_ms;             // set limit at off time of 20 ms and desired duty cycle of 1.5 ms
LPC_SCT->MATCHREL[0].U = LPC_SCT->MATCH[0].U;     // load the reload value
LPC_SCT->EVENT[0].CTRL |= 0;                     // set event 0 to match 0
LPC_SCT->EVENT[0].CTRL |= (1<<12);             // set event 0 to trigger on match
LPC_SCT->EVENT[0].STATE |= 0x1;                  // event 0 operates in state 0

LPC_SCT->MATCH[1].U = 20*Count_ms;           // set match 1 to the off time of 20 ms
LPC_SCT->MATCHREL[1].U = LPC_SCT->MATCH[1].U;     // load reload value
LPC_SCT->EVENT[1].CTRL |= 1;                     //set event 1 to match 1
LPC_SCT->EVENT[1].CTRL |= (1<<12);                 // set event 1 to trigger on match
LPC_SCT->EVENT[1].STATE |= 0x1;                  // event 1 operates in state 0

LPC_SCT->OUT[0].SET |= (1<<1);                     // output is set at event 1
LPC_SCT->OUT[0].CLR |= (1<<0);                     // output is cleared at event 0

LPC_SCT->CTRL_U &=~(1<<2);                     // turn off halt bit
} 

Main()

Servo_Init(); // initialize the SCT pwm

while(1) {

for(i = 0; i < 300000; i++);                 // random delay
LPC_SCT->CTRL_U |= (1<<2);                     // turn on halt bit
LPC_SCT->MATCHREL[0].U = 20.75*Count_ms; // change reload of limit
LPC_SCT->CTRL_U &=~(1<<2);                     // turn off halt bit
for(i = 0; i < 300000; i++);             // random delay
LPC_SCT->CTRL_U |= (1<<2);                 // turn on halt bit
LPC_SCT->MATCHREL[0].U = 22.25*Count_ms; // change reload of limit
LPC_SCT->CTRL_U &=~(1<<2);                 // turn off halt bit
for(i = 0; i < 300000; i++);             // random delay
LPC_SCT->CTRL_U |= (1<<2);                 // turn on halt bit
LPC_SCT->MATCHREL[0].U = 21.5*Count_ms;      // change reload limit
LPC_SCT->CTRL_U &=~(1<<2);                 // turn off halt bit

}

TMR

ほかによく見かけるのは、PWM信号のTMRタイマです。これは基本的なタイマです。PWM信号の生成には、通常、周期とデューティサイクルを設定します。このPWM信号のスタイルについては、こちらを参照してください。この例では、周期とデューティサイクルを変更する必要があります。

TMR用のPWMコード

//This code was borrowed from http://www.eewiki.net/display/microcontroller/Getting+Started+with+NXP%27s+LPC11XX+Cortex-M0+ARM+Microcontrollers
//Author: Justin Clack

#include "LPC11xx.h"

int main(void) {

//Set up 16 bit timer for PWM operation
LPC_IOCON->PIO0_8         = (LPC_IOCON->PIO0_8 & ~(0x3FF)) | 0x2;     //set up pin for PWM use (sec 7.4.23)
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);                                  //enable clock signal to 16 bit timer0 (sec 3.5.14)
LPC_TMR16B0->PR           = 0x0;                                      //set prescaler max value, not used here (sec 18.7.4)
LPC_TMR16B0->MCR          = 0x10;                                     //set for reset on counter match (sec 18.7.6)
LPC_TMR16B0->EMR          |= 0x20;                                    //set pin 27 to 1 on match (sec 18.7.10)
LPC_TMR16B0->CCR          = 0;                                        //set to timer mode (sec 18.7.11)
LPC_TMR16B0->PWMC         = 0x1;                                      //set channel zero to PWM mode (sec 18.7.12)
LPC_TMR16B0->MR1          = 0x32;                                     //set value for period (sec 18.7.7)
LPC_TMR16B0->MR0          = 0xC;                                      //set value for duty cycle (sec 18.7.7)
LPC_TMR16B0->TCR          |= 0x3;                                     //enable and reset counter (sec 18.7.2)
LPC_TMR16B0->TCR          &= ~(0x2);                                  //clear reset bit (sec 18.7.2)

while(1){                                                     //infinite loop
}
return 0 ;
}

力ずくの方法

GPIOピンを使ってダミーのものを作り、自分でタイミングをとることができます。しかし、これは力ずくのやり方で、正確性に欠け、多くの欠点があります。信号が他のコードから分離して実行されていないため、他の関数呼び出しやコードによってタイマが変更されてしまいます。つまり、そのすべてを考慮しなければならないか、あるいはこのコードが実行するのはこれだけである可能性があり、あまり有用ではないのです。オシロスコープ出力で、PWM信号が作れることがわかりますが、正しい信号にするためには、少し作業が必要です。

GPIO_PWM_Init()

void delay_ms(int x)
{
int i;
for(i = 0; i < (x*1000); i++); // random delay to get as close as possible to a ms
return;
}

delay_msソースを展開

Main() ソースを展開

結論

サーボモータは、かなり簡単に動かすことができます。おそらく、最も動作させやすい電気モータでしょう。必要なのはPWM信号だけです。PWM信号の生成は、ほとんどのマイクロコントローラでかなり一般的に行われています。このC言語コードは普遍的なものではありませんが、少なくともあなたのマイクロコントローラの第一歩としては良いものになるはずです。サーボモータを動かすのはロケット科学のように難しいものではなく、簡単に使えるように設計されています。

Useful Links

LPC 812 User Manual
AN11538_SCTimer_PWM_Cookbook v5.0.pdf (1.8 MB)



オリジナル・ソース(English)