Inverse kinematics
Inverse kinematics determines the joint configuration required to place a robot at a desired Cartesian target.
For a serial manipulator with configuration
forward kinematics provides the Cartesian position of a point \(P\) attached to the robot:
The inverse problem asks for a configuration \(\vec q\) that produces a desired position
The conventions used in this section follow Mathematical notation and conventions, Forward kinematics, and Differential kinematics.
Position inverse kinematics in Moro
The general inverse-kinematics problem may involve both position and orientation:
Moro currently focuses on numerical position inverse kinematics.
The problem solved is therefore
For the current public position IK solver, \(P\) corresponds to the origin of the terminal frame.
Thus,
Orientation constraints are not currently part of the position IK problem solved by Moro.
Important
Moro’s current inverse-kinematics solver addresses Cartesian position, not full pose.
The orientation of the terminal frame is therefore not constrained by the desired target.
Position error
At iteration \(k\), let
be the current joint configuration.
The Cartesian residual is defined as
Its Euclidean norm is
A numerical solution is considered converged when
The tolerance is expressed in the same linear units used for the robot geometry and the target position.
Multiple inverse-kinematics solutions
Unlike forward kinematics, inverse kinematics does not generally define a unique mapping from Cartesian space to joint space.
A target may have
For example, a planar 2R manipulator can often reach the same Cartesian point using two different configurations, commonly described as elbow-up and elbow-down.
Therefore,
This non-uniqueness is one of the reasons why numerical IK depends on the initial configuration used by the solver.
Numerical inverse kinematics
Moro provides three numerical methods:
Newton-type iteration using the Jacobian pseudoinverse,
Levenberg–Marquardt,
Cyclic Coordinate Descent (CCD).
The first two methods use the linear part of the geometric Jacobian,
For position IK,
For a small joint displacement,
The numerical methods use this local relationship to construct joint updates that reduce the position error.
Initial configuration
Iterative IK requires an initial configuration
The solver then generates a sequence
with the goal of reducing
The initial configuration can influence both:
whether the solver converges,
which inverse-kinematics solution is found.
If multiple joint configurations produce the same Cartesian position, different initial configurations may lead to different solution branches.
Note
The initial guess is an algorithmic starting point.
It is not a preferred posture or a secondary optimization objective. The solver is free to move away from \(\vec q_0\) while reducing the Cartesian error.
Automatic initialization
If no initial configuration is provided, Moro generates one randomly within the joint limits.
A reproducible initialization can be obtained through random_state.
Integer seeds use a local NumPy random generator and do not modify NumPy’s global random state.
Joint limits
If joint limits are defined,
the admissible configuration space becomes
A Cartesian target may therefore be reachable by the unconstrained robot model while being unreachable within the allowed joint ranges.
Moro enforces limits by clipping joint updates:
For Jacobian-based methods, clipping is applied to the complete trial configuration.
For CCD, clipping is applied immediately after each individual joint update.
If a user-provided \(\vec q_0\) lies outside the joint limits, Moro clips it to the admissible range before the iterative process begins.
Note
Joint limits are constraints, not optimization objectives.
The current solver does not explicitly attempt to stay near the middle of the joint range or maximize the distance from joint limits.
Clipping can modify the update originally proposed by the numerical method. Consequently, a solver may stagnate at the boundary of the admissible configuration space even while the Cartesian error remains above the requested tolerance.
Newton method
For method="newton", Moro computes a joint update from
In the general case, the update is obtained using the Moore–Penrose pseudoinverse:
Therefore,
When the robot has three degrees of freedom, Moro first attempts to solve the square linear system directly:
If that system is singular, the implementation falls back to the pseudoinverse. For other Jacobian shapes, the pseudoinverse is used directly.
The resulting trial configuration is then projected onto the joint limits.
Newton-type updates can converge rapidly near a suitable solution, but their behavior depends on the local Jacobian and the initial configuration.
Near singularities or poorly conditioned configurations, the pseudoinverse may generate large or unstable joint updates.
Levenberg–Marquardt
Levenberg–Marquardt is the default position IK method in Moro.
For method="lm", the update is
The trial configuration is
followed by projection onto the joint limits.
The regularization term
limits excessively large joint updates when the Jacobian is ill-conditioned or close to singular.
The update may also be interpreted as the solution of the regularized least-squares problem
The first term attempts to reduce Cartesian error, while the second penalizes large joint changes.
Adaptive damping
Moro adjusts the damping parameter during the iteration.
Let
be damping_scale.
If the trial configuration improves the error,
the step is accepted and
If the trial configuration does not improve the error, the step is rejected and
Thus, successful steps make the method progressively less damped, while unsuccessful steps increase regularization.
A rejected LM trial still counts as one algorithm iteration.
Cyclic Coordinate Descent
Cyclic Coordinate Descent, or CCD, solves inverse kinematics without explicitly using a Jacobian matrix.
Instead, it updates one joint at a time, starting from the terminal joint and moving toward the base:
One complete sweep through all joints is considered one CCD iteration in Moro.
CCD for revolute joints
Consider revolute joint \(i\).
Its axis is
and its origin is
Let the current end-effector position be
and the desired target be
Construct the vectors
and
A revolute joint can only rotate these vectors around its own axis.
Therefore, both vectors are projected onto the plane perpendicular to
The projections are
and
After normalization,
The signed angular update is obtained from
and
Thus,
The joint is updated according to
and then clipped to its joint limits.
Geometrically, the update attempts to rotate the end-effector direction toward the target direction within the plane of motion available to that joint.
If either projected vector is too small to define a reliable direction, Moro skips that individual angular update.
CCD for prismatic joints
For a prismatic joint, motion is restricted to translation along its axis.
The current position residual is
The required joint displacement is obtained by projecting this residual onto the joint axis:
The update is therefore
followed by clipping to the corresponding joint limits.
Moro recomputes the current end-effector position before the prismatic update so that the residual reflects changes already made by other joints during the same CCD sweep.
Convergence and termination
Solver termination does not necessarily imply convergence.
The main success condition is
A solve may also terminate because of:
maximum iterations,
joint-step stagnation,
error-improvement stagnation,
numerical failure.
Therefore,
Maximum iterations
If the tolerance has not been reached after the allowed number of global iterations,
the solver terminates without convergence.
The default maximum is method dependent:
100 iterations for Newton and LM,
500 sweeps for CCD.
Reaching the iteration limit does not prove that the target is unreachable. It only indicates that the selected method did not converge within the available iteration budget.
Stagnation by joint step
The effective joint update is measured after applying joint limits.
For Newton and LM,
For CCD, it is measured between the configurations before and after a complete sweep.
If
while the Cartesian error remains above the desired tolerance, a stagnation counter is increased.
The solver terminates when this condition persists for
consecutive iterations or sweeps.
Stagnation by lack of error improvement
Moro also tracks the change in Cartesian error:
If
for the required number of consecutive iterations, the solver terminates because the error is no longer improving sufficiently.
This condition can occur near singularities, joint-limit boundaries, unreachable targets, or unfavorable local configurations.
Numerical failures
Moro checks that quantities produced during numerical IK remain finite.
Controlled numerical failure results may be generated when finite values cannot be obtained while evaluating:
forward kinematics,
the position Jacobian,
the joint update,
CCD geometric quantities.
Invalid user inputs, unresolved symbolic parameters, and failures to construct valid numerical functions are treated separately as input or setup errors.
Position IK result
The result of solving one Cartesian position target is represented by
IKSolution
which contains:
q,converged,iterations,error,method,residual,message.
Final configuration
q contains the final valid joint configuration reached by the solver.
This field is available even when the solver does not converge.
Convergence status
converged indicates whether the requested position tolerance was achieved.
For a valid converged result,
This invariant is enforced by IKSolution.
Residual and error
When available,
The reported scalar error satisfies
A finite residual must contain exactly three components.
If no finite residual can be obtained after a numerical failure,
residual = None
error = np.inf
is used instead.
Iteration count
For Newton and LM, iterations counts attempted global updates.
For LM, rejected trial steps still count.
For CCD, iterations counts complete joint sweeps.
If the initial configuration already satisfies the requested tolerance,
iterations = 0
is returned.
Outcome message
message contains a short description of the termination cause, such as:
successful convergence,
maximum iterations,
step stagnation,
error stagnation,
numerical failure.
Solving a sequence of position targets
Moro also provides sequential position IK through
solve_position_trajectory(...)
for a sequence
The first target uses the user-provided initial configuration
After a target converges, its solution is reused as the initial configuration for the next target:
This strategy is commonly called a warm start.
It can reduce the number of iterations and often encourages local continuity between neighboring IK solutions.
Important
Sequential seeding does not guarantee global branch continuity.
solve_position_trajectory does not perform branch optimization, smoothing, timing, interpolation, or global trajectory planning.
The trajectory solver stops at the first target that does not converge.
Trajectory IK result
A sequence of IK solves is represented by
IKTrajectorySolution
which contains:
solutions,converged,failed_index,message.
Successful trajectory
A converged trajectory requires every individual solve to have converged:
In this case,
failed_index = None
is required.
Failed trajectory
If target \(k\) is the first one that does not converge, processing stops and
The failed IKSolution is retained as the final processed result.
All previous solutions are guaranteed to be converged:
while
Therefore, a failed trajectory result has the structure
Targets after the failing one are not processed.
Convenience properties
IKTrajectorySolution provides convenient access to
trajectory.qs
trajectory.errors
trajectory.iterations
which return the per-target joint configurations, final error norms, and iteration counts, respectively.
Inverse kinematics in Moro
A single Cartesian target can be solved using
from moro.inverse_kinematics import solve_position_ik
solution = solve_position_ik(
robot,
target_position,
q0=initial_guess,
)
The available methods are
method="newton"
method="lm"
method="ccd"
with Levenberg–Marquardt used by default.
For symbolic robot models containing geometric parameters, numerical values can be supplied through
parameters={...}
These substitutions are applied locally to the inverse-kinematics expressions and do not modify the robot model or its cached symbolic expressions.
Example: planar 2R manipulator
Consider a planar 2R robot with link lengths \(a_1\) and \(a_2\).
Its forward position is
For a desired Cartesian position
the inverse-kinematics problem is
Using Moro:
import moro as mr
from moro.abc import l1, l2, q1, q2
from moro.inverse_kinematics import solve_position_ik
robot = mr.Robot(
(l1, 0, 0, q1, "r"),
(l2, 0, 0, q2, "r"),
)
solution = solve_position_ik(
robot,
[1.5, 0.5, 0.0],
q0=[0.1, 0.1],
parameters={
l1: 1.0,
l2: 1.0,
},
)
The resulting object can be inspected through
solution.q
solution.converged
solution.error
solution.residual
solution.iterations
solution.message
Different initial guesses may lead to different valid joint configurations for the same Cartesian target.
Example: sequence of targets
A sequence of Cartesian targets can be solved as
from moro.inverse_kinematics import solve_position_trajectory
targets = [
[1.5, 0.2, 0.0],
[1.4, 0.4, 0.0],
[1.2, 0.6, 0.0],
]
trajectory = solve_position_trajectory(
robot,
targets,
q0=[0.1, 0.1],
parameters={
l1: 1.0,
l2: 1.0,
},
)
The sequence of joint configurations is available through
trajectory.qs
and can be used, for example, as input to a robot animation workflow.
Scope and limitations
The current inverse-kinematics implementation in Moro provides numerical position IK for serial manipulators.
It supports:
revolute and prismatic joints,
joint limits,
user-defined or reproducible random initialization,
Newton-type pseudoinverse updates,
adaptive Levenberg–Marquardt,
Cyclic Coordinate Descent,
stagnation detection,
sequential position targets,
controlled numerical-failure results.
The current implementation does not provide:
full-pose inverse kinematics,
orientation-error constraints,
analytical closed-form IK,
collision avoidance,
global IK branch optimization,
trajectory interpolation,
trajectory timing,
joint-space smoothing,
global motion planning.
Summary of conventions
Concept |
Moro convention |
|---|---|
IK scope |
Position inverse kinematics |
Target |
\(\vec r_d^{\,0}\in\mathbb R^3\) |
Current position |
\(\vec r_{O_n}^{\,0}(\vec q)\) |
Residual |
\(\vec e=\vec r_d^{\,0}-\vec r_{O_n}^{\,0}\) |
Error |
\(|\vec e|_2\) |
Convergence |
\(|\vec e|_2<\texttt{tol}\) |
Jacobian used for IK |
\(J_p=J[:3,:]\) |
Newton update |
\(J_p^\dagger\vec e\) |
LM update |
\((J_p^TJ_p+\lambda^2I)^{-1}J_p^T\vec e\) |
LM damping |
Adaptive |
CCD joint order |
\(n,n-1,\ldots,1\) |
Joint limits |
Enforced by clipping |
Missing |
Random initialization within limits |
Random reproducibility |
|
Newton/LM iteration |
One attempted global update |
CCD iteration |
One complete joint sweep |
Trajectory initialization |
Previous converged solution |
Trajectory failure |
Stop at first non-converged target |
Full pose IK |
Not currently supported |
Inverse kinematics complements forward and differential kinematics by solving the local numerical search problem in the opposite direction: from a desired Cartesian position to an admissible joint configuration.