SMACC
Loading...
Searching...
No Matches
undo_path_global_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 <boost/assign.hpp>
7#include <boost/range/adaptor/reversed.hpp>
8#include <boost/range/algorithm/copy.hpp>
9#include <pluginlib/class_list_macros.h>
11#include <fstream>
12#include <streambuf>
13#include <nav_msgs/Path.h>
14#include <visualization_msgs/MarkerArray.h>
15#include <tf/tf.h>
16#include <tf/transform_datatypes.h>
17#include <angles/angles.h>
18
19//register this planner as a BaseGlobalPlanner plugin
20
22
23namespace cl_move_base_z
24{
25 namespace undo_path_global_planner
26 {
33 {
35 }
36
38 {
39 //clear
40 nav_msgs::Path planMsg;
41 planMsg.header.stamp = ros::Time::now();
42 planPub_.publish(planMsg);
43 }
44
50 void UndoPathGlobalPlanner::initialize(std::string name, costmap_2d::Costmap2DROS *costmap_ros)
51 {
52 //ROS_INFO_NAMED("Backwards", "UndoPathGlobalPlanner initialize");
53 costmap_ros_ = costmap_ros;
54 //ROS_WARN_NAMED("Backwards", "initializating global planner, costmap address: %ld", (long)costmap_ros);
55
56 forwardPathSub_ = nh_.subscribe("odom_tracker_path", 2, &UndoPathGlobalPlanner::onForwardTrailMsg, this);
57
58 ros::NodeHandle nh;
59 planPub_ = nh.advertise<nav_msgs::Path>("undo_path_planner/global_plan", 1);
60 markersPub_ = nh.advertise<visualization_msgs::MarkerArray>("undo_path_planner/markers", 1);
61 }
62
68 void UndoPathGlobalPlanner::onForwardTrailMsg(const nav_msgs::Path::ConstPtr &trailMessage)
69 {
70 lastForwardPathMsg_ = *trailMessage;
71 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] received backward path msg poses [" << lastForwardPathMsg_.poses.size() << "]");
72 }
73
79 void UndoPathGlobalPlanner::publishGoalMarker(const geometry_msgs::Pose &pose, double r, double g, double b)
80 {
81 double phi = tf::getYaw(pose.orientation);
82 visualization_msgs::Marker marker;
83 marker.header.frame_id = this->costmap_ros_->getGlobalFrameID();
84 marker.header.stamp = ros::Time::now();
85 marker.ns = "my_namespace2";
86 marker.id = 0;
87 marker.type = visualization_msgs::Marker::ARROW;
88 marker.action = visualization_msgs::Marker::ADD;
89 marker.scale.x = 0.1;
90 marker.scale.y = 0.3;
91 marker.scale.z = 0.1;
92 marker.color.a = 1.0;
93 marker.color.r = r;
94 marker.color.g = g;
95 marker.color.b = b;
96
97 geometry_msgs::Point start, end;
98 start.x = pose.position.x;
99 start.y = pose.position.y;
100
101 end.x = pose.position.x + 0.5 * cos(phi);
102 end.y = pose.position.y + 0.5 * sin(phi);
103
104 marker.points.push_back(start);
105 marker.points.push_back(end);
106
107 visualization_msgs::MarkerArray ma;
108 ma.markers.push_back(marker);
109
110 markersPub_.publish(ma);
111 }
112
118 bool UndoPathGlobalPlanner::createDefaultUndoPathPlan(const geometry_msgs::PoseStamped &start,
119 const geometry_msgs::PoseStamped &goal,
120 std::vector<geometry_msgs::PoseStamped> &plan)
121 {
122 //ROS_WARN_NAMED("Backwards", "Iterating in last forward cord path");
123 int i = lastForwardPathMsg_.poses.size() - 1;
124 double linear_mindist = std::numeric_limits<double>::max();
125 int mindistindex = -1;
126 double startPoseAngle = tf::getYaw(start.pose.orientation);
127 geometry_msgs::Pose startPositionProjected;
128
129 // The goal of this code is finding the most convenient initial path pose.
130 // first, find closest linear point to the current robot position
131 // we start from the final goal, that is, the beginning of the trajectory
132 // (since this was the forward motion from the odom tracker)
133 for (auto &p : lastForwardPathMsg_.poses /*| boost::adaptors::reversed*/)
134 {
135 geometry_msgs::PoseStamped pose = p;
136 pose.header.frame_id = costmap_ros_->getGlobalFrameID();
137 pose.header.stamp = ros::Time::now();
138
139 double dx = pose.pose.position.x - start.pose.position.x;
140 double dy = pose.pose.position.y - start.pose.position.y;
141
142 double dist = sqrt(dx * dx + dy * dy);
143 double angleOrientation = tf::getYaw(pose.pose.orientation);
144 double angleError = fabs(angles::shortest_angular_distance(angleOrientation, startPoseAngle));
145 if (dist <= linear_mindist)
146 {
147 mindistindex = i;
148 linear_mindist = dist;
149 startPositionProjected = pose.pose;
150
151 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] initial start point search, NEWBEST_LINEAR= " << i << ". error, linear: " << linear_mindist << ", angular: " << angleError);
152 }
153 else
154 {
155 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] initial start point search, skipped= " << i << ". best linear error: " << linear_mindist << ". current error, linear: " << dist << " angular: " << angleError);
156 }
157
158 i--;
159 }
160
161 double const ERROR_DISTANCE_PURE_SPINNING_FACTOR = 1.5;
162 // Concept of second pass: now we only consider a pure spinning motion in this point. We want to consume some very close angular targets, (accepting a larger linear minerror of 1.5 besterror. That is, more or less in the same point).
163
164 ROS_DEBUG("[UndoPathGlobalPlanner] second angular pass");
165 double angularMinDist = std::numeric_limits<double>::max();
166
167 if(mindistindex >= lastForwardPathMsg_.poses.size())
168 mindistindex = lastForwardPathMsg_.poses.size() -1;// workaround, something is making a out of bound exception in poses array access
169 {
170 if(lastForwardPathMsg_.poses.size() == 0)
171 {
172 ROS_WARN_STREAM("[UndoPathGlobalPlanner] Warning possible bug");
173 }
174
175 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] second pass loop");
176 for (int i = mindistindex; i >= 0; i--)
177 {
178 // warning this index, i refers to some inverse interpretation from the previous loop,
179 // (last indexes in this path corresponds to the poses closer to our current position)
180 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] " << i << "/" << lastForwardPathMsg_.poses.size());
181 auto index = lastForwardPathMsg_.poses.size() - i -1;
182 if(index < 0 || index >= lastForwardPathMsg_.poses.size())
183 {
184 ROS_WARN_STREAM("[UndoPathGlobalPlanner] this should not happen. Check implementation.");
185 break;
186 }
187 geometry_msgs::PoseStamped pose = lastForwardPathMsg_.poses[lastForwardPathMsg_.poses.size() - i -1];
188
189 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] global frame");
190 pose.header.frame_id = costmap_ros_->getGlobalFrameID();
191 pose.header.stamp = ros::Time::now();
192
193 double dx = pose.pose.position.x - start.pose.position.x;
194 double dy = pose.pose.position.y - start.pose.position.y;
195
196 double dist = sqrt(dx * dx + dy * dy);
197 if (dist <= linear_mindist * ERROR_DISTANCE_PURE_SPINNING_FACTOR)
198 {
199 double angleOrientation = tf::getYaw(pose.pose.orientation);
200 double angleError = fabs(angles::shortest_angular_distance(angleOrientation, startPoseAngle));
201 if (angleError < angularMinDist)
202 {
203 angularMinDist = angleError;
204 mindistindex = i;
205 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] initial start point search (angular update), NEWBEST_ANGULAR= " << i << ". error, linear: "<< dist << "(" << linear_mindist << ")" <<", angular: " << angleError << "(" << angularMinDist << ")");
206 }
207 else
208 {
209 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] initial start point search (angular update), skipped= " << i <<". error, linear: "<< dist << "(" << linear_mindist << ")" <<", angular: " << angleError << "(" << angularMinDist << ")");
210 }
211 }
212 else
213 {
214 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] initial start point search (angular update) not in linear range, skipped= " << i << " linear error: " << dist << "(" << linear_mindist << ")");
215 }
216 }
217 }
218
219 if (mindistindex != -1)
220 {
221 //plan.push_back(start);
222
223 ROS_WARN_STREAM("[UndoPathGlobalPlanner] Creating the backwards plan from odom tracker path (" << lastForwardPathMsg_.poses.size() << ") poses");
224 ROS_WARN_STREAM("[UndoPathGlobalPlanner] closer point to goal i=" << mindistindex << " (linear min dist " << linear_mindist << ")");
225 // copy the path at the inverse direction
226 for (int i = lastForwardPathMsg_.poses.size() - 1; i >= mindistindex; i--)
227 {
228 auto &pose = lastForwardPathMsg_.poses[i];
229 ROS_DEBUG_STREAM("[UndoPathGlobalPlanner] adding to plan i = " << i);
230 plan.push_back(pose);
231 }
232 ROS_WARN_STREAM("[UndoPathGlobalPlanner] refined plan has " << plan.size() << " points");
233 }
234 else
235 {
236 ROS_ERROR_STREAM("[UndoPathGlobalPlanner ] backward global plan size: " << plan.size());
237 }
238
239 return true;
240 }
241
247 bool UndoPathGlobalPlanner::makePlan(const geometry_msgs::PoseStamped &start,
248 const geometry_msgs::PoseStamped &goal, std::vector<geometry_msgs::PoseStamped> &plan)
249 {
250 //ROS_WARN_NAMED("Backwards", "Backwards global planner: Generating global plan ");
251 //ROS_WARN_NAMED("Backwards", "Clearing...");
252
253 plan.clear();
254
255 if(lastForwardPathMsg_.poses.size() == 0)
256 {
257 return false;
258 }
259
260 auto forcedGoal = lastForwardPathMsg_.poses[lastForwardPathMsg_.poses.size() - 1]; // FORCE LAST POSE
261 this->createDefaultUndoPathPlan(start, forcedGoal, plan);
262 //this->createPureSpiningAndStragihtLineBackwardPath(start, goal, plan);
263
264 //ROS_INFO_STREAM(" start - " << start);
265 //ROS_INFO_STREAM(" end - " << goal.pose.position);
266
267 //ROS_INFO("3 - heading to goal orientation");
268 //double goalOrientation = angles::normalize_angle(tf::getYaw(goal.pose.orientation));
269 //cl_move_base_z::makePureSpinningSubPlan(prevState,goalOrientation,plan);
270
271 //ROS_WARN_STREAM( "MAKE PLAN INVOKED, plan size:"<< plan.size());
272 publishGoalMarker(forcedGoal.pose, 1.0, 0, 1.0);
273
274 nav_msgs::Path planMsg;
275 planMsg.poses = plan;
276 planMsg.header.frame_id = this->costmap_ros_->getGlobalFrameID();
277
278 // check plan rejection
279 bool acceptedGlobalPlan = true;
280
281 // static const unsigned char NO_INFORMATION = 255;
282 // static const unsigned char LETHAL_OBSTACLE = 254;
283 // static const unsigned char INSCRIBED_INFLATED_OBSTACLE = 253;
284 // static const unsigned char FREE_SPACE = 0;
285
286 costmap_2d::Costmap2D *costmap2d = this->costmap_ros_->getCostmap();
287 for (auto &p : plan)
288 {
289 uint32_t mx, my;
290 costmap2d->worldToMap(p.pose.position.x, p.pose.position.y, mx, my);
291 auto cost = costmap2d->getCost(mx, my);
292
293 if (cost >= costmap_2d::INSCRIBED_INFLATED_OBSTACLE)
294 {
295 acceptedGlobalPlan = false;
296 break;
297 }
298 }
299
300 planPub_.publish(planMsg);
301
302 // this was previously set to size() <= 1, but a plan with a single point is also a valid plan (the goal)
303 return true;
304 }
305
311 bool UndoPathGlobalPlanner::makePlan(const geometry_msgs::PoseStamped &start,
312 const geometry_msgs::PoseStamped &goal, std::vector<geometry_msgs::PoseStamped> &plan,
313 double &cost)
314 {
315 cost = 0;
316 makePlan(start, goal, plan);
317 return true;
318 }
319
320 } // namespace undo_path_global_planner
321} // namespace cl_move_base_z
void publishGoalMarker(const geometry_msgs::Pose &pose, double r, double g, double b)
bool makePlan(const geometry_msgs::PoseStamped &start, const geometry_msgs::PoseStamped &goal, std::vector< geometry_msgs::PoseStamped > &plan)
virtual bool createDefaultUndoPathPlan(const geometry_msgs::PoseStamped &start, const geometry_msgs::PoseStamped &goal, std::vector< geometry_msgs::PoseStamped > &plan)
virtual void initialize(std::string name, costmap_2d::Costmap2DROS *costmap_ros_) override
costmap_2d::Costmap2DROS * costmap_ros_
stored but almost not used
void onForwardTrailMsg(const nav_msgs::Path::ConstPtr &trailMessage)
PLUGINLIB_EXPORT_CLASS(cl_move_base_z::undo_path_global_planner::UndoPathGlobalPlanner, nav_core::BaseGlobalPlanner)