00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <angles/angles.h>
00039 #include <pluginlib/class_list_macros.h>
00040 #include <robot_controllers/diff_drive_base.h>
00041
00042 PLUGINLIB_EXPORT_CLASS(robot_controllers::DiffDriveBaseController, robot_controllers::Controller)
00043
00044 namespace robot_controllers
00045 {
00046
00047 DiffDriveBaseController::DiffDriveBaseController() :
00048 initialized_(false),
00049 safety_scaling_(1.0)
00050 {
00051 theta_ = 0.0;
00052
00053 odom_.pose.pose.orientation.z = 0.0;
00054 odom_.pose.pose.orientation.w = 1.0;
00055
00056 last_sent_x_ = desired_x_ = 0.0;
00057 last_sent_r_ = desired_r_ = 0.0;
00058
00059 left_last_timestamp_ = right_last_timestamp_ = 0.0;
00060 last_command_ = last_update_ = ros::Time(0.0);
00061 }
00062
00063 int DiffDriveBaseController::init(ros::NodeHandle& nh, ControllerManager* manager)
00064 {
00065
00066 if (!manager)
00067 {
00068 ROS_ERROR_NAMED("BaseController", "No controller manager available.");
00069 initialized_ = false;
00070 return -1;
00071 }
00072
00073 Controller::init(nh, manager);
00074 manager_ = manager;
00075
00076
00077 std::string l_name, r_name;
00078 nh.param<std::string>("l_wheel_joint", l_name, "l_wheel_joint");
00079 nh.param<std::string>("r_wheel_joint", r_name, "r_wheel_joint");
00080 left_ = manager_->getJointHandle(l_name);
00081 right_ = manager_->getJointHandle(r_name);
00082 if (left_ == NULL || right_ == NULL)
00083 {
00084 ROS_ERROR_NAMED("BaseController", "Cannot get wheel joints.");
00085 initialized_ = false;
00086 return -1;
00087 }
00088 left_last_position_ = left_->getPosition();
00089 right_last_position_ = right_->getPosition();
00090 last_update_ = ros::Time::now();
00091
00092
00093 nh.param<double>("track_width", track_width_, 0.37476);
00094 nh.param<double>("radians_per_meter", radians_per_meter_, 16.5289);
00095
00096
00097
00098 nh.param<bool>("publish_tf", publish_tf_, true);
00099
00100
00101 nh.param<std::string>("odometry_frame", odom_.header.frame_id, "odom");
00102
00103
00104 nh.param<std::string>("base_frame", odom_.child_frame_id, "base_link");
00105
00106
00107 nh.param<double>("wheel_rotating_threshold", wheel_rotating_threshold_, 0.001);
00108 nh.param<double>("rotating_threshold", rotating_threshold_, 0.05);
00109 nh.param<double>("moving_threshold", moving_threshold_, 0.05);
00110
00111 double t;
00112 nh.param<double>("timeout", t, 0.25);
00113 timeout_ = ros::Duration(t);
00114
00115
00116 nh.param<double>("max_velocity_x", max_velocity_x_, 1.0);
00117 nh.param<double>("max_velocity_r", max_velocity_r_, 4.5);
00118 nh.param<double>("max_acceleration_x", max_acceleration_x_, 0.75);
00119 nh.param<double>("max_acceleration_r", max_acceleration_r_, 3.0);
00120
00121
00122 cmd_sub_ = nh.subscribe<geometry_msgs::Twist>("command", 1,
00123 boost::bind(&DiffDriveBaseController::command, this, _1));
00124
00125
00126 ros::NodeHandle n;
00127 odom_pub_ = n.advertise<nav_msgs::Odometry>("odom", 10);
00128 if (publish_tf_)
00129 broadcaster_.reset(new tf::TransformBroadcaster());
00130
00131
00132 double publish_frequency;
00133 nh.param<double>("publish_frequency", publish_frequency, 100.0);
00134 odom_timer_ = n.createTimer(ros::Duration(1/publish_frequency),
00135 &DiffDriveBaseController::publishCallback,
00136 this);
00137
00138
00139 nh.param<double>("laser_safety_dist", safety_scaling_distance_, 0.0);
00140 nh.param<double>("robot_safety_width", robot_width_, 0.7);
00141 if (safety_scaling_distance_ > 0.0)
00142 {
00143 scan_sub_ = n.subscribe<sensor_msgs::LaserScan>("base_scan", 1,
00144 boost::bind(&DiffDriveBaseController::scanCallback, this, _1));
00145 }
00146
00147 initialized_ = true;
00148
00149
00150 bool autostart;
00151 nh.param("autostart", autostart, false);
00152 if (autostart)
00153 manager->requestStart(getName());
00154
00155 return 0;
00156 }
00157
00158 void DiffDriveBaseController::command(const geometry_msgs::TwistConstPtr& msg)
00159 {
00160 if (!initialized_)
00161 {
00162 ROS_ERROR_NAMED("BaseController", "Unable to accept command, not initialized.");
00163 return;
00164 }
00165
00166 if (std::isfinite(msg->linear.x) && std::isfinite(msg->angular.z))
00167 {
00168 boost::mutex::scoped_lock lock(command_mutex_);
00169 last_command_ = ros::Time::now();
00170 desired_x_ = msg->linear.x;
00171 desired_r_ = msg->angular.z;
00172 }
00173 else
00174 {
00175 ROS_ERROR_NAMED("BaseController", "Commanded velocities not finite!");
00176 return;
00177 }
00178
00179 manager_->requestStart(getName());
00180 }
00181
00182 bool DiffDriveBaseController::start()
00183 {
00184 if (!initialized_)
00185 {
00186 ROS_ERROR_NAMED("BaseController", "Unable to start, not initialized.");
00187 return false;
00188 }
00189
00190 return true;
00191 }
00192
00193 bool DiffDriveBaseController::stop(bool force)
00194 {
00195
00196 if (last_update_ - last_command_ >= timeout_)
00197 return true;
00198
00199
00200 if (last_sent_x_ == 0.0 && last_sent_r_ == 0.0)
00201 return true;
00202
00203
00204 if (force)
00205 return true;
00206
00207 return false;
00208 }
00209
00210 bool DiffDriveBaseController::reset()
00211 {
00212
00213 last_command_ = ros::Time(0);
00214 return true;
00215 }
00216
00217 void DiffDriveBaseController::update(const ros::Time& now, const ros::Duration& dt)
00218 {
00219 if (!initialized_)
00220 return;
00221
00222
00223 if (now - last_command_ >= timeout_)
00224 {
00225 ROS_DEBUG_THROTTLE_NAMED(5, "BaseController", "Command timed out.");
00226 boost::mutex::scoped_lock lock(command_mutex_);
00227 desired_x_ = desired_r_ = 0.0;
00228 }
00229
00230
00231 if ((safety_scaling_distance_ > 0.0) &&
00232 (ros::Time::now() - last_laser_scan_ > ros::Duration(0.5)))
00233 {
00234 safety_scaling_ = 0.1;
00235 }
00236
00237
00238 double x, r;
00239 {
00240 boost::mutex::scoped_lock lock(command_mutex_);
00241
00242 x = std::max(-max_velocity_x_ * safety_scaling_, std::min(desired_x_, max_velocity_x_ * safety_scaling_));
00243
00244 double actual_scaling = 1.0;
00245 if (desired_x_ != 0.0)
00246 actual_scaling = x/desired_x_;
00247
00248
00249 r = std::max(-max_velocity_r_, std::min(actual_scaling * desired_r_, max_velocity_r_));
00250 }
00251 if (x > last_sent_x_)
00252 {
00253 last_sent_x_ += max_acceleration_x_ * (now - last_update_).toSec();
00254 if (last_sent_x_ > x)
00255 last_sent_x_ = x;
00256 }
00257 else
00258 {
00259 last_sent_x_ -= max_acceleration_x_ * (now - last_update_).toSec();
00260 if (last_sent_x_ < x)
00261 last_sent_x_ = x;
00262 }
00263 if (r > last_sent_r_)
00264 {
00265 last_sent_r_ += max_acceleration_r_ * (now - last_update_).toSec();
00266 if (last_sent_r_ > r)
00267 last_sent_r_ = r;
00268 }
00269 else
00270 {
00271 last_sent_r_ -= max_acceleration_r_ * (now - last_update_).toSec();
00272 if (last_sent_r_ < r)
00273 last_sent_r_ = r;
00274 }
00275
00276 double dx = 0.0;
00277 double dr = 0.0;
00278
00279 double left_pos = left_->getPosition();
00280 double right_pos = right_->getPosition();
00281 double left_dx = angles::shortest_angular_distance(left_last_position_, left_pos)/radians_per_meter_;
00282 double right_dx = angles::shortest_angular_distance(right_last_position_, right_pos)/radians_per_meter_;
00283 double left_vel = static_cast<double>(left_->getVelocity())/radians_per_meter_;
00284 double right_vel = static_cast<double>(right_->getVelocity())/radians_per_meter_;
00285
00286
00287 if (fabs(left_dx) > wheel_rotating_threshold_ ||
00288 fabs(right_dx) > wheel_rotating_threshold_ ||
00289 last_sent_x_ != 0.0 ||
00290 last_sent_r_ != 0.0)
00291 {
00292
00293 left_last_position_ = left_pos;
00294 right_last_position_ = right_pos;
00295 }
00296 else
00297 {
00298
00299 left_dx = right_dx = 0.0;
00300 left_vel = right_vel = 0.0;
00301 }
00302
00303
00304 double d = (left_dx+right_dx)/2.0;
00305 double th = (right_dx-left_dx)/track_width_;
00306
00307
00308 dx = (left_vel + right_vel)/2.0;
00309 dr = (right_vel - left_vel)/track_width_;
00310
00311
00312 if (fabs(dx) > moving_threshold_ ||
00313 fabs(dr) > rotating_threshold_ ||
00314 last_sent_x_ != 0.0 ||
00315 last_sent_r_ != 0.0)
00316 {
00317 setCommand(last_sent_x_ - (last_sent_r_/2.0 * track_width_),
00318 last_sent_x_ + (last_sent_r_/2.0 * track_width_));
00319 }
00320
00321
00322 boost::mutex::scoped_lock lock(odom_mutex_);
00323
00324
00325 theta_ += th/2.0;
00326 odom_.pose.pose.position.x += d*cos(theta_);
00327 odom_.pose.pose.position.y += d*sin(theta_);
00328 theta_ += th/2.0;
00329 odom_.pose.pose.orientation.z = sin(theta_/2.0);
00330 odom_.pose.pose.orientation.w = cos(theta_/2.0);
00331
00332 odom_.twist.twist.linear.x = dx;
00333 odom_.twist.twist.angular.z = dr;
00334
00335 last_update_ = now;
00336 }
00337
00338 std::vector<std::string> DiffDriveBaseController::getCommandedNames()
00339 {
00340 std::vector<std::string> names;
00341 if (left_)
00342 names.push_back(left_->getName());
00343 if (right_)
00344 names.push_back(right_->getName());
00345 return names;
00346 }
00347
00348 std::vector<std::string> DiffDriveBaseController::getClaimedNames()
00349 {
00350
00351 return getCommandedNames();
00352 }
00353
00354 void DiffDriveBaseController::publishCallback(const ros::TimerEvent& event)
00355 {
00356
00357 nav_msgs::Odometry msg;
00358 {
00359 boost::mutex::scoped_lock lock(odom_mutex_);
00360 msg = odom_;
00361 }
00362
00363
00364 msg.header.stamp = ros::Time::now();
00365 odom_pub_.publish(msg);
00366
00367 if (publish_tf_)
00368 {
00369 tf::Transform transform;
00370 transform.setOrigin(tf::Vector3(msg.pose.pose.position.x, msg.pose.pose.position.y, 0.0));
00371 transform.setRotation(tf::Quaternion(msg.pose.pose.orientation.x,
00372 msg.pose.pose.orientation.y,
00373 msg.pose.pose.orientation.z,
00374 msg.pose.pose.orientation.w) );
00375
00376
00377
00378
00379 broadcaster_->sendTransform(tf::StampedTransform(transform, msg.header.stamp, msg.header.frame_id, msg.child_frame_id));
00380 }
00381 }
00382
00383 void DiffDriveBaseController::scanCallback(
00384 const sensor_msgs::LaserScanConstPtr& scan)
00385 {
00386 double angle = scan->angle_min;
00387 double min_dist = safety_scaling_distance_;
00388
00389 for (size_t i = 0; i < scan->ranges.size(); ++i, angle += scan->angle_increment)
00390 {
00391 if (std::isfinite(scan->ranges[i]) &&
00392 scan->ranges[i] > scan->range_min &&
00393 scan->ranges[i] < min_dist)
00394 {
00395
00396 if (angle < -1.5 || angle > 1.5)
00397 continue;
00398
00399
00400 double py = sin(angle) * scan->ranges[i];
00401 if (fabs(py) < (robot_width_/2.0))
00402 min_dist = scan->ranges[i];
00403 }
00404 }
00405
00406 boost::mutex::scoped_lock lock(command_mutex_);
00407 safety_scaling_ = std::max(0.1, min_dist / safety_scaling_distance_);
00408 last_laser_scan_ = ros::Time::now();
00409 }
00410
00411 void DiffDriveBaseController::setCommand(float left, float right)
00412 {
00413
00414 left_->setVelocity(left * radians_per_meter_, 0.0);
00415 right_->setVelocity(right * radians_per_meter_, 0.0);
00416 }
00417
00418 }