50 #include <Eigen/Geometry> 54 #include <dynamic_reconfigure/server.h> 55 #include <geometry_msgs/PoseStamped.h> 56 #include <geometry_msgs/Twist.h> 57 #include <nav_msgs/Odometry.h> 58 #include <nav_msgs/Path.h> 59 #include <std_msgs/Float32.h> 60 #include <std_msgs/Header.h> 67 #include <trajectory_tracker_msgs/PathWithVelocity.h> 68 #include <trajectory_tracker_msgs/TrajectoryTrackerStatus.h> 70 #include <trajectory_tracker/TrajectoryTrackerConfig.h> 179 template <
typename MSG_TYPE>
180 void cbPath(
const typename MSG_TYPE::ConstPtr&);
181 void cbSpeed(
const std_msgs::Float32::ConstPtr&);
182 void cbOdometry(
const nav_msgs::Odometry::ConstPtr&);
188 void cbParameter(
const TrajectoryTrackerConfig& config,
const uint32_t );
208 sub_path_ = neonavigation_common::compat::subscribe<nav_msgs::Path>(
211 boost::bind(&TrackerNode::cbPath<nav_msgs::Path>,
this, _1));
214 boost::bind(&TrackerNode::cbPath<trajectory_tracker_msgs::PathWithVelocity>,
this, _1));
218 pub_vel_ = neonavigation_common::compat::advertise<geometry_msgs::Twist>(
221 pub_status_ = pnh_.advertise<trajectory_tracker_msgs::TrajectoryTrackerStatus>(
"status", 10,
true);
222 pub_tracking_ = pnh_.advertise<geometry_msgs::PoseStamped>(
"tracking", 10,
true);
238 k_[0] = config.k_dist;
239 k_[1] = config.k_ang;
240 k_[2] = config.k_avel;
245 vel_[0] = config.max_vel;
246 vel_[1] = config.max_angvel;
247 acc_[0] = config.max_acc;
248 acc_[1] = config.max_angacc;
270 geometry_msgs::Twist cmd_vel;
271 cmd_vel.linear.x = 0;
272 cmd_vel.angular.z = 0;
283 float getVelocity(
const geometry_msgs::PoseStamped& msg)
285 return std::numeric_limits<float>::quiet_NaN();
287 float getVelocity(
const trajectory_tracker_msgs::PoseStampedWithVelocity& msg)
289 return msg.linear_velocity.x;
293 template <
typename MSG_TYPE>
300 if (msg->poses.size() == 0)
304 bool in_place_turning =
false;
306 auto j = msg->poses.begin();
308 for (++j; j < msg->poses.end(); ++j)
310 const float velocity = getVelocity(*j);
311 if (std::isfinite(velocity) && velocity < -0.0)
321 if (in_place_turning)
323 path_.push_back(in_place_turn_end);
324 in_place_turning =
false;
326 path_.push_back(next);
332 in_place_turning =
true;
335 if (in_place_turning)
336 path_.push_back(in_place_turn_end);
343 ROS_WARN(
"frame_odom is invalid. Update from \"%s\" to \"%s\"",
frame_odom_.c_str(), odom->header.frame_id.c_str());
348 ROS_WARN(
"frame_robot is invalid. Update from \"%s\" to \"%s\"",
368 nav_msgs::Odometry odom_compensated = *odom;
369 Eigen::Vector3d prediction_offset(0, 0, 0);
372 const double predict_dt = std::max(0.0, std::min(
max_dt_, (
ros::Time::now() - odom->header.stamp).toSec()));
374 const tf2::Quaternion rotation(tf2::Vector3(0, 0, 1), odom->twist.twist.angular.z * predict_dt);
375 const tf2::Vector3 translation(odom->twist.twist.linear.x * predict_dt, 0, 0);
377 prediction_offset[0] = odom->twist.twist.linear.x * predict_dt;
378 prediction_offset[1] = odom->twist.twist.angular.z * predict_dt;
383 tf2::toMsg(trans, odom_compensated.pose.pose);
387 tf2::fromMsg(odom_compensated.pose.pose, odom_to_robot);
390 odom->header.stamp, odom->header.frame_id);
392 control(robot_to_odom, prediction_offset, dt);
404 control(transform, Eigen::Vector3d(0, 0, 0), 1.0 /
hz_);
408 ROS_WARN(
"TF exception: %s", e.what());
409 trajectory_tracker_msgs::TrajectoryTrackerStatus status;
411 status.distance_remains = 0.0;
412 status.angle_remains = 0.0;
414 status.status = trajectory_tracker_msgs::TrajectoryTrackerStatus::NO_PATH;
425 geometry_msgs::Twist cmd_vel;
426 cmd_vel.linear.x = 0.0;
427 cmd_vel.angular.z = 0.0;
430 trajectory_tracker_msgs::TrajectoryTrackerStatus status;
432 status.distance_remains = 0.0;
433 status.angle_remains = 0.0;
435 status.status = trajectory_tracker_msgs::TrajectoryTrackerStatus::NO_PATH;
451 const Eigen::Vector3d& prediction_offset,
454 trajectory_tracker_msgs::TrajectoryTrackerStatus status;
465 switch (tracking_result.
status)
467 case trajectory_tracker_msgs::TrajectoryTrackerStatus::NO_PATH:
468 case trajectory_tracker_msgs::TrajectoryTrackerStatus::FAR_FROM_PATH:
472 geometry_msgs::Twist cmd_vel;
473 cmd_vel.linear.x = 0;
474 cmd_vel.angular.z = 0;
486 const double expected_angle_remains =
492 const double wvel_increment =
497 "trajectory_tracker: angular residual %0.3f, angular vel %0.3f",
513 wref = std::copysign(1.0, wref) *
vel_[1];
520 const double wvel_diff =
w_lim_.
get() - wref;
524 "trajectory_tracker: distance residual %0.3f, angular residual %0.3f, ang vel residual %0.3f" 525 ", v_lim %0.3f, w_lim %0.3f signed_local_distance %0.3f, k_ang %0.3f",
536 geometry_msgs::Twist cmd_vel;
544 status.status = tracking_result.
status;
555 return TrackingResult(trajectory_tracker_msgs::TrajectoryTrackerStatus::NO_PATH);
559 double transform_delay = 0;
566 transform *= odom_to_path;
571 1.0,
"Timestamp of the transform is too old %f %f",
575 const float trans_yaw =
tf2::getYaw(transform.getRotation());
576 const Eigen::Transform<double, 2, Eigen::TransformTraits::AffineCompact> trans =
577 Eigen::Translation2d(
578 Eigen::Vector2d(transform.getOrigin().x(), transform.getOrigin().y())) *
579 Eigen::Rotation2Dd(trans_yaw);
584 trans *
path_[i].pos_, trans_yaw +
path_[i].yaw_,
path_[i].velocity_));
588 ROS_WARN(
"TF exception: %s", e.what());
589 return TrackingResult(trajectory_tracker_msgs::TrajectoryTrackerStatus::NO_PATH);
592 const Eigen::Vector2d origin_raw = prediction_offset.head<2>();
593 const float yaw_raw = prediction_offset[2];
596 const Eigen::Vector2d origin =
599 const double path_length = lpath.
length();
610 if (it_nearest == lpath.end())
612 return TrackingResult(trajectory_tracker_msgs::TrajectoryTrackerStatus::NO_PATH);
615 const int i_nearest = std::distance(lpath.cbegin(), it_nearest);
616 const int i_nearest_prev = std::max(0, i_nearest - 1);
617 const int i_local_goal = std::distance(lpath.cbegin(), it_local_goal);
619 const Eigen::Vector2d pos_on_line =
621 const Eigen::Vector2d pos_on_line_raw =
624 const float linear_vel =
625 std::isnan(lpath[i_nearest].velocity_) ?
vel_[0] : lpath[i_nearest].velocity_;
628 float remain_local = lpath.
remainedDistance(lpath.cbegin(), it_nearest, it_local_goal, pos_on_line);
630 float distance_remains = lpath.
remainedDistance(lpath.cbegin(), it_nearest, lpath.cend(), pos_on_line);
631 float distance_remains_raw = lpath.
remainedDistance(lpath.cbegin(), it_nearest, lpath.cend(), pos_on_line_raw);
633 distance_remains = distance_remains_raw = remain_local = 0;
637 lpath[i_nearest_prev].pos_, lpath[i_nearest].pos_, origin);
640 const Eigen::Vector2d vec = lpath[i_nearest].pos_ - lpath[i_nearest_prev].pos_;
641 float angle_remains = -
atan2(vec[1], vec[0]);
642 const float angle_pose =
allow_backward_ ? lpath[i_nearest].yaw_ : -angle_remains;
643 float sign_vel = 1.0;
644 if (std::cos(-angle_remains) * std::cos(angle_pose) + std::sin(-angle_remains) * std::sin(angle_pose) < 0)
647 angle_remains = angle_remains + M_PI;
655 "trajectory_tracker: nearest: %d, local goal: %d, done: %d, goal: %lu, remain: %0.3f, remain_local: %0.3f",
656 i_nearest, i_local_goal,
path_step_done_, lpath.size(), distance_remains, remain_local);
658 bool arrive_local_goal(
false);
659 bool in_place_turning = (vec[1] == 0.0 && vec[0] == 0.0);
661 TrackingResult result(trajectory_tracker_msgs::TrajectoryTrackerStatus::FOLLOWING);
664 const bool large_angle_error = std::abs(
rotate_ang_) < M_PI && std::cos(
rotate_ang_) > std::cos(angle_remains);
665 if (large_angle_error ||
670 if (large_angle_error)
672 ROS_INFO_THROTTLE(1.0,
"Stop and rotate due to large angular error: %0.3f", angle_remains);
680 if (it_local_goal != lpath.end())
681 arrive_local_goal =
true;
684 distance_remains = distance_remains_raw = 0.0;
695 float dist_from_path = dist_err;
697 dist_from_path = -(lpath[i_nearest].pos_ - origin).norm();
698 else if (i_nearest + 1 >= static_cast<int>(
path_.size()))
699 dist_from_path = -(lpath[i_nearest].pos_ - origin).norm();
700 if (std::abs(dist_from_path) >
d_stop_)
706 result.
status = trajectory_tracker_msgs::TrajectoryTrackerStatus::FAR_FROM_PATH;
728 it_local_goal == lpath.end())
730 result.
status = trajectory_tracker_msgs::TrajectoryTrackerStatus::GOAL;
733 if (arrive_local_goal)
742 int main(
int argc,
char** argv)
744 ros::init(argc, argv,
"trajectory_tracker");
bool use_time_optimal_control_
void cbSpeed(const std_msgs::Float32::ConstPtr &)
double remainedDistance(const ConstIterator &begin, const ConstIterator &nearest, const ConstIterator &end, const Eigen::Vector2d &target_on_line) const
ros::Publisher pub_status_
TrackingResult(const int s)
void cbOdomTimeout(const ros::TimerEvent &)
TransportHints & reliable()
void cbParameter(const TrajectoryTrackerConfig &config, const uint32_t)
void publish(const boost::shared_ptr< M > &message) const
double goal_tolerance_dist_
void cbTimer(const ros::TimerEvent &)
ros::Publisher pub_tracking_
trajectory_tracker::Path2D path_
std::vector< Pose2D >::const_iterator ConstIterator
float set(float v, const float vel, const float acc, const float dt)
std_msgs::Header path_header_
ConstIterator findLocalGoal(const ConstIterator &begin, const ConstIterator &end, const bool allow_backward_motion) const
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
dynamic_reconfigure::Server< TrajectoryTrackerConfig > parameter_server_
void setPeriod(const Duration &period, bool reset=true)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ConstIterator findNearest(const ConstIterator &begin, const ConstIterator &end, const Eigen::Vector2d &target, const float max_search_range=0, const float epsilon=1e-6) const
trajectory_tracker::VelAccLimitter w_lim_
boost::recursive_mutex parameter_server_mutex_
ros::Subscriber subscribe(ros::NodeHandle &nh_new, const std::string &topic_new, ros::NodeHandle &nh_old, const std::string &topic_old, uint32_t queue_size, void(*fp)(M), const ros::TransportHints &transport_hints=ros::TransportHints())
ros::Subscriber sub_odom_
ROSCPP_DECL void spin(Spinner &spinner)
ros::Timer odom_timeout_timer_
tf2_ros::TransformListener tfl_
double time_optimal_control_future_gain_
std::string topic_cmd_vel_
float getCurvature(const ConstIterator &begin, const ConstIterator &end, const Eigen::Vector2d &target_on_line, const float max_search_range) const
TransportHints & tcpNoDelay(bool nodelay=true)
#define ROS_ERROR_THROTTLE(rate,...)
double stop_tolerance_dist_
double signed_local_distance
double distance_remains_raw
void control(const tf2::Stamped< tf2::Transform > &, const Eigen::Vector3d &, const double)
float lineDistance(const Eigen::Vector2d &a, const Eigen::Vector2d &b, const Eigen::Vector2d &c)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void fromMsg(const A &, B &b)
trajectory_tracker::VelAccLimitter v_lim_
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
void cbPath(const typename MSG_TYPE::ConstPtr &)
ros::Time prev_odom_stamp_
#define ROS_WARN_STREAM(args)
double distance_from_target
double getYaw(const A &a)
Eigen::Vector2d projection2d(const Eigen::Vector2d &a, const Eigen::Vector2d &b, const Eigen::Vector2d &c)
void cbOdometry(const nav_msgs::Odometry::ConstPtr &)
ros::Subscriber sub_path_velocity_
double stop_tolerance_ang_
double tracking_point_curv
float increment(const float v, const float vel, const float acc, const float dt)
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
#define ROS_INFO_THROTTLE(rate,...)
float angleNormalized(float ang)
float timeOptimalControl(const float angle, const float acc)
TrackingResult getTrackingResult(const tf2::Stamped< tf2::Transform > &, const Eigen::Vector3d &) const
void deprecatedParam(const ros::NodeHandle &nh, const std::string &key, T ¶m, const T &default_value)
double goal_tolerance_ang_
int main(int argc, char **argv)
float clip(const float v, const float max)
ros::Subscriber sub_path_