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