-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Added #define-based namespaces to prevent linking errors. #355
base: kinetic-devel
Are you sure you want to change the base?
Added #define-based namespaces to prevent linking errors. #355
Conversation
In the current setup, it is impossible to link against the ur5 or ur10 versions of the kinematics library, as all expose the same ur_kinematics::inverse() signature. Since all libraries are exported in the catkin_package() macro, this results in undefined behavior when linking. GCC just picks the first suitable signature it encounters, in this case the ur3 version, and continues without an error. Adding a namespace allows the linker to find the correct library call.
Related: #220. |
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.
Hi, Andrew!
I've opened a PR to your fork with some tweaks that I think will make this fix more digestible for end users. The motivations are explained in my comments in this review. If you're okay with merging those changes, then I'll be happy to approve this PR.
However, there may be one last concern, which is that this PR breaks ABI compatibility. I'm not sure what the ABI policy is for the universal_robot
package. There's an REP about ABI compatibility which suggests that ABI should be maintained for even versions, and the current version is 1.2.1
. If universal_robot
follows that policy, then we'd either have to
- increment the version to
1.3.0
or - create a copy of each of these functions (
forward
,forward_all
, andinverse
) outside of the namespace that simply call the namespaced version.
I would probably recommend option (2), because it's the least intrusive. If any universal_robot
maintainers have a preference, input would be appreciated.
#endif | ||
|
||
#ifdef UR3_PARAMS | ||
#define UR_NAMESPACE ur3 |
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 approach will require users to always define one of these options before including the header. We could approximate the original behavior by doing this instead:
#ifdef UR10_PARAMS
#define UR_NAMESPACE ur10
#elif UR5_PARAMS
#define UR_NAMESPACE ur5
#else
#define UR_NAMESPACE ur3
#endif
Using the approach in this PR, users will get a crytpic linking error if they neglect to specify one of these options.
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.
Agreed. It does slightly privilege the UR3, but that's probably fine.
@@ -56,13 +68,14 @@ | |||
// 0, 0, 0, 1 | |||
|
|||
namespace ur_kinematics { | |||
// @param q The 6 joint values | |||
namespace UR_NAMESPACE { |
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 we make this an inline
namespace, then we can keep API compatibility the same, so people don't need to add this extra namespace to their function calls.
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.
Interesting idea. I wasn't familiar with inline namespace
.
Grey! It's good to hear from you! Thanks for the suggestions. I wasn't aware of the ABI recommendations; that's good to know about. Here's a couple of thoughts:
Given the current state of the interfaces, I'd be a little surprised if anyone else is trying to link directly to the library rather than accessing the kinematics through the plugins/ROS interface. I'd be happy to be corrected, though. |
The way I'm using the library currently is by calling:
which is admittedly a little awkward and non-C++-like. It does have the advantage that the user has to explicitly call out which UR arm they wish to use, since it's not clear from the filename. I could see a couple of ways around this. One would be to use CMake to generate different headers, e.g.
which does emit a comprehensible error message when I try to compile without the |
It's undefined by the C++ standard, but I believe on ROS's supported platform (Ubuntu) it's well-defined: Whichever version of the symbol the linker finds first is the one it will use, and the order in which the linker finds the symbol is based on the build system configuration. Users will get consistent behavior as long as they don't change their build system configuration, and some users might be depending on that behavior. The changes recommended here will maintain API+ABI compatibility and keep the behavior consistent for any users who don't change their code. That would allow us to increment the patch version instead of the minor release version. |
Well, I definitely agree that the better way would be to have a distinct header that is properly namespaced and hides all the macro business from the end user. The library in its current state, to my understanding, cannot be used directly (i.e. without using the plugin code) with 2/3 of the robots which it services, at least if you want to use If I seem hesitant to incorporate maintaining the current interface, that's probably two-fold. First, I spent several hours troubleshooting why calling the kinematics gave bizarre results, and I'd like to prevent future users from encountering the same pitfall. Second, it's still not clear to me what that function ought to do. Maybe link it to the UR3 kinematics, since that's what it happened to link against up to this point, and mark it as deprecated? Moving forward, would there be any objection to adding a new header file containing
That would at least get rid of the necessity to use a |
re: breaking existing setups: personally I would be ok with that in this instance. The current situation with I would normally be in favour of maintaining ABI as @mxgrey suggests, but in this case I believe I'm ok with ignoring that. @a-price: could I also ask you to revert the version number increment? That cannot be done for individual packages -- we'll need to do that to the entire repository in order to be able to properly tag and release it. |
Is there an advantage to using compiler definitions versus a data structure which is provided the inverse function? Parameter data structure: /** @brief The Universal Robot kinematic parameters */
struct URParameters
{
URParameters() = default;
URParameters(double d1, double a2, double a3, double d4, double d5, double d6)
: d1(d1), a2(a2), a3(a3), d4(d4), d5(d5), d6(d6)
{
}
double d1{ 0 };
double a2{ 0 };
double a3{ 0 };
double d4{ 0 };
double d5{ 0 };
double d6{ 0 };
};
/** @brief The UR10 kinematic parameters */
const static URParameters UR10Parameters(0.1273, -0.612, -0.5723, 0.163941, 0.1157, 0.0922);
/** @brief The UR5 kinematic parameters */
const static URParameters UR5Parameters(0.089159, -0.42500, -0.39225, 0.10915, 0.09465, 0.0823);
/** @brief The UR3 kinematic parameters */
const static URParameters UR3Parameters(0.1519, -0.24365, -0.21325, 0.11235, 0.08535, 0.0819);
Change Inverse function: int inverse(const Eigen::Isometry3d& T, const URParameters& params, double* q_sols, double q6_des) |
In the current setup, it is impossible to link against the ur5 or ur10 versions of the kinematics library, as all expose the same ur_kinematics::inverse() signature.
Since all libraries are exported in the catkin_package() macro, this results in undefined behavior when linking.
GCC just picks the first suitable signature it encounters, in this case the ur3 version, and continues without an error.
Adding a namespace allows the linker to find the correct library call.