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
00097
00098
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
00108
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
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
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
00197 std::string modelName = _sdf->GetParent()->Get<std::string>("name");
00198
00199
00200
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
00217 if (contact.position(j).x() > 0.012 && contact.position(j).z() < 0.06 &&
00218 contact.position(j).z() > 0.01)
00219 {
00220
00221 if (contact.position(j).y() <= y_overlap)
00222 sensor_state_.bumps_wheeldrops |= 0x1;
00223
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
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
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
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
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
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
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