SMACC
Loading...
Searching...
No Matches
odom_tracker.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>
8#include <boost/range/adaptor/reversed.hpp>
9
10namespace cl_move_base_z
11{
12namespace odom_tracker
13{
14OdomTracker::OdomTracker(std::string odomTopicName, std::string odomFrame)
15 : paramServer_(ros::NodeHandle("~/odom_tracker"))
16{
18 publishMessages = true;
20 this->odomFrame_ = odomFrame;
21
22 ros::NodeHandle nh("~/odom_tracker");
23
24 ROS_WARN("Initializing Odometry Tracker");
25
26 if (!nh.getParam("odom_frame", this->odomFrame_))
27 {
28 ROS_INFO_STREAM("[OdomTracker] odomFrame:" << this->odomFrame_);
29 }
30 ROS_INFO_STREAM("[OdomTracker] odomFrame overwritten by ros parameter:" << this->odomFrame_);
31
32 if (!nh.getParam("record_point_distance_threshold", recordPointDistanceThreshold_))
33 {
34 recordPointDistanceThreshold_ = 0.005; // 5 mm
35 }
36 ROS_INFO_STREAM("[OdomTracker] record_point_distance_threshold :" << recordPointDistanceThreshold_);
37
38 if (!nh.getParam("record_angular_distance_threshold", recordAngularDistanceThreshold_))
39 {
40 recordAngularDistanceThreshold_ = 0.1; // radians
41 }
42 ROS_INFO_STREAM("[OdomTracker] record_angular_distance_threshold :" << recordAngularDistanceThreshold_);
43
44 if (!nh.getParam("clear_point_distance_threshold", clearPointDistanceThreshold_))
45 {
46 clearPointDistanceThreshold_ = 0.05; // 5 cm
47 }
48 ROS_INFO_STREAM("[OdomTracker] clear_point_distance_threshold :" << clearPointDistanceThreshold_);
49
50 if (!nh.getParam("clear_angular_distance_threshold", clearAngularDistanceThreshold_))
51 {
52 clearAngularDistanceThreshold_ = 0.1; // radians
53 }
54 ROS_INFO_STREAM("[OdomTracker] clear_angular_distance_threshold :" << clearAngularDistanceThreshold_);
55
57 {
58 odomSub_ = nh.subscribe(odomTopicName, 1, &OdomTracker::processOdometryMessage, this);
59 }
60
61 robotBasePathPub_ = std::make_shared<realtime_tools::RealtimePublisher<nav_msgs::Path>>(nh, "odom_tracker_path", 1);
63 std::make_shared<realtime_tools::RealtimePublisher<nav_msgs::Path>>(nh, "odom_tracker_stacked_path", 1);
64
65 f = boost::bind(&OdomTracker::reconfigCB, this, _1, _2);
66 paramServer_.setCallback(f);
67}
68
75{
76 // ROS_INFO("odom_tracker m_mutex acquire");
77 std::lock_guard<std::mutex> lock(m_mutex_);
78 ROS_INFO("[OdomTracker] setting working mode to: %d", (uint8_t)workingMode);
79 workingMode_ = workingMode;
80 // ROS_INFO("odom_tracker m_mutex release");
81}
82
89{
90 // ROS_INFO("odom_tracker m_mutex acquire");
91 std::lock_guard<std::mutex> lock(m_mutex_);
92 publishMessages = value;
93 // ROS_INFO("odom_tracker m_mutex release");
95}
96
97void OdomTracker::pushPath(std::string newPathTagName)
98{
99 ROS_INFO("odom_tracker m_mutex acquire");
100 std::lock_guard<std::mutex> lock(m_mutex_);
101 ROS_INFO("PUSH_PATH PATH EXITING");
102 this->logStateString();
103
105 baseTrajectory_.poses.clear();
106
107 if(newPathTagName =="")
108 {
109 this->currentPathTagName_="(unspecified path name)";
110 }
111 else
112 {
113 this->currentPathTagName_ = newPathTagName;
114 }
115
116 ROS_INFO("PUSH_PATH PATH EXITING");
117 this->logStateString();
118 ROS_INFO("odom_tracker m_mutex release");
120}
121
122void OdomTracker::popPath(int popCount, bool keepPreviousPath)
123{
124 ROS_INFO("odom_tracker m_mutex acquire");
125 std::lock_guard<std::mutex> lock(m_mutex_);
126
127 ROS_INFO("POP PATH ENTRY");
128 this->logStateString();
129
130 if (!keepPreviousPath)
131 {
132 baseTrajectory_.poses.clear();
133 }
134
135 while (popCount > 0 && !pathStack_.empty())
136 {
137 auto &stacked = pathStack_.back().path.poses;
138 baseTrajectory_.poses.insert(baseTrajectory_.poses.begin(), stacked.begin(), stacked.end());
139 pathStack_.pop_back();
140 popCount--;
141
142 ROS_INFO("POP PATH Iteration ");
143 this->logStateString();
144 }
145
146 ROS_INFO("POP PATH EXITING");
147 this->logStateString();
148 ROS_INFO("odom_tracker m_mutex release");
150}
151
153{
154 ROS_INFO("--- odom tracker state ---");
155 ROS_INFO(" - stacked paths count: %ld", pathStack_.size());
156 ROS_INFO_STREAM(" - [STACK-HEAD active path '" << currentPathTagName_ <<"' size: "<< baseTrajectory_.poses.size()<<"]");
157 int i = 0;
158 for (auto &p : pathStack_ | boost::adaptors::reversed)
159 {
160 ROS_INFO_STREAM(" - p " << i << "[" << p.path.header.stamp << "][" << p.pathTagName << "], size: " << p.path.poses.size());
161 i++;
162 }
163 ROS_INFO("---");
164}
165
167{
168 std::lock_guard<std::mutex> lock(m_mutex_);
169 baseTrajectory_.poses.clear();
170
171 rtPublishPaths(ros::Time::now());
172 this->logStateString();
174}
175
176void OdomTracker::setStartPoint(const geometry_msgs::PoseStamped &pose)
177{
178 std::lock_guard<std::mutex> lock(m_mutex_);
179 ROS_INFO_STREAM("[OdomTracker] set current path starting point: " << pose);
180 if (baseTrajectory_.poses.size() > 0)
181 {
182 baseTrajectory_.poses[0] = pose;
183 }
184 else
185 {
186 baseTrajectory_.poses.push_back(pose);
187 }
189}
190
191void OdomTracker::setStartPoint(const geometry_msgs::Pose &pose)
192{
193 std::lock_guard<std::mutex> lock(m_mutex_);
194 ROS_INFO_STREAM("[OdomTracker] set current path starting point: " << pose);
195 geometry_msgs::PoseStamped posestamped;
196 posestamped.header.frame_id = this->odomFrame_;
197 posestamped.header.stamp = ros::Time::now();
198 posestamped.pose = pose;
199
200 if (baseTrajectory_.poses.size() > 0)
201 {
202 baseTrajectory_.poses[0] = posestamped;
203 }
204 else
205 {
206 baseTrajectory_.poses.push_back(posestamped);
207 }
209}
210
211nav_msgs::Path OdomTracker::getPath()
212{
213 std::lock_guard<std::mutex> lock(m_mutex_);
214 return this->baseTrajectory_;
215}
216
222void OdomTracker::rtPublishPaths(ros::Time timestamp)
223{
224 if (robotBasePathPub_->trylock())
225 {
226 nav_msgs::Path &msg = robotBasePathPub_->msg_;
228
229 msg = baseTrajectory_;
230
231 msg.header.stamp = timestamp;
232 robotBasePathPub_->unlockAndPublish();
233 }
234
235 if (robotBasePathStackedPub_->trylock())
236 {
237 nav_msgs::Path &msg = robotBasePathStackedPub_->msg_;
239
241 msg.header.stamp = timestamp;
242 robotBasePathStackedPub_->unlockAndPublish();
243 }
244}
245
247{
248 aggregatedStackPathMsg_.poses.clear();
249 for (auto &p : pathStack_)
250 {
251 aggregatedStackPathMsg_.poses.insert(aggregatedStackPathMsg_.poses.end(), p.path.poses.begin(), p.path.poses.end());
252 }
253
254 aggregatedStackPathMsg_.header.frame_id = this->odomFrame_;
255}
256
262bool OdomTracker::updateClearPath(const nav_msgs::Odometry &odom)
263{
264 // we initially accept any message if the queue is empty
266 geometry_msgs::PoseStamped base_pose;
267
268 base_pose.pose = odom.pose.pose;
269 base_pose.header = odom.header;
270 baseTrajectory_.header = odom.header;
271
272 bool acceptBackward = false;
273 bool clearingError = false;
274 bool finished = false;
275
276 while (!finished)
277 {
278 if (baseTrajectory_.poses.size() <= 1) // we at least keep always the first point of the forward path when clearing
279 // (this is important for backwards planner replanning and not losing the
280 // last goal)
281 {
282 acceptBackward = false;
283 finished = true;
284 }
285 else
286 {
287 auto &carrotPose = baseTrajectory_.poses.back().pose;
288 const geometry_msgs::Point &carrotPoint = carrotPose.position;
289 double carrotAngle = tf::getYaw(carrotPose.orientation);
290
291 auto &currePose = base_pose.pose;
292 const geometry_msgs::Point &currePoint = currePose.position;
293 double currentAngle = tf::getYaw(currePose.orientation);
294
295 double lastpointdist = p2pDistance(carrotPoint, currePoint);
296 double goalAngleOffset = fabs(angles::shortest_angular_distance(carrotAngle, currentAngle));
297
298 acceptBackward = !baseTrajectory_.poses.empty() && lastpointdist < clearPointDistanceThreshold_ &&
299 goalAngleOffset < clearAngularDistanceThreshold_;
300
301 clearingError = lastpointdist > 2 * clearPointDistanceThreshold_;
302 ROS_DEBUG_STREAM("[OdomTracker] clearing (accepted: " << acceptBackward << ") linerr: " << lastpointdist
303 << ", anglerr: " << goalAngleOffset);
304 }
305
306 // ROS_INFO("Backwards, last distance: %lf < %lf accept: %d", dist, minPointDistanceBackwardThresh_,
307 // acceptBackward);
308 if (acceptBackward && baseTrajectory_.poses.size() > 1) /*we always leave at least one item, specially interesting
309 for the backward local planner reach the backwards goal
310 with precision enough*/
311 {
312 baseTrajectory_.poses.pop_back();
313 }
314 else if (clearingError)
315 {
316 finished = true;
317 ROS_WARN("[OdomTracker] Incorrect odom clearing motion.");
318 }
319 else
320 {
321 finished = true;
323 }
324 }
325
326 return acceptBackward;
327}
333bool OdomTracker::updateRecordPath(const nav_msgs::Odometry &odom)
334{
336 geometry_msgs::PoseStamped base_pose;
337
338 base_pose.pose = odom.pose.pose;
339 base_pose.header = odom.header;
340 baseTrajectory_.header = odom.header;
341
342 bool enqueueOdomMessage = false;
343
344 double dist = -1;
345 if (baseTrajectory_.poses.empty())
346 {
347 enqueueOdomMessage = true;
348 }
349 else
350 {
351 const auto &prevPose = baseTrajectory_.poses.back().pose;
352 const geometry_msgs::Point &prevPoint = prevPose.position;
353 double prevAngle = tf::getYaw(prevPose.orientation);
354
355 const geometry_msgs::Point &currePoint = base_pose.pose.position;
356 double currentAngle = tf::getYaw(base_pose.pose.orientation);
357
358 dist = p2pDistance(prevPoint, currePoint);
359 double goalAngleOffset = fabs(angles::shortest_angular_distance(prevAngle, currentAngle));
360
361 // ROS_WARN("dist %lf vs min %lf", dist, recordPointDistanceThreshold_);
362
364 {
365 enqueueOdomMessage = true;
366 }
367 else
368 {
369 // ROS_WARN("skip odom, dist: %lf", dist);
370 enqueueOdomMessage = false;
371 }
372 }
373
374 if (enqueueOdomMessage)
375 {
376 baseTrajectory_.poses.push_back(base_pose);
377 }
378
379 return enqueueOdomMessage;
380}
381
387void OdomTracker::reconfigCB(::move_base_z_client_plugin::OdomTrackerConfig &config, uint32_t level)
388{
389 ROS_INFO("[OdomTracker] reconfigure Request");
390 this->odomFrame_ = config.odom_frame;
391
392 this->recordPointDistanceThreshold_ = config.record_point_distance_threshold;
393 this->recordAngularDistanceThreshold_ = config.record_angular_distance_threshold;
394 this->clearPointDistanceThreshold_ = config.clear_point_distance_threshold;
395 this->clearAngularDistanceThreshold_ = config.clear_angular_distance_threshold;
396}
397
403void OdomTracker::processOdometryMessage(const nav_msgs::Odometry &odom)
404{
405 // ROS_INFO("odom_tracker m_mutex acquire");
406 std::lock_guard<std::mutex> lock(m_mutex_);
407
409 {
410 updateRecordPath(odom);
411 }
413 {
414 updateClearPath(odom);
415 }
416
417 // ROS_WARN("odomTracker odometry callback");
418 if (publishMessages)
419 {
420 rtPublishPaths(odom.header.stamp);
421 }
422
423 // ROS_INFO("odom_tracker m_mutex release");
424}
425} // namespace odom_tracker
426} // namespace cl_move_base_z
virtual void processOdometryMessage(const nav_msgs::Odometry &odom)
odom callback: Updates the path - this must be called periodically for each odometry message.
std::vector< StackedPathEntry > pathStack_
Definition: odom_tracker.h:140
void popPath(int pathCount=1, bool keepPreviousPath=false)
dynamic_reconfigure::Server< move_base_z_client_plugin::OdomTrackerConfig >::CallbackType f
Definition: odom_tracker.h:92
double recordPointDistanceThreshold_
How much distance there is between two points of the path.
Definition: odom_tracker.h:118
std::shared_ptr< realtime_tools::RealtimePublisher< nav_msgs::Path > > robotBasePathPub_
Definition: odom_tracker.h:108
nav_msgs::Path baseTrajectory_
Processed path for the mouth of the reel.
Definition: odom_tracker.h:136
virtual bool updateRecordPath(const nav_msgs::Odometry &odom)
std::shared_ptr< realtime_tools::RealtimePublisher< nav_msgs::Path > > robotBasePathStackedPub_
Definition: odom_tracker.h:109
dynamic_reconfigure::Server< move_base_z_client_plugin::OdomTrackerConfig > paramServer_
Definition: odom_tracker.h:91
virtual void rtPublishPaths(ros::Time timestamp)
OdomTracker(std::string odomtopicName="/odom", std::string odomFrame="odom")
void setStartPoint(const geometry_msgs::PoseStamped &pose)
void pushPath(std::string newPathTagName="")
virtual bool updateClearPath(const nav_msgs::Odometry &odom)
void reconfigCB(move_base_z_client_plugin::OdomTrackerConfig &config, uint32_t level)
void setWorkingMode(WorkingMode workingMode)
double p2pDistance(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
Definition: odom_tracker.h:158