-
Notifications
You must be signed in to change notification settings - Fork 955
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
Backport: Planning with multiple pipelines in parallel with moveit_cpp #3244
Conversation
Thanks for helping in improving MoveIt and open source robotics! |
Codecov ReportBase: 62.03% // Head: 61.82% // Decreases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #3244 +/- ##
==========================================
- Coverage 62.03% 61.82% -0.21%
==========================================
Files 377 378 +1
Lines 33268 33373 +105
==========================================
- Hits 20636 20630 -6
- Misses 12632 12743 +111
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
Downgrade log from ERROR to INFO
We've been using this a lot and I can attest that it's AWESOME! I'm going to review it over at MoveIt2, though, so I don't review twice. |
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 have a handful of remarks. The most important one is the API incompatibility with existing PlannerManager plugins. While you might break API in ROS2, we shouldn't do so in ROS1.
moveit_core/planning_interface/include/moveit/planning_interface/planning_interface.h
Outdated
Show resolved
Hide resolved
@@ -53,7 +53,15 @@ struct MotionPlanResponse | |||
|
|||
robot_trajectory::RobotTrajectoryPtr trajectory_; | |||
double planning_time_; | |||
moveit_msgs::MoveItErrorCodes error_code_; | |||
moveit::core::MoveItErrorCode error_code_; | |||
moveit_msgs::RobotState start_state_; |
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.
As far as I could see, both start_state_
and planner_id_
are not actually used. What's the purpose of these fields?
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.
It is possible to pass an optional solution_selection_callback
and/or a stopping_criterion_function
both use the produced MotionPlanResponses to make a decision and these to additional fields might be useful to make that decision. For example
bool stoppingCriterionCallBack(
moveit_cpp::PlanningComponent::PlanSolutions const& plan_solutions,
moveit_cpp::PlanningComponent::MultiPipelinePlanRequestParameters const& plan_request_parameters)
for (auto const& solution : solutions)
{
// Stop parallel planning if PILZ found a solution
if (solution.planner_id_ == "LIN")
{
return true;
}
}
return false;
}
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 agree for the planner_id_
, but all plans share the very same start state, don't they?
Please add a comment, e.g. "planner this solution originates from".
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.
That's true, it does not matter for the solution selection. I added it since the MotionPlanResponse message has a similar field and it can be useful when the MotionPlanResponse is processed further independent from moveit_cpp/ the planning_component. Do you think we should remove it or is a comment sufficient?
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 yet. If the start state is identical for all solutions, saving it here would be a waste of memory.
However, due to different pipeline configs, modifying the start state (or not), the actual start state might differ between solutions (but I don't know by heart). That would be an argument to keep it here...
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'd remove the underscore from the field names but you're right, the API will be broken by this. I can open a PR for moveit_tutorials to fix this. Would MTC be affected?
I'm not only worried about moveit_tutorials or MTC. The problem is that any user code out there accessing those members will be affected by this change! At least we should provide a deprecation period for transition.
My suggestion is to:
- remove the underscores
- provide additional, deprecated members with the underscore as const references to the new members:
Obviously, those references need to be initialized in the constructor. This will render the struct read-only. So you will need to provide a custom copy constructor and assignment operator as well.
moveit_msgs::RobotState start_state; [[deprecated("Use start_state instead.")]] const moveit_msgs::RobotState& start_state_;
@@ -63,7 +71,15 @@ struct MotionPlanDetailedResponse | |||
std::vector<robot_trajectory::RobotTrajectoryPtr> trajectory_; | |||
std::vector<std::string> description_; | |||
std::vector<double> processing_time_; | |||
moveit_msgs::MoveItErrorCodes error_code_; | |||
moveit::core::MoveItErrorCode error_code_; | |||
moveit_msgs::RobotState start_state_; |
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 here.
const planning_interface::PlannerConfigurationSettings planner_config_settings{ | ||
group, group, std::map<std::string, std::string>() | ||
}; | ||
pconfig[planner_config_settings.name] = planner_config_settings; | ||
} | ||
setPlannerConfigurations(pconfig); |
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's the purpose of setting these empty planner configs?
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.
Isn't it only empty when the robot model does not have any JointModelGroups? The line above adds for each joint model group settings
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.
But those settings are simply empty: <std::string, std::string>()
void setPlannerConfigurations(const planning_interface::PlannerConfigurationMap& pcs) override | ||
{ | ||
config_settings_ = pcs; | ||
} |
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.
Maybe introduce this as the default implementation of PlannerManager
?
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.
Personally, I'd like to remind the person that implements a new planner plugin to think about the planner config and forcing them to implement this function would be a good way. But I can make this a default implementation if you don't like that
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 understand your reasoning and for MoveIt2 it is probably the right way to go.
For MoveIt1, I personally think we should maintain API stability. Other maintainers might have a different opinion.
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.
Reverting this will be required for CI to pass...
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.
Ok, let's do it that way then 👍
moveit_ros/planning/moveit_cpp/include/moveit/moveit_cpp/moveit_cpp.h
Outdated
Show resolved
Hide resolved
moveit_ros/planning/moveit_cpp/include/moveit/moveit_cpp/planning_component.h
Outdated
Show resolved
Hide resolved
moveit_ros/planning/planning_pipeline/include/moveit/planning_pipeline/planning_pipeline.h
Outdated
Show resolved
Hide resolved
Co-authored-by: Robert Haschke <[email protected]>
This PR had several clang-tidy warnings. Don't you have clang-tidy checks enabled anymore for MoveIt2? |
How did you handle the API-incompatible member renamings in MoveIt2?? |
Since MotionPlanResponse is a struct and all member variables are public the _ underscore naming convention for private member variables is not correctly used here anyway's. In moveit2 we opened an additional issue to fix this but I can included into this pr for simplicity's sake |
Yes, moveit2 uses clang-tidy but the related clang-tidy check is disabled moveit/moveit2#214 |
I still don't know how you solved it in MoveIt2. Please add a reference.
Depends on the solution approach you took. I don't yet see how this can be fixed in a fashion not breaking API for somebody. |
279038b
to
c72ca11
Compare
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.
There is still a lot of redundancy. Can you handle the missing config settings in moveitcpp instead?
|
||
// Construct default configurations for planning groups that don't have configs already passed in. This is necessary | ||
// since moveit_cpp can only use planners with a config for a given joint group | ||
for (const moveit::core::JointModelGroup* group : robot_model_->getJointModelGroups()) | ||
{ | ||
if (config_settings_.find(group->getName()) == config_settings_.end()) | ||
{ | ||
planning_interface::PlannerConfigurationSettings empty_config; | ||
empty_config.name = empty_config.group = group->getName(); | ||
config_settings_[empty.name] = empty; | ||
} | ||
} |
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.
Why did you decide to initialize settings for "missing" groups here instead of in PlannerManager::initialize
as suggested here?
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.
Sorry, you reviewed to fast, that change did not work. The problem is that initialize() function can easily be overwritten and thus compatibility with moveit_cpp be destroyed. The way I implemented it would have added a default empty config for all planning plugins with setPlannerConfigurations
. But that did not work because the robot model is not available in this function.
I think the planner plugins should be modified because the flaw right now is that pconfig is not used correctly (as expected by moveit_cpp) by the plugins. If we hide this implementation detail away in the base class, I fear future plugin implementations will repeat the same error,
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.
pconfig is not used correctly (as expected by moveit_cpp) by the plugins.
Can you please detail this? As far as I can see, moveit_cpp just generates a "shortcut" map from these configs.
If there are no config settings, why should a plugin declare them as empty? I think we should first agree on the semantics, before implementing anything further...
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 preference would be to use the current solution and open an issue to re-evaluate the PlannerConfigurationSettings, since it is only properly used by OMPL at the moment. Maybe it would be better to remove/refactor it and the pipeline detection in moveit_cpp but I think this is out of the scope of this PR.
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.
From: moveit/moveit2#1522
When the plan() method of the planning component gets called, all available planning pipelines are searched based on their name [1]. These names are provided by moveit_cpp [2]. The moveit_cpp function that provides the planning pipeline names reads them from an internal map [3]. A planning pipelines needs to have a planner plugin that has a PlannerConfiguration in order to be added to this map [4].
@@ -279,7 +261,7 @@ void ompl_interface::OMPLInterface::loadPlannerConfigurations() | |||
ROS_DEBUG_STREAM_NAMED(LOGNAME, " - " << parameters.first << " = " << parameters.second); | |||
} | |||
|
|||
setPlannerConfigurations(pconfig); | |||
context_manager_.setPlannerConfigurations(pconfig); |
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.
Why does the OMPL planner use a different approach to configure settings?
I would expect a similar approach to other planners, i.e. calling setPlannerConfigurations(pconfig)
.
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 way, ompl defined a default setPlannerConfigurations
implementation to add empty configs for joint model groups and moved that implementation into the base class. But that did not work
moveit_msgs::RobotState start_state; | ||
std::string planner_id; | ||
|
||
[[deprecated("Use trajectory instead.")]] robot_trajectory::RobotTrajectoryPtr& trajectory_; |
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 Probably I am doing something wrong, but if I make these references const, the API breaks again. Do I miss something here?
…plementation" This reverts commit c72ca11.
This reverts commit 5fd520f.
This reverts commit 8f96165.
- reverse naming: - underscore_ members stay the default - (deprecated) non_underscore members are added for API compatibility - add deprecated start_state member - avoid code duplication between copy constructor and copy assignment
This is a backport of moveit/moveit2#1710, dropping function getPlanningPipelineNames().
This member is not needed anymore.
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 the latest version passes CI, I'm fine with the current state.
👍 Thanks a lot for your help to get this merged! |
Congrats on getting your first MoveIt pull request merged and improving open source robotics! |
I think it would be a good idea to add some notes on the API change there. @sjahr |
@rhaschke @sjahr I might misunderstand something just perusing this thread, but I just ran into these deprecations and they are the inverted logic of what was discussed throughout this thread. It recommends the historical |
This PR removed the rather new data structure |
Thanks for the explanation. Not great to keep the legacy annotation |
Our naming rules enforce the underscore: Why do you claim this notation legacy? |
Somewhat a mix of personal opinion, conventions I know and the |
There are Public, Protected, and Private variants for all rules. So we could remove the suffix for public members... I have triggered a corresponding build: https://github.com/ros-planning/moveit/actions/runs/4005320877 |
* Fix old-style-cast * Fix deprecated member names (due to moveit/moveit#3244) * Enable -Werror
Description
This is a backport of the parallel planning API for moveit_cpp from moveit2#1420.
This PR adds:
Usage example:
config.yaml
demo_node.cpp
Checklist