Arduino NanoとMG996Rサーボで作るPC制御精密ロボットアーム
必要な部品と材料
| Arduino Nano R3 | ×1 | |
| サーボモーター Tower Pro MG996R | ×4 |
使用するアプリとオンラインサービス
- Microsoft Visual Studio 2015(C# Windowsアプリケーション開発用)
- Arduino IDE
プロジェクト概要
現代の製造技術と、資材搬送・部品組立・溶接・切断・倉庫作業などで活躍するロボットアームに憧れ、自作に挑戦しました。fortzeroas氏設計のシンプルなロボットアーム(2016年)をベースに、手動制御ではなくC# Windowsアプリケーションで自動化制御する「製造オートメーション風」アプリを自作しました。
プログラミング経験を活かし、ロボットアームを完全制御・監視し、多様なタスクを実行できるオートメーションアプリケーションを開発しました。
ステップ1: 材料準備

主材料はMDF材。構造部に2mm、ベースに4mm厚を使用。設計図(ブループリント)は最終ステップでダウンロード可能。印刷してMDFに貼り付け、輪郭に沿ってカットし穴あけ。ルーターツールで加工しました。ベースは設計図なしでアレンジ可能です。
ステップ2: 塗装とスタイリング

同じ設計図をベースにPhotoshopでデカールや幾何学模様をデザインし、木工用ボンドで貼り付けてリアルな外観に仕上げました。
ステップ3: フレーム組み立て

事前計画通りで組み立ては容易。サーボモーターをネジで固定し、微調整を実施。左右フレーム連結には長ネジの代わりに太い木棒と強力接着剤を使用し軽量化しました。
ステップ4: グリッパー(つまみ機構)

金属棒をペンチで曲げ、3mm厚木材にルータードリルで穴を開け、強力接着剤で固定して挟み機構を作成。
ステップ5: ベース製作

4mm厚MDFで約17cm×10cmの土台をテーブルソーで切り出し、ベース用サーボ(9g)取付穴を加工。ベースとシリンダーの摩擦低減のため、高さ2.5cm・直径10cmの厚紙筒を挟み、これにもサーボ軸取付穴を開けました。
ステップ6: 電子回路


Arduinoで複数サーボを駆動するには外部電源が必須。本プロジェクトではマイクロサーボ9g×3と大型サーボ×1を使用。最初にTinkercadで仮想シミュレーションし、回路を検証しました。
単3電池4本(1.5V×4=6V)で電源を確保し、ブレッドボードでテスト後、Arduino Nano用シンプル拡張ドックを自作しました。
ステップ7: Arduinoコード
- 最新版Arduino IDEをダウンロード・インストール(公式サイト)
- ArduinoをUSB接続
- ツール>ボードで対象ボード選択
- コードをIDEにコピペ
- 検証ボタン(✔)でコンパイル確認
- 書き込みボタン(▶)でアップロード
ステップ8: オートメーションアプリケーション


PCでArduinoプロジェクトを自動化するのがこのプロジェクトの核心部分です。固定角度位置への到達は容易ではなく、当初は「Processing 3」でサーボ角度をキーボード操作で微調整し、目標位置の4サーボ角度(ベース、ショルダー、エルボー、グリッパー)を記録する補助インターフェースを作りました。
記録した角度配列をWindowsアプリで活用し、各サーボの可動限界をUIスライダーのガイドラインとして設定。再生機能もサポートしています。
アプリケーション機能
1. 動作制御(マニュアルモード)
- グリッパー: 開/閉ボタンで操作
- ベース: トラックバー左右ドラッグ、またはキーボード左右矢印で左右回転
- ショルダー: トラックバー左右ドラッグ、またはキーボード上下矢印で上下動作
- エルボー: トラックバー左右ドラッグ、またはW/Sキーで上下動作
2. 動作記録
「Rec. Position」ボタンまたはRキーで現在位置を記録。移動したサーボの位置をステップごとに個別リストへ保存。「Start Auto mood」で記録シーケンスを順次送信し自動実行。
3. 監視機能
グラフで各ステップを描画し、異常変化を視覚確認。右側データテーブルで正確な角度と時刻を表示。製造オートメーションさながらに、独自の動作シーケンスをタスクとしてロボットアームに送信可能です。
ステップ9: アップデート(2018年8月)

3mm MDFでレーザーカット版を再製作。カスタムジョイスティックを追加し、操作性を向上させました。
コード
Task.ino Arduino
int delayT = 350;
void Home() { // ホームポジション設定
MyServo0.write(valGripper); delay(15); // グリッパー
MyServo.write(valBase); delay(30); // ベース
MyServo2.write(valShoulder); delay(30); // ショルダー
MyServo3.write(valElbow); delay(delayT); // エルボー
}
void Pick() { // 固定ピック位置
MyServo.write(4); delay(delayT); // ベース
MyServo3.write(125); // エルボー
MyServo2.write(95); delay(delayT); // ショルダー
MyServo0.write(50); delay(delayT); // グリッパー開
MyServo0.write(2); delay(delayT); // グリッパー閉
MyServo2.write(60); // ショルダー少し上
MyServo3.write(80); delay(delayT); // エルボー少し上
Serial.println("Object Picked");
}
void Drop() { // 固定ドロップ位置
MyServo.write(145); delay(delayT); // ベース
MyServo2.write(80); delay(15); // ショルダー
MyServo3.write(115); delay(delayT); // エルボー
MyServo0.write(40); delay(delayT); // グリッパー開
MyServo3.write(90); delay(delayT); // エルボー少し上
Serial.println("Object Dropped");
}
void Playback() {
// シリアル入力形式: "1:90&2:80&3:180" (servoId:angle&...)
char* command = strtok(ByteReceived, "&");
while (command != 0) {
char* separator = strchr(command, ':');
if (separator != 0) {
*separator = 0;
int servoId = atoi(command);
++separator;
int angle = atoi(separator);
if (servoId == 1) { MyServo.write(angle); delay(delayT); }
else if (servoId == 2) { MyServo2.write(angle); delay(delayT); }
else if (servoId == 3) { MyServo3.write(angle); delay(delayT); }
}
command = strtok(0, "&");
}
}
RobotArm.ino Arduino
// written by AhmedAzouz
#include <Servo.h>
Servo MyServo, MyServo2, MyServo3, MyServo0;
char ByteReceived;
int MyPosition, MyPosition2, MyPosition3, MyPositionG;
int runCounter = 0;
int ledPin = A5;
// デフォルトホームポジション
int valGripper = 30;
int valBase = 70;
int valShoulder = 25;
int valElbow = 150;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
digitalWrite(13, LOW);
MyServo0.attach(12); // グリッパー
MyServo.attach(11); // ベース
MyServo2.attach(13); // ショルダー
MyServo3.attach(10); // エルボー
// 起動時位置設定
MyServo0.write(valGripper); delay(15);
MyServo.write(valBase); delay(30);
MyServo2.write(valShoulder); delay(30);
MyServo3.write(valElbow); delay(300);
}
void loop() {
// 現在位置をシリアル出力
Serial.print("Base: "); Serial.print(valBase); Serial.print("\t");
Serial.print("Shou: "); Serial.print(valShoulder); Serial.print("\t");
Serial.print("Elbow: "); Serial.print(valElbow); Serial.print("\t");
Serial.print("Grip: "); Serial.println(valGripper);
while (Serial.available() > 0) {
ByteReceived = Serial.read();
switch (ByteReceived) {
// LED制御
case 'n': digitalWrite(ledPin, HIGH); Serial.println("LED is on"); break;
case 'f': digitalWrite(ledPin, LOW); Serial.println("LED is off"); break;
// ベース制御
case 'l': MyPosition = MyServo.read() + 2; MyServo.write(MyPosition); break; // 左
case 'r': MyPosition = MyServo.read() - 2; MyServo.write(MyPosition); break; // 右
// エルボー制御
case 'u': MyPosition2 = MyServo2.read() + 2; MyServo2.write(MyPosition2); break; // 上
case 'd': MyPosition2 = MyServo2.read() - 2; MyServo2.write(MyPosition2); break; // 下
// ショルダー制御
case 'w': MyPosition3 = MyServo3.read() + 2; MyServo3.write(MyPosition3); break; // 下
case 's': MyPosition3 = MyServo3.read() - 2; MyServo3.write(MyPosition3); break; // 上
// グリッパー制御
case 'o': MyServo0.write(30); break; // 開
case 'c': MyServo0.write(1); break; // 閉
// クイックドロップ(デフォルト位置)
case 'q': digitalWrite(ledPin, HIGH); Pick(); Drop(); Home(); digitalWrite(ledPin, LOW); break;
// 強制停止・ホーム復帰
case 'h': Home(); digitalWrite(ledPin, LOW); break;
// 自動モード(Playback実行)
default: digitalWrite(ledPin, HIGH); Pick(); Playback(); Home(); digitalWrite(ledPin, LOW); break;
}
}
}
カスタムパーツとエンクロージャ
f98t2axin238k2n_khGWAEIqdl.skp (SketchUpファイル)
回路図

製造プロセス
- IoTで遠隔操作する自作ロボットアーム:Arduino MKR1000とSimulink、ThingSpeak活用
- Arduino駆動3Dプリントロボットアームの製作:ステップバイステップガイド
- Arduinoベースのヌンチャク操作6自由度ロボットアームキット
- Ethernet制御ロボットアーム - WIZ750SRとAndroidアプリでリモート操作
- 産業用ロボットアーム:製造革命を牽引する自動化の核心
- SCARAロボット市場、2026年に147.8億ドル到達予測、自動化成長を牽引
- ロボットアームの構造と機能:設計から組み立てまで完全解説
- 産業用ロボットアームが製造業を変える:導入メリットと主要メーカー完全ガイド
- 産業用ロボットアーム:生産効率と労働価値を飛躍させる自動化の核心
- 油圧ロボットアーム徹底解説:仕組み・メリット・用途・将来性まで
- Makerarm:メイカーのためのオールインワン デスクトップ ロボットアーム