Arduinoを使いサーボモーターを制御出来るようになるとロボットアームや歩行ロボットなどの制御ができ電子工作の幅が広がります。
サーボモーターの制御には、PWM(Pulse Width Modulation)というパルス幅変調方式という制御方法が使われています。
そしてArduino(こちらではArduino Unoで説明していきます)でサーボモーターを動かすには、標準ライブラリで用意されている「Servoライブラリ」を使うのが一番簡単な方法となります。
このServoライブラリを使うと角度指定やパルス幅の指定によりあまりPWMについて意識しなくても12台までのサーボモーターを同時に制御して動かすことが出来るため大変便利となります。
しかしArduinoで使えるGPIOピン(入出力端子)の数はそれほど多くないため、複数のサーボモーターをArduinoに接続して占領してしまうとセンサーやスイッチ、ディスプレイなど他のデバイスを接続するための端子が足りなくなってしまいます。
そこで便利となるのが今回ご紹介するサーボドライバとなります。
Arduinoに接続して使いサーボモーターの配線は全てドライバに接続する形となるので、Arduino側で使うGPIOピンの数は少なくてすみます。
Arduinoで使えるサーボモーター用のドライバはいろいろとありますが、今回使うPCA9685サーボモータードライバはその中でも定番的なドライバになるかと思います。
このPCA9685はPWM制御(12ビット制御)で使えるI2C通信に対応したサーボモーター用のドライバとなり、これ1台で16台のサーボモーターを接続して同時に動かすことが出来ます。
また複数のLEDをPWM制御で点灯させる場合などでも使えます。
接続はI2C通信を利用すためArduino側との接続は、SCLピン(シリアルクロック)とSDAピン(シリアルデータ)の2本のみの接続で16台のサーボモーターを同時に動かすことが出来ます。
またI2Cアドレスを変えることにより最大62枚のPCA9685ドライバを連結する事ができるため、理論的には最大992台のサーボモーターを同時に制御するなんてことも可能となります。
目次
- PCA9685サーボモータードライバを使って複数のサーボモーターを同時に制御してみる!(最大16台)
PCA9685サーボモータードライバを使って複数のサーボモーターを同時に制御してみる!(最大16台)
今回の目的
サーボモーターの制御には、PWM(Pulse Width Modulation)というパルス幅変調方式という制御方法が使われています。
1周期の中にあるHIGHの時間の割合デューティー比やそのパルス幅を指定することによりサーボモーターを特定の位置(角度)まで動かすというものです。
今回PCA9685サーボドライバを使い複数のサーボモーターを動かしてみたいと思いますが、その制御にはパルス幅やPWMの話が出てきます。
サーボモーターの制御の概要に関してはこちらの記事を参考にして下さい。
Arduinoでサーボモーターを動かすには「Servoライブラリ」という標準のライブラリが用意されています。
上記図のようなパルスの生成部分をライブラリが担当して処理してくれるのでPWMに関してあまり意識することなくサーボモーターを動かすことが出来ます。
このServoライブラリを使うことにより最大12台までのサーボモーターを同時に制御し動かすことが出来ます。
Arduino Unoにサーボモーターを繋げることが出来るGPIOピンは、デジタル入出力ピンではD0~D13までの14本あり、またアナログ入力ピンA0~A5もデジタル出力ピンとして使うことが出来るので、サーボモーターを繋げることが出来るピンとしてはArduino Unoでは合計20本となります。
しかしD0ピンとD1ピンはシリアル通信で使われたり、またA4ピンとA5ピンはI2C通信で使われたりするので他のデバイスの接続を考えると実際に接続できるピンの数は少なくなります。
さらにセンサーやディスプレイなど他のデバイスを繋げようと考えると、さらにサーボモーターを接続して使えるピンの数は実質的に少なくなってしまうということですね。
例えばこちらは3Dプリンタでパーツを作成した3関節の4脚ロボットとなります。
合計12個のサーボモーターを使って動かすロボットとなります。
サーボの数が多いのでセンサーシールドを使い接続しその配線はシンプルに接続できました。
そして動作も問題なく動くものとして完成できました。
この投稿をInstagramで見る
しかし使えるデジタルピンがもう残っていない状態で、これ以上機能をもたせることがなかなか難しく・・・。
障害物の検知にセンサーなどを追加しようと考えるとデジタルピンの空きがありません。
このようにArduinoでは使えるGPIOピンの数が限られあまり多くないので、複数のサーボモーターを制御する場合はサーボドライバを使う方法が便利となります。
上記ロボットはそんなことからサーボドライバを使った構成に作り直そうと考えています。
今回使うPCA9685サーボモータードライバは、これ1台で16台までのサーボモーターを接続し同時に制御することが出来ます。
そしてI2C通信に対応したドライバとなるのでArduinoとの接続は、SCL(シリアルクロック)・SDA(シリアルデータ)のたった2本の信号線の接続のみで完結してしまいます。(VCC・GND端子も入れると計4本)
これならGPIOピンの少ないArduinoでも多くのサーボモーターを同時に動かしつつセンサーなど他のデバイスを接続してもまだまだGPIOピンの空きは残ります。
今後いろいろとカスタマイズしようと考えると非常に有効な手段となります。
PCA9685サーボモータードライバを使い複数台のサーボモーターを同時に動かすまでを今回の目標としたいと思います。
PCA9685 16チャンネルPWMサーボモータードライバ
こちらがPCA9685サーボモータードライバとなります。
16chのPWM出力が出来るドライバとなり、これ1台で16台までのサーボモーターを同時に制御することが出来ます。
サーボモーターの接続ピンは3ピン端子(Signal/Vcc/GND)となっているのでサーボ側のコネクタをそのまま挿すだけで接続できます。
I2C通信に対応したデバイスとなり、SCL・SDA・Vcc・GND端子をArduinoに接続して使う形となります。
Arduino側で使うGPIOピンは、SCLとSDAの2本だけとなるためGPIOピンの少ないArduinoでは便利となります。
I2C通信に関してはこちらの記事を参考にして下さい。
I2Cアドレスはデフォルトで0x40となっているようです。
またアドレス選択パッドをはんだブリッジする事によりI2Cアドレスの変更が可能で、62台のPCA9685を接続し最大992台のサーボモーターを同時に制御することも理論的には可能となります。
サーボ駆動用の電源は中央にあるネジターミナルから外部電源として給電する形となります。
その時の外部電源は最大6Vとなっています。
複数接続させる場合は下写真右の6ピン(GND/OE/SCL/SDA/Vcc/V+)を数珠つなぎで接続していきI2Cアドレスパッドをはんだブリッジし2段目以降のアドレスを変更する事により接続していきます。
その際の電源の供給は1段目の基板のみで大丈夫です。
PCA9685ドライバをArduinoに接続
それではPCA9685サーボモータードライバの概要が分かったところで、Arduinoとの接続に移ります。
PCA9685サーボモータードライバはI2C通信対応デバイスとなるためArduinoとの接続は非常に簡単です。
SCLピン(シリアルクロック)とSDAピン(シリアルデータ)を接続するだけです。
Arduino UnoのSCLピン・SDAピンは以下となります。
PCA9685の駆動電源は今回Arduino側から取っているのでその接続は、SCL・SDA・Vcc・GNDの計4本のみの接続で完了します。
PCA9685 | Arduino Uno |
SCL | SCL(またはA5) |
SDA | SDA(またはA4) |
Vcc | +5V端子 |
GND | GND端子 |
ライブラリのインストール
Arduinoのスケッチ(プログラム)を書く前にライブラリをインストールしておきます。
PCA9685サーボモータードライバを制御するためのライブラリとして今回、『Adafruit PWM Servo Driver library』を使用します。
Arduino IDEの[スケッチ]→[ライブラリをインクルード]→[ライブラリを管理]から[Adafruit PWM Servo]で検索すると出てくるかと思います。
また以下サイトからZIP形式でダウンロードしたものをインストールすることも出来ます。
参考 Adafruit PWM Servo Driver LibraryGithubインストールが完了したらこれを使ってスケッチを書いていきます。
PCA9685でサーボ1台を動かしてみる
それではPCA9685サーボモータードライバを使い動かしてみたいと思います。
最大16台まで同時に接続&制御出来ますが、まずは1台のサーボモーターを動かしてみようと思います。
基本的に接続するサーボの数が増えても制御方法は同じです。
接続はこのようになります。
I2C通信なので接続は簡単ですね。
PCA9685ドライバの駆動電源はArduinoから直接取っているので接続は、SCL・SDA・Vcc・GNDの計4本となります。
サーボ駆動用電源は外部電源から5Vを取ります。
単三電池6本の電池ボックスを使ったり、ブレッドボード用電源などを使い供給する形となります。
配線が完了したら次にスケッチへ移ります。
『Adafruit PWM Servo Driver library』でサーボモーターを動かす関数として「setPWM()」と「writeMicroseconds()」の2つの関数が提供されています。
writeMicroseconds()関数を使うとServo.hライブラリのようにパルス幅を直接指定できますが、リファレンスによるとPWM出力は正確ではないようなことが書かれていました。
また、setPWM()関数を使うと0~4096の範囲で対応するパルス幅を見つける必要があります。
参考 Adafruit PWMServoDriver Class ReferenceAdafruit PCA9685 PWM Library<br />いろいろ調べてみましたが、setPWM()関数をみなさん使って動かされているようですね。
個人的にはパルス幅を指定して動かせるwriteMicroseconds()関数を使った方が分かりやすいのですが・・・
両パターンでスケッチを作ってみました。
スケッチ① writeMicroseconds()関数を使って動かす
今回テストで動かすサーボモーターにはSG90を使用しました。
『Adafruit PWM Servo Driver library』を使ってサーボを動かすには先述したように、setPWM()とwriteMicroseconds()関数が使えますが、まずはwriteMicroseconds()関数を使って動かしてみます。
このようなスケッチを書いてみました。
PCA9685の0番ピンに繋いだサーボモーターを1秒間隔で0度→180度と動かし繰り返すスケッチとなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // Arduino入門編㉓ PCA9685サーボモータードライバテスト(writeMicroseconds関数使用) // https://burariweb.info #include <Wire.h> // ライブラリのインクルード #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // PCA9685のI2Cアドレスを指定 #define SERVOMIN 500 // 最小パルス幅(μs) #define SERVOMAX 2400 // 最大パルス幅(μs) int Servo_pin = 0; // サーボ接続ピンを0番に int angle; void setup() { pwm.begin(); // 初期設定 pwm.setPWMFreq(50); // PWM周期を50Hzに設定 delay(1000); } void loop() { angle = 0; angle = map(angle,0, 180, SERVOMIN, SERVOMAX); // 角度(0~180)をパルス幅(500~2400μs)に変換 pwm.writeMicroseconds(Servo_pin, angle); // サーボを動作させる delay(1000); angle = 180; angle = map(angle,0, 180, SERVOMIN, SERVOMAX); pwm.writeMicroseconds(Servo_pin, angle); delay(1000); } |
スケッチ解説
SG90 仕様
スケッチの解説の前に今回使っているSG90サーボモーターの仕様について少し書いておきます。
こちらは秋月さんのサイトで提供されていたSG90サーボモーターのデータシートとなります。
PWM周波数が50Hzでパルス幅は0.5~2.4msとなっています。
つまりパルス幅を0.5msで0度、2.4msで180度サーボが回転することになります。(または-90度から90度)
サーボモーターの概要、デューティーサイクルに関してはこちらの記事を参考にして下さい。
以上を踏まえスケッチを解説していきます。
スケッチ解説
ArduinoでI2C通信を使用するための『Wire.h』ライブラリとPCA9685を制御するための『Adafruit_PWMServoDriver.h』ライブラリをインクルードしています。
3 4 | #include <Wire.h> // ライブラリのインクルード #include <Adafruit_PWMServoDriver.h> |
次にI2Cアドレスの指定です。
このボードは0x40がデフォルトのI2Cアドレスとなっているのでそのアドレスを指定しています。(1段のみの場合はアドレス省略可)
もう1段PCA9685を追加する場合は、2段目のPCA9685をはんだパットでアドレスを変更し、
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x41);というように指定し追加するということとなります。
7 | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // PCA9685のI2Cアドレスを指定 |
次にサーボ駆動のためのパルス幅を指定しています。
使用するサーボモーターにより数値が異なりますが、SG90では次のように指定します。(単位はμs)
9 10 | #define SERVOMIN 500 // 最小パルス幅(μs) #define SERVOMAX 2400 // 最大パルス幅(μs) |
次に初期設定およびPWM周波数を設定しています。
SG90のPWM周波数は50Hzなのでこれを指定します。
118 119 | pwm.begin(); // 初期設定 pwm.setPWMFreq(50); // PWM周期を50Hzに設定 |
最後に指定した角度(0~180)をmap関数を使いパルス幅(500~2400μs)に変換してwriteMicroseconds()関数でサーボを動かしています。
Servo.hライブラリのようにパルス幅を指定して動かせるので分かりやすいかと思います。
27 28 | angle = map(angle,0, 180, SERVOMIN, SERVOMAX); // 角度(0~180)をパルス幅(500~2400μs)に変換 pwm.writeMicroseconds(Servo_pin, angle); // サーボを動作させる |
スケッチ② setPWM()関数を使って動かす
次に、同様のことをsetPWM()関数を使ってやってみます。
スケッチを一部変更しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | // Arduino入門編㉓ PCA9685サーボモータードライバテスト(setPWM関数使用) // https://burariweb.info #include <Wire.h> //ライブラリのインクルード #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // PCA9685のI2Cアドレスを指定 #define SERVOMIN 110 // 最小パルス幅(~4096の範囲) #define SERVOMAX 480 // 最大パルス幅(~4096の範囲) int Servo_Pin = 0; // サーボ接続ピンを0番に int angle; void setup() { pwm.begin(); // 初期設定 pwm.setPWMFreq(50); // PWM周期を50Hzに設定 delay(1000); } void loop() { angle = 0; angle = map(angle, 0, 180, SERVOMIN, SERVOMAX); // 角度(0~180)を4096の範囲に変換 pwm.setPWM(Servo_Pin, 0, angle); // サーボを動作させる delay(1000); angle = 180; angle = map(angle, 0, 180, SERVOMIN, SERVOMAX); pwm.setPWM(Servo_Pin, 0, angle); delay(1000); } |
スケッチで違う部分はパルス幅の指定部分です。
先程、最小パルス幅を500μs、最大パルス幅を2400μsと指定しましたがsetPWM()関数を使う場合は0~4096の範囲で指定する必要があるようです。
PCA9685ドライバは制御信号を12ビットの分解能でPWM出力します。
つまり2の12乗で0~4096の範囲で指定する必要があるようですね!
SG90サーボモーターのパルス幅は0.5ms(500μs)から2.4ms(2400μs)でした。
PWM周波数は50Hz(1/50=20ms)です。
これを上記範囲にすると、
最小パルス幅:500/20000 × 4096 = 102
最大パルス幅:2400/20000 × 4096 = 491
となり、これをサーボが駆動する動作範囲として指定しています。
少し余裕を取ってSERVOMINを110、SERVOMAXを480として指定しました。
ここが少しややこしいですね!
9 10 | #define SERVOMIN 110 // 最小パルス幅(~4096の範囲) #define SERVOMAX 480 // 最大パルス幅(~4096の範囲) |
PCA9685について解説しているサイトを見ると、サンプルスケッチにある値(SERVOMINを150・SERVOMAXを600)のまま使われているようですが・・・上記方法での計算方法あってるのかな?と少し疑問が残りますが・・・。
一般的なサーボモーターの動作範囲に合わせサンプルスケッチではSERVOMINを150・SERVOMAXを600の値となっていますが、使うサーボモーターにより調整する必要があるようですね。
こちらの動画では、この数値を徐々に変えていきサーボモーターが停止した状態の音を確認して調整されてました。
動作範囲を超えた角度指定ではサーボから「ジー」といった音が鳴ることから微調整されているようですね。(11:30あたりから)
サーボを動かすのにpwm.writeMicroseconds()と記述しパルス幅(μs)を指定した方が分かりやすいのですが、Adafruit_PWMServoDriverクラスリファレンスによると出力が正確ではないようです。
単品サーボでは問題なく動作しましたが、今後複数のサーボモーターを使い上記のようなロボットを作る場合などでは問題になってくるのでしょうかね?
このあたり、確認できていません。
よってsetPWM()関数を使ってサーボを動かす場合は、パルス幅の範囲を0~4096の範囲にする必要があるようです。
つまり動作的には、pwm.writeMicroseconds(n,500)はpwm.setPWM(n,0,102)と等しいということですね!(nは接続するサーボ番号)
同様に、pwm.writeMicroseconds(n,2400)は、pwm.setPWM(n,0,491)と等しいことになります。
16台のサーボを動かしてみる
1台のサーボモーターを動かすことができれば、サーボの数を増やしても同様に制御することが出来ます。
ArduinoとのPCA9685ドライバの接続は同じです。
PCA9685ドライバの方にサーボを増やしていくだけです。
スケッチはこのようなものを作りました。
16台のサーボモーターを順番に0度→180度、180度→0度と動かすものとなります。
やっていることは1台の時と同じです。
pwm.setPWM(n, 0, angle);の変数nで動かすサーボ番号(0~15)を指定しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | // Arduino入門編㉓ PCA9685サーボモータードライバテスト 16台のサーボを動かす // https://burariweb.info #include <Wire.h> // ライブラリのインクルード #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // PCA9685のI2Cアドレスを指定 #define SERVOMIN 110 // 最小パルス幅(~4096の範囲) #define SERVOMAX 480 // 最大パルス幅(~4096の範囲) int angle; void setup() { pwm.begin(); // 初期設定 pwm.setPWMFreq(50); // PWM周期を50Hzに設定 for(int i=0; i<=15; i++){ // 全てのサーボを90度の位置に動かす servo_move(i, 90); delay(100); } delay(1000); } void loop() { angle = 0; // 0~15番の順にサーボを0度の位置に動かす for(int i=0; i<=15; i++){ servo_move(i, angle); delay(70); } delay(500); angle = 180; // 15~0番の順にサーボを180度の位置に動かす for(int i=15; i>=0; i--){ servo_move(i, angle); delay(70); } delay(500); } // 指定角度にサーボを動かす void servo_move(int n, int angle){ angle = map(angle, 0, 180, SERVOMIN, SERVOMAX); pwm.setPWM(n, 0, angle); } |
この投稿をInstagramで見る
16台のサーボモーターを接続していますが、Arduino Unoで使っているGPIOピンはSCLとSDAの2ピンのみと少ない接続で制御できます。
これは便利ですね!
複数LEDの点灯制御にも使えます
PCA9685はサーボモータードライバという名称が付けられていますが、サーボモーター以外にも使うことが出来ます。
PWM制御が出来るドライバとなるので、このように複数LEDの点灯にも使えます。
PWM制御なのでナイトライダーみたいにLED点灯を動かしながら徐々に暗くして・・・なんていう制御もできます。
この投稿をInstagramで見る
このような複数LEDの点灯にはArduinoの多くのGPIOピンを占領してしまいますが、このドライバはI2C通信に対応しているのでSCLとSDAの2本のみの接続で多くのLEDを制御することが出来ます。
使い方により便利に使えるドライバとなります!
【追記】テスト環境で便利なケースを作りました!
テスト環境であると便利な?ケースを作ってみました!
Thingiverseからダウンロードできるのでよろしかったら使ってみて下さい。
【追記】ArduinoシールドタイプのPCA9685を試してみました!
本記事でご紹介したPCA9685ドライバボードのArduinoシールドタイプのものも試してみました。
基本的な使い方は同じですが、シールド形状なのでArduinoボードに挿し込みサーボモーター駆動用の外部電源と接続するだけで使えます。
この投稿をInstagramで見る
今回使ったアイテム
PCA9685サーボモータードライバ
I2C通信に対応したサーボドライバとなります。
1台で16サーボの制御ができ、台数を増やすことにより最大992台までのサーボモーターの制御も可能となります。
SG90サーボモーター
ホビー用途でよく使われる安価な小型サーボモーターとなります。
Arduinoなどマイコンボードを使った電子工作ではお馴染み定番のサーボモーターですね。
Arduino UNO
Arduinoはオープンソースのハードウェアなので正規品以外にも互換品が多数メーカーから販売されています。
互換品でも正規品と比べて特に問題なく使用でき数百円程度で購入が可能なのでArduino学習用としていいですね!
Arduino スターターキット
これからArduino学習を進めていくにあたりArduino UNO(互換品)やブレッドボード、ジャンパーピンなどがセットになったスターターキットが販売されています。
私はGeekcreit製のスターターキットを使っていますが、ELEGOO製のものは国内Amazonなどでも購入可能で人気があるようです。(セット内容はほぼ同じです!)
そしてELEGOOのサイトからスターターキット用サンプルスケッチのダウンロードも可能です。(Geekcreitのキットでも使えます)
参考 チュートリアルダウンロードELEGOO基本的にこれからこのセットで出来るものから紹介していこうと考えていますが、かなり多くのことが出来ます。
電子工作を始めるにはまずブレッドボードやジャンパーピン、メインとなるArduino UNOやサーボ、LEDなどの基本的なパーツがないと実際に動かすことが出来ませんが、個々にパーツを購入して回路を組んでとなるとかなりの手間がかかります。
スターターキットがあればArduinoの初歩的なことはかなりの数こなすことが出来るのでオススメです!
そこからスキルアップに伴い個別でセンサーなど必要なものを増やしていくのがいいと思います。
最後に!
今回、PCA9685サーボモータードライバを使って16台のサーボモーターを動かしてみました。
I2C通信対応のドライバとなりArduinoとの接続は簡単で占領するGPIOピンも少なくなるので多くのサーボモーターを制御する際は非常に有効な手段になるかと思います。
Adafruit PWM Servo Driver LibraryのリファレンスにPWM出力が正確ではないとの記述があったのでwriteMicroseconds()関数とsetPWM()関数を使った2パターンで動かしてみましたが、テストレベルで動かす場合正直違いが分からず・・・
4脚ロボットの作り変えが出来たらその違いに関してもご報告できればと思います。
コメントを残す