moveit2
The MoveIt Motion Planning Framework for ROS 2.
hybrid_planning_demo_node.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2020, PickNik Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of PickNik Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Sebastian Jahr
36  Description: A demonstration that re-plans around a moving box.
37  */
38 
39 #include <thread>
40 
47 #include <moveit_msgs/action/hybrid_planner.hpp>
48 #include <moveit_msgs/msg/display_robot_state.hpp>
49 #include <moveit_msgs/msg/motion_plan_response.hpp>
50 #include <rclcpp/executors.hpp>
51 #include <rclcpp/experimental/buffers/intra_process_buffer.hpp>
52 #include <rclcpp/logger.hpp>
53 #include <rclcpp/logging.hpp>
54 #include <rclcpp/node.hpp>
55 #include <rclcpp/node_options.hpp>
56 #include <rclcpp/parameter_value.hpp>
57 #include <rclcpp/qos.hpp>
58 #include <rclcpp/qos_event.hpp>
59 #include <rclcpp/subscription.hpp>
60 #include <rclcpp/timer.hpp>
61 #include <rclcpp/utilities.hpp>
62 #include <rclcpp_action/client.hpp>
63 #include <rclcpp_action/client_goal_handle.hpp>
64 #include <rclcpp_action/create_client.hpp>
65 
66 using namespace std::chrono_literals;
67 namespace
68 {
69 const rclcpp::Logger LOGGER = rclcpp::get_logger("test_hybrid_planning_client");
70 } // namespace
71 
73 {
74 public:
75  HybridPlanningDemo(const rclcpp::Node::SharedPtr& node)
76  {
77  node_ = node;
78 
79  std::string hybrid_planning_action_name = "";
80  if (node_->has_parameter("hybrid_planning_action_name"))
81  {
82  node_->get_parameter<std::string>("hybrid_planning_action_name", hybrid_planning_action_name);
83  }
84  else
85  {
86  RCLCPP_ERROR(LOGGER, "hybrid_planning_action_name parameter was not defined");
87  std::exit(EXIT_FAILURE);
88  }
89  hp_action_client_ =
90  rclcpp_action::create_client<moveit_msgs::action::HybridPlanner>(node_, hybrid_planning_action_name);
91 
92  collision_object_1_.header.frame_id = "panda_link0";
93  collision_object_1_.id = "box1";
94 
95  collision_object_2_.header.frame_id = "panda_link0";
96  collision_object_2_.id = "box2";
97 
98  collision_object_3_.header.frame_id = "panda_link0";
99  collision_object_3_.id = "box3";
100 
101  box_1_.type = box_1_.BOX;
102  box_1_.dimensions = { 0.5, 0.8, 0.01 };
103 
104  box_2_.type = box_2_.BOX;
105  box_2_.dimensions = { 1.0, 0.4, 0.01 };
106 
107  // Add new collision object as soon as global trajectory is available.
108  global_solution_subscriber_ = node_->create_subscription<moveit_msgs::msg::MotionPlanResponse>(
109  "global_trajectory", rclcpp::SystemDefaultsQoS(),
110  [this](const moveit_msgs::msg::MotionPlanResponse::ConstSharedPtr& /* unused */) {
111  // Remove old collision objects
112  collision_object_1_.operation = collision_object_1_.REMOVE;
113 
114  // Add new collision objects
115  geometry_msgs::msg::Pose box_pose_2;
116  box_pose_2.position.x = 0.2;
117  box_pose_2.position.y = 0.4;
118  box_pose_2.position.z = 0.95;
119 
120  collision_object_2_.primitives.push_back(box_2_);
121  collision_object_2_.primitive_poses.push_back(box_pose_2);
122  collision_object_2_.operation = collision_object_2_.ADD;
123 
124  geometry_msgs::msg::Pose box_pose_3;
125  box_pose_3.position.x = 0.2;
126  box_pose_3.position.y = -0.4;
127  box_pose_3.position.z = 0.95;
128 
129  collision_object_3_.primitives.push_back(box_2_);
130  collision_object_3_.primitive_poses.push_back(box_pose_3);
131  collision_object_3_.operation = collision_object_3_.ADD;
132 
133  // Add object to planning scene
134  { // Lock PlanningScene
135  planning_scene_monitor::LockedPlanningSceneRW scene(planning_scene_monitor_);
136  scene->processCollisionObjectMsg(collision_object_2_);
137  scene->processCollisionObjectMsg(collision_object_3_);
138  scene->processCollisionObjectMsg(collision_object_1_);
139  } // Unlock PlanningScene
140  });
141  }
142 
143  void run()
144  {
145  RCLCPP_INFO(LOGGER, "Initialize Planning Scene Monitor");
146  tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
147 
148  planning_scene_monitor_ = std::make_shared<planning_scene_monitor::PlanningSceneMonitor>(
149  node_, "robot_description", tf_buffer_, "planning_scene_monitor");
150  if (!planning_scene_monitor_->getPlanningScene())
151  {
152  RCLCPP_ERROR(LOGGER, "The planning scene was not retrieved!");
153  return;
154  }
155  else
156  {
157  planning_scene_monitor_->startStateMonitor();
158  planning_scene_monitor_->providePlanningSceneService(); // let RViz display query PlanningScene
159  planning_scene_monitor_->setPlanningScenePublishingFrequency(100);
160  planning_scene_monitor_->startPublishingPlanningScene(planning_scene_monitor::PlanningSceneMonitor::UPDATE_SCENE,
161  "/planning_scene");
162  planning_scene_monitor_->startSceneMonitor();
163  }
164 
165  if (!planning_scene_monitor_->waitForCurrentRobotState(node_->now(), 5))
166  {
167  RCLCPP_ERROR(LOGGER, "Timeout when waiting for /joint_states updates. Is the robot running?");
168  return;
169  }
170 
171  if (!hp_action_client_->wait_for_action_server(20s))
172  {
173  RCLCPP_ERROR(LOGGER, "Hybrid planning action server not available after waiting");
174  return;
175  }
176 
177  geometry_msgs::msg::Pose box_pose;
178  box_pose.position.x = 0.4;
179  box_pose.position.y = 0.0;
180  box_pose.position.z = 0.85;
181 
182  collision_object_1_.primitives.push_back(box_1_);
183  collision_object_1_.primitive_poses.push_back(box_pose);
184  collision_object_1_.operation = collision_object_1_.ADD;
185 
186  // Add object to planning scene
187  { // Lock PlanningScene
188  planning_scene_monitor::LockedPlanningSceneRW scene(planning_scene_monitor_);
189  scene->processCollisionObjectMsg(collision_object_1_);
190  } // Unlock PlanningScene
191 
192  RCLCPP_INFO(LOGGER, "Wait 2s for the collision object");
193  rclcpp::sleep_for(2s);
194 
195  // Setup motion planning goal taken from motion_planning_api tutorial
196  const std::string planning_group = "panda_arm";
197  robot_model_loader::RobotModelLoader robot_model_loader(node_, "robot_description");
198  const moveit::core::RobotModelPtr& robot_model = robot_model_loader.getModel();
199 
200  // Create a RobotState and JointModelGroup
201  const auto robot_state = std::make_shared<moveit::core::RobotState>(robot_model);
202  const moveit::core::JointModelGroup* joint_model_group = robot_state->getJointModelGroup(planning_group);
203 
204  // Configure a valid robot state
205  robot_state->setToDefaultValues(joint_model_group, "ready");
206  robot_state->update();
207  // Lock the planning scene as briefly as possible
208  {
209  planning_scene_monitor::LockedPlanningSceneRW locked_planning_scene(planning_scene_monitor_);
210  locked_planning_scene->setCurrentState(*robot_state);
211  }
212 
213  // Create desired motion goal
214  moveit_msgs::msg::MotionPlanRequest goal_motion_request;
215 
216  moveit::core::robotStateToRobotStateMsg(*robot_state, goal_motion_request.start_state);
217  goal_motion_request.group_name = planning_group;
218  goal_motion_request.num_planning_attempts = 10;
219  goal_motion_request.max_velocity_scaling_factor = 0.1;
220  goal_motion_request.max_acceleration_scaling_factor = 0.1;
221  goal_motion_request.allowed_planning_time = 2.0;
222  goal_motion_request.planner_id = "ompl";
223  goal_motion_request.pipeline_id = "ompl";
224 
225  moveit::core::RobotState goal_state(robot_model);
226  std::vector<double> joint_values = { 0.0, 0.0, 0.0, 0.0, 0.0, 1.571, 0.785 };
227  goal_state.setJointGroupPositions(joint_model_group, joint_values);
228 
229  goal_motion_request.goal_constraints.resize(1);
230  goal_motion_request.goal_constraints[0] =
231  kinematic_constraints::constructGoalConstraints(goal_state, joint_model_group);
232 
233  // Create Hybrid Planning action request
234  moveit_msgs::msg::MotionSequenceItem sequence_item;
235  sequence_item.req = goal_motion_request;
236  sequence_item.blend_radius = 0.0; // Single goal
237 
238  moveit_msgs::msg::MotionSequenceRequest sequence_request;
239  sequence_request.items.push_back(sequence_item);
240 
241  auto goal_action_request = moveit_msgs::action::HybridPlanner::Goal();
242  goal_action_request.planning_group = planning_group;
243  goal_action_request.motion_sequence = sequence_request;
244 
245  auto send_goal_options = rclcpp_action::Client<moveit_msgs::action::HybridPlanner>::SendGoalOptions();
246  send_goal_options.result_callback =
247  [](const rclcpp_action::ClientGoalHandle<moveit_msgs::action::HybridPlanner>::WrappedResult& result) {
248  switch (result.code)
249  {
250  case rclcpp_action::ResultCode::SUCCEEDED:
251  RCLCPP_INFO(LOGGER, "Hybrid planning goal succeeded");
252  break;
253  case rclcpp_action::ResultCode::ABORTED:
254  RCLCPP_ERROR(LOGGER, "Hybrid planning goal was aborted");
255  return;
256  case rclcpp_action::ResultCode::CANCELED:
257  RCLCPP_ERROR(LOGGER, "Hybrid planning goal was canceled");
258  return;
259  default:
260  RCLCPP_ERROR(LOGGER, "Unknown hybrid planning result code");
261  return;
262  RCLCPP_INFO(LOGGER, "Hybrid planning result received");
263  }
264  };
265  send_goal_options.feedback_callback =
266  [](const rclcpp_action::ClientGoalHandle<moveit_msgs::action::HybridPlanner>::SharedPtr& /*unused*/,
267  const std::shared_ptr<const moveit_msgs::action::HybridPlanner::Feedback>& feedback) {
268  RCLCPP_INFO_STREAM(LOGGER, feedback->feedback);
269  };
270 
271  RCLCPP_INFO(LOGGER, "Sending hybrid planning goal");
272  // Ask server to achieve some goal and wait until it's accepted
273  auto goal_handle_future = hp_action_client_->async_send_goal(goal_action_request, send_goal_options);
274  }
275 
276 private:
277  rclcpp::Node::SharedPtr node_;
278  rclcpp_action::Client<moveit_msgs::action::HybridPlanner>::SharedPtr hp_action_client_;
279  rclcpp::Subscription<moveit_msgs::msg::MotionPlanResponse>::SharedPtr global_solution_subscriber_;
280  planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_;
281  rclcpp::TimerBase::SharedPtr timer_;
282 
283  moveit_msgs::msg::CollisionObject collision_object_1_;
284  moveit_msgs::msg::CollisionObject collision_object_2_;
285  moveit_msgs::msg::CollisionObject collision_object_3_;
286  shape_msgs::msg::SolidPrimitive box_1_;
287  shape_msgs::msg::SolidPrimitive box_2_;
288 
289  // TF
290  std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
291 };
292 
293 int main(int argc, char** argv)
294 {
295  rclcpp::init(argc, argv);
296  rclcpp::NodeOptions node_options;
297  node_options.automatically_declare_parameters_from_overrides(true);
298 
299  rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>("hybrid_planning_test_node", "", node_options);
300 
301  HybridPlanningDemo demo(node);
302  std::thread run_demo([&demo]() {
303  // This sleep isn't necessary but it gives humans time to process what's going on
304  rclcpp::sleep_for(5s);
305  demo.run();
306  });
307 
308  rclcpp::spin(node);
309  run_demo.join();
310  rclcpp::shutdown();
311  return 0;
312 }
HybridPlanningDemo(const rclcpp::Node::SharedPtr &node)
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
Given positions for the variables that make up a group, in the order found in the group (including va...
Definition: robot_state.h:605
This is a convenience class for obtaining access to an instance of a locked PlanningScene.
int main(int argc, char **argv)
moveit_msgs::msg::Constraints constructGoalConstraints(const moveit::core::RobotState &state, const moveit::core::JointModelGroup *jmg, double tolerance_below, double tolerance_above)
Generates a constraint message intended to be used as a goal constraint for a joint group....
Definition: utils.cpp:144
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::msg::RobotState &robot_state, bool copy_attached_bodies=true)
Convert a MoveIt robot state to a robot state message.
scene
Definition: pick.py:52
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
const rclcpp::Logger LOGGER
Definition: async_test.h:31