moveit2
The MoveIt Motion Planning Framework for ROS 2.
test_basic_integration.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2022, 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: Andy Zelenak
36  Desc: Launch hybrid planning and test basic functionality
37 */
38 
39 #include <gtest/gtest.h>
43 #include <rclcpp/rclcpp.hpp>
44 #include <rclcpp_action/rclcpp_action.hpp>
45 #include <tf2_ros/buffer.h>
46 
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 
52 {
53 using namespace std::chrono_literals;
54 
55 class HybridPlanningFixture : public ::testing::Test
56 {
57 public:
58  HybridPlanningFixture() : node_(std::make_shared<rclcpp::Node>("hybrid_planning_testing"))
59  {
60  action_successful_ = false;
61  action_aborted_ = false;
62  action_complete_ = false;
63 
64  executor_.add_node(node_);
65 
66  std::string hybrid_planning_action_name = "";
67  node_->declare_parameter("hybrid_planning_action_name", "");
68  if (node_->has_parameter("hybrid_planning_action_name"))
69  {
70  node_->get_parameter<std::string>("hybrid_planning_action_name", hybrid_planning_action_name);
71  }
72  else
73  {
74  RCLCPP_ERROR(node_->get_logger(), "hybrid_planning_action_name parameter was not defined");
75  std::exit(EXIT_FAILURE);
76  }
77 
78  hp_action_client_ =
79  rclcpp_action::create_client<moveit_msgs::action::HybridPlanner>(node_, hybrid_planning_action_name);
80 
81  // Add new collision object as soon as global trajectory is available.
82  global_solution_subscriber_ = node_->create_subscription<moveit_msgs::msg::MotionPlanResponse>(
83  "global_trajectory", rclcpp::SystemDefaultsQoS(),
84  [this](const moveit_msgs::msg::MotionPlanResponse::SharedPtr /* unused */) {});
85 
86  RCLCPP_INFO(node_->get_logger(), "Initialize Planning Scene Monitor");
87  tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
88 
89  planning_scene_monitor_ = std::make_shared<planning_scene_monitor::PlanningSceneMonitor>(node_, "robot_description",
90  "planning_scene_monitor");
91  if (!planning_scene_monitor_->getPlanningScene())
92  {
93  RCLCPP_ERROR(node_->get_logger(), "The planning scene was not retrieved!");
94  std::exit(EXIT_FAILURE);
95  }
96  else
97  {
98  planning_scene_monitor_->startStateMonitor();
99  planning_scene_monitor_->setPlanningScenePublishingFrequency(100);
100  planning_scene_monitor_->startPublishingPlanningScene(planning_scene_monitor::PlanningSceneMonitor::UPDATE_SCENE,
101  "/planning_scene");
102  planning_scene_monitor_->startSceneMonitor();
103  }
104 
105  if (!planning_scene_monitor_->waitForCurrentRobotState(node_->now(), 5))
106  {
107  RCLCPP_ERROR(node_->get_logger(), "Timeout when waiting for /joint_states updates. Is the robot running?");
108  std::exit(EXIT_FAILURE);
109  }
110 
111  if (!hp_action_client_->wait_for_action_server(20s))
112  {
113  RCLCPP_ERROR(node_->get_logger(), "Hybrid planning action server not available after waiting");
114  std::exit(EXIT_FAILURE);
115  }
116 
117  // Setup motion planning goal taken from motion_planning_api tutorial
118  const std::string planning_group = "panda_arm";
119  robot_model_loader::RobotModelLoader robot_model_loader(node_, "robot_description");
120  const moveit::core::RobotModelPtr& robot_model = robot_model_loader.getModel();
121 
122  // Create a RobotState and JointModelGroup
123  const auto robot_state = std::make_shared<moveit::core::RobotState>(robot_model);
124  const moveit::core::JointModelGroup* joint_model_group = robot_state->getJointModelGroup(planning_group);
125 
126  // Configure a valid robot state
127  robot_state->setToDefaultValues(joint_model_group, "ready");
128  robot_state->update();
129  // Lock the planning scene as briefly as possible
130  {
131  planning_scene_monitor::LockedPlanningSceneRW locked_planning_scene(planning_scene_monitor_);
132  locked_planning_scene->setCurrentState(*robot_state);
133  }
134 
135  const moveit::core::RobotState goal_state([robot_model, joint_model_group]() {
136  moveit::core::RobotState goal_state(robot_model);
137  std::vector<double> joint_values = { 0.0, 0.0, 0.0, 0.0, 0.0, 1.571, 0.785 };
138  goal_state.setJointGroupPositions(joint_model_group, joint_values);
139  return goal_state;
140  }());
141 
142  // Create desired motion goal
143  const moveit_msgs::msg::MotionPlanRequest goal_motion_request(
144  [robot_state, planning_group, goal_state, joint_model_group]() {
145  moveit_msgs::msg::MotionPlanRequest goal_motion_request;
146  moveit::core::robotStateToRobotStateMsg(*robot_state, goal_motion_request.start_state);
147  goal_motion_request.group_name = planning_group;
148  goal_motion_request.num_planning_attempts = 10;
149  goal_motion_request.max_velocity_scaling_factor = 0.1;
150  goal_motion_request.max_acceleration_scaling_factor = 0.1;
151  goal_motion_request.allowed_planning_time = 2.0;
152  goal_motion_request.planner_id = "ompl";
153  goal_motion_request.pipeline_id = "ompl";
154  goal_motion_request.goal_constraints.resize(1);
155  goal_motion_request.goal_constraints[0] =
156  kinematic_constraints::constructGoalConstraints(goal_state, joint_model_group);
157  return goal_motion_request;
158  }());
159 
160  // Create Hybrid Planning action request
161  moveit_msgs::msg::MotionSequenceItem sequence_item;
162  sequence_item.req = goal_motion_request;
163  sequence_item.blend_radius = 0.0; // Single goal
164 
165  moveit_msgs::msg::MotionSequenceRequest sequence_request;
166  sequence_request.items.push_back(sequence_item);
167 
168  goal_action_request_ = moveit_msgs::action::HybridPlanner::Goal();
169  goal_action_request_.planning_group = planning_group;
170  goal_action_request_.motion_sequence = sequence_request;
171 
172  send_goal_options_ = rclcpp_action::Client<moveit_msgs::action::HybridPlanner>::SendGoalOptions();
173  send_goal_options_.result_callback =
174  [this](const rclcpp_action::ClientGoalHandle<moveit_msgs::action::HybridPlanner>::WrappedResult& result) {
175  switch (result.code)
176  {
177  case rclcpp_action::ResultCode::SUCCEEDED:
178  action_successful_ = true;
179  RCLCPP_INFO(node_->get_logger(), "Hybrid planning goal succeeded");
180  break;
181  case rclcpp_action::ResultCode::ABORTED:
182  action_aborted_ = true;
183  RCLCPP_ERROR(node_->get_logger(), "Hybrid planning goal was aborted");
184  break;
185  case rclcpp_action::ResultCode::CANCELED:
186  RCLCPP_ERROR(node_->get_logger(), "Hybrid planning goal was canceled");
187  break;
188  default:
189  RCLCPP_ERROR(node_->get_logger(), "Unknown hybrid planning result code");
190  break;
191  }
192  action_complete_ = true;
193  return;
194  };
195  send_goal_options_.feedback_callback =
196  [this](rclcpp_action::ClientGoalHandle<moveit_msgs::action::HybridPlanner>::SharedPtr /*unused*/,
197  const std::shared_ptr<const moveit_msgs::action::HybridPlanner::Feedback> feedback) {
198  RCLCPP_INFO(node_->get_logger(), feedback->feedback.c_str());
199  };
200  }
201 
202  rclcpp::executors::MultiThreadedExecutor executor_;
203 
204 protected:
205  rclcpp::Node::SharedPtr node_;
206  rclcpp_action::Client<moveit_msgs::action::HybridPlanner>::SharedPtr hp_action_client_;
207  rclcpp::Subscription<moveit_msgs::msg::MotionPlanResponse>::SharedPtr global_solution_subscriber_;
208  std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
209  planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_;
210  std::atomic_bool action_successful_;
211  std::atomic_bool action_complete_;
212  std::atomic_bool action_aborted_;
213 
214  // Action request
215  moveit_msgs::action::HybridPlanner::Goal goal_action_request_;
216  rclcpp_action::Client<moveit_msgs::action::HybridPlanner>::SendGoalOptions send_goal_options_;
217 }; // class HybridPlanningFixture
218 
219 // Make a hybrid planning request and verify it completes
220 TEST_F(HybridPlanningFixture, ActionCompletion)
221 {
222  std::thread run_thread([this]() {
223  // Send the goal
224  auto goal_handle_future = hp_action_client_->async_send_goal(goal_action_request_, send_goal_options_);
225  });
226 
227  rclcpp::Rate rate(10);
228  while (!action_complete_)
229  {
230  executor_.spin_once();
231  rate.sleep();
232  }
233  run_thread.join();
234  ASSERT_TRUE(action_successful_);
235 }
236 
237 // Make a hybrid planning request then abort it
239 {
240  std::thread run_thread([this]() {
241  // Send the goal
242  auto goal_handle_future = hp_action_client_->async_send_goal(goal_action_request_, send_goal_options_);
243 
244  // Cancel the goal
245  hp_action_client_->async_cancel_all_goals();
246  });
247 
248  rclcpp::Rate rate(10);
249  while (!action_complete_)
250  {
251  executor_.spin_once();
252  rate.sleep();
253  }
254  run_thread.join();
255  ASSERT_FALSE(action_successful_);
256  ASSERT_TRUE(action_aborted_);
257 }
258 } // namespace moveit_hybrid_planning
259 
260 int main(int argc, char** argv)
261 {
262  rclcpp::init(argc, argv);
263  ::testing::InitGoogleTest(&argc, argv);
264 
265  int ret = RUN_ALL_TESTS();
266  rclcpp::shutdown();
267  return ret;
268 }
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
planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_
rclcpp_action::Client< moveit_msgs::action::HybridPlanner >::SendGoalOptions send_goal_options_
rclcpp::Subscription< moveit_msgs::msg::MotionPlanResponse >::SharedPtr global_solution_subscriber_
rclcpp::executors::MultiThreadedExecutor executor_
moveit_msgs::action::HybridPlanner::Goal goal_action_request_
rclcpp_action::Client< moveit_msgs::action::HybridPlanner >::SharedPtr hp_action_client_
This is a convenience class for obtaining access to an instance of a locked PlanningScene.
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.
TEST_F(HybridPlanningFixture, ActionCompletion)
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
int main(int argc, char **argv)