Installation & Quickstart#

HJCD-IK is a GPU-accelerated, batched inverse kinematics solver: it explores many candidate joint configurations in parallel (one candidate per coarse-search block, then one candidate per LM warp) and refines the promising ones, with optional collision avoidance. Kinematics come from GRiD (a per-URDF generated grid.cuh); the warp-scoped linear algebra comes from GLASS.

Requirements#

  • Linux, a CUDA 12.x or 13.x toolkit (nvcc), and an NVIDIA GPU

  • CMake ≥ 3.24, a C++17 host compiler

  • Python ≥ 3.9

No system libraries beyond the CUDA toolkit are needed (the former nlohmann-json dependency went with the native JSON parser in October 2026; obstacle worlds are plain arrays now).

Build#

git clone https://github.com/A2R-Lab/HJCD-IK
cd HJCD-IK
bash scripts/setup/bootstrap.sh      # only the required pinned submodules
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e .

This builds the _hjcdik extension. The CUDA architecture is auto-detected for the GPU present at configure time (CMAKE_CUDA_ARCHITECTURES=native). For a fresh build targeting other GPUs, set CUDAARCHS (for example CUDAARCHS="86;89" python -m pip install -e .), or explicitly override a cached setting with python -m pip install -e . -Ccmake.define.CMAKE_CUDA_ARCHITECTURES="86;89". The checked-in collision-enabled Panda grid.cuh is used by default; codegen is not needed for that build. See the custom-robot tutorial to generate a different model.

Tip

One-shot dev setup — system deps + pinned submodules + a .venv + the docs toolchain + codegen + build: ./scripts/setup/setup_dev.sh (SKIP_APT=1 / SKIP_BUILD=1 / SKIP_SUBMODULES=1 to skip steps).

Source archives retain the implementation, codegen sources, licenses, tests, and pre-spherized robot URDFs, but omit upstream mesh collections, upstream tests/docs, and showcase media. Use a recursive repository clone if you need those full asset collections.

The top-level submodules are external/GRiD (kinematics codegen → grid.cuh), external/GLASS (warp CUDA linear algebra), and external/foam (the default Panda’s pre-spherized collision model). Development setup and GPU-proof tooling require Python 3.11+; the base package supports Python 3.9+. Runtime builds/prepared artifacts use grid-rbd, which requires Python 3.10+. Validation here used Python 3.12/CUDA 13.2 on Linux; other declared combinations were not all exercised.

Quickstart#

import hjcdik

solver = hjcdik.Solver()
print("robot:", solver.info.robot, "DOF:", solver.info.dof)

# Sample a reachable target: [x, y, z, qw, qx, qy, qz]
target = solver.sample_targets(1, seed=0)[0]

# Explore a batch of candidates for this target; collision=None is an open-world solve
out = solver.solve(
    target,
    batch_size=2000,     # candidates explored in parallel
    num_solutions=4,     # result capacity per target
    collision=None,
)
r = out[0]
print("returned:", r.count)
if r.count:
    print("candidate position errors (mm):", r.pos_err_mm)
    print("candidate orientation errors (rad):", r.ori_err_rad)
    print("accurate candidates:", r.q[r.ok(pos_mm=5, ori_rad=0.001)])
print("joint configs shape:", r.q.shape)

batch_size counts candidate configurations for one target, not independent targets; solve accepts a (T, 7) batch of targets and returns (T, num_solutions, ...) arrays, NaN-padded beyond count. Targets/returned poses use meters and wxyz quaternions; returned errors use millimeters and radians. Check both errors against your application’s tolerances, even when count > 0.

For collision-free solving, install the obstacles with solver.set_world(...) and solve with the default collision="hard"; examples/02_collision_free_solve.py loads a MotionBenchMaker scene.

Other robots#

Install the build extra and point the solver at a URDF; the robot is compiled once through GRiD’s artifact store (about twenty seconds on an RTX 5090) and reused afterwards:

python -m pip install -e ".[dev,build]" --no-build-isolation
hjcdik build path/to/arm.urdf --ee-link <fixed joint of the tool frame> --name my-arm
import hjcdik
solver = hjcdik.Solver("my-arm")                       # a prepared build, no compiler needed to load
# or, building on first use:
solver = hjcdik.Solver("path/to/arm.urdf", ee_link="tool_joint", spheres=None)

See Custom robot for sphere models, end-effector frames and the limits of the solver model.

Native executable and checks#

The native executable is an open-world example/export tool; use the Python API for collision controls. It is built by CMake but is not installed as a command by the Python wheel. A separate build directory keeps native configuration independent of the editable Python build:

cmake -S . -B build-native -DBUILD_PYTHON=OFF -DHJCDIK_BUILD_NATIVE_TESTS=ON
cmake --build build-native -j2
ctest --test-dir build-native --output-on-failure
./build-native/hjcdik --help
./build-native/hjcdik --mode=single --batch_size=2000 --num_solutions=4 --yaml_out=results.yml

single samples one reachable target; sweep samples --num_targets reachable targets. YAML preserves the legacy keys Batch-Size, IK-time(ms), Pos-Error, and Ori-Error. Position errors are millimeters, orientation errors are radians. IK-time(ms) divides the total solve wall time by the returned count; it is not an independently measured per-solution latency. For performance comparisons use the benchmark harness on an idle GPU.

from_csv consumes the unquoted numeric CSV interchange format from TRAC-IK exports:

target_id,target_px,target_py,target_pz,target_qx,target_qy,target_qz,target_qw
7,0.3,0.0,0.5,0,0,0,1
./build-native/hjcdik --mode=from_csv --csv_in=targets.csv --csv_out=solutions.csv

Column order may vary and additional columns are allowed; required names must be present. Positions are meters and quaternions are finite and nonzero (normalized by the solver). Whitespace and CRLF line endings are accepted. Every nonblank row is validated; the first valid row for each integer target_id supplies that target. This legacy MMD mode requests 50 solutions per unique target, overriding --num_solutions, and writes target_id,sample_id,q1,...,qN; it can return fewer than 50. Returned configurations are approximate IK candidates, not collision-checked paths. Unknown options, malformed numbers/rows, and output-write failures return nonzero status. CSV diagnostics include the input line number.