$search
00001 /* 00002 * Copyright (c) 2008, Willow Garage, Inc. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the Willow Garage, Inc. nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "robot_link.h" 00031 #include "robot.h" 00032 #include "properties/property.h" 00033 #include "properties/property_manager.h" 00034 #include "visualization_manager.h" 00035 #include "selection/selection_manager.h" 00036 #include "mesh_loader.h" 00037 00038 #include "ogre_tools/stl_loader.h" 00039 #include "ogre_tools/object.h" 00040 #include "ogre_tools/shape.h" 00041 #include "ogre_tools/axes.h" 00042 00043 #include <urdf/model.h> 00044 #include <urdf_interface/link.h> 00045 00046 #include <OGRE/OgreSceneNode.h> 00047 #include <OGRE/OgreSceneManager.h> 00048 #include <OGRE/OgreRibbonTrail.h> 00049 #include <OGRE/OgreEntity.h> 00050 #include <OGRE/OgreSubEntity.h> 00051 #include <OGRE/OgreMaterialManager.h> 00052 #include <OGRE/OgreMaterial.h> 00053 #include <OGRE/OgreTextureManager.h> 00054 00055 #include <ros/console.h> 00056 00057 #include <resource_retriever/retriever.h> 00058 00059 #include <boost/filesystem.hpp> 00060 00061 namespace fs=boost::filesystem; 00062 00063 namespace rviz 00064 { 00065 00066 class RobotLinkSelectionHandler : public SelectionHandler 00067 { 00068 public: 00069 RobotLinkSelectionHandler(RobotLink* link); 00070 virtual ~RobotLinkSelectionHandler(); 00071 00072 virtual void createProperties(const Picked& obj, PropertyManager* property_manager); 00073 00074 private: 00075 RobotLink* link_; 00076 }; 00077 00078 RobotLinkSelectionHandler::RobotLinkSelectionHandler(RobotLink* link) 00079 : link_(link) 00080 { 00081 } 00082 00083 RobotLinkSelectionHandler::~RobotLinkSelectionHandler() 00084 { 00085 } 00086 00087 void RobotLinkSelectionHandler::createProperties(const Picked& obj, PropertyManager* property_manager) 00088 { 00089 std::stringstream ss; 00090 ss << link_->getName() << " Link " << link_->getName(); 00091 00092 CategoryPropertyWPtr cat = property_manager->createCategory( "Link " + link_->getName(), ss.str(), CategoryPropertyWPtr(), (void*)obj.handle ); 00093 properties_.push_back(cat); 00094 00095 properties_.push_back(property_manager->createProperty<Vector3Property>( "Position", ss.str(), boost::bind( &RobotLink::getPositionInRobotFrame, link_ ), 00096 Vector3Property::Setter(), cat, (void*)obj.handle )); 00097 00098 properties_.push_back(property_manager->createProperty<QuaternionProperty>( "Orientation", ss.str(), boost::bind( &RobotLink::getOrientationInRobotFrame, link_ ), 00099 QuaternionProperty::Setter(), cat, (void*)obj.handle )); 00100 } 00101 00102 RobotLink::RobotLink(Robot* parent, VisualizationManager* manager) 00103 : parent_(parent) 00104 , scene_manager_(manager->getSceneManager()) 00105 , property_manager_(0) 00106 , vis_manager_(manager) 00107 , visual_mesh_( NULL ) 00108 , collision_mesh_( NULL ) 00109 , visual_node_( NULL ) 00110 , collision_node_( NULL ) 00111 , position_(Ogre::Vector3::ZERO) 00112 , orientation_(Ogre::Quaternion::IDENTITY) 00113 , trail_( NULL ) 00114 , axes_( NULL ) 00115 , selection_object_(NULL) 00116 { 00117 } 00118 00119 RobotLink::~RobotLink() 00120 { 00121 if ( visual_mesh_ ) 00122 { 00123 scene_manager_->destroyEntity( visual_mesh_ ); 00124 } 00125 00126 if ( collision_mesh_ ) 00127 { 00128 scene_manager_->destroyEntity( collision_mesh_ ); 00129 } 00130 00131 if ( trail_ ) 00132 { 00133 scene_manager_->destroyRibbonTrail( trail_ ); 00134 } 00135 00136 delete axes_; 00137 00138 if (selection_object_) 00139 { 00140 vis_manager_->getSelectionManager()->removeObject(selection_object_); 00141 } 00142 00143 if (property_manager_) 00144 { 00145 property_manager_->deleteByUserData(this); 00146 } 00147 } 00148 00149 bool RobotLink::isValid() 00150 { 00151 return visual_mesh_ || collision_mesh_; 00152 } 00153 00154 void RobotLink::load(TiXmlElement* root_element, urdf::Model& descr, const urdf::LinkConstPtr& link, bool visual, bool collision) 00155 { 00156 name_ = link->name; 00157 00158 if ( visual ) 00159 { 00160 createVisual( root_element, link ); 00161 } 00162 00163 if ( collision ) 00164 { 00165 createCollision( root_element, link ); 00166 } 00167 00168 if (collision || visual) 00169 { 00170 createSelection( descr, link ); 00171 } 00172 00173 if ( property_manager_ ) 00174 { 00175 createProperties(); 00176 } 00177 } 00178 00179 void RobotLink::setAlpha(float a) 00180 { 00181 M_SubEntityToMaterial::iterator it = materials_.begin(); 00182 M_SubEntityToMaterial::iterator end = materials_.end(); 00183 for (; it != end; ++it) 00184 { 00185 const Ogre::MaterialPtr& material = it->second; 00186 00187 Ogre::ColourValue color = material->getTechnique(0)->getPass(0)->getDiffuse(); 00188 color.a = a; 00189 material->setDiffuse( color ); 00190 00191 if ( a < 0.9998 ) 00192 { 00193 material->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); 00194 material->setDepthWriteEnabled( false ); 00195 } 00196 else 00197 { 00198 material->setSceneBlending( Ogre::SBT_REPLACE ); 00199 material->setDepthWriteEnabled( true ); 00200 } 00201 } 00202 } 00203 00204 Ogre::MaterialPtr getMaterialForLink(TiXmlElement* root_element, const urdf::LinkConstPtr& link) 00205 { 00206 if (!link->visual || !link->visual->material) 00207 { 00208 return Ogre::MaterialManager::getSingleton().getByName("RVIZ/Red"); 00209 } 00210 00211 static int count = 0; 00212 std::stringstream ss; 00213 ss << "Robot Link Material" << count; 00214 00215 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(ss.str(), ROS_PACKAGE_NAME); 00216 mat->getTechnique(0)->setLightingEnabled(true); 00217 if (link->visual->material->texture_filename.empty()) 00218 { 00219 const urdf::Color& col = link->visual->material->color; 00220 mat->getTechnique(0)->setAmbient(col.r * 0.5, col.g * 0.5, col.b * 0.5); 00221 mat->getTechnique(0)->setDiffuse(col.r, col.g, col.b, col.a); 00222 } 00223 else 00224 { 00225 std::string filename = link->visual->material->texture_filename; 00226 if (!Ogre::TextureManager::getSingleton().resourceExists(filename)) 00227 { 00228 resource_retriever::Retriever retriever; 00229 resource_retriever::MemoryResource res; 00230 try 00231 { 00232 res = retriever.get(filename); 00233 } 00234 catch (resource_retriever::Exception& e) 00235 { 00236 ROS_ERROR("%s", e.what()); 00237 } 00238 00239 if (res.size != 0) 00240 { 00241 Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size)); 00242 Ogre::Image image; 00243 std::string extension = fs::extension(fs::path(filename)); 00244 00245 if (extension[0] == '.') 00246 { 00247 extension = extension.substr(1, extension.size() - 1); 00248 } 00249 00250 try 00251 { 00252 image.load(stream, extension); 00253 Ogre::TextureManager::getSingleton().loadImage(filename, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image); 00254 } 00255 catch (Ogre::Exception& e) 00256 { 00257 ROS_ERROR("Could not load texture [%s]: %s", filename.c_str(), e.what()); 00258 } 00259 } 00260 } 00261 00262 Ogre::Pass* pass = mat->getTechnique(0)->getPass(0); 00263 Ogre::TextureUnitState* tex_unit = pass->createTextureUnitState();; 00264 tex_unit->setTextureName(filename); 00265 } 00266 00267 return mat; 00268 } 00269 00270 void RobotLink::createEntityForGeometryElement(TiXmlElement* root_element, const urdf::LinkConstPtr& link, const urdf::Geometry& geom, const urdf::Pose& origin, Ogre::SceneNode* parent_node, Ogre::Entity*& entity, Ogre::SceneNode*& scene_node, Ogre::SceneNode*& offset_node) 00271 { 00272 scene_node = parent_node->createChildSceneNode(); 00273 offset_node = scene_node->createChildSceneNode(); 00274 00275 static int count = 0; 00276 std::stringstream ss; 00277 ss << "Robot Link" << count++; 00278 std::string entity_name = ss.str(); 00279 00280 Ogre::Vector3 scale(Ogre::Vector3::UNIT_SCALE); 00281 00282 Ogre::Vector3 offset_position(Ogre::Vector3::ZERO); 00283 Ogre::Quaternion offset_orientation(Ogre::Quaternion::IDENTITY); 00284 00285 00286 { 00287 Ogre::Vector3 position( origin.position.x, origin.position.y, origin.position.z ); 00288 Ogre::Quaternion orientation( Ogre::Quaternion::IDENTITY ); 00289 orientation = orientation * Ogre::Quaternion( origin.rotation.w, origin.rotation.x, origin.rotation.y, origin.rotation.z ); 00290 00291 offset_position = position; 00292 offset_orientation = orientation; 00293 } 00294 00295 switch (geom.type) 00296 { 00297 case urdf::Geometry::SPHERE: 00298 { 00299 const urdf::Sphere& sphere = static_cast<const urdf::Sphere&>(geom); 00300 entity = ogre_tools::Shape::createEntity(entity_name, ogre_tools::Shape::Sphere, scene_manager_); 00301 00302 scale = Ogre::Vector3( sphere.radius*2, sphere.radius*2, sphere.radius*2 ); 00303 break; 00304 } 00305 case urdf::Geometry::BOX: 00306 { 00307 const urdf::Box& box = static_cast<const urdf::Box&>(geom); 00308 entity = ogre_tools::Shape::createEntity(entity_name, ogre_tools::Shape::Cube, scene_manager_); 00309 00310 scale = Ogre::Vector3( box.dim.x, box.dim.y, box.dim.z ); 00311 00312 break; 00313 } 00314 case urdf::Geometry::CYLINDER: 00315 { 00316 const urdf::Cylinder& cylinder = static_cast<const urdf::Cylinder&>(geom); 00317 00318 Ogre::Quaternion rotX; 00319 rotX.FromAngleAxis( Ogre::Degree(90), Ogre::Vector3::UNIT_X ); 00320 offset_orientation = offset_orientation * rotX; 00321 00322 entity = ogre_tools::Shape::createEntity(entity_name, ogre_tools::Shape::Cylinder, scene_manager_); 00323 scale = Ogre::Vector3( cylinder.radius*2, cylinder.length, cylinder.radius*2 ); 00324 break; 00325 } 00326 case urdf::Geometry::MESH: 00327 { 00328 const urdf::Mesh& mesh = static_cast<const urdf::Mesh&>(geom); 00329 00330 if ( mesh.filename.empty() ) 00331 return; 00332 00333 scale = Ogre::Vector3(mesh.scale.x, mesh.scale.y, mesh.scale.z); 00334 00335 std::string model_name = mesh.filename; 00336 loadMeshFromResource(model_name); 00337 00338 try 00339 { 00340 entity = scene_manager_->createEntity( ss.str(), model_name ); 00341 } 00342 catch( Ogre::Exception& e ) 00343 { 00344 ROS_ERROR( "Could not load model '%s' for link '%s': %s\n", model_name.c_str(), link->name.c_str(), e.what() ); 00345 } 00346 break; 00347 } 00348 default: 00349 ROS_WARN("Unsupported geometry type for element: %d", geom.type); 00350 break; 00351 } 00352 00353 if ( entity ) 00354 { 00355 offset_node->attachObject(entity); 00356 offset_node->setScale(scale); 00357 offset_node->setPosition(offset_position); 00358 offset_node->setOrientation(offset_orientation); 00359 00360 if (default_material_name_.empty()) 00361 { 00362 default_material_ = getMaterialForLink(root_element, link); 00363 00364 static int count = 0; 00365 std::stringstream ss; 00366 ss << default_material_->getName() << count++ << "Robot"; 00367 std::string cloned_name = ss.str(); 00368 00369 default_material_ = default_material_->clone(cloned_name); 00370 default_material_name_ = default_material_->getName(); 00371 } 00372 00373 for (uint32_t i = 0; i < entity->getNumSubEntities(); ++i) 00374 { 00375 // Assign materials only if the submesh does not have one already 00376 Ogre::SubEntity* sub = entity->getSubEntity(i); 00377 const std::string& material_name = sub->getMaterialName(); 00378 00379 if (material_name == "BaseWhite" || material_name == "BaseWhiteNoLighting") 00380 { 00381 sub->setMaterialName(default_material_name_); 00382 } 00383 else 00384 { 00385 // Need to clone here due to how selection works. Once selection id is done per object and not per material, 00386 // this can go away 00387 static int count = 0; 00388 std::stringstream ss; 00389 ss << material_name << count++ << "Robot"; 00390 std::string cloned_name = ss.str(); 00391 sub->getMaterial()->clone(cloned_name); 00392 sub->setMaterialName(cloned_name); 00393 } 00394 00395 materials_[sub] = sub->getMaterial(); 00396 } 00397 } 00398 } 00399 00400 void RobotLink::createCollision(TiXmlElement* root_element, const urdf::LinkConstPtr& link) 00401 { 00402 if (!link->collision || !link->collision->geometry) 00403 return; 00404 00405 createEntityForGeometryElement(root_element, link, *link->collision->geometry, link->collision->origin, parent_->getCollisionNode(), collision_mesh_, collision_node_, collision_offset_node_); 00406 } 00407 00408 void RobotLink::createVisual(TiXmlElement* root_element, const urdf::LinkConstPtr& link ) 00409 { 00410 if (!link->visual || !link->visual->geometry) 00411 return; 00412 00413 createEntityForGeometryElement(root_element, link, *link->visual->geometry, link->visual->origin, parent_->getVisualNode(), visual_mesh_, visual_node_, visual_offset_node_); 00414 } 00415 00416 void RobotLink::createSelection(const urdf::Model& descr, const urdf::LinkConstPtr& link) 00417 { 00418 selection_handler_ = RobotLinkSelectionHandlerPtr(new RobotLinkSelectionHandler(this)); 00419 SelectionManager* sel_man = vis_manager_->getSelectionManager(); 00420 selection_object_ = sel_man->createHandle(); 00421 sel_man->addObject(selection_object_, selection_handler_); 00422 00423 M_SubEntityToMaterial::iterator it = materials_.begin(); 00424 M_SubEntityToMaterial::iterator end = materials_.end(); 00425 for (; it != end; ++it) 00426 { 00427 const Ogre::MaterialPtr& material = it->second; 00428 00429 sel_man->addPickTechnique(selection_object_, material); 00430 } 00431 00432 if (visual_mesh_) 00433 { 00434 selection_handler_->addTrackedObject(visual_mesh_); 00435 } 00436 00437 if (collision_mesh_) 00438 { 00439 selection_handler_->addTrackedObject(collision_mesh_); 00440 } 00441 } 00442 00443 void RobotLink::setPropertyManager(PropertyManager* property_manager) 00444 { 00445 property_manager_ = property_manager; 00446 } 00447 00448 void RobotLink::createProperties() 00449 { 00450 ROS_ASSERT( property_manager_ ); 00451 00452 std::stringstream ss; 00453 ss << parent_->getName() << " Link " << name_; 00454 00455 CategoryPropertyWPtr cat = property_manager_->createCategory( name_, ss.str(), parent_->getLinksCategory(), this ); 00456 00457 00458 trail_property_ = property_manager_->createProperty<BoolProperty>( "Show Trail", ss.str(), boost::bind( &RobotLink::getShowTrail, this ), 00459 boost::bind( &RobotLink::setShowTrail, this, _1 ), cat, this ); 00460 setPropertyHelpText(trail_property_, "Enable/disable a 2 meter \"ribbon\" which follows this link."); 00461 00462 axes_property_ = property_manager_->createProperty<BoolProperty>( "Show Axes", ss.str(), boost::bind( &RobotLink::getShowAxes, this ), 00463 boost::bind( &RobotLink::setShowAxes, this, _1 ), cat, this ); 00464 setPropertyHelpText(axes_property_, "Enable/disable showing the axes of this link."); 00465 00466 position_property_ = property_manager_->createProperty<Vector3Property>( "Position", ss.str(), boost::bind( &RobotLink::getPositionInRobotFrame, this ), 00467 Vector3Property::Setter(), cat, this ); 00468 setPropertyHelpText(position_property_, "Position of this link, in the current Fixed Frame. (Not editable)"); 00469 orientation_property_ = property_manager_->createProperty<QuaternionProperty>( "Orientation", ss.str(), boost::bind( &RobotLink::getOrientationInRobotFrame, this ), 00470 QuaternionProperty::Setter(), cat, this ); 00471 setPropertyHelpText(orientation_property_, "Orientation of this link, in the current Fixed Frame. (Not editable)"); 00472 00473 CategoryPropertyPtr cat_prop = cat.lock(); 00474 cat_prop->collapse(); 00475 } 00476 00477 00478 Ogre::Vector3 RobotLink::getPositionInRobotFrame() 00479 { 00480 return position_; 00481 } 00482 00483 Ogre::Quaternion RobotLink::getOrientationInRobotFrame() 00484 { 00485 return orientation_; 00486 } 00487 00488 void RobotLink::setShowTrail(bool show) 00489 { 00490 if ( show ) 00491 { 00492 if ( !trail_ ) 00493 { 00494 if ( visual_node_ ) 00495 { 00496 static int count = 0; 00497 std::stringstream ss; 00498 ss << "Trail for link " << name_ << count++; 00499 trail_ = scene_manager_->createRibbonTrail( ss.str() ); 00500 trail_->setMaxChainElements( 100 ); 00501 trail_->setInitialWidth( 0, 0.01f ); 00502 trail_->setInitialColour( 0, 0.0f, 0.5f, 0.5f ); 00503 trail_->addNode( visual_node_ ); 00504 trail_->setTrailLength( 2.0f ); 00505 parent_->getOtherNode()->attachObject( trail_ ); 00506 } 00507 else 00508 { 00509 ROS_WARN( "No visual node for link %s, cannot create a trail", name_.c_str() ); 00510 } 00511 } 00512 } 00513 else 00514 { 00515 if ( trail_ ) 00516 { 00517 scene_manager_->destroyRibbonTrail( trail_ ); 00518 trail_ = NULL; 00519 } 00520 } 00521 00522 propertyChanged(trail_property_); 00523 } 00524 00525 bool RobotLink::getShowTrail() 00526 { 00527 return trail_ != NULL; 00528 } 00529 00530 void RobotLink::setShowAxes(bool show) 00531 { 00532 if ( show ) 00533 { 00534 if ( !axes_ ) 00535 { 00536 static int count = 0; 00537 std::stringstream ss; 00538 ss << "Axes for link " << name_ << count++; 00539 axes_ = new ogre_tools::Axes( scene_manager_, parent_->getOtherNode(), 0.1, 0.01 ); 00540 } 00541 } 00542 else 00543 { 00544 if ( axes_ ) 00545 { 00546 delete axes_; 00547 axes_ = NULL; 00548 } 00549 } 00550 00551 propertyChanged(axes_property_); 00552 } 00553 00554 bool RobotLink::getShowAxes() 00555 { 00556 return axes_ != NULL; 00557 } 00558 00559 void RobotLink::setTransforms( const Ogre::Vector3& visual_position, const Ogre::Quaternion& visual_orientation, 00560 const Ogre::Vector3& collision_position, const Ogre::Quaternion& collision_orientation, bool apply_offset_transforms ) 00561 { 00562 position_ = visual_position; 00563 orientation_ = visual_orientation; 00564 00565 if ( visual_node_ ) 00566 { 00567 visual_node_->setPosition( visual_position ); 00568 visual_node_->setOrientation( visual_orientation ); 00569 } 00570 00571 if ( collision_node_ ) 00572 { 00573 collision_node_->setPosition( collision_position ); 00574 collision_node_->setOrientation( collision_orientation ); 00575 } 00576 00577 if (property_manager_) 00578 { 00579 propertyChanged(position_property_); 00580 propertyChanged(orientation_property_); 00581 } 00582 00583 00584 if ( axes_ ) 00585 { 00586 axes_->setPosition( position_ ); 00587 axes_->setOrientation( orientation_ ); 00588 } 00589 } 00590 00591 void RobotLink::setToErrorMaterial() 00592 { 00593 if (visual_mesh_) 00594 { 00595 visual_mesh_->setMaterialName("BaseWhiteNoLighting"); 00596 } 00597 00598 if (collision_mesh_) 00599 { 00600 collision_mesh_->setMaterialName("BaseWhiteNoLighting"); 00601 } 00602 } 00603 00604 void RobotLink::setToNormalMaterial() 00605 { 00606 M_SubEntityToMaterial::iterator it = materials_.begin(); 00607 M_SubEntityToMaterial::iterator end = materials_.end(); 00608 for (; it != end; ++it) 00609 { 00610 it->first->setMaterial(it->second); 00611 } 00612 } 00613 00614 } // namespace rviz 00615