In this tutorial, you will learn, step by step, how to build a DIY 6-DOF robotic arm entirely from scratch. Specifically, the project covers every stage of the build — from designing each part in Autodesk Inventor and 3D printing them, to wiring the electronics with an Arduino and programming real-time servo control with potentiometers.
This DIY 6-DOF robotic arm uses three MG996R high-torque servos for the heavy-lift base, shoulder, and elbow joints, and three SG90 micro servos for the lighter wrist and gripper. For example, for a primer on how these motors work, see our servo motor control guide. In turn, each servo is controlled in real time by a dedicated 10 kΩ potentiometer, and all six PWM signals are handled by a PCA9685 servo driver board over I²C — keeping the wiring clean and freeing up Arduino pins for future upgrades.
Whether you are a hobbyist building your first robot or an engineering student looking for a hands-on mechatronics project, this guide walks you through every detail with a full bill of materials, print settings, wiring diagrams, and source code. Once you are ready, you can watch the full build video below or continue reading the written tutorial.
Project Overview
Overall, the build is organized into four major phases: CAD design, 3D printing, mechanical assembly, and electronics wiring with programming. Furthermore, every 3D-printable STL file is modeled in Autodesk Inventor with precise tolerances for the servo mounts and bearing seats, so the parts fit together without modification.
On the electronics side, similarly, an Arduino Uno reads analog values from six 10 kΩ potentiometers and sends I²C commands to a PCA9685 16-channel PWM driver. In turn, the driver outputs the correct pulse widths. Consequently to each servo. As a result, this architecture keeps high servo current completely separate from the Arduino and leaves room for adding sensors or wireless modules later.
Complete Bill of Materials
Before you start, gather every component listed in the table below. As a result, having all parts on hand will prevent frustrating mid-build pauses.
6-DOF Robotic Arm Parts and Components
| Item | Quantity | Part | Description |
|---|---|---|---|
| 1 | 1 | Base_1 | Essentially, base platform |
| 2 | 1 | base_link_upper1 | Similarly, upper base section |
| 3 | 1 | arm_link_1 | Specifically, first arm link |
| 4 | 1 | arm_link_2 | Similarly, second arm link |
| 5 | 1 | arm_link_3 | Likewise, third arm link |
| 6 | 1 | gripper_base | Basically, gripper base |
| 7 | 1 | Gripper_2 | Similarly, gripper finger |
| 8 | 1 | Gear_right | Gripper gear (right) |
| 9 | 1 | Gear_left | Gripper gear (left) |
| 10 | 1 | Gripper | Gripper assembly |
| 11 | 4 | Link | Gripper link parts |
| 12 | 2 | Spacer | Gripper joint spacers |
| 13 | 3 | MG996R Servo Motor | Essentially, high-torque servo (base, shoulder, elbow) |
| 14 | 3 | SG90 Micro Servo Motor | Similarly, micro servo (wrist, gripper) |
| 15 | 14 | ANSI B18.6.4 No.2-32 3/8″ | Specifically, truss head screw, No.2-32 |
| 16 | 2 | ANSI B18.6.4 No.2-32 1/4″ | Truss head screw, No.2-32 |
| 17 | 3 | DIN 7985 M1.6×2-Z | M1.6×2 cross-recess screw |
| 18 | 7 | ISO 4762 M3x16 (AS 1420) | Essentially, M3×16 hex socket screw |
| 19 | 12 | ISO 4032 M3 (AS 1112) | Similarly, M3 hex nut |
| 20 | 2 | ANSI B18.6.4 No.2-32 1/2″ | Truss head screw, No.2-32 |
| 21 | 3 | MG955 Horn | Horn for MG996R |
| 22 | 3 | DIN 7985 M3x6-Z | M3×6 cross-recess screw |
| 23 | 3 | SG90 Servo Horn | Horn for SG90 |
| 24 | 2 | ANSI B18.6.4 No.2-32 3/8″ | Truss head screw, No.2-32 |
| 25 | 12 | ANSI B18.6.4 No.3-28 1/2″ | Truss head screw, No.3-28 |
| 26 | 1 | Ball Bearing 6806ZZ (30x42x7) | Specifically, deep-groove bearing (30×42×7) |
| 27 | 1 | Arduino Uno or Mega | Essentially, main controller |
| 28 | 1 | PCA9685 Servo Driver Board | Specifically, 16-ch PWM driver (I²C) |
| 29 | 6 | 10kΩ Potentiometer | Correspondingly, analog control knob per servo |
| 30 | 1 | Breadboard | Basically, wiring base for potentiometers |
| 31 | 1 | 5V 10A Power Supply | Importantly, servo power source |
| 32 | 1 | Jumper Wires (male-male) | Specifically, Arduino ↔ PCA9685 connections |
| 33 | 1 | Jumper Wires (male-female) | Similarly, potentiometer ↔ Arduino connections |
| 34 | 1 | Wooden Board | Essentially, arm mounting platform |
Designing the Parts in Autodesk Inventor
The first phase is modeling every component in Autodesk Inventor. Specifically, this parametric CAD software lets you define exact dimensions, fillet edges for added strength, and verify fit before a single gram of filament is extruded. If you are new to Inventor or 3D printing, check out our Introduction to 3D Printing and 3D Design with Inventor before starting.
Essentially, two servo types drive the design constraints. The SG90 micro servos handle the lighter upper joints and gripper due to their compact footprint, while the MG996R servos power the base rotation and the two heavy-lift shoulder and elbow joints, providing the torque needed to move the full arm. The technical drawing below shows all part dimensions, sectional views, and assembly relationships — use it as your reference when checking print accuracy.

3D Printing the 6-DOF Robotic Arm Components
Once your STL files are exported from Inventor, it is time to fire up the 3D printer. For this project, PLA filament is recommended because of its ease of printing and good detail reproduction. For best results, therefore, use a layer height of 0.2 mm and at least 40% infill for structural parts like the base and arm links.
In particular, pay special attention to the servo mount pockets — they need to be dimensionally accurate so that the motors press-fit snugly. After printing, therefore, perform light post-processing: remove support material, sand mating surfaces, and test-fit each servo before moving on to assembly.


Assembling Your DIY 6-DOF Robotic Arm
Once every part is printed and test-fitted, you can begin the hands-on assembly. Therefore, work through each step in order — the arm is built from the base up. Additionally, test each joint for smooth rotation before proceeding to the next step.

Step 1: Assembling the Base
Above all, the base is the foundation of the entire arm, so accuracy here is critical.
- Securing the Servo Motor — Install the first MG996R servo into the base mount using the included screws (or M3×12 cross-head self-tapping screws). Essentially, this servo provides the rotational base movement for the arm.
- Adding the Ball Bearing (6806ZZ, 30×42×7 mm) — Press-fit the deep-groove ball bearing into its seat on the base. Specifically, the bearing sits between the fixed base plate and the rotating upper platform, reducing friction and extending the life of the joint.
- Connecting the Servo Horn — Attach the servo horn to the rotating upper platform using M2×12 self-tapping screws. Above all, make sure the connection is tight — this horn transmits all rotational force from the servo to the rest of the arm above it.


Step 2: Mounting Servo Horns to Arm Links
Next, align each servo horn with its corresponding arm link attachment point, then secure with two screws per horn. In particular, make sure the holes line up perfectly — a misaligned horn will cause binding and uneven movement, so double-check every connection before tightening fully.

Step 3: Mounting Servo Motors to Arm Links
Then, seat each servo motor into its 3D-printed pocket on the arm link, ensuring the correct orientation. Then, fasten with two screws per motor and test stability by applying gentle pressure — the servo should not shift or rock at all. Indeed, a solid motor mount is essential for precise, repeatable arm movements.

Step 4: Connecting the Arm Links
Subsequently, join the individual link-and-servo assemblies together. First, position the horn on one link so it slots into the attachment point of the next link, then secure with screws. Finally, tighten evenly to maintain structural continuity and fluid joint articulation across the entire arm.

Step 5: Assembling the Gripper
Next, attach the gripper sub-assembly to the arm’s end link. Specifically, the gripper uses an SG90 micro servo with a pair of 3D-printed gears to open and close the fingers. Additionally, use M3×20 screws for the gripper joints and verify that the fingers move freely without binding.

Step 6: Securing the Arm to a Wooden Base
Lastly, mount the fully assembled arm onto a flat wooden board using M3×12 self-tapping screws. As a result, a solid base prevents the arm from tipping during fast movements and provides a convenient platform for attaching the breadboard and power supply later.


Wiring the 6-DOF Robotic Arm: Arduino and Servo Driver
Once the mechanical build of your DIY 6-DOF robotic arm is complete, it is time to wire the electronics. Essentially, the control system has three main elements: the Arduino Uno (or Mega) as the microcontroller, the PCA9685 servo driver board for generating PWM signals, and six 10 kΩ potentiometers for user input.
Components and Wiring Guide
- Arduino Uno / Mega — Essentially, the main controller. Essentially, it reads potentiometer values and sends I²C commands to the PCA9685.
- PCA9685 Servo Driver Board — An I²C-controlled, 16-channel PWM driver. Furthermore, it handles all six servo signals, leaving room for expansion later.
- 5 V 10 A Power Supply — Importantly, provides dedicated power to the servos through the PCA9685 V+ terminal. Importantly, never power six servos from the Arduino’s 5 V pin — it cannot supply enough current.
- 6 × 10 kΩ Potentiometers — Correspondingly, connected to Arduino analog pins A0–A5. Essentially, turning a knob changes the voltage, which the Arduino reads as a value from 0 to 1023.
- Breadboard and Jumper Wires — Essentially, used to organize potentiometer connections cleanly.
Wiring Steps
- PCA9685 → Arduino: First, connect VCC to 5 V, GND to GND, SDA to A4, and SCL to A5. Similarly, on the Mega, SDA and SCL use pins 20 and 21 respectively.
- Servos → PCA9685: Next, plug each servo’s 3-pin connector into channels 0–5 on the PCA9685. Also, make sure the ground wire (brown or black) aligns with the bottom row of headers.
- Potentiometers → Arduino: Then, wire the outer legs of each pot to 5 V and GND on the breadboard, and connect the center (wiper) pin to A0 through A5.
- Servo Power Supply: Finally, connect the 5 V 10 A supply to the PCA9685 V+ and GND screw terminals. As a result, this keeps high servo current completely separate from the Arduino.

Why the 6-DOF Robotic Arm Needs a PCA9685 Servo Driver
So, why not just drive servos straight from the Arduino? You can — however, it quickly becomes limiting. After all, the Arduino Uno has only six PWM-capable pins, and the built-in Servo library can conflict with other timer-dependent features like tone() or certain communication protocols.
Instead, the PCA9685 solves this by offloading all PWM generation to a dedicated chip. Specifically, it communicates over the I²C bus using just two wires (SDA and SCL) regardless of how many servos you control. Moreover, a single board handles 16 channels, and you can daisy-chain up to 62 boards for a theoretical maximum of 992 servos.
PCA9685 Pinout Reference
- GND — Essentially, common ground shared with the Arduino.
- OE (Output Enable) — By default, active low. Therefore, leave unconnected to keep all outputs enabled by default.
- SCL — Specifically, I²C clock line for synchronization.
- SDA — Similarly, I²C data line for communication.
- VCC — Specifically, logic power at 3.3–5 V. Notably, powers only the PCA9685 chip, not the servos.
- V+ — Importantly, servo power rail (up to 6 V). Then, connect your external supply here via the polarized screw terminal.
Consequently, each channel on the board has a 3-pin header that accepts a standard servo connector directly, making wiring quick and error-proof.

