00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <ros/ros.h>
00022
00023 #include <dynamic_reconfigure/server.h>
00024 #include <cob_base_velocity_smoother/velocity_smoother.h>
00025
00026 #include <boost/thread.hpp>
00027
00028
00029
00030
00031
00032 #define PERIOD_RECORD_SIZE 5
00033 #define ZERO_VEL_COMMAND geometry_msgs::Twist();
00034 #define IS_ZERO_VEOCITY(a) ((a.linear.x == 0.0) && (a.linear.y == 0.0) && (a.angular.z == 0.0))
00035
00036
00037
00038
00039
00040 namespace cob_base_velocity_smoother {
00041
00042
00043
00044
00045
00046 VelocitySmoother::VelocitySmoother(const std::string &name)
00047 : name(name)
00048 , shutdown_req(false)
00049 , input_active(false)
00050 , pr_next(0)
00051 , dynamic_reconfigure_server(NULL)
00052 {
00053 }
00054
00055 void VelocitySmoother::reconfigCB(cob_base_velocity_smoother::paramsConfig &config, uint32_t level)
00056 {
00057 ROS_INFO("Reconfigure request : %f %f %f %f %f %f %f %f",
00058 config.speed_lim_vx, config.speed_lim_vy, config.speed_lim_w, config.accel_lim_vx, config.accel_lim_vy, config.accel_lim_w, config.decel_factor, config.decel_factor_safe);
00059
00060 speed_lim_vx = config.speed_lim_vx;
00061 speed_lim_vy = config.speed_lim_vy;
00062 speed_lim_w = config.speed_lim_w;
00063 accel_lim_vx = config.accel_lim_vx;
00064 accel_lim_vy = config.accel_lim_vy;
00065 accel_lim_w = config.accel_lim_w;
00066 decel_factor = config.decel_factor;
00067 decel_factor_safe = config.decel_factor_safe;
00068 decel_lim_vx = decel_factor*accel_lim_vx;
00069 decel_lim_vy = decel_factor*accel_lim_vy;
00070 decel_lim_w = decel_factor*accel_lim_w;
00071 decel_lim_vx_safe = decel_factor_safe*accel_lim_vx;
00072 decel_lim_vy_safe = decel_factor_safe*accel_lim_vy;
00073 decel_lim_w_safe = decel_factor_safe*accel_lim_w;
00074 }
00075
00076 void VelocitySmoother::velocityCB(const geometry_msgs::Twist::ConstPtr& msg)
00077 {
00078
00079
00080 if (period_record.size() < PERIOD_RECORD_SIZE)
00081 {
00082 period_record.push_back((ros::Time::now() - last_cb_time).toSec());
00083 }
00084 else
00085 {
00086 period_record[pr_next] = (ros::Time::now() - last_cb_time).toSec();
00087 }
00088
00089 pr_next++;
00090 pr_next %= period_record.size();
00091 last_cb_time = ros::Time::now();
00092
00093 if (period_record.size() <= PERIOD_RECORD_SIZE/2)
00094 {
00095
00096 cb_avg_time = 0.1;
00097 }
00098 else
00099 {
00100
00101 cb_avg_time = median(period_record);
00102 }
00103
00104 input_active = true;
00105
00106
00107 target_vel.linear.x =
00108 msg->linear.x > 0.0 ? std::min(msg->linear.x, speed_lim_vx) : std::max(msg->linear.x, -speed_lim_vx);
00109 target_vel.linear.y =
00110 msg->linear.y > 0.0 ? std::min(msg->linear.y, speed_lim_vy) : std::max(msg->linear.y, -speed_lim_vy);
00111 target_vel.angular.z =
00112 msg->angular.z > 0.0 ? std::min(msg->angular.z, speed_lim_w) : std::max(msg->angular.z, -speed_lim_w);
00113 }
00114
00115 void VelocitySmoother::odometryCB(const nav_msgs::Odometry::ConstPtr& msg)
00116 {
00117 if (robot_feedback == ODOMETRY)
00118 current_vel = msg->twist.twist;
00119
00120
00121 }
00122
00123 void VelocitySmoother::robotVelCB(const geometry_msgs::Twist::ConstPtr& msg)
00124 {
00125 if (robot_feedback == COMMANDS)
00126 current_vel = *msg;
00127
00128
00129 }
00130
00131 void VelocitySmoother::spin()
00132 {
00133 double period = 1.0/frequency;
00134 ros::Rate spin_rate(frequency);
00135
00136 double decel_vx;
00137 double decel_vy;
00138 double decel_w;
00139
00140 while (! shutdown_req && ros::ok())
00141 {
00142 if ((input_active == true) && (cb_avg_time > 0.0) &&
00143 ((ros::Time::now() - last_cb_time).toSec() > std::min(3.0*cb_avg_time, 0.5)))
00144 {
00145
00146
00147
00148
00149
00150 input_active = false;
00151 if (IS_ZERO_VEOCITY(target_vel) == false)
00152 {
00153 ROS_WARN_STREAM("Velocity Smoother : input got inactive leaving us a non-zero target velocity ("
00154 << target_vel.linear.x << ", " << target_vel.linear.y << ", " << target_vel.angular.z << "), zeroing...[" << name << "]");
00155 target_vel = ZERO_VEL_COMMAND;
00156 }
00157 }
00158
00159 if(input_active)
00160 {
00161 decel_vx = decel_lim_vx;
00162 decel_vy = decel_lim_vy;
00163 decel_w = decel_lim_w;
00164 }
00165 else
00166 {
00167
00168 decel_vx = decel_lim_vx_safe;
00169 decel_vy = decel_lim_vy_safe;
00170 decel_w = decel_lim_w_safe;
00171 }
00172
00173 if ((robot_feedback != NONE) && (input_active == true) && (cb_avg_time > 0.0) &&
00174 (((ros::Time::now() - last_cb_time).toSec() > 5.0*cb_avg_time) ||
00175 (std::abs(current_vel.linear.x - last_cmd_vel.linear.x) > 0.2) ||
00176 (std::abs(current_vel.linear.y - last_cmd_vel.linear.y) > 0.2) ||
00177 (std::abs(current_vel.angular.z - last_cmd_vel.angular.z) > 2.0)))
00178 {
00179
00180
00181
00182
00183
00184
00185
00186 ROS_WARN("Using robot velocity feedback (%s) instead of last command: %f, %f, %f, %f",
00187 robot_feedback == ODOMETRY ? "odometry" : "end commands",
00188 (ros::Time::now() - last_cb_time).toSec(),
00189 current_vel.linear.x - last_cmd_vel.linear.x,
00190 current_vel.linear.y - last_cmd_vel.linear.y,
00191 current_vel.angular.z - last_cmd_vel.angular.z);
00192 last_cmd_vel = current_vel;
00193 }
00194
00195 geometry_msgs::TwistPtr cmd_vel;
00196
00197 if ((target_vel.linear.x != last_cmd_vel.linear.x) ||
00198 (target_vel.linear.y != last_cmd_vel.linear.y) ||
00199 (target_vel.angular.z != last_cmd_vel.angular.z))
00200 {
00201
00202 cmd_vel.reset(new geometry_msgs::Twist(target_vel));
00203
00204 double vx_inc, vy_inc, w_inc, max_vx_inc, max_vy_inc, max_w_inc;
00205
00206 vx_inc = target_vel.linear.x - last_cmd_vel.linear.x;
00207 if ((robot_feedback == ODOMETRY) && (current_vel.linear.x*target_vel.linear.x < 0.0))
00208 {
00209
00210 max_vx_inc = decel_vx*period;
00211 }
00212 else
00213 {
00214 max_vx_inc = ((vx_inc*target_vel.linear.x > 0.0)?accel_lim_vx:decel_vx)*period;
00215 }
00216
00217 vy_inc = target_vel.linear.y - last_cmd_vel.linear.y;
00218 if ((robot_feedback == ODOMETRY) && (current_vel.linear.y*target_vel.linear.y < 0.0))
00219 {
00220
00221 max_vy_inc = decel_vy*period;
00222 }
00223 else
00224 {
00225 max_vy_inc = ((vy_inc*target_vel.linear.x > 0.0)?accel_lim_vy:decel_vy)*period;
00226 }
00227
00228 w_inc = target_vel.angular.z - last_cmd_vel.angular.z;
00229 if ((robot_feedback == ODOMETRY) && (current_vel.angular.z*target_vel.angular.z < 0.0))
00230 {
00231
00232 max_w_inc = decel_w*period;
00233 }
00234 else
00235 {
00236 max_w_inc = ((w_inc*target_vel.angular.z > 0.0)?accel_lim_w:decel_w)*period;
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 if (std::abs(vx_inc) > max_vx_inc)
00264 {
00265
00266 cmd_vel->linear.x = last_cmd_vel.linear.x + sign(vx_inc)*max_vx_inc;
00267 }
00268
00269 if (std::abs(vy_inc) > max_vy_inc)
00270 {
00271
00272 cmd_vel->linear.y = last_cmd_vel.linear.y + sign(vy_inc)*max_vy_inc;
00273 }
00274
00275 if (std::abs(w_inc) > max_w_inc)
00276 {
00277
00278 cmd_vel->angular.z = last_cmd_vel.angular.z + sign(w_inc)*max_w_inc;
00279 }
00280
00281 smooth_vel_pub.publish(cmd_vel);
00282 last_cmd_vel = *cmd_vel;
00283 }
00284 else if (input_active == true)
00285 {
00286
00287 cmd_vel.reset(new geometry_msgs::Twist(last_cmd_vel));
00288 smooth_vel_pub.publish(cmd_vel);
00289 }
00290
00291 spin_rate.sleep();
00292 }
00293 }
00294
00300 bool VelocitySmoother::init(ros::NodeHandle& nh)
00301 {
00302
00303 dynamic_reconfigure_callback = boost::bind(&VelocitySmoother::reconfigCB, this, _1, _2);
00304
00305 dynamic_reconfigure_server = new dynamic_reconfigure::Server<cob_base_velocity_smoother::paramsConfig>(nh);
00306 dynamic_reconfigure_server->setCallback(dynamic_reconfigure_callback);
00307
00308
00309 int feedback;
00310 nh.param("frequency", frequency, 20.0);
00311 nh.param("decel_factor", decel_factor, 1.0);
00312 nh.param("decel_factor_safe", decel_factor_safe, 1.0);
00313 nh.param("robot_feedback", feedback, (int)NONE);
00314
00315 if ((int(feedback) < NONE) || (int(feedback) > COMMANDS))
00316 {
00317 ROS_WARN("Invalid robot feedback type (%d). Valid options are 0 (NONE, default), 1 (ODOMETRY) and 2 (COMMANDS)",
00318 feedback);
00319 feedback = NONE;
00320 }
00321
00322 robot_feedback = static_cast<RobotFeedbackType>(feedback);
00323
00324
00325 if ((nh.getParam("speed_lim_vx", speed_lim_vx) == false) ||
00326 (nh.getParam("speed_lim_vy", speed_lim_vy) == false) ||
00327 (nh.getParam("speed_lim_w", speed_lim_w) == false))
00328 {
00329 ROS_ERROR("Missing velocity limit parameter(s)");
00330 return false;
00331 }
00332
00333 if ((nh.getParam("accel_lim_vx", accel_lim_vx) == false) ||
00334 (nh.getParam("accel_lim_vy", accel_lim_vy) == false) ||
00335 (nh.getParam("accel_lim_w", accel_lim_w) == false))
00336 {
00337 ROS_ERROR("Missing acceleration limit parameter(s)");
00338 return false;
00339 }
00340
00341
00342 decel_lim_vx = decel_factor*accel_lim_vx;
00343 decel_lim_vy = decel_factor*accel_lim_vy;
00344 decel_lim_w = decel_factor*accel_lim_w;
00345
00346 decel_lim_vx_safe = decel_factor_safe*accel_lim_vx;
00347 decel_lim_vy_safe = decel_factor_safe*accel_lim_vy;
00348 decel_lim_w_safe = decel_factor_safe*accel_lim_w;
00349
00350
00351 odometry_sub = nh.subscribe("odometry", 1, &VelocitySmoother::odometryCB, this);
00352 current_vel_sub = nh.subscribe("robot_cmd_vel", 1, &VelocitySmoother::robotVelCB, this);
00353 raw_in_vel_sub = nh.subscribe("raw_cmd_vel", 1, &VelocitySmoother::velocityCB, this);
00354 smooth_vel_pub = nh.advertise <geometry_msgs::Twist> ("smooth_cmd_vel", 1);
00355
00356 return true;
00357 }
00358 }