$search
00001 /* 00002 * Software License Agreement (Modified BSD License) 00003 * 00004 * Copyright (c) 2012, PAL Robotics, S.L. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of PAL Robotics, S.L. nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 00035 #include <reem_bumper_gazebo/reem_bumper_gazebo.h> 00036 00037 #include <gazebo/Global.hh> 00038 #include <gazebo/XMLConfig.hh> 00039 #include <gazebo/ContactSensor.hh> 00040 #include <gazebo/World.hh> 00041 #include <gazebo/gazebo.h> 00042 #include <gazebo/GazeboError.hh> 00043 #include <gazebo/ControllerFactory.hh> 00044 #include <gazebo/Simulator.hh> 00045 #include <gazebo/Body.hh> 00046 #include <gazebo/Model.hh> 00047 #include <gazebo/Geom.hh> 00048 00049 #include <reem_msgs/Bumper.h> 00050 00051 00052 namespace gazebo 00053 { 00054 00055 GZ_REGISTER_DYNAMIC_CONTROLLER("reem_bumper_gazebo", My_Generic_Bumper); 00056 00058 // Constructor 00059 My_Generic_Bumper::My_Generic_Bumper(Entity *parent ) 00060 : Controller(parent) 00061 { 00062 this->myParent = dynamic_cast<gazebo::ContactSensor*>(this->parent); 00063 00064 if (!this->myParent) 00065 gzthrow("Bumper controller requires a Contact Sensor as its parent"); 00066 00067 Param::Begin(&this->parameters); 00068 this->bumperTopicNameP = new ParamT<std::string>("bumperTopicName", "", 1); 00069 this->frameNameP = new ParamT<std::string>("frameName", "world", 0); 00070 this->robotNamespaceP = new ParamT<std::string>("robotNamespace", "/", 0); 00071 this->frameIdP = new ParamT<std::string>("frameId", "/", 0); 00072 Param::End(); 00073 00074 this->contactConnectCount = 0; 00075 } 00076 00078 // Destructor 00079 My_Generic_Bumper::~My_Generic_Bumper() 00080 { 00081 delete this->robotNamespaceP; 00082 delete this->frameNameP; 00083 delete this->bumperTopicNameP; 00084 delete this->rosnode_; 00085 delete this->frameIdP; 00086 } 00087 00089 // Load the controller 00090 void My_Generic_Bumper::LoadChild(XMLConfigNode *node) 00091 { 00092 this->robotNamespaceP->Load(node); 00093 this->robotNamespace = this->robotNamespaceP->GetValue(); 00094 00095 if (!ros::isInitialized()) 00096 { 00097 int argc = 0; 00098 char** argv = NULL; 00099 ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName); 00100 } 00101 00102 this->rosnode_ = new ros::NodeHandle(this->robotNamespace); 00103 00104 // "publishing contact/collisions to this topic name: " << this->bumperTopicName << std::endl; 00105 this->bumperTopicNameP->Load(node); 00106 this->bumperTopicName = this->bumperTopicNameP->GetValue(); 00107 ROS_DEBUG("publishing contact/collisions to topic name: %s", 00108 this->bumperTopicName.c_str()); 00109 00110 // "transform contact/collisions pose, forces to this body (link) name: " << this->frameName << std::endl; 00111 this->frameNameP->Load(node); 00112 this->frameName = this->frameNameP->GetValue(); 00113 00114 this->frameIdP->Load(node); 00115 this->frameId = this->frameIdP->GetValue(); 00116 00117 00118 #ifdef USE_CBQ 00119 ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<reem_msgs::Bumper>(this->bumperTopicName+std::string("/state"),1,boost::bind( &My_Generic_Bumper::ContactConnect,this), 00120 boost::bind( &My_Generic_Bumper::ContactDisconnect,this), ros::VoidPtr(), &this->contact_queue_); 00121 this->contact_pub_ = this->rosnode_->advertise(ao); 00122 #else 00123 this->contact_pub_ = this->rosnode_->advertise<gazebo_msgs::ContactsState>(this->bumperTopicName+std::string("/state"),1); 00124 #endif 00125 } 00126 00128 // Increment count 00129 void My_Generic_Bumper::ContactConnect() 00130 { 00131 this->contactConnectCount++; 00132 } 00134 // Decrement count 00135 void My_Generic_Bumper::ContactDisconnect() 00136 { 00137 this->contactConnectCount--; 00138 } 00139 00141 // Initialize the controller 00142 void My_Generic_Bumper::InitChild() 00143 { 00144 // preset myFrame to NULL, will search for the body with matching name in UpdateChild() 00145 // since most bodies are constructed on the fly 00146 this->myFrame = NULL; 00147 #ifdef USE_CBQ 00148 // start custom queue for contact bumper 00149 this->callback_queue_thread_ = boost::thread( boost::bind( &My_Generic_Bumper::ContactQueueThread,this ) ); 00150 #endif 00151 } 00152 00154 // Update the controller 00155 void My_Generic_Bumper::UpdateChild() 00156 { 00158 if (this->myFrame == NULL && this->frameName != "world" && this->frameName != "/map" && this->frameName != "map") 00159 { 00160 // lock in case a model is being spawned 00161 boost::recursive_mutex::scoped_lock lock(*Simulator::Instance()->GetMRMutex()); 00162 // look through all models in the world, search for body name that matches frameName 00163 std::vector<Model*> all_models = World::Instance()->GetModels(); 00164 for (std::vector<Model*>::iterator iter = all_models.begin(); iter != all_models.end(); iter++) 00165 { 00166 if (*iter) this->myFrame = dynamic_cast<Body*>((*iter)->GetBody(this->frameName)); 00167 if (this->myFrame) break; 00168 } 00169 00170 // not found 00171 if (this->myFrame == NULL) 00172 { 00173 ROS_DEBUG("gazebo_ros_bumper plugin: frameName: %s does not exist yet, will not publish\n",this->frameName.c_str()); 00174 return; 00175 } 00176 } 00177 00178 boost::mutex::scoped_lock sclock(this->lock); 00179 00180 reem_msgs::Bumper bumperMsg; 00181 00182 bool in_contact; 00183 unsigned int num_contact_count = 0; 00184 int l = 0; 00185 std::string geom2_name; 00186 Vector3 body1ContactForce, body2ContactForce; 00187 Geom *geom1; 00188 00189 // Count the number of geom-geom contacts 00190 for (unsigned int i=0; i < this->myParent->GetGeomCount(); i++) 00191 num_contact_count += this->myParent->GetGeomContactCount(i) > 0; 00192 00193 // populate header 00194 //if (cur_body) 00195 // this->contactMsg.header.frame_id = cur_body->GetName(); // @todo: transform results to the link name 00196 00197 Time cur_time = Simulator::Instance()->GetSimTime(); 00198 this->contactsStateMsg.header.frame_id = frameName; // information are in inertial coordinates 00199 this->contactsStateMsg.header.stamp.sec = cur_time.sec; 00200 this->contactsStateMsg.header.stamp.nsec = cur_time.nsec; 00201 00202 bumperMsg.header.frame_id = this->frameId; 00203 bumperMsg.header.stamp = ros::Time::now(); 00204 bumperMsg.header.seq = 0; 00205 00206 // set contact states size 00207 this->contactsStateMsg.states.clear(); // one contact_count per pair of geoms in contact (up to 64 contact points per pair of geoms) 00208 00209 // get contact array sizes for this contact param. 00210 // each contact param has num_contact_count contact pairs, 00211 // each contact geom pair has up to 64 contact points 00212 //std::vector<Geom*> contact_geoms; 00213 int total_contact_points = 0; 00214 00215 // get reference frame (body(link)) pose and subtract from it to get relative 00216 // force, torque, position and normal vectors 00217 Pose3d pose, frame_pose; 00218 Quatern rot, frame_rot; 00219 Vector3 pos, frame_pos; 00220 if (this->myFrame) 00221 { 00222 frame_pose = this->myFrame->GetWorldPose(); // - this->myBody->GetCoMPose(); 00223 frame_pos = frame_pose.pos; 00224 frame_rot = frame_pose.rot; 00225 } 00226 else 00227 { 00228 // no specific frames specified, use identity pose, keeping relative frame at inertial origin 00229 frame_pos = Vector3(0,0,0); 00230 frame_rot = Quatern(1,0,0,0); // gazebo u,x,y,z == identity 00231 frame_pose = Pose3d(frame_pos,frame_rot); 00232 } 00233 00234 // For each geom that the sensor is monitoring 00235 for (unsigned int i=0; i < this->myParent->GetGeomCount(); i++) 00236 { 00237 in_contact = this->myParent->GetGeomContactCount(i) > 0; 00238 00239 if (!in_contact) 00240 continue; 00241 00242 // get pointer to the Geom 00243 geom1 = this->myParent->GetGeom(i); 00244 00245 // Number of contacts for this geom ( this is the number of geom-geom 00246 // contacts) 00247 unsigned int contactCount = geom1->GetContactCount(); 00248 00249 total_contact_points += contactCount; 00250 00251 // For each geom-geom contact 00252 for (unsigned int j=0; j < contactCount; j++) 00253 { 00254 Contact contact = geom1->GetContact(j); 00255 unsigned int pts = contact.positions.size(); 00256 00257 std::ostringstream stream; 00258 stream << "touched! i:" << l 00259 << " my geom:" << contact.geom1->GetName() 00260 << " other geom:" << contact.geom2->GetName() 00261 << " time:" << contact.time 00262 << std::endl; 00263 00264 gazebo_msgs::ContactState state; 00265 state.info = stream.str(); 00266 state.geom1_name = contact.geom1->GetName(); 00267 state.geom2_name = contact.geom2->GetName(); 00268 00269 state.wrenches.clear(); 00270 state.contact_positions.clear(); 00271 state.contact_normals.clear(); 00272 state.depths.clear(); 00273 00274 // sum up all wrenches for each DOF 00275 geometry_msgs::Wrench total_wrench; 00276 total_wrench.force.x = 0; 00277 total_wrench.force.y = 0; 00278 total_wrench.force.z = 0; 00279 total_wrench.torque.x = 0; 00280 total_wrench.torque.y = 0; 00281 total_wrench.torque.z = 0; 00282 00283 for (unsigned int k=0; k < pts; k++) 00284 { 00285 // rotate into user specified frame. frame_rot is identity if world is used. 00286 Vector3 force = frame_rot.RotateVectorReverse(Vector3(contact.forces[k].body1Force.x, 00287 contact.forces[k].body1Force.y, 00288 contact.forces[k].body1Force.z)); 00289 Vector3 torque = frame_rot.RotateVectorReverse(Vector3(contact.forces[k].body1Torque.x, 00290 contact.forces[k].body1Torque.y, 00291 contact.forces[k].body1Torque.z)); 00292 00293 // set wrenches 00294 geometry_msgs::Wrench wrench; 00295 wrench.force.x = force.x; 00296 wrench.force.y = force.y; 00297 wrench.force.z = force.z; 00298 wrench.torque.x = torque.x; 00299 wrench.torque.y = torque.y; 00300 wrench.torque.z = torque.z; 00301 state.wrenches.push_back(wrench); 00302 total_wrench.force.x += wrench.force.x ; 00303 total_wrench.force.y += wrench.force.y ; 00304 total_wrench.force.z += wrench.force.z ; 00305 total_wrench.torque.x += wrench.torque.x; 00306 total_wrench.torque.y += wrench.torque.y; 00307 total_wrench.torque.z += wrench.torque.z; 00308 00309 // transform contact positions into relative frame 00310 // set contact positions 00311 gazebo::Vector3 contact_position; 00312 contact_position = contact.positions[k] - frame_pos; 00313 contact_position = frame_rot.RotateVectorReverse(contact_position); 00314 geometry_msgs::Vector3 tmp; 00315 tmp.x = contact_position.x; 00316 tmp.y = contact_position.y; 00317 tmp.z = contact_position.z; 00318 state.contact_positions.push_back(tmp); 00319 00320 // rotate normal into user specified frame. frame_rot is identity if world is used. 00321 Vector3 normal = frame_rot.RotateVectorReverse(Vector3(contact.normals[k].x, 00322 contact.normals[k].y, 00323 contact.normals[k].z)); 00324 // set contact normals 00325 geometry_msgs::Vector3 contact_normal; 00326 contact_normal.x = normal.x; 00327 contact_normal.y = normal.y; 00328 contact_normal.z = normal.z; 00329 state.contact_normals.push_back(contact_normal); 00330 00331 // set contact depth, interpenetration 00332 state.depths.push_back(contact.depths[k]); 00333 } 00334 state.total_wrench = total_wrench; 00335 this->contactsStateMsg.states.push_back(state); 00336 if (state.contact_positions.empty()) 00337 { 00338 bumperMsg.is_pressed = false; 00339 boolMsg.data=false; 00340 } 00341 else 00342 { 00343 boolMsg.data=true; 00344 bumperMsg.is_pressed = true; 00345 } 00346 } 00347 } 00348 00349 // this->contact_pub_.publish(boolMsg); 00350 00351 //boolMsg.data=false; 00352 00353 this->contact_pub_.publish(bumperMsg); 00354 00355 bumperMsg.is_pressed = false; 00356 00357 } 00358 00360 // Finalize the controller 00361 void My_Generic_Bumper::FiniChild() 00362 { 00363 this->rosnode_->shutdown(); 00364 this->callback_queue_thread_.join(); 00365 } 00366 00367 #ifdef USE_CBQ 00368 00369 // Put laser data to the interface 00370 void My_Generic_Bumper::ContactQueueThread() 00371 { 00372 static const double timeout = 0.01; 00373 00374 while (this->rosnode_->ok()) 00375 { 00376 this->contact_queue_.callAvailable(ros::WallDuration(timeout)); 00377 } 00378 } 00379 #endif 00380 00381 }