Programming the 6-DOF Robotic Arm for Servo Control
Ultimately, the Arduino sketch ties everything together. Essentially, it reads the voltage on each analog pin, converts it into a servo pulse width, and sends the result to the PCA9685. Below is how the key logic works, step by step.
How the Code Works
- Library Initialization — First, the sketch includes
Wire.hfor I²C andAdafruit_PWMServoDriver.hfor the PCA9685. Insetup(), it callspwm.begin()and sets the PWM frequency to 60 Hz — the standard refresh rate for hobby servos. - Reading the Potentiometers — Inside
loop(),Next, analogRead(A0)throughanalogRead(A5)returns a value between 0 and 1023, corresponding to the knob position. - Subsequently, mapping to Servo Pulse — The
map()function converts the 0–1023 range into a 125–575 tick range. These tick values represent the minimum and maximum pulse widths the PCA9685 outputs at 60 Hz (roughly 1 ms to 2.3 ms), which correspond to the servo’s full rotation range. - Then, setting the PWM Output —
pwm.setPWM(channel, 0, ticks)In turn, sends the computed pulse to the correct PCA9685 channel. The second parameter (0) is the “on” tick, and the third is the “off” tick within the 4096-step PWM cycle. - Loop Delay — Finally, a 20 ms delay at the end of each loop keeps the refresh rate smooth and prevents flooding the I²C bus.
Finally, upload the following sketch to your Arduino Uno (or Mega). Make sure the Adafruit PWM Servo Driver Library is installed via the Arduino Library Manager before compiling.
Arduino Sketch: Full Source Code
/**
* Author: Omar Draidrya
* Date: 2024/05/05
* Controls 6 servos via PCA9685 with potentiometer input.
*/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); // Default address 0x40
void setup() {
Serial.begin(9600); // First, init serial.
pwm.begin(); // Then, init PCA9685.
pwm.setPWMFreq(60); // Specifically, 60 Hz for servos.
}
void loop() {
// Servo 0
int potValue0 = analogRead(A0); // First, read A0
int servoPos0 = map(potValue0, 0, 1023, 125, 575); // Map to pulse range
pwm.setPWM(0, 0, servoPos0); // Set servo 0
// Servo 1
int potValue1 = analogRead(A1); // Then, read A1
int servoPos1 = map(potValue1, 0, 1023, 125, 575); // Map to pulse range
pwm.setPWM(1, 0, servoPos1); // Set servo 1
// Servo 2
int potValue2 = analogRead(A2); // Similarly, read A2
int servoPos2 = map(potValue2, 0, 1023, 125, 575); // Map to pulse range
pwm.setPWM(2, 0, servoPos2); // Set servo 2
// Servo 3
int potValue3 = analogRead(A3); // Next, read A3
int servoPos3 = map(potValue3, 0, 1023, 125, 575); // Map to pulse range
pwm.setPWM(3, 0, servoPos3); // Set servo 3
// Servo 4
int potValue4 = analogRead(A4); // Likewise, read A4
int servoPos4 = map(potValue4, 0, 1023, 125, 575); // Map to pulse range
pwm.setPWM(4, 0, servoPos4); // Set servo 4
// Servo 5
int potValue5 = analogRead(A5); // Finally, read A5
int servoPos5 = map(potValue5, 0, 1023, 125, 575); // Map to pulse range
pwm.setPWM(5, 0, servoPos5); // Set servo 5
delay(20); // Finally, loop delay
}
Required Libraries
Before compiling, first install the following libraries through the Arduino IDE Library Manager: Adafruit PWM Servo Driver Library and Wire (included by default). After that, then select your board (Arduino Uno or Mega), choose the correct COM port, and click Upload.
Calibrating and Testing Your 6-DOF Robotic Arm
Once your DIY 6-DOF robotic arm is fully wired, power on the servo supply and slowly turn each potentiometer. As a result, you should see the corresponding joint move in real time. If a joint moves in the wrong direction, swap the outer wires on that potentiometer to reverse it.
Fine-tune the map() range values (125 and 575) for each servo individually. For example, some servos may need slightly different minimum and maximum tick values to avoid mechanical end-stop buzzing. Lastly, test the arm under load by picking up small objects with the gripper to confirm torque and stability.
6-DOF Robotic Arm: Conclusion and Next Steps
Congratulations — you now have, indeed, a fully functional DIY 6-DOF robotic arm built entirely from scratch. Indeed, this project covers every core discipline of mechatronics: CAD design, additive manufacturing, electronic wiring, and embedded programming.
From here, consequently, the possibilities are wide open. You could add inverse kinematics for automated positioning, integrate a Bluetooth module for wireless control (we did exactly that in our Bluetooth-controlled robotic arm upgrade), or train the arm to record and replay movement sequences. Regardless of which direction you take, this six-axis platform gives you a solid foundation for deeper exploration into robotics and automation.
can u tell how to connect potentiometer with bread board
I am building an AI Robot and want to use your robotic arm in the build. I want to mount it on the front side vertically. I noticed on past photos there was a tension spring attached to the rotating base to the first arm piece but not listed in the parts list or build instructions. I wish to implement the spring back into the build because of its vertical placement on my robot. Can you provide me with the specifications for the spring? This robotic arm is in my opinion is one of the better designed and documented arms of its type out on the web.
Thanks a lot! I’m glad you liked the design
Yes, that tension spring connects the rotating base to the first arm segment to help support the shoulder joint, especially when the arm is mounted vertically.
The spring is about 2 cm long (at rest) and 9 mm in diameter.
I actually reused it from an old desk lamp stand, but you can find similar extension springs easily online or in hardware stores.
It’s optional but really helps balance the arm and reduce servo stress.
Hello! I wanted to ask the function of the atachment points on the base and the first link, are they for a spring? it is modelled but the pictures of the assembly don’t have this feature, nor is it referenced on the post. Thank you! this is a nice design
Yes, those points are for a spring. The spring is optional — it helps the shoulder joint carry part of the arm’s weight.

This feature was added in a later version of the design.
You can also use a rubber band, but I personally prefer a spring.
The one I used is about 2 cm long (at rest) and 9 mm in diameter.
I actually took it from an old desk lamp stand, but you can easily find similar springs online or in hardware stores.