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 #include <mobility_base_gazebo_plugins/MobilityBasePlugin.h>
00036
00037 namespace gazebo
00038 {
00039
00040 MobilityBasePlugin::MobilityBasePlugin() :
00041 nh_(NULL), spinner_thread_(NULL), tf_broadcaster_(NULL), first_update_(true), fast_(true)
00042 {
00043 omni_a_ = 1.0 / WHEEL_RADIUS;
00044 omni_b_ = 1.0 / WHEEL_RADIUS;
00045 omni_c_ = 0.5 * (WHEEL_BASE_WIDTH + WHEEL_BASE_LENGTH) / WHEEL_RADIUS;
00046 frame_id_ = "/base_footprint";
00047 mode_ = mobility_base_core_msgs::Mode::MODE_DISABLED;
00048 }
00049 MobilityBasePlugin::~MobilityBasePlugin()
00050 {
00051 if (nh_) {
00052 delete nh_;
00053 }
00054 if (spinner_thread_) {
00055 delete spinner_thread_;
00056 }
00057 }
00058 void MobilityBasePlugin::FiniChild()
00059 {
00060 nh_->shutdown();
00061 spinner_thread_->join();
00062 }
00063
00064 void MobilityBasePlugin::omniFromCartesian(double vx, double vy, double wz, double w[4]) const {
00065 w[0] = omni_a_ * vx - omni_b_ * vy - omni_c_ * wz;
00066 w[1] = omni_a_ * vx + omni_b_ * vy + omni_c_ * wz;
00067 w[2] = omni_a_ * vx + omni_b_ * vy - omni_c_ * wz;
00068 w[3] = omni_a_ * vx - omni_b_ * vy + omni_c_ * wz;
00069 }
00070
00071
00072
00073
00074
00075
00076
00077
00078 void MobilityBasePlugin::omniToCartesian(const double w[4], double *vx, double *vy, double *wz) const {
00079
00080
00081
00082 }
00083
00084 void MobilityBasePlugin::Load(physics::ModelPtr parent, sdf::ElementPtr sdf)
00085 {
00086 first_update_ = true;
00087
00088
00089 model_ = parent;
00090 world_ = model_->GetWorld();
00091
00092
00093 std::string model_name = sdf->GetParent()->Get<std::string>("name");
00094 gzdbg << "MobilityBasePlugin loaded for model '" << model_name << "'\n";
00095
00096
00097 if (sdf->HasElement("fast")) {
00098 std::string comp = "true";
00099 fast_ = comp.compare(sdf->GetElement("fast")->Get<std::string>()) ? false : true;
00100 }
00101 if (sdf->HasElement("parent_frame_id")) {
00102 parent_frame_id_ = sdf->GetElement("parent_frame_id")->Get<std::string>();
00103 if (sdf->HasElement("child_frame_id")) {
00104 child_frame_id_ = sdf->GetElement("child_frame_id")->Get<std::string>();
00105 } else {
00106 child_frame_id_ = frame_id_;
00107 }
00108 tf_broadcaster_ = new tf::TransformBroadcaster();
00109 }
00110
00111
00112 link_base_footprint_ = model_->GetLink("base_footprint");
00113
00114 joint_state_wheels_.name.push_back("wheel_fl");
00115 joint_state_wheels_.name.push_back("wheel_fr");
00116 joint_state_wheels_.name.push_back("wheel_rl");
00117 joint_state_wheels_.name.push_back("wheel_rr");
00118
00119
00120 for (unsigned int i = 0; i < NUM_WHEELS; i++) {
00121
00122 const std::string &wheel = joint_state_wheels_.name[i];
00123 joint_wheels_[i] = parent->GetJoint(wheel);
00124 if (joint_wheels_[i]) {
00125 joint_wheels_[i]->SetDamping(0, 0.1);
00126 joint_state_wheels_.position.push_back(0);
00127 joint_state_wheels_.velocity.push_back(0);
00128 joint_state_wheels_.effort.push_back(0);
00129 } else {
00130 gzerr << "Failed to find joint '" << wheel << "' in the model\n";
00131 return;
00132 }
00133 if (!fast_) {
00134
00135 for (unsigned int j = 0; j < NUM_ROLLERS; j++) {
00136 std::stringstream ss;
00137 ss << wheel << "_roller_" << j;
00138 std::string roller = ss.str();
00139 joint_rollers_[i][j] = parent->GetJoint(roller);
00140 if (joint_rollers_[i][j]) {
00141 joint_rollers_[i][j]->SetDamping(0, 0.0005);
00142 joint_state_rollers_.name.push_back(roller);
00143 joint_state_rollers_.position.push_back(0);
00144 joint_state_rollers_.velocity.push_back(0);
00145 joint_state_rollers_.effort.push_back(0);
00146 } else {
00147 gzerr << "Failed to find joint '" << roller << "' in the model\n";
00148 return;
00149 }
00150 }
00151 }
00152 }
00153
00154
00155 int argc = 0;
00156 char** argv = NULL;
00157 ros::init(argc, argv, "gazebo_mobility_base", ros::init_options::NoSigintHandler | ros::init_options::AnonymousName);
00158 nh_ = new ros::NodeHandle("/mobility_base");
00159
00160
00161 pub_imu_data_ = nh_->advertise<sensor_msgs::Imu>("imu/data_raw", 10, false);
00162 pub_imu_mag_ = nh_->advertise<sensor_msgs::MagneticField>("imu/mag", 10, false);
00163 pub_imu_is_calibrated_ = nh_->advertise<std_msgs::Bool>("imu/is_calibrated", 1, true);
00164 pub_twist_ = nh_->advertise<geometry_msgs::TwistStamped>("twist", 10, false);
00165 pub_wrench_ = nh_->advertise<geometry_msgs::WrenchStamped>("wrench", 10, false);
00166 pub_joint_states_ = nh_->advertise<sensor_msgs::JointState>("joint_states", 10, false);
00167 pub_joystick_ = nh_->advertise<geometry_msgs::TwistStamped>("joystick", 10, false);
00168 pub_bumper_states_ = nh_->advertise<mobility_base_core_msgs::BumperState>("bumper_states", 10, true);
00169 pub_mode_ = nh_->advertise<mobility_base_core_msgs::Mode>("mode", 1, true);
00170
00171
00172 pmq_.startServiceThread();
00173 pmq_imu_data_ = pmq_.addPub<sensor_msgs::Imu>();
00174 pmq_imu_mag_ = pmq_.addPub<sensor_msgs::MagneticField>();
00175 pmq_imu_is_calibrated_ = pmq_.addPub<std_msgs::Bool>();
00176 pmq_twist_ = pmq_.addPub<geometry_msgs::TwistStamped>();
00177 pmq_wrench_ = pmq_.addPub<geometry_msgs::WrenchStamped>();
00178 pmq_joint_states_ = pmq_.addPub<sensor_msgs::JointState>();
00179 pmq_joystick_ = pmq_.addPub<geometry_msgs::TwistStamped>();
00180 pmq_bumper_states_ = pmq_.addPub<mobility_base_core_msgs::BumperState>();
00181 pmq_mode_ = pmq_.addPub<mobility_base_core_msgs::Mode>();
00182
00183
00184 sub_cmd_vel_ = nh_->subscribe("cmd_vel", 1, &MobilityBasePlugin::recvCmdVel, this);
00185 sub_cmd_vel_raw_ = nh_->subscribe("cmd_vel_raw", 1, &MobilityBasePlugin::recvCmdVelRaw, this);
00186
00187
00188 publishMode(ros::Time(0));
00189 std_msgs::Bool msg;
00190 msg.data = true;
00191 pmq_imu_is_calibrated_->push(msg, pub_imu_is_calibrated_);
00192
00193
00194 spinner_thread_ = new boost::thread(boost::bind( &MobilityBasePlugin::spin, this));
00195 update_connection_ = event::Events::ConnectWorldUpdateBegin(boost::bind(&MobilityBasePlugin::UpdateChild, this, _1));
00196 }
00197
00198
00199 void MobilityBasePlugin::UpdateChild(const common::UpdateInfo & _info)
00200 {
00201 const common::Time gstamp = world_->GetSimTime();
00202 const ros::Time rstamp(gstamp.sec, gstamp.nsec);
00203 const double ts = (gstamp - previous_stamp_).Double();
00204
00205
00206 std_msgs::Header header;
00207 header.stamp = rstamp;
00208 header.frame_id = frame_id_;
00209
00210
00211 math::Vector3 linear_vel;
00212 math::Vector3 angular_vel;
00213 math::Vector3 linear_accel;
00214 math::Vector3 angular_pos;
00215 math::Quaternion orientation;
00216 math::Vector3 position;
00217
00218 linear_vel = model_->GetRelativeLinearVel();
00219 angular_vel = model_->GetRelativeAngularVel();
00220 linear_accel = model_->GetRelativeLinearAccel();
00221 angular_pos = model_->GetWorldPose().rot.GetAsEuler();
00222 orientation = model_->GetWorldPose().rot;
00223 position = model_->GetWorldPose().pos;
00224
00225 const math::Vector3 fb_vel(linear_vel.x, linear_vel.y, angular_vel.z);
00226
00227
00228 if (first_update_) {
00229 stamp_vehicle_ = gstamp;
00230 stamp_imu_ = gstamp;
00231 stamp_joystick_ = gstamp;
00232 stamp_bumpers_ = gstamp;
00233 stamp_mode_ = gstamp;
00234 cmd_vel_history_ = math::Vector3::Zero;
00235
00236 } else {
00237
00238 math::Vector3 cmd = math::Vector3::Zero;
00239 mobility_base_core_msgs::Mode::_mode_type mode = mobility_base_core_msgs::Mode::MODE_TIMEOUT;
00240 {
00241 boost::lock_guard<boost::mutex> lock1(cmd_vel_mutex_);
00242 boost::lock_guard<boost::mutex> lock2(cmd_vel_raw_mutex_);
00243 if (cmd_vel_stamp_ > cmd_vel_raw_stamp_) {
00244 if (gstamp - cmd_vel_stamp_ < common::Time(CMD_TIMEOUT)) {
00245 cmd = cmd_vel_;
00246 mode = mobility_base_core_msgs::Mode::MODE_VELOCITY;
00247 }
00248 } else {
00249 if (gstamp - cmd_vel_raw_stamp_ < common::Time(CMD_TIMEOUT)) {
00250 cmd = cmd_vel_raw_;
00251 mode = mobility_base_core_msgs::Mode::MODE_VELOCITY_RAW;
00252 }
00253 }
00254 }
00255
00256
00257 math::Vector3 accel_limit;
00258 switch (mode) {
00259 case mobility_base_core_msgs::Mode::MODE_VELOCITY:
00260 accel_limit.x = ACCEL_LIMIT_SLOW_VXY;
00261 accel_limit.y = ACCEL_LIMIT_SLOW_VXY;
00262 accel_limit.z = ACCEL_LIMIT_SLOW_WZ;
00263 break;
00264 case mobility_base_core_msgs::Mode::MODE_VELOCITY_RAW:
00265 case mobility_base_core_msgs::Mode::MODE_TIMEOUT:
00266 default:
00267 accel_limit.x = ACCEL_LIMIT_FAST_VXY;
00268 accel_limit.y = ACCEL_LIMIT_FAST_VXY;
00269 accel_limit.z = ACCEL_LIMIT_FAST_WZ;
00270 break;
00271 }
00272
00273
00274 if (mode != mode_) {
00275 cmd_vel_history_ = fb_vel;
00276 }
00277
00278
00279 math::Vector3 temp;
00280 temp.x = limitDelta(cmd.x, cmd_vel_history_.x, accel_limit.x * ts);
00281 temp.y = limitDelta(cmd.y, cmd_vel_history_.y, accel_limit.y * ts);
00282 temp.z = limitDelta(cmd.z, cmd_vel_history_.z, accel_limit.z * ts);
00283
00284
00285 temp.x = limitDelta(temp.x, fb_vel.x, ACCEL_INSTANT_VXY);
00286 temp.y = limitDelta(temp.y, fb_vel.y, ACCEL_INSTANT_VXY);
00287 temp.z = limitDelta(temp.z, fb_vel.z, ACCEL_INSTANT_WZ);
00288
00289
00290 double speed[4];
00291 omniFromCartesian(temp.x, temp.y, temp.z, speed);
00292 if (omniSaturate(RADIANS_PER_SECOND_MAX, speed)) {
00293 cmd_vel_history_ = fb_vel;
00294 } else {
00295 cmd_vel_history_ = temp;
00296 }
00297
00298 if (fast_) {
00299
00300 math::Vector3 linear_vel = orientation.RotateVector(math::Vector3(temp.x, temp.y, 0.0));
00301 math::Vector3 linear_vel_orig = link_base_footprint_->GetRelativeLinearVel();
00302 math::Vector3 angular_vel_orig = link_base_footprint_->GetRelativeAngularVel();
00303 link_base_footprint_->SetLinearVel(math::Vector3(GAIN_X * linear_vel.x, GAIN_Y * linear_vel.y, linear_vel_orig.z + linear_vel.z));
00304 link_base_footprint_->SetAngularVel(math::Vector3(angular_vel_orig.x, angular_vel_orig.y, GAIN_Z * temp.z));
00305 }
00306
00307
00308 for (unsigned int i = 0; i < NUM_WHEELS; i++) {
00309 joint_wheels_[i]->SetVelocity(0, speed[i]);
00310 #if GAZEBO_MAJOR_VERSION >= 7
00311 joint_wheels_[i]->SetEffortLimit(0, TORQUE_MAX_GLOBAL);
00312 #else
00313 joint_wheels_[i]->SetMaxForce(0, TORQUE_MAX_GLOBAL);
00314 #endif
00315 }
00316
00317
00318 if (gstamp - stamp_vehicle_ >= common::Time(1.0 / PUB_FREQ_VEHICLE)) {
00319 stamp_vehicle_ += common::Time(1.0 / PUB_FREQ_VEHICLE);
00320
00321
00322 geometry_msgs::TwistStamped msg_twist;
00323 msg_twist.header = header;
00324 msg_twist.twist.linear.x = linear_vel.x;
00325 msg_twist.twist.linear.y = linear_vel.y;
00326 msg_twist.twist.linear.z = linear_vel.z;
00327 msg_twist.twist.angular.x = angular_vel.x;
00328 msg_twist.twist.angular.y = angular_vel.y;
00329 msg_twist.twist.angular.z = angular_vel.z;
00330 pmq_twist_->push(msg_twist, pub_twist_);
00331
00332
00333 geometry_msgs::WrenchStamped msg_wrench;
00334 msg_wrench.header = header;
00335 msg_wrench.wrench.force.x = 0.0;
00336 msg_wrench.wrench.force.y = 0.0;
00337 msg_wrench.wrench.torque.z = 0.0;
00338 pmq_wrench_->push(msg_wrench, pub_wrench_);
00339
00340
00341 joint_state_wheels_.header = header;
00342 if (!fast_)
00343 joint_state_rollers_.header = header;
00344 for (unsigned int i = 0; i < NUM_WHEELS; i++) {
00345 joint_state_wheels_.position[i] = joint_wheels_[i]->GetAngle(0).Radian();
00346 joint_state_wheels_.velocity[i] = joint_wheels_[i]->GetVelocity(0);
00347
00348 if (!fast_) {
00349 for (unsigned int j = 0; j < NUM_ROLLERS; j++) {
00350 joint_state_rollers_.position[i * NUM_ROLLERS + j] = joint_rollers_[i][j]->GetAngle(0).Radian();
00351 joint_state_rollers_.velocity[i * NUM_ROLLERS + j] = joint_rollers_[i][j]->GetVelocity(0);
00352 }
00353 }
00354 }
00355 pmq_joint_states_->push(joint_state_wheels_, pub_joint_states_);
00356 if (!fast_)
00357 pmq_joint_states_->push(joint_state_rollers_, pub_joint_states_);
00358
00359
00360 if (tf_broadcaster_) {
00361 geometry_msgs::TransformStamped transform;
00362 transform.header.stamp = rstamp;
00363 transform.header.frame_id = parent_frame_id_;
00364 transform.child_frame_id = child_frame_id_;
00365 transform.transform.translation.x = position.x;
00366 transform.transform.translation.y = position.y;
00367 transform.transform.translation.z = position.z;
00368 transform.transform.rotation.w = orientation.w;
00369 transform.transform.rotation.x = orientation.x;
00370 transform.transform.rotation.y = orientation.y;
00371 transform.transform.rotation.z = orientation.z;
00372 tf_broadcaster_->sendTransform(transform);
00373 }
00374 }
00375
00376
00377 if (gstamp - stamp_imu_ >= common::Time(1.0 / PUB_FREQ_IMU)) {
00378 stamp_imu_ += common::Time(1.0 / PUB_FREQ_IMU);
00379
00380
00381 sensor_msgs::Imu msg_imu;
00382 msg_imu.header = header;
00383 msg_imu.linear_acceleration.x = linear_accel.x;
00384 msg_imu.linear_acceleration.y = linear_accel.y;
00385 msg_imu.linear_acceleration.z = linear_accel.z;
00386 msg_imu.orientation_covariance[0] = -1;
00387 msg_imu.angular_velocity.x = angular_vel.x;
00388 msg_imu.angular_velocity.y = angular_vel.y;
00389 msg_imu.angular_velocity.z = angular_vel.z;
00390 msg_imu.angular_velocity_covariance[0] = -1;
00391 pmq_imu_data_->push(msg_imu, pub_imu_data_);
00392
00393 sensor_msgs::MagneticField msg_mag;
00394 msg_mag.header = header;
00395 msg_mag.magnetic_field.x = 0.0;
00396 msg_mag.magnetic_field.y = 0.0;
00397 msg_mag.magnetic_field.z = 0.0;
00398 msg_mag.magnetic_field_covariance[0] = -1;
00399 pmq_imu_mag_->push(msg_mag, pub_imu_mag_);
00400 }
00401
00402
00403 if (gstamp - stamp_joystick_ >= common::Time(1.0 / PUB_FREQ_JOYSTICK)) {
00404 stamp_joystick_ += common::Time(1.0 / PUB_FREQ_JOYSTICK);
00405 geometry_msgs::TwistStamped msg;
00406 msg.header = header;
00407 pmq_joystick_->push(msg, pub_joystick_);
00408 }
00409
00410
00411 if (gstamp - stamp_bumpers_ >= common::Time(1.0 / PUB_FREQ_BUMPERS)) {
00412 stamp_bumpers_ += common::Time(1.0 / PUB_FREQ_BUMPERS);
00413 mobility_base_core_msgs::BumperState msg;
00414 msg.front_left = 0;
00415 msg.front_right = 0;
00416 msg.rear_left = 0;
00417 msg.rear_right = 0;
00418 pmq_bumper_states_->push(msg, pub_bumper_states_);
00419 }
00420
00421
00422 if (mode != mode_) {
00423 stamp_mode_ = gstamp;
00424 publishMode(rstamp);
00425 } else if (gstamp - stamp_mode_ >= common::Time(1.0 / PUB_FREQ_MODE)) {
00426 stamp_mode_ += common::Time(1.0 / PUB_FREQ_MODE);
00427 publishMode(rstamp);
00428 }
00429
00430 mode_ = mode;
00431 }
00432
00433 previous_stamp_ = gstamp;
00434 first_update_ = false;
00435 }
00436
00437 void MobilityBasePlugin::recvCmdVel(const geometry_msgs::Twist::ConstPtr& msg)
00438 {
00439 boost::lock_guard<boost::mutex> lock(cmd_vel_mutex_);
00440 cmd_vel_stamp_ = world_->GetSimTime();
00441 cmd_vel_.x = msg->linear.x;
00442 cmd_vel_.y = msg->linear.y;
00443 cmd_vel_.z = msg->angular.z;
00444 }
00445
00446 void MobilityBasePlugin::recvCmdVelRaw(const geometry_msgs::Twist::ConstPtr& msg)
00447 {
00448 boost::lock_guard<boost::mutex> lock(cmd_vel_raw_mutex_);
00449 cmd_vel_raw_stamp_ = world_->GetSimTime();
00450 cmd_vel_raw_.x = msg->linear.x;
00451 cmd_vel_raw_.y = msg->linear.y;
00452 cmd_vel_raw_.z = msg->angular.z;
00453 }
00454
00455 void MobilityBasePlugin::publishMode(const ros::Time &stamp)
00456 {
00457 mobility_base_core_msgs::Mode msg;
00458 msg.header.frame_id = frame_id_;
00459 msg.header.stamp = stamp;
00460 msg.mode = mode_;
00461 pmq_mode_->push(msg, pub_mode_);
00462 }
00463
00464 void MobilityBasePlugin::spin()
00465 {
00466 while (ros::ok()) {
00467 ros::spinOnce();
00468 }
00469 }
00470
00471
00472 GZ_REGISTER_MODEL_PLUGIN(MobilityBasePlugin)
00473 }