# Inverse kinematics Inverse kinematics determines the joint configuration required to place a robot at a desired Cartesian target. For a serial manipulator with configuration $$ \vec q= \begin{bmatrix} q_1 & q_2 & \cdots & q_n \end{bmatrix}^{T}, $$ forward kinematics provides the Cartesian position of a point $P$ attached to the robot: $$ \boxed{ \vec r_P^{\,0}=f_P(\vec q). } $$ The inverse problem asks for a configuration $\vec q$ that produces a desired position $$ \vec r_d^{\,0}. $$ The conventions used in this section follow [Mathematical notation and conventions](notation.md), [Forward kinematics](forward-kinematics.md), and [Differential kinematics](differential-kinematics.md). ## Position inverse kinematics in Moro The general inverse-kinematics problem may involve both position and orientation: $$ T(\vec q)=T_d. $$ Moro currently focuses on **numerical position inverse kinematics**. The problem solved is therefore $$ \boxed{ \text{Given }\vec r_d^{\,0}, \text{ find }\vec q\in\mathcal Q \text{ such that } \vec r_P^{\,0}(\vec q)\approx\vec r_d^{\,0}. } $$ For the current public position IK solver, $P$ corresponds to the origin of the terminal frame. Thus, $$ \boxed{ P=O_n. } $$ 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 $$ \vec q_k $$ be the current joint configuration. The Cartesian residual is defined as $$ \boxed{ \vec e_k = \vec r_d^{\,0} - \vec r_{O_n}^{\,0}(\vec q_k). } $$ Its Euclidean norm is $$ \boxed{ e_k = \|\vec e_k\|_2. } $$ A numerical solution is considered converged when $$ \boxed{ e_k<\texttt{tol}. } $$ 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 $$ \boxed{ 0,\quad 1,\quad \text{multiple, or infinitely many solutions}. } $$ 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, $$ \vec r_d \not\Rightarrow \text{a unique }\vec q. $$ 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, $$ \boxed{ J_p = J[:3,:]. } $$ For position IK, $$ \vec v_{O_n}^{\,0} = J_p(\vec q)\dot{\vec q}. $$ For a small joint displacement, $$ \Delta\vec r \approx J_p(\vec q)\Delta\vec q. $$ The numerical methods use this local relationship to construct joint updates that reduce the position error. ## Initial configuration Iterative IK requires an initial configuration $$ \boxed{ \vec q_0. } $$ The solver then generates a sequence $$ \vec q_0,\vec q_1,\vec q_2,\ldots $$ with the goal of reducing $$ \|\vec e(\vec q)\|. $$ 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, $$ q_i^{\min}\leq q_i\leq q_i^{\max}, $$ the admissible configuration space becomes $$ \boxed{ \mathcal Q_{\mathrm{adm}} = \left\{ \vec q: q_i^{\min}\leq q_i\leq q_i^{\max} \right\}. } $$ 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: $$ \boxed{ q_i \leftarrow \min \left( q_i^{\max}, \max(q_i^{\min},q_i) \right). } $$ 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 $$ J_p(\vec q_k)\Delta\vec q_k \approx \vec e_k. $$ In the general case, the update is obtained using the Moore--Penrose pseudoinverse: $$ \boxed{ \Delta\vec q_k = J_p^\dagger(\vec q_k)\vec e_k. } $$ Therefore, $$ \boxed{ \vec q_{k+1} = \vec q_k + J_p^\dagger(\vec q_k)\vec e_k. } $$ When the robot has three degrees of freedom, Moro first attempts to solve the square linear system directly: $$ J_p\Delta\vec q=\vec e. $$ 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 $$ \boxed{ \Delta\vec q_k = \left( J_p^TJ_p+\lambda_k^2I \right)^{-1} J_p^T\vec e_k. } $$ The trial configuration is $$ \vec q_{\mathrm{trial}} = \vec q_k+\Delta\vec q_k, $$ followed by projection onto the joint limits. The regularization term $$ \lambda_k^2I $$ 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 $$ \boxed{ \min_{\Delta\vec q} \left( \|J_p\Delta\vec q-\vec e\|_2^2 + \lambda^2\|\Delta\vec q\|_2^2 \right). } $$ 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 $$ 0