robotMeshModel.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2008, Robert Bosch LLC.
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Robert Bosch nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *********************************************************************/
00036 
00037 /*
00038  * robotMeshModel.cpp
00039  *
00040  *  Created on: Oct 7, 2010
00041  *      Author: Christian Bersch
00042  */
00043 
00044 
00045 #include <GL/glew.h>
00046 #include <GL/glu.h>
00047 #include <GL/freeglut.h>
00048 #include "camera_self_filter/robotMeshModel.h"
00049 #include "LinearMath/btTransform.h"
00050 
00051 class ResourceIOStream : public Assimp::IOStream
00052 {
00053 public:
00054   ResourceIOStream(const resource_retriever::MemoryResource& res)
00055     : res_(res)
00056     , pos_(res.data.get())
00057   {}
00058 
00059   ~ResourceIOStream()
00060   {}
00061 
00062   size_t Read(void* buffer, size_t size, size_t count)
00063   {
00064     size_t to_read = size * count;
00065     if (pos_ + to_read > res_.data.get() + res_.size)
00066       {
00067         to_read = res_.size - (pos_ - res_.data.get());
00068       }
00069 
00070     memcpy(buffer, pos_, to_read);
00071     pos_ += to_read;
00072 
00073     return to_read;
00074   }
00075 
00076   size_t Write( const void* buffer, size_t size, size_t count) {
00077     ROS_BREAK(); return 0; }
00078 
00079   aiReturn Seek( size_t offset, aiOrigin origin)
00080   {
00081     uint8_t* new_pos = 0;
00082     switch (origin)
00083       {
00084       case aiOrigin_SET:
00085         new_pos = res_.data.get() + offset;
00086         break;
00087       case aiOrigin_CUR:
00088         new_pos = pos_ + offset; // TODO is this right?  can offset  really not be negative
00089     break;
00090       case aiOrigin_END:
00091         new_pos = res_.data.get() + res_.size - offset; // TODO is   this right?
00092     break;
00093       default:
00094         ROS_BREAK();
00095       }
00096 
00097     if (new_pos < res_.data.get() || new_pos > res_.data.get() +
00098     res_.size)
00099       {
00100         return aiReturn_FAILURE;
00101       }
00102 
00103     pos_ = new_pos;
00104     return aiReturn_SUCCESS;
00105   }
00106 
00107   size_t Tell() const
00108   {
00109     return pos_ - res_.data.get();
00110   }
00111 
00112   size_t FileSize() const
00113   {
00114     return res_.size;
00115   }
00116 
00117   void Flush() {}
00118 
00119 private:
00120   resource_retriever::MemoryResource res_;
00121   uint8_t* pos_;
00122 };
00123 
00124 class ResourceIOSystem : public Assimp::IOSystem
00125 {
00126 public:
00127   ResourceIOSystem()
00128   {
00129   }
00130 
00131   ~ResourceIOSystem()
00132   {
00133   }
00134 
00135   // Check whether a specific file exists
00136   bool Exists(const char* file) const
00137   {
00138     // Ugly -- two retrievals where there should be one (Exists + Open)
00139   // resource_retriever needs a way of checking for existence
00140   // TODO: cache this
00141   resource_retriever::MemoryResource res;
00142       try 
00143         {   
00144           res = retriever_.get(file);
00145         }   
00146       catch (resource_retriever::Exception& e)
00147         {   
00148           return false;
00149         }   
00150 
00151   return true;
00152 }
00153 
00154 // Get the path delimiter character we'd like to see
00155   char getOsSeparator() const
00156   {
00157     return '/';
00158   }
00159 
00160 // ... and finally a method to open a custom stream
00161 Assimp::IOStream* Open(const char* file, const char* mode)
00162 {
00163   ROS_ASSERT(mode == std::string("r") || mode == std::string("rb"));
00164 
00165   // Ugly -- two retrievals where there should be one (Exists + Open)
00166   // resource_retriever needs a way of checking for existence
00167   resource_retriever::MemoryResource res;
00168       try 
00169         {   
00170           res = retriever_.get(file);
00171         }   
00172       catch (resource_retriever::Exception& e)
00173         {   
00174           return 0;
00175         }   
00176 
00177       return new ResourceIOStream(res);
00178 }
00179 
00180 void Close(Assimp::IOStream* stream) { delete stream; }
00181 
00182 private:
00183 mutable resource_retriever::Retriever retriever_;
00184 };
00185 
00186 
00187 RobotMeshModel::SubMesh::SubMesh ()
00188 {
00189   // vbo = INVALID_VALUE;
00190   // ibo = INVALID_VALUE;
00191   // num_indices = 0;
00192 }
00193 
00194 RobotMeshModel::SubMesh::~SubMesh ()
00195 {
00196   // if (vbo != INVALID_VALUE)
00197   //   glDeleteBuffers (1, &vbo);
00198   // if (ibo != INVALID_VALUE)
00199   //   glDeleteBuffers (1, &ibo);
00200 }
00201 
00202 void RobotMeshModel::fromAssimpScene (const aiScene* scene)
00203 {
00204   //  meshes_vec.resize (scene->mNumMeshes);
00205   // std::cerr << "meshes loaded: " << meshes_vec.size () << std::endl;
00206   for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
00207     {
00208       const aiMesh* mesh = scene->mMeshes[i];
00209       initMesh (mesh);
00210     }
00211 }
00212 
00213 void RobotMeshModel::initMesh (const aiMesh* mesh)
00214 {
00215   // TODO: mesh->mMaterialIndex
00216   // TODO: const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
00217   std::vector<Vertex> vertices;
00218   std::vector<unsigned int> indices;
00219 
00220   for (unsigned int i = 0; i < mesh->mNumVertices; ++i)
00221     {
00222       const aiVector3D* pos = &(mesh->mVertices[i]);
00223       const aiVector3D* n = &(mesh->mNormals[i]);
00224       // TODO: const aiVector3D* pTexCoord = mesh->HasTextureCoords(0) ? &(mesh->mTextureCoords[0][i]) : &Zero3D;
00225 
00226       Vertex v(pos->x, pos->y, pos->z, n->x, n->y, n->z);
00227       vertices.push_back (v);
00228     }
00229 
00230   for (unsigned int i = 0 ; i < mesh->mNumFaces ; ++i)
00231     {
00232       const aiFace& face = mesh->mFaces[i];
00233       assert(face.mNumIndices == 3);
00234       indices.push_back(face.mIndices[0]);
00235       indices.push_back(face.mIndices[1]);
00236       indices.push_back(face.mIndices[2]);
00237     }
00238 
00239   SubMesh submesh;
00240   submesh.vertices.resize (vertices.size()); 
00241   submesh.vertices = vertices;
00242   submesh.indices.resize (indices.size()); 
00243   submesh.indices = indices;
00244   meshes_vec.push_back (submesh);
00245   // meshes[index].init (vertices, indices);
00246 }
00247 
00248 RobotMeshModel::RobotMeshModel():nh_priv_("~"), use_assimp_ (true)
00249 {
00250 
00251   //Load robot description from parameter server
00252   std::string robot_desc_string;
00253   if(!nh_.getParam("robot_description", robot_desc_string))
00254     {
00255       ROS_ERROR("Could not get urdf from param server");
00256     }
00257   
00258   if (!urdf_.initString(robot_desc_string))
00259     {
00260       ROS_ERROR("Failed to parse urdf");  
00261     }
00262   modelframe_= "/torso_lift_link";
00263   
00264   nh_priv_.param<std::string>("robot_description_package_path", description_path, "..");
00265   ROS_INFO("package_path %s", description_path.c_str());
00266   nh_priv_.param<std::string>("camera_topic", camera_topic_, "/wide_stereo/right" );
00267   nh_priv_.param<std::string>("camera_info_topic", camera_info_topic_, "/wide_stereo/right/camera_info" );
00268   
00269   
00270   //Load robot mesh for each link
00271   std::vector<boost::shared_ptr<urdf::Link> > links ;
00272   urdf_.getLinks(links);
00273   for (int i=0; i< links.size(); i++){
00274     if (links[i]->visual.get() == NULL) continue;
00275     if (links[i]->visual->geometry.get() == NULL) continue;
00276     if (links[i]->visual->geometry->type == urdf::Geometry::MESH)
00277       {
00278         //todo: this should really be done by resource retriever
00279         boost::shared_ptr<urdf::Mesh> mesh = boost::dynamic_pointer_cast<urdf::Mesh> (links[i]->visual->geometry);
00280         std::string filename (mesh->filename);
00281         std::string filename_resource = filename;
00282         
00283         if (filename.substr(filename.size() - 4 , 4) != ".stl" && filename.substr(filename.size() - 4 , 4) != ".dae") continue;
00284         
00285         // TODO load with assimp
00286         if (filename.substr(filename.size() - 4 , 4) == ".dae")
00287           filename.replace(filename.size() - 4 , 4, ".stl");
00288         //ROS_INFO("adding link %d %s",i,links[i]->name.c_str());
00289         filename.erase(0,25);
00290         filename = description_path + filename;
00291         
00292         Assimp::Importer as_importer;
00293         as_importer.SetIOHandler(new ResourceIOSystem());
00294         const aiScene* scene =
00295           as_importer.ReadFile(filename_resource.c_str(), aiProcess_SortByPType|aiProcess_GenNormals|aiProcess_Triangulate|aiProcess_GenUVCoords|aiProcess_FlipUVs);
00296         
00297         if (!scene)
00298           {
00299             ROS_ERROR("Could not load resource [%s]:  %s", filename_resource.c_str(),
00300                       as_importer.GetErrorString());
00301           }
00302         else
00303           {
00304             ROS_INFO ("Mesh [%s] successfully loaded.",
00305                       filename_resource.c_str());
00306             if (!scene->HasMeshes())
00307               { 
00308                 ROS_ERROR("No meshes found in file [%s]", filename_resource.c_str());
00309               }
00310             std::cerr << "Constructor mNumMeshes: " << scene->mNumMeshes << std::endl;
00311           }
00312         fromAssimpScene (scene);
00313         as_meshes[links[i]->name] = scene;
00314       }
00315     links_with_meshes.push_back(links[i]);
00316     
00317     
00318     tf::Vector3 origin(links[i]->visual->origin.position.x, links[i]->visual->origin.position.y, links[i]->visual->origin.position.z);
00319     tf::Quaternion rotation(links[i]->visual->origin.rotation.x, links[i]->visual->origin.rotation.y, links[i]->visual->origin.rotation.z, links[i]->visual->origin.rotation.w);
00320     
00321     offsets_[links[i]->name] = tf::Transform(rotation,
00322                                              origin);
00323   }
00324   
00325   initRobot();
00326   
00327   //get camera intinsics
00328   ROS_INFO("waiting for %s", camera_info_topic_.c_str());
00329   cam_info_ = ros::topic::waitForMessage<sensor_msgs::CameraInfo>(camera_info_topic_);
00330   cameraframe_ = cam_info_->header.frame_id;
00331   
00332   ROS_INFO("%s: robot model initialization done!", ros::this_node::getName().c_str());
00333 }
00334 
00335 RobotMeshModel::~RobotMeshModel(){
00336 
00337 }
00338 
00339 //TODO: Remove
00340 void RobotMeshModel::initRobot()
00341 {
00342 };
00343 
00344 
00345 void RobotMeshModel::updateRobotLinks(const ros::Time time_stamp){
00346 
00347         // get the current configuration of the robot links
00348         if (current_time_stamp_ != time_stamp){
00349                 current_time_stamp_ = time_stamp;
00350                 tf::StampedTransform tf;
00351                 for (int i=0; i < links_with_meshes.size(); ++i){
00352                         if (!tf_.waitForTransform(links_with_meshes[i]->name, modelframe_, current_time_stamp_, ros::Duration(0.5))){
00353                                 ROS_ERROR("could not get transform from %s to %s", links_with_meshes[i]->name.c_str(),modelframe_.c_str() );
00354                                 continue;
00355                         }
00356                         tf_.lookupTransform( modelframe_, links_with_meshes[i]->name, current_time_stamp_, tf);
00357 
00358                                         tf  *= offsets_[links_with_meshes[i]->name];;
00359                         robotLinks_[links_with_meshes[i]->name] = tf;
00360 
00361                 }
00362 
00363         }
00364 }
00365 
00366 
00367 void RobotMeshModel::paintRobot()
00368 {
00369   // draw the configuration of the robot links as  specified in robotLinks_
00370   float d=1.0f; 
00371   glScalef(1.0, 1.0, 1.0);
00372   glDisable(GL_CULL_FACE);
00373   glMatrixMode(GL_MODELVIEW);
00374   std::cerr << "meshes: " << meshes_vec.size () << std::endl;
00375   for (unsigned int n = 0; n < meshes_vec.size (); n++) 
00376     {
00377       std::cerr << "Lin name: " << links_with_meshes[n]->name <<
00378         " Vertices: " << meshes_vec[n].vertices.size() << std::endl;
00379       btScalar glTf[16];
00380       robotLinks_[links_with_meshes[n]->name].getOpenGLMatrix(glTf);
00381       glPushMatrix();
00382       glMultMatrixd((GLdouble*)glTf);
00383       
00384       for (unsigned int t = 0; t < meshes_vec[n].indices.size(); t
00385              = t + 3)
00386         {
00387           GLenum face_mode;
00388           switch(3) 
00389             {
00390             case 1: face_mode =
00391                 GL_POINTS; break;
00392             case 2: face_mode =
00393                 GL_LINES; break;
00394             case 3: face_mode =
00395                 GL_TRIANGLES; break;
00396             default: face_mode
00397                 = GL_POLYGON; break;
00398             }
00399           glBegin(face_mode); // Drawing Using Triangles
00400           glVertex3f(meshes_vec[n].vertices[t].x,
00401                      meshes_vec[n].vertices[t].y,
00402                      meshes_vec[n].vertices[t].z); // Top
00403           glVertex3f(meshes_vec[n].vertices[t+1].x,
00404                      meshes_vec[n].vertices[t+1].y,
00405                      meshes_vec[n].vertices[t+1].z); // Bottom Left
00406           glVertex3f(meshes_vec[n].vertices[t+2].x,
00407                      meshes_vec[n].vertices[t+2].y,
00408                      meshes_vec[n].vertices[t+2].z); // Bottom Right
00409           
00410           glNormal3f(meshes_vec[n].vertices[t].nx,
00411                      meshes_vec[n].vertices[t].ny,
00412                      meshes_vec[n].vertices[t].nz); // Top
00413           glNormal3f(meshes_vec[n].vertices[t+1].nx,
00414                      meshes_vec[n].vertices[t+1].ny,
00415                      meshes_vec[n].vertices[t+1].nz); // Bottom Left
00416           glNormal3f(meshes_vec[n].vertices[t+2].nx,
00417                      meshes_vec[n].vertices[t+2].ny,
00418                      meshes_vec[n].vertices[t+2].nz); // Bottom Right
00419           glEnd();  
00420         }
00421       glPopMatrix();
00422       
00423     }
00424 }
00425 
00426 void RobotMeshModel::setCameraInfo(sensor_msgs::CameraInfoConstPtr cam_info){
00427   cam_info_ = cam_info;
00428 }
00429 
00430 
00431 void RobotMeshModel::setCamera(){
00432 
00433         //calc field of view for OpenGL Camera;
00434 
00435     double FulstrumWidth, FulstrumHeight, left, right, top, bottom;
00436 
00437     double near_clip = 0.1;
00438     double farclip = 100;
00439 
00440 
00441     double cx= cam_info_->P[2];
00442     double cy = cam_info_->P[6];
00443 
00444     double fx = cam_info_->P[0];
00445     double fy = cam_info_->P[5];
00446 
00447 
00448     FulstrumWidth = near_clip * cam_info_->width / fx;
00449     FulstrumHeight = near_clip * cam_info_->height / fy;
00450 
00451 
00452     left = FulstrumWidth * (- cx / cam_info_->width);
00453     right = FulstrumWidth * ( 1.0 - cx / cam_info_->width);
00454     top = FulstrumHeight * ( cy / cam_info_->height);
00455     bottom = FulstrumHeight * ( -1.0 + cy / cam_info_->height);
00456 
00457 
00458     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00459     glMatrixMode(GL_PROJECTION);
00460     glLoadIdentity();
00461 
00462     glFrustum(left,right, bottom, top, near_clip, farclip);
00463     glMatrixMode(GL_MODELVIEW);
00464 
00465 }
00466 
00467 
00468 bool RobotMeshModel::setCameraPose(){
00469 
00470 
00471         //set camera pose relative to robot links
00472         if (!tf_.waitForTransform(modelframe_, cameraframe_, current_time_stamp_, ros::Duration(0.5))){
00473                         ROS_ERROR("setting cam pose: could not get transform from %s to %s", modelframe_.c_str(),cameraframe_.c_str() );
00474                         return false;
00475          }
00476         tf_.lookupTransform(modelframe_, cameraframe_, current_time_stamp_, cameraPose);
00477 
00478 
00479         //get offset for stereo
00480         double tx = -1.0 * (cam_info_->P[3] / cam_info_->P[0]);
00481         tf::Vector3 origin = cameraPose.getOrigin() + cameraPose.getBasis() * tf::Vector3(tx, 0.0, 0.0);
00482 
00483         tf::Vector3 look_at_position = origin + cameraPose.getBasis().getColumn(2);
00484          glLoadIdentity();
00485          tf::Vector3 up = -cameraPose.getBasis().getColumn(1);
00486 
00487          gluLookAt(origin.getX() , origin.getY() , origin.getZ() ,
00488                          look_at_position.getX() , look_at_position.getY(), look_at_position.getZ(),
00489                          up.getX(), up.getY(), up.getZ());
00490          return true;
00491 }
00492 
00493 


camera_self_filter
Author(s): Christian Bersch (Maintained by Benjamin Pitzer)
autogenerated on Thu Jan 2 2014 11:07:31