From e54787facd0cfa48242289cdcf4ab8de7853ee3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mathias=20L=C3=BCdtke?= <mathias.luedtke@ipa.fraunhofer.de>
Date: Tue, 4 Jun 2013 11:22:10 +0200
Subject: [PATCH] added IKfast compatibility functions

---
 ur_kinematics/include/ur_kinematics/ikfast.h | 328 +++++++++++++++++++
 ur_kinematics/src/ur_kin.cpp                 |  79 +++++
 2 files changed, 407 insertions(+)
 create mode 100644 ur_kinematics/include/ur_kinematics/ikfast.h

diff --git a/ur_kinematics/include/ur_kinematics/ikfast.h b/ur_kinematics/include/ur_kinematics/ikfast.h
new file mode 100644
index 0000000..9a2a2f1
--- /dev/null
+++ b/ur_kinematics/include/ur_kinematics/ikfast.h
@@ -0,0 +1,328 @@
+// -*- coding: utf-8 -*-
+// Copyright (C) 2012 Rosen Diankov <rosen.diankov@gmail.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+/** \brief  Header file for all ikfast c++ files/shared objects.
+
+    The ikfast inverse kinematics compiler is part of OpenRAVE.
+
+    The file is divided into two sections:
+    - <b>Common</b> - the abstract classes section that all ikfast share regardless of their settings
+    - <b>Library Specific</b> - the library-specific definitions, which depends on the precision/settings that the library was compiled with
+
+    The defines are as follows, they are also used for the ikfast C++ class:
+
+   - IKFAST_HEADER_COMMON - common classes
+   - IKFAST_HAS_LIBRARY - if defined, will include library-specific functions. by default this is off
+   - IKFAST_CLIBRARY - Define this linking statically or dynamically to get correct visibility.
+   - IKFAST_NO_MAIN - Remove the ``main`` function, usually used with IKFAST_CLIBRARY
+   - IKFAST_ASSERT - Define in order to get a custom assert called when NaNs, divides by zero, and other invalid conditions are detected.
+   - IKFAST_REAL - Use to force a custom real number type for IkReal.
+   - IKFAST_NAMESPACE - Enclose all functions and classes in this namespace, the ``main`` function is excluded.
+
+ */
+#include <vector>
+#include <list>
+#include <stdexcept>
+
+#ifndef IKFAST_HEADER_COMMON
+#define IKFAST_HEADER_COMMON
+
+/// should be the same as ikfast.__version__
+#define IKFAST_VERSION 61
+
+namespace ikfast {
+
+/// \brief holds the solution for a single dof
+template <typename T>
+class IkSingleDOFSolutionBase
+{
+public:
+    IkSingleDOFSolutionBase() : fmul(0), foffset(0), freeind(-1), maxsolutions(1) {
+        indices[0] = indices[1] = indices[2] = indices[3] = indices[4] = -1;
+    }
+    T fmul, foffset; ///< joint value is fmul*sol[freeind]+foffset
+    signed char freeind; ///< if >= 0, mimics another joint
+    unsigned char jointtype; ///< joint type, 0x01 is revolute, 0x11 is slider
+    unsigned char maxsolutions; ///< max possible indices, 0 if controlled by free index or a free joint itself
+    unsigned char indices[5]; ///< unique index of the solution used to keep track on what part it came from. sometimes a solution can be repeated for different indices. store at least another repeated root
+};
+
+/// \brief The discrete solutions are returned in this structure.
+///
+/// Sometimes the joint axes of the robot can align allowing an infinite number of solutions.
+/// Stores all these solutions in the form of free variables that the user has to set when querying the solution. Its prototype is:
+template <typename T>
+class IkSolutionBase
+{
+public:
+    virtual ~IkSolutionBase() {
+    }
+    /// \brief gets a concrete solution
+    ///
+    /// \param[out] solution the result
+    /// \param[in] freevalues values for the free parameters \se GetFree
+    virtual void GetSolution(T* solution, const T* freevalues) const = 0;
+
+    /// \brief std::vector version of \ref GetSolution
+    virtual void GetSolution(std::vector<T>& solution, const std::vector<T>& freevalues) const {
+        solution.resize(GetDOF());
+        GetSolution(&solution.at(0), freevalues.size() > 0 ? &freevalues.at(0) : NULL);
+    }
+
+    /// \brief Gets the indices of the configuration space that have to be preset before a full solution can be returned
+    ///
+    /// \return vector of indices indicating the free parameters
+    virtual const std::vector<int>& GetFree() const = 0;
+
+    /// \brief the dof of the solution
+    virtual const int GetDOF() const = 0;
+};
+
+/// \brief manages all the solutions
+template <typename T>
+class IkSolutionListBase
+{
+public:
+    virtual ~IkSolutionListBase() {
+    }
+
+    /// \brief add one solution and return its index for later retrieval
+    ///
+    /// \param vinfos Solution data for each degree of freedom of the manipulator
+    /// \param vfree If the solution represents an infinite space, holds free parameters of the solution that users can freely set.
+    virtual size_t AddSolution(const std::vector<IkSingleDOFSolutionBase<T> >& vinfos, const std::vector<int>& vfree) = 0;
+
+    /// \brief returns the solution pointer
+    virtual const IkSolutionBase<T>& GetSolution(size_t index) const = 0;
+
+    /// \brief returns the number of solutions stored
+    virtual size_t GetNumSolutions() const = 0;
+
+    /// \brief clears all current solutions, note that any memory addresses returned from \ref GetSolution will be invalidated.
+    virtual void Clear() = 0;
+};
+
+/// \brief holds function pointers for all the exported functions of ikfast
+template <typename T>
+class IkFastFunctions
+{
+public:
+    IkFastFunctions() : _ComputeIk(NULL), _ComputeFk(NULL), _GetNumFreeParameters(NULL), _GetFreeParameters(NULL), _GetNumJoints(NULL), _GetIkRealSize(NULL), _GetIkFastVersion(NULL), _GetIkType(NULL), _GetKinematicsHash(NULL) {
+    }
+    virtual ~IkFastFunctions() {
+    }
+    typedef bool (*ComputeIkFn)(const T*, const T*, const T*, IkSolutionListBase<T>&);
+    ComputeIkFn _ComputeIk;
+    typedef void (*ComputeFkFn)(const T*, T*, T*);
+    ComputeFkFn _ComputeFk;
+    typedef int (*GetNumFreeParametersFn)();
+    GetNumFreeParametersFn _GetNumFreeParameters;
+    typedef int* (*GetFreeParametersFn)();
+    GetFreeParametersFn _GetFreeParameters;
+    typedef int (*GetNumJointsFn)();
+    GetNumJointsFn _GetNumJoints;
+    typedef int (*GetIkRealSizeFn)();
+    GetIkRealSizeFn _GetIkRealSize;
+    typedef const char* (*GetIkFastVersionFn)();
+    GetIkFastVersionFn _GetIkFastVersion;
+    typedef int (*GetIkTypeFn)();
+    GetIkTypeFn _GetIkType;
+    typedef const char* (*GetKinematicsHashFn)();
+    GetKinematicsHashFn _GetKinematicsHash;
+};
+
+// Implementations of the abstract classes, user doesn't need to use them
+
+/// \brief Default implementation of \ref IkSolutionBase
+template <typename T>
+class IkSolution : public IkSolutionBase<T>
+{
+public:
+    IkSolution(const std::vector<IkSingleDOFSolutionBase<T> >& vinfos, const std::vector<int>& vfree) {
+        _vbasesol = vinfos;
+        _vfree = vfree;
+    }
+
+    virtual void GetSolution(T* solution, const T* freevalues) const {
+        for(std::size_t i = 0; i < _vbasesol.size(); ++i) {
+            if( _vbasesol[i].freeind < 0 )
+                solution[i] = _vbasesol[i].foffset;
+            else {
+                solution[i] = freevalues[_vbasesol[i].freeind]*_vbasesol[i].fmul + _vbasesol[i].foffset;
+                if( solution[i] > T(3.14159265358979) ) {
+                    solution[i] -= T(6.28318530717959);
+                }
+                else if( solution[i] < T(-3.14159265358979) ) {
+                    solution[i] += T(6.28318530717959);
+                }
+            }
+        }
+    }
+
+    virtual void GetSolution(std::vector<T>& solution, const std::vector<T>& freevalues) const {
+        solution.resize(GetDOF());
+        GetSolution(&solution.at(0), freevalues.size() > 0 ? &freevalues.at(0) : NULL);
+    }
+
+    virtual const std::vector<int>& GetFree() const {
+        return _vfree;
+    }
+    virtual const int GetDOF() const {
+        return static_cast<int>(_vbasesol.size());
+    }
+
+    virtual void Validate() const {
+        for(size_t i = 0; i < _vbasesol.size(); ++i) {
+            if( _vbasesol[i].maxsolutions == (unsigned char)-1) {
+                throw std::runtime_error("max solutions for joint not initialized");
+            }
+            if( _vbasesol[i].maxsolutions > 0 ) {
+                if( _vbasesol[i].indices[0] >= _vbasesol[i].maxsolutions ) {
+                    throw std::runtime_error("index >= max solutions for joint");
+                }
+                if( _vbasesol[i].indices[1] != (unsigned char)-1 && _vbasesol[i].indices[1] >= _vbasesol[i].maxsolutions ) {
+                    throw std::runtime_error("2nd index >= max solutions for joint");
+                }
+            }
+        }
+    }
+
+    virtual void GetSolutionIndices(std::vector<unsigned int>& v) const {
+        v.resize(0);
+        v.push_back(0);
+        for(int i = (int)_vbasesol.size()-1; i >= 0; --i) {
+            if( _vbasesol[i].maxsolutions != (unsigned char)-1 && _vbasesol[i].maxsolutions > 1 ) {
+                for(size_t j = 0; j < v.size(); ++j) {
+                    v[j] *= _vbasesol[i].maxsolutions;
+                }
+                size_t orgsize=v.size();
+                if( _vbasesol[i].indices[1] != (unsigned char)-1 ) {
+                    for(size_t j = 0; j < orgsize; ++j) {
+                        v.push_back(v[j]+_vbasesol[i].indices[1]);
+                    }
+                }
+                if( _vbasesol[i].indices[0] != (unsigned char)-1 ) {
+                    for(size_t j = 0; j < orgsize; ++j) {
+                        v[j] += _vbasesol[i].indices[0];
+                    }
+                }
+            }
+        }
+    }
+
+    std::vector< IkSingleDOFSolutionBase<T> > _vbasesol;       ///< solution and their offsets if joints are mimiced
+    std::vector<int> _vfree;
+};
+
+/// \brief Default implementation of \ref IkSolutionListBase
+template <typename T>
+class IkSolutionList : public IkSolutionListBase<T>
+{
+public:
+    virtual size_t AddSolution(const std::vector<IkSingleDOFSolutionBase<T> >& vinfos, const std::vector<int>& vfree)
+    {
+        size_t index = _listsolutions.size();
+        _listsolutions.push_back(IkSolution<T>(vinfos,vfree));
+        return index;
+    }
+
+    virtual const IkSolutionBase<T>& GetSolution(size_t index) const
+    {
+        if( index >= _listsolutions.size() ) {
+            throw std::runtime_error("GetSolution index is invalid");
+        }
+        typename std::list< IkSolution<T> >::const_iterator it = _listsolutions.begin();
+        std::advance(it,index);
+        return *it;
+    }
+
+    virtual size_t GetNumSolutions() const {
+        return _listsolutions.size();
+    }
+
+    virtual void Clear() {
+        _listsolutions.clear();
+    }
+
+protected:
+    std::list< IkSolution<T> > _listsolutions;
+};
+
+}
+
+#endif // OPENRAVE_IKFAST_HEADER
+
+// The following code is dependent on the C++ library linking with.
+#ifdef IKFAST_HAS_LIBRARY
+
+// defined when creating a shared object/dll
+#ifdef IKFAST_CLIBRARY
+#ifdef _MSC_VER
+#define IKFAST_API extern "C" __declspec(dllexport)
+#else
+#define IKFAST_API extern "C"
+#endif
+#else
+#define IKFAST_API
+#endif
+
+#ifdef IKFAST_NAMESPACE
+namespace IKFAST_NAMESPACE {
+#endif
+
+#ifdef IKFAST_REAL
+typedef IKFAST_REAL IkReal;
+#else
+typedef double IkReal;
+#endif
+
+/** \brief Computes all IK solutions given a end effector coordinates and the free joints.
+
+   - ``eetrans`` - 3 translation values. For iktype **TranslationXYOrientation3D**, the z-axis is the orientation.
+   - ``eerot``
+   - For **Transform6D** it is 9 values for the 3x3 rotation matrix.
+   - For **Direction3D**, **Ray4D**, and **TranslationDirection5D**, the first 3 values represent the target direction.
+   - For **TranslationXAxisAngle4D**, **TranslationYAxisAngle4D**, and **TranslationZAxisAngle4D** the first value represents the angle.
+   - For **TranslationLocalGlobal6D**, the diagonal elements ([0],[4],[8]) are the local translation inside the end effector coordinate system.
+ */
+IKFAST_API bool ComputeIk(const IkReal* eetrans, const IkReal* eerot, const IkReal* pfree, ikfast::IkSolutionListBase<IkReal>& solutions);
+
+/// \brief Computes the end effector coordinates given the joint values. This function is used to double check ik.
+IKFAST_API void ComputeFk(const IkReal* joints, IkReal* eetrans, IkReal* eerot);
+
+/// \brief returns the number of free parameters users has to set apriori
+IKFAST_API int GetNumFreeParameters();
+
+/// \brief the indices of the free parameters indexed by the chain joints
+IKFAST_API int* GetFreeParameters();
+
+/// \brief the total number of indices of the chain
+IKFAST_API int GetNumJoints();
+
+/// \brief the size in bytes of the configured number type
+IKFAST_API int GetIkRealSize();
+
+/// \brief the ikfast version used to generate this file
+IKFAST_API const char* GetIkFastVersion();
+
+/// \brief the ik type ID
+IKFAST_API int GetIkType();
+
+/// \brief a hash of all the chain values used for double checking that the correct IK is used.
+IKFAST_API const char* GetKinematicsHash();
+
+#ifdef IKFAST_NAMESPACE
+}
+#endif
+
+#endif // IKFAST_HAS_LIBRARY
diff --git a/ur_kinematics/src/ur_kin.cpp b/ur_kinematics/src/ur_kin.cpp
index 5510c83..5714454 100644
--- a/ur_kinematics/src/ur_kin.cpp
+++ b/ur_kinematics/src/ur_kin.cpp
@@ -182,6 +182,84 @@ namespace ur_kinematics {
   }
 };
 
+
+#define IKFAST_HAS_LIBRARY
+#include <ur_kinematics/ikfast.h>
+using namespace ikfast;
+
+// check if the included ikfast version matches what this file was compiled with
+#define IKFAST_COMPILE_ASSERT(x) extern int __dummy[(int)x]
+IKFAST_COMPILE_ASSERT(IKFAST_VERSION==61);
+
+#ifdef IKFAST_NAMESPACE
+namespace IKFAST_NAMESPACE {
+#endif
+
+void to_mat44(double * mat4_4, const IkReal* eetrans, const IkReal* eerot)
+{
+    for(int i=0; i< 3;++i){
+        mat4_4[i*4+0] = eerot[i*3+0];
+        mat4_4[i*4+1] = eerot[i*3+1];
+        mat4_4[i*4+2] = eerot[i*3+2];
+        mat4_4[i*4+3] = eetrans[i];
+    }
+    mat4_4[3*4+0] = 0;
+    mat4_4[3*4+1] = 0;
+    mat4_4[3*4+2] = 0;
+    mat4_4[3*4+3] = 1;
+}
+
+void from_mat44(const double * mat4_4, IkReal* eetrans, IkReal* eerot)
+{
+    for(int i=0; i< 3;++i){
+        eerot[i*3+0] = mat4_4[i*4+0];
+        eerot[i*3+1] = mat4_4[i*4+1];
+        eerot[i*3+2] = mat4_4[i*4+2];
+        eetrans[i] = mat4_4[i*4+3];
+    }
+}
+
+
+IKFAST_API bool ComputeIk(const IkReal* eetrans, const IkReal* eerot, const IkReal* pfree, IkSolutionListBase<IkReal>& solutions) {
+  if(!pfree) return false;
+
+  int n = GetNumJoints();
+  double q_sols[8*6];
+  double T[16];
+
+  to_mat44(T, eetrans, eerot);
+
+  int num_sols = ur_kinematics::inverse(T, q_sols,pfree[0]);
+
+  std::vector<int> vfree(0);
+
+  for (int i=0; i < num_sols; ++i){
+    std::vector<IkSingleDOFSolutionBase<IkReal> > vinfos(n);
+    for (int j=0; j < n; ++j) vinfos[j].foffset = q_sols[i*n+j];
+    solutions.AddSolution(vinfos,vfree);
+  }
+  return num_sols > 0;
+}
+
+IKFAST_API void ComputeFk(const IkReal* j, IkReal* eetrans, IkReal* eerot)
+{
+    double T[16];
+    ur_kinematics::forward(j,T);
+    from_mat44(T,eetrans,eerot);
+}
+
+IKFAST_API int GetNumFreeParameters() { return 1; }
+IKFAST_API int* GetFreeParameters() { static int freeparams[] = {5}; return freeparams; }
+IKFAST_API int GetNumJoints() { return 6; }
+
+IKFAST_API int GetIkRealSize() { return sizeof(IkReal); }
+
+#ifdef IKFAST_NAMESPACE
+} // end namespace
+#endif
+
+#ifndef IKFAST_NO_MAIN
+
 using namespace std;
 using namespace ur_kinematics;
 
@@ -206,3 +284,4 @@ int main(int argc, char* argv[])
   printf("\n");
   return 0;
 }
+#endif
-- 
GitLab