Hi. I really relate to your question — I also struggled to understand servoj parameters at first. Not sure if this will help, but let me share how I understand servoj and the empirical trends I saw from my own parameter tests.
1) servoj is not a “one-shot move” command — it’s streaming servo tracking
movej/movel generate a full trajectory internally and execute it to completion.
servoj, on the other hand, means: “for the next t seconds, keep tracking this joint target.”
So servoj is designed for continuous streaming of targets, typically at a fixed rate like 125 Hz (8 ms).
2) Why doesn’t the robot stop if you call servoj for t and wait t?
This is not mainly due to lookahead_time.
It’s because the next target arrives on time, so the servo loop stays active.
-
If a new target arrives every t seconds (or faster),
the robot assumes the stream is continuous and keeps tracking without braking.
-
If targets arrive later than t,
the robot runs out of targets at the end of the interval, so it starts slowing down / pausing, and may even trigger protective stops.
So the “no stop in between” behavior comes from servoj’s streaming-tracking nature.
3) What lookahead_time really does (why it smooths motion)
lookahead_time makes the controller reference a near-future target, allowing it to keep velocity/acceleration more continuous even when the target stream is noisy or step-like.
-
Smaller lookahead_time (e.g., 0.03s)
-
Larger lookahead_time (e.g., 0.2s)
-
motion is smoother and more stable
-
but with more lag, so it may fall behind when targets change quickly
This matches my tests:
-
lookahead 0.03 felt fast but noticeably less stable/accurate,
-
lookahead 0.2 felt much smoother/stable but slower to respond.
4) gain is “how aggressively the robot chases the target”
A more intuitive way to phrase it:
higher gain makes the robot latch onto the target faster and harder; lower gain makes it approach more gently.
-
High gain (e.g., 2000)
-
Low gain (e.g., 100)
Again consistent with my tests:
5) Effect of t (command duration / streaming period)
t is both how long each target is tracked and the expected update interval.
-
Smaller t (higher update rate) → faster tracking, but more sensitive to jitter/noise
-
Larger t (lower update rate) → smoother/stabler, but slower response
My tests showed the same trade-off:
6) If your goal is real-time tracking, consider init_realtime_pose / set_realtime_pose
I implemented real-time tracking using URScript’s init_realtime_pose and set_realtime_pose.
If your purpose is to continuously update targets from an external source, this method can also be a good fit, sometimes even more straightforward than raw servoj streaming.
7) Tip: if joint targets aren’t intuitive, drive servoj from TCP pose
I personally found joint angles hard to reason about.
So I generated joint targets from a desired TCP pose via IK, which felt much more intuitive:
servoj(
get_inverse_kin(new_pose),
t=command_time_interval,
lookahead_time=lookahead_time,
gain=gain
)
Thinking in TCP space made it easier to understand what was happening and tune parameters.
In short:
-
t controls update bandwidth / tracking frequency
-
lookahead_time smooths motion by referencing near-future targets
-
gain controls how strongly and quickly the robot converges to each target
And the smoothness vs. accuracy/response trade-off comes from the combination of those three.