$search
00001 /* 00002 * Gazebo - Outdoor Multi-Robot Simulator 00003 * Copyright (C) 2003 00004 * Nate Koenig & Andrew Howard 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 */ 00021 /* 00022 * Desc: Bumper controller 00023 * Author: Nate Koenig 00024 * Date: 09 Setp. 2008 00025 */ 00026 00027 #include <gazebo_plugins/gazebo_ros_bumper.h> 00028 00029 #include <gazebo/Global.hh> 00030 #include <gazebo/XMLConfig.hh> 00031 #include <gazebo/ContactSensor.hh> 00032 #include <gazebo/World.hh> 00033 #include <gazebo/gazebo.h> 00034 #include <gazebo/GazeboError.hh> 00035 #include <gazebo/ControllerFactory.hh> 00036 #include <gazebo/Simulator.hh> 00037 #include <gazebo/Body.hh> 00038 #include <gazebo/Model.hh> 00039 #include <gazebo/Geom.hh> 00040 00041 namespace gazebo 00042 { 00043 00044 GZ_REGISTER_DYNAMIC_CONTROLLER("gazebo_ros_bumper", GazeboRosBumper); 00045 00047 // Constructor 00048 GazeboRosBumper::GazeboRosBumper(Entity *parent ) 00049 : Controller(parent) 00050 { 00051 this->myParent = dynamic_cast<gazebo::ContactSensor*>(this->parent); 00052 00053 if (!this->myParent) 00054 gzthrow("Bumper controller requires a Contact Sensor as its parent"); 00055 00056 Param::Begin(&this->parameters); 00057 this->bumperTopicNameP = new ParamT<std::string>("bumperTopicName", "", 1); 00058 this->frameNameP = new ParamT<std::string>("frameName", "world", 0); 00059 this->robotNamespaceP = new ParamT<std::string>("robotNamespace", "/", 0); 00060 Param::End(); 00061 00062 this->contactConnectCount = 0; 00063 } 00064 00066 // Destructor 00067 GazeboRosBumper::~GazeboRosBumper() 00068 { 00069 delete this->robotNamespaceP; 00070 delete this->frameNameP; 00071 delete this->bumperTopicNameP; 00072 delete this->rosnode_; 00073 } 00074 00076 // Load the controller 00077 void GazeboRosBumper::LoadChild(XMLConfigNode *node) 00078 { 00079 this->robotNamespaceP->Load(node); 00080 this->robotNamespace = this->robotNamespaceP->GetValue(); 00081 00082 if (!ros::isInitialized()) 00083 { 00084 int argc = 0; 00085 char** argv = NULL; 00086 ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName); 00087 } 00088 00089 this->rosnode_ = new ros::NodeHandle(this->robotNamespace); 00090 00091 // "publishing contact/collisions to this topic name: " << this->bumperTopicName << std::endl; 00092 this->bumperTopicNameP->Load(node); 00093 this->bumperTopicName = this->bumperTopicNameP->GetValue(); 00094 ROS_DEBUG("publishing contact/collisions to topic name: %s", 00095 this->bumperTopicName.c_str()); 00096 00097 // "transform contact/collisions pose, forces to this body (link) name: " << this->frameName << std::endl; 00098 this->frameNameP->Load(node); 00099 this->frameName = this->frameNameP->GetValue(); 00100 00101 #ifdef USE_CBQ 00102 ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<gazebo_msgs::ContactsState>( 00103 this->bumperTopicName+std::string("/state"),1, 00104 boost::bind( &GazeboRosBumper::ContactConnect,this), 00105 boost::bind( &GazeboRosBumper::ContactDisconnect,this), ros::VoidPtr(), &this->contact_queue_); 00106 this->contact_pub_ = this->rosnode_->advertise(ao); 00107 #else 00108 this->contact_pub_ = this->rosnode_->advertise<gazebo_msgs::ContactsState>(this->bumperTopicName+std::string("/state"),1); 00109 #endif 00110 } 00111 00113 // Increment count 00114 void GazeboRosBumper::ContactConnect() 00115 { 00116 this->contactConnectCount++; 00117 } 00119 // Decrement count 00120 void GazeboRosBumper::ContactDisconnect() 00121 { 00122 this->contactConnectCount--; 00123 } 00124 00126 // Initialize the controller 00127 void GazeboRosBumper::InitChild() 00128 { 00129 // preset myFrame to NULL, will search for the body with matching name in UpdateChild() 00130 // since most bodies are constructed on the fly 00131 this->myFrame = NULL; 00132 #ifdef USE_CBQ 00133 // start custom queue for contact bumper 00134 this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosBumper::ContactQueueThread,this ) ); 00135 #endif 00136 } 00137 00139 // Update the controller 00140 void GazeboRosBumper::UpdateChild() 00141 { 00143 if (this->myFrame == NULL && this->frameName != "world" && this->frameName != "/map" && this->frameName != "map") 00144 { 00145 // lock in case a model is being spawned 00146 boost::recursive_mutex::scoped_lock lock(*Simulator::Instance()->GetMRMutex()); 00147 // look through all models in the world, search for body name that matches frameName 00148 std::vector<Model*> all_models = World::Instance()->GetModels(); 00149 for (std::vector<Model*>::iterator iter = all_models.begin(); iter != all_models.end(); iter++) 00150 { 00151 if (*iter) this->myFrame = dynamic_cast<Body*>((*iter)->GetBody(this->frameName)); 00152 if (this->myFrame) break; 00153 } 00154 00155 // not found 00156 if (this->myFrame == NULL) 00157 { 00158 ROS_DEBUG("gazebo_ros_bumper plugin: frameName: %s does not exist yet, will not publish\n",this->frameName.c_str()); 00159 return; 00160 } 00161 } 00162 00163 boost::mutex::scoped_lock sclock(this->lock); 00164 00165 bool in_contact; 00166 unsigned int num_contact_count = 0; 00167 int l = 0; 00168 std::string geom2_name; 00169 Vector3 body1ContactForce, body2ContactForce; 00170 Geom *geom1; 00171 00172 // Count the number of geom-geom contacts 00173 for (unsigned int i=0; i < this->myParent->GetGeomCount(); i++) 00174 num_contact_count += this->myParent->GetGeomContactCount(i) > 0; 00175 00176 // populate header 00177 //if (cur_body) 00178 // this->contactMsg.header.frame_id = cur_body->GetName(); // @todo: transform results to the link name 00179 00180 Time cur_time = Simulator::Instance()->GetSimTime(); 00181 this->contactsStateMsg.header.frame_id = frameName; // information are in inertial coordinates 00182 this->contactsStateMsg.header.stamp.sec = cur_time.sec; 00183 this->contactsStateMsg.header.stamp.nsec = cur_time.nsec;; 00184 00185 // set contact states size 00186 this->contactsStateMsg.states.clear(); // one contact_count per pair of geoms in contact (up to 64 contact points per pair of geoms) 00187 00188 // get contact array sizes for this contact param. 00189 // each contact param has num_contact_count contact pairs, 00190 // each contact geom pair has up to 64 contact points 00191 //std::vector<Geom*> contact_geoms; 00192 int total_contact_points = 0; 00193 00194 // get reference frame (body(link)) pose and subtract from it to get relative 00195 // force, torque, position and normal vectors 00196 Pose3d pose, frame_pose; 00197 Quatern rot, frame_rot; 00198 Vector3 pos, frame_pos; 00199 if (this->myFrame) 00200 { 00201 frame_pose = this->myFrame->GetWorldPose(); // - this->myBody->GetCoMPose(); 00202 frame_pos = frame_pose.pos; 00203 frame_rot = frame_pose.rot; 00204 } 00205 else 00206 { 00207 // no specific frames specified, use identity pose, keeping relative frame at inertial origin 00208 frame_pos = Vector3(0,0,0); 00209 frame_rot = Quatern(1,0,0,0); // gazebo u,x,y,z == identity 00210 frame_pose = Pose3d(frame_pos,frame_rot); 00211 } 00212 00213 // For each geom that the sensor is monitoring 00214 for (unsigned int i=0; i < this->myParent->GetGeomCount(); i++) 00215 { 00216 in_contact = this->myParent->GetGeomContactCount(i) > 0; 00217 00218 if (!in_contact) 00219 continue; 00220 00221 // get pointer to the Geom 00222 geom1 = this->myParent->GetGeom(i); 00223 00224 // Number of contacts for this geom ( this is the number of geom-geom 00225 // contacts) 00226 unsigned int contactCount = geom1->GetContactCount(); 00227 00228 total_contact_points += contactCount; 00229 00230 // For each geom-geom contact 00231 for (unsigned int j=0; j < contactCount; j++) 00232 { 00233 Contact contact = geom1->GetContact(j); 00234 unsigned int pts = contact.positions.size(); 00235 00236 std::ostringstream stream; 00237 stream << "touched! i:" << l 00238 << " my geom:" << contact.geom1->GetName() 00239 << " other geom:" << contact.geom2->GetName() 00240 << " time:" << contact.time 00241 << std::endl; 00242 00243 gazebo_msgs::ContactState state; 00244 state.info = stream.str(); 00245 state.geom1_name = contact.geom1->GetName(); 00246 state.geom2_name = contact.geom2->GetName(); 00247 00248 state.wrenches.clear(); 00249 state.contact_positions.clear(); 00250 state.contact_normals.clear(); 00251 state.depths.clear(); 00252 00253 // sum up all wrenches for each DOF 00254 geometry_msgs::Wrench total_wrench; 00255 total_wrench.force.x = 0; 00256 total_wrench.force.y = 0; 00257 total_wrench.force.z = 0; 00258 total_wrench.torque.x = 0; 00259 total_wrench.torque.y = 0; 00260 total_wrench.torque.z = 0; 00261 00262 for (unsigned int k=0; k < pts; k++) 00263 { 00264 // rotate into user specified frame. frame_rot is identity if world is used. 00265 Vector3 force = frame_rot.RotateVectorReverse(Vector3(contact.forces[k].body1Force.x, 00266 contact.forces[k].body1Force.y, 00267 contact.forces[k].body1Force.z)); 00268 Vector3 torque = frame_rot.RotateVectorReverse(Vector3(contact.forces[k].body1Torque.x, 00269 contact.forces[k].body1Torque.y, 00270 contact.forces[k].body1Torque.z)); 00271 00272 // set wrenches 00273 geometry_msgs::Wrench wrench; 00274 wrench.force.x = force.x; 00275 wrench.force.y = force.y; 00276 wrench.force.z = force.z; 00277 wrench.torque.x = torque.x; 00278 wrench.torque.y = torque.y; 00279 wrench.torque.z = torque.z; 00280 state.wrenches.push_back(wrench); 00281 total_wrench.force.x += wrench.force.x ; 00282 total_wrench.force.y += wrench.force.y ; 00283 total_wrench.force.z += wrench.force.z ; 00284 total_wrench.torque.x += wrench.torque.x; 00285 total_wrench.torque.y += wrench.torque.y; 00286 total_wrench.torque.z += wrench.torque.z; 00287 00288 // transform contact positions into relative frame 00289 // set contact positions 00290 gazebo::Vector3 contact_position; 00291 contact_position = contact.positions[k] - frame_pos; 00292 contact_position = frame_rot.RotateVectorReverse(contact_position); 00293 geometry_msgs::Vector3 tmp; 00294 tmp.x = contact_position.x; 00295 tmp.y = contact_position.y; 00296 tmp.z = contact_position.z; 00297 state.contact_positions.push_back(tmp); 00298 00299 // rotate normal into user specified frame. frame_rot is identity if world is used. 00300 Vector3 normal = frame_rot.RotateVectorReverse(Vector3(contact.normals[k].x, 00301 contact.normals[k].y, 00302 contact.normals[k].z)); 00303 // set contact normals 00304 geometry_msgs::Vector3 contact_normal; 00305 contact_normal.x = normal.x; 00306 contact_normal.y = normal.y; 00307 contact_normal.z = normal.z; 00308 state.contact_normals.push_back(contact_normal); 00309 00310 // set contact depth, interpenetration 00311 state.depths.push_back(contact.depths[k]); 00312 } 00313 state.total_wrench = total_wrench; 00314 this->contactsStateMsg.states.push_back(state); 00315 } 00316 } 00317 00318 this->contact_pub_.publish(this->contactsStateMsg); 00319 00320 } 00321 00323 // Finalize the controller 00324 void GazeboRosBumper::FiniChild() 00325 { 00326 this->rosnode_->shutdown(); 00327 this->callback_queue_thread_.join(); 00328 } 00329 00330 #ifdef USE_CBQ 00331 00332 // Put laser data to the interface 00333 void GazeboRosBumper::ContactQueueThread() 00334 { 00335 static const double timeout = 0.01; 00336 00337 while (this->rosnode_->ok()) 00338 { 00339 this->contact_queue_.callAvailable(ros::WallDuration(timeout)); 00340 } 00341 } 00342 #endif 00343 00344 }