gazebo_ros_diffdrive_uos.cpp
Go to the documentation of this file.
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 // index of left / right middle wheel joint
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   // this MUST be called 'robotNamespace' for proper remapping to work
00052   // TODO: could be 'node_namespace' now
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   //initialize time and odometry position
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   // Get then name of the parent model
00154   std::string modelName = _sdf->GetParent()->Get<std::string>("name");
00155 
00156   // Listen to the update event. This event is broadcast every
00157   // simulation iteration.
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   // Distance travelled by middle wheels
00184   d1 = step_time.Double() * (wd / 2) * joints_[LEFT]->GetVelocity(0);
00185   d2 = step_time.Double() * (wd / 2) * joints_[RIGHT]->GetVelocity(0);
00186 
00187   // Can see NaN values here, just zero them out if needed
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   // Compute odometric pose
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   // Compute odometric instantaneous velocity
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   // turn left wheels
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   // turn right wheels
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   // limit wheel speed
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);


diffdrive_gazebo_plugin
Author(s): Martin Guenther
autogenerated on Wed Aug 16 2017 02:53:53