Arduino UNOとAdafruit PWMシールドでサーボを精密キャリブレーション
部品と材料
| 部品名 | 数量 | 備考 |
|---|---|---|
| Arduino UNO | 1 | |
| Adafruit PWMサーボドライバーシールド | 1 | |
| M3ボルト | 8 | |
| M3ワッシャー | 8 | |
| LM2596 DC-DC 降圧コンバーター | 1 | |
| 赤色PLAフィラメント | 1 | 3Dプリント用 |
| 白色PLAフィラメント | 1 | 3Dプリント用 |
| 180度透明プロトラクター(分度器) | 1 | |
| ロータリーポテンショメーター(汎用) | 1 | |
| 9gサーボモーター | 1 |
必要な工具と機器
- 3Dプリンター(汎用)
アプリとオンラインサービス
- Arduino IDE
- Autodesk Fusion 360(3Dモデリング用)
プロジェクト概要
以前のHackster投稿で、同一ロットの複数サーボに同じPWM信号を送っても、それぞれの回転角度が大きく異なることを確認しました。下の写真は、すべてのサーボを最も反時計回りの位置からスタートさせ、同一PWM信号を送ったときのばらつきです。

なぜArduino標準のサーボライブラリを使わないのか?
Adafruit PWMサーボドライバーを使えば、I2Cの2ピンだけで複数のサーボを個別に制御できます。Arduino標準のServoライブラリを使わない理由は主に2つです。
- ピンをサーボの数だけ専有せず、I2Cの2ピンで済む
- 標準ライブラリでサーボをアタッチして0度指令を出すと、機械的リミットまで回転してギアが削れる音がすることがある
使用している9gサーボは安価で高精度ではないですが、歩行ロボット用により予測可能で正確な動作を引き出したいと考えました。
ホビーサーボをより正確に制御するには?
各サーボの個体差を確認したことで、「ある角度に動かすために必要なPWM値」を個別に調べるキャリブレーション装置を作ることにしました。具体的には:
- サーボの出力軸をプロトラクターの中心に合わせ、回転角を目視で読み取れるようにする
- ポテンショメーターをArduinoのアナログ入力(A0)に接続し、ツマミを回してPWM値を可変しながらサーボ角度を調整
- Arduino IDEのシリアルモニターに出力されるPWM値を手動で記録
このキャリブレーションでもAdafruit PWMドライバーを使用します。最終プロジェクトで同じドライバーを使うため、実運用環境と同じ条件で校正するためです。

装置の製作
Autodesk 123Dで設計したパーツを3Dプリントし、M3ボルトとワッシャーで組み立てました。取り付け穴は手持ちの部品に合わせて調整しています。
電子部品の接続:
- ポテンショメーターの中央端子 → Arduino A0、両端 → GNDと5V
- Adafruit PWMシールドをArduinoに装着
- LM2596降圧コンバーターで9V電源を5Vに変換
- 9gサーボをシールドのスロット0に接続
- スケッチを書き込み
完成品の写真を以下に示します。左上のツマミを回すとサーボが動き、シリアルモニターにその瞬間のPWM値が表示されます。


装置で何がわかるか?
手持ちのサーボで実測した結果です。サーボを時計回り限界まで回し、出力アームをプロトラクターの180度目盛りより少し先にセット。そこからポテンショメーターで0度、10度、20度…と10度刻みで180度まで合わせ、各角度でのPWM値を記録しました。

グラフ化すると、PWM値と角度の間に強い線形関係があることがわかります。

このサーボ固有の「角度⇔PWM」対応表が得られました。他のサーボでも傾向は似ていますが、完全に一致しません。
このデータを活用するには2つのアプローチがあります:
- ルックアップテーブル方式:角度とPWMの組み合わせを配列に保存し、目的の角度に最も近いPWM値を参照して送信。欠点は10度刻みなど離散的な角度しか指定できないこと。
- 線形回帰による式化:データセットから一次回帰式を求め(このサーボでは
PWM = 2.35 × 角度 + 159.4)、任意の角度をパラメータとして渡せば必要なPWMをプログラムで計算。連続的な角度指定が可能。
どちらにしても、キャリブレーション前より確実に正確かつ再現性のある制御が可能になります。全サーボを個別に校正するのは手間ですが、プロジェクトの精度向上のために十分価値があります。なお、キャリブレーション時に取り付けたサーボアーム(ホーン)を外さずに使うことが前提です。
次期バージョンへの改善案
いくつかサーボを校正してみて、次の改善点が見えてきました:
- サーボの着脱をマグネットクリップなどでワンタッチ化
- Arduinoと電源の配置を見直して小型化
- 9V電池と降圧コンバーターの間に電源スイッチを追加
- 3Dプリントパーツ数を削減
- プロトラクター目視読み取りの代わりに、特定角度でセンサーが検知してArduinoにフィードバックする仕組み(視差誤差の排除)
- LCDディスプレイを搭載し、PC接続なしで結果を確認できるようにする
まとめ
ホビーサーボは安価で高精度ではないですが、多くの用途では十分です。しかし、もう少し精度と再現性を高めたい場合、このキャリブレーション装置が役立ちます。自分のプロジェクトに合わせて改良してみてください。
コード
サーボキャリブレーター用スケッチ(C/C++)
#include <Adafruit_PWMServoDriver.h>
#define analogIn A0
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
int inputValue = 0;
int tmpPwmValue = 0;
void setup() {
Serial.begin(9600);
pwm.begin();
pwm.setPWMFreq(60);
}
void loop() {
inputValue = analogRead(analogIn); // 0-1023
// 観察により、サーボのPWM最小/最大はだいたい100-612の範囲
int pwmValue = (int)(100 + (inputValue / 2));
pwm.setPWM(0, 0, pwmValue);
// 重複表示を避ける
if (pwmValue != tmpPwmValue) {
Serial.print("Potentiometer Input = ");
Serial.print(inputValue);
Serial.print(", PWM = ");
Serial.println(pwmValue);
}
tmpPwmValue = pwmValue;
delay(15);
}
カスタムパーツとエンクロージャー
3Dプリント用パーツのリポジトリ:
GitHub - ServoCalibrator
製造プロセス
- Raspberry Piでリアルタイムパン/チルト顔追跡 - 実践ガイド
- Walbi:ArduinoとLX-16Aサーボで作る安定二足歩行ロボット
- Arduino Yun搭載 IoT対応 5自由度ロボットアーム(Blynk制御)
- ポリ乳酸(PLA)3Dプリンティング:プロフェッショナルのための総合ガイド
- PLA vs ABS vs ナイロン:3Dプリンティングフィラメント選定ガイド
- 3Dプリント材料 PLA vs ABS:主要違いと使い分け完全ガイド
- PLAは本当にリサイクル・生分解可能か? 真実と実践的対応
- PLAは水に溶ける?分解条件と防水化の実践テクニック
- PLAフィラメントは電気を通す?導電性バリエーションと造形時の注意点
- PLA導電性の理解:3Dプリントフィラメントの電気的特性
- DCドライブへの切り替え:産業モーション制御におけるACサーボの信頼性ある代替案