Skip to content

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:

import novaphy
solver_type = novaphy.ik.IKSolver

from novaphy import ik

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_problems and seed expansion do not create a CUDA batch.
  • IKJacobianType has no AUTODIFF or MIXED value.
  • A raw finalized Model lacks the Python joint descriptors needed by the hand-written analytic Jacobian, so ANALYTIC currently 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.

See also