41 #include <boost/tokenizer.hpp> 51 #include <nav_msgs/Path.h> 60 void TrajectoryPlannerROS::reconfigureCB(BaseLocalPlannerConfig &config, uint32_t level) {
61 if (setup_ && config.restore_defaults) {
62 config = default_config_;
64 config.restore_defaults =
false;
67 default_config_ = config;
70 tc_->reconfigure(config);
71 reached_goal_ =
false;
74 TrajectoryPlannerROS::TrajectoryPlannerROS() :
75 world_model_(NULL), tc_(NULL), costmap_ros_(NULL),
tf_(NULL), setup_(false), initialized_(false), odom_helper_(
"odom") {}
99 double sim_time, sim_granularity, angular_sim_granularity;
100 int vx_samples, vtheta_samples;
101 double pdist_scale, gdist_scale, occdist_scale, heading_lookahead, oscillation_reset_dist, escape_reset_dist, escape_reset_theta;
102 bool holonomic_robot, dwa, simple_attractor, heading_scoring;
103 double heading_scoring_timestep;
104 double max_vel_x, min_vel_x;
106 double stop_time_buffer;
107 std::string world_model_type;
124 private_nh.
param(
"stop_time_buffer", stop_time_buffer, 0.2);
130 if(private_nh.
hasParam(
"acc_limit_x"))
131 ROS_ERROR(
"You are using acc_limit_x where you should be using acc_lim_x. Please change your configuration files appropriately. The documentation used to be wrong on this, sorry for any confusion.");
133 if(private_nh.
hasParam(
"acc_limit_y"))
134 ROS_ERROR(
"You are using acc_limit_y where you should be using acc_lim_y. Please change your configuration files appropriately. The documentation used to be wrong on this, sorry for any confusion.");
136 if(private_nh.
hasParam(
"acc_limit_th"))
137 ROS_ERROR(
"You are using acc_limit_th where you should be using acc_lim_th. Please change your configuration files appropriately. The documentation used to be wrong on this, sorry for any confusion.");
142 std::string controller_frequency_param_name;
143 if(!private_nh.
searchParam(
"controller_frequency", controller_frequency_param_name))
147 double controller_frequency = 0;
148 private_nh.
param(controller_frequency_param_name, controller_frequency, 20.0);
149 if(controller_frequency > 0)
153 ROS_WARN(
"A controller_frequency less than 0 has been set. Ignoring the parameter, assuming a rate of 20Hz");
159 private_nh.
param(
"sim_time", sim_time, 1.0);
160 private_nh.
param(
"sim_granularity", sim_granularity, 0.025);
161 private_nh.
param(
"angular_sim_granularity", angular_sim_granularity, sim_granularity);
162 private_nh.
param(
"vx_samples", vx_samples, 3);
163 private_nh.
param(
"vtheta_samples", vtheta_samples, 20);
165 private_nh.
param(
"path_distance_bias", pdist_scale, 0.6);
166 private_nh.
param(
"goal_distance_bias", gdist_scale, 0.8);
167 private_nh.
param(
"occdist_scale", occdist_scale, 0.01);
170 if ( ! private_nh.
hasParam(
"meter_scoring")) {
171 ROS_WARN(
"Trajectory Rollout planner initialized with param meter_scoring not set. Set it to true to make your settins robust against changes of costmap resolution.");
173 private_nh.
param(
"meter_scoring", meter_scoring,
false);
178 gdist_scale *= resolution;
179 pdist_scale *= resolution;
180 occdist_scale *= resolution;
182 ROS_WARN(
"Trajectory Rollout planner initialized with param meter_scoring set to false. Set it to true to make your settins robust against changes of costmap resolution.");
186 private_nh.
param(
"heading_lookahead", heading_lookahead, 0.325);
187 private_nh.
param(
"oscillation_reset_dist", oscillation_reset_dist, 0.05);
188 private_nh.
param(
"escape_reset_dist", escape_reset_dist, 0.10);
189 private_nh.
param(
"escape_reset_theta", escape_reset_theta, M_PI_4);
190 private_nh.
param(
"holonomic_robot", holonomic_robot,
true);
191 private_nh.
param(
"max_vel_x", max_vel_x, 0.5);
192 private_nh.
param(
"min_vel_x", min_vel_x, 0.1);
194 double max_rotational_vel;
195 private_nh.
param(
"max_rotational_vel", max_rotational_vel, 1.0);
201 if(private_nh.
getParam(
"backup_vel", backup_vel))
202 ROS_WARN(
"The backup_vel parameter has been deprecated in favor of the escape_vel parameter. To switch, just change the parameter name in your configuration files.");
205 private_nh.
getParam(
"escape_vel", backup_vel);
207 if(backup_vel >= 0.0)
208 ROS_WARN(
"You've specified a positive escape velocity. This is probably not what you want and will cause the robot to move forward instead of backward. You should probably change your escape_vel parameter to be negative");
210 private_nh.
param(
"world_model", world_model_type, std::string(
"costmap"));
211 private_nh.
param(
"dwa", dwa,
true);
212 private_nh.
param(
"heading_scoring", heading_scoring,
false);
213 private_nh.
param(
"heading_scoring_timestep", heading_scoring_timestep, 0.8);
215 simple_attractor =
false;
218 double min_pt_separation, max_obstacle_height, grid_resolution;
220 private_nh.
param(
"point_grid/min_pt_separation", min_pt_separation, 0.01);
221 private_nh.
param(
"point_grid/max_obstacle_height", max_obstacle_height, 2.0);
222 private_nh.
param(
"point_grid/grid_resolution", grid_resolution, 0.2);
224 ROS_ASSERT_MSG(world_model_type ==
"costmap",
"At this time, only costmap world models are supported by this controller");
226 std::vector<double> y_vels =
loadYVels(private_nh);
232 gdist_scale, occdist_scale, heading_lookahead, oscillation_reset_dist, escape_reset_dist, escape_reset_theta, holonomic_robot,
234 dwa, heading_scoring, heading_scoring_timestep, meter_scoring, simple_attractor, y_vels, stop_time_buffer,
sim_period_, angular_sim_granularity);
239 dsrv_ =
new dynamic_reconfigure::Server<BaseLocalPlannerConfig>(private_nh);
241 dsrv_->setCallback(cb);
244 ROS_WARN(
"This planner has already been initialized, doing nothing");
249 std::vector<double> y_vels;
251 std::string y_vel_list;
252 if(node.
getParam(
"y_vels", y_vel_list)){
253 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
254 boost::char_separator<char> sep(
"[], ");
255 tokenizer tokens(y_vel_list, sep);
257 for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); i++){
258 y_vels.push_back(atof((*i).c_str()));
263 y_vels.push_back(-0.3);
264 y_vels.push_back(-0.1);
265 y_vels.push_back(0.1);
266 y_vels.push_back(0.3);
286 double vx =
sign(robot_vel.getOrigin().x()) * std::max(0.0, (fabs(robot_vel.getOrigin().x()) -
acc_lim_x_ *
sim_period_));
287 double vy =
sign(robot_vel.getOrigin().y()) * std::max(0.0, (fabs(robot_vel.getOrigin().y()) -
acc_lim_y_ * sim_period_));
289 double vel_yaw =
tf::getYaw(robot_vel.getRotation());
290 double vth =
sign(vel_yaw) * std::max(0.0, (fabs(vel_yaw) -
acc_lim_theta_ * sim_period_));
293 double yaw =
tf::getYaw(global_pose.getRotation());
294 bool valid_cmd =
tc_->
checkTrajectory(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw,
295 robot_vel.getOrigin().getX(), robot_vel.getOrigin().getY(), vel_yaw, vx, vy, vth);
299 ROS_DEBUG(
"Slowing down... using vx, vy, vth: %.2f, %.2f, %.2f", vx, vy, vth);
300 cmd_vel.linear.x = vx;
301 cmd_vel.linear.y = vy;
302 cmd_vel.angular.z = vth;
306 cmd_vel.linear.x = 0.0;
307 cmd_vel.linear.y = 0.0;
308 cmd_vel.angular.z = 0.0;
313 double yaw =
tf::getYaw(global_pose.getRotation());
314 double vel_yaw =
tf::getYaw(robot_vel.getRotation());
315 cmd_vel.linear.x = 0;
316 cmd_vel.linear.y = 0;
319 double v_theta_samp = ang_diff > 0.0 ? std::min(
max_vel_th_,
327 v_theta_samp =
sign(v_theta_samp) * std::min(std::max(fabs(v_theta_samp), min_acc_vel), max_acc_vel);
332 v_theta_samp =
sign(v_theta_samp) * std::min(max_speed_to_stop, fabs(v_theta_samp));
335 v_theta_samp = v_theta_samp > 0.0
340 bool valid_cmd =
tc_->
checkTrajectory(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw,
341 robot_vel.getOrigin().getX(), robot_vel.getOrigin().getY(), vel_yaw, 0.0, 0.0, v_theta_samp);
343 ROS_DEBUG(
"Moving to desired goal orientation, th cmd: %.2f, valid_cmd: %d", v_theta_samp, valid_cmd);
346 cmd_vel.angular.z = v_theta_samp;
350 cmd_vel.angular.z = 0.0;
357 ROS_ERROR(
"This planner has not been initialized, please call initialize() before using this planner");
374 ROS_ERROR(
"This planner has not been initialized, please call initialize() before using this planner");
378 std::vector<geometry_msgs::PoseStamped> local_plan;
384 std::vector<geometry_msgs::PoseStamped> transformed_plan;
387 ROS_WARN(
"Could not transform the global plan to the frame of the controller");
408 if(transformed_plan.empty())
414 double goal_x = goal_point.getOrigin().getX();
415 double goal_y = goal_point.getOrigin().getY();
417 double yaw =
tf::getYaw(goal_point.getRotation());
419 double goal_th = yaw;
434 cmd_vel.linear.x = 0.0;
435 cmd_vel.linear.y = 0.0;
436 cmd_vel.angular.z = 0.0;
448 nav_msgs::Odometry base_odom;
461 if(!
rotateToGoal(global_pose, robot_vel, goal_th, cmd_vel)) {
490 cmd_vel.linear.x = drive_cmds.getOrigin().getX();
491 cmd_vel.linear.y = drive_cmds.getOrigin().getY();
492 cmd_vel.angular.z =
tf::getYaw(drive_cmds.getRotation());
495 if (path.
cost_ < 0) {
497 "The rollout planner failed to find a valid plan. This means that the footprint of the robot was in collision for all simulated trajectories.");
504 ROS_DEBUG_NAMED(
"trajectory_planner_ros",
"A valid velocity command of (%.2f, %.2f, %.2f) was found for this cycle.",
505 cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z);
509 double p_x, p_y, p_th;
517 geometry_msgs::PoseStamped pose;
519 local_plan.push_back(pose);
534 std::vector<geometry_msgs::PoseStamped> plan;
535 geometry_msgs::PoseStamped pose_msg;
537 plan.push_back(pose_msg);
542 nav_msgs::Odometry base_odom;
544 boost::recursive_mutex::scoped_lock lock(
odom_lock_);
549 base_odom.twist.twist.linear.x,
550 base_odom.twist.twist.linear.y,
551 base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
554 ROS_WARN(
"Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
566 std::vector<geometry_msgs::PoseStamped> plan;
567 geometry_msgs::PoseStamped pose_msg;
569 plan.push_back(pose_msg);
574 nav_msgs::Odometry base_odom;
576 boost::recursive_mutex::scoped_lock lock(
odom_lock_);
581 base_odom.twist.twist.linear.x,
582 base_odom.twist.twist.linear.y,
583 base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
586 ROS_WARN(
"Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
592 ROS_ERROR(
"This planner has not been initialized, please call initialize() before using this planner");
Computes control velocities for a robot given a costmap, a plan, and the robot's position in the worl...
void initialize(std::string name, tf::TransformListener *tf, costmap_2d::Costmap2DROS *costmap_ros)
Constructs the ros wrapper.
nav_msgs::Odometry base_odom_
Used to get the velocity of the robot.
bool setPlan(const std::vector< geometry_msgs::PoseStamped > &orig_global_plan)
Set the plan that the controller is following.
std::string robot_base_frame_
Used as the base frame id of the robot.
std::vector< double > loadYVels(ros::NodeHandle node)
bool getCellCosts(int cx, int cy, float &path_cost, float &goal_cost, float &occ_cost, float &total_cost)
Compute the components and total cost for a map grid cell.
void getRobotVel(tf::Stamped< tf::Pose > &robot_vel)
double scoreTrajectory(double x, double y, double theta, double vx, double vy, double vtheta, double vx_samp, double vy_samp, double vtheta_samp)
Generate and score a single trajectory.
bool isGoalReached()
Check if the goal pose has been achieved.
std::vector< geometry_msgs::Point > footprint_spec_
bool getRobotPose(tf::Stamped< tf::Pose > &global_pose) const
double max_sensor_range_
Keep track of the effective maximum range of our sensors.
void publishCostCloud(const costmap_2d::Costmap2D *costmap_p_)
Build and publish a PointCloud if the publish_cost_grid_pc parameter was true. Only include points fo...
bool computeVelocityCommands(geometry_msgs::Twist &cmd_vel)
Given the current position, orientation, and velocity of the robot, compute velocity commands to send...
double getGoalPositionDistance(const tf::Stamped< tf::Pose > &global_pose, double goal_x, double goal_y)
return squared distance to check if the goal position has been achieved
bool rotateToGoal(const tf::Stamped< tf::Pose > &global_pose, const tf::Stamped< tf::Pose > &robot_vel, double goal_th, geometry_msgs::Twist &cmd_vel)
Once a goal position is reached... rotate to the goal orientation.
ros::Publisher g_plan_pub_
static void poseStampedTFToMsg(const Stamped< Pose > &bt, geometry_msgs::PoseStamped &msg)
static double getYaw(const Quaternion &bt_q)
std::string getGlobalFrameID()
PLUGINLIB_EXPORT_CLASS(BAGReader, nodelet::Nodelet)
void getOdom(nav_msgs::Odometry &base_odom)
boost::recursive_mutex odom_lock_
void prunePlan(const tf::Stamped< tf::Pose > &global_pose, std::vector< geometry_msgs::PoseStamped > &plan, std::vector< geometry_msgs::PoseStamped > &global_plan)
Trim off parts of the global plan that are far enough behind the robot.
bool checkTrajectory(double x, double y, double theta, double vx, double vy, double vtheta, double vx_samp, double vy_samp, double vtheta_samp)
Generate and score a single trajectory.
dynamic_reconfigure::Server< BaseLocalPlannerConfig > * dsrv_
void getPoint(unsigned int index, double &x, double &y, double &th) const
Get a point within the trajectory.
void initialize(const std::string &name, std::string frame, boost::function< bool(int cx, int cy, float &path_cost, float &goal_cost, float &occ_cost, float &total_cost)> cost_function)
Initializes the MapGridVisualizer.
double cost_
The cost/score of the trajectory.
costmap_2d::Costmap2D * costmap_
The costmap the controller will use.
double rot_stopped_velocity_
bool latch_xy_goal_tolerance_
bool stopped(const nav_msgs::Odometry &base_odom, const double &rot_stopped_velocity, const double &trans_stopped_velocity)
Check whether the robot is stopped or not.
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
double yaw_goal_tolerance_
std::string global_frame_
The frame in which the controller will run.
#define ROS_DEBUG_NAMED(name,...)
double xy_goal_tolerance_
static Quaternion createQuaternionFromYaw(double yaw)
bool transformGlobalPlan(const tf::TransformListener &tf, const std::vector< geometry_msgs::PoseStamped > &global_plan, const tf::Stamped< tf::Pose > &global_robot_pose, const costmap_2d::Costmap2D &costmap, const std::string &global_frame, std::vector< geometry_msgs::PoseStamped > &transformed_plan)
Transforms the global plan of the robot from the planner frame to the frame of the costmap...
bool searchParam(const std::string &key, std::string &result) const
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
double scoreTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map=true)
Generate and score a single trajectory.
#define ROS_ASSERT_MSG(cond,...)
MapGridVisualizer map_viz_
The map grid visualizer for outputting the potential field generated by the cost function.
std::string getBaseFrameID()
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
TrajectoryPlanner * tc_
The trajectory controller.
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
unsigned int getPointsSize() const
Return the number of points in the trajectory.
double trans_stopped_velocity_
void updatePlan(const std::vector< geometry_msgs::PoseStamped > &new_plan, bool compute_dists=false)
Update the plan that the controller is following.
void publishPlan(const std::vector< geometry_msgs::PoseStamped > &path, const ros::Publisher &pub)
Publish a plan for visualization purposes.
bool stopWithAccLimits(const tf::Stamped< tf::Pose > &global_pose, const tf::Stamped< tf::Pose > &robot_vel, geometry_msgs::Twist &cmd_vel)
Stop the robot taking into account acceleration limits.
bool checkTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map=true)
Generate and score a single trajectory.
base_local_planner::OdometryHelperRos odom_helper_
bool getParam(const std::string &key, std::string &s) const
void reconfigureCB(BaseLocalPlannerConfig &config, uint32_t level)
Callback to update the local planner's parameters based on dynamic reconfigure.
WorldModel * world_model_
The world model that the controller will use.
Trajectory findBestPath(tf::Stamped< tf::Pose > global_pose, tf::Stamped< tf::Pose > global_vel, tf::Stamped< tf::Pose > &drive_velocities)
Given the current position, orientation, and velocity of the robot, return a trajectory to follow...
std::vector< geometry_msgs::PoseStamped > global_plan_
static void poseStampedMsgToTF(const geometry_msgs::PoseStamped &msg, Stamped< Pose > &bt)
TrajectoryPlannerROS()
Default constructor for the ros wrapper.
tf::TransformListener * tf_
Used for transforming point clouds.
A class that implements the WorldModel interface to provide grid based collision checks for the traje...
double getResolution() const
bool hasParam(const std::string &key) const
~TrajectoryPlannerROS()
Destructor for the wrapper.
std::vector< geometry_msgs::Point > getRobotFootprint()
A ROS wrapper for the trajectory controller that queries the param server to construct a controller...
costmap_2d::Costmap2DROS * costmap_ros_
The ROS wrapper for the costmap the controller will use.
ros::Publisher l_plan_pub_
def shortest_angular_distance(from_angle, to_angle)
double getGoalOrientationAngleDifference(const tf::Stamped< tf::Pose > &global_pose, double goal_th)
return angle difference to goal to check if the goal orientation has been achieved ...
Holds a trajectory generated by considering an x, y, and theta velocity.
double min_in_place_vel_th_