00001 #include <diffdrive_gazebo_plugin/gazebo_ros_diffdrive_uos.h>
00002 #include <nav_msgs/Odometry.h>
00003 #include <geometry_msgs/Twist.h>
00004
00005 #include <ros/time.h>
00006
00007 #include <tf/transform_broadcaster.h>
00008
00009 using namespace gazebo;
00010
00011
00012 enum
00013 {
00014 LEFT = 1, RIGHT = 4
00015 };
00016
00017 const double gazebo::GazeboRosDiffdrive::CMD_VEL_TIMEOUT = 0.6;
00018
00019 GazeboRosDiffdrive::GazeboRosDiffdrive() :
00020 wheel_speed_right_(0.0),
00021 wheel_speed_left_(0.0)
00022 {
00023 this->spinner_thread_ = new boost::thread( boost::bind( &GazeboRosDiffdrive::spin, this) );
00024
00025 for (size_t i = 0; i < NUM_JOINTS; ++i)
00026 {
00027 joints_[i].reset();
00028 }
00029 }
00030
00031 GazeboRosDiffdrive::~GazeboRosDiffdrive()
00032 {
00033 rosnode_->shutdown();
00034 this->spinner_thread_->join();
00035 delete this->spinner_thread_;
00036 delete rosnode_;
00037 }
00038
00039 void GazeboRosDiffdrive::Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf )
00040 {
00041 this->my_world_ = _parent->GetWorld();
00042
00043 this->my_parent_ = _parent;
00044 if (!this->my_parent_)
00045 {
00046 ROS_FATAL("Gazebo_ROS_Create controller requires a Model as its parent");
00047 return;
00048 }
00049
00050
00051
00052
00053 this->node_namespace_ = "/";
00054 if (_sdf->HasElement("robotNamespace"))
00055 this->node_namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>() + "/";
00056
00057
00058 cmd_vel_topic_name_ = "/cmd_vel";
00059 if (_sdf->HasElement("cmd_vel_topic_name"))
00060 cmd_vel_topic_name_ = _sdf->GetElement("cmd_vel_topic_name")->Get<std::string>();
00061
00062 odom_topic_name_ = "/odom";
00063 if (_sdf->HasElement("odom_topic_name"))
00064 odom_topic_name_ = _sdf->GetElement("odom_topic_name")->Get<std::string>();
00065
00066 joint_states_topic_name_ = "/joint_states";
00067 if (_sdf->HasElement("joint_states_topic_name"))
00068 joint_states_topic_name_ = _sdf->GetElement("joint_states_topic_name")->Get<std::string>();
00069
00070 js_.name.resize(NUM_JOINTS);
00071 js_.position.resize(NUM_JOINTS);
00072 js_.velocity.resize(NUM_JOINTS);
00073 js_.effort.resize(NUM_JOINTS);
00074
00075 for (size_t i = 0; i < NUM_JOINTS; ++i)
00076 {
00077 js_.position[i] = 0;
00078 js_.velocity[i] = 0;
00079 js_.effort[i] = 0;
00080 }
00081
00082 js_.name[0] = "left_front_wheel_joint";
00083 if (_sdf->HasElement("left_front_wheel_joint"))
00084 js_.name[0] = _sdf->GetElement("left_front_wheel_joint")->Get<std::string>();
00085
00086 js_.name[1] = "left_middle_wheel_joint";
00087 if (_sdf->HasElement("left_middle_wheel_joint"))
00088 js_.name[1] = _sdf->GetElement("left_middle_wheel_joint")->Get<std::string>();
00089
00090 js_.name[2] = "left_rear_wheel_joint";
00091 if (_sdf->HasElement("left_rear_wheel_joint"))
00092 js_.name[2] = _sdf->GetElement("left_rear_wheel_joint")->Get<std::string>();
00093
00094 js_.name[3] = "right_front_wheel_joint";
00095 if (_sdf->HasElement("right_front_wheel_joint"))
00096 js_.name[3] = _sdf->GetElement("right_front_wheel_joint")->Get<std::string>();
00097
00098 js_.name[4] = "right_middle_wheel_joint";
00099 if (_sdf->HasElement("right_middle_wheel_joint"))
00100 js_.name[5] = _sdf->GetElement("right_middle_wheel_joint")->Get<std::string>();
00101
00102 js_.name[5] = "right_rear_wheel_joint";
00103 if (_sdf->HasElement("right_rear_wheel_joint"))
00104 js_.name[5] = _sdf->GetElement("right_rear_wheel_joint")->Get<std::string>();
00105
00106 wheel_sep_ = 0.34;
00107 if (_sdf->HasElement("wheel_separation"))
00108 wheel_sep_ = _sdf->GetElement("wheel_separation")->Get<double>();
00109
00110 turning_adaptation_ = 0.15;
00111 if (_sdf->HasElement("turning_adaptation"))
00112 turning_adaptation_ = _sdf->GetElement("turning_adaptation")->Get<double>();
00113
00114 wheel_diam_ = 0.15;
00115 if (_sdf->HasElement("wheel_diameter"))
00116 wheel_diam_ = _sdf->GetElement("wheel_diameter")->Get<double>();
00117
00118 torque_ = 4.0;
00119 if (_sdf->HasElement("torque"))
00120 torque_ = _sdf->GetElement("torque")->Get<double>();
00121
00122 max_velocity_ = 4.0;
00123 if (_sdf->HasElement("max_velocity"))
00124 max_velocity_ = _sdf->GetElement("max_velocity")->Get<double>();
00125
00126
00127 if (!ros::isInitialized())
00128 {
00129 int argc = 0;
00130 char** argv = NULL;
00131 ros::init(argc, argv, "gazebo_ros_diffdrive_uos", ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00132 }
00133
00134 rosnode_ = new ros::NodeHandle(node_namespace_);
00135
00136 cmd_vel_sub_ = rosnode_->subscribe(cmd_vel_topic_name_, 1, &GazeboRosDiffdrive::OnCmdVel, this);
00137 odom_pub_ = rosnode_->advertise<nav_msgs::Odometry> (odom_topic_name_, 1);
00138 joint_state_pub_ = rosnode_->advertise<sensor_msgs::JointState> (joint_states_topic_name_, 1);
00139
00140 for (size_t i = 0; i < NUM_JOINTS; ++i)
00141 {
00142 joints_[i] = my_parent_->GetJoint(js_.name[i]);
00143 if (!joints_[i])
00144 gzthrow("The controller couldn't get joint " << js_.name[i]);
00145 }
00146
00147
00148 prev_update_time_ = last_cmd_vel_time_ = this->my_world_->GetSimTime();
00149 odom_pose_[0] = 0.0;
00150 odom_pose_[1] = 0.0;
00151 odom_pose_[2] = 0.0;
00152
00153
00154 std::string modelName = _sdf->GetParent()->Get<std::string>("name");
00155
00156
00157
00158 this->updateConnection = event::Events::ConnectWorldUpdateBegin(
00159 boost::bind(&GazeboRosDiffdrive::UpdateChild, this));
00160 gzdbg << "plugin model name: " << modelName << "\n";
00161
00162 ROS_INFO("gazebo_ros_diffdrive_uos plugin initialized");
00163 }
00164
00165 void GazeboRosDiffdrive::UpdateChild()
00166 {
00167 common::Time time_now = this->my_world_->GetSimTime();
00168 common::Time step_time = time_now - prev_update_time_;
00169 prev_update_time_ = time_now;
00170
00171 double wd, ws;
00172 double d1, d2;
00173 double dr, da;
00174 double turning_adaptation;
00175
00176 wd = wheel_diam_;
00177 ws = wheel_sep_;
00178 turning_adaptation = turning_adaptation_;
00179
00180 d1 = d2 = 0;
00181 dr = da = 0;
00182
00183
00184 d1 = step_time.Double() * (wd / 2) * joints_[LEFT]->GetVelocity(0);
00185 d2 = step_time.Double() * (wd / 2) * joints_[RIGHT]->GetVelocity(0);
00186
00187
00188 if (std::isnan(d1)) {
00189 ROS_WARN_THROTTLE(0.1, "gazebo_ros_diffdrive_uos: NaN in d1. Step time: %.2f. WD: %.2f. Velocity: %.2f", step_time.Double(), wd, joints_[LEFT]->GetVelocity(0));
00190 d1 = 0;
00191 }
00192
00193 if (std::isnan(d2)) {
00194 ROS_WARN_THROTTLE(0.1, "gazebo_ros_diffdrive_uos: NaN in d2. Step time: %.2f. WD: %.2f. Velocity: %.2f", step_time.Double(), wd, joints_[RIGHT]->GetVelocity(0));
00195 d2 = 0;
00196 }
00197
00198 dr = (d1 + d2) / 2;
00199 da = (d2 - d1) / ws * turning_adaptation;
00200
00201
00202 odom_pose_[0] += dr * cos(odom_pose_[2]);
00203 odom_pose_[1] += dr * sin(odom_pose_[2]);
00204 odom_pose_[2] += da;
00205
00206
00207 odom_vel_[0] = dr / step_time.Double();
00208 odom_vel_[1] = 0.0;
00209 odom_vel_[2] = da / step_time.Double();
00210
00211 if (this->my_world_->GetSimTime() > last_cmd_vel_time_ + common::Time(CMD_VEL_TIMEOUT))
00212 {
00213 ROS_DEBUG("gazebo_ros_diffdrive_uos: cmd_vel timeout - current: %f, last cmd_vel: %f, timeout: %f", this->my_world_->GetSimTime().Double(), last_cmd_vel_time_.Double(), common::Time(CMD_VEL_TIMEOUT).Double());
00214 wheel_speed_left_ = wheel_speed_right_ = 0.0;
00215 }
00216
00217 ROS_DEBUG("gazebo_ros_diffdrive_uos: setting wheel speeds (left; %f, right: %f)", wheel_speed_left_ / (wd / 2.0), wheel_speed_right_ / (wd / 2.0));
00218
00219
00220 for (unsigned short i = 0; i < NUM_JOINTS/2; i++)
00221 {
00222 joints_[i]->SetVelocity(0, wheel_speed_left_ / (wd / 2.0));
00223 #if GAZEBO_MAJOR_VERSION < 5
00224 joints_[i]->SetMaxForce(0, torque_);
00225 #endif
00226 }
00227
00228
00229 for (unsigned short i = NUM_JOINTS/2; i < NUM_JOINTS; i++)
00230 {
00231 joints_[i]->SetVelocity(0, wheel_speed_right_ / (wd / 2.0));
00232 #if GAZEBO_MAJOR_VERSION < 5
00233 joints_[i]->SetMaxForce(0, torque_);
00234 #endif
00235 }
00236
00237 nav_msgs::Odometry odom;
00238 odom.header.stamp.sec = time_now.sec;
00239 odom.header.stamp.nsec = time_now.nsec;
00240 odom.header.frame_id = "odom_combined";
00241 odom.child_frame_id = "base_footprint";
00242 odom.pose.pose.position.x = odom_pose_[0];
00243 odom.pose.pose.position.y = odom_pose_[1];
00244 odom.pose.pose.position.z = 0;
00245
00246 tf::Quaternion qt;
00247 qt.setEuler(0, 0, odom_pose_[2]);
00248
00249 odom.pose.pose.orientation.x = qt.getX();
00250 odom.pose.pose.orientation.y = qt.getY();
00251 odom.pose.pose.orientation.z = qt.getZ();
00252 odom.pose.pose.orientation.w = qt.getW();
00253
00254 double pose_cov[36] = { 1e-3, 0, 0, 0, 0, 0,
00255 0, 1e-3, 0, 0, 0, 0,
00256 0, 0, 1e6, 0, 0, 0,
00257 0, 0, 0, 1e6, 0, 0,
00258 0, 0, 0, 0, 1e6, 0,
00259 0, 0, 0, 0, 0, 1e3};
00260
00261 memcpy(&odom.pose.covariance[0], pose_cov, sizeof(double) * 36);
00262 memcpy(&odom.twist.covariance[0], pose_cov, sizeof(double) * 36);
00263
00264 odom.twist.twist.linear.x = odom_vel_[0];
00265 odom.twist.twist.linear.y = 0;
00266 odom.twist.twist.linear.z = 0;
00267
00268 odom.twist.twist.angular.x = 0;
00269 odom.twist.twist.angular.y = 0;
00270 odom.twist.twist.angular.z = odom_vel_[2];
00271
00272 odom_pub_.publish(odom);
00273
00274 js_.header.stamp.sec = time_now.sec;
00275 js_.header.stamp.nsec = time_now.nsec;
00276
00277 for (size_t i = 0; i < NUM_JOINTS; ++i)
00278 {
00279 js_.position[i] = joints_[i]->GetAngle(0).Radian();
00280 js_.velocity[i] = joints_[i]->GetVelocity(0);
00281 }
00282
00283 joint_state_pub_.publish(js_);
00284 }
00285
00286 void GazeboRosDiffdrive::OnCmdVel(const geometry_msgs::TwistConstPtr &msg)
00287 {
00288 last_cmd_vel_time_ = this->my_world_->GetSimTime();
00289 double vr, va;
00290 vr = msg->linear.x;
00291 va = msg->angular.z;
00292
00293 wheel_speed_left_ = vr - va * wheel_sep_ / 2;
00294 wheel_speed_right_ = vr + va * wheel_sep_ / 2;
00295
00296
00297 if (fabs(wheel_speed_left_) > max_velocity_)
00298 wheel_speed_left_ = copysign(max_velocity_, wheel_speed_left_);
00299 if (fabs(wheel_speed_right_) > max_velocity_)
00300 wheel_speed_right_ = copysign(max_velocity_, wheel_speed_right_);
00301 }
00302
00303 void GazeboRosDiffdrive::spin()
00304 {
00305 while(ros::ok()) ros::spinOnce();
00306 }
00307
00308 GZ_REGISTER_MODEL_PLUGIN(GazeboRosDiffdrive);