Arduinoのライブラリでサーボモーターを操作する

組み込みエンジニア

こんにちは、ENGかぴです。

Arduino環境では標準ライブラリでサーボモーターを操作することができます。サーボモータはラジコンカーのステアリングやロボットによる弁の開閉部など様々な用途で使用されており0~180度の範囲で動作するものが多くあります。

本記事では標準ライブラリを使用してサーボモーターを回転させる方法をまとめています。サーボモーターはArduinoのスターターキットに付属されていたSG90を使用しています。

Arduino UNO(以下Arduinoとします。)を対象とします。Arduinoのライブラリを使用して動作確認したことをまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

標準ライブラリでサーボモーターを操作する

SG90の仕様説明
引用:SG90のデータシート SG90の仕様説明

サーボモーターはパルス波形を与えてモータを動作させるものです。SG90のデータシートによるとPWM周期(キャリア周波数)が50Hzの波形でデューティーサイクル(Duty Cycle)が0.5~2.4msになるように調整することで回転する角度が決まります。

データシートにはOperating speed(動作速度)が0.12s/60 degreeと記載されています。60度回転させる場合はキャリア周波数20msでデューティーサイクルが1.13mであるパルス波形を120ms経過するまで出力する必要があります。

Arduinoライブラリはマイコンの割り込みを使用して指定の角度になるようにパルスを調整する仕様になっています。以下では標準ライブラリを使ってサーボモーターの操作を行う手順を説明します。

ライブラリの準備と初期化

#include <Servo.h>

Servo sg90; //Servoクラスの型の変数を宣言

void setup() {
  sg90.attach(SERVO_PIN,500,2400); //サーボモーターの初期化
}

ライブラリを使用するためServo.hをインクルードします。サーボモーター専用のクラスの型の変数としてsg90(任意の宣言名でOK)を宣言してオブジェクトを作成します。

attach()関数でサーボモーターの初期化を行います。第1引数にサーボモーターを操作するDO出力のピンを指定します。第2引数にサーボモーターの操作の最小値(usの値)を指定します。第3引数にサーボモーターの操作の最大値(usの値)を指定します。

第2引数と第3引数を指定しない場合はそれぞれ最小値が544・最大値が2400となります。sg90のデータシートではデューティーサイクルが0.5ms~2.4msとなっているので例では第2引数に500・第3引数に2400を指定しています。

すき間時間で資格をゲット【STUDYing(スタディング)】

ライブラリの使用例

#define WAIT_TIM 30 //300msウェイト

void loop() {

  switch (move){
  case 0: //角度指定
    sg90.write(90);
    timcount = WAIT_TIM;
    ++move;
    break;
  case 1: //動作完了までのウェイト
    if(timcount == TIME_UP ){
      timcount = TIME_OFF;
      ++move;
    }
    break;
  }
}

サーボモーターの回転角度の指定と動作完了待ちをモード管理で行います。delay()関数を使用して動作完了までのウェイトを置く方法もありますが、delay()関数では割り込み処理以外が一時停止してしまいます。動作の遅延が問題となる場合はdelay()関数が使用できないことがあります。

例ではdelay()関数を使用せずにモードによる切り替えとタイマーを使用してウェイトを置く方法でサーボモーターを操作しています。

モード管理とタイマを使用することでdelay()関数によるソフトウェアウェイトを使用しなくてもサーボモーターを操作することができます。

モード0ではサーボモーターの回転角度をwrite()関数で指定します。引数に操作したい角度を指定します。例では90度を指定しています。角度を指定した後はサーボモーターが回転し終わるまでのウェイトを管理するタイマをセットしてモード1に進みます。

モード1でモード0で指定した角度になるまで待機します。サーボモーターのデータシートによるとOperating speed(動作速度)が0.12s/60 degreeなので90度回転させる場合は0.18s以上のウェイトを置く必要があります。例では余裕を見て300msのタイマを置いています。タイムアップすると次のモードに遷移させます。

