DIYモータライズドカメラスライダー(パン・チルト付き)─ Arduino制御プロジェクト
このチュートリアルでは、パン・チルトヘッド付きのモータライズドカメラスライダーの作り方を学びます。このArduinoベースのプロジェクトは100% DIYで、MDFや合板などの安価な材料を使用し、Arduino、3つのステッピングモーター、ボタン、ジョイスティックをカスタム設計PCBで制御します。それでも完成品はかなり印象的で、超スムーズなカメラ移動によりプロフェッショナルなシネマティックショットが可能です。 以下の動画をご覧いただくか、書面によるチュートリアルをお読みください。 コントローラーでカメラを手動操作できるほか、開始点と終了点を設定すればカメラが自動でその間を移動します。支持アームを使えば小型三脚にも任意の角度で取り付けられ、安定した動作が得られます。 まず3Dモデリングソフトでスライダーを設計しました。 この3Dモデルからすべての寸法を確認・ダウンロードでき、Thangsでブラウザ上でも探索可能です。 アセンブリ3DモデルをThangsからダウンロード。 スライダーレールには22mm径の銅管を使用。長さ1メートルに決定し、2本を1mにカット。銅管は酸化しやすいため金属用研磨剤で磨きます。手元になかったので歯磨き粉で代用しました。 完璧ではありませんが、違いは明確でパイプがきれいになりました。 木製ベースには21mm厚の合板2枚を接着して厚みを出し、三脚取り付けプレートのレプリカを無垢材で作って木工用ボンドとネジで固定。これでスライダーベースを三脚に簡単に取り付けられます。 レール固定には8mmネジロッドを使用。ベースに穴を開け、138mmにカットしたロッドを挿入。パイプに8mm穴を開けるのは少しトリッキーです。 鉛筆を11mm(パイプ半径)の高さに固定したジグを作り、パイプを平らな面に固定して両側からマーク。これで両側から精密に位置合わせされた穴が開けられます。シャープなネジ先でポイントをマークし、2→4→6→8mmと段階的にドリルで穴あけ。 レールをネジロッドに通し、ワッシャーとナットでベースに固定。同様に合板とネジロッドでレール端部も固定。 スライディングプラットフォームは8mm厚MDFを丸ノコでカット。3Dモデルに従ってベアリング取り付け用の8mm穴も加工。木工用ボンドとネジで組み立て(下穴→皿取り→3mmネジ)。 ベアリングシステムの組み立て。608Zベアリング(外径22mm)を使用。2つのベアリングの間にワッシャー2枚とナットを挟み、適切な間隔を確保して22mmレールと良好に接触させます。 傾斜使用時の安定性のため、プラットフォーム底面にも同様に2セットのベアリングを追加。スライディングプラットフォームは完璧に動作します。 小型三脚ではヘッドがプラットフォームの重さを支えきれないため、支持アームで安定化。木材2枚とナット・ボルトで三脚脚に固定するシンプルなクランプを製作。 クランプにボルトを設け支持アームを固定。アームにスロットを設けスライダー角度を調整可能に。6mmドリルで多数の穴を並べて開け、ヤスリで整えて直線スロットに。この支持システムは完璧に機能します。 三脚不要の場合用に脚を追加。8mm MDFで製作、糸ノコとヤスリで成形、ボンドとナット2個でスライダー両端に固定。 パン・チルトシステムをスライディングプラットフォーム上部に構築。丸ノコで3Dモデル寸法通りにカット。合板でカメラ水平用ヒンジ機構、MDFでモーターとベアリング用穴を開けたパンシステムを製作。 スライディングプラットフォームにステッピングモーターとタイミングベルトを取り付け。片側にMDFとネジ・ボルトでモーター固定、反対側にアイドラープーリーを固定しタイミングベルトを装着。2本のボルトと結束バンドでベルトをプラットフォームに固定。 パン・チルト上部パーツを組み立て。3Dモデルに従ってモーターとベアリング用穴を開け、接着・ネジ固定。 友人が80歯プーリーを2個3Dプリントしてくれました。ステッピングモーターの16歯プーリーと組み合わせて5倍の減速比を実現。 セットアップに合わせたクローズドループタイミングベルトを製作。必要長さを測ってカット、シアノアクリレート接着剤で接着しテープで補強。ゴムにはシアノアクリレートがよく効くため問題なく動作。 パン・チルトシステムの最終組み立て。チルトモーターをボルト固定、ベアリング2個をスロットにエポキシで固定。チルトプラットフォームを8mmボルトでパンプラットフォームに固定し、同時に80歯プーリーとタイミングベルトを取り付け。 ベルトが少し緩かったため、ステッピングモーターボルトの位置に小さなベアリングを追加してテンショナーとして機能させ、適切なテンションを確保。 パンモーターを固定し、水平プラットフォームの上下にベアリングを追加。ボルトを通してスラストベアリング、80歯プーリー、タイミングベルト、組み立て済みチルトヘッドを順に取り付け、ボルトで固定。これでスライダーの構造は完成です。 いよいよ電子部品の取り付けです。DIYカメラスライダーの回路図は以下の通り。 3つのNEMA 17ステッピングモーターを3つのA4988ステッピングドライバーで制御。スライダー移動はポテンショメーター(アナログ入力)、パン・チルトはジョイスティックモジュール(2つのポテンショメーター内蔵、2つのアナログ入力)で制御。自動移動速度設定用のポテンショメーター、イン/アウト位置設定用のプッシュボタン(プルアップ抵抗付き、デジタルピン接続)、リセットボタン、電源スイッチ、DCジャック、スライダー用リミットスイッチ、イン/アウト状態表示用LED2個を搭載。9Vまたは12Vで駆動可能。 必要なコンポーネント: 回路図に基づきEasyEDAでカスタムPCBを設計。接続が多いため両面基板とし、機能的で見栄えの良いPCBに仕上げました。ガーバーファイルを生成し、JLCPCB(このチュートリアルのスポンサー)で発注。 1週間後にPCB到着。品質は素晴らしく、自分の設計が製品化されるのはかなり満足感があります。 ピンヘッダーをPCBにはんだ付け(コンデンサと抵抗は直接はんだ付け)。すべての電子部品にジャンパーワイヤーをはんだ付けし、コントローラーケースに取り付けつつPCBに接続できるようにします。 コントローラーケースは4mm厚透明アクリルで製作(電子部品の美しさを可視化)。丸ノコでパネルをカット、ドリルとフォースナービットで前面パネルにボタン、ポテンショメーター、電源スイッチ、ジョイスティック用の開口部を加工。5分硬化型エポキシで組み立て、上面はボルト2本を挿入・接着し、前面パネルをナットで固定できるようにしました。 ArduinoボードとA4988ドライバーをPCBに装着。前面パネルのボタン等を固定し、適切なピンヘッダーに接続。側面パネルにDCジャックを追加、PCBをケースに収納。同パネルにステッピングモーターとリミットスイッチ接続用のジャンパーワイヤー通し穴を設けました。 ケースから出るジャンパーワイヤーをヒートシュリンクチューブで整理。最後にコントローラーと3つのステッピングモーター、リミットスイッチを接続。 電源は3.7Vリチウムイオンバッテリー3個直列(約11V)を使用。スライダー完成、完璧に動作します。 Arduinoコードを見てプログラムの仕組みを解説します。コードが長いため、セクションごとに説明を加え、最後に完全なソースコードを掲載します。 プログラムはMike McCauley氏のAccelStepperライブラリベース。複数のステッピングモーターを同時制御できる優れたライブラリです。ライブラリとMultiStepper.hをインクルード後、使用ピン定義、ステッパーインスタンス、プログラム用変数を定義。 setup()ではステッパーの初期速度設定、ピンモード定義、3つのステッパーをStepperControlインスタンスに追加。whileループでスライダーを初期位置(ホーム)に移動:リミットスイッチが押されるまで動かし、押されたら位置を0に設定。その後200ステップ戻してリミットスイッチを解除。 loop()ではまずスライダーがリミット位置(リミットスイッチまたは反対側80cm)に達していないかチェック。 ジョイスティックスイッチ押下でパン・チルト速度を上昇。 セットボタンでイン/アウト位置を設定。初回押下でイン位置を記憶しインLED点灯。 2回目でアウト位置を記憶しアウトLED点灯。 3回目で自動速度ポテンショメーターを読み取り、イン位置を配列にセットしてmoveTo()関数で各モーターの必要速度を計算、runSpeedToPosition()で自動的にイン位置へ移動。 4回目(case 3)で同様にアウト位置へ移動し、case 2に戻る。 セットボタンを0.5秒以上長押しするとcase 4が実行され、イン/アウト位置をリセットして新規設定可能に。 ジョイスティックによるパン・チルト制御。アナログ値は0〜1024、中央で約500。左に倒して600以上なら正方向、右に倒して400未満なら負方向、中央なら速度0。 ジョイスティックY軸(チルト)とスライダーポテンショメーターも同様。ポテンショメーターの場合はアナログ値に応じて速度も変化(map関数で0〜3000にマッピング)。 最後に各ステッパーのrunSpeed()を呼び出してコマンドを実行。 このArduinoプロジェクトをお楽しみいただけたら幸いです。ご質問はコメント欄で、また私のArduinoプロジェクトコレクションもご覧ください。概要



