任意のDCモーターを360°連続回転カスタムサーボに変換するステップバイステップガイド
概要
このチュートリアルでは、任意のDCモーターをスタンドアローンのカスタムサーボモーターに変換する方法を学びます。通常のサーボが180°または270°の可動範囲に限定されるのに対し、このカスタムサーボは無制限の360°連続回転が可能で、さらに回転範囲を任意の値に調整できます。センターポイント(中立位置)も同時に調整可能です。
感度(応答速度)調整機能も搭載。入力モードは3種類:
- アナログ電圧入力 / ポテンショメーター
- RC送信機
- シリアルポート(PC/ノートPCのシリアルモニターから角度値入力)
シリアルモニターからの値入力とRC送信機による手動操作を同時に行うことも可能。サーボは常に現在位置を把握し、シリアルモニターで確認できます。
さらに連続回転モードでは、無限回転しながら位置を追跡可能。シャフトを任意の角度(無限回転数含む)へ移動指令できます。
これら全てを実現するのが、12ビットエンコーダー「AS5600磁気ロータリーポジションセンサー」とDCモーター駆動用PID制御です。
独自マイコンと必要回路を全て搭載したカスタムサーボモーターコントローラーボードを設計。ボードを出力シャフト中心に配置(シャフトに特定マグネット装着)、定格3.5Aまでの任意サイズDCモーターを接続、12V電源供給するだけで、上記全機能を持つスタンドアロンサーボモーターが完成します。
サーボモーターの動作原理、クローズドループ制御、PID制御、カスタムPCB/ギアボックス設計、コード解説まで全工程を解説します。
サーボモーターの動作原理
一般的なRCサーボを分解すると:小型DCモーター、コントローラーボード、ポテンショメーター、3線接続(電源2線+信号1線)、減速/増トルク用ギアが内蔵されています。ポテンショメーターが出力シャフトに連結され位置センサーとして機能。コントローラーは入力信号(目標位置)とポテンショメーターのフィードバック(実位置)を比較し、エラーを処理してモーターを目標位置まで駆動。これがクローズドループ制御システムです。
カスタムサーボモーターの作り方
より大型のDCモーターで同じクローズドループシステムを実装するには、出力シャフトに何らかの形で位置センサーを取り付け、マイクロコントローラーでDCモーターを駆動すればよいです。
位置センサーとして最もシンプルなのはRCサーボと同じポテンショメーターですが、回転範囲が270°に限定されるためサーボの可動範囲も制限されます。マルチターンポテンショメーターならより広い範囲/分解能が得られますが、やはり回転数に限界があります。
無制限の回転範囲が必要ならエンコーダーを使用します。エンコーダーはシャフトの角度位置を無限回転で追跡できる電気機械デバイス。インクリメンタル/アブソリュート、光学/磁気/容量式など様々なタイプがあり、それぞれ長所短所があります。
AS5600エンコーダー - 磁気ロータリーポジションセンサー
磁気エンコーダーであるAS5600を採用。極めてコンパクトで実装容易、高精度/高分解能。内蔵ホール効果センサーが磁場方向の変化を検知。出力シャフトにマグネットを取り付け、チップから0.5-3mmの距離に配置するだけ。シャフト/マグネットが回転するとホール効果センサーが磁場変化を捉え、内蔵12ビットA/Dコンバーターで4096位置/回転(360°)を出力。角度変化0.0878°まで検出可能。低コストで入手しやすく、カスタムサーボに最適です。
他に必要なのはマイクロコントローラーとDCモータードライバー。DRV8871(ピーク3.5A対応)とATmega328(表面実装版、DIP版よりコンパクト)を選定。スタンドアローン動作可能な最小限のカスタムPCBに全て収めることを目標としました。
カスタムサーボモーター回路図
部品表
- AS5600磁気エンコーダー ………………… Amazon / AliExpress
- DRV8871 DCモータードライバー ………… Amazon / AliExpress
- ATmega328p-AU ……………………………… Amazon / AliExpress
- 16MHz水晶発振子 …………………………… Amazon / AliExpress
- AMS1117 5Vレギュレーター ……………… Amazon / AliExpress
- 3386P角型トリマーポテンショメーター … Amazon / AliExpress
- 0805コンデンサーキット …………………… Amazon / AliExpress
- 12V DCモーター ~50RPM ………………… Amazon / AliExpress
注: アフィリエイトリンクを含みます。
ATmega328と推奨最小構成(16MHz発振子、コンデンサー、抵抗)。AMS1117で12V→5V降圧。AS5600推奨回路(コンデンサー2個、I2C用プルアップ抵抗2個)。DRV8871は電流制限抵抗1個とデカップリングコンデンサー2個。2つのトリマーポテンショメーターをアナログ入力に接続(回転範囲調整用、感度調整用)。センターポイント設定用タクトスイッチ、2way DIPスイッチで動作モード選択。入力用ピンヘッダー(アナログ電圧入力またはRC受信機からのデジタルPWM入力、5V、GND)。プログラミング用SPI/シリアルポートピンヘッダー。
回路ワークフロー
- 入力(目標角度位置)を2ピンで受信:アナログ電圧(ポテンショメーター)またはデジタルPWM(RC受信機)
- マイコン内部で入力とAS5600検出実位置を比較(I2C通信)
- エラー計算し、PID制御でDRV8871へPWM信号出力、DCモーターを目標位置まで駆動
- 全回路12V駆動、AMS1117がマイコン等5V部品へ給電
PCB設計
回路図に基づき可能な限り小型化、40×40mmに収めました。エンコーダーを裏面中央に配置し、出力シャフト中心と容易にアラインメント可能。他部品は表面実装でエンコーダー/シャフトと干渉しないよう配置。
PCBWayで発注:ガーバーファイルアップロード、プロパティ選択、適正価格。4層基板(中間層GND、コスト若干増)。デフォルトから色ホワイト、表面処理イマージョンゴールド(無料なら受け入れ)のみ変更。ガーバーファイルはPCBWayプロジェクト共有からダウンロード・直接発注可能。
数日で到着。品質良好、設計通り、イマージョンゴールド仕上げ。SMD部品ハンダ付け:インジケーターLED、コンデンサー、抵抗から開始。初SMDハンダ付けでかなり苦戦。最も困難だったのはATmega328(ピンが微小で密集)。AS5600裏面実装、スルーホール部品(DIPスイッチ、ポテンショメーター、ターミナルブロック、ピンヘッダー)は容易。最終的な外観はまずまずです。
カスタムサーボ3Dモデル
Onshapeでギアボックス設計。DCモーターに依存する設計で、コントローラーボードと組み合わせて任意サイズのDCモーターが使用可能。ここでは37mm径、内蔵ギアボックス出力50RPMのDCモーターを使用。50RPMはサーボとして良好だが、より高トルクを得るため3倍減速ギアボックスを追加。ヘリンボーンギア採用(効率的、3Dプリント容易)。DCモーターと目標出力速度に応じて自由にギアボックス設計可能。
コントローラーボードをギアボックス背面に配置、出力シャフト中心に完璧にアラインメント。DCモーターシャフトを直接出力として使う場合は1:1ギアセットでシャフト位置を正しく追跡。ベルト駆動も選択可能。無限の設計自由度があります。
3DモデルとSTLファイルダウンロード
Onshapeでブラウザ閲覧・探索可能(無料アカウントで利用可)。3Dモデル、STLファイルは以下からダウンロード:STEPファイル、STLファイル(3Dプリント用)。
カスタムサーボ組み立て
3DプリントパーツとM3ボルト/スレッドインサート、ベアリングで組み立て。
- DCモーターをベースプレートにM3×8mmボルトで固定。
- 2つのギア設置:小ギアをモーターシャフトへ、大ギアをサーボ出力とする。出力シャフトは2分割構成:片側にギア接続用、反対側にサーボ出力側への取り付け用スレッドインサート。小ギアにもスレッドインサートでグリブネジ固定用。
- ヘリンボーンギアは同時にスライド挿入しないと噛み合わない(順次挿入不可)。グリブネジで小ギアをモーターシャフト固定。12V印加でギアセット動作確認。
- サイドパネル、出力シャフト用ボールベアリング、トップカバーでギアボックス完成。バックプレートにM3スレッドインサート、M3×20mmボルトで全体固定。再テストOK。出力シャフト背面回転部にAS5600追跡用マグネット挿入。
- コントローラーボードをM2ボルト/ナットでギアボックス固定。AS5600とマグネットが完璧にアラインメント。
- 重要:マグネットの着磁方向。軸方向着磁か径方向着磁かにより、AS5600 ICに対して垂直または平行に配置する必要あり。最初は方向が合わず、マグネット向きを変更して対応。
- DCモーター線をハンダ付け、ターミナルブロックでコントローラー接続。電源線もターミナルブロック経由で5.5mm DCコネクター接続。完成。
コントローラープログラミング
ATmega328pにブートローダー書き込み必須(ブートローダーなしではコードを理解不能)。
ブートローダー書き込み
- Arduinoボード(ここではArduino Nano)を用意。
- SPI通信でArduinoとコントローラーボードのSPIピン接続。
- Arduino IDEで「ArduinoISP」スケッチ例を開きNanoへ書き込み。Nanoがブートローダー書き込み機能を持つ。
- ツールメニュー→書き込み装置「Arduino as ISP」選択→「ブートローダーを書き込み」クリック。
- 書き込み中NanoのLEDが激しく点滅し、成功すれば完了。
コード書き込み
USB-UARTインターフェースモジュールでコード書き込み。コントローラーボードに専用ピンあり。AS5600ライブラリとPIDライブラリをArduino IDEライブラリマネージャーからインストール後、書き込み実行。
完成。ポテンショメーター接続でテスト。※アナログ入力はコントローラーボードの「S」ピンへ(設計時に「A」ピンと誤配線)。DIPスイッチでアナログ入力モード選択、電源投入でポテンショメーターによる位置制御動作確認。DCモーターからサーボモーターへの変換成功。
ソースコード
/* Custom-built Servo Motor - Arduino Code by Dejan, www.HowToMechatronics.com
Libraries: AS5600 encoder: https://github.com/RobTillaart/AS5600
PID controller: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h */
#include "AS5600.h"
#include "Wire.h"
#include
AS5600 as5600; // use default Wire
double Pk1 = 2; // 到達速度
double Ik1 = 0;
double Dk1 = 0.025;
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Pk1, Ik1, Dk1, DIRECT);
#define motor_IN1 5
#define motor_IN2 6
#define ch1 2
#define centerSet 7
#define inputSwitch 3
#define modeSwitch 4
int ch1Value;
int encoderValue, inputValue, pwmValue;
String inString = "";
int centerAngle = 2047; // 180度
int angleDifference = 0;
int angleValue = 0;
int leftLimit = 30;
int rightLimit = 4067;
int rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
int quadrantNumber = 2;
int previousQuadrantNumber = 3;
int numberOfTurns = 0;
float totalAngle = 0;
int error = 0;
char incomingByte = 0;
int intInput = 0;
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("AS5600_LIB_VERSION: ");
Serial.println(AS5600_LIB_VERSION);
Wire.begin();
pinMode(motor_IN1, OUTPUT);
pinMode(motor_IN2, OUTPUT);
pinMode(centerSet, INPUT_PULLUP);
pinMode(inputSwitch, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(-255, 255);
myPID.SetSampleTime(20);
}
void loop() {
encoderValue = as5600.readAngle(); // エンコーダー値読み取り - 現在位置
// 連続回転モード
if (digitalRead(modeSwitch) == 0) {
// シリアルモニターから目標角度入力
while (Serial.available() > 0) {
int inChar = Serial.read();
if (isDigit(inChar)) {
inString += (char)inChar;
}
if (inChar == '\n') {
Setpoint = inString.toInt(); // セットポイント = 目標角度
inString = "";
}
}
if (digitalRead(inputSwitch) == 0) {
// ポテンショメーター入力
inputValue = analogRead(A0);
if (inputValue < 400) Setpoint = Setpoint - 0.3;
if (inputValue < 300) Setpoint = Setpoint - 0.3;
if (inputValue < 200) Setpoint = Setpoint - 0.3;
if (inputValue > 600) Setpoint = Setpoint + 0.3;
if (inputValue > 700) Setpoint = Setpoint + 0.3;
if (inputValue > 800) Setpoint = Setpoint + 0.3;
} else if (digitalRead(inputSwitch) == 1) {
// RC受信機入力
inputValue = pulseIn(ch1, HIGH, 30000);
if (inputValue < 1450) Setpoint--;
if (inputValue < 1350) Setpoint--;
if (inputValue < 1250) Setpoint--;
if (inputValue < 1150) Setpoint--;
if (inputValue > 1550) Setpoint++;
if (inputValue > 1650) Setpoint++;
if (inputValue > 1750) Setpoint++;
if (inputValue > 1850) Setpoint++;
}
// エンコーダーRAW値を角度値に変換、象限判定で回転数追跡
angle = encoderValue * 0.087890625;
if (angle >= 0 && angle <= 90) quadrantNumber = 1;
if (angle >= 90 && angle <= 180) quadrantNumber = 2;
if (angle >= 180 && angle <= 270) quadrantNumber = 3;
if (angle >= 270 && angle <= 360) quadrantNumber = 4;
if (quadrantNumber != previousQuadrantNumber) {
if (quadrantNumber == 1 && previousQuadrantNumber == 4) numberOfTurns++;
if (quadrantNumber == 4 && previousQuadrantNumber == 1) numberOfTurns--;
previousQuadrantNumber = quadrantNumber;
}
if (totalAngle >= 0) totalAngle = (numberOfTurns * 360) + angle;
else totalAngle = (numberOfTurns * 360) + angle;
Input = totalAngle; // PID入力値
}
// 制限付き回転モード
else if (digitalRead(modeSwitch) == 1) {
rangeAdjustment = analogRead(A1);
leftLimit = 0 + 30 + rangeAdjustment;
rightLimit = 4097 - 30 - rangeAdjustment;
if (digitalRead(inputSwitch) == 0) {
// アナログ入力 - ポテンショメーター
inputValue = analogRead(A0);
if (inputValue < 15) inputValue = 15;
if (inputValue > 1008) inputValue = 1008;
Setpoint = map(inputValue, 15, 1008, -255, 255);
} else if (digitalRead(inputSwitch) == 1) {
// デジタル入力 - RC送信機
inputValue = pulseIn(ch1, HIGH, 30000);
Setpoint = map(inputValue, 1000, 2000, -255, 255);
}
// センターアngle設定
if (digitalRead(centerSet) == LOW) {
centerAngle = encoderValue;
angleDifference = 2047 - encoderValue;
delay(1000);
}
// 実測値をセンターポイント基準でオフセット調整
if (centerAngle < 2047) {
angleValue = encoderValue + angleDifference;
if (encoderValue < 4097 && encoderValue > (4096 - angleDifference)) {
angleValue = encoderValue - 4097 + angleDifference;
}
}
if (centerAngle > 2047) {
angleValue = encoderValue + angleDifference;
if (encoderValue >= 0 && encoderValue < abs(angleDifference)) {
angleValue = encoderValue + 4097 + angleDifference;
}
} else if (centerAngle == 2047) {
angleValue = encoderValue;
}
Input = map(angleValue, leftLimit, rightLimit, -255, 255); // PID入力値
}
// 感度調整
Pk1 = analogRead(A2) * 0.002;
myPID.SetTunings(Pk1, Ik1, Dk1);
myPID.Compute(); // PID演算
// 右回転
if (Output > 1) {
pwmValue = Output;
if (pwmValue < 30 && pwmValue > 5) pwmValue = pwmValue + 30;
if (pwmValue <= 5) pwmValue = 0;
digitalWrite(motor_IN1, LOW);
analogWrite(motor_IN2, pwmValue);
}
// 左回転
else if (Output < 1) {
pwmValue = abs(Output);
if (pwmValue < 30 && pwmValue > 5) pwmValue = pwmValue + 30;
if (pwmValue <= 5) pwmValue = 0;
analogWrite(motor_IN1, pwmValue);
digitalWrite(motor_IN2, LOW);
}
// 停止
else if (Output > -1 && Output < 1) {
pwmValue = 0;
digitalWrite(motor_IN1, LOW);
digitalWrite(motor_IN2, LOW);
}
}
コード概要
ループ冒頭でエンコーダー値読み取り。連続回転モード(modeSwitch=LOW)ではシリアルモニターからの数値入力をセットポイントとして受け付け。入力モードがポテンショメーターならアナログ値読み取り、値の大小でセットポイントを微調整。RC受信機ならパルス幅読み取りで同様に微調整。RAWエンコーダー値を角度変換し、象限判定で回転数(numberOfTurns)をカウント。totalAngleをPIDのInputとする。
制限付き回転モード(modeSwitch=HIGH)では、トリマーポテンショメーター(A1)で回転範囲調整(leftLimit/rightLimit)。アナログ入力ならポテンショメーター値を-255〜255にマッピングしてセットポイントに。RC入力ならパルス幅を同様にマッピング。タクトスイッチ(centerSet)長押しで現在位置を新センターポイントとして記録(angleDifference計算)。実測エンコーダー値をangleDifferenceでオフセット補正し、補正値をleftLimit/rightLimit範囲で-255〜255へマッピングしてPID入力とする。トリマーポテンショメーター(A2)でPゲイン調整、PID演算実行、出力値でPWM駆動(デッドバンド補正付き)。
PIDゲイン初期値:P=2, I=0, D=0.025。コードは最適化の余地あり。SMDハンダ付けの難しさ、PCB配線ミスなどトラブルシューティング覚悟で挑戦を。初回で動かず、PCB再発注・数回試行で動作達成。
この記事セクションはまだ構築中です。後で再度チェックしてください…。
製造プロセス
- マイクロホン製造の全工程:ウェハー製造からパッケージングまで
- コンベアシステム完全ガイド:仕組み、種類、導入メリット
- CNC加工 vs 3Dプリント:違いを徹底比較
- 黒板:中世の角板から現代のホーローへ
- 現代ブラジャーの完全な進化と生産
- OscPocketO - コンパクトなArduinoシンセサイザー&ドラムマシン
- 電子インク:仕組み、歴史、未来応用
- Microsoft Teams用カスタムミュートボタン:リモート会議を快適に
- START:PS2キーボード、LCD、Ethernet、リモートシェル搭載のスタンドアロンArduinoターミナル
- フライスと旋削の統合:マルチタスキングマシンで効率向上
- Arduinoオーディオ周波数検出器 – 高感度サウンドモジュールで最大音量ピークの周波数を測定