robot_link.cpp
Go to the documentation of this file.
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 


rviz_qt
Author(s): Dave Hershberger
autogenerated on Fri Dec 6 2013 20:56:53