以降は操作する角度に応じてモードを追加していきます。

動作確認

動作確認用の回路図
動作確認用の回路図

サーボモーターの電源は外部の電源からDC5Vを供給しています。サーボモーターのようにモータ系の負荷になると消費電流が大きいためマイコンのDO出力では過負荷になるためです。外部電源とArduinoのGNDは同一系統にするため接続します。

マイコンのDOの出力電流は最大でも10mA程度であるため過負荷の状態が続くとマイコンが発熱し故障する可能性があるため注意が必要です。

電源をONするとArduinoからのパルス波形によってサーボモーターが回転を始めます。今回は0度(-90度)→90度(0度)→180度(90度)→90度(0度)→0度(-90度)を繰り返すようにソースコードを組みました。

回転角度を指定した後に300ms毎にウェイトを置きましたが、この時間を長くすると一時停止しながら回転するため動作の確認がしやすくなります。逆に90度の時に最低必要時間である180msを下回ると指定する角度が回転が完了しない状態で次の回転指令が上書きされるため不安定な動作になります。

スポンサーリンク

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

#include <Servo.h>
#include <MsTimer2.h>

#define SERVO_PIN 7
#define TIME_UP 0
#define TIME_OFF -1
#define BASE_CNT 10 //10msがベースタイマとなる
#define WAIT_TIM 30 //300msウェイト

Servo sg90;
uint8_t move;
int angle;
int8_t cnt10ms;
int8_t timcount;
int8_t ram;
uint8_t chk;

void mainTimer(void);
void TimerCnt(void);

void setup() {
  
  Serial.begin(115200);
  sg90.attach(SERVO_PIN,500,2400);

  MsTimer2::set(1,TimerCnt); //1msごとに関数へ遷移
  MsTimer2::start();

}

void loop() {

  mainTimer();
 
  switch (move){
  case 0: //回転指令
    ram = rand() % 10;
    chk = 80 + ram;
    sg90.write(chk); //回転角度を指定
    Serial.println(chk);
    timcount = WAIT_TIM;
    ++move;
    break;
  case 1: //タイマウェイト
    if(timcount == TIME_UP ){
      //angle = sg90.read(); 現在どの角度が指定されているか
      timcount = TIME_OFF;
      ++move;
    }
    break;
  case 2: //回転指令
    ram = rand() % 10;
    chk = 170 + ram;
    sg90.write(chk); //回転角度を指定
    timcount = WAIT_TIM;
    ++move;
    break;
  case 3: //タイマウェイト
    if(timcount == TIME_UP ){
      timcount = TIME_OFF;
      ++move;
    }
    break;
  case 4: //回転指令
    ram = rand() % 10;
    chk = 80 + ram;
    sg90.write(chk); //回転角度を指定
    timcount = WAIT_TIM;
    ++move;
    break;
  case 5: //タイマウェイト
    if(timcount == TIME_UP ){
      timcount = TIME_OFF;
      ++move;
    }
    break;
  case 6: //回転指令
    ram = rand() % 10;
    chk = 0 + ram;
    sg90.write(chk); //回転角度を指定
    timcount = WAIT_TIM;
    ++move;
    break;
  case 7: //タイマウェイト
    if(timcount == TIME_UP ){
      timcount = TIME_OFF;
      ++move;
    }
    break;
  default:
    break;
  }

  if( move >= 8){
    move = 0;
  }
}
/* callback function add */
void TimerCnt(void){
  ++cnt10ms;
}
/* Timer Management function add */
void mainTimer(void){

  if( cnt10ms >= BASE_CNT ){
    cnt10ms -=BASE_CNT; //10msごとにここに遷移する
    if( timcount > TIME_UP ){
        timcount--;
    }
  }
}

サーボモーターの角度を指定する際に0~9のランダム値を加えた角度を指定しています。毎回同じ角度でなく変化を確認するのが目的です。

関連リンク

Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方

ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方

Code Camp完全オンラインのプログラミング個人レッスン【無料体験】

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました