Inverse Kinematics

DART ships with a modular inverse kinematics (IK) framework that works the same way across C++ and dartpy. Every end effector can own an dart::dynamics::InverseKinematics instance that exposes:

  • A target frame (typically a dart::dynamics::SimpleFrame) describing the desired pose

  • Optional hierarchy levels so you can stack multiple objectives

  • A gradient method implementation that numerically optimizes the joint vector or an analytical solver that produces closed-form solutions

The IK module updates the owning skeleton directly, so you can wire it into UI handlers, controllers, or headless loops without writing glue code.

Workflow overview

  1. Create or locate a dart::dynamics::EndEffector (BodyNode::createEndEffector in C++ / body_node.createEndEffector in dartpy).

  2. Create or fetch the IK instance with EndEffector::createIK() (C++) or end_effector.getIK(True) (dartpy) to build the solver if it does not already exist.

  3. Configure the target, hierarchy level, error bounds, and solver tolerances. Targets are ordinary dart::dynamics::SimpleFrame objects in both languages.

  4. Choose a gradient method (default GD, damped least squares, etc.) or plug in an analytical solver such as IkFast.

  5. Call InverseKinematics::solve() (ik.solveAndApply(True) in dartpy when you want to apply the result) to update the skeleton.

For analytical solver integration, see IkFast Support and Integration, which pairs the API with the maintained Filament wam-ikfast scene.

Quick example

auto hand = robot->getBodyNode("hand");
auto ee = hand->createEndEffector("hand_ee");
auto ik = ee->createIK();

auto target = dynamics::SimpleFrame::createShared(
    dynamics::Frame::World(), "hand_target");
target->setTransform(ee->getTransform());

ik->setTarget(target);
ik->setActive(true);
ik->solveAndApply(true);

Gradient methods

Gradient methods iterate numerically until the desired pose is met. DART exposes multiple built-in strategies (Jacobians with pseudo-inverse, damped least squares, biasing functions, joint limit soft constraints, etc.) that you can mix via InverseKinematics::setGradientMethod(). The “Whole-Body IK” tutorial shows how to:

  • Clamp translation/rotation error bounds to tighten convergence

  • Bias floating-base DOFs to keep the robot balanced

  • Stack multiple objectives (hands, head, torso) using hierarchy levels

  • Drive the solver headlessly for scripted trajectories

All of these APIs are mirrored in dartpy, so once you obtain an IK object you can call ik.useWholeBody(True), ik.getGradientMethod(), and other setter functions exactly as you would in C++.

Analytical methods

Analytical IK solvers emit closed-form joint configurations without iteratively optimizing a cost function. DART exposes them through dart::dynamics::InverseKinematics::Analytical and lets you mix them with gradient objectives―for example, you can solve a 6-DOF manipulator analytically while leaving the rest of the skeleton to the gradient backend.

The most common implementation is IkFast; consult the page below for current upstream status, generation instructions, and DART’s support policy. Analytical solvers appear in both languages through InverseKinematics::getAnalytical() and ik.getAnalytical(); however, only the C++ API currently exposes the IkFast shared-library helper as described on the next page.