3DプリントGT2プーリーのリンク:
Thingiverseカメラスライダーの製作















回路図

PCB設計




電子部品の組み立て






DIYカメラスライダー Arduinoコード
#include <AccelStepper.h>
#include <MultiStepper.h>
#define JoyX A0 // ジョイスティックXピン
#define JoyY A1 // ジョイスティックYピン
#define slider A2 // スライダーポテンショメーター
#define inOutPot A3 // イン/アウト速度ポテンショメーター
#define JoySwitch 10 // ジョイスティックスイッチ
#define InOutSet 12 // セットボタン
#define limitSwitch 11 // リミットスイッチ
#define inLED 8 // インLED
#define outLED 9 // アウトLED
// ステッピングモーター定義 (Type:driver, STEP, DIR)
AccelStepper stepper1(1, 7, 6); // スライダー
AccelStepper stepper2(1, 5, 4); // パン
AccelStepper stepper3(1, 3, 2); // チルト
MultiStepper StepperControl; // マルチステッパー制御インスタンス
long gotoposition[3]; // 各モーターのイン/アウト位置格納用配列
int JoyXPos = 0, JoyYPos = 0, sliderPos = 0;
int currentSpeed = 100, inOutSpeed = 100;
int XInPoint = 0, YInPoint = 0, ZInPoint = 0;
int XOutPoint = 0, YOutPoint = 0, ZOutPoint = 0;
int InandOut = 0;void setup() {
stepper1.setMaxSpeed(3000); stepper1.setSpeed(200);
stepper2.setMaxSpeed(3000); stepper2.setSpeed(200);
stepper3.setMaxSpeed(3000); stepper3.setSpeed(200);
pinMode(JoySwitch, INPUT_PULLUP);
pinMode(InOutSet, INPUT_PULLUP);
pinMode(limitSwitch, INPUT_PULLUP);
pinMode(inLED, OUTPUT);
pinMode(outLED, OUTPUT);
StepperControl.addStepper(stepper1);
StepperControl.addStepper(stepper2);
StepperControl.addStepper(stepper3);
// ホーミング
while (digitalRead(limitSwitch) != 0) {
stepper1.setSpeed(3000);
stepper1.runSpeed();
stepper1.setCurrentPosition(0);
}
delay(20);
while (stepper1.currentPosition() != -200) {
stepper1.setSpeed(-3000);
stepper1.run();
}
}// 移動制限 - リミットスイッチ押下時または反対方向80cm以上で停止
while (digitalRead(limitSwitch) == 0 || stepper1.currentPosition() < -64800) {}if (digitalRead(JoySwitch) == 0) {
currentSpeed = currentSpeed + 50;
delay(200);
}switch (InandOut) {
case 0: // イン位置設定
InandOut = 1;
XInPoint = stepper1.currentPosition();
YInPoint = stepper2.currentPosition();
ZInPoint = stepper3.currentPosition();
digitalWrite(inLED, HIGH);
break; case 1: // アウト位置設定
InandOut = 2;
XOutPoint = stepper1.currentPosition();
YOutPoint = stepper2.currentPosition();
ZOutPoint = stepper3.currentPosition();
digitalWrite(outLED, HIGH);
break; case 2: // イン位置へ移動 / case 3へ
InandOut = 3;
inOutSpeed = analogRead(inOutPot);
gotoposition[0] = XInPoint;
gotoposition[1] = YInPoint;
gotoposition[2] = ZInPoint;
stepper1.setMaxSpeed(inOutSpeed);
stepper2.setMaxSpeed(inOutSpeed);
stepper3.setMaxSpeed(inOutSpeed);
StepperControl.moveTo(gotoposition);
StepperControl.runSpeedToPosition(); // 全モーターが位置に着くまでブロック
delay(200);
break; case 3: // アウト位置へ移動 / case 2へ戻る
InandOut = 2;
inOutSpeed = analogRead(inOutPot);
gotoposition[0] = XOutPoint;
gotoposition[1] = YOutPoint;
gotoposition[2] = ZOutPoint;
stepper1.setMaxSpeed(inOutSpeed);
stepper2.setMaxSpeed(inOutSpeed);
stepper3.setMaxSpeed(inOutSpeed);
StepperControl.moveTo(gotoposition);
StepperControl.runSpeedToPosition();
delay(200);
break;// ジョイスティックX - パン移動
JoyXPos = analogRead(JoyX);
if (JoyXPos > 600) {
stepper2.setSpeed(currentSpeed);
} else if (JoyXPos < 400) {
stepper2.setSpeed(-currentSpeed);
} else {
stepper2.setSpeed(0);
}// スライダーポテンショメーター
sliderPos = analogRead(slider);
if (sliderPos > 600) {
sliderPos = map(sliderPos, 600, 1024, 0, 3000);
stepper1.setSpeed(sliderPos);
} else if (sliderPos < 400) {
sliderPos = map(sliderPos, 400, 0, 0, 3000);
stepper1.setSpeed(-sliderPos);
} else {
stepper1.setSpeed(0);
}stepper1.runSpeed();
stepper2.runSpeed();
stepper3.runSpeed();完全なソースコード
/* DIY Camera Slider with Pan and Tilt Head
by Dejan Nedelkovski, www.HowToMechatronics.com
Library - AccelStepper by Mike McCauley:
https://www.airspayce.com/mikem/arduino/AccelStepper/index.html */
#include <AccelStepper.h>
#include <MultiStepper.h>
#define JoyX A0
#define JoyY A1
#define slider A2
#define inOutPot A3
#define JoySwitch 10
#define InOutSet 12
#define limitSwitch 11
#define inLED 8
#define outLED 9
AccelStepper stepper1(1, 7, 6);
AccelStepper stepper2(1, 5, 4);
AccelStepper stepper3(1, 3, 2);
MultiStepper StepperControl;
long gotoposition[3];
int JoyXPos = 0, JoyYPos = 0, sliderPos = 0;
int currentSpeed = 100, inOutSpeed = 100;
int XInPoint = 0, YInPoint = 0, ZInPoint = 0;
int XOutPoint = 0, YOutPoint = 0, ZOutPoint = 0;
int InandOut = 0;
void setup() {
stepper1.setMaxSpeed(3000); stepper1.setSpeed(200);
stepper2.setMaxSpeed(3000); stepper2.setSpeed(200);
stepper3.setMaxSpeed(3000); stepper3.setSpeed(200);
pinMode(JoySwitch, INPUT_PULLUP);
pinMode(InOutSet, INPUT_PULLUP);
pinMode(limitSwitch, INPUT_PULLUP);
pinMode(inLED, OUTPUT);
pinMode(outLED, OUTPUT);
StepperControl.addStepper(stepper1);
StepperControl.addStepper(stepper2);
StepperControl.addStepper(stepper3);
while (digitalRead(limitSwitch) != 0) {
stepper1.setSpeed(3000);
stepper1.runSpeed();
stepper1.setCurrentPosition(0);
}
delay(20);
while (stepper1.currentPosition() != -200) {
stepper1.setSpeed(-3000);
stepper1.run();
}
}
void loop() {
while (digitalRead(limitSwitch) == 0 || stepper1.currentPosition() < -64800) {}
if (digitalRead(JoySwitch) == 0) {
currentSpeed = currentSpeed + 50;
delay(200);
}
if (digitalRead(InOutSet) == 0) {
delay(500);
if (digitalRead(InOutSet) == 0) { InandOut = 4; }
switch (InandOut) {
case 0: InandOut = 1; XInPoint = stepper1.currentPosition(); YInPoint = stepper2.currentPosition(); ZInPoint = stepper3.currentPosition(); digitalWrite(inLED, HIGH); break;
case 1: InandOut = 2; XOutPoint = stepper1.currentPosition(); YOutPoint = stepper2.currentPosition(); ZOutPoint = stepper3.currentPosition(); digitalWrite(outLED, HIGH); break;
case 2: InandOut = 3; inOutSpeed = analogRead(inOutPot); gotoposition[0] = XInPoint; gotoposition[1] = YInPoint; gotoposition[2] = ZInPoint; stepper1.setMaxSpeed(inOutSpeed); stepper2.setMaxSpeed(inOutSpeed); stepper3.setMaxSpeed(inOutSpeed); StepperControl.moveTo(gotoposition); StepperControl.runSpeedToPosition(); delay(200); break;
case 3: InandOut = 2; inOutSpeed = analogRead(inOutPot); gotoposition[0] = XOutPoint; gotoposition[1] = YOutPoint; gotoposition[2] = ZOutPoint; stepper1.setMaxSpeed(inOutSpeed); stepper2.setMaxSpeed(inOutSpeed); stepper3.setMaxSpeed(inOutSpeed); StepperControl.moveTo(gotoposition); StepperControl.runSpeedToPosition(); delay(200); break;
case 4: InandOut = 0; digitalWrite(inLED, LOW); digitalWrite(outLED, LOW); delay(1000); break;
}
}
JoyXPos = analogRead(JoyX);
if (JoyXPos > 600) stepper2.setSpeed(currentSpeed);
else if (JoyXPos < 400) stepper2.setSpeed(-currentSpeed);
else stepper2.setSpeed(0);
JoyYPos = analogRead(JoyY);
if (JoyYPos > 600) stepper3.setSpeed(currentSpeed);
else if (JoyYPos < 400) stepper3.setSpeed(-currentSpeed);
else stepper3.setSpeed(0);
sliderPos = analogRead(slider);
if (sliderPos > 600) { sliderPos = map(sliderPos, 600, 1024, 0, 3000); stepper1.setSpeed(sliderPos); }
else if (sliderPos < 400) { sliderPos = map(sliderPos, 400, 0, 0, 3000); stepper1.setSpeed(-sliderPos); }
else stepper1.setSpeed(0);
stepper1.runSpeed();
stepper2.runSpeed();
stepper3.runSpeed();
}
製造プロセス
- Bluetooth対応 Arduino制御 モータライズド カメラ スライダー 〜滑らかなシネマティック撮影を実現〜
- Arduinoで作るモニター用Ambilightシステム:没入感アップの自作ガイド
- Python連携で信頼性向上: Arduino RFID勤怠管理システム
- Arduinoとスマホで作るスマート電圧計 – 簡単DIYプロジェクト
- ArduinoとNokia 5110ディスプレイで自作電圧計:ステップバイステップガイド
- Arduino Nanoと128x64 OLEDで実行するセルラーオートマトン「ライフゲーム」
- Arduinoで高速・高精度RPM測定 – レーザーとIRセンサーによる新アルゴリズム
- Arduino NanoとRDA5807Mで作るコンパクトFMラジオ
- ArduinoとGoogleスプレッドシート連携 リアルタイムRFID勤怠管理システム
- Arduinoで楽器演奏:音階生成のステップバイステップガイド
- Arduino UNOで作る信頼性の高いスマートエネルギーモニター – ステップバイステップガイド