gazebo_ros_create.cpp
Go to the documentation of this file.
00001 #include <gazebo/sensors/SensorManager.hh>
00002 #include <gazebo/sensors/RaySensor.hh>
00003 #include <create_node/TurtlebotSensorState.h>
00004 #include <nav_msgs/Odometry.h>
00005 #include <geometry_msgs/Twist.h>
00006 #include <sensor_msgs/JointState.h>
00007 #include "turtlebot_plugins/gazebo_ros_create.h"
00008 
00009 using namespace gazebo;
00010 
00011 enum {LEFT= 0, RIGHT=1, FRONT=2, REAR=3};
00012 
00013 GazeboRosCreate::GazeboRosCreate()
00014   : gazebo_node_(new transport::Node())
00015 {
00016   this->spinner_thread_ = new boost::thread( boost::bind( &GazeboRosCreate::spin, this) );
00017 
00018   wheel_speed_ = new float[2];
00019   wheel_speed_[LEFT] = 0.0;
00020   wheel_speed_[RIGHT] = 0.0;
00021 
00022   set_joints_[0] = false;
00023   set_joints_[1] = false;
00024   set_joints_[2] = false;
00025   set_joints_[3] = false;
00026   joints_[0].reset();
00027   joints_[1].reset();
00028   joints_[2].reset();
00029   joints_[3].reset();
00030 }
00031 
00032 GazeboRosCreate::~GazeboRosCreate()
00033 {
00034   rosnode_->shutdown();
00035   this->spinner_thread_->join();
00036   delete this->spinner_thread_;
00037   delete [] wheel_speed_;
00038   delete rosnode_;
00039 }
00040 
00041 void GazeboRosCreate::Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf )
00042 {
00043   this->my_world_ = _parent->GetWorld();
00044 
00045   this->my_parent_ = _parent;
00046   if (!this->my_parent_)
00047   {
00048     ROS_FATAL("Gazebo_ROS_Create controller requires a Model as its parent");
00049     return;
00050   }
00051 
00052 
00053   this->node_namespace_ = "";
00054   if (_sdf->HasElement("node_namespace"))
00055     this->node_namespace_ = _sdf->GetElement("node_namespace")->Get<std::string>() + "/";
00056 
00057 
00058   left_wheel_joint_name_ = "left_wheel_joint";
00059   if (_sdf->HasElement("left_wheel_joint"))
00060     left_wheel_joint_name_ = _sdf->GetElement("left_wheel_joint")->Get<std::string>();
00061 
00062   right_wheel_joint_name_ = "right_wheel_joint";
00063   if (_sdf->HasElement("right_wheel_joint"))
00064     right_wheel_joint_name_ = _sdf->GetElement("right_wheel_joint")->Get<std::string>();
00065 
00066   front_castor_joint_name_ = "front_castor_joint";
00067   if (_sdf->HasElement("front_castor_joint"))
00068     front_castor_joint_name_ = _sdf->GetElement("front_castor_joint")->Get<std::string>();
00069 
00070   rear_castor_joint_name_ = "rear_castor_joint";
00071   if (_sdf->HasElement("rear_castor_joint"))
00072     rear_castor_joint_name_ = _sdf->GetElement("rear_castor_joint")->Get<std::string>();
00073 
00074   wheel_sep_ = 0.34;
00075   if (_sdf->HasElement("wheel_separation"))
00076     wheel_sep_ = _sdf->GetElement("wheel_separation")->Get<double>();
00077 
00078   wheel_sep_ = 0.34;
00079   if (_sdf->HasElement("wheel_separation"))
00080     wheel_sep_ = _sdf->GetElement("wheel_separation")->Get<double>();
00081 
00082   wheel_diam_ = 0.15;
00083   if (_sdf->HasElement("wheel_diameter"))
00084     wheel_diam_ = _sdf->GetElement("wheel_diameter")->Get<double>();
00085 
00086   torque_ = 10.0;
00087   if (_sdf->HasElement("torque"))
00088     torque_ = _sdf->GetElement("torque")->Get<double>();
00089 
00090   base_geom_name_ = "base_footprint_collision_base_link";
00091   if (_sdf->HasElement("base_geom"))
00092     base_geom_name_ = _sdf->GetElement("base_geom")->Get<std::string>();
00093   base_geom_ = my_parent_->GetChildCollision(base_geom_name_);
00094   if (!base_geom_)
00095   {
00096     // This is a hack for ROS Diamond back. E-turtle and future releases
00097     // will not need this, because it will contain the fixed-joint reduction
00098     // in urdf2gazebo
00099     base_geom_ = my_parent_->GetChildCollision("base_footprint_geom");
00100     if (!base_geom_)
00101     {
00102       ROS_ERROR("Unable to find geom[%s]",base_geom_name_.c_str());
00103       return;
00104     }
00105   }
00106 
00107   //base_geom_->SetContactsEnabled(true);
00108   //contact_event_ = base_geom_->ConnectContact(boost::bind(&GazeboRosCreate::OnContact, this, _1, _2));
00109   physics::ContactManager *mgr = my_world_->GetPhysicsEngine()->GetContactManager();
00110   std::string topic = mgr->CreateFilter(base_geom_name_, base_geom_name_);
00111   contact_sub_ = gazebo_node_->Subscribe(topic, &GazeboRosCreate::OnContact, this);
00112 
00113   wall_sensor_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00114     sensors::SensorManager::Instance()->GetSensor("wall_sensor"));
00115   if (!wall_sensor_)
00116   {
00117     ROS_ERROR("Unable to find sensor[wall_sensor]");
00118     return;
00119   }
00120 
00121   left_cliff_sensor_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00122     sensors::SensorManager::Instance()->GetSensor("left_cliff_sensor"));
00123   right_cliff_sensor_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00124     sensors::SensorManager::Instance()->GetSensor("right_cliff_sensor"));
00125   leftfront_cliff_sensor_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00126     sensors::SensorManager::Instance()->GetSensor("leftfront_cliff_sensor"));
00127   rightfront_cliff_sensor_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00128     sensors::SensorManager::Instance()->GetSensor("rightfront_cliff_sensor"));
00129 
00130   wall_sensor_->SetActive(true);
00131   left_cliff_sensor_->SetActive(true);
00132   right_cliff_sensor_->SetActive(true);
00133   rightfront_cliff_sensor_->SetActive(true);
00134   leftfront_cliff_sensor_->SetActive(true);
00135 
00136   if (!ros::isInitialized())
00137   {
00138     int argc = 0;
00139     char** argv = NULL;
00140     ros::init(argc, argv, "gazebo_turtlebot", ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00141   }
00142 
00143   rosnode_ = new ros::NodeHandle( node_namespace_ );
00144 
00145   cmd_vel_sub_ = rosnode_->subscribe("cmd_vel", 1, &GazeboRosCreate::OnCmdVel, this );
00146 
00147   sensor_state_pub_ = rosnode_->advertise<create_node::TurtlebotSensorState>("sensor_state", 1);
00148   odom_pub_ = rosnode_->advertise<nav_msgs::Odometry>("/odom", 1);
00149 
00150   joint_state_pub_ = rosnode_->advertise<sensor_msgs::JointState>("/joint_states", 1);
00151 
00152   js_.name.push_back( left_wheel_joint_name_ );
00153   js_.position.push_back(0);
00154   js_.velocity.push_back(0);
00155   js_.effort.push_back(0);
00156 
00157   js_.name.push_back( right_wheel_joint_name_ );
00158   js_.position.push_back(0);
00159   js_.velocity.push_back(0);
00160   js_.effort.push_back(0);
00161 
00162   js_.name.push_back( front_castor_joint_name_ );
00163   js_.position.push_back(0);
00164   js_.velocity.push_back(0);
00165   js_.effort.push_back(0);
00166 
00167   js_.name.push_back( rear_castor_joint_name_ );
00168   js_.position.push_back(0);
00169   js_.velocity.push_back(0);
00170   js_.effort.push_back(0);
00171 
00172   prev_update_time_ = 0;
00173   last_cmd_vel_time_ = 0;
00174 
00175 
00176   sensor_state_.bumps_wheeldrops = 0x0;
00177 
00178   //TODO: fix this
00179 
00180   joints_[LEFT] = my_parent_->GetJoint(left_wheel_joint_name_);
00181   joints_[RIGHT] = my_parent_->GetJoint(right_wheel_joint_name_);
00182   joints_[FRONT] = my_parent_->GetJoint(front_castor_joint_name_);
00183   joints_[REAR] = my_parent_->GetJoint(rear_castor_joint_name_);
00184 
00185   if (joints_[LEFT]) set_joints_[LEFT] = true;
00186   if (joints_[RIGHT]) set_joints_[RIGHT] = true;
00187   if (joints_[FRONT]) set_joints_[FRONT] = true;
00188   if (joints_[REAR]) set_joints_[REAR] = true;
00189 
00190   //initialize time and odometry position
00191   prev_update_time_ = last_cmd_vel_time_ = this->my_world_->GetSimTime();
00192   odom_pose_[0] = 0.0;
00193   odom_pose_[1] = 0.0;
00194   odom_pose_[2] = 0.0;
00195 
00196   // Get then name of the parent model
00197   std::string modelName = _sdf->GetParent()->Get<std::string>("name");
00198 
00199   // Listen to the update event. This event is broadcast every
00200   // simulation iteration.
00201   this->updateConnection = event::Events::ConnectWorldUpdateBegin(boost::bind(&GazeboRosCreate::UpdateChild, this));
00202   gzdbg << "plugin model name: " << modelName << "\n";
00203 }
00204 
00205 
00206 void GazeboRosCreate::OnContact(ConstContactsPtr &contacts)
00207 {
00208   float y_overlap = 0.16495 * sin( 10 * (M_PI/180.0) );
00209 
00210   for (int i=0; i < contacts->contact_size(); i++ )
00211   {
00212     const msgs::Contact & contact = contacts->contact(i);
00213     const int contact_count = contact.position_size();
00214     for (unsigned int j=0; j < contact_count; j++)
00215     {
00216       // Make sure the contact is on the front bumper
00217       if (contact.position(j).x() > 0.012 && contact.position(j).z() < 0.06 &&
00218           contact.position(j).z() > 0.01)
00219       {
00220         // Right bump sensor
00221         if (contact.position(j).y() <= y_overlap)
00222           sensor_state_.bumps_wheeldrops |= 0x1;
00223         // Left bump sensor
00224         if (contact.position(j).y() >= -y_overlap)
00225           sensor_state_.bumps_wheeldrops |= 0x2;
00226       }
00227     }
00228   }
00229 
00230 }
00231 
00232 void GazeboRosCreate::UpdateChild()
00233 {
00234   common::Time time_now = this->my_world_->GetSimTime();
00235   common::Time step_time = time_now - prev_update_time_;
00236   prev_update_time_ = time_now;
00237 
00238   double wd, ws;
00239   double d1, d2;
00240   double dr, da;
00241 
00242   wd = wheel_diam_;
00243   ws = wheel_sep_;
00244 
00245   d1 = d2 = 0;
00246   dr = da = 0;
00247 
00248   // Distance travelled by front wheels
00249   if (set_joints_[LEFT])
00250     d1 = step_time.Double() * (wd / 2) * joints_[LEFT]->GetVelocity(0);
00251   if (set_joints_[RIGHT])
00252     d2 = step_time.Double() * (wd / 2) * joints_[RIGHT]->GetVelocity(0);
00253 
00254   // Can see NaN values here, just zero them out if needed
00255   if (isnan(d1)) {
00256     ROS_WARN_THROTTLE(0.1, "Gazebo ROS Create plugin. NaN in d1. Step time: %.2f. WD: %.2f. Velocity: %.2f", step_time.Double(), wd, joints_[LEFT]->GetVelocity(0));
00257     d1 = 0;
00258   }
00259 
00260   if (isnan(d2)) {
00261     ROS_WARN_THROTTLE(0.1, "Gazebo ROS Create plugin. NaN in d2. Step time: %.2f. WD: %.2f. Velocity: %.2f", step_time.Double(), wd, joints_[RIGHT]->GetVelocity(0));
00262     d2 = 0;
00263   }
00264 
00265   dr = (d1 + d2) / 2;
00266   da = (d2 - d1) / ws;
00267 
00268   // Compute odometric pose
00269   odom_pose_[0] += dr * cos( odom_pose_[2] );
00270   odom_pose_[1] += dr * sin( odom_pose_[2] );
00271   odom_pose_[2] += da;
00272 
00273   // Compute odometric instantaneous velocity
00274   odom_vel_[0] = dr / step_time.Double();
00275   odom_vel_[1] = 0.0;
00276   odom_vel_[2] = da / step_time.Double();
00277 
00278 
00279   if (set_joints_[LEFT])
00280   {
00281     joints_[LEFT]->SetVelocity( 0, wheel_speed_[LEFT] / (wd/2.0) );
00282     joints_[LEFT]->SetMaxForce( 0, torque_ );
00283   }
00284   if (set_joints_[RIGHT])
00285   {
00286     joints_[RIGHT]->SetVelocity( 0, wheel_speed_[RIGHT] / (wd / 2.0) );
00287     joints_[RIGHT]->SetMaxForce( 0, torque_ );
00288   }
00289 
00290   nav_msgs::Odometry odom;
00291   odom.header.stamp.sec = time_now.sec;
00292   odom.header.stamp.nsec = time_now.nsec;
00293   odom.header.frame_id = "odom";
00294   odom.child_frame_id = "base_footprint";
00295   odom.pose.pose.position.x = odom_pose_[0];
00296   odom.pose.pose.position.y = odom_pose_[1];
00297   odom.pose.pose.position.z = 0;
00298 
00299   tf::Quaternion qt;
00300   qt.setEuler(0,0,odom_pose_[2]);
00301 
00302   odom.pose.pose.orientation.x = qt.getX();
00303   odom.pose.pose.orientation.y = qt.getY();
00304   odom.pose.pose.orientation.z = qt.getZ();
00305   odom.pose.pose.orientation.w = qt.getW();
00306 
00307   double pose_cov[36] = { 1e-3, 0, 0, 0, 0, 0,
00308                           0, 1e-3, 0, 0, 0, 0,
00309                           0, 0, 1e6, 0, 0, 0,
00310                           0, 0, 0, 1e6, 0, 0,
00311                           0, 0, 0, 0, 1e6, 0,
00312                           0, 0, 0, 0, 0, 1e3};
00313 
00314   memcpy( &odom.pose.covariance[0], pose_cov, sizeof(double)*36 );
00315   memcpy( &odom.twist.covariance[0], pose_cov, sizeof(double)*36 );
00316 
00317   odom.twist.twist.linear.x = odom_vel_[0];
00318   odom.twist.twist.linear.y = 0;
00319   odom.twist.twist.linear.z = 0;
00320 
00321   odom.twist.twist.angular.x = 0;
00322   odom.twist.twist.angular.y = 0;
00323   odom.twist.twist.angular.z = odom_vel_[2];
00324 
00325   odom_pub_.publish( odom );
00326 
00327   js_.header.stamp.sec = time_now.sec;
00328   js_.header.stamp.nsec = time_now.nsec;
00329   if (this->set_joints_[LEFT])
00330   {
00331     js_.position[0] = joints_[LEFT]->GetAngle(0).Radian();
00332     js_.velocity[0] = joints_[LEFT]->GetVelocity(0);
00333   }
00334 
00335   if (this->set_joints_[RIGHT])
00336   {
00337     js_.position[1] = joints_[RIGHT]->GetAngle(0).Radian();
00338     js_.velocity[1] = joints_[RIGHT]->GetVelocity(0);
00339   }
00340 
00341   if (this->set_joints_[FRONT])
00342   {
00343     js_.position[2] = joints_[FRONT]->GetAngle(0).Radian();
00344     js_.velocity[2] = joints_[FRONT]->GetVelocity(0);
00345   }
00346 
00347   if (this->set_joints_[REAR])
00348   {
00349     js_.position[3] = joints_[REAR]->GetAngle(0).Radian();
00350     js_.velocity[3] = joints_[REAR]->GetVelocity(0);
00351   }
00352 
00353   joint_state_pub_.publish( js_ );
00354 
00355   this->UpdateSensors();
00356 
00357   //timeout if didn't receive cmd in a while
00358   common::Time time_since_last_cmd = time_now - last_cmd_vel_time_;
00359   if (time_since_last_cmd.Double() > 0.6)
00360   {
00361     wheel_speed_[LEFT] = 0;
00362     wheel_speed_[RIGHT] = 0;
00363   }
00364 
00365 }
00366 
00367 void GazeboRosCreate::UpdateSensors()
00368 {
00369   if (wall_sensor_->GetRange(0) < 0.04)
00370     sensor_state_.wall = true;
00371   else
00372     sensor_state_.wall = false;
00373 
00374   if (left_cliff_sensor_->GetRange(0) > 0.02)
00375     sensor_state_.cliff_left = true;
00376   else
00377     sensor_state_.cliff_left = false;
00378 
00379   if (right_cliff_sensor_->GetRange(0) > 0.02)
00380     sensor_state_.cliff_right = true;
00381   else
00382     sensor_state_.cliff_right = false;
00383 
00384   if (rightfront_cliff_sensor_->GetRange(0) > 0.02)
00385     sensor_state_.cliff_front_right = true;
00386   else
00387     sensor_state_.cliff_front_right = false;
00388 
00389   if (leftfront_cliff_sensor_->GetRange(0) > 0.02)
00390     sensor_state_.cliff_front_left = true;
00391   else
00392     sensor_state_.cliff_front_left = false;
00393 
00394   sensor_state_pub_.publish(sensor_state_);
00395 
00396   // Reset the bump sensors
00397   sensor_state_.bumps_wheeldrops = 0x0;
00398 }
00399 
00400 void GazeboRosCreate::OnCmdVel( const geometry_msgs::TwistConstPtr &msg)
00401 {
00402   last_cmd_vel_time_ = this->my_world_->GetSimTime();
00403   double vr, va;
00404   vr = msg->linear.x;
00405   va = msg->angular.z;
00406 
00407   wheel_speed_[LEFT] = vr - va * (wheel_sep_) / 2;
00408   wheel_speed_[RIGHT] = vr + va * (wheel_sep_) / 2;
00409 }
00410 
00411 void GazeboRosCreate::spin()
00412 {
00413   while(ros::ok()) ros::spinOnce();
00414 }
00415 
00416 GZ_REGISTER_MODEL_PLUGIN(GazeboRosCreate);
00417 


create_gazebo_plugins
Author(s): Nate Koenig
autogenerated on Thu Jun 6 2019 17:51:22