Custom Inverse Kinematics MoveIt Plugin
Introduction
Solving inverse kinematics (IK) is a fundamental problem in robotics that converts task space co-ordinates to joint space variables. To solve for joint space values (q's
) analytically, we require non-linear transcendental equations connecting the task-space and joint-space values or forward kinematic equations (Note that IK can be seen as a minimization problem as well). As a simple case to understand this, lets take the case of a single degree of freedom planar robot arm having a revolute joint. We can write the forward kinematics as \begin{align} x = l * \cos(q) \nonumber \newline y = l * \sin(q) \nonumber \end{align} where l
and q
are respectively the link length and the angle that the link makes with the fixed co-ordinate system. The inverse kinematics (given (x,y), what is the value of q
?) can be written as
\begin{align} \tan (q) = \frac{y}{x} \implies q = \arctan(\frac{y}{x}) \label{eqn:pend_ik} \end{align}
Equation \ref{eqn:pend_ik} is a very simple example of an analytic inverse kinematics solution. IKFast is one such analytic IK solver for robot arms having any number of joints and is quite popular. However, it’s often difficult to set it up and there are a lot of “IKFast Not Working” queries if you do a google search.
In ROS, the most popular way of setting up a robot is using URDF and I will discuss another simple case of generating symbolic forward kinematics equations using sympy in another post. For now, I will assume that we already have an analytic expression for the IK.
This article will discuss the various steps involved in creating a custom IK plugin to be used along with MoveIt. (Why MoveIt because it is a very powerful and popular open source library for motion planning problems and is used by several robots). Firstly, we need to create a plugin using pluginlib, pluginlib_tutorials. The KDL and SRV kinematics plugin documentation give a very good idea of how to get started and set it up. I am just writing my experiences here for a quick overview of various things involved. So the steps involved are as follows
- Open a terminal and
cd
tocatkin_ws/src
andcatkin_create_pkg moveit_kinematics_plugin roscpp rospy pluginlib moveit_core
-
cd moveit_kinematics_plugin/include/moveit_kinematics_plugin
and create aTestKinematicsPlugin.h
(here). - Most importatnly, this header file should inherit the
kinematics::KinematicsBase
and implement the pure virtual methodsgetPositionFK()
,getJointNames()
,getLinkNames()
, the overloadedgetPositionIK()
and thesearchPositionIk()
. This also should have theinitialize()
method for initialization using the new syntax which takes therobot_model
as the first argument instead of the deprecatedrobot_description
. - I have added three other private functions,
getIKSolutions()
,isSolutionValid()
andgetNearestSolutionToSeed()
for my specific case. - getIKSolutions() implements the solution (for example equation \ref{eqn:pend_ik}). Something Important that I found here is that if you have two joint variables
q1
andq2
which respectively being the first and second joints, thesolutions
vector should implement something likesolutions.push_back({q2, q1})
. (Something to be investigated again) -
isSolutionValid()
checks if the solution found is within the joint limits andgetNearestSolutionToSeed()
finds the solution that is closest to the seed state provided. This is implemented for my specific robot and may not be required in general. - The last but very important bit is the implementation of one of the overloaded
searchPositionIK()
method. I have numbered it as 4. Go through it and copy paste the function as such - The
solution_callback()
is provided to check if the configuration of the robot arm corresponding to the solution is collision free or not. This should be implemented for additional safety but the program would work even without this. - Add the following as well in the
TestKinematicsPlugin.cpp
#include <class_loader/class_loader.hpp> CLASS_LOADER_REGISTER_CLASS(moveit_kinematics_plugin::TestKinematicsPlugin, kinematics::KinematicsBase);
- Create a
plugin_description.xml
file in the same level assrc
that should look like
<?xml version='1.0' encoding='UTF-8'?>
<library path="lib/test_arm_moveit_plugin">
<class base_class_type="kinematics::KinematicsBase" name="analytic/kinematicsPlugin" type="moveit_kinematics_plugin::TestArmKinematicsPlugin">
<description>MoveIt plugin for solving the kinematics analytically </description>
</class>
</library>
- Add an
export
tag in thepackage.xml
and it should look like<export> <moveit_core plugin="${prefix}/plugin_description.xml"/> </export>
- Copy the missing contents of the
CMakeLists.txt
into yourCMakeLists.txt
especially theinstall
parts -
cd
to yourcatkin_ws
and docatkin_make
andsource devel/setup.bash
. - When it finishes, you should see a
test_arm_moveit_plugin.so
(check theplugin_description.xml
library path) generated undercatkin_ws/devel/lib
. It’s often in my case, the plugin is not regenerated if an IDE like CLion is used (dont know why!!). So make sure to check the time of generation of thetest_arm_moveit_plugin.so
by typingll devel/lib | grep test_arm
. This will give the time of the latest generation of the plugin. Or as a last resort, removebuild
anddevel
folders and reruncatkin_make
if the plugin is not generated. - Additionally run
rospack plugins --attrib=plugin moveit_core
on your console. This should list the full path ofplugin_description.xml
. - Modify the
robot_moveit_config/config/kinematics.yaml
with the followingarm: kinematics_solver: analytic/kinematicsPlugin
Note: The
robot_moveit_config
package is generated using MoveIt Setup Assistant.
Congratulations, Your plugin is ready to be launched when you start your simulation
Enjoy Reading This Article?
Here are some more articles you might like to read next: