ftc_planner.cpp
Go to the documentation of this file.
1 
18 #include <ros/ros.h>
19 
21 
23 
25 
26 namespace ftc_local_planner
27 {
28 
30  {
31  }
32 
33  void FTCPlanner::initialize(std::string name, tf2_ros::Buffer* tf, costmap_2d::Costmap2DROS* costmap_ros)
34  {
35  ros::NodeHandle private_nh("~/" + name);
36  local_plan_publisher_ = private_nh.advertise<nav_msgs::Path>("local_plan", 1);
37  costmap_ros_ = costmap_ros;
38  tf_ = tf;
39  first_setPlan_ = true;
40  rotate_to_global_plan_ = false;
41  goal_reached_ = false;
42  stand_at_goal_ = false;
46 
47  //Parameter for dynamic reconfigure
48  dsrv_ = new dynamic_reconfigure::Server<FTCPlannerConfig>(private_nh);
49  dynamic_reconfigure::Server<FTCPlannerConfig>::CallbackType cb = boost::bind(&FTCPlanner::reconfigureCB, this, _1, _2);
50  dsrv_->setCallback(cb);
51 
52  joinCostmap_ = new JoinCostmap();
53 
54  ROS_INFO("FTCPlanner: Version 2 Init.");
55  }
56 
57  void FTCPlanner::reconfigureCB(FTCPlannerConfig &config, uint32_t level)
58  {
59  if (config.restore_defaults)
60  {
61  config = default_config_;
62  config.restore_defaults = false;
63  }
64  config_ = config;
65  }
66 
67  bool FTCPlanner::setPlan(const std::vector<geometry_msgs::PoseStamped>& plan)
68  {
69  global_plan_ = plan;
70 
71  //First start of the local plan. First global plan.
72  bool first_use = false;
73  if(first_setPlan_)
74  {
75  if(config_.join_obstacle){
76  //init joincostmap with local an global costmap.
77  joinCostmap_->initialize(costmap_ros_, global_costmap_ros_);
78  }
79 
80  first_setPlan_ = false;
82  first_use = true;
83  }
84 
86  //Have the new global plan an new goal, reset. Else dont reset.
87  if(std::abs(std::abs(old_goal_pose_.getOrigin().getX())-std::abs(goal_pose_.getOrigin().getX())) <= config_.position_accuracy &&
88  std::abs(std::abs(old_goal_pose_.getOrigin().getY())-std::abs(goal_pose_.getOrigin().getY())) <= config_.position_accuracy && !first_use
89  && std::abs(angles::shortest_angular_distance(tf::getYaw(old_goal_pose_.getRotation()), tf::getYaw(goal_pose_.getRotation()))) <= config_.rotation_accuracy)
90  {
91  ROS_DEBUG("FTCPlanner: Old Goal == new Goal.");
92  }
93  else
94  {
95  //Rotate to first global plan point.
97  goal_reached_ = false;
98  stand_at_goal_ = false;
99  ROS_INFO("FTCPlanner: New Goal. Start new routine.");
100  }
101 
103 
104  return true;
105  }
106 
107  bool FTCPlanner::computeVelocityCommands(geometry_msgs::Twist& cmd_vel)
108  {
109 
110  ros::Time begin = ros::Time::now();
111 
112  tf::Stamped<tf::Pose> current_pose;
113  geometry_msgs::PoseStamped msg;
115 
116  current_pose.setData(tf::Transform(tf::Quaternion(msg.pose.orientation.x, msg.pose.orientation.y, msg.pose.orientation.z, msg.pose.orientation.w),
117  tf::Vector3(msg.pose.position.x, msg.pose.position.y, msg.pose.position.z)));
118 
119 
120  //Join the actual global an local costmap in the global costmap.
121  if(config_.join_obstacle){
123  }
124  int max_point = 0;
125  //First part of the routine. Rotatio to the first global plan orientation.
127  {
128  double angle_to_global_plan = calculateGlobalPlanAngle(current_pose, global_plan_, checkMaxDistance(current_pose));
129  rotate_to_global_plan_ = rotateToOrientation(angle_to_global_plan, cmd_vel, 0.1);
130  }
131  //Second part of the routine. Drive alonge the global plan.
132  else
133  {
134 
135  double distance = sqrt(pow((goal_pose_.getOrigin().getX()-current_pose.getOrigin().getX()),2)+pow((goal_pose_.getOrigin().getY()-current_pose.getOrigin().getY()),2));
136 
137  //Check if robot near enough to global goal.
138  if(distance > config_.position_accuracy && !stand_at_goal_)
139  {
140 
141  if(fabs(calculateGlobalPlanAngle(current_pose, global_plan_, checkMaxDistance(current_pose)) > 1.2))
142  {
143  ROS_INFO("FTCPlanner: Excessive deviation from global plan orientation. Start routine new.");
144  rotate_to_global_plan_ = true;
145  }
146 
147  max_point = driveToward(current_pose, cmd_vel);
148 
149  if(!checkCollision(max_point))
150  {
151  return false;
152  }
153  }
154  //Third part of the routine. Rotate at goal to goal orientation.
155  else
156  {
157  if(!stand_at_goal_)
158  {
159  ROS_INFO("FTCPlanner: Stand at goal. Rotate to goal orientation.");
160  }
161  stand_at_goal_ = true;
162 
163 
164  //Get the goal orientation.
165  double angle_to_global_plan = angles::shortest_angular_distance(tf::getYaw(current_pose.getRotation()), tf::getYaw(goal_pose_.getRotation()));
166  //Rotate until goalorientation is reached.
167  if(!rotateToOrientation(angle_to_global_plan, cmd_vel, config_.rotation_accuracy))
168  {
169  goal_reached_ = true;
170  }
171  cmd_vel.linear.x = 0;
172  cmd_vel.linear.y = 0;
173  }
174  }
175 
176  publishPlan(max_point);
177 
178  ros::Time end = ros::Time::now();
179  ros::Duration duration = end - begin;
180  ROS_DEBUG("FTCPlanner: Calculation time: %f seconds", duration.toSec());
181  return true;
182  }
183 
185  {
186  int max_point = 0;
187  tf::Stamped<tf::Pose> x_pose;
188  transformed_global_plan_.clear();
189  for (unsigned int i = 0; i < global_plan_.size(); i++)
190  {
192  double distance = sqrt(pow((x_pose.getOrigin().getX()-current_pose.getOrigin().getX()),2)+pow((x_pose.getOrigin().getY()-current_pose.getOrigin().getY()),2));
193 
195  ros::Time::now(),
197  geometry_msgs::PoseStamped pose;
198  tf::poseStampedTFToMsg(p, pose);
199  transformed_global_plan_.push_back(pose);
200 
201  max_point = i-1;
202  //If distance higher than maximal moveable distance in sim_time.
203  if(distance > (config_.max_x_vel*config_.sim_time))
204  {
205  break;
206  }
207  }
208  if(max_point < 0)
209  {
210  max_point = 0;
211  }
212  return max_point;
213  }
214 
215  int FTCPlanner::checkMaxAngle(int points, tf::Stamped<tf::Pose> current_pose)
216  {
217  int max_point = points;
218  double angle = 0;
219  for(int i = max_point; i >= 0; i--)
220  {
221  angle = calculateGlobalPlanAngle(current_pose, global_plan_, i);
222 
223  max_point = i;
224  //check if the angle is moveable
225  if(fabs(angle) < config_.max_rotation_vel*config_.sim_time)
226  {
227  break;
228  }
229  }
230  return max_point;
231  }
232 
233  double FTCPlanner::calculateGlobalPlanAngle(tf::Stamped<tf::Pose> current_pose, const std::vector<geometry_msgs::PoseStamped>& plan, int point)
234  {
235  if(point >= (int)plan.size())
236  {
237  point = plan.size()-1;
238  }
239  double angle = 0;
240  double current_th = tf::getYaw(current_pose.getRotation());
241  for(int i = 0; i <= point; i++)
242  {
243  geometry_msgs::PoseStamped x_pose;
244  x_pose=transformed_global_plan_.at(i);
245 
246  //Calculate the angles between robotpose and global plan point pose
247  double angle_to_goal = atan2(x_pose.pose.position.y - current_pose.getOrigin().getY(),
248  x_pose.pose.position.x - current_pose.getOrigin().getX());
249  angle += angle_to_goal;
250  }
251 
252  //average
253  angle = angle/(point+1);
254 
255  return angles::shortest_angular_distance(current_th, angle);
256  }
257 
258  bool FTCPlanner::rotateToOrientation(double angle, geometry_msgs::Twist& cmd_vel, double accuracy)
259  {
260 
261  if((cmd_vel_linear_x_ - 0.1) >= 0){
262  cmd_vel.linear.x = cmd_vel_linear_x_ - 0.1;
264  }
265  if(fabs(angle) > accuracy)
266  {
267  //Slow down
268  if(config_.max_rotation_vel >= fabs(angle) * (config_.acceleration_z+config_.slow_down_factor))
269  {
270  ROS_DEBUG("FTCPlanner: Slow down.");
271  if(angle < 0)
272  {
273  if(cmd_vel_angular_z_rotate_ >= -config_.min_rotation_vel)
274  {
275  cmd_vel_angular_z_rotate_ = - config_.min_rotation_vel;
276  cmd_vel.angular.z = cmd_vel_angular_z_rotate_;
277 
278  }
279  else
280  {
281  cmd_vel_angular_z_rotate_ = cmd_vel_angular_z_rotate_ + config_.acceleration_z/config_.local_planner_frequence;
282  cmd_vel.angular.z = cmd_vel_angular_z_rotate_;
283  }
284  }
285  if(angle > 0)
286  {
287  if(cmd_vel_angular_z_rotate_ <= config_.min_rotation_vel)
288  {
289  cmd_vel_angular_z_rotate_ = config_.min_rotation_vel;
290  cmd_vel.angular.z = cmd_vel_angular_z_rotate_;
291 
292  }
293  else
294  {
295  cmd_vel_angular_z_rotate_ = cmd_vel_angular_z_rotate_ - config_.acceleration_z/config_.local_planner_frequence;
296  cmd_vel.angular.z = cmd_vel_angular_z_rotate_;
297  }
298  }
299  }
300  else
301  {
302  //Speed up
303  if(fabs(cmd_vel_angular_z_rotate_) < config_.max_rotation_vel)
304  {
305  ROS_DEBUG("FTCPlanner: Speeding up");
306  if(angle < 0)
307  {
308  cmd_vel_angular_z_rotate_ = cmd_vel_angular_z_rotate_ - config_.acceleration_z/config_.local_planner_frequence;
309 
310  if(fabs(cmd_vel_angular_z_rotate_) > config_.max_rotation_vel)
311  {
312  cmd_vel_angular_z_rotate_ = - config_.max_rotation_vel;
313  }
314  cmd_vel.angular.z = cmd_vel_angular_z_rotate_;
315  }
316  if(angle > 0)
317  {
318  cmd_vel_angular_z_rotate_ = cmd_vel_angular_z_rotate_ + config_.acceleration_z/config_.local_planner_frequence;
319 
320  if(fabs(cmd_vel_angular_z_rotate_) > config_.max_rotation_vel)
321  {
322  cmd_vel_angular_z_rotate_ = config_.max_rotation_vel;
323  }
324 
325  cmd_vel.angular.z = cmd_vel_angular_z_rotate_;
326  }
327  }
328  else
329  {
330  cmd_vel.angular.z = cmd_vel_angular_z_rotate_;
331  }
332  }
333  ROS_DEBUG("FTCPlanner: cmd_vel.z: %f, angle: %f", cmd_vel.angular.z, angle);
334  return true;
335  }
336  else
337  {
339  cmd_vel.angular.z = 0;
340  return false;
341  }
342  }
343 
344  int FTCPlanner::driveToward(tf::Stamped<tf::Pose> current_pose, geometry_msgs::Twist& cmd_vel)
345  {
346  double distance = 0;
347  double angle = 0;
348  int max_point = 0;
349 
350  //Search for max achievable point on global plan.
351  max_point = checkMaxDistance(current_pose);
352  max_point = checkMaxAngle(max_point, current_pose);
353 
354 
355  double cmd_vel_linear_x_old = cmd_vel_linear_x_;
356  double cmd_vel_angular_z_old = cmd_vel_angular_z_;
357 
358  geometry_msgs::PoseStamped x_pose;
359  x_pose = transformed_global_plan_.at(max_point);
360 
361  distance = sqrt(pow((x_pose.pose.position.x-current_pose.getOrigin().getX()),2)+pow((x_pose.pose.position.y-current_pose.getOrigin().getY()),2));
362  angle = calculateGlobalPlanAngle(current_pose, global_plan_, max_point);
363 
364  //check if max velocity is exceeded
365  if((distance/config_.sim_time) > config_.max_x_vel)
366  {
367  cmd_vel_linear_x_ = config_.max_x_vel;
368  }
369  else
370  {
371  cmd_vel_linear_x_ = (distance/config_.sim_time);
372  }
373 
374  //check if max rotation velocity is exceeded
375  if(fabs(angle/config_.sim_time)>config_.max_rotation_vel)
376  {
377  cmd_vel_angular_z_ = config_.max_rotation_vel;
378  }
379  else
380  {
381  cmd_vel_angular_z_ = (angle/config_.sim_time);
382  }
383 
384  //Calculate new velocity with max acceleration
385  if(cmd_vel_linear_x_ > cmd_vel_linear_x_old+config_.acceleration_x/config_.local_planner_frequence)
386  {
387  cmd_vel_linear_x_ = cmd_vel_linear_x_old+config_.acceleration_x/config_.local_planner_frequence;
388  }
389  else
390  {
391  if(cmd_vel_linear_x_ < cmd_vel_linear_x_old-config_.acceleration_x/config_.local_planner_frequence)
392  {
393  cmd_vel_linear_x_ = cmd_vel_linear_x_old-config_.acceleration_x/config_.local_planner_frequence;
394  }
395  else
396  {
397  cmd_vel_linear_x_ = cmd_vel_linear_x_old;
398  }
399  }
400 
401  //Calculate new velocity with max acceleration
402  if(fabs(cmd_vel_angular_z_) > fabs(cmd_vel_angular_z_old)+fabs(config_.acceleration_z/config_.local_planner_frequence))
403  {
404  if(cmd_vel_angular_z_ < 0)
405  {
406  cmd_vel_angular_z_ = cmd_vel_angular_z_old-config_.acceleration_z/config_.local_planner_frequence;
407  }
408  else
409  {
410  cmd_vel_angular_z_ = cmd_vel_angular_z_old+config_.acceleration_z/config_.local_planner_frequence;
411  }
412  }
413 
414  if(cmd_vel_angular_z_ < 0 && cmd_vel_angular_z_old > 0)
415  {
416  if( fabs(cmd_vel_angular_z_ - cmd_vel_angular_z_old) > fabs(config_.acceleration_z/config_.local_planner_frequence))
417  {
418  cmd_vel_angular_z_ = cmd_vel_angular_z_old - config_.acceleration_z/config_.local_planner_frequence;
419  }
420  }
421 
422  if(cmd_vel_angular_z_ > 0 && cmd_vel_angular_z_old < 0)
423  {
424  if( fabs(cmd_vel_angular_z_ - cmd_vel_angular_z_old) > fabs(config_.acceleration_z/config_.local_planner_frequence))
425  {
426  cmd_vel_angular_z_ = cmd_vel_angular_z_old + config_.acceleration_z/config_.local_planner_frequence;
427  }
428  }
429 
430  //Check at last if velocity is to high.
431  if(cmd_vel_angular_z_ > config_.max_rotation_vel)
432  {
433  cmd_vel_angular_z_ = config_.max_rotation_vel;
434  }
435  if(cmd_vel_angular_z_ < -config_.max_rotation_vel)
436  {
437  cmd_vel_angular_z_ = (- config_.max_rotation_vel);
438  }
439  if(cmd_vel_linear_x_ > config_.max_x_vel)
440  {
441  cmd_vel_linear_x_ = config_.max_x_vel;
442  }
443  //Push velocity to cmd_vel for driving.
444  cmd_vel.linear.x = cmd_vel_linear_x_;
445  cmd_vel.angular.z = cmd_vel_angular_z_;
447  ROS_DEBUG("FTCPlanner: max_point: %d, distance: %f, x_vel: %f, rot_vel: %f, angle: %f", max_point, distance, cmd_vel.linear.x, cmd_vel.angular.z, angle);
448 
449  return max_point;
450  }
451 
452 
454  {
455  if(goal_reached_)
456  {
457  ROS_INFO("FTCPlanner: Goal reached.");
458  }
459  return goal_reached_;
460  }
461 
462  bool FTCPlanner::checkCollision(int max_points)
463  {
464  //maximal costs
465  unsigned char previous_cost = 255;
466 
467  for (int i = 0; i <= max_points; i++)
468  {
469  geometry_msgs::PoseStamped x_pose;
470  x_pose = transformed_global_plan_.at(i);
471 
472  unsigned int x;
473  unsigned int y;
474  costmap_ros_->getCostmap()->worldToMap(x_pose.pose.position.x, x_pose.pose.position.y, x, y);
475  unsigned char costs = costmap_ros_->getCostmap()->getCost(x, y);
476  //Near at obstacel
477  if(costs > 0)
478  {
480  {
481  ROS_INFO("FTCPlanner: Obstacel detected. Start routine new.");
482  }
483  rotate_to_global_plan_ = true;
484 
485  //Possible collision
486  if(costs > 127 && costs > previous_cost)
487  {
488  ROS_WARN("FTCPlanner: Possible collision. Stop local planner.");
489  return false;
490  }
491  }
492  previous_cost = costs;
493  }
494  return true;
495  }
496 
497  void FTCPlanner::publishPlan(int max_point)
498  {
499  std::vector<geometry_msgs::PoseStamped> path;
501 
502  //given an empty path we won't do anything
503  if(path.empty())
504  return;
505 
506  //create a path message
507  nav_msgs::Path gui_path;
508  gui_path.poses.resize(path.size());
509  gui_path.header.frame_id = path[0].header.frame_id;
510  gui_path.header.stamp = path[0].header.stamp;
511 
512  // Extract the plan in world co-ordinates, we assume the path is all in the same frame
513  for(unsigned int i=0; i < path.size(); i++)
514  {
515  gui_path.poses[i] = path[i];
516  }
517 
518  local_plan_publisher_.publish(gui_path);
519  }
520 
522  {
523  }
524 }
bool setPlan(const std::vector< geometry_msgs::PoseStamped > &plan)
Set the plan that the local planner is following.
Definition: ftc_planner.cpp:67
int checkMaxAngle(int points, tf::Stamped< tf::Pose > current_pose)
Goes backward along global plan the max angle whith sim_time and max_rotation_vel allow...
tf::Stamped< tf::Pose > goal_pose_
Definition: ftc_planner.h:148
void reconfigureCB(FTCPlannerConfig &config, uint32_t level)
Reconfigure config_.
Definition: ftc_planner.cpp:57
int checkMaxDistance(tf::Stamped< tf::Pose > current_pose)
Goes along global plan the max distance whith sim_time and max_x_vel allow.
void setData(const T &input)
tf::Stamped< tf::Pose > old_goal_pose_
Definition: ftc_planner.h:150
static void poseStampedTFToMsg(const Stamped< Pose > &bt, geometry_msgs::PoseStamped &msg)
static double getYaw(const Quaternion &bt_q)
void joinMaps()
joinMaps join the local costmap in the global costmap.
std::string getGlobalFrameID()
std::vector< geometry_msgs::PoseStamped > transformed_global_plan_
Definition: ftc_planner.h:144
std::vector< geometry_msgs::PoseStamped > global_plan_
Definition: ftc_planner.h:142
bool rotateToOrientation(double angle, geometry_msgs::Twist &cmd_vel, double accuracy)
Rotation at place.
#define ROS_WARN(...)
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
bool isGoalReached()
Check if the goal pose has been achieved by the local planner.
void initialize(costmap_2d::Costmap2DROS *local_costmap_ros, costmap_2d::Costmap2DROS *global_costmap_ros)
initialize the two costmaps and check if resolution global costmap > resolution local costmap...
dynamic_reconfigure::Server< FTCPlannerConfig > * dsrv_
Definition: ftc_planner.h:154
bool checkCollision(int max_points)
Check if the considerd points are in local collision.
void publish(const boost::shared_ptr< M > &message) const
double distance(double x0, double y0, double x1, double y1)
ros::Publisher local_plan_publisher_
Definition: ftc_planner.h:164
double calculateGlobalPlanAngle(tf::Stamped< tf::Pose > current_pose, const std::vector< geometry_msgs::PoseStamped > &plan, int points)
Calculate the orientation of the global plan.
#define ROS_INFO(...)
void publishPlan(int max_point)
Publish the global plan for visulatation.
bool getRobotPose(geometry_msgs::PoseStamped &global_pose) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool computeVelocityCommands(geometry_msgs::Twist &cmd_vel)
Given the current position, orientation, and velocity of the robot, compute velocity commands to send...
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
ftc_local_planner::FTCPlannerConfig config_
Definition: ftc_planner.h:158
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
void initialize(std::string name, tf2_ros::Buffer *tf, costmap_2d::Costmap2DROS *costmap_ros)
Constructs the local planner.
Definition: ftc_planner.cpp:33
bool worldToMap(double wx, double wy, unsigned int &mx, unsigned int &my) const
ftc_local_planner::FTCPlannerConfig default_config_
Definition: ftc_planner.h:156
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
static Time now()
int driveToward(tf::Stamped< tf::Pose > current_pose, geometry_msgs::Twist &cmd_vel)
Drive along the global plan and calculate the velocity.
Costmap2D * getCostmap()
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
bool getXPose(const tf2_ros::Buffer &tf, const std::vector< geometry_msgs::PoseStamped > &global_plan, const std::string &global_frame, tf::Stamped< tf::Pose > &goal_pose, int plan_point)
Returns X pose in plan.
def shortest_angular_distance(from_angle, to_angle)
unsigned char getCost(unsigned int mx, unsigned int my) const
#define ROS_DEBUG(...)
costmap_2d::Costmap2DROS * costmap_ros_
Definition: ftc_planner.h:140


asr_ftc_local_planner
Author(s): Marek Felix
autogenerated on Mon Feb 28 2022 21:45:41