/** @page kinematics Kinematics @brief Tesseract provides a plugin-based kinematics system with analytical and numerical FK/IK solvers. The tesseract_kinematics package provides a common interface for forward and inverse kinematics of kinematic chains, trees, and graphs. Solvers are loaded as plugins and configured via YAML files referenced in the SRDF. > For plugin configuration syntax and available solvers, see the > @ref kinematics_plugins_file "Kinematics Solver Configuration" section on the @ref srdf "SRDF page". @section kinematics_overview Overview Tesseract's kinematics system is designed around three principles: 1. Plugin Architecture — Solvers are loaded at runtime from shared libraries. No recompilation needed to switch solvers. 2. Per-Group Configuration — Each planning group can use different FK and IK solvers with independent parameters. 3. Multiple Solver Support — You can configure multiple solvers per group with a designated default and fall back to alternatives. @section kinematics_plugin_config Plugin Configuration Kinematics plugins are configured in a YAML file with four sections: | Section | Description | |---------|-------------| | `search_paths` | Directories to search for plugin libraries | | `search_libraries` | Specific libraries to search for plugin classes | | `fwd_kin_plugins` | Map of group names to forward kinematics plugins | | `inv_kin_plugins` | Map of group names to inverse kinematics plugins | Example Configuration: @code{.yaml} kinematic_plugins: search_paths: - /usr/local/lib search_libraries: - tesseract_kinematics_kdl_factories fwd_kin_plugins: iiwa_manipulator: default: KDLFwdKinChain plugins: KDLFwdKinChain: class: KDLFwdKinChainFactory config: base_link: base_link tip_link: tool0 inv_kin_plugins: iiwa_manipulator: default: KDLInvKinChainLMA plugins: KDLInvKinChainLMA: class: KDLInvKinChainLMAFactory config: base_link: base_link tip_link: tool0 @endcode @section kinematics_available_solvers Available Solvers @subsection kin_kdl_fk KDL Forward Kinematics A general-purpose numerical FK solver based on the Kinematics and Dynamics Library (KDL). Works with any kinematic structure. @code{.yaml} fwd_kin_plugins: manipulator: default: KDLFwdKinChain plugins: KDLFwdKinChain: class: KDLFwdKinChainFactory config: base_link: base_link tip_link: tool0 @endcode @subsection kin_kdl_lma KDL Inverse Kinematics (Levenberg-Marquardt) A numerical IK solver using the Levenberg-Marquardt optimization algorithm. Use when your robot doesn't match analytical solver geometry requirements. @code{.yaml} inv_kin_plugins: manipulator: default: KDLInvKinChainLMA plugins: KDLInvKinChainLMA: class: KDLInvKinChainLMAFactory config: base_link: base_link tip_link: tool0 @endcode @subsection kin_kdl_nr KDL Inverse Kinematics (Newton-Raphson) A numerical IK solver using the Newton-Raphson iterative method. Often converges faster than LMA but may be less stable for far-from-solution starting points. @code{.yaml} inv_kin_plugins: manipulator: default: KDLInvKinChainNR plugins: KDLInvKinChainNR: class: KDLInvKinChainNRFactory config: base_link: base_link tip_link: tool0 @endcode @subsection kin_opw OPW Inverse Kinematics An analytical IK solver optimized for 6-DOF industrial robots with the OPW (Ortho-Parallel-Wrist) geometry pattern (ABB, KUKA, Fanuc, etc.). Extremely fast with closed-form solutions. @code{.yaml} inv_kin_plugins: manipulator: default: OPWInvKin plugins: OPWInvKin: class: OPWInvKinFactory config: base_link: base_link tip_link: tool0 params: a1: 0.100 a2: -0.135 b: 0.00 c1: 0.615 c2: 0.705 c3: 0.755 c4: 0.086 offsets: [0, 0, -1.57079632679, 0, 0, 0] sign_corrections: [1, 1, 1, 1, 1, 1] @endcode @subsection kin_ur UR Inverse Kinematics A dedicated analytical IK solver for Universal Robots arms. Can use preconfigured models or custom D-H parameters. Using a preconfigured model: @code{.yaml} inv_kin_plugins: manipulator: default: URInvKin plugins: URInvKin: class: URInvKinFactory config: base_link: base_link tip_link: tool0 model: UR10 # Options: UR3, UR5, UR10, UR3e, UR5e, UR10e @endcode Using custom parameters: @code{.yaml} inv_kin_plugins: manipulator: default: URInvKin plugins: URInvKin: class: URInvKinFactory config: base_link: base_link tip_link: tool0 params: d1: 0.1273 a2: -0.612 a3: -0.5723 d4: 0.163941 d5: 0.1157 d6: 0.0922 @endcode @subsection kin_rop Robot on Positioner (ROP) Combines a robot IK solver with a sampled external axis (positioner, track, turntable). The positioner axis is sampled at discrete intervals and the robot IK is solved at each position. @code{.yaml} inv_kin_plugins: manipulator: default: ROPInvKin plugins: ROPInvKin: class: ROPInvKinFactory config: manipulator_reach: 2.0 positioner_sample_resolution: - name: positioner_joint_1 value: 0.1 positioner: class: KDLFwdKinChainFactory config: base_link: positioner_base_link tip_link: positioner_tool0 manipulator: class: OPWInvKinFactory config: base_link: base_link tip_link: tool0 params: a1: 0.100 a2: -0.135 b: 0.00 c1: 0.615 c2: 0.705 c3: 0.755 c4: 0.086 offsets: [0, 0, -1.57079632679, 0, 0, 0] sign_corrections: [1, 1, 1, 1, 1, 1] @endcode @subsection kin_rep Robot with External Positioner (REP) Similar to ROP, but for an external positioner that can be reoriented independently (e.g., a rotary table holding the workpiece). Supports multiple positioner axes. @code{.yaml} inv_kin_plugins: manipulator: default: REPInvKin plugins: REPInvKin: class: REPInvKinFactory config: manipulator_reach: 2.0 positioner_sample_resolution: - name: positioner_joint_1 value: 0.1 - name: positioner_joint_2 value: 0.1 positioner: class: KDLFwdKinChainFactory config: base_link: positioner_base_link tip_link: positioner_tool0 manipulator: class: OPWInvKinFactory config: base_link: base_link tip_link: tool0 params: a1: 0.100 a2: -0.135 b: 0.00 c1: 0.615 c2: 0.705 c3: 0.755 c4: 0.086 offsets: [0, 0, -1.57079632679, 0, 0, 0] sign_corrections: [1, 1, 1, 1, 1, 1] @endcode @section kinematics_ikfast Creating an IKFast Plugin IKFast is an analytical IK solver generator from OpenRAVE. It produces a C++ source file containing a closed-form IK solver specific to your robot's kinematic chain. This section walks through the complete process. @subsection ikfast_prerequisites Prerequisites Install Docker and configure permissions: @code{.sh} # Install Docker curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo apt-key fingerprint 0EBFCD88 sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo apt update sudo apt install -y docker-ce # Add your user to the docker group sudo groupadd docker sudo usermod -aG docker $USER @endcode After adding the group, reboot if `docker run hello-world` produces a permission error. Pull the OpenRAVE docker container: @code{.sh} docker pull hamzamerzic/openrave @endcode @subsection ikfast_urdf_to_dae Converting URDF to .dae OpenRAVE uses the COLLADA (.dae) format. Convert your URDF: @code{.sh} # Install the converter (ROS required for this step) sudo apt install ros--collada-urdf source catkin_ws/devel/setup.bash # Convert URDF to COLLADA rosrun collada_urdf urdf_to_collada /path/to/my_robot.urdf /path/to/robot_full.dae # Round precision to 6 decimal places (avoids numerical issues) rosrun moveit_kinematics round_collada_numbers.py /path/to/robot_full.dae /path/to/robot.dae 6 @endcode @subsection ikfast_find_links Finding Robot Link Indices The IKFast generator needs link indices from the .dae file. Use OpenRAVE's utility: @code{.sh} docker run --rm \ --env PYTHONPATH=/usr/local/lib/python2.7/dist-packages \ -v /path/to/dir:/out \ hamzamerzic/openrave \ /bin/bash -c "cd /out; openrave-robot.py robot.dae --info links" @endcode Example output: @code name index parents ------------------------------------------ world 0 base_link 1 world base 2 base_link shoulder_link 3 base_link upper_arm_link 4 shoulder_link forearm_link 5 upper_arm_link wrist_1_link 6 forearm_link wrist_2_link 7 wrist_1_link wrist_3_link 8 wrist_2_link tool0 9 wrist_3_link ee_link 10 tool0 @endcode @subsection ikfast_generate Running the IKFast Generator Run the generator with the base link and end-effector link indices: @code{.sh} docker run --rm \ --env PYTHONPATH=/usr/local/lib/python2.7/dist-packages \ -v /path/to/dir:/out \ hamzamerzic/openrave \ /bin/bash -c "cd /out; python /usr/local/lib/python2.7/dist-packages/openravepy/_openravepy_/ikfast.py \ --robot=robot.dae \ --iktype=transform6d \ --baselink=1 \ --eelink=9 \ --savefile=robot_ikfast.cpp" @endcode Key arguments: - `--robot` — The .dae filename in the mounted directory - `--iktype` — IK solver type (`transform6d` for 6-DOF robots) - `--baselink` — Index of the robot's base link - `--eelink` — Index of the end-effector link (usually `tool0`) - `--savefile` — Output C++ filename - `--freeindex` — (Optional) For 7+ DOF robots, specify the free joint index (e.g., `--freeindex=8`) > This process can take up to 20 minutes depending on the kinematic chain. @subsection ikfast_create_solver Creating the Tesseract IKFast Solver Header file: @code{.cpp} #include #include #include namespace my_robot_ikfast { class MyRobotInvKinematics : public tesseract_kinematics::IKFastInvKin { public: MyRobotInvKinematics(const std::string base_link_name, const std::string tip_link_name, const std::vector joint_names, const std::string name); }; } // namespace my_robot_ikfast @endcode Source file (include order matters): @code{.cpp} #include #include // Generated IKFast code #include namespace my_robot_ikfast { MyRobotInvKinematics::MyRobotInvKinematics(const std::string base_link_name, const std::string tip_link_name, const std::vector joint_names, const std::string name) : IKFastInvKin(base_link_name, tip_link_name, joint_names, name) {} } // namespace my_robot_ikfast @endcode @subsection ikfast_create_plugin Creating the Tesseract IKFast Plugin Header file: @code{.cpp} #include namespace my_robot_ikfast { class MyRobotInvKinFactory : public tesseract::kinematics::InvKinFactory { public: tesseract::common::PropertyTree schema() const override final; protected: std::unique_ptr createImpl(const std::string& solver_name, const tesseract::scene_graph::SceneGraph& scene_graph, const tesseract::scene_graph::SceneState& scene_state, const tesseract::kinematics::KinematicsPluginFactory& plugin_factory, const tesseract::common::PropertyTree& config) const override final; }; } // namespace my_robot_ikfast @endcode Source file: @code{.cpp} #include #include #include namespace my_robot_ikfast { tesseract::common::PropertyTree MyRobotInvKinFactory::schema() const { using namespace tesseract::common; return PropertyTreeBuilder() .attribute(property_attribute::TYPE, property_type::CONTAINER) .string("base_link").required().minimumLength(1).done() .string("tip_link").required().minimumLength(1).done() .build(); } std::unique_ptr MyRobotInvKinFactory::createImpl(const std::string& solver_name, const tesseract::scene_graph::SceneGraph& scene_graph, const tesseract::scene_graph::SceneState& /*scene_state*/, const tesseract::kinematics::KinematicsPluginFactory& /*plugin_factory*/, const tesseract::common::PropertyTree& config) const { const auto base_link = config.at("base_link").as(); const auto tip_link = config.at("tip_link").as(); auto shortest_path = scene_graph.getShortestPath(base_link, tip_link); return std::make_unique(base_link, tip_link, shortest_path.active_joint_names, solver_name); } } // namespace my_robot_ikfast // Register the plugin TESSERACT_ADD_INV_KIN_PLUGIN(my_robot_ikfast::MyRobotInvKinFactory, MyRobotInvKinFactory); @endcode @subsection ikfast_cmake CMakeLists.txt Add the following to your CMakeLists.txt: @code{.cmake} find_package(tesseract_kinematics REQUIRED) find_package(Eigen3 REQUIRED) find_package(LAPACK REQUIRED) # Required for IKFast # IKFast solver library add_library(${PROJECT_NAME} src/my_robot_kinematics.cpp) target_link_libraries(${PROJECT_NAME} PUBLIC tesseract::tesseract_kinematics_ikfast spdlog::spdlog Eigen3::Eigen ${LAPACK_LIBRARIES}) target_include_directories(${PROJECT_NAME} PUBLIC "$" "$") target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${LAPACK_INCLUDE_DIRS}) # Plugin factory library add_library(${PROJECT_NAME}_factory src/my_robot_factory.cpp) target_link_libraries(${PROJECT_NAME}_factory PUBLIC ${PROJECT_NAME} tesseract::tesseract_kinematics_core) target_include_directories(${PROJECT_NAME}_factory PUBLIC "$" "$") @endcode @subsection ikfast_plugin_config Plugin Configuration Configure your IKFast plugin in the kinematics YAML: @code{.yaml} kinematic_plugins: search_paths: - search_libraries: - _factory fwd_kin_plugins: manipulator: default: KDLFwdKinChain plugins: KDLFwdKinChain: class: KDLFwdKinChainFactory config: base_link: base_link tip_link: tool0 inv_kin_plugins: manipulator: default: MyRobotInvKinematics plugins: MyRobotInvKinematics: class: MyRobotInvKinFactory config: base_link: base_link tip_link: tool0 @endcode @section kinematics_next_steps Next Steps - @ref srdf — Configure kinematics plugins in your SRDF - @ref environment — Use kinematics through the environment interface - @ref getting_started — Set up your development workspace */