Go to the documentation of this file.00001 #include <cmath>
00002 #include <boost/shared_ptr.hpp>
00003 #include <ros/ros.h>
00004 #include <dynamic_reconfigure/server.h>
00005 #include <cmd_vel_smoother/CmdVelSmootherConfig.h>
00006 #include <geometry_msgs/Twist.h>
00007
00008 template<class T> inline T sgn(T val) { return val > 0 ? 1.0 : -1.0; }
00009
00010 namespace dyn = dynamic_reconfigure;
00011
00012 class VelocitySmootherNode
00013 {
00014 ros::NodeHandle nh_, pnh_;
00015 ros::Publisher pub_;
00016 ros::Subscriber sub_;
00017 ros::Timer timer_;
00018
00019 boost::mutex cfg_mutex_;
00020 typedef cmd_vel_smoother::CmdVelSmootherConfig Config;
00021 boost::shared_ptr<dyn::Server<Config> > dyn_srv_;
00022
00023 int interpolate_max_frame_, count_;
00024 double desired_rate_;
00025 double x_acc_lim_, y_acc_lim_, yaw_acc_lim_;
00026 ros::Time latest_time_;
00027 geometry_msgs::Twist::ConstPtr latest_vel_;
00028 geometry_msgs::Twist::Ptr pub_vel_;
00029
00030 public:
00031 ros::Duration timerDuration() {
00032 return ros::Duration(1./(desired_rate_ * 2.2));
00033 }
00034
00035 void dynConfigCallback(Config &cfg, uint32_t level) {
00036 boost::mutex::scoped_lock lock(cfg_mutex_);
00037 x_acc_lim_ = cfg.x_acc_lim;
00038 y_acc_lim_ = cfg.y_acc_lim;
00039 yaw_acc_lim_ = cfg.yaw_acc_lim;
00040 interpolate_max_frame_ = cfg.interpolate_max_frame;
00041
00042 if(desired_rate_ != cfg.desired_rate) {
00043 desired_rate_ = cfg.desired_rate;
00044 if (timer_.isValid()) {
00045 ros::Duration d = timerDuration();
00046 timer_.setPeriod(d);
00047 ROS_INFO_STREAM("timer loop rate is changed to " << 1.0 / d.toSec() << "[Hz]");
00048 }
00049 }
00050 }
00051
00052 void velCallback(const geometry_msgs::Twist::ConstPtr &msg){
00053 latest_time_ = ros::Time::now();
00054 latest_vel_ = msg;
00055 count_ = 0;
00056 pub_.publish(msg);
00057 }
00058
00059 void timerCallback(const ros::TimerEvent& event){
00060 if (count_ > interpolate_max_frame_) return;
00061 if (latest_vel_ == NULL) return;
00062
00063 double past_sec = (event.current_real - latest_time_).toSec();
00064 if (past_sec < 1.0 / desired_rate_) return;
00065
00066 double g_x = std::abs(latest_vel_->linear.x / past_sec);
00067 double g_y = std::abs(latest_vel_->linear.y / past_sec);
00068 double g_yaw = std::abs(latest_vel_->angular.z / past_sec);
00069
00070 ROS_DEBUG_STREAM("G: (" << g_x << ", " << g_y << ", " << g_yaw << ") detected");
00071
00072 bool need_publish = false;
00073 if (g_x > x_acc_lim_) {
00074 pub_vel_->linear.x = (g_x - x_acc_lim_) * past_sec * sgn(latest_vel_->linear.x);
00075 need_publish = true;
00076 }
00077
00078 if (g_y > y_acc_lim_) {
00079 pub_vel_->linear.y = (g_y - y_acc_lim_) * past_sec * sgn(latest_vel_->linear.y);
00080 need_publish = true;
00081 }
00082
00083 if (g_yaw > yaw_acc_lim_) {
00084 pub_vel_->angular.z = (g_yaw - yaw_acc_lim_) * past_sec * sgn(latest_vel_->angular.z);
00085 need_publish = true;
00086 }
00087
00088 if (need_publish)
00089 pub_.publish(*pub_vel_);
00090 count_++;
00091 }
00092
00093 VelocitySmootherNode(): nh_(), pnh_("~") {
00094 latest_time_ = ros::Time::now();
00095
00096 dyn_srv_ = boost::make_shared<dyn::Server<Config> >(pnh_);
00097 dyn::Server<Config>::CallbackType f = boost::bind(&VelocitySmootherNode::dynConfigCallback, this, _1, _2);
00098 dyn_srv_->setCallback(f);
00099
00100 pub_vel_ = boost::shared_ptr<geometry_msgs::Twist>(new geometry_msgs::Twist());
00101 pub_ = nh_.advertise<geometry_msgs::Twist>("output", 100);
00102 sub_ = nh_.subscribe("input", 1, &VelocitySmootherNode::velCallback, this);
00103 timer_ = nh_.createTimer(timerDuration(), &VelocitySmootherNode::timerCallback, this);
00104 };
00105 ~VelocitySmootherNode() {};
00106
00107 };
00108
00109 int main(int argc, char** argv) {
00110 ros::init(argc, argv, "cmd_vel_smoother");
00111 VelocitySmootherNode n;
00112 ros::spin();
00113
00114 return 0;
00115 }
00116