novaphy.ik¶
CPU/NumPy inverse kinematics for NovaPhy articulations. The current public
surface includes the Newton-aligned class API—IKSolver, composable
objectives, LM/L-BFGS optimizers, and seed samplers—plus the earlier
free-function compatibility layer.
import numpy as np
from novaphy import ik
position = ik.IKObjectivePosition(
link_index=end_effector_body,
link_offset=np.zeros(3, dtype=np.float32),
target_positions=np.array([[0.5, 0.2, 0.4]], dtype=np.float32),
)
solver = ik.IKSolver(
model=model,
n_problems=1,
objectives=[position],
optimizer=ik.IKOptimizer.LM,
jacobian_mode=ik.IKJacobianType.FINITE_DIFF,
)
q_in = np.asarray(model.joint_q, dtype=np.float32).reshape(1, -1).copy()
q_out = np.empty_like(q_in)
solver.step(q_in, q_out, iterations=50)
novaphy.ik is imported by novaphy, so both of these forms are public:
Class API¶
| Class / enum | Description |
|---|---|
| IKSolver | High-level sampling, optimizer dispatch, and best-seed selection. |
| IKObjective | Base class for a residual/Jacobian block. |
| IKObjectivePosition | Match the world position of a point on a link. |
| IKObjectiveRotation | Match a link-frame orientation using xyzw quaternions. |
| IKObjectiveJointLimit | Soft per-coordinate joint-limit penalty. |
| IKJacobianType | ANALYTIC or FINITE_DIFF; NovaPhy has no autodiff IK backend. |
| IKOptimizer | Optimizer selector: LM or LBFGS. |
| IKOptimizerLM | Levenberg-Marquardt with adaptive trust-region damping. |
| IKOptimizerLBFGS | L-BFGS with Wolfe line search. |
| IKSampler | NONE, GAUSS, UNIFORM, or ROBERTS seed expansion. |
The concrete objective names begin with IKObjective. Symbols from an
older documentation plan—IKPositionObjective, IKRotationObjective,
IKJointLimitObjective, IKJacobianMode, IKLevenbergMarquardt,
IKLBFGS, and IKSamplingMode—are not public NovaPhy classes.
Objective composition¶
IKObjectivePosition and IKObjectiveRotation accept one target row per
problem. Targets can be changed without rebuilding the solver:
position.set_target_position(0, next_position)
rotation.set_target_rotation(0, next_quaternion_xyzw)
solver.reset()
solver.step(q_in, q_out, iterations=20)
IKObjectiveJointLimit adds a soft hinge residual for coordinates outside
the supplied lower/upper arrays. It does not hard-clamp class-style
optimizer steps.
IKSolver.step() writes (n_problems, joint_coord_count) float32 arrays,
returns None, and may run in place. solver.costs reports the squared
residual norm for every expanded seed. With n_seeds > 1, the lowest-cost
seed for each problem is gathered into the output.
Current execution boundaries¶
Scalar-coordinate IK only
The optimizer currently requires joint_coord_count == joint_dof_count.
Revolute and Prismatic serial chains are supported. Ball, Free, and D6
joints need a quaternion/manifold retraction and are not yet supported.
Keep free-jointed props out of the IK-only model.
- IK executes serially on the CPU.
n_problemsand seed expansion do not create a CUDA batch. IKJacobianTypehas noAUTODIFForMIXEDvalue.- A raw finalized
Modellacks the Python joint descriptors needed by the hand-written analytic Jacobian, soANALYTICcurrently falls back to finite differences. - The Python-only JointBodyBundle enables the true analytic path, but only Revolute/Prismatic columns are implemented. Unsupported multi-DOF columns remain zero.
- The class solver uses a fixed iteration count and has no tolerance-based return flag.
See Robotics and inverse kinematics for a complete workflow and the separate robot-only IK model pattern.
Compatibility functions¶
The legacy functions are implemented and remain public:
| Class / function | Description |
|---|---|
| JointBodyBundle | Python (joints, bodies) bridge with cached FK model. |
| solve_ik() | Position-only LM wrapper returning (q, converged). |
| solve_ik_pose() | Position + orientation LM wrapper. |
| solve_ik_pose_best_of_seeds() | Deterministic multi-start compatibility wrapper. |
| compute_jacobian_position() | Legacy finite-difference position Jacobian. |
| compute_jacobian_angular_velocity() | Legacy angular-velocity Jacobian. |
| get_ee_position() | World-frame end-effector position. |
| get_ee_rotation() | World-frame end-effector rotation matrix. |
| get_link_transforms() | World transforms for every selected link. |
| rotation_error_axis_angle() | Robust world-frame axis-angle rotation error. |
The solver wrappers are implemented on top of IKSolver with LM. They run
the requested fixed iteration count, evaluate convergence afterward, and
apply a final hard clip when explicit joint limits are supplied.
Demos¶
| Demo | What it shows |
|---|---|
python/demos/mujoco/demo_robot_panda_hydro.py |
Class-style pose IK feeding simulation joint targets. |
python/demos/demo_ik_arm.py |
ViewerGL target gizmo, standard-state FK rendering, headless solve, and benchmarks. |
python/demos/ik_arm_demo/benchmark_compare.py |
LM finite-difference, LM analytic, and L-BFGS comparison. |