moveit_cpp.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, PickNik LLC
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 LLC 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: Henning Kayser */
36 
37 #include <stdexcept>
39 
40 namespace moveit_cpp
41 {
42 constexpr char LOGNAME[] = "moveit_cpp";
43 constexpr char PLANNING_PLUGIN_PARAM[] = "planning_plugin";
44 
45 MoveItCpp::MoveItCpp(const ros::NodeHandle& nh, const std::shared_ptr<tf2_ros::Buffer>& tf_buffer)
46  : MoveItCpp(Options(nh), nh, tf_buffer)
47 {
48 }
49 
50 MoveItCpp::MoveItCpp(const Options& options, const ros::NodeHandle& nh,
51  const std::shared_ptr<tf2_ros::Buffer>& tf_buffer)
52  : tf_buffer_(tf_buffer), node_handle_(nh)
53 {
54  if (!tf_buffer_)
55  tf_buffer_ = std::make_shared<tf2_ros::Buffer>();
56  tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
57 
58  // Configure planning scene monitor
59  if (!loadPlanningSceneMonitor(options.planning_scene_monitor_options))
60  {
61  const std::string error = "Unable to configure planning scene monitor";
63  throw std::runtime_error(error);
64  }
65 
66  if (!getRobotModel())
67  {
68  const std::string error = "Unable to construct robot model. Please make sure all needed information is on the "
69  "parameter server.";
71  throw std::runtime_error(error);
72  }
73 
74  bool load_planning_pipelines = true;
75  if (load_planning_pipelines && !loadPlanningPipelines(options.planning_pipeline_options))
76  {
77  const std::string error = "Failed to load planning pipelines from parameter server";
79  throw std::runtime_error(error);
80  }
81 
82  // TODO(henningkayser): configure trajectory execution manager
83  trajectory_execution_manager_ = std::make_shared<trajectory_execution_manager::TrajectoryExecutionManager>(
84  getRobotModel(), planning_scene_monitor_->getStateMonitor());
85 
86  ROS_DEBUG_NAMED(LOGNAME, "MoveItCpp running");
87 }
88 
89 MoveItCpp::~MoveItCpp()
90 {
91  ROS_INFO_NAMED(LOGNAME, "Deleting MoveItCpp");
92 }
93 
94 bool MoveItCpp::loadPlanningSceneMonitor(const PlanningSceneMonitorOptions& options)
95 {
96  planning_scene_monitor_ = std::make_shared<planning_scene_monitor::PlanningSceneMonitor>(options.robot_description,
97  tf_buffer_, options.name);
98  // Allows us to sycronize to Rviz and also publish collision objects to ourselves
99  ROS_DEBUG_STREAM_NAMED(LOGNAME, "Configuring Planning Scene Monitor");
100  if (planning_scene_monitor_->getPlanningScene())
101  {
102  // Start state and scene monitors
103  ROS_INFO_NAMED(LOGNAME, "Listening to '%s' for joint states", options.joint_state_topic.c_str());
104  // Subscribe to JointState sensor messages
105  planning_scene_monitor_->startStateMonitor(options.joint_state_topic, options.attached_collision_object_topic);
106  // Publish planning scene updates to remote monitors like RViz
107  planning_scene_monitor_->startPublishingPlanningScene(planning_scene_monitor::PlanningSceneMonitor::UPDATE_SCENE,
108  options.monitored_planning_scene_topic);
109  // Monitor and apply planning scene updates from remote publishers like the PlanningSceneInterface
110  planning_scene_monitor_->startSceneMonitor(options.publish_planning_scene_topic);
111  // Monitor requests for changes in the collision environment
112  planning_scene_monitor_->startWorldGeometryMonitor();
113  }
114  else
115  {
116  ROS_ERROR_STREAM_NAMED(LOGNAME, "Planning scene not configured");
117  return false;
118  }
119 
120  // Wait for complete state to be recieved
121  if (options.wait_for_initial_state_timeout > 0.0)
122  {
123  return planning_scene_monitor_->getStateMonitor()->waitForCurrentState(ros::Time::now(),
124  options.wait_for_initial_state_timeout);
125  }
126 
127  return true;
128 }
129 
130 bool MoveItCpp::loadPlanningPipelines(const PlanningPipelineOptions& options)
131 {
132  ros::NodeHandle node_handle(options.parent_namespace.empty() ? "~" : options.parent_namespace);
133  for (const auto& planning_pipeline_name : options.pipeline_names)
134  {
135  if (planning_pipelines_.count(planning_pipeline_name) > 0)
136  {
137  ROS_WARN_NAMED(LOGNAME, "Skipping duplicate entry for planning pipeline '%s'.", planning_pipeline_name.c_str());
138  continue;
139  }
140  ROS_INFO_NAMED(LOGNAME, "Loading planning pipeline '%s'", planning_pipeline_name.c_str());
141  ros::NodeHandle child_nh(node_handle, planning_pipeline_name);
142 
143  try
144  {
145  auto pipeline =
146  std::make_shared<planning_pipeline::PlanningPipeline>(getRobotModel(), child_nh, PLANNING_PLUGIN_PARAM);
147 
148  if (!pipeline->getPlannerManager())
149  throw std::runtime_error("Invalid planner manager");
150 
151  planning_pipelines_[planning_pipeline_name] = pipeline;
152  }
153  catch (std::exception& ex)
154  {
155  ROS_ERROR_NAMED(LOGNAME, "Failed to initialize planning pipeline '%s':\n%s", planning_pipeline_name.c_str(),
156  ex.what());
157  }
158  }
159 
160  if (planning_pipelines_.empty())
161  {
162  ROS_ERROR_NAMED(LOGNAME, "Failed to load any planning pipelines.");
163  return false;
164  }
165 
166  return true;
167 }
168 
169 moveit::core::RobotModelConstPtr MoveItCpp::getRobotModel() const
170 {
171  return planning_scene_monitor_->getRobotModel();
172 }
173 
174 const ros::NodeHandle& MoveItCpp::getNodeHandle() const
175 {
176  return node_handle_;
177 }
178 
179 bool MoveItCpp::getCurrentState(moveit::core::RobotStatePtr& current_state, double wait_seconds)
180 {
181  if (wait_seconds > 0.0 &&
182  !planning_scene_monitor_->getStateMonitor()->waitForCurrentState(ros::Time::now(), wait_seconds))
183  {
184  ROS_ERROR_NAMED(LOGNAME, "Did not receive robot state");
185  return false;
186  }
187  { // Lock planning scene
188  planning_scene_monitor::LockedPlanningSceneRO scene(planning_scene_monitor_);
189  current_state = std::make_shared<moveit::core::RobotState>(scene->getCurrentState());
190  } // Unlock planning scene
191  return true;
192 }
193 
194 moveit::core::RobotStatePtr MoveItCpp::getCurrentState(double wait)
195 {
196  moveit::core::RobotStatePtr current_state;
197  getCurrentState(current_state, wait);
198  return current_state;
199 }
200 
201 const std::map<std::string, planning_pipeline::PlanningPipelinePtr>& MoveItCpp::getPlanningPipelines() const
202 {
203  return planning_pipelines_;
204 }
205 
206 planning_scene_monitor::PlanningSceneMonitorConstPtr MoveItCpp::getPlanningSceneMonitor() const
207 {
208  return planning_scene_monitor_;
209 }
210 
211 planning_scene_monitor::PlanningSceneMonitorPtr MoveItCpp::getPlanningSceneMonitorNonConst()
212 {
213  return planning_scene_monitor_;
214 }
215 
216 trajectory_execution_manager::TrajectoryExecutionManagerConstPtr MoveItCpp::getTrajectoryExecutionManager() const
217 {
218  return trajectory_execution_manager_;
219 }
220 
221 trajectory_execution_manager::TrajectoryExecutionManagerPtr MoveItCpp::getTrajectoryExecutionManagerNonConst()
222 {
223  return trajectory_execution_manager_;
224 }
225 
226 bool MoveItCpp::execute(const std::string& group_name, const robot_trajectory::RobotTrajectoryPtr& robot_trajectory,
227  bool blocking)
228 {
229  if (!robot_trajectory)
230  {
231  ROS_ERROR_NAMED(LOGNAME, "Robot trajectory is undefined");
232  return false;
233  }
234 
235  // Check if there are controllers that can handle the execution
236  if (!trajectory_execution_manager_->ensureActiveControllersForGroup(group_name))
237  {
238  ROS_ERROR_NAMED(LOGNAME, "Execution failed! No active controllers configured for group '%s'", group_name.c_str());
239  return false;
240  }
241 
242  // Execute trajectory
243  moveit_msgs::RobotTrajectory robot_trajectory_msg;
244  robot_trajectory->getRobotTrajectoryMsg(robot_trajectory_msg);
245  // TODO: cambel
246  // blocking is the only valid option right now. Add non-bloking use case
247  if (blocking)
248  {
249  trajectory_execution_manager_->push(robot_trajectory_msg);
250  trajectory_execution_manager_->execute();
251  return trajectory_execution_manager_->waitForExecution();
252  }
253  return true;
254 }
255 
256 bool MoveItCpp::terminatePlanningPipeline(std::string const& pipeline_name)
257 {
258  try
259  {
260  auto const& planning_pipeline = planning_pipelines_.at(pipeline_name);
261  if (planning_pipeline->isActive())
262  {
263  planning_pipeline->terminate();
264  }
265  return true;
266  }
267  catch (const std::out_of_range& oor)
268  {
269  ROS_ERROR_NAMED(LOGNAME, "Cannot terminate pipeline '%s' because no pipeline with that name exists",
270  pipeline_name.c_str());
271  return false;
272  }
273 }
274 
275 std::shared_ptr<const tf2_ros::Buffer> MoveItCpp::getTFBuffer() const
276 {
277  return tf_buffer_;
278 }
279 std::shared_ptr<tf2_ros::Buffer> MoveItCpp::getTFBuffer()
280 {
281  return tf_buffer_;
282 }
283 
284 } // namespace moveit_cpp
moveit_cpp::MoveItCpp::MoveItCpp
MoveItCpp(const ros::NodeHandle &nh, const std::shared_ptr< tf2_ros::Buffer > &tf_buffer={})
Constructor.
Definition: moveit_cpp.cpp:77
ROS_DEBUG_STREAM_NAMED
#define ROS_DEBUG_STREAM_NAMED(name, args)
moveit_cpp::PLANNING_PLUGIN_PARAM
constexpr char PLANNING_PLUGIN_PARAM[]
Definition: moveit_cpp.cpp:75
ROS_ERROR_NAMED
#define ROS_ERROR_NAMED(name,...)
moveit_cpp
Definition: moveit_cpp.h:50
robot_trajectory
ROS_INFO_NAMED
#define ROS_INFO_NAMED(name,...)
ROS_FATAL_STREAM_NAMED
#define ROS_FATAL_STREAM_NAMED(name, args)
ROS_DEBUG_NAMED
#define ROS_DEBUG_NAMED(name,...)
ROS_ERROR_STREAM_NAMED
#define ROS_ERROR_STREAM_NAMED(name, args)
moveit_cpp.h
planning_pipeline
Planning pipeline.
Definition: planning_pipeline.h:48
tf_buffer
tf2_ros::Buffer * tf_buffer
planning_scene_monitor::LockedPlanningSceneRO
This is a convenience class for obtaining access to an instance of a locked PlanningScene.
Definition: planning_scene_monitor.h:643
ROS_WARN_NAMED
#define ROS_WARN_NAMED(name,...)
planning_scene_monitor::PlanningSceneMonitor::UPDATE_SCENE
@ UPDATE_SCENE
The entire scene was updated.
Definition: planning_scene_monitor.h:112
moveit_cpp::LOGNAME
constexpr char LOGNAME[]
Definition: moveit_cpp.cpp:74
ros::NodeHandle
moveit::planning_interface::MoveItCpp
moveit_cpp::MoveItCpp MoveItCpp
Definition: moveit_cpp.h:192
ros::Time::now
static Time now()


planning
Author(s): Ioan Sucan , Sachin Chitta
autogenerated on Thu Apr 18 2024 02:24:19