Fix pilz planners to consider and plan Cartesian motions w.r.t. subframes#3519
Conversation
rhaschke
left a comment
There was a problem hiding this comment.
Generally, I think the approach is correct. In order to yield interpolation w.r.t. the subframe, the frame needs to be resolved in the Pilz planner and not only in setFromIK.
moveit_planners/pilz_industrial_motion_planner/src/command_list_manager.cpp
Outdated
Show resolved
Hide resolved
moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp
Outdated
Show resolved
Hide resolved
moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp
Outdated
Show resolved
Hide resolved
| // if (!robot_model_->getJointModelGroup(group_name)->canSetStateFromIK(pos_constraint.link_name)) | ||
| // { | ||
| // std::ostringstream os; | ||
| // os << "No IK solver available for link: \"" << pos_constraint.link_name << "\""; | ||
| // throw NoIKSolverAvailable(os.str()); | ||
| // } |
There was a problem hiding this comment.
If not needed anymore: remove completely. Leave a comment here, why it's not needed anymore.
I guess it is redundant to similar checks elsewhere?
But: Instead of doing the error checking and reporting frequently in downstream trajectory generators, why not do it once here?
There was a problem hiding this comment.
Will double check that this is redundant. Do you think it'd make sense to move the transformation into a tip goal here too?
There was a problem hiding this comment.
Do you think it'd make sense to move the transformation into a tip goal here too?
Scratch that part given the transformation is no longer necessary (see reply from above comment)
@rhaschke What would be the easiest way of turning this check into one that can detect subframes? In other places, I've been using RobotState::knowsFrameTransform().
The method calls are:
TrajectoryGenerator::generate() -> TrajectoryGenerator::validateRequest() -> TrajectoryGenerator::checkGoalConstraints() -> TrajectoryGenerator::checkCartesianGoalConstraint()
The first of those methods has access to a planning scene, though I'm unsure if there's a cleaner way than passing a state through the method calls (especially since the state itself is arbitrary, it's just the access to the subframes we're interested in)
There was a problem hiding this comment.
From my understanding, the check (for existence of the IK (sub)frame and it's usability for IK) didn't fail.
In contrast to RobotState::knowsFrameTransform(), canSetStateFromIK() should also verify that the IK frame is rigidly connected to the IK solver's tip frame (so exactly what you need).
There was a problem hiding this comment.
I do get the same error as before uncommenting this when planning with a subframe:
[10:15:49.016004] [/fake/move_group]: No IK solver available for link: "tb_1_1/disc_tip"
[10:15:49.016126] [/fake/move_group]: Planner threw an exception (error code: -31): Could not solve request
[10:15:49.017372] [/fake/motion_server]: Failed to plan sequence motion foo. Error code: NO_IK_SOLUTION. If problem persists, check toolbit config.
I think the issue the issue is that JointModelGroup has no notion of subframes and only checks for links in canSetStateFromIK, whereas RobotState knows about both and setStateFromIK is designed for that possibility.
There was a problem hiding this comment.
To summarise my findings:
- The transformation from subframe goal to tip link goal I added to pilz isn't required provided the
RobotStateused forsetStateFromIK()is built from the scene which knows about the subframes, assetStateFromIK()accounts for this case. I've removed this transformation from pilz now. - I'm no longer using the
default_planner_request_adapters/ResolveConstraintFramesadapter as this was causing the original issue of planning a linear motion wrt the tip link rather than the subframe. - Therefore, anywhere pilz is validating the
link_nameof constraints, it's the subframe name that's being used (causing the above failure whenever the validation code is subframe unaware). This appears to be the case whenever usingJointModelGroup.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #3519 +/- ##
==========================================
+ Coverage 61.81% 61.84% +0.04%
==========================================
Files 385 385
Lines 34121 34091 -30
==========================================
- Hits 21088 21081 -7
+ Misses 13033 13010 -23
☔ View full report in Codecov by Sentry. |
Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com>
moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp
Outdated
Show resolved
Hide resolved
|
Simple sanity check of the LIN output: Will do the same for CIRC as I believe a decent portion of the code is shared |
moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp
Outdated
Show resolved
Hide resolved
moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp
Outdated
Show resolved
Hide resolved
moveit_planners/pilz_industrial_motion_planner/src/trajectory_generator_circ.cpp
Outdated
Show resolved
Hide resolved
Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com>
….com/rr-tom-noble/moveit into bugfix/fix-lin-plans-using-subframes
|
We're currently looking into an issue using this for our use case, which is as follows:
@rr-mark is also looking into this issue |
With a little more digging, what is actually happening is now that It looks like Now those objects are being checked, it matters that their joints are not properly being updated. Is computePoseIK supposed to be unaware of attached collision objects, with these checks happening elsewhere? Or is this something which should now be updated? It seems easy enough to fix the |
| @@ -134,9 +133,7 @@ void TrajectoryGeneratorLIN::extractMotionPlanInfo(const planning_scene::Plannin | |||
| info.start_joint_position[joint_name] = req.start_state.joint_state.position[index]; | |||
| } | |||
There was a problem hiding this comment.
assert(req.start_state.joint_state.name.size() == req.start_state.joint_state.position.size());
std::map<std::string, double> start_joint_position;
for (unsigned i=0; i<req.start_state.joint_state.name.size(); ++i) {
start_joint_position[req.start_state.joint_state.name[i]] = req.start_state.joint_state.position[i];
}
for (const auto& joint_name : robot_model_->getJointModelGroup(req.group_name)->getActiveJointModelNames())
{
if (start_joint_position.count(joint_name) == 0)
{
std::ostringstream os;
os << "Could not find joint \"" << joint_name << "\" of group \"" << req.group_name
<< "\" in start state of request";
throw LinJointMissingInStartState(os.str());
}
info.start_joint_position[joint_name] = start_joint_position[joint_name];
}
computeLinkFK(robot_state, info.link_name, info.start_joint_position, info.start_pose);
// check goal pose ik before Cartesian motion plan starts
std::map<std::string, double> ik_solution;
if (!computePoseIK(scene, info.group_name, info.link_name, info.goal_pose, frame_id, start_joint_position,
ik_solution))
{
std::ostringstream os;
os << "Failed to compute inverse kinematics for link: " << info.link_name << " of goal pose";
throw LinInverseForGoalIncalculable(os.str());
}
There was a problem hiding this comment.
This looks like it correctly updates all the joint states, including those not in the current joint group, so that the IK collision detection is correct.
|
I'm not sure what (remaining?) problem you are referring to in #3519 (comment) and #3519 (comment). That |
|
Your changes work on my end, thank you for your time. |
|
We're seeing a couple of issues with this PR:
Is all the extra collision checking working as intended? Or is this redundant with other collision checking after the path has been generated? |
|
You are right, collision checking is performed twice: (i) during path generation and (ii) as a final trajectory validation step. |
|
Actually, collision checking in Can you please verify that the behavior is as intended now? |
|
Yes, it looks good now; collisions along the path are reported as they were before this PR. Thanks again. |
|
Thanks for iterating on this. |
|
While this PR seems to fix ignored modified start states in unrelated JMGs, the original issue is not yet solved, is it?
I think this can only be resolved by explicitly interpolating between the actual subframe's start and goal pose (i.e. not first back-projecting to the associated robot link) and considering the offset when computing the IK instead. I implemented this for the CartesianInterpolator in #3197. #2890, authored by you guys, should be reverted to a large extent in order to maintain the original goal pose. Unfortunately, the unit tests don't cover those cases yet - they only consider the final goal pose, but don't check the path in between. |
Partially reverts changes of moveit#3519
Hi, and thanks for the feedback and help with this PR. I think the code does work as intended as passing in the subframe as the link_name and removing the default_planner_request_adapters/ResolveConstraintFrames adapter causes the target point offset to be [0. 0. 0]. The start and goal points are for the subframe, and it's those points we use KDL to build the LIN motion for. It's only when we're sampling points along that path and performing IK that the points are back projected to a robot link (within the robot_state->setFromIK() call I believe). I do wonder if this makes the point of target_offset_point a little redundant, so I don't mind those changes being reverted. Maybe still useful if you did want to plan using an offset from the subframe itself? Let me know if you agree with the above |
|
Sure, if you remove the ResolveConstraintFrames adapter, the target_point_offset becomes zero. However, I was complaining about the case when this offset is non-zero. See #3523 for the fix. Now it works with both ResolveConstraintFrames enabled or disabled. |
* Ports moveit/moveit/pull/3519 to ros2 * Applies formatting * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Replaces RobotState with pointer in tests * Fixes tests
* Ports moveit/moveit/pull/3519 to ros2 * Applies formatting * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Replaces RobotState with pointer in tests * Fixes tests (cherry picked from commit 70e1aae) # Conflicts: # moveit_planners/pilz_industrial_motion_planner/include/pilz_industrial_motion_planner/planning_context_base.h # moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp # moveit_planners/pilz_industrial_motion_planner/src/trajectory_generator.cpp # moveit_planners/pilz_industrial_motion_planner/test/unit_tests/src/unittest_trajectory_generator_circ.cpp # moveit_planners/pilz_industrial_motion_planner/test/unit_tests/src/unittest_trajectory_generator_lin.cpp
* Ports moveit/moveit/pull/3519 to ros2 * Applies formatting * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Replaces RobotState with pointer in tests * Fixes tests (cherry picked from commit 70e1aae) # Conflicts: # moveit_planners/pilz_industrial_motion_planner/include/pilz_industrial_motion_planner/planning_context_base.h # moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp # moveit_planners/pilz_industrial_motion_planner/src/trajectory_generator.cpp # moveit_planners/pilz_industrial_motion_planner/test/unit_tests/src/unittest_trajectory_generator_circ.cpp # moveit_planners/pilz_industrial_motion_planner/test/unit_tests/src/unittest_trajectory_generator_lin.cpp
Co-authored-by: Tom Noble <tom@rivelinrobotics.com>
* Ports moveit/moveit/pull/3519 to ros2 * Applies formatting * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Fixes compilation errors * Replaces RobotState with pointer in tests * Fixes tests
Description
Fixes #3517 by allowing pilz to use subframes in goal constraints.
Updates
computePoseIK()to build aRobotStatefrom thePlanningScenerather than theRobotModel, so that subframes are taken into account. Also adds some error handling logic around calls to this function as, currently, if the passedlink_namedoes not exist, thestart_poseis set to the identity pose, which leads to a less intuitive IK solver error later on.This also means the collision checking in the pilz
computePoseIK()method is now attached collision object aware.Checklist