22#include <angles/angles.h>
28#include <boost/range/adaptor/reversed.hpp>
48 rclcpp::Node::SharedPtr & node, std::string param_name, T & value)
50 if (!node->get_parameter(param_name, value))
53 node->get_logger(),
"[CpOdomTracker] autoset " << param_name <<
": " << value);
54 node->declare_parameter(param_name, value);
58 RCLCPP_INFO_STREAM(node->get_logger(),
"[CpOdomTracker] " << param_name <<
": " << value);
71 RCLCPP_WARN(
getLogger(),
"[CpOdomTracker] Initializing Odometry Tracker");
87 nh->create_publisher<nav_msgs::msg::Path>(
"odom_tracker_path", rclcpp::QoS(1));
90 nh->create_publisher<nav_msgs::msg::Path>(
"odom_tracker_stacked_path", rclcpp::QoS(1));
95 nh->get_logger(),
"[CpOdomTracker] subscribing to odom topic: " <<
odomTopicName_);
97 rclcpp::SensorDataQoS qos;
98 odomSub_ = nh->create_subscription<nav_msgs::msg::Odometry>(
111 nh->get_logger(),
"[CpOdomTracker] unknown strategy: " << (
int)this->strategy_);
121 const std::vector<rclcpp::Parameter> & parameters)
123 std::lock_guard<std::mutex> lock(
m_mutex_);
124 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex acquire");
126 for (
const auto & param : parameters)
128 if (param.get_name() ==
"record_point_distance_threshold")
132 else if (param.get_name() ==
"record_angular_distance_threshold")
136 else if (param.get_name() ==
"clear_point_distance_threshold")
140 else if (param.get_name() ==
"clear_angular_distance_threshold")
144 else if (param.get_name() ==
"odom_frame")
150 rcl_interfaces::msg::SetParametersResult result;
151 result.successful =
true;
152 result.reason =
"success";
163 std::lock_guard<std::mutex> lock(
m_mutex_);
170 "[CpOdomTracker] setting working mode to RECORD - record_point_distance_threshold: "
177 "[CpOdomTracker] setting working mode to CLEAR - clear_point_distance_threshold: "
182 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] setting working mode to IDLE");
186 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] setting working mode to <UNKNOWN>");
189 if (this->
odomSub_ !=
nullptr && this->
odomSub_->get_publisher_count() == 0)
193 "[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to the "
209 std::lock_guard<std::mutex> lock(
m_mutex_);
219 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex acquire, to push path");
220 std::lock_guard<std::mutex> lock(
m_mutex_);
223 if (this->
odomSub_ !=
nullptr && this->
odomSub_->get_publisher_count() == 0)
227 "[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to the "
234 geometry_msgs::msg::PoseStamped goalPose;
238 getLogger(),
"[CpOdomTracker] currentPathName: " << pathname
240 <<
" current motion goal: " << goalPose);
255 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex acquire to pop path");
256 std::lock_guard<std::mutex> lock(
m_mutex_);
258 RCLCPP_INFO(
getLogger(),
"POP PATH ENTRY");
261 if (this->
odomSub_ !=
nullptr && this->
odomSub_->get_publisher_count() == 0)
265 "[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to the "
269 if (!keepPreviousPath)
280 baseTrajectory_.poses.begin(), stackedPath.begin(), stackedPath.end());
286 RCLCPP_INFO(
getLogger(),
"POP PATH Iteration ");
290 RCLCPP_INFO(
getLogger(),
"POP PATH EXITING");
292 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex release");
300 std::stringstream ss;
301 ss <<
"--- odom tracker state ---" << std::endl;
307 ss <<
" - [STACK-HEAD active path size: " <<
baseTrajectory_.poses.size() <<
"]" << std::endl;
309 for (
auto & p :
pathStack_ | boost::adaptors::reversed)
312 std::string goalstr =
"[]";
313 if (pathinfo.goalPose)
315 std::stringstream ss;
316 ss << *(pathinfo.goalPose);
320 ss <<
" - p " << i <<
"[" << p.header.stamp <<
"], size: " << p.poses.size() <<
" - "
321 << pathinfo.name <<
" - goal: " << goalstr << std::endl;
326 if (this->
odomSub_ !=
nullptr && this->
odomSub_->get_publisher_count() == 0)
329 <<
"[CpOdomTracker] Odom tracker cannot record the path because there is no publisher to "
335 RCLCPP_DEBUG(
getLogger(), ss.str().c_str());
337 RCLCPP_INFO(
getLogger(), ss.str().c_str());
342 RCLCPP_INFO(
getLogger(),
"odom_tracker m_mutex acquire to clear path");
343 std::lock_guard<std::mutex> lock(
m_mutex_);
355 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] set current path name: " << currentPathName);
361 std::lock_guard<std::mutex> lock(
m_mutex_);
362 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] set current path starting point: " << pose);
376 std::lock_guard<std::mutex> lock(
m_mutex_);
377 RCLCPP_INFO_STREAM(
getLogger(),
"[CpOdomTracker] set current path starting point: " << pose);
378 geometry_msgs::msg::PoseStamped posestamped;
379 posestamped.header.frame_id = this->
odomFrame_;
380 posestamped.header.stamp =
getNode()->now();
381 posestamped.pose = pose;
396 std::lock_guard<std::mutex> lock(
m_mutex_);
402 std::lock_guard<std::mutex> lock(
m_mutex_);
408 std::lock_guard<std::mutex> lock(
m_mutex_);
449 bool acceptBackward =
false;
450 bool clearingError =
false;
451 bool finished =
false;
461 acceptBackward =
false;
467 auto & carrotPoint = carrotPose.position;
469 double carrotAngle = tf2::getYaw(carrotPose.orientation);
471 auto & currePose = base_pose.pose;
472 auto & currePoint = currePose.position;
473 double currentAngle = tf2::getYaw(currePose.orientation);
475 double lastpointdist =
p2pDistance(carrotPoint, currePoint);
476 double goalAngleOffset = fabs(angles::shortest_angular_distance(carrotAngle, currentAngle));
484 getLogger(),
"[CpOdomTracker] clearing (accepted: " << acceptBackward
485 <<
") linerr: " << lastpointdist
486 <<
", anglerr: " << goalAngleOffset);
499 else if (clearingError)
502 RCLCPP_WARN(
getLogger(),
"[CpOdomTracker] Incorrect odom clearing motion.");
511 return acceptBackward;
524 bool enqueueOdomMessage =
false;
529 enqueueOdomMessage =
true;
534 const geometry_msgs::msg::Point & prevPoint = prevPose.position;
535 double prevAngle = tf2::getYaw(prevPose.orientation);
537 const geometry_msgs::msg::Point & currePoint = base_pose.pose.position;
538 double currentAngle = tf2::getYaw(base_pose.pose.orientation);
541 double goalAngleOffset = fabs(angles::shortest_angular_distance(prevAngle, currentAngle));
545 RCLCPP_WARN_THROTTLE(
getLogger(), *
getNode()->get_clock(), 2000,
"odom received");
549 enqueueOdomMessage =
true;
554 enqueueOdomMessage =
false;
558 if (enqueueOdomMessage)
560 RCLCPP_WARN_THROTTLE(
561 getLogger(), *
getNode()->get_clock(), 2000,
"enqueue odom tracker pose. dist %lf vs min %lf",
566 return enqueueOdomMessage;
607 RCLCPP_INFO(
getLogger(),
"odom_tracker update");
609 RCLCPP_INFO(
getLogger(),
"odom tracker updatd pose, frame: %s", pose.header.frame_id.c_str());
611 RCLCPP_INFO(
getLogger(),
"odom_tracker update end");
621 geometry_msgs::msg::PoseStamped base_pose;
622 base_pose.pose = odom->pose.pose;
623 base_pose.header = odom->header;
635 RCLCPP_INFO_THROTTLE(
637 "[odom_tracker] processing odom msg update heartbeat");
638 std::lock_guard<std::mutex> lock(
m_mutex_);
geometry_msgs::msg::PoseStamped toPoseStampedMsg()
void popPath(int pathCount=1, bool keepPreviousPath=false)
virtual bool updateRecordPath(const geometry_msgs::msg::PoseStamped &odom)
rclcpp::Subscription< nav_msgs::msg::Odometry >::SharedPtr odomSub_
std::string odomTopicName_
std::string currentPathName_
double clearPointDistanceThreshold_
rads
double clearAngularDistanceThreshold_
rads
std::optional< geometry_msgs::msg::PoseStamped > currentMotionGoal_
cl_nav2z::CpPose * robotPose_
virtual void processNewPose(const geometry_msgs::msg::PoseStamped &odom)
odom callback: Updates the path - this must be called periodically for each odometry message.
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)
rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr param_callback_handle_
void setCurrentPathName(const std::string ¤tPathName)
nav_msgs::msg::Path getPath()
virtual void odomMessageCallback(const nav_msgs::msg::Odometry::SharedPtr odom)
std::vector< PathInfo > pathInfos_
double recordAngularDistanceThreshold_
Meters.
rclcpp::TimerBase::SharedPtr robotPoseTimer_
rclcpp::Publisher< nav_msgs::msg::Path >::SharedPtr robotBasePathStackedPub_
void setCurrentMotionGoal(const geometry_msgs::msg::PoseStamped &pose)
virtual bool updateClearPath(const geometry_msgs::msg::PoseStamped &odom)
nav_msgs::msg::Path aggregatedStackPathMsg_
std::vector< nav_msgs::msg::Path > pathStack_
void setPublishMessages(bool value)
void setWorkingMode(WorkingMode workingMode)
rclcpp::Publisher< nav_msgs::msg::Path >::SharedPtr robotBasePathPub_
void updateAggregatedStackPath()
rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector< rclcpp::Parameter > ¶meters)
std::optional< geometry_msgs::msg::PoseStamped > getCurrentMotionGoal()
void onInitialize() override
void setStartPoint(const geometry_msgs::msg::PoseStamped &pose)
void updateConfiguration()
OdomTrackerStrategy strategy_
CpOdomTracker(std::string odomtopicName="/odom", std::string odomFrame="odom", OdomTrackerStrategy strategy=OdomTrackerStrategy::ODOMETRY_SUBSCRIBER)
void logStateString(bool debug=true)
rclcpp::Logger getLogger() const
void requiresComponent(TComponent *&requiredComponentStorage, ComponentRequirement requirementType=ComponentRequirement::SOFT)
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)