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