dwa_planner_ros.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 *
3 * Software License Agreement (BSD License)
4 *
5 * Copyright (c) 2009, Willow Garage, Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of Willow Garage, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * Author: Eitan Marder-Eppstein
36 *********************************************************************/
37 
39 #include <Eigen/Core>
40 #include <cmath>
41 
42 #include <ros/console.h>
43 
45 
47 #include <nav_msgs/Path.h>
48 
49 //register this planner as a BaseLocalPlanner plugin
51 
52 namespace dwa_local_planner {
53 
54  void DWAPlannerROS::reconfigureCB(DWAPlannerConfig &config, uint32_t level) {
55  if (setup_ && config.restore_defaults) {
56  config = default_config_;
57  config.restore_defaults = false;
58  }
59  if ( ! setup_) {
60  default_config_ = config;
61  setup_ = true;
62  }
63 
64  // update generic local planner params
66  limits.max_trans_vel = config.max_trans_vel;
67  limits.min_trans_vel = config.min_trans_vel;
68  limits.max_vel_x = config.max_vel_x;
69  limits.min_vel_x = config.min_vel_x;
70  limits.max_vel_y = config.max_vel_y;
71  limits.min_vel_y = config.min_vel_y;
72  limits.max_rot_vel = config.max_rot_vel;
73  limits.min_rot_vel = config.min_rot_vel;
74  limits.acc_lim_x = config.acc_lim_x;
75  limits.acc_lim_y = config.acc_lim_y;
76  limits.acc_lim_theta = config.acc_lim_theta;
77  limits.acc_limit_trans = config.acc_limit_trans;
78  limits.xy_goal_tolerance = config.xy_goal_tolerance;
79  limits.yaw_goal_tolerance = config.yaw_goal_tolerance;
80  limits.prune_plan = config.prune_plan;
81  limits.trans_stopped_vel = config.trans_stopped_vel;
82  limits.rot_stopped_vel = config.rot_stopped_vel;
83  planner_util_.reconfigureCB(limits, config.restore_defaults);
84 
85  // update dwa specific configuration
86  dp_->reconfigure(config);
87  }
88 
89  DWAPlannerROS::DWAPlannerROS() : initialized_(false),
90  odom_helper_("odom"), setup_(false) {
91 
92  }
93 
95  std::string name,
97  costmap_2d::Costmap2DROS* costmap_ros) {
98  if (! isInitialized()) {
99 
100  ros::NodeHandle private_nh("~/" + name);
101  g_plan_pub_ = private_nh.advertise<nav_msgs::Path>("global_plan", 1);
102  l_plan_pub_ = private_nh.advertise<nav_msgs::Path>("local_plan", 1);
103  tf_ = tf;
104  costmap_ros_ = costmap_ros;
106 
107  // make sure to update the costmap we'll use for this cycle
109 
111 
112  //create the actual planner that we'll use.. it'll configure itself from the parameter server
114 
115  if( private_nh.getParam( "odom_topic", odom_topic_ ))
116  {
118  }
119 
120  initialized_ = true;
121 
122  dsrv_ = new dynamic_reconfigure::Server<DWAPlannerConfig>(private_nh);
123  dynamic_reconfigure::Server<DWAPlannerConfig>::CallbackType cb = boost::bind(&DWAPlannerROS::reconfigureCB, this, _1, _2);
124  dsrv_->setCallback(cb);
125  }
126  else{
127  ROS_WARN("This planner has already been initialized, doing nothing.");
128  }
129  }
130 
131  bool DWAPlannerROS::setPlan(const std::vector<geometry_msgs::PoseStamped>& orig_global_plan) {
132  if (! isInitialized()) {
133  ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
134  return false;
135  }
136  //when we get a new plan, we also want to clear any latch we may have on goal tolerances
138 
139  ROS_INFO("Got new plan");
140  return dp_->setPlan(orig_global_plan);
141  }
142 
144  if (! isInitialized()) {
145  ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
146  return false;
147  }
149  ROS_ERROR("Could not get robot pose");
150  return false;
151  }
152 
154  ROS_INFO("Goal reached");
155  return true;
156  } else {
157  return false;
158  }
159  }
160 
161  void DWAPlannerROS::publishLocalPlan(std::vector<geometry_msgs::PoseStamped>& path) {
163  }
164 
165 
166  void DWAPlannerROS::publishGlobalPlan(std::vector<geometry_msgs::PoseStamped>& path) {
168  }
169 
171  //make sure to clean things up
172  delete dsrv_;
173  }
174 
175 
176 
177  bool DWAPlannerROS::dwaComputeVelocityCommands(tf::Stamped<tf::Pose> &global_pose, geometry_msgs::Twist& cmd_vel) {
178  // dynamic window sampling approach to get useful velocity commands
179  if(! isInitialized()){
180  ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
181  return false;
182  }
183 
184  tf::Stamped<tf::Pose> robot_vel;
185  odom_helper_.getRobotVel(robot_vel);
186 
187  /* For timing uncomment
188  struct timeval start, end;
189  double start_t, end_t, t_diff;
190  gettimeofday(&start, NULL);
191  */
192 
193  //compute what trajectory to drive along
194  tf::Stamped<tf::Pose> drive_cmds;
195  drive_cmds.frame_id_ = costmap_ros_->getBaseFrameID();
196 
197  // call with updated footprint
198  base_local_planner::Trajectory path = dp_->findBestPath(global_pose, robot_vel, drive_cmds);
199  //ROS_ERROR("Best: %.2f, %.2f, %.2f, %.2f", path.xv_, path.yv_, path.thetav_, path.cost_);
200 
201  /* For timing uncomment
202  gettimeofday(&end, NULL);
203  start_t = start.tv_sec + double(start.tv_usec) / 1e6;
204  end_t = end.tv_sec + double(end.tv_usec) / 1e6;
205  t_diff = end_t - start_t;
206  ROS_INFO("Cycle time: %.9f", t_diff);
207  */
208 
209  //pass along drive commands
210  cmd_vel.linear.x = drive_cmds.getOrigin().getX();
211  cmd_vel.linear.y = drive_cmds.getOrigin().getY();
212  cmd_vel.angular.z = tf::getYaw(drive_cmds.getRotation());
213 
214  //if we cannot move... tell someone
215  std::vector<geometry_msgs::PoseStamped> local_plan;
216  if(path.cost_ < 0) {
217  ROS_DEBUG_NAMED("dwa_local_planner",
218  "The dwa local planner failed to find a valid plan, cost functions discarded all candidates. This can mean there is an obstacle too close to the robot.");
219  local_plan.clear();
220  publishLocalPlan(local_plan);
221  return false;
222  }
223 
224  ROS_DEBUG_NAMED("dwa_local_planner", "A valid velocity command of (%.2f, %.2f, %.2f) was found for this cycle.",
225  cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z);
226 
227  // Fill out the local plan
228  for(unsigned int i = 0; i < path.getPointsSize(); ++i) {
229  double p_x, p_y, p_th;
230  path.getPoint(i, p_x, p_y, p_th);
231 
235  tf::Point(p_x, p_y, 0.0)),
236  ros::Time::now(),
238  geometry_msgs::PoseStamped pose;
239  tf::poseStampedTFToMsg(p, pose);
240  local_plan.push_back(pose);
241  }
242 
243  //publish information to the visualizer
244 
245  publishLocalPlan(local_plan);
246  return true;
247  }
248 
249 
250 
251 
252  bool DWAPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel) {
253  // dispatches to either dwa sampling control or stop and rotate control, depending on whether we have been close enough to goal
255  ROS_ERROR("Could not get robot pose");
256  return false;
257  }
258  std::vector<geometry_msgs::PoseStamped> transformed_plan;
259  if ( ! planner_util_.getLocalPlan(current_pose_, transformed_plan)) {
260  ROS_ERROR("Could not get local plan");
261  return false;
262  }
263 
264  //if the global plan passed in is empty... we won't do anything
265  if(transformed_plan.empty()) {
266  ROS_WARN_NAMED("dwa_local_planner", "Received an empty transformed plan.");
267  return false;
268  }
269  ROS_DEBUG_NAMED("dwa_local_planner", "Received a transformed plan with %zu points.", transformed_plan.size());
270 
271  // update plan in dwa_planner even if we just stop and rotate, to allow checkTrajectory
272  dp_->updatePlanAndLocalCosts(current_pose_, transformed_plan, costmap_ros_->getRobotFootprint());
273 
275  //publish an empty plan because we've reached our goal position
276  std::vector<geometry_msgs::PoseStamped> local_plan;
277  std::vector<geometry_msgs::PoseStamped> transformed_plan;
278  publishGlobalPlan(transformed_plan);
279  publishLocalPlan(local_plan);
282  cmd_vel,
283  limits.getAccLimits(),
284  dp_->getSimPeriod(),
285  &planner_util_,
286  odom_helper_,
288  boost::bind(&DWAPlanner::checkTrajectory, dp_, _1, _2, _3));
289  } else {
290  bool isOk = dwaComputeVelocityCommands(current_pose_, cmd_vel);
291  if (isOk) {
292  publishGlobalPlan(transformed_plan);
293  } else {
294  ROS_WARN_NAMED("dwa_local_planner", "DWA planner failed to produce path.");
295  std::vector<geometry_msgs::PoseStamped> empty_plan;
296  publishGlobalPlan(empty_plan);
297  }
298  return isOk;
299  }
300  }
301 
302 
303 };
boost::shared_ptr< DWAPlanner > dp_
The trajectory controller.
void reconfigureCB(DWAPlannerConfig &config, uint32_t level)
Callback to update the local planner&#39;s parameters based on dynamic reconfigure.
void getRobotVel(tf::Stamped< tf::Pose > &robot_vel)
bool getRobotPose(tf::Stamped< tf::Pose > &global_pose) const
#define ROS_WARN_NAMED(name,...)
dynamic_reconfigure::Server< DWAPlannerConfig > * dsrv_
static void poseStampedTFToMsg(const Stamped< Pose > &bt, geometry_msgs::PoseStamped &msg)
void initialize(std::string name, tf::TransformListener *tf, costmap_2d::Costmap2DROS *costmap_ros)
Constructs the ros wrapper.
static double getYaw(const Quaternion &bt_q)
bool getLocalPlan(tf::Stamped< tf::Pose > &global_pose, std::vector< geometry_msgs::PoseStamped > &transformed_plan)
bool isGoalReached(LocalPlannerUtil *planner_util, OdometryHelperRos &odom_helper, tf::Stamped< tf::Pose > global_pose)
std::string getGlobalFrameID()
PLUGINLIB_EXPORT_CLASS(BAGReader, nodelet::Nodelet)
base_local_planner::OdometryHelperRos odom_helper_
void getPoint(unsigned int index, double &x, double &y, double &th) const
#define ROS_WARN(...)
base_local_planner::LatchedStopRotateController latchedStopRotateController_
ROS Wrapper for the DWAPlanner that adheres to the BaseLocalPlanner interface and can be used as a pl...
void initialize(tf::TransformListener *tf, costmap_2d::Costmap2D *costmap, std::string global_frame)
tf::Transform Pose
#define ROS_DEBUG_NAMED(name,...)
bool dwaComputeVelocityCommands(tf::Stamped< tf::Pose > &global_pose, geometry_msgs::Twist &cmd_vel)
Given the current position, orientation, and velocity of the robot, compute velocity commands to send...
bool computeVelocityCommandsStopRotate(geometry_msgs::Twist &cmd_vel, Eigen::Vector3f acc_lim, double sim_period, LocalPlannerUtil *planner_util, OdometryHelperRos &odom_helper, tf::Stamped< tf::Pose > global_pose, boost::function< bool(Eigen::Vector3f pos, Eigen::Vector3f vel, Eigen::Vector3f vel_samples)> obstacle_check)
tf::TransformListener * tf_
Used for transforming point clouds.
A class implementing a local planner using the Dynamic Window Approach.
Definition: dwa_planner.h:71
costmap_2d::Costmap2DROS * costmap_ros_
static Quaternion createQuaternionFromYaw(double yaw)
bool computeVelocityCommands(geometry_msgs::Twist &cmd_vel)
Given the current position, orientation, and velocity of the robot, compute velocity commands to send...
#define ROS_INFO(...)
LocalPlannerLimits getCurrentLimits()
std::string getBaseFrameID()
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool setPlan(const std::vector< geometry_msgs::PoseStamped > &orig_global_plan)
Set the plan that the controller is following.
unsigned int getPointsSize() const
void publishPlan(const std::vector< geometry_msgs::PoseStamped > &path, const ros::Publisher &pub)
std::string frame_id_
void publishLocalPlan(std::vector< geometry_msgs::PoseStamped > &path)
bool getParam(const std::string &key, std::string &s) const
static Time now()
void setOdomTopic(std::string odom_topic)
void publishGlobalPlan(std::vector< geometry_msgs::PoseStamped > &path)
~DWAPlannerROS()
Destructor for the wrapper.
Costmap2D * getCostmap()
std::vector< geometry_msgs::Point > getRobotFootprint()
bool isGoalReached()
Check if the goal pose has been achieved.
tf::Stamped< tf::Pose > current_pose_
#define ROS_ERROR(...)
base_local_planner::LocalPlannerUtil planner_util_
bool checkTrajectory(const Eigen::Vector3f pos, const Eigen::Vector3f vel, const Eigen::Vector3f vel_samples)
Check if a trajectory is legal for a position/velocity pair.
bool isPositionReached(LocalPlannerUtil *planner_util, tf::Stamped< tf::Pose > global_pose)


dwa_local_planner
Author(s): Eitan Marder-Eppstein, contradict@gmail.com
autogenerated on Sun Mar 3 2019 03:44:35