- Published on
What a Robot Arm Is Made Of: Links, Joints, and What Actually Drives Them
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- Introduction — An Arm Built From Six Servos Collapses Under Its Own Weight
- Link, Joint, End Effector — What These Three Words Precisely Mean
- What Degrees of Freedom Actually Count, and Why 6 Is the Baseline
- Revolute and Prismatic Joints
- What Actually Drives a Joint — Servo, Stepper, BLDC
- Gearboxes — What Gear Ratio Does to Torque and Backlash
- Working Out Static Torque With Real Numbers — Why the Shoulder Is Bigger Than the Wrist
- Conclusion — The Shape of the Arm Is the Result of a Torque Calculation
Introduction — An Arm Built From Six Servos Collapses Under Its Own Weight
You decide to build a robot arm and buy the parts. There's a combination that shows up more than any other in search results: six MG996R servos, an acrylic or 3D-printed bracket, a 5V power supply.
You assemble it. You power it on. The servos find their positions and move.
You command the arm to reach out horizontally. The shoulder trembles and slowly sags. The servo keeps making noise, but the arm doesn't rise. Tell it to pick something up and it just collapses entirely.
It's not a code problem. It's not a power problem either. The torque the shoulder joint needs is 1.66 times what that servo can produce.
We'll calculate that number ourselves later on. What matters right now is that this calculation could have been finished on paper before buying a single part. Fix the arm length and the weight of what you want to lift, and the torque each joint demands falls out — then you compare that against the datasheet.
This post covers what you need for that calculation: what a robot arm is made of, what degrees of freedom actually count, what each of the three ways to turn a joint is good and bad at, and what a gearbox gives you and what it takes away. And at the end, we work through that torque calculation from start to finish.
Link, Joint, End Effector — What These Three Words Precisely Mean
Let's get the terminology exactly right first. The definitions of these three words are the foundation for every calculation that follows.
A link is a rigid member that doesn't deform. In a robot arm, it's the structure connecting one joint to the next. In a human arm, it's the upper arm bone and the forearm bone. Kinematics treats a link as rigid purely for the sake of calculation, and however much the real part actually flexes becomes error.
A joint is the element connecting two links that allows relative motion between them. Which motion it allows determines the joint's type.
The end effector is the device mounted at the very end of the arm that actually does the work: a gripper, a suction cup, a welding torch, a camera. When kinematics talks about "the end-effector position," that end point is a reference point defined on the end effector, and that point is called the tool center point.
Add a base and the structure is complete: a chain starting at the base, alternating links and joints, ending at the end effector. A structure like this that never branches and stays in a single chain is called an open kinematic chain, and the overwhelming majority of industrial robot arms take this form.
There are also closed chains — structures like a delta robot, where several branches meet back up at the end. These have an advantage in stiffness and speed, at the cost of a narrower workspace and much more complex kinematics. This post covers open chains only.
There's one convention worth knowing. Links and joints are numbered starting from the base, counting outward. The base is link 0, the first joint is joint 1, and the link after that is link 1. This way, joint i connects link i-1 to link i. The subscripts on the transformation matrices in the forward kinematics post follow exactly this convention.
What Degrees of Freedom Actually Count, and Why 6 Is the Baseline
Degrees of freedom is the number of motion variables you can specify independently. In a robot arm, this is usually the same as the number of joints.
Counting from the target side makes clear why 6 is the baseline. To fully specify the state of one rigid body in three-dimensional space, how many numbers do you need?
Position needs three: x, y, z.
Orientation needs three too, because you can independently rotate an object about three axes while keeping it fixed in place.
Add them up and you get six. So to put the end effector at any position and in any orientation, you need at least six joints.
Using this number as a baseline, robot arms split into three categories.
| DOF | Name | What it can do | Examples |
|---|---|---|---|
| Under 6 | Underactuated | Can only specify some of position or orientation | SCARA (4), delta (3), hobbyist 5-axis arms |
| 6 | Fully actuated | Any position and orientation within the workspace | Most industrial robots |
| 7 and up | Redundant | The same end-effector pose reachable in multiple arm shapes | Many cobots, human arms |
Being underactuated isn't a bad thing. A SCARA arm has 4 degrees of freedom, but for a task like inserting components straight down onto a board, all you need is for the part to descend vertically — the remaining degrees of freedom aren't needed. Drop the degrees of freedom and you get something much faster, stronger, and cheaper. Having exactly as much as you need is the design — 6 is a reference point, not a ceiling.
What redundancy gives you is the ability to change the arm's shape while keeping the end effector fixed. Rest your hand on a fixed point on a desk and move your elbow up and down, and you can feel exactly this. You can use that slack for obstacle avoidance or to steer clear of joint limits, and that math is the null space from the inverse kinematics post.
The 5-degree-of-freedom arms common in hobbyist builds sit in an awkward spot. They're missing one rotational axis at the wrist, so a task requiring you to grip an object at a specific orientation suddenly runs into an unreachable pose. Position is achievable but orientation isn't, and it's a situation you're guaranteed to run into once you start writing programs for it.
Revolute and Prismatic Joints
The joints actually used in real robot arms come down to essentially two kinds.
A revolute joint rotates about a single axis. Its joint variable is an angle. A human elbow and shoulder are like this, and almost every joint in an industrial robot arm is a revolute joint.
A prismatic joint slides along a single axis. Its joint variable is a length. Each axis of a 3D printer, gantry robots, and the Z-axis of a SCARA arm are all like this.
The difference between them shows up in the shape of their performance curves.
| Criterion | Revolute joint | Prismatic joint |
|---|---|---|
| Joint variable | Angle | Distance |
| Workspace vs. footprint | Wide | Narrow |
| Stiffness | Drops sharply as the link gets longer | Generally uniform |
| Precision | Error amplified toward the link's tip | Uniform regardless of position |
| Torque change under load | Varies significantly with pose | Generally constant |
| Kinematics | Trigonometric, multiple solutions | Generally linear, single solution |
| Sealing and cleanliness | Easy | Hard, since the rail is exposed |
The fourth row is the problem unique to revolute joints in a robot arm. Angular error at a joint gets amplified into end-effector position error in proportion to the link length. If the shoulder joint is off by 0.1 degrees, at an end effector 0.35 meters away that's:
0.1 degree = 0.001745 rad
0.001745 × 0.35 m = 0.000611 m = 0.61 mm
0.61 millimeters. And this error gets amplified more the closer the joint is to the base. The precision of the base-side joints dominates the precision of the end effector. This is also part of why, as covered later, more expensive gearboxes get used on the shoulder side.
In the international standard URDF, kinematics is expressed with a joint-type string, and there are exactly six valid values: revolute (rotation with a range limit), continuous (unlimited rotation), prismatic (linear), fixed (rigid), floating (6 DOF), planar (planar, 3 DOF). The first three are the actual driven joints, and fixed is used when you want to add one more frame purely for calculation purposes.
What Actually Drives a Joint — Servo, Stepper, BLDC
Now the main event. We know a joint rotates — but what turns it?
RC Servo — Command an Angle and It Goes There On Its Own
Overwhelmingly the most common choice in hobbyist robot arms. Inside is a DC motor, a reduction gearbox, a position sensor, and control circuitry, all bundled together. From the outside you just supply a target angle, and the closed loop inside the servo handles getting there.
The command is delivered as the width of a PWM pulse. The standard convention is to send one pulse roughly every 20 milliseconds, where a width of 1 millisecond means one extreme, 1.5 milliseconds means center, and 2 milliseconds means the other extreme. The update rate is forgiving — anywhere from 40Hz to 200Hz generally works.
Two things are worth cautioning about here.
First, the pulse-width range differs by manufacturer and model. For the widely used SG90, distributor documentation lists 500 to 2400 microseconds, though the manufacturer TowerPro itself doesn't publish a pulse-width spec. Use only 1000 to 2000 microseconds and you'll only be using about half the servo's actual range of motion. You need to find the real range by moving the servo incrementally and observing it.
Second, an ordinary PWM output has nowhere near enough resolution. An Arduino's analogWrite() is 8-bit, dividing a 20-millisecond period into 256 steps:
20000 μs / 256 = 78.125 μs
One step is 78 microseconds. If 1000 to 2000 microseconds maps to 180 degrees, then 1 degree is 5.56 microseconds, so:
78.125 μs / 5.56 μs = 14.06 degrees
One step is 14 degrees. That means you can only specify the angle in 14-degree increments. This is why a servo gets driven with a dedicated library, not analogWrite(). The Arduino Servo library grabs a timer directly and generates a microsecond-precision pulse width.
#include <Servo.h>
// Always give the servo its own separate power supply, and only tie GND to the board.
// We'll confirm why in the "Power" section below, with a calculation.
Servo shoulder;
const int SERVO_PIN = 9;
const int PULSE_MIN = 600; // These two values differ by model.
const int PULSE_MAX = 2400; // Narrow them down incrementally to find the actual limits.
void setup() {
// Passing the min/max pulse width to attach maps write(angle) onto that range.
shoulder.attach(SERVO_PIN, PULSE_MIN, PULSE_MAX);
shoulder.writeMicroseconds(1500); // Start at center
delay(500);
}
void loop() {
// write(degrees) has lower resolution than writeMicroseconds(microseconds).
// Set the step to 20us and that's about 2 degrees, which is smooth enough.
for (int us = 1000; us <= 2000; us += 20) {
shoulder.writeMicroseconds(us);
delay(20); // Matched to the update rate
}
for (int us = 2000; us >= 1000; us -= 20) {
shoulder.writeMicroseconds(us);
delay(20);
}
}
An RC servo's limits are clear: you can't read its current angle, you can't command a torque, and you can't tell how much force it's exerting. Sending a command and trusting it arrived is the whole story. If it gets loaded down and can't get there, there's no way to know.
Smart servos solve this limitation. ROBOTIS's Dynamixel line is the classic example, daisy-chaining several units over a serial bus and letting you read each servo's current position, speed, load, and temperature. Per manufacturer specs, the AX-12A delivers 1.5 N·m of stall torque at 12V with a position resolution of 0.29 degrees (a 300-degree range divided into 1024 steps). The higher-end X series bumps resolution up to 4096 per revolution, and the XM430-W350-R delivers 3.8 N·m at 11.1V. This model has a current-based position control mode, letting you issue a command like "don't push harder than this force."
Stepper Motor — Get There By Counting, But You Don't Know If You Arrived
A stepper energizes its coils in sequence to drag its rotor forward one step at a time. Without a position sensor, counting steps effectively tells you the angle.
The most common NEMA 17's step angle is 1.8 degrees, 200 steps per revolution. Use that value directly and a joint's resolution is 1.8 degrees — convert that to end-effector error at a 0.35-meter arm length:
1.8 degrees = 0.031416 rad
0.031416 × 0.35 = 0.011 m = 11.0 mm
11.0 millimeters. Nowhere close to good enough for a robot arm. So you use microstepping — a technique that runs the coil current through a sine-wave approximation rather than steps, dividing each step into smaller pieces.
| Driver | Max microstep | Steps per revolution | Angle per step | End-effector motion at 0.35m |
|---|---|---|---|---|
| None (full step) | 1/1 | 200 | 1.8 degrees | 11.00 mm |
| A4988 | 1/16 | 3200 | 0.1125 degrees | 0.687 mm |
| DRV8825 | 1/32 | 6400 | 0.0563 degrees | 0.344 mm |
| TMC2209 | 1/256 | 51200 | 0.0070 degrees | 0.043 mm |
The TMC2209's 1/256 is produced by an interpolation feature called MicroPlyer, and the values you can select directly with pins are 8, 16, 32, 64.
There's something essential to know here. Microstepping raises resolution, not accuracy. The finer you divide a step, the smaller the holding torque produced at each micro-step, and once static friction or load torque exceeds that, the rotor doesn't actually move at all. The command says it's moving 1/256th of a step at a time, but physically it's actually jumping abruptly every few steps.
And there's a fundamental danger unique to steppers: losing steps.
A stepper is open-loop. It assumes the rotor is following the stator's magnetic field without ever confirming it. This synchronization breaks under three conditions.
One, when the load torque exceeds what the motor can produce at that speed. A stepper's torque drops off sharply with speed, so you can't just look at the static holding torque when selecting one. Manufacturer documentation recommends leaving a 30 percent margin on the torque-versus-speed curve.
Two, when acceleration is too aggressive. The torque demanded momentarily by the rotor's and load's inertia gets exceeded.
Three, low-frequency resonance. Roughly in the range of 50 to 150 RPM — 167 to 500 full steps per second — the rotor rings like a torsional pendulum and effective torque drops out. If it's fine at other speeds but only loses steps in a specific speed band, this is the cause.
What makes losing steps dangerous is that it's silent. Lose ten steps and the driver says nothing, and the controller still trusts the angle it thinks it knows. That error stays permanently until you re-home. In a robot arm, this means the joint angle no longer matches reality, which means every end-effector position that forward kinematics calculates is now wrong.
For reference, the commonly used 17HS4401S's manufacturer spec is 43 N·cm holding torque, 1.7A phase current — that's 0.43 N·m, less than a quarter of the shoulder joint torque we'll calculate later. Connecting it directly without a reduction gear isn't an option.
BLDC and Encoder — A True Closed Loop
If you want the ceiling on performance, you attach an encoder to a brushless motor and control it directly yourself. Cobots and recent high-performance hobbyist arms go this direction.
A BLDC has no brushes, so there's no wear, its torque density is higher than a brushed motor of the same size, and cooling is easier. In exchange, you have to know the rotor's position to know when to energize the coils, so a position sensor is mandatory.
Magnetic rotary encoders are widely used as the position sensor. A small magnet is mounted on the end of the shaft, and a chip reads the direction of its magnetic field.
| Part | Resolution | Divisions per revolution | Angle | 0.35m end-effector equivalent |
|---|---|---|---|---|
| AS5600 | 12-bit | 4096 | 0.0879 degrees | 0.537 mm |
| AS5047P | 14-bit | 16384 | 0.0220 degrees | 0.134 mm |
| Dynamixel AX-12A | 1024 steps / 300 degrees | 1024 | 0.2930 degrees | 1.790 mm |
| Dynamixel X series | 4096 pulse/rev | 4096 | 0.0879 degrees | 0.537 mm |
The AS5047P supports up to 28,000 RPM and delivers 4096 steps per revolution from its ABI incremental output in binary mode.
Field-oriented control (FOC) is the proper way to drive a BLDC. Instead of handling the three-phase currents directly, it goes through two coordinate transforms. The Clarke transform maps the three phases onto a fixed two-axis frame, and the Park transform then maps that onto a frame rotating along with the rotor. In this frame, the currents become DC quantities that an ordinary PI controller can handle, and the two components' roles separate cleanly. The d-axis current produces flux, and the q-axis current produces torque. That's what lets you command torque directly.
In the hobbyist space, the SimpleFOC library does this work for you. As of v2.4.0, released in February 2026, it supports a wide range of boards — AVR, STM32, ESP32, Teensy, RP2040 — and its documentation recommends the STM32 family once you factor in current sensing.
Summarizing the three approaches:
| Criterion | RC servo | Stepper | BLDC + encoder |
|---|---|---|---|
| Control loop | Built-in closed loop | Open loop | Self-built closed loop |
| What you command | Angle | Step count | Choice of current, speed, or position |
| Reading current angle | Not possible (smart servos can) | Not possible | Possible |
| Torque control | Not possible | Not possible | Possible |
| Silent failure | Doesn't know if it arrived | Doesn't know it lost steps | Error shows up immediately |
| Wiring difficulty | 3 wires | 4 wires + driver | 3-phase + encoder + driver |
| Difficulty to get started | Easiest | Moderate | Hardest |
| Gearbox | Usually built in | Separate | Separate |
Gearboxes — What Gear Ratio Does to Torque and Backlash
Picking a motor isn't the end of it. Most robot-arm joints are driven through a gearbox. There are three reasons, and the third one — the most important — rarely gets mentioned.
Call the gear ratio N.
First, torque grows by a factor of N. More precisely, multiplied by the mechanical efficiency η.
Output torque = Motor torque × N × η
Second, speed drops to 1/N. This is the tradeoff. A motor spinning at 3000 RPM becomes 30 RPM after passing through a 100:1 gearbox.
Third, the load's inertia appears reduced by a factor of 1/N². This is reflected inertia, and it's the real reason a gearbox makes control easier. At 20:1, the inertia of the arm as felt by the motor is 400 times smaller. Smaller apparent inertia means you can accelerate faster with the same torque, and more importantly, changes in the load transfer less to the motor, letting the controller run stably.
Let's look at the numbers. Take a small motor producing 0.09 N·m and attach a few different gear ratios:
| Gear ratio | Assumed efficiency | Output torque | Speed | Reflected inertia |
|---|---|---|---|---|
| 5:1 | 0.97 | 0.437 N·m | 1/5 | 1/25 |
| 20:1 | 0.94 | 1.692 N·m | 1/20 | 1/400 |
| 50:1 | 0.90 | 4.050 N·m | 1/50 | 1/2500 |
| 100:1 | 0.90 | 8.100 N·m | 1/100 | 1/10000 |
The efficiency values are assumptions, and real values vary widely by gearbox type and grade. Precision planetary gearbox manufacturers publish values of 97 percent or better for a single stage and 94 percent or better for two stages, but cheap hobbyist gearboxes fall well below this.
Backlash — What a Gearbox Takes Away
A gearbox doesn't give you torque for free. The biggest thing it costs you is backlash.
For gear teeth to mesh, there has to be a gap between them. With no gap, thermal expansion or manufacturing tolerance would jam the teeth together. But because of that gap, when the input reverses direction, the output doesn't follow along while it crosses that gap. That angle is backlash.
In robotics, it's managed in arcminutes. One arcminute is 1/60th of a degree. Converted for a 0.35-meter arm:
| Backlash | Radians | Slop at the end effector |
|---|---|---|
| 10 arcmin | 2909 μrad | 1.018 mm |
| 5 arcmin | 1454 μrad | 0.509 mm |
| 3 arcmin | 873 μrad | 0.305 mm |
| 1 arcmin | 291 μrad | 0.102 mm |
| 36 arcsec | 175 μrad | 0.061 mm |
| 2 arcsec | 9.7 μrad | 0.003 mm |
Precision planetary gearbox manufacturers publish values ranging by grade from 1, 3, or 5 arcminutes for a single stage to 3, 5, or 7 arcminutes for two stages. Even at a good grade, that leaves roughly 0.1 millimeters of slop at the end effector.
Why backlash matters this much is covered again in the control loop post. In short: within the slop region, the motor turns but the joint doesn't move, so the controller's perceived gain drops to zero, and the moment the teeth mesh, it suddenly snaps back to normal. A system whose gain differs region to region is hard to stabilize with a single set of gains, and it produces a limit cycle — the arm oscillating back and forth continuously near the target.
Why Harmonic Drives Are Used in Robotics
Open up an industrial robot arm's joints, especially at the wrist, and you'll find strain wave gearing inside — better known by the trademark Harmonic Drive.
The structure is unusual. It's made of three parts.
Wave generator An elliptical hub + a thin bearing. The input shaft.
Flex spline A thin cup shape. Flexes radially, but stiff against torsion.
Teeth on the outside. The output shaft.
Circular spline A thick ring. Teeth on the inside, two more teeth than the flex spline.
The wave generator pushes the flex spline into an ellipse,
so the teeth only mesh along the long axis of that ellipse.
One full turn of the input pushes the flex spline back by just 2 teeth.
Two things fall out of this.
A single stage produces a large reduction ratio. Because the tooth-count difference is only 2, the reduction ratio can be very large. Per manufacturer data, component sets are offered at 30, 50, 80, 100, 120, 160:1, and technical documentation states a single stage's reduction ratio ranges from 50:1 to 320:1. Getting 100:1 out of a planetary gearbox needs two or three stages, and backlash accumulates with each added stage.
Multiple teeth are always meshed at once. Because a wide region on both sides of the ellipse's long axis meshes simultaneously, the manufacturer describes this meshing as having zero backlash.
There's something worth pinning down precisely here. "Zero backlash" refers to this meshing specifically — it doesn't mean the total slop between the input and output shafts is zero. The manufacturers themselves state that while a cup-style gear has zero backlash in the meshing itself, cross-axis backlash coming from the input coupling runs 2 to 36 arcseconds. In the table above, 36 arcseconds is 0.061 millimeters at the end effector of a 0.35-meter arm. And separately from this, there's also elastic deformation from torsional stiffness, and that's often actually the larger source of error in practice.
Efficiency is stated by the manufacturer as up to 90 percent at best — lower than a precision planetary gearbox's 97 percent for a single stage. A harmonic drive trades away efficiency to buy precision and reduction ratio.
A third option is the cycloidal gearbox, used in spots needing large torque, like a large robot's shoulder or waist. This part's documentation is especially useful because it publishes error broken down into three separate components: mechanical backlash of 0.1 to 0.3 arcminutes, lost motion of 0.3 to 0.6 arcminutes, and hysteresis loss of 0.2 up to 1 arcminute. This is where it becomes clear that backlash, lost motion, and hysteresis are three genuinely different quantities — which is exactly why the phrase "zero backlash" can be honest, and exactly why you shouldn't pick a part based on that phrase alone.
Working Out Static Torque With Real Numbers — Why the Shoulder Is Bigger Than the Wrist
Now let's calculate that number from the first paragraph.
Let's define the arm like this.
| Segment | Length | Mass |
|---|---|---|
| Upper arm (shoulder to elbow) | 0.20 m | 0.15 kg |
| Forearm (elbow to wrist) | 0.15 m | 0.10 kg |
| Gripper (at the wrist end) | 0.05 m from the wrist axis | 0.15 kg |
| Payload (item being held) | Same location as the gripper | 0.25 kg |
The pose we're calculating for is the arm fully extended horizontally. That's the worst case, where gravity produces maximum torque, and component selection should always be done for the worst case.
Torque is force times lever arm. Treat a uniform rod's weight as acting at its midpoint.
First, the elbow. We only count what's outboard of the elbow.
Forearm: 0.10 kg × 9.81 × 0.075 m = 0.073575 N·m
Gripper: 0.15 kg × 9.81 × 0.15 m = 0.220725 N·m
Payload: 0.25 kg × 9.81 × 0.15 m = 0.367875 N·m
------------------------------------------------
Total 0.662175 N·m
Next, the shoulder. Re-measure every distance from the shoulder.
Upper arm: 0.15 kg × 9.81 × 0.10 m = 0.147150 N·m
Forearm: 0.10 kg × 9.81 × 0.275 m = 0.269775 N·m
Gripper: 0.15 kg × 9.81 × 0.35 m = 0.515025 N·m
Payload: 0.25 kg × 9.81 × 0.35 m = 0.858375 N·m
------------------------------------------------
Total 1.790325 N·m
The wrist only sees the distance to the gripper's and payload's combined center of mass.
(0.15 + 0.25) kg × 9.81 × 0.05 m = 0.196200 N·m
Lining up all three values:
Shoulder 1.790325 N·m
Elbow 0.662175 N·m (1/2.704 of the shoulder)
Wrist 0.196200 N·m (1/9.125 of the shoulder)
The shoulder demands 9.1 times the torque of the wrist.
Two effects stack up to cause this. One, the shoulder carries the weight of everything outboard of it. Two, those weights sit further away from the shoulder. Both distance and mass grow, so their product grows sharply.
That's why robot arms get thicker toward the base. An industrial robot's silhouette, thick at the base and tapering toward the tip, isn't a design choice — it's the result of this calculation.
import numpy as np
G = 9.81
KGCM_PER_NM = 1.0 / 0.0980665 # 1 kg·cm = 0.0980665 N·m (a defined conversion, so this is exact)
# From shoulder toward wrist: (link length m, link mass kg)
LINKS = [(0.20, 0.15), # upper arm
(0.15, 0.10)] # forearm
GRIPPER_MASS = 0.15 # gripper mounted at the wrist end
PAYLOAD_MASS = 0.25 # the object being held
WRIST_OFFSET = 0.05 # from the wrist axis to the gripper+payload center of mass
def static_torque(joint_index):
"""Gravity torque on one joint in the worst-case pose, arm fully extended horizontally.
Only counts mass outboard of this joint."""
outer = LINKS[joint_index:]
reach, total = 0.0, 0.0
for length, mass in outer:
total += mass * G * (reach + length / 2) # a uniform rod's center of mass is at its midpoint
reach += length
total += (GRIPPER_MASS + PAYLOAD_MASS) * G * reach
return total
rows = [("Shoulder", static_torque(0)),
("Elbow", static_torque(1)),
("Wrist", (GRIPPER_MASS + PAYLOAD_MASS) * G * WRIST_OFFSET)]
print("Static torque in the worst-case pose, arm fully extended horizontally")
print(f"{'Joint':<9}{'N·m':>10}{'kg·cm':>10}{'2x safety factor (kg·cm)':>26}")
for name, t in rows:
print(f"{name:<9}{t:10.4f}{t * KGCM_PER_NM:10.3f}{t * 2 * KGCM_PER_NM:26.3f}")
print(f"\nShoulder / Elbow = {rows[0][1] / rows[1][1]:.3f}x")
print(f"Shoulder / Wrist = {rows[0][1] / rows[2][1]:.3f}x")
MG996R_6V = 11.0 * 0.0980665 # manufacturer-published stall torque 11 kg·cm @ 6.0V
print(f"\nMG996R's 6V stall torque, 11 kg·cm = {MG996R_6V:.4f} N·m")
print(f"The shoulder's required torque is {rows[0][1] / MG996R_6V:.3f}x that (even before applying a safety factor)")
Here's the output.
Static torque in the worst-case pose, arm fully extended horizontally
Joint N·m kg·cm 2x safety factor (kg·cm)
Shoulder 1.7903 18.256 36.512
Elbow 0.6622 6.752 13.505
Wrist 0.1962 2.001 4.001
Shoulder / Elbow = 2.704x
Shoulder / Wrist = 9.125x
MG996R's 6V stall torque, 11 kg·cm = 1.0787 N·m
The shoulder's required torque is 1.660x that (even before applying a safety factor)
Picking Parts From This Number
With the calculation done, let's compare against datasheets.
| Part | Manufacturer-published torque | Usable for the shoulder (1.790 N·m)? |
|---|---|---|
| SG90 | 1.8 kg·cm @ 4.8V = 0.177 N·m | No. A tenth of what's needed |
| MG996R | 11 kg·cm @ 6.0V = 1.079 N·m | No. 60 percent of what's needed |
| Dynamixel AX-12A | 1.5 N·m @ 12V | Just barely short. No safety margin |
| Dynamixel XL430-W250-T | 1.4 N·m @ 11.1V | No |
| Dynamixel XM430-W350-R | 3.8 N·m @ 11.1V | Yes. 2.1x safety margin |
| NEMA 17 (17HS4401S), direct drive | 0.43 N·m holding torque | No. A quarter of what's needed |
That's where the arm from the first paragraph fell apart. The MG996R's stall torque is 60 percent of what the shoulder demands.
And there's one more trap in this table. Stall torque is the maximum a motor can briefly produce with the shaft completely stopped. In that state there's no back-EMF, so current is at its peak, and if the motor keeps sitting there, the coils burn. The convention is to treat continuously usable torque as 20 to 30 percent of stall torque, which is exactly why a 2x safety factor is the bare minimum. A 3x safety factor is a more common recommendation.
Apply a 2x safety factor and the shoulder demands 36.5 kg·cm, or 3.58 N·m. In the table above, only the XM430-W350-R satisfies this, and even then, its margin is only 1.06x.
The alternative is a gearbox. If you attach a gearbox to a small 0.09 N·m BLDC, the gear ratio you need is:
N = 3.58 N·m / (0.09 N·m × 0.94) = 42.3
A 50:1 gearbox would do it. Output torque then becomes 4.05 N·m and reflected inertia drops to 1/2500, making control easier too. The tradeoff is speed: the motor's 3000 RPM becomes 60 RPM at the joint. For a robot arm, 60 RPM at the joint is plenty fast.
Another alternative is to make the arm lighter. In the calculation above, the 0.25kg payload accounts for 48 percent of the shoulder's torque. Drop the payload to 0.1kg and the shoulder torque falls to 1.28 N·m, giving even the AX-12A a 1.2x safety margin. When a part falls short, making the motor bigger isn't the only answer.
Power Supply Needs to Be Calculated Separately
Even with torque sorted out, the arm still won't move if the power supply isn't up to it.
Move six servos at once and the currents add up. A single MG996R's stall current is on the order of amps, and if all six hit a load at the same time, that's several amps. Pull that current from a microcontroller board's 5V rail and you will get a brownout, guaranteed.
The physics and fixes for this problem are covered in detail in the driving motors and inductive loads post. In short, there are three: pull servo power from a separate supply, always tie the GNDs together at one point, and put a sufficiently sized capacitor at the power input.
Mismatched logic voltage is common too — driving a 5V servo with a Raspberry Pi's 3.3V signal, or wiring a 12V stepper driver's signal lines into a 3.3V board. Which direction is safe and which one fries a chip is laid out in the logic levels and level shifting post. And the pull-up resistors and debouncing needed when wiring up a limit switch or homing sensor are in the GPIO pull-ups and debouncing post.
Conclusion — The Shape of the Arm Is the Result of a Torque Calculation
Everything covered in this post ultimately converges on a single calculation: how many newton-meters land on this joint.
That value decides the arm's shape. The shoulder demands nine times the torque of the wrist, so the shoulder-side motor is bigger, and a bigger motor is itself heavier, which grows the torque demand further, which gives you a reason to make the links shorter and lighter. Industrial robots all having a similar silhouette is because they all went through the same calculation.
That value decides the gearbox choice too. If the motor alone can't produce the torque you need, you have to buy a gear ratio, and buying a gear ratio means buying backlash along with it, and reducing backlash means accepting a harmonic drive's efficiency loss. None of it is free.
And that value decides the drive method too. A servo is easy but doesn't know its own state; a stepper is cheap and precise but silently loses steps; a BLDC can do everything but you have to write your own control loop.
The calculation you can finish entirely on paper before buying a single part is this whole post. Fix the link lengths, fix the weight you want to lift, multiply and add, and out comes the torque each joint demands. Multiply that by 2 or 3, and that's the number you need to go find on a datasheet. Skip this and buy servos anyway, and you get the arm from the first paragraph.
Next up is calculating where the end effector actually is, given the pose these joints produce. That's the forward kinematics post.