Build a 3D-Printed Desktop Robotic Arm: Servos, Inverse Kinematics, and Python Control
A robotic arm is one of the best projects for combining this site's 3D printing, electronics, and coding content into a single build: printed structural links, servo actuators at each joint, and software that turns "move the gripper to this point in space" into the individual joint angles that get it there. This build produces a 4-5 degree-of-freedom desktop arm — base rotation, shoulder, elbow, wrist, and gripper — sized for picking up small objects on a desk, controlled either by direct servo angle commands or, once the basics work, by inverse kinematics so you can command an XYZ target position instead of manually working out each joint's angle yourself.
Mechanical Design
Print each link as a rigid segment with a servo horn mount at one end and a servo body cutout at the other, so each joint's servo is embedded directly in the link above or below it rather than relying on a separate bracket — this keeps the arm compact and reduces the number of fasteners. Print orientation matters more here than on most prints: links need to resist bending loads along their length, so orient parts so layer lines run across the load path rather than parallel to it, and use a higher infill (40-60%) and more perimeter walls on load-bearing links than you would for a purely cosmetic print — this site's guide on designing parts for 3D printing covers the general strength-orientation relationship in more depth. PETG or ASA hold up better than PLA for a part under sustained servo torque and occasional knocks, since PLA's lower heat deflection temperature and higher brittleness under repeated flex make long-term joint wear a bigger concern.
JointTypical RangeServo Torque Guidance Base rotation0-180° (or continuous with a different servo type)Carries the weight of every joint above it — use your highest-torque servo here Shoulder0-180°Second-highest load — lifts the entire forearm, wrist, and gripper assembly Elbow0-180°Moderate torque, lower load than shoulder Wrist (pitch/roll)0-180° per axisLower torque acceptable — only supports the gripper and its payload GripperOpen/close, roughly 30-60° of servo travelLowest torque requirement, but check grip force against your target payload weightElectronics
Standard hobby servos (SG90 for lighter joints, MG996R or similar metal-gear servos for base and shoulder where load is highest) are the simplest starting point and what this build assumes, though stepper motors with drivers offer more precision and holding torque at the cost of more complex wiring and code — a reasonable upgrade path once the servo version is working. Run all servo signal wires to a servo driver board (a PCA9685 16-channel PWM driver is the standard choice, communicating over I2C so it only needs two GPIO pins from your microcontroller regardless of how many servos you're driving) rather than wiring servos directly to microcontroller GPIO pins, both for cleaner wiring and because the PCA9685 has its own dedicated power input, keeping servo current draw off your microcontroller's regulator entirely.
ComponentRole ESP32 or Raspberry PiRuns control software and issues joint angle commands PCA9685 16-channel PWM servo driverDrives all servos from one I2C bus, isolating servo current from the microcontroller 5-6x hobby servos (mixed SG90/MG996R by joint load)Joint actuators External 5-6V, several-amp power supplyDedicated servo power — do not power multiple loaded servos from a microcontroller's onboard regulator 3D-printed link and joint setThe arm's structure — download an existing open-source arm design or design your own around your specific servo dimensionsBasic Control: Direct Joint Angles
Before attempting inverse kinematics, get direct joint control working first — a simple script that takes five angle values and moves each servo to that position via the PCA9685, with basic easing (moving through intermediate angles gradually rather than snapping instantly) to avoid mechanical shock and reduce servo current spikes. This alone lets you pose the arm, record a sequence of poses, and play them back — a legitimate, useful robot on its own before any inverse kinematics enters the picture.
Inverse Kinematics: From XYZ Target to Joint Angles
Forward kinematics — computing where the gripper ends up given a set of joint angles — is straightforward trigonometry once you know each link's length. Inverse kinematics, going the other direction (given a desired gripper position, what joint angles get you there), is the harder and more interesting problem, and for a simple planar arm with a rotating base it's tractable with closed-form trigonometry rather than requiring a heavy numerical IK library:
- Base rotation is simply the angle from the base to the target position projected onto the XY (top-down) plane — a single atan2(y, x) calculation.
- With base rotation handled, the shoulder-elbow problem reduces to a 2D problem in the vertical plane containing the target: given the target's distance and height from the shoulder joint, and knowing the upper arm and forearm link lengths, the law of cosines gives you the elbow angle directly, and the shoulder angle follows from there.
- Wrist orientation is typically solved last and more loosely — many simple arms just hold the wrist at a fixed angle relative to the ground (keeping the gripper level) rather than solving full 6-axis orientation, which is more than sufficient for basic pick-and-place tasks.
This is a well-documented approach for 2-3 link planar arms, and plenty of open-source Python IK implementations for hobby servo arms exist to reference or adapt rather than deriving the trigonometry from scratch — the important part for a first build is understanding what the math is solving for, so you can debug it when a target position produces an impossible or out-of-range joint angle (which will happen, and needs to fail gracefully rather than commanding a servo past its mechanical limit).
Software Stack
A Python script on a Raspberry Pi (or MicroPython on an ESP32 for a more embedded setup) talking to the PCA9685 over I2C via the Adafruit CircuitPython PCA9685 library is the most common, well-documented path, since it has extensive examples for exactly this servo-driver combination. Structure the code in three layers: a low-level layer that just sets raw PWM values for a given channel, a joint-angle layer that converts degrees to the correct PWM pulse width for your specific servos (calibrate this per-servo, since cheap servos vary in their actual angle-to-pulse-width mapping), and a kinematics layer on top that converts target positions into joint angles and calls the joint-angle layer. Keeping these layers separate makes it much easier to debug — you can command a raw joint angle directly to rule out a kinematics bug versus a calibration bug.
Practical Build Notes
- Servo horn slop (the small amount of play in how a servo horn attaches to its shaft) accumulates across multiple joints — reinforce horn attachment points with a drop of thread-locking adhesive on the mounting screw, and expect to periodically re-tighten as the arm sees use.
- Test each joint's full range of motion before final assembly — a joint that's slightly misaligned in the printed geometry can bind or over-travel and stall the servo, drawing excess current and generating heat.
- Power sequencing matters: connect servo power before sending PWM commands, and consider a soft-start or center-position-on-boot behavior so the arm doesn't lurch unpredictably every time you power it on.
Once basic pick-and-place with inverse kinematics works reliably, natural extensions include adding a camera and basic object detection for the arm to locate targets on its own, scaling up to stepper motors and a rigid frame for higher payload capacity, or building a second identical arm and exploring basic coordinated dual-arm tasks — each an entire project in its own right built on the same foundation established here.
Related Guides
- Getting Started with ROS2 on Raspberry Pi for Robotics
- Building a Voron 2.4: Frame Assembly, Wiring, and Klipper Commissioning
- Build a 3D-Printed FPV Drone Frame: Motor Mounts, Vibration Isolation, and a 5-Inch Quad Parts List
- Build a Tethered Underwater ROV with Raspberry Pi: Thrusters, Waterproof Enclosure, and Live Video Control
- Build a Dual-Axis Solar Tracker: ESP32, LDR Sensors, and Servo-Driven Panel Positioning
- How to Design and 3D Print Functional Threads: Screws, Nuts, and Threaded Inserts
- How to Print Multi-Color Models with a Single Extruder Using M600 Filament Changes
- How to Design Snap-Fit Joints and Living Hinges for 3D Printed Parts