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 #include <algorithm>
00027 #include <assert.h>
00028
00029 #include <erratic_gazebo_plugins/diffdrive_plugin.h>
00030
00031 #include <gazebo/gazebo.h>
00032 #include <gazebo/GazeboError.hh>
00033 #include <gazebo/Quatern.hh>
00034 #include <gazebo/Controller.hh>
00035 #include <gazebo/Body.hh>
00036 #include <gazebo/World.hh>
00037 #include <gazebo/Simulator.hh>
00038 #include <gazebo/Global.hh>
00039 #include <gazebo/XMLConfig.hh>
00040 #include <gazebo/ControllerFactory.hh>
00041 #include <gazebo/PhysicsEngine.hh>
00042
00043 #include <ros/ros.h>
00044 #include <tf/transform_broadcaster.h>
00045 #include <tf/transform_listener.h>
00046 #include <geometry_msgs/Twist.h>
00047 #include <nav_msgs/Odometry.h>
00048 #include <boost/bind.hpp>
00049
00050 using namespace gazebo;
00051
00052 GZ_REGISTER_DYNAMIC_CONTROLLER("diffdrive_plugin", DiffDrivePlugin);
00053
00054 enum
00055 {
00056 RIGHT, LEFT
00057 };
00058
00059
00060 DiffDrivePlugin::DiffDrivePlugin(Entity *parent) :
00061 Controller(parent)
00062 {
00063 parent_ = dynamic_cast<Model*> (parent);
00064
00065 if (!parent_)
00066 gzthrow("Differential_Position2d controller requires a Model as its parent");
00067
00068 enableMotors = true;
00069
00070 wheelSpeed[RIGHT] = 0;
00071 wheelSpeed[LEFT] = 0;
00072
00073 prevUpdateTime = Simulator::Instance()->GetSimTime();
00074
00075 Param::Begin(¶meters);
00076 leftJointNameP = new ParamT<std::string> ("leftJoint", "", 1);
00077 rightJointNameP = new ParamT<std::string> ("rightJoint", "", 1);
00078 wheelSepP = new ParamT<float> ("wheelSeparation", 0.34, 1);
00079 wheelDiamP = new ParamT<float> ("wheelDiameter", 0.15, 1);
00080 torqueP = new ParamT<float> ("torque", 10.0, 1);
00081 robotNamespaceP = new ParamT<std::string> ("robotNamespace", "/", 0);
00082 topicNameP = new ParamT<std::string> ("topicName", "", 1);
00083 Param::End();
00084
00085 x_ = 0;
00086 rot_ = 0;
00087 alive_ = true;
00088 }
00089
00090
00091 DiffDrivePlugin::~DiffDrivePlugin()
00092 {
00093 delete leftJointNameP;
00094 delete rightJointNameP;
00095 delete wheelSepP;
00096 delete wheelDiamP;
00097 delete torqueP;
00098 delete robotNamespaceP;
00099 delete topicNameP;
00100 delete callback_queue_thread_;
00101 delete rosnode_;
00102 delete transform_broadcaster_;
00103 }
00104
00105
00106 void DiffDrivePlugin::LoadChild(XMLConfigNode *node)
00107 {
00108 pos_iface_ = dynamic_cast<libgazebo::PositionIface*> (GetIface("position"));
00109
00110
00111 wheelSepP->Load(node);
00112 wheelDiamP->Load(node);
00113 torqueP->Load(node);
00114
00115 leftJointNameP->Load(node);
00116 rightJointNameP->Load(node);
00117
00118 joints[LEFT] = parent_->GetJoint(**leftJointNameP);
00119 joints[RIGHT] = parent_->GetJoint(**rightJointNameP);
00120
00121 if (!joints[LEFT])
00122 gzthrow("The controller couldn't get left hinge joint");
00123
00124 if (!joints[RIGHT])
00125 gzthrow("The controller couldn't get right hinge joint");
00126
00127
00128
00129 robotNamespaceP->Load(node);
00130 robotNamespace = robotNamespaceP->GetValue();
00131
00132 int argc = 0;
00133 char** argv = NULL;
00134 ros::init(argc, argv, "diff_drive_plugin", ros::init_options::NoSigintHandler | ros::init_options::AnonymousName);
00135 rosnode_ = new ros::NodeHandle(robotNamespace);
00136
00137 tf_prefix_ = tf::getPrefixParam(*rosnode_);
00138 transform_broadcaster_ = new tf::TransformBroadcaster();
00139
00140 topicNameP->Load(node);
00141 topicName = topicNameP->GetValue();
00142
00143
00144 ros::SubscribeOptions so =
00145 ros::SubscribeOptions::create<geometry_msgs::Twist>(topicName, 1,
00146 boost::bind(&DiffDrivePlugin::cmdVelCallback, this, _1),
00147 ros::VoidPtr(), &queue_);
00148 sub_ = rosnode_->subscribe(so);
00149 pub_ = rosnode_->advertise<nav_msgs::Odometry>("odom", 1);
00150 }
00151
00152
00153 void DiffDrivePlugin::InitChild()
00154 {
00155
00156 odomPose[0] = 0.0;
00157 odomPose[1] = 0.0;
00158 odomPose[2] = 0.0;
00159
00160 odomVel[0] = 0.0;
00161 odomVel[1] = 0.0;
00162 odomVel[2] = 0.0;
00163
00164 callback_queue_thread_ = new boost::thread(boost::bind(&DiffDrivePlugin::QueueThread, this));
00165 }
00166
00167
00168 void DiffDrivePlugin::SaveChild(std::string &prefix, std::ostream &stream)
00169 {
00170 stream << prefix << *(leftJointNameP) << "\n";
00171 stream << prefix << *(rightJointNameP) << "\n";
00172 stream << prefix << *(torqueP) << "\n";
00173 stream << prefix << *(wheelDiamP) << "\n";
00174 stream << prefix << *(wheelSepP) << "\n";
00175 }
00176
00177
00178 void DiffDrivePlugin::ResetChild()
00179 {
00180
00181 odomPose[0] = 0.0;
00182 odomPose[1] = 0.0;
00183 odomPose[2] = 0.0;
00184
00185 odomVel[0] = 0.0;
00186 odomVel[1] = 0.0;
00187 odomVel[2] = 0.0;
00188 }
00189
00190
00191 void DiffDrivePlugin::UpdateChild()
00192 {
00193
00194 double wd, ws;
00195 double d1, d2;
00196 double dr, da;
00197 Time stepTime;
00198
00199
00200
00201 GetPositionCmd();
00202
00203 wd = **(wheelDiamP);
00204 ws = **(wheelSepP);
00205
00206
00207 stepTime = Simulator::Instance()->GetSimTime() - prevUpdateTime;
00208 prevUpdateTime = Simulator::Instance()->GetSimTime();
00209
00210
00211 d1 = stepTime.Double() * wd / 2 * joints[LEFT]->GetVelocity(0);
00212 d2 = stepTime.Double() * wd / 2 * joints[RIGHT]->GetVelocity(0);
00213
00214 dr = (d1 + d2) / 2;
00215 da = (d1 - d2) / ws;
00216
00217
00218 odomPose[0] += dr * cos(odomPose[2]);
00219 odomPose[1] += dr * sin(odomPose[2]);
00220 odomPose[2] += da;
00221
00222
00223 odomVel[0] = dr / stepTime.Double();
00224 odomVel[1] = 0.0;
00225 odomVel[2] = da / stepTime.Double();
00226
00227 if (enableMotors)
00228 {
00229 joints[LEFT]->SetVelocity(0, wheelSpeed[LEFT] / (**(wheelDiamP) / 2.0));
00230
00231 joints[RIGHT]->SetVelocity(0, wheelSpeed[RIGHT] / (**(wheelDiamP) / 2.0));
00232
00233 joints[LEFT]->SetMaxForce(0, **(torqueP));
00234 joints[RIGHT]->SetMaxForce(0, **(torqueP));
00235 }
00236
00237 write_position_data();
00238 publish_odometry();
00239
00240
00241 }
00242
00243
00244 void DiffDrivePlugin::FiniChild()
00245 {
00246
00247 alive_ = false;
00248
00249 queue_.clear();
00250 queue_.disable();
00251 rosnode_->shutdown();
00252 callback_queue_thread_->join();
00253
00254 }
00255
00256
00257 void DiffDrivePlugin::GetPositionCmd()
00258 {
00259 lock.lock();
00260
00261 double vr, va;
00262
00263 vr = x_;
00264 va = rot_;
00265
00266
00267
00268
00269 enableMotors = true;
00270
00271
00272
00273 wheelSpeed[LEFT] = vr + va * **(wheelSepP) / 2;
00274 wheelSpeed[RIGHT] = vr - va * **(wheelSepP) / 2;
00275
00276 lock.unlock();
00277 }
00278
00279
00280 void DiffDrivePlugin::cmdVelCallback(const geometry_msgs::Twist::ConstPtr& cmd_msg)
00281 {
00282
00283
00284 lock.lock();
00285
00286 x_ = cmd_msg->linear.x;
00287 rot_ = cmd_msg->angular.z;
00288
00289 lock.unlock();
00290
00291
00292 }
00293
00294
00295 void DiffDrivePlugin::QueueThread()
00296 {
00297 static const double timeout = 0.01;
00298
00299 while (alive_ && rosnode_->ok())
00300 {
00301
00302 queue_.callAvailable(ros::WallDuration(timeout));
00303 }
00304 }
00305
00306
00307 void DiffDrivePlugin::publish_odometry()
00308 {
00309
00310 ros::Time current_time_((Simulator::Instance()->GetSimTime()).sec, (Simulator::Instance()->GetSimTime()).nsec);
00311
00312
00313 btQuaternion qt;
00314
00315 qt.setEulerZYX(pos_iface_->data->pose.yaw, pos_iface_->data->pose.pitch, pos_iface_->data->pose.roll);
00316 btVector3 vt(pos_iface_->data->pose.pos.x, pos_iface_->data->pose.pos.y, pos_iface_->data->pose.pos.z);
00317 tf::Transform base_footprint_to_odom(qt, vt);
00318
00319 transform_broadcaster_->sendTransform(tf::StampedTransform(base_footprint_to_odom,
00320 current_time_,
00321 "odom",
00322 "base_footprint"));
00323
00324
00325 odom_.pose.pose.position.x = pos_iface_->data->pose.pos.x;
00326 odom_.pose.pose.position.y = pos_iface_->data->pose.pos.y;
00327
00328 gazebo::Quatern rot;
00329 rot.SetFromEuler(gazebo::Vector3(pos_iface_->data->pose.roll, pos_iface_->data->pose.pitch, pos_iface_->data->pose.yaw));
00330
00331 odom_.pose.pose.orientation.x = rot.x;
00332 odom_.pose.pose.orientation.y = rot.y;
00333 odom_.pose.pose.orientation.z = rot.z;
00334 odom_.pose.pose.orientation.w = rot.u;
00335
00336 odom_.twist.twist.linear.x = pos_iface_->data->velocity.pos.x;
00337 odom_.twist.twist.linear.y = pos_iface_->data->velocity.pos.y;
00338 odom_.twist.twist.angular.z = pos_iface_->data->velocity.yaw;
00339
00340 odom_.header.frame_id = tf::resolve(tf_prefix_, "odom");
00341 odom_.child_frame_id = "base_footprint";
00342
00343
00344 odom_.header.stamp.sec = (Simulator::Instance()->GetSimTime()).sec;
00345 odom_.header.stamp.nsec = (Simulator::Instance()->GetSimTime()).nsec;
00346
00347 pub_.publish(odom_);
00348 }
00349
00350
00351 void DiffDrivePlugin::write_position_data()
00352 {
00353
00354 pos_iface_->data->head.time = Simulator::Instance()->GetSimTime().Double();
00355
00356 pos_iface_->data->pose.pos.x = odomPose[0];
00357 pos_iface_->data->pose.pos.y = odomPose[1];
00358 pos_iface_->data->pose.yaw = NORMALIZE(odomPose[2]);
00359
00360 pos_iface_->data->velocity.pos.x = odomVel[0];
00361 pos_iface_->data->velocity.yaw = odomVel[2];
00362
00363
00364 pos_iface_->data->stall = 0;
00365 }
00366