How to Implement Inverse Kinematics in DART Using the IKFast Module

To implement inverse kinematics in DART using IKFast, you must generate a C++ solver from your robot URDF, compile it into a shared library, then load it at runtime using the SharedLibraryIkFast wrapper class and attach it to a dart::dynamics::InverseKinematics object via setGradientMethod.

The DART simulation library (dartsim/dart) provides a built-in analytical IK interface that integrates with pre-generated IKFast solvers from OpenRAVE. This architecture allows you to swap the default gradient-based IK with a fast, closed-form solution for compatible robot kinematic chains.

Understanding the IKFast Architecture in DART

DART’s IKFast integration follows a three-layer architecture that separates code generation from runtime execution:

  1. IKFast Generator (external tool): Produces a single C++ file containing ComputeIk, ComputeFk, and related functions. The WAM arm example in the repository shows this output at examples/wam_ikfast/ikfast/ikfast71.Transform6D.4_6_9_10_11_12_f8.cpp.

  2. Shared-Library Wrapper: The SharedLibraryIkFast class (defined in dart/dynamics/shared_library_ik_fast.hpp and implemented in dart/dynamics/shared_library_ik_fast.cpp) loads your compiled .so, .dylib, or .dll at runtime using dart::common::SharedLibrary::create. It binds required symbols like GetNumFreeParameters and ComputeIk via the loadFunction helper, then exposes these through virtual overrides such as computeIk() and getNumJoints().

  3. DART Analytical IK API: The abstract IkFast base class (in dart/dynamics/ik_fast.hpp) integrates with dart::dynamics::InverseKinematics. When you call setGradientMethod<SharedLibraryIkFast>(), the InverseKinematics::Analytical subsystem stores DOF mappings and forwards solution requests to the loaded solver’s ComputeIk function.

Prerequisites: Generating and Compiling the IKFast Solver

Before running IK in DART, you must generate and compile the solver outside the DART codebase.

Step 1: Generate the IKFast C++ Source

Use OpenRAVE’s generator script to create an analytical solver for your specific robot kinematics:

git clone https://github.com/rdiankov/openrave
cd openrave
python3 python/ikfast_generator_cpp.py \
    --robot=my_robot.urdf \
    --iktype=Transform6D \
    --freeindex=2 \
    --output=ikfast71.Transform6D.my_robot.cpp

This produces a file containing the ComputeIk function that calculates joint angles given a target end-effector transform.

Step 2: Build the Shared Library

Create a minimal CMakeLists.txt following the pattern in examples/wam_ikfast/ikfast/CMakeLists.txt:

cmake_minimum_required(VERSION 3.12)
project(GeneratedMyRobotIkFast LANGUAGES CXX)

add_library(GeneratedMyRobotIkFast SHARED ikfast71.Transform6D.my_robot.cpp)
target_compile_definitions(GeneratedMyRobotIkFast PRIVATE IKFAST_NO_MAIN IKFAST_CLIBRARY)

Compile the library:

mkdir build && cd build
cmake .. && make

This produces libGeneratedMyRobotIkFast.so (Linux), .dylib (macOS), or .dll (Windows).

Loading and Configuring the Solver in DART

With the shared library compiled, you can load it into a DART application. The integration test in tests/integration/io/test_ik_fast.cpp demonstrates the complete workflow.

Setting Up the Skeleton and End Effector

First, load your robot and create an IK object attached to the end-effector body node:

#include <dart/dart.hpp>
using namespace dart::dynamics;

// Load robot model
auto skel = dart::io::readSkeleton(
    dart::common::Uri::createFromPath("path/to/robot.urdf"));
assert(skel);

// Create end-effector and IK controller
auto ee = skel->getBodyNode("hand")->createEndEffector("ee");
auto ik = ee->createIK();

Configuring the Shared Library Wrapper

Use setGradientMethod<SharedLibraryIkFast>() to replace the default gradient-based solver with your analytical library. You must explicitly map the joint indices that IKFast solves versus those left as free parameters:

std::string libPath = "libGeneratedMyRobotIkFast.so";  // Adjust extension per OS

