サーボを動かす方法

2022/12/23に公開


0度と180度を行き来する

仕様確認

SG90 がよく使われる。

https://akizukidenshi.com/catalog/g/gM-08761/

項目
PWMサイクル 20ms
制御パルス 0.5ms 〜 2.4ms
制御角 ±約90°(180°)
配線 茶:GND 赤:電源 橙:制御信号
動作速度 0.1秒/60度
動作電圧 4.8 〜 5 V

ここからわかること。

  • 一周期が 20ms (サーボが360度回転するのにかかる時間ではない)
  • そのうちの 0.5ms だけ HIGH にすると0度になる
  • そのうちの 2.4ms だけ HIGH にすると180度になる
  • 電圧は 5 V なので Arduino の 5V をそのまま使える

角度と時間の関係

角度 ms μs
0 0.5 500
45 0.975 975
90 1.45 1450
135 1.925 1925
180 2.4 2400
  • 0.5ms 〜 2.4ms が 0〜180度 に対応する
  • なので時間(ms) は 0.5 + (2.4 - 0.5) / 180.0 * 角度 で求まる

配線

場所
10 PWM対応のピンならどこでもいい
5V
茶色 GND

抵抗もブレッドボードもいらない。

0度に設定する例

void setup() {
  pinMode(10, OUTPUT);
}

void loop() {
  digitalWrite(10, HIGH);
  delayMicroseconds(500);
  digitalWrite(10, LOW);
  delayMicroseconds(20000 - 500);
}

HIGH を 500μs 続けたあとLOW を 20000μs - 500μs 続ける。20000 はPWMサイクル 20ms のこと。仮に500を2400にすると180度になる。

0度と180度を行き来する例 (間違い)

void setup() {
  pinMode(10, OUTPUT);
}

void loop() {
  digitalWrite(10, HIGH);
  delayMicroseconds(500);
  digitalWrite(10, LOW);
  delayMicroseconds(20000 - 500);
  delay(1000);

  digitalWrite(10, HIGH);
  delayMicroseconds(2400);
  digitalWrite(10, LOW);
  delayMicroseconds(20000 - 2400);
  delay(1000);
}

最初このように書いてしまってはまった。PWM は繰り返さないといけない。この例だと単発パルスなのでサーボは正しく動いてくれない。最初の例が動いていたのはたまたま loop() が繰り返されているからだった。

0度と180度を行き来する例 (正しい)

void setup() {
  pinMode(10, OUTPUT);
}

void loop() {
  for (int i = 0; i < 3000000/20000; i++) {
    digitalWrite(10, HIGH);
    delayMicroseconds(500);
    digitalWrite(10, LOW);
    delayMicroseconds(20000 - 500);
  }
  delay(1000);

  for (int i = 0; i < 3000000/20000; i++) {
    digitalWrite(10, HIGH);
    delayMicroseconds(2400);
    digitalWrite(10, LOW);
    delayMicroseconds(20000 - 2400);
  }
  delay(1000);
}

連続パルスにすると目的の角度まで正しく移動する。ただしどれだけ繰り返せばいいのかはよくわからない。上で例では仮に3秒(=3000000μs)とした。3秒は目的の角度まで移動するには十分だろうと考えて勝手に決めた値である。本当は仕様にある60度あたり0.1秒で計算しないといけないのかもしれない。そう考えて実際やってみたら動かなかった。180度が0.3秒は速すぎるのでなにか勘違いしているかもしれない。あとからこのコードを見ても何をやってるかわからなそう。

ライブラリを使う

#include <Servo.h>

Servo servo;

void setup() {
  servo.attach(10);
}

void loop() {
  servo.write(0);
  delay(1000);

  servo.write(180);
  delay(1000);
}

なんと角度を指定するだけでよくなった。ここまで抽象化してくれるならメソッド名は angle とかにしといてほしかった(小声)。どれだけPWMを繰り返すかもうまく制御してくれているっぽい。

サーボが使えると何ができる?

SwitchBotのように物理的なスイッチが押せる。タッチペンと連動すればスマホの物理的な操作を自動化してテストできる。

Discussion