22#include <angles/angles.h>
26#include <boost/range/adaptor/reversed.hpp>
43 rclcpp::Node::SharedPtr & node, std::string param_name, T & value)
45 if (!node->get_parameter(param_name, value))
48 node->get_logger(),
"[CpOdomTracker] autoset " << param_name <<
": " << value);
49 node->declare_parameter(param_name, value);
53 RCLCPP_INFO_STREAM(node->get_logger(),
"[CpOdomTracker] " << param_name <<
": " << value);
66 RCLCPP_WARN(
getLogger(),
"[CpOdomTracker] Initializing Odometry Tracker");
81 nh->get_logger(),
"[CpOdomTracker] subscribing to odom topic: " <<
odomTopicName_);
83 rclcpp::SensorDataQoS qos;
84 odomSub_ = nh->create_subscription<nav_msgs::msg::Odometry>(
90 nh->create_publisher<nav_msgs::msg::Path>(
"odom_tracker_path", rclcpp::QoS(1));
92 nh->create_publisher<nav_msgs::msg::Path>(
"odom_tracker_stacked_path", rclcpp::QoS(1));
102 std::lock_guard<std::mutex> lock(
m_mutex_);
109 "[CpOdomTracker] setting working mode to RECORD - record_point_distance_threshold: "
116 "[CpOdomTracker] setting working mode to CLEAR - clear_point_distance_threshold: "
121 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] setting working mode to IDLE");
125 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] setting working mode to <UNKNOWN>");
128 if (this->
odomSub_->get_publisher_count() == 0)
132 "[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to the "
148 std::lock_guard<std::mutex> lock(
m_mutex_);
158 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex acquire");
159 std::lock_guard<std::mutex> lock(
m_mutex_);
162 if (this->
odomSub_->get_publisher_count() == 0)
166 "[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to the "
173 geometry_msgs::msg::PoseStamped goalPose;
177 getLogger(),
"[CpOdomTracker] currentPathName: " << pathname
179 <<
" current motion goal: " << goalPose);
194 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex acquire");
195 std::lock_guard<std::mutex> lock(
m_mutex_);
197 RCLCPP_INFO(
getLogger(),
"POP PATH ENTRY");
200 if (this->
odomSub_->get_publisher_count() == 0)
204 "[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to the "
208 if (!keepPreviousPath)
219 baseTrajectory_.poses.begin(), stackedPath.begin(), stackedPath.end());
225 RCLCPP_INFO(
getLogger(),
"POP PATH Iteration ");
229 RCLCPP_INFO(
getLogger(),
"POP PATH EXITING");
231 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex release");
239 std::stringstream ss;
240 ss <<
"--- odom tracker state ---" << std::endl;
246 ss <<
" - [STACK-HEAD active path size: " <<
baseTrajectory_.poses.size() <<
"]" << std::endl;
248 for (
auto & p :
pathStack_ | boost::adaptors::reversed)
251 std::string goalstr =
"[]";
252 if (pathinfo.goalPose)
254 std::stringstream ss;
255 ss << *(pathinfo.goalPose);
259 ss <<
" - p " << i <<
"[" << p.header.stamp <<
"], size: " << p.poses.size() <<
" - "
260 << pathinfo.name <<
" - goal: " << goalstr << std::endl;
265 if (this->
odomSub_->get_publisher_count() == 0)
268 <<
"[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to "
274 RCLCPP_DEBUG(
getLogger(), ss.str().c_str());
276 RCLCPP_INFO(
getLogger(), ss.str().c_str());
281 std::lock_guard<std::mutex> lock(
m_mutex_);
298 std::lock_guard<std::mutex> lock(
m_mutex_);
299 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] set current path starting point: " << pose);
313 std::lock_guard<std::mutex> lock(
m_mutex_);
314 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] set current path starting point: " << pose);
315 geometry_msgs::msg::PoseStamped posestamped;
316 posestamped.header.frame_id = this->
odomFrame_;
317 posestamped.header.stamp =
getNode()->now();
318 posestamped.pose = pose;
333 std::lock_guard<std::mutex> lock(
m_mutex_);
339 std::lock_guard<std::mutex> lock(
m_mutex_);
345 std::lock_guard<std::mutex> lock(
m_mutex_);
384 geometry_msgs::msg::PoseStamped base_pose;
386 base_pose.pose = odom.pose.pose;
387 base_pose.header = odom.header;
390 bool acceptBackward =
false;
391 bool clearingError =
false;
392 bool finished =
false;
402 acceptBackward =
false;
408 auto & carrotPoint = carrotPose.position;
410 double carrotAngle = tf2::getYaw(carrotPose.orientation);
412 auto & currePose = base_pose.pose;
413 auto & currePoint = currePose.position;
414 double currentAngle = tf2::getYaw(currePose.orientation);
416 double lastpointdist =
p2pDistance(carrotPoint, currePoint);
417 double goalAngleOffset = fabs(angles::shortest_angular_distance(carrotAngle, currentAngle));
425 getLogger(),
"[CpOdomTracker] clearing (accepted: " << acceptBackward
426 <<
") linerr: " << lastpointdist
427 <<
", anglerr: " << goalAngleOffset);
440 else if (clearingError)
443 RCLCPP_WARN(
getLogger(),
"[CpOdomTracker] Incorrect odom clearing motion.");
452 return acceptBackward;
462 geometry_msgs::msg::PoseStamped base_pose;
464 base_pose.pose = odom.pose.pose;
465 base_pose.header = odom.header;
468 bool enqueueOdomMessage =
false;
473 enqueueOdomMessage =
true;
478 const geometry_msgs::msg::Point & prevPoint = prevPose.position;
479 double prevAngle = tf2::getYaw(prevPose.orientation);
481 const geometry_msgs::msg::Point & currePoint = base_pose.pose.position;
482 double currentAngle = tf2::getYaw(base_pose.pose.orientation);
485 double goalAngleOffset = fabs(angles::shortest_angular_distance(prevAngle, currentAngle));
489 RCLCPP_WARN_THROTTLE(
getLogger(), *
getNode()->get_clock(), 2000,
"odom received");
493 enqueueOdomMessage =
true;
498 enqueueOdomMessage =
false;
502 if (enqueueOdomMessage)
504 RCLCPP_WARN_THROTTLE(
505 getLogger(), *
getNode()->get_clock(), 2000,
"enqueue odom tracker pose. dist %lf vs min %lf",
510 return enqueueOdomMessage;
549 RCLCPP_INFO_THROTTLE(
551 "[odom_tracker] processing odom msg update heartbeat");
552 std::lock_guard<std::mutex> lock(
m_mutex_);
void popPath(int pathCount=1, bool keepPreviousPath=false)
rclcpp::Subscription< nav_msgs::msg::Odometry >::SharedPtr odomSub_
std::string odomTopicName_
std::string currentPathName_
double clearPointDistanceThreshold_
rads
double clearAngularDistanceThreshold_
rads
virtual void processOdometryMessage(const nav_msgs::msg::Odometry::SharedPtr odom)
odom callback: Updates the path - this must be called periodically for each odometry message.
CpOdomTracker(std::string odomtopicName="/odom", std::string odomFrame="odom")
std::optional< geometry_msgs::msg::PoseStamped > currentMotionGoal_
virtual bool updateRecordPath(const nav_msgs::msg::Odometry &odom)
double recordPointDistanceThreshold_
How much distance there is between two points of the path.
nav_msgs::msg::Path baseTrajectory_
Processed path for the mouth of the reel.
virtual void rtPublishPaths(rclcpp::Time timestamp)
void setCurrentPathName(const std::string ¤tPathName)
nav_msgs::msg::Path getPath()
std::vector< PathInfo > pathInfos_
double recordAngularDistanceThreshold_
Meters.
rclcpp::Publisher< nav_msgs::msg::Path >::SharedPtr robotBasePathStackedPub_
void setCurrentMotionGoal(const geometry_msgs::msg::PoseStamped &pose)
nav_msgs::msg::Path aggregatedStackPathMsg_
virtual bool updateClearPath(const nav_msgs::msg::Odometry &odom)
std::vector< nav_msgs::msg::Path > pathStack_
void setPublishMessages(bool value)
void setWorkingMode(WorkingMode workingMode)
rclcpp::Publisher< nav_msgs::msg::Path >::SharedPtr robotBasePathPub_
bool subscribeToOdometryTopic_
void updateAggregatedStackPath()
std::optional< geometry_msgs::msg::PoseStamped > getCurrentMotionGoal()
void onInitialize() override
void setStartPoint(const geometry_msgs::msg::PoseStamped &pose)
void updateConfiguration()
void logStateString(bool debug=true)
rclcpp::Logger getLogger() const
rclcpp::Node::SharedPtr getNode()
double p2pDistance(const geometry_msgs::msg::Point &p1, const geometry_msgs::msg::Point &p2)
void parameterDeclareAndtryGetOrSet(rclcpp::Node::SharedPtr &node, std::string param_name, T &value)