Back to Blog

S-Curve Trajectory for a Robot Joint: A Worked Jerk-Limited Motion Profile

From jerk and acceleration limits to the seven phase durations of a real move

A trapezoidal velocity profile is the first motion profile most builders reach for, and for good reason: it is easy to compute and it gets a joint from rest to rest in near-minimum time. But it has a hidden cost. At the corners of the trapezoid, acceleration jumps instantaneously from zero to its maximum and back. That step in acceleration is infinite jerk, and your joint feels it as a sharp jolt at the start and end of every move. The gearbox rattles, the arm tip rings, and over time the mechanical play gets worse.

The fix is an S-curve trajectory: a jerk-limited motion profile that ramps the acceleration up and down smoothly instead of switching it on and off. This article works through the full seven-phase computation for a single robot joint with real numbers, then shows the check you need for short moves where the profile never reaches its limits.

What a jerk-limited S-curve trajectory actually is

The name comes from the shape of the velocity curve: instead of straight ramps, the velocity follows an S at each end. That S shape is what you get when acceleration itself ramps linearly instead of stepping. The quantity you are limiting is jerk, the derivative of acceleration.

A full rest-to-rest S-curve move has seven phases:

  1. Jerk up: acceleration rises from 0 to +A at constant jerk +J.
  2. Constant acceleration: acceleration held at +A.
  3. Jerk down: acceleration falls from +A to 0 at jerk -J, and velocity reaches its peak V.
  4. Constant velocity (cruise): acceleration is 0, velocity held at V.
  5. Jerk down: acceleration falls from 0 to -A.
  6. Constant deceleration: acceleration held at -A.
  7. Jerk up: acceleration rises from -A back to 0, velocity returns to rest.

You feed the planner three limits: the maximum jerk J, the maximum acceleration A, and the maximum velocity V. The job is to find the duration of each phase so the joint travels exactly the commanded distance L.

The worked example: a 90 degree joint move

Take one joint of a robot arm and command it to slew 90 degrees, so the target displacement is L = 1.5708 rad. Pick these limits:

Step 1: does the profile reach maximum acceleration?

The acceleration ramp needs enough velocity room to actually reach A. The condition is V >= A^2 / J. Here A^2 / J = 64 / 80 = 0.8 rad/s, and V = 2.0 rad/s is comfortably larger, so yes, the joint reaches full acceleration A.

Step 2: the jerk phase duration

Each jerk phase ramps acceleration between 0 and A at rate J, so its duration is

T_j = A / J = 8.0 / 80 = 0.1 s

During a single jerk phase the velocity gained is 0.5 * J * T_j^2 = 0.5 * 80 * 0.01 = 0.4 rad/s. The two jerk phases of the acceleration segment (phases 1 and 3) together add A * T_j = 8.0 * 0.1 = 0.8 rad/s.

Step 3: the constant-acceleration phase duration

The joint still needs to gain V minus 0.8 = 1.2 rad/s at constant acceleration A:

T_a = (V - A * T_j) / A = 1.2 / 8.0 = 0.15 s

So the full acceleration segment takes T_acc = 2 * T_j + T_a = 0.2 + 0.15 = 0.35 s. By symmetry the deceleration segment takes the same 0.35 s.

Step 4: distance used by accelerating and decelerating

An S-curve velocity segment that runs from 0 to V is antisymmetric about its midpoint, so its average velocity is exactly V/2. The distance to accelerate up to V is therefore

d_acc = (V / 2) * T_acc = 1.0 * 0.35 = 0.35 rad

Decelerating from V back to rest uses another 0.35 rad, so the two ends consume 0.70 rad.

Step 5: is there a cruise phase?

The accel and decel segments together need 0.70 rad. The commanded move is 1.5708 rad, which is larger, so a constant-velocity phase exists. Its length is

d_cruise = L - 2 * d_acc = 1.5708 - 0.70 = 0.8708 rad
T_v = d_cruise / V = 0.8708 / 2.0 = 0.4354 s

Step 6: total move time

Add it up:

T_total = T_acc + T_v + T_dec = 0.35 + 0.4354 + 0.35 = 1.1354 s

That is the full jerk-limited trajectory. Compared with a trapezoidal profile using the same V and A, the S-curve costs a little extra time (the rounded corners) but keeps jerk bounded at 80 rad/s^3 everywhere instead of spiking to infinity.

The short-move check

The computation above assumed the move was long enough to reach cruise velocity V. For short moves that assumption breaks, and this is where a lot of naive planners produce garbage. There are two escalating cases:

Take the same limits but command only L = 0.5 rad. The accel plus decel distance to reach V is 0.70 rad, which is larger than 0.5, so V is not reached. Assuming A is still reached, the peak velocity V' solves a quadratic that comes from L = V' * T_j + V'^2 / A:

V'^2 + A * T_j * V' - A * L = 0

With A = 8, T_j = 0.1, L = 0.5 this gives V' = (-0.8 + sqrt(0.64 + 16)) / 2 = (-0.8 + 4.079) / 2 = 1.64 rad/s. Since 1.64 is still above A^2/J = 0.8, full acceleration is reached, so the profile has six phases (no cruise) and the total time is 2 * (T_j + V'/A) = 2 * (0.1 + 0.205) = 0.61 s. Always run this check before trusting the seven-phase result.

A compact planner in Python

import math

def s_curve_time(L, V, A, J):
    Tj = A / J                      # jerk phase duration
    if V < A * A / J:               # A is never reached
        Tj = math.sqrt(V / J)
        A = J * Tj
    Ta = (V - A * Tj) / A           # constant-accel duration
    d_acc = (V / 2.0) * (2 * Tj + Ta)
    if 2 * d_acc > L:               # V is never reached, reduce peak
        Vp = (-A * Tj + math.sqrt((A * Tj) ** 2 + 4 * A * L)) / 2.0
        return 2 * (Tj + Vp / A), Vp
    d_cruise = L - 2 * d_acc
    Tv = d_cruise / V
    return 2 * (2 * Tj + Ta) + Tv, V

print(s_curve_time(1.5708, 2.0, 8.0, 80.0))  # ~ (1.135, 2.0)
print(s_curve_time(0.5, 2.0, 8.0, 80.0))      # ~ (0.610, 1.64)

Once you have the phase durations you integrate jerk to get acceleration, velocity, and position at your control-loop rate, then feed the position setpoints to the joint controller. If you are still choosing that loop rate and its actuator torque headroom, the jerk you pick here directly sets the peak torque demand, which ties straight into motor and gearbox sizing for a robot arm joint.

Why bother over a trapezoid

The trapezoidal profile in our trajectory planning walkthrough is fine for slow, stiff, lightly loaded joints. But as soon as you have a long arm, a flexible transmission, or a payload that must not slosh or wobble, bounding jerk pays off: less structural ringing, gentler gear loading, and smoother tracking. The extra few tens of milliseconds per move is almost always worth it.

Building or studying robotics?

Arcbotix publishes practical guides on robotics engineering, control systems and real-world builds. Explore more articles on the blog.