// Indices must match the DOF order expected by your generated solver
std::vector<std::size_t> solvedDofs = {0, 1, 3, 4, 5, 6};
std::vector<std::size_t> freeDofs   = {2};

ik->setGradientMethod<SharedLibraryIkFast>(libPath, solvedDofs, freeDofs);

The solvedDofs vector lists the joint indices that the IKFast solver computes, while freeDofs contains indices passed as parameters during generation (e.g., the shoulder roll in a 7-DOF arm).

Querying and Applying Solutions

Set a target transform and retrieve all valid configurations:

// Configure target
auto target = dart::dynamics::SimpleFrame::createShared(
    dart::dynamics::Frame::World());
target->setTranslation(Eigen::Vector3d(0.3, 0.0, 0.5));
target->setRotation(Eigen::Matrix3d::Identity());
ik->setTarget(target);
ik->setHierarchyLevel(1);  // Optional: limits search depth

// Retrieve analytical solutions
auto analytical = ik->getAnalytical();  // Returns SharedLibraryIkFast*
auto solutions = analytical->getSolutions(ee->getTransform());

// Apply first valid solution
for (const auto& sol : solutions)
{
  if (sol.mValidity != dart::dynamics::InverseKinematics::Analytical::VALID) 
    continue;
  
  skel->setPositions(solvedDofs, sol.mConfig);
  break;
}

The getSolutions() method returns a std::vector of InverseKinematics::Solution objects, where sol.mConfig contains the joint values and sol.mValidity indicates if the configuration respects joint limits and collision constraints.

Python Bindings Limitations

The dartpy Python bindings do not currently expose the SharedLibraryIkFast class directly, as noted in the documentation at docs/readthedocs/shared/inverse_kinematics/ikfast.rst. To use IKFast from Python, you must either:

  • Write a thin C++ helper that calls the C++ API and expose it via pybind11
  • Use DART’s gradient-based IK methods available in dartpy as a fallback

Summary

  • Generate the IKFast solver using OpenRAVE’s ikfast_generator_cpp.py for your specific robot URDF and IK type (e.g., Transform6D).
  • Compile the generated C++ file into a shared library with IKFAST_NO_MAIN and IKFAST_CLIBRARY definitions.
  • Load the library in DART using SharedLibraryIkFast, which binds ComputeIk, ComputeFk, and other required symbols at runtime via dart::common::SharedLibrary.
  • Configure the IK object by calling setGradientMethod<SharedLibraryIkFast>() with the library path and explicit DOF mappings for solved and free joints.
  • Solve by calling InverseKinematics::Analytical::getSolutions() to retrieve all valid joint configurations for a target end-effector pose.

Frequently Asked Questions

What is the difference between gradient-based and analytical IK in DART?

Gradient-based IK (the default) uses Jacobian iteration to iteratively approach a solution, which is general-purpose but slower and may converge to local minima. Analytical IK via IKFast uses pre-generated closed-form equations that compute all valid solutions instantly, but requires a compatible kinematic structure and pre-processing step to generate the solver code.

How do I map joint indices correctly when using SharedLibraryIkFast?

The solvedDofs vector must list the indices (in the DART skeleton) of joints that your IKFast solver was generated to compute, in the exact order the solver expects. The freeDofs vector lists indices of joints treated as free parameters during generation (often the first joint in a 7-DOF arm). Mismatches between these mappings and the generated solver will cause incorrect joint angle calculations or segmentation faults.

Can I use IKFast with any robot arm in DART?

No, IKFast only works with kinematic chains that have a solvable analytical solution (typically 6 or 7 DOF arms with specific geometric configurations). You must first verify that OpenRAVE’s IKFast generator can produce a solver for your specific URDF. If generation fails, the robot likely requires numerical IK methods instead.

Where can I find a complete working example?

The file tests/integration/io/test_ik_fast.cpp contains a full integration test that loads a generated WAM arm solver, configures DOF maps, queries solutions for a target transform, and verifies that the end-effector pose matches the target within tolerance. Additionally, examples/wam_ikfast/ shows the CMake configuration for compiling the generated solver.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →