Skip to content
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 hybrid planning feature #488

Closed
wants to merge 26 commits into from
Closed

Add hybrid planning feature #488

wants to merge 26 commits into from

Conversation

sjahr
Copy link
Contributor

@sjahr sjahr commented Jun 8, 2021

Description

This PR adds the new hybrid planning architecture to MoveIt2. The related issues that document the development process are #300 and #433.

To run the demo's you simply need to build moveit2 from source and make sure you use sjahr/moveit_msgs's hybrid_planning branch until the message definitions get merged into ros_planning/moveit_msgs.

The current setup includes a demo to verify the architecture's correct behavior. To run it use the following command:

ros2 launch moveit_hybrid_planning hybrid_planning.launch.py

The expected behavior looks like this:

replan

You can change the configuration of the hybrid planning architecture by switching the different plugins used by the architecture's main components in the associated config file.

Checklist

  • Required by CI: Code is auto formatted using clang-format
  • Extend the tutorials / documentation reference
  • Create tests, which fail without this PR reference
  • While waiting for someone to review your request, please help review another open pull request to support the maintainers

@codecov
Copy link

codecov bot commented Jun 8, 2021

Codecov Report

Merging #488 (f9a4494) into main (0b27304) will increase coverage by 0.32%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #488      +/-   ##
==========================================
+ Coverage   54.17%   54.48%   +0.32%     
==========================================
  Files         192      192              
  Lines       20182    20448     +266     
==========================================
+ Hits        10931    11139     +208     
- Misses       9251     9309      +58     
Impacted Files Coverage Δ
moveit_ros/moveit_servo/src/servo_calcs.cpp 73.13% <0.00%> (+2.61%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0b27304...f9a4494. Read the comment docs.

Copy link
Contributor

@AdamPettinger AdamPettinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through mostly the local planner stuff, but skimmed the manager and global as well.

This looks great! Very clean, and I think the plugin architecture will allow a lot of flexibility

Implementation of MoveIt 2's new hybrid planning architecture. You find more information in the project's issues[#300](https://github.com/ros-planning/moveit2/issues/300), [#433](https://github.com/ros-planning/moveit2/issues/433) and on the [MoveIt 2 roadmap](https://moveit.ros.org/documentation/contributing/roadmap/).

## Getting started
1. Build moveit2 from source and make sure you use [this fork](https://github.com/sjahr/moveit_msgs) of moveit_msgs for the hybrid planning specific action definitions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to change this when the msgs PR is merged

timer_ = this->create_wall_timer(1ms, [this]() {
if (initialized_)
{
timer_->cancel();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we talked about initializing this way with a timer. My understanding is right now this is the easiest way to access ROS node capabilities during initialization if this class inherits from rclcpp::Node, and that this will not be necessary with future lifecycle node work.

Maybe we should leave a TODO in all these initialization timers for after the lifecycle thing is sorted out?

{
auto& clock = *hybrid_planning_manager_->get_clock();
RCLCPP_INFO_THROTTLE(LOGGER, clock, 1000, event.c_str());
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really desired behavior here? Looks like debugging, maybe it should give a warning that the SinglePlanExecute plugin doesn't handle string feedback?


bool ForwardTrajectory::reset()
{
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to make sure it does not need to do anything on reset(), and not that this got overlooked

* @param new_trajectory New reference trajectory segment to add
* @return True if segment was successfully added
*/
virtual bool addTrajectorySegment(const robot_trajectory::RobotTrajectory& new_trajectory) = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function should include feedback (moveit_msgs::action::LocalPlanner::Feedback), perhaps as the return instead of a bool

if (pass_through_)
{
// Use reference_trajectory as local trajectory
local_trajectory.swap(*reference_trajectory_);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I set the pass_through parameter true in the config file, I get a segfault, I believe at this line

@@ -0,0 +1 @@
planner_logic_plugin_name: "moveit_hybrid_planning/ReplanInvalidatedTrajectory"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to combine all these config files into 1 file? Do we even want to?

load_controllers = []
for controller in [
"joint_state_controller",
"panda_joint_group_position_controller",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move to using the panda_arm_controller here as the default, because that is what the rest of the MoveIt tutorials and demos use

@@ -0,0 +1,28 @@
controller_manager:
ros__parameters:
update_rate: 500 # Hz
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this (to 100) has strange effects on the demo, which I cannot explain. Sometimes the robot moves a bit and then stops

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an int type and not a floating point?

pass_through: false

# ForwardTrajectory param
stop_before_collision: false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be true so the demonstration runs like the provided gif.

If this is false, the demo robot passes through the objects when I try it

Comment on lines 51 to 56
global_planner/include
hybrid_planning_manager/hybrid_planning_manager_component/include
hybrid_planning_manager/planner_logic_plugins/include
local_planner/local_planner_component/include
local_planner/trajectory_operator_plugins/include
local_planner/local_constraint_solver_plugins/include
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
global_planner/include
hybrid_planning_manager/hybrid_planning_manager_component/include
hybrid_planning_manager/planner_logic_plugins/include
local_planner/local_planner_component/include
local_planner/trajectory_operator_plugins/include
local_planner/local_constraint_solver_plugins/include
global_planner/include/
hybrid_planning_manager/hybrid_planning_manager_component/include/
hybrid_planning_manager/planner_logic_plugins/include/
local_planner/local_planner_component/include/
local_planner/trajectory_operator_plugins/include/
local_planner/local_constraint_solver_plugins/include/

Without the trailing slash, these are installed at install/moveit_hybrid_planning/include/include/moveit/..... (notice the extra include) and other packages cannot find them without adding an include in the path

Copy link
Member

@AndyZe AndyZe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do another pass after you address this round of reviews. Looks good! I'm excited to see it develop further.

sjahr and others added 19 commits September 28, 2021 15:46
* Add hybrid_planning architecture skeleton code
* Add simple state machines to hybrid planning manager and local planner
* Initial global planner prototype implementation
* Forward joint_trajectory with local planner
* Forward hybrid planning motion request to global planner
* Abstract planner logic from hybrid planning manager by using a plugin
* Implement single plan execution logic
* Add test launch files, RViz and demo config
* Add test for motion_planning_request
* Make local planner component generic
* Add next_waypoint_sampler trajectory operator
* Update hybrid planning test to include collision object
* Clean up code and fix minor bugs.
* Update local planner component parameter
* Add local collision constraint solver
* Update planning scene topic name and test node
* Fix bugs and runtime errors in local planner component and it's plugins
* Add collision object that invalidates global trajectory
* Add simple "stop in front of collision object" demo
* Add hybrid planning manager reaction to local planner feedback
* Fix ament_lint_cmake
* Ensure that local planner start command and collision event are send once
* Add simple replanning logic plugin
* Use current state as start state for global planner
* Use RobotTrajectory instead of constraint vector describe local problem
* Add PlanningSceneMonitorPtr to local solver plugin
* Add local planner frequency parameter
* Use PID controller to create control outputs for robot controller
* Add hybrid_planning_manager config file
* Add more complex test node
* Update README
* Reset index in next_waypoint_sampler
* Use correct isPathValid() interface
* Rename path_invalidation flag
* Read planning scene instead of cloning it in local planner
* Add TODO creator
* Rename local constraint solver plugin
* Use read-locked access to the planning scene for collision checking
* Rename constraint_solver into local_constraint_solver
* Add missing pointer initialization
* Export missing plugins
* Use std::chrono_literals
* Construct smart pointers with std::make_* instead of 'new'
* Fixup const-ref in function signatures, reduce copies
* Improve planning scene locking, robot state processing, controller logic
* Add forward_trajectory local solver plugin (#359)
* Use ros2_control based joint simulation and remove unnecessary comment
* Update copyrights
* Restructure hybrid planning package
* Fix formatting and add missing time stamp in local solver plugin
* Remove unnecessary logging and param loading
* Enable different interfaces between local planner and controller
* Use JointGroupPositionController as demo hardware controller
* Add reset method for trajectory operator and local constraint sampler
* Refactor next_waypoint_sampler into simple_sampler
* Include collision checking to forward_trajectory and remove unneeded plugin
* Fix formatting and plugin description
* Update README and add missing planner logic plugin description
Copy link
Member

@henningkayser henningkayser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here a first round of comments. Also, two things that should be addressed:

  • Use include guards (i.e. #pragma once) for all headers
  • Consider using consistent prefixes/postfixes for plugin names. For instance SimpleSampler, SinglePlanExecutiondoes not really tell you what kind of plugin is or does. I'd suggest using postfixes like *PlannerLogic, *TrajectoryOp, GlobalPlanner, etc...

std::unique_ptr<pluginlib::ClassLoader<moveit_hybrid_planning::GlobalPlannerInterface>> global_planner_plugin_loader_;

// Global planner instance
std::shared_ptr<moveit_hybrid_planning::GlobalPlannerInterface> global_planner_instance_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use std::unique_ptr?

Copy link
Member

@AndyZe AndyZe Nov 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A unique_ptr leads to an issue when creating the plugin here. I'm not quite sure how to fix this.

global_planner_instance_ = global_planner_plugin_loader_->createUniqueInstance(global_planner_name_);

The error:

error: no match for ‘operator=’ (operand types are ‘std::unique_ptr<moveit_hybrid_planning::GlobalPlannerInterface>’ and ‘pluginlib::UniquePtr<moveit_hybrid_planning::GlobalPlannerInterface>’ {aka ‘std::unique_ptr<moveit_hybrid_planning::GlobalPlannerInterface, std::function<void(moveit_hybrid_planning::GlobalPlannerInterface*)> >’})

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pluginlib has its own unique_ptr type which basically provides unique access to the single instance managed by the plugin loader. So you either need to use pluginlib::UniquePtr or create an unmanaged plugin instance. Thinking about this more, I'm not sure if any of these versions is better than simply using shared_ptr, though. @tylerjw any thoughts?

last_global_solution_ = planning_solution; // TODO(sjahr) Add Service to expose this

// Reset the global planner
if (!global_planner_instance_->reset())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this case even relevant? I think that resetting a planner should never fail. If possible, reset() should even be noexcept imo and we can remove this exception.

std::unique_ptr<pluginlib::ClassLoader<moveit_hybrid_planning::PlannerLogicInterface>> planner_logic_plugin_loader_;

// Planner logic instance to implement reactive behavior
std::shared_ptr<moveit_hybrid_planning::PlannerLogicInterface> planner_logic_instance_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unique_ptr?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue with plugin loading, discussed above

* @param event Basic hybrid planning event
* @return Reaction result that summarizes the outcome of the reaction
*/
virtual ReactionResult react(const BasicHybridPlanningEvent& event) = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if react() is a good function name here. Maybe use something like processEvent() or similar

@@ -8,7 +8,7 @@ on:
pull_request:
push:
branches:
- main
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to change the branch here to trigger a CI run, you can do that just by pushing to your branch with an open PR.

By doing this you will cause CI to run twice for each time you push. Once for your push, and another because there was a push into a branch with a open PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add a TODO to remove this. As I cannot directly push on the feature branch, I need to open PRs against it and from my understanding, without this change, these PRs wouldn't get checked by CI

.github/workflows/format.yaml Show resolved Hide resolved
moveit2.repos Show resolved Hide resolved
moveit_ros/hybrid_planning/CMakeLists.txt Show resolved Hide resolved
moveit_ros/hybrid_planning/CMakeLists.txt Show resolved Hide resolved

HybridPlanningDemo demo(node);
std::thread run_demo([&demo]() {
rclcpp::sleep_for(5s);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems fairly fragile, have you tested this on slow machines?

@tylerjw
Copy link
Member

tylerjw commented Oct 1, 2021

The lack of unit tests to test the functionality inside the core classes of this is sad. Please consider adding unit tests to this to verify the logic in the core classes of this.

@sjahr sjahr mentioned this pull request Oct 20, 2021
7 tasks
@henningkayser henningkayser self-assigned this Oct 22, 2021
@tylerjw tylerjw mentioned this pull request Oct 29, 2021
6 tasks
@AndyZe
Copy link
Member

AndyZe commented Nov 17, 2021

I'm working on addressing the code reviews but I can't push to this branch. I'll probably just open a new PR like Tyler did already with #763

Overall, this still works with a few tweaks but bit rot is starting to set in. Would like to get it merged sooner rather than later.

@sjahr
Copy link
Contributor Author

sjahr commented Nov 18, 2021

I'm working on addressing the code reviews but I can't push to this branch. I'll probably just open a new PR like Tyler did already with #763

Overall, this still works with a few tweaks but bit rot is starting to set in. Would like to get it merged sooner rather than later.

@AndyZe Thanks for taking this up! I've also addressed a couple of things today and reopened a PR to add those things to the feature branch to make them visible in this PR. Feel free to add your changes to PR #811 or incorporate them in your own PR

@AndyZe
Copy link
Member

AndyZe commented Nov 18, 2021

Closing in favor of #811. I'll still track whether the comments get addressed here

@AndyZe AndyZe closed this Nov 18, 2021
@henningkayser henningkayser deleted the feature/hybrid_planning branch May 24, 2022 12:23
MikeWrock pushed a commit to MikeWrock/moveit2 that referenced this pull request Aug 15, 2022
* Add detail on custom IK plugin param declaration.

MoveIt Servo dispenses with the `automatically_declare_parameters_from_overrides` machinery discussed here:

https://github.com/orgs/ros-planning/discussions/1486

However, unlike a kinematics plugin loaded by a `move_group` node, this seems to mean that the kinematics plugin code is responsible for declaring any custom parameters on `/servo_node` that it needs to load from a MoveIt Config's `kinematics.yaml`

Maybe this is not the case for configs generated with `MoveItConfigsBuilder`, but it was my experience with the launch strategy used by

https://github.com/UniversalRobots/Universal_Robots_ROS2_Driver/tree/main/ur_moveit_config

* Typo on line number

* Fix code tag formatting

* getROSParam code tag

* Whitespace cleanup

Co-authored-by: AndyZe <andyz@utexas.edu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants