SMACC
Loading...
Searching...
No Matches
forward_local_planner.cpp
Go to the documentation of this file.
1/*****************************************************************************************************************
2 * ReelRobotix Inc. - Software License Agreement Copyright (c) 2018
3 * Authors: Pablo Inigo Blasco, Brett Aldrich
4 *
5 ******************************************************************************************************************/
6#include <angles/angles.h>
7#include <pluginlib/class_list_macros.h>
9#include <visualization_msgs/MarkerArray.h>
10#include <boost/intrusive_ptr.hpp>
11#include <angles/angles.h>
12
13#include <base_local_planner/simple_trajectory_generator.h>
14
15//register this planner as a BaseLocalPlanner plugin
17
18namespace cl_move_base_z
19{
20namespace forward_local_planner
21{
28{
29}
30
37{
38}
39
41{
42 k_rho_ = 1.0;
43 k_alpha_ = -0.4;
44 k_betta_ = -1.0; // set to zero means that orientation is not important
45 //k_betta_ = 1.0;
46 //betta_offset_=0;
47
48 goalReached_ = false;
49 carrot_distance_ = 0.4;
50
51 ros::NodeHandle private_nh("~");
52
54
55 ros::NodeHandle nh("~/ForwardLocalPlanner");
56
57 nh.param("k_rho", k_rho_, k_rho_);
58 nh.param("k_alpha", k_alpha_, k_alpha_);
59 nh.param("k_betta", k_betta_, k_betta_);
60 nh.param("carrot_distance", carrot_distance_, carrot_distance_);
61
62 nh.param("yaw_goal_tolerance", yaw_goal_tolerance_, 0.05);
63 nh.param("xy_goal_tolerance", xy_goal_tolerance_, 0.10);
64 nh.param("max_linear_x_speed", max_linear_x_speed_, 1.0);
65 nh.param("max_angular_z_speed", max_angular_z_speed_, 2.0);
66
67 ROS_INFO("[ForwardLocalPlanner] max linear speed: %lf, max angular speed: %lf, k_rho: %lf, carrot_distance: %lf, ", max_linear_x_speed_, max_angular_z_speed_, k_rho_, carrot_distance_);
68 goalMarkerPublisher_ = nh.advertise<visualization_msgs::MarkerArray>("goal_marker", 1);
69
70 waiting_ = false;
71 waitingTimeout_ = ros::Duration(10);
72 ROS_INFO("[ForwardLocalPlanner] initialized");
73}
74
75void ForwardLocalPlanner::initialize(std::string name, tf2_ros::Buffer *tf, costmap_2d::Costmap2DROS *costmap_ros)
76{
77 costmapRos_ = costmap_ros;
78 this->initialize();
79}
80
81void ForwardLocalPlanner::generateTrajectory(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, float maxdist, float maxanglediff, float maxtime, float dt, std::vector<Eigen::Vector3f> &outtraj)
82{
83 //simulate the trajectory and check for collisions, updating costs along the way
84 bool end = false;
85 float time = 0;
86 Eigen::Vector3f currentpos = pos;
87 int i = 0;
88 while (!end)
89 {
90 //add the point to the trajectory so we can draw it later if we want
91 //traj.addPoint(pos[0], pos[1], pos[2]);
92
93 // if (continued_acceleration_) {
94 // //calculate velocities
95 // loop_vel = computeNewVelocities(sample_target_vel, loop_vel, limits_->getAccLimits(), dt);
96 // //ROS_WARN_NAMED("Generator", "Flag: %d, Loop_Vel %f, %f, %f", continued_acceleration_, loop_vel[0], loop_vel[1], loop_vel[2]);
97 // }
98
99 auto loop_vel = vel;
100 //update the position of the robot using the velocities passed in
101 auto newpos = computeNewPositions(currentpos, loop_vel, dt);
102
103 auto dx = newpos[0] - currentpos[0];
104 auto dy = newpos[1] - currentpos[1];
105 float dist, angledist;
106
107 //ROS_INFO("traj point %d", i);
108 dist = sqrt(dx * dx + dy * dy);
109 if (dist > maxdist)
110 {
111 end = true;
112 //ROS_INFO("dist break: %f", dist);
113 }
114 else
115 {
116 // ouble from, double to
117 angledist = fabs(angles::shortest_angular_distance(currentpos[2], newpos[2]));
118 if (angledist > maxanglediff)
119 {
120 end = true;
121 //ROS_INFO("angle dist break: %f", angledist);
122 }
123 else
124 {
125 outtraj.push_back(newpos);
126
127 time += dt;
128 if (time > maxtime)
129 {
130 end = true;
131 //ROS_INFO("time break: %f", time);
132 }
133
134 //ROS_INFO("dist: %f, angledist: %f, time: %f", dist, angledist, time);
135 }
136 }
137
138 currentpos = newpos;
139 i++;
140 } // end for simulation steps
141}
142
143Eigen::Vector3f ForwardLocalPlanner::computeNewPositions(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, double dt)
144{
145 Eigen::Vector3f new_pos = Eigen::Vector3f::Zero();
146 new_pos[0] = pos[0] + (vel[0] * cos(pos[2]) + vel[1] * cos(M_PI_2 + pos[2])) * dt;
147 new_pos[1] = pos[1] + (vel[0] * sin(pos[2]) + vel[1] * sin(M_PI_2 + pos[2])) * dt;
148 new_pos[2] = pos[2] + vel[2] * dt;
149 return new_pos;
150}
151
157void ForwardLocalPlanner::initialize(std::string name, tf::TransformListener *tf, costmap_2d::Costmap2DROS *costmap_ros)
158{
159 costmapRos_ = costmap_ros;
160 this->initialize();
161}
162
168void ForwardLocalPlanner::publishGoalMarker(double x, double y, double phi)
169{
170 visualization_msgs::Marker marker;
171
172 marker.header.frame_id = this->costmapRos_->getGlobalFrameID();
173 marker.header.stamp = ros::Time::now();
174 marker.ns = "my_namespace2";
175 marker.id = 0;
176 marker.type = visualization_msgs::Marker::ARROW;
177 marker.action = visualization_msgs::Marker::ADD;
178 marker.pose.orientation.w = 1;
179
180 marker.scale.x = 0.1;
181 marker.scale.y = 0.3;
182 marker.scale.z = 0.1;
183 marker.color.a = 1.0;
184 marker.color.r = 0;
185 marker.color.g = 0;
186 marker.color.b = 1.0;
187
188 geometry_msgs::Point start, end;
189 start.x = x;
190 start.y = y;
191
192 end.x = x + 0.5 * cos(phi);
193 end.y = y + 0.5 * sin(phi);
194
195 marker.points.push_back(start);
196 marker.points.push_back(end);
197
198 visualization_msgs::MarkerArray ma;
199 ma.markers.push_back(marker);
200
201 this->goalMarkerPublisher_.publish(ma);
202}
203
204// MELODIC
205#if ROS_VERSION_MINIMUM(1, 13, 0)
206tf::Stamped<tf::Pose> optionalRobotPose(costmap_2d::Costmap2DROS *costmapRos)
207{
208 geometry_msgs::PoseStamped paux;
209 costmapRos->getRobotPose(paux);
210 tf::Stamped<tf::Pose> tfpose;
211 tf::poseStampedMsgToTF(paux, tfpose);
212 return tfpose;
213}
214#else
215// INDIGO AND PREVIOUS
216tf::Stamped<tf::Pose> optionalRobotPose(costmap_2d::Costmap2DROS *costmapRos)
217{
218 tf::Stamped<tf::Pose> tfpose;
219 costmapRos->getRobotPose(tfpose);
220 return tfpose;
221}
222#endif
223
224void clamp(geometry_msgs::Twist &cmd_vel, double max_linear_x_speed_, double max_angular_z_speed_)
225{
226 if (max_angular_z_speed_ == 0 || max_linear_x_speed_ == 0)
227 return;
228
229 if (cmd_vel.angular.z == 0)
230 {
231 cmd_vel.linear.x = max_linear_x_speed_;
232 }
233 else
234 {
235 double kurvature = cmd_vel.linear.x / cmd_vel.angular.z;
236
237 double linearAuthority = fabs(cmd_vel.linear.x / max_linear_x_speed_);
238 double angularAuthority = fabs(cmd_vel.angular.z / max_angular_z_speed_);
239 if (linearAuthority < angularAuthority)
240 {
241 // lets go to maximum linear speed
242 cmd_vel.linear.x = max_linear_x_speed_;
243 cmd_vel.angular.z = kurvature / max_linear_x_speed_;
244 ROS_WARN_STREAM("k=" << kurvature << "lets go to maximum linear capacity: " << cmd_vel);
245 }
246 else
247 {
248 // lets go with maximum angular speed
249 cmd_vel.angular.x = max_angular_z_speed_;
250 cmd_vel.linear.x = kurvature * max_angular_z_speed_;
251 ROS_WARN_STREAM("lets go to maximum angular capacity: " << cmd_vel);
252 }
253 }
254}
255
261bool ForwardLocalPlanner::computeVelocityCommands(geometry_msgs::Twist &cmd_vel)
262{
263 goalReached_ = false;
264 ROS_DEBUG("[ForwardLocalPlanner] ----- COMPUTE VELOCITY COMMAND LOCAL PLANNER ---");
265
266 tf::Stamped<tf::Pose> tfpose = optionalRobotPose(costmapRos_);
267
268 geometry_msgs::PoseStamped currentPose;
269 tf::poseStampedTFToMsg(tfpose,currentPose);
270 ROS_DEBUG_STREAM("[ForwardLocalPlanner] current robot pose " << currentPose);
271
272
273 bool ok = false;
274 while (!ok)
275 {
276 // iterate the point from the current position and ahead until reaching a new goal point in the path
277 while (!ok && currentPoseIndex_ < plan_.size())
278 {
279 auto &pose = plan_[currentPoseIndex_];
280 const geometry_msgs::Point &p = pose.pose.position;
281 tf::Quaternion q;
282 tf::quaternionMsgToTF(pose.pose.orientation, q);
283
284 // take error from the current position to the path point
285 double dx = p.x - tfpose.getOrigin().x();
286 double dy = p.y - tfpose.getOrigin().y();
287 double dist = sqrt(dx * dx + dy * dy);
288
289 double pangle = tf::getYaw(q);
290 double angle = tf::getYaw(tfpose.getRotation());
291 double angular_error = angles::shortest_angular_distance(pangle, angle);
292
293 if (dist >= carrot_distance_ || fabs(angular_error) > 0.1)
294 {
295 // the target pose is enough different to be defined as a target
296 ok = true;
297 ROS_DEBUG("current index: %d, carrot goal percentaje: %lf, dist: %lf, maxdist: %lf, angle_error: %lf", currentPoseIndex_, 100.0 * currentPoseIndex_ / plan_.size(), dist, carrot_distance_, angular_error);
298 }
299 else
300 {
302 }
303 }
304
305 ROS_DEBUG_STREAM("[ForwardLocalPlanner] selected carrot pose index " << currentPoseIndex_ << "/" << plan_.size());
306
307 if (currentPoseIndex_ >= plan_.size())
308 {
309 // even the latest point is quite similar, then take the last since it is the final goal
310 cmd_vel.linear.x = 0;
311 cmd_vel.angular.z = 0;
312 //ROS_INFO("End Local planner");
313 ok = true;
314 currentPoseIndex_ = plan_.size() - 1;
315 //return true;
316 }
317 }
318
319 //ROS_INFO("pose control algorithm");
320
321 const geometry_msgs::PoseStamped &finalgoalpose = plan_.back();
322 const geometry_msgs::PoseStamped &carrot_goalpose = plan_[currentPoseIndex_];
323 const geometry_msgs::Point &goalposition = carrot_goalpose.pose.position;
324
325 tf::Quaternion carrotGoalQ;
326 tf::quaternionMsgToTF(carrot_goalpose.pose.orientation, carrotGoalQ);
327 //ROS_INFO_STREAM("Plan goal quaternion at "<< goalpose.pose.orientation);
328
329 //goal orientation (global frame)
330 double betta = tf::getYaw(carrot_goalpose.pose.orientation) + betta_offset_;
331
332 double dx = goalposition.x - tfpose.getOrigin().x();
333 double dy = goalposition.y - tfpose.getOrigin().y();
334
335 //distance error to the targetpoint
336 double rho_error = sqrt(dx * dx + dy * dy);
337
338 //current angle
339 tf::Quaternion currentOrientation = tfpose.getRotation();
340 double theta = tf::getYaw(currentOrientation);
341 double alpha = atan2(dy, dx);
342 alpha = alpha + alpha_offset_;
343
344 double alpha_error = angles::shortest_angular_distance(alpha, theta);
345 double betta_error = angles::shortest_angular_distance(betta, theta);
346
347 double vetta; // = k_rho_ * rho_error;
348 double gamma; //= k_alpha_ * alpha_error + k_betta_ * betta_error;
349
350 if (rho_error > xy_goal_tolerance_) // reguular control rule, be careful, rho error is with the carrot not with the final goal (this is something to improve like the backwards planner)
351 {
352 vetta = k_rho_ * rho_error;
353 gamma = k_alpha_ * alpha_error;
354 }
355 else if (fabs(betta_error) >= yaw_goal_tolerance_) // pureSpining
356 {
357 vetta = 0;
358 gamma = k_betta_ * betta_error;
359 }
360 else // goal reached
361 {
362 ROS_DEBUG("GOAL REACHED");
363 vetta = 0;
364 gamma = 0;
365 goalReached_ = true;
366 }
367
368 // linear speed clamp
369 if (vetta > max_linear_x_speed_)
370 {
371 vetta = max_linear_x_speed_;
372 }
373 else if (vetta < -max_linear_x_speed_)
374 {
375 vetta = -max_linear_x_speed_;
376 }
377
378 // angular speed clamp
379 if (gamma > max_angular_z_speed_)
380 {
381 gamma = max_angular_z_speed_;
382 }
383 else if (gamma < -max_angular_z_speed_)
384 {
385 gamma = -max_angular_z_speed_;
386 }
387
388 cmd_vel.linear.x = vetta;
389 cmd_vel.angular.z = gamma;
390
391 //clamp(cmd_vel, max_linear_x_speed_, max_angular_z_speed_);
392
393 //ROS_INFO_STREAM("Local planner: "<< cmd_vel);
394
395 publishGoalMarker(goalposition.x, goalposition.y, betta);
396
397 ROS_DEBUG_STREAM("Forward local planner," << std::endl
398 << " theta: " << theta << std::endl
399 << " betta: " << betta << std::endl
400 << " err_x: " << dx << std::endl
401 << " err_y:" << dy << std::endl
402 << " rho_error:" << rho_error << std::endl
403 << " alpha_error:" << alpha_error << std::endl
404 << " betta_error:" << betta_error << std::endl
405 << " vetta:" << vetta << std::endl
406 << " gamma:" << gamma << std::endl
407 << " xy_goal_tolerance:" << xy_goal_tolerance_ << std::endl
408 << " yaw_goal_tolerance:" << yaw_goal_tolerance_ << std::endl);
409
410 //if(cmd_vel.linear.x==0 && cmd_vel.angular.z == 0 )
411 //{
412 //}
413
414 //integrate trajectory and check collision
415
416 tf::Stamped<tf::Pose> global_pose = optionalRobotPose(costmapRos_);
417
418 //->getRobotPose(global_pose);
419
420 auto *costmap2d = costmapRos_->getCostmap();
421 auto yaw = tf::getYaw(global_pose.getRotation());
422
423 auto &pos = global_pose.getOrigin();
424
425 Eigen::Vector3f currentpose(pos.x(), pos.y(), yaw);
426 Eigen::Vector3f currentvel(cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z);
427 std::vector<Eigen::Vector3f> trajectory;
428 this->generateTrajectory(currentpose, currentvel, 0.8 /*meters*/, M_PI / 8 /*rads*/, 3.0 /*seconds*/, 0.05 /*seconds*/, trajectory);
429
430 // check plan rejection
431 bool aceptedplan = true;
432
433 uint32_t mx, my;
434
435 int i = 0;
436 // ROS_INFO_STREAM("lplanner goal: " << finalgoalpose.pose.position);
437 for (auto &p : trajectory)
438 {
439 float dx = p[0] - finalgoalpose.pose.position.x;
440 float dy = p[1] - finalgoalpose.pose.position.y;
441
442 float dst = sqrt(dx * dx + dy * dy);
443 if (dst < xy_goal_tolerance_)
444 {
445 // ROS_INFO("trajectory checking skipped, goal reached");
446 break;
447 }
448
449 costmap2d->worldToMap(p[0], p[1], mx, my);
450 uint64_t cost = costmap2d->getCost(mx, my);
451
452 // ROS_INFO("checking cost pt %d [%lf, %lf] cell[%d,%d] = %d", i, p[0], p[1], mx, my, cost);
453 // ROS_INFO_STREAM("cost: " << cost);
454
455 // static const unsigned char NO_INFORMATION = 255;
456 // static const unsigned char LETHAL_OBSTACLE = 254;
457 // static const unsigned char INSCRIBED_INFLATED_OBSTACLE = 253;
458 // static const unsigned char FREE_SPACE = 0;
459
460 if (costmap2d->getCost(mx, my) >= costmap_2d::INSCRIBED_INFLATED_OBSTACLE)
461 {
462 aceptedplan = false;
463 // ROS_WARN("ABORTED LOCAL PLAN BECAUSE OBSTACLE DETEDTED");
464 break;
465 }
466 i++;
467 }
468
469 if (aceptedplan)
470 {
471 waiting_ = false;
472 return true;
473 }
474 else
475 {
476 // stop and wait
477 cmd_vel.linear.x = 0;
478 cmd_vel.angular.z = 0;
479
480 if (waiting_ == false)
481 {
482 waiting_ = true;
483 waitingStamp_ = ros::Time::now();
484 }
485 else
486 {
487 auto waitingduration = ros::Time::now() - waitingStamp_;
488
489 if (waitingduration > this->waitingTimeout_)
490 {
491 return false;
492 }
493 }
494
495 return true;
496 }
497}
498
505{
506 return goalReached_;
507}
508
514bool ForwardLocalPlanner::setPlan(const std::vector<geometry_msgs::PoseStamped> &plan)
515{
516 plan_ = plan;
517 goalReached_ = false;
518 return true;
519}
520} // namespace forward_local_planner
521} // namespace cl_move_base_z
PLUGINLIB_EXPORT_CLASS(cl_move_base_z::backward_global_planner::BackwardGlobalPlanner, nav_core::BaseGlobalPlanner)
Eigen::Vector3f computeNewPositions(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, double dt)
virtual bool computeVelocityCommands(geometry_msgs::Twist &cmd_vel) override
Given the current position, orientation, and velocity of the robot: compute velocity commands to send...
void generateTrajectory(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, float maxdist, float maxangle, float maxtime, float dt, std::vector< Eigen::Vector3f > &outtraj)
virtual bool setPlan(const std::vector< geometry_msgs::PoseStamped > &plan) override
Set the plan that the local planner is following.
virtual bool isGoalReached() override
Check if the goal pose has been achieved by the local planner.
void clamp(geometry_msgs::Twist &cmd_vel, double max_linear_x_speed_, double max_angular_z_speed_)
tf::Stamped< tf::Pose > optionalRobotPose(costmap_2d::Costmap2DROS *costmapRos)