-
Notifications
You must be signed in to change notification settings - Fork 939
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
adding absolute jump threshold capability in parallel #821
Conversation
for (std::size_t i = 0; i < dist_vector.size(); ++i) | ||
if (dist_vector[i] > thres) | ||
{ | ||
CONSOLE_BRIDGE_logDebug("Truncating Cartesian path due to detected jump in joint-space distance"); | ||
percentage = (double)i / (double)dist_vector.size(); | ||
traj.resize(i); | ||
percentage = (double)(i + 1) / (double)(traj.size()); |
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.
Looks like you identified another bug. Well done!
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.
thanks
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 had various style improvements and thus pushed them directly. In general I approve this.
However, I suggest to not throw an exception from within testJointSpaceJump()
. What do you think, @mlautman and @davetcoleman?
else if (jt.prismatic_jump_threshold > 0.0 || jt.revolute_jump_threshold > 0.0) | ||
CONSOLE_BRIDGE_logWarn("Attempting to test for absolute joint-space jumps, but zero threshold was provided"); | ||
|
||
return 1.0; | ||
} | ||
|
||
double RobotState::testJointSpaceJump(const JointModelGroup* group, std::vector<RobotStatePtr>& traj, |
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.
What about renaming these worker functions to testJointSpaceJumpRelative
and testJointSpaceJumpAbsolute
?
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 think that's a good idea
EXPECT_EQ(traj.size(), 3); // traj should be cut | ||
EXPECT_NEAR(fraction, 3. / 4., 0.01); | ||
} | ||
|
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.
What about adding tests that ensure that testJointSpaceJump
correctly relays to testJointSpaceJumpRelative
and testJointSpaceJumpAbsolute
?
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'll add that
traj.insert(traj.end(), start, waypoint_traj.end()); | ||
if (!joint->getType() == JointModel::PRISMATIC && !joint->getType() == JointModel::REVOLUTE) | ||
{ | ||
CONSOLE_BRIDGE_logError("Unsupported joint type %zu in JointModelGroup %s testJointSpaceJump can only support " |
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.
Throwing an exception here, seems rather hard. I think it should be perfectly valid to test a trajectory involving multi-dof joints and just ignore them. Probably there should be a warning once to emphasize the fact that we ignore them.
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 think Cartesian planning with multi-dof joints is an unusual circumstance that has not yet been addressed in moveit and probably should be in the future. However allowing it to return a solution that is wrong is very misleading and perhaps even potentially dangerous. I don't see why this is perfectly valid. Please give an example of why you would allow a multi-dof joint to not be checked for jumps.
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.
The joint-space jump test is only supported for revolute or prismatic joints. If the trajectory involves multi-dof joints, why shouldn't it be possible to test all the remaining, normal joints?
I'm not proposing to silently ignore multi-dof joints.
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.
My point is that multi-dof joints should also be checked for jumps for potential safety reasons. Until we support this, we should disallow someone to be mislead into thinking it has been checked by throwing an error.
Another option would be to just implement this now, but I'm not convinced this use-case is very common or necessary and it would delay getting "MVP" features out.
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 don't think that testing for joint-space jumps for Cartesian-pose-based joints is necessary at all. If we do Cartesian interpolation for those poses with a given max_step
, they will have the given max_step
distance anyway...
const GroupStateValidityCallbackFn& validCallback = GroupStateValidityCallbackFn(), | ||
const kinematics::KinematicsQueryOptions& options = kinematics::KinematicsQueryOptions()) | ||
{ | ||
return computeCartesianPath(group, traj, link, direction, global_reference_frame, distance, max_step, |
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 moved the implementation of these functions into the header, as this clearly states that they simply relay to the actual worker function. Having nice constructors for the the JumpThreshold
struct facilitates readability.
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 is great
@@ -2007,6 +2007,13 @@ double RobotState::testJointSpaceJump(const JointModelGroup* group, std::vector< | |||
double RobotState::testJointSpaceJump(const JointModelGroup* group, std::vector<RobotStatePtr>& traj, | |||
double jump_threshold_factor) | |||
{ | |||
if (traj.size() < MIN_STEPS_FOR_JUMP_THRESH) | |||
{ | |||
CONSOLE_BRIDGE_logWarn("The computed trajectory is too short to detect jumps in joint-space " |
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 warning should stay here, shouldn't it?
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 think so
if (jump_threshold.prismatic_jump_threshold > 0.0 || jump_threshold.revolute_jump_threshold > 0.0) | ||
percentage *= testJointSpaceJump(group, traj, jump_threshold.revolute_jump_threshold, | ||
jump_threshold.prismatic_jump_threshold); | ||
else if (jt.prismatic_jump_threshold > 0.0 && jt.revolute_jump_threshold > 0.0) |
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.
Switched to else if
here. For me, it doesn't make sense to test for both, relative and absolute jumps.
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 generally agree
|
||
return percentage; | ||
else if (jt.prismatic_jump_threshold > 0.0 || jt.revolute_jump_threshold > 0.0) |
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.
For me it doesn't make sense to test only revolute or only prismatic joints. Thus, both parameters need to be positive.
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'm not sure if I agree with this. If I have a robot with only revolute joints, I don't want to have to pass in a made up prismatic_jump_threshold and vice versa
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 think one should provide reasonable thresholds for both cases. If you are very sure that you have no joints of either type, you can still pass any value > 0.
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 still don't like the idea of asking the user to make up prismatic joint cutoff values for their fully revolute robot. I just pushed a commit that deals with this issue in a way that I think is clean.
I also think that else if
should be if
to cover the use case when someone wants to be super safe and run both checks
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 still don't like the idea of asking the user to make up prismatic joint cutoff values for their fully revolute robot.
I guess we keep to have different opinions on that. What about the following: The thresholds are kept zero by default. If there is a joint of "wrong" type in the trajectory (although not expected), the zero threshold will reject the trajectory if this joint moves at all.
Then the absolute testing can be triggered if (jt.prismatic > 0 || jt.revolute > 0)
I just pushed a commit that deals with this issue in a way that I think is clean.
In my point of view, your last commit 8566096 is only bloating the code without any benefit. Please revert this.
I also think that else if should be if to cover the use case when someone wants to be super safe and run both checks.
If you like. Maybe that's the expected behaviour when all params are set. However, you should update the comments to match this behaviour. I actually adapted the behaviour to the behaviour originally promised in the comments...
else if (jt.prismatic_jump_threshold > 0.0 || jt.revolute_jump_threshold > 0.0) | ||
CONSOLE_BRIDGE_logWarn("Attempting to test for absolute joint-space jumps, but zero threshold was provided"); | ||
|
||
return 1.0; |
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.
Probably, there should be a warning about illegal ( < 0) parameters here.
unsigned int steps = floor(distance / max_step) + 1; | ||
if (test_joint_space_jump && steps < MIN_STEPS_FOR_JUMP_THRESH) | ||
if (jump_threshold.jump_threshold_factor > 0 && steps < MIN_STEPS_FOR_JUMP_THRESH) |
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.
Good catch!
if (jump_threshold.prismatic_jump_threshold > 0.0 || jump_threshold.revolute_jump_threshold > 0.0) | ||
percentage *= testJointSpaceJump(group, traj, jump_threshold.revolute_jump_threshold, | ||
jump_threshold.prismatic_jump_threshold); | ||
else if (jt.prismatic_jump_threshold > 0.0 && jt.revolute_jump_threshold > 0.0) |
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 generally agree
|
||
return percentage; | ||
else if (jt.prismatic_jump_threshold > 0.0 || jt.revolute_jump_threshold > 0.0) |
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'm not sure if I agree with this. If I have a robot with only revolute joints, I don't want to have to pass in a made up prismatic_jump_threshold and vice versa
else if (jt.prismatic_jump_threshold > 0.0 || jt.revolute_jump_threshold > 0.0) | ||
CONSOLE_BRIDGE_logWarn("Attempting to test for absolute joint-space jumps, but zero threshold was provided"); | ||
|
||
return 1.0; | ||
} | ||
|
||
double RobotState::testJointSpaceJump(const JointModelGroup* group, std::vector<RobotStatePtr>& traj, |
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 think that's a good idea
{ | ||
} | ||
|
||
explicit JumpThreshold(double factor) : JumpThreshold() |
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.
love it
@@ -1087,9 +1102,13 @@ as the new values that correspond to the group */ | |||
|
|||
double computeCartesianPath(const JointModelGroup* group, std::vector<RobotStatePtr>& traj, const LinkModel* link, | |||
const Eigen::Vector3d& direction, bool global_reference_frame, double distance, | |||
double max_step, double jump_threshold, | |||
double max_step, double jump_threshold_factor, |
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.
Yessss :)
const GroupStateValidityCallbackFn& validCallback = GroupStateValidityCallbackFn(), | ||
const kinematics::KinematicsQueryOptions& options = kinematics::KinematicsQueryOptions()) | ||
{ | ||
return computeCartesianPath(group, traj, link, direction, global_reference_frame, distance, max_step, |
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 is great
@@ -2007,6 +2007,13 @@ double RobotState::testJointSpaceJump(const JointModelGroup* group, std::vector< | |||
double RobotState::testJointSpaceJump(const JointModelGroup* group, std::vector<RobotStatePtr>& traj, | |||
double jump_threshold_factor) | |||
{ | |||
if (traj.size() < MIN_STEPS_FOR_JUMP_THRESH) | |||
{ | |||
CONSOLE_BRIDGE_logWarn("The computed trajectory is too short to detect jumps in joint-space " |
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 think so
EXPECT_EQ(traj.size(), 3); // traj should be cut | ||
EXPECT_NEAR(fraction, 3. / 4., 0.01); | ||
} | ||
|
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'll add that
I agree with @rhaschke on this one.
Just print a warning and skip joints we don't want to handle at the moment.
|
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 like the source code changes.
However, I'm puzzled about the test changes.
@@ -70,23 +70,23 @@ typedef boost::function<bool(RobotState* robot_state, const JointModelGroup* joi | |||
thresholds for detecting joint space jumps. */ | |||
struct JumpThreshold |
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.
+1 to the name cleanup
"prismatic and revolute joints.", | ||
joint->getType(), group->getName().c_str()); | ||
throw Exception("Unsupported joint type"); | ||
CONSOLE_BRIDGE_logWarn("Unsupported joint type %s in JointModelGroup %s testAbsoluteJointSpaceJump can only " |
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.
Please split the message into two separate sentences. Maybe even separated by a newline char \n
.
} | ||
|
||
double distance = traj[traj_ix]->distance(*traj[traj_ix + 1], joint); | ||
if ((joint->getType() == JointModel::PRISMATIC && distance > prismatic_jump_threshold) || | ||
(joint->getType() == JointModel::REVOLUTE && distance > revolute_jump_threshold)) | ||
{ | ||
CONSOLE_BRIDGE_logDebug("Truncating Cartesian path due to detected jump of %.4f > %.4f in joint-space distance", | ||
CONSOLE_BRIDGE_logError("Truncating Cartesian path due to detected jump of %.4f > %.4f in joint-space distance", |
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.
Also name the joint:
"Cartesian path due to jump of %.4f > %.4f in joint %s"
void generateTestTraj(std::vector<std::shared_ptr<robot_state::RobotState>>& traj, | ||
const moveit::core::RobotModelConstPtr& robot_model, | ||
const robot_model::JointModelGroup* joint_model_group) | ||
std::size_t generateTestTraj(std::vector<std::shared_ptr<robot_state::RobotState>>& traj, |
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 don't understand why you made these tests so much more complicated. This doesn't add any functionality.
Please revert this part or explain.
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.
@rhaschke I did a few things here. I changed the tests to use the testJointSpaceJump with the struct parameter rather than calling the absolute and relative tests directly. To make it clear which test is being used by testJointSpaceJump under the hood I changed the test trajectory so that the absolute jump threshold and relative jump threshold trip at different waypoints. I also now use the PR2's default values as a base instead of a vector of all zeros since the zero vector is out of the joint limits for the PR2. This isn't that important for the absolute and relative jump tests but it becomes important for the cartesian tests that I am going to open a PR for after this get merged.
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 noticed these changes. But I think they are not necessary to perform the testing. Particularly adding many more waypoints make the whole test less comprehensible (for a short glance). Having exactly a single jump is much clearer.
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 reverted the test to 4 waypoints with a single obvious jump at the end
… removing throw error from abs jump test
…alues for prismatic and revolute cutoffs
@mlautman, as I still didn't like some of your recent changes, I assembled an alternative proposal. git fetch https://github.com/ubi-agni/moveit.git jump-threshold
git checkout -b rhaschke-abs-jt FETCH_HEAD This should fetch my changes and checkout locally as branch git checkout kinetic-abs-jt
git reset --hard rhaschke-abs-jt
git push --force <your picknick origin> |
Closing this in favour of #843. |
@rhaschke why did you close this? I don't think we had resolved whether the changes you wanted to make are an improvement |
I finally had a chance to look through your changes a minute ago. I like the changes to robot_state but I think the tests are better in this one. |
@mlautman, as I didn't get any feedback from you for a while, I thought to close this in favour of #843, which is a PR comprising my changes applied to your original branch. This way, I was hoping to facilitate reviewing my alternative branch. As we shouldn't have two similar PRs open at a time, I closed this one. |
@rhaschke In the future, do not do that again. You could have ping'd me, you could have emailed me but instead you decided to go ahead and overwrite my changes with yours which I found to be pretty disrespectful |
Description
The git history in my pr #798 got very messy with multiple upstream merges followed by local commits. I cleaned up the git history so I could re-open the PR. I'm not sure if that was the best way and am open to feedback on better ways to cleanup my PR's in the future.
I took a stab at implementing a absolute jump threshold for the computeCartesianPath functionality. (#773) This implementation required separate jump thresholds for prismatic and revolute joints and does not support planar, floating, fixed or multi-DOF joints. This implementation does not affect or replace the old computeCartesianPath method which is used by the move_group computeCartesianPath capability since that would involve changing messages and would have a much larger scope.
The goal of this PR is to address the issue where using the existing jump_threshold method, paths with few waypoints can have huge jumps in joint space. To demonstrate this problem, I generated hundreds of thousands of trajectories with varying goals, eef_steps and jump_thresholds, filtered out anything with less than 100% completion, sorted them by the number of interpolated waypoints in the returned trajectory, and then searched through for the largest absolute jump.
eef_steps = [0.01, 0.05, 0.1]
jump_thresholds = [1.1, 1.5, 1.75, 2.0]
After testing this new implementation and comparing it to the existing computeCartesianPath, I was able to filter out jumps from 100,000 trajectories with minimal parameter tuning. For what it's worth, IMHO it is a lot easier to tune the absolute jump thresholds than the jump threshold factor.
Checklist