-
Notifications
You must be signed in to change notification settings - Fork 287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an analytic IK solver (IkFast) #887
Conversation
Codecov Report
@@ Coverage Diff @@
## master #887 +/- ##
==========================================
+ Coverage 50.59% 51.17% +0.58%
==========================================
Files 299 307 +8
Lines 23408 23691 +283
Branches 3015 3065 +50
==========================================
+ Hits 11843 12124 +281
+ Misses 10236 10203 -33
- Partials 1329 1364 +35
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generally looks good. Very nice work @jslee02 - this clearly took a lot of work to implement and the solution is much cleaner than I imagined it could be.
My biggest request is documentation. Specifically:
- If I am a new user to DART, how to do I generate an IKFast solution for my robot? (I can help write this one.)
- If I have the output of IKFast, how do I load it into DART using the functionality you added?
- Once I have the IK solver loaded, how does using
Analytical
differ from using other types of IK? How do I get multiple solutions?
Additionally, I would like to have optional support for checking the solution returned by IKFast against forward kinematics. This is generally useful for analytic IK solvers, so I suggest moving it to the Analytical
base class.
Finally, I am not sure where this class enumerates the free parameters to generate a set of IK solutions. Can you point me to that code so I can take another look at it?
struct HINSTANCE__; | ||
typedef struct HINSTANCE__* hInstance; | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well this is pretty horrifying. I have no doubt that it's necessary on Windows. Can you add a few comments explaining what all of this does?
dart/common/SharedLibrary.cpp
Outdated
nameWithExtension += ".so"; | ||
#elif DART_OS_MACOS | ||
// dlopen() does not add .dylib to the filename, like windows does for .dll | ||
if (nameWithExtension.substr(fileName.length() - 6, 6) != ".dylib") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will cause an unsigned overflow if fileName.length() < 6
. Then it will likely SEGFAULT because the index is out of bounds.
dart/common/SharedLibrary.cpp
Outdated
#endif | ||
|
||
mInstance | ||
= static_cast<DYNLIB_HANDLE>(DYNLIB_LOAD(nameWithExtension.c_str())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DYNLIB_LOAD
seems to only be used here. I think it would be cleaner to simply load the library in the chain of #ifdef
blocks above instead of duplicating the same preprocessor logic in two places (this function and the implementation of the DYNLIB_LOAD
macro).
if (!isValid()) | ||
return nullptr; | ||
|
||
auto symbol = DYNLIB_GETSYM(mInstance, symbolName.c_str()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here: could we embed the logic instead of wrapping it in a macro?
dart/common/SharedLibrary.hpp
Outdated
/// Windows). | ||
/// \return Pointer to the created SharedLibrary upon success in loading. | ||
/// Otherwise, returns nullptr. | ||
explicit SharedLibrary(ProtectedContructionTag, const std::string& fileName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment explaining that ProtectedContructionTag
is necessary because you want to use std::make_shared
to create this type, which does not inherit the friend class
designation below. We presumably want to use std::make_shared
because it eliminates a memory allocation that would otherwise be necessary for the shared_ptr
's control block.
dart/gui/osg/DragAndDrop.cpp
Outdated
@@ -814,6 +814,8 @@ void BodyNodeDnD::saveState() | |||
else | |||
{ | |||
mIK = bn->createIK(); | |||
// TODO(JS): I guess this should be changed to: | |||
// mIK = bn->getIK(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will open as a separate PR
data/urdf/wam/wam.urdf
Outdated
@@ -0,0 +1,231 @@ | |||
<?xml version="1.0" ?> | |||
<!-- =================================================================================== --> | |||
<!-- | This document was autogenerated by xacro from /home/js/dev/catkin_workspaces/dev_libherb/src/herb_description/robots/wam_standalone.urdf.xacro | --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Remove the path from this comment.
data/urdf/wam/wam.urdf
Outdated
<child link="/wam1"/> | ||
<axis xyz="0 0 1"/> | ||
<!-- HERB's J1 joints are modified to have a +180 degree offset. --> | ||
<limit effort="1.8" lower="0.54159265359" upper="5.74159265359" velocity="0.75"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you are going to distribute this file with DART, then I suggest reverting to the default joint limits of the Barrett WAM arm. HERB's WAMs were specially modified by Barrett to have different joint limits, to improve the workspace when two WAMs are mounted side-by-side.
#include "dart/common/SharedLibrary.hpp" | ||
#include "dart/dynamics/IkFast.hpp" | ||
|
||
class SharedLibraryWamIkFast : public dart::dynamics::IkFast |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the code that an end-user would implement to use IKFast on their robot? Why is this necessary versus just passing the path to the .so
file into one of the SharedLibrary
functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An end-user would juse use this class. This class enables the user to use DART's inverse kinematics framework with IkFast .so
file without any further modification. All the user needs to do is passing the path to the .so
file and the list of free/non-free joint indices like:
std::string libName = "libGeneratedWamIkFast.so";
std::vector<std::size_t> ikFastDofs{0, 1, 3, 4, 5, 6};
std::vector<std::size_t> ikFastFreeDofs{2};
ik->setGradientMethod<dynamics::SharedLibraryIkFast>(
libName, ikFastDofs, ikFastFreeDofs);
SharedLibrary
only loads arbitrary .so
file and extracts symbols from the file, but doens't have any information how to interact with IkFast nor the inverse kinematics framework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jslee02 Could you give an example how to generate .so
file with wam robot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once you have a .cpp
file generated for WAM, you just compile the file with any compiler you like. Hope this helps. Note https://github.com/dartsim/dart/blob/master/examples/osgExamples/osgWamIkFast/ikfast/ikfast71.Transform6D.4_6_9_10_11_12_f8.cpp is just an example of IK for WAM. You might want different free joints setting for the same robot.
|
||
index++; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class - or the Analytic
base class - should support a bool
flag that toggles error checking. It's inexpensive to verify that running the IK solver's solution through DART's forward kinematics returns the expected BodyNode
pose.
This is a very important check - to the extent that we may want to enable it by default - because it catches to broad classes of errors: (1) using an analytic IK solution for a slightly different model and (2) bugs in the analytic IK solution. OpenRAVE avoids the former by hashing the model - which is not really possible here. I have also been burned by the latter due to bugs in IKFast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe I've addressed this in my top-level comment, but let me know if I'm misunderstanding your concern.
Suppose you have an
This can already be done in two ways. If you implicitly use the Analytical solver by calling So I believe the functionality that you're looking for is already immediately available. If you have ideas for ways to improve it or make it more accessible, I'd be very open to making changes.
If you're referring to the That being said, I'm personally not satisfied at all with the current design of the "extra DoF utilization". I mean, it works for my own personal use cases (which is why I made it in the first place), but it's kind of clumsy and not at all extensible, so I'd love to hear ideas for alternative designs. |
I don't think this addresses my concern. Suppose you call This most often occurs because there is a mismatch between the kinematics used to create the analytical solution and the I am fine with putting this in the |
I believe I've addressed all the @mkoval's comments except for the platform specific macros. Let me handle that in a separate PR. |
This pull request introduces an API for IkFast, which is an analytic IK solver that is a submodule of OpenRAVE.
Here is an example of Solving IK using IkFast for Barrett WAM Arm:

TODOs