cmap_plugin.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002  * \file
00003  *
00004  * $Id:$
00005  *
00006  * Copyright (C) Brno University of Technology
00007  *
00008  * This file is part of software developed by dcgm-robotics@FIT group.
00009  *
00010  * Author: Vit Stancl (stancl@fit.vutbr.cz)
00011  * Supervised by: Michal Spanel (spanel@fit.vutbr.cz)
00012  * Date: dd/mm/2012
00013  * 
00014  * This file is free software: you can redistribute it and/or modify
00015  * it under the terms of the GNU Lesser General Public License as published by
00016  * the Free Software Foundation, either version 3 of the License, or
00017  * (at your option) any later version.
00018  * 
00019  * This file is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU Lesser General Public License for more details.
00023  * 
00024  * You should have received a copy of the GNU Lesser General Public License
00025  * along with this file.  If not, see <http://www.gnu.org/licenses/>.
00026  */
00027 
00028 #include <srs_env_model/but_server/plugins/cmap_plugin.h>
00029 #include <srs_env_model/topics_list.h>
00030 
00031 #include <pcl_ros/transforms.h>
00032 
00033 #define FIXED_FRAME "/map"
00034 
00035 srs_env_model::CCMapPlugin::CCMapPlugin(const std::string & name)
00036 : srs_env_model::CServerPluginBase(name)
00037 , m_cmapPublisherName(COLLISION_MAP_PUBLISHER_NAME)
00038 , m_collisionMapLimitRadius(2.0)
00039 , m_collisionMapVersion(0)
00040 , m_cmapFrameId(COLLISION_MAP_FRAME_ID)
00041 , m_dataBuffer( new tData )
00042 , m_publishCollisionMap( true )
00043 , m_tfListener( ros::Duration(tf::Transformer::DEFAULT_CACHE_TIME), true )
00044 , m_latchedTopics(false)
00045 , m_bConvertPoint( false )
00046 , m_mapTime(0)
00047 {
00048 }
00049 
00051 void srs_env_model::CCMapPlugin::init(ros::NodeHandle & node_handle)
00052 {
00053         m_collisionMapVersion = 0;
00054         m_dataBuffer->boxes.clear();
00055         m_data->boxes.clear();
00056 
00057         // Read parameters
00058 
00059         // Get collision map radius
00060         node_handle.param("collision_map_radius", m_collisionMapLimitRadius, COLLISION_MAP_RADIUS_LIMIT );
00061 
00062         // Get collision map topic name
00063         node_handle.param("collision_map_publisher", m_cmapPublisherName, COLLISION_MAP_PUBLISHER_NAME );
00064 
00065         // Get FID to which will be points transformed when publishing collision map
00066         node_handle.param("collision_map_frame_id", m_cmapFrameId, COLLISION_MAP_FRAME_ID ); //
00067 
00068         // Create and publish service - get collision map
00069         m_serviceGetCollisionMap = node_handle.advertiseService( GetCollisionMap_SRV,   &CCMapPlugin::getCollisionMapSrvCallback, this);
00070 
00071         // Create and publish service - is new collision map
00072         m_serviceIsNewCMap = node_handle.advertiseService( IsNewCMap_SRV, &CCMapPlugin::isNewCmapSrvCallback, this );
00073 
00074         // Create and publish service - lock map
00075         m_serviceLockCMap = node_handle.advertiseService( LockCMap_SRV, &CCMapPlugin::lockCmapSrvCallback, this );
00076 
00077         // Create and publish service - remove cube from map
00078         m_serviceRemoveCube = node_handle.advertiseService( RemoveCubeCMP_SRV, &CCMapPlugin::removeBoxCallback, this );
00079 
00080         // Create and publish service - add cube to map
00081         m_serviceAddCube = node_handle.advertiseService( AddCubeCMP_SRV, &CCMapPlugin::addBoxCallback, this );
00082 
00083         // Connect publishing services
00084         pause( false, node_handle );
00085 }
00086 
00088 void srs_env_model::CCMapPlugin::publishInternal(const ros::Time & timestamp)
00089 {
00090         // Lock data
00091         boost::mutex::scoped_lock lock(m_lockData);
00092 
00093         // Should map be published?
00094         bool publishCollisionMap = m_publishCollisionMap && (m_latchedTopics || m_cmapPublisher.getNumSubscribers() > 0);
00095 
00096         // Test collision maps and swap them, if needed
00097         if( ! sameCMaps( m_data.get(), m_dataBuffer.get() ) )
00098         {
00099                 // CMaps differs, increase version index and swap them
00100                 ++m_collisionMapVersion;
00101                 m_mapTime = timestamp;
00102                 swap( m_data, m_dataBuffer );
00103 
00104                 lock.unlock();
00105 
00106                 // Call invalidation
00107                 invalidate();
00108         }
00109 
00110         if( m_bLocked )
00111         {
00112                 if( m_mapTime != timestamp )
00113                 {
00114                         retransformTF(timestamp);
00115                 }
00116         }
00117 
00118         // Publish collision map
00119         if (publishCollisionMap) {
00120 //              std::cerr << "Publishing cmap. Frame id: " << m_cmapFrameId << ", Size: " << m_data->boxes.size() << std::endl;
00121                 m_data->header.frame_id = m_cmapFrameId;
00122                 m_data->header.stamp = timestamp;
00123                 m_cmapPublisher.publish(*m_data);
00124         }
00125 }
00126 
00128 void srs_env_model::CCMapPlugin::newMapDataCB( SMapWithParameters & par )
00129 {
00130         if( m_bLocked )
00131         {
00132                 return;
00133         }
00134         // Lock data
00135         boost::mutex::scoped_lock lock(m_lockData);
00136 
00137         // Reset collision map buffer
00138         m_dataBuffer->boxes.clear();
00139 
00140         std::string robotBaseFrameId("/base_footprint");
00141 
00142         // Get octomap to collision map transform matrix
00143         tf::StampedTransform omapToCmapTf,      // Octomap to collision map
00144                                                  baseToOmapTf,  // Robot baselink to octomap
00145                                                  cmapToWorldTF; // Collision map to world
00146         try
00147         {
00148                 // Transformation - to, from, time, waiting time
00149                 m_tfListener.waitForTransform(m_cmapFrameId, par.frameId, par.currentTime, ros::Duration(5));
00150                 m_tfListener.lookupTransform(m_cmapFrameId, par.frameId, par.currentTime, omapToCmapTf);
00151 
00152                 m_tfListener.waitForTransform(par.frameId, robotBaseFrameId, par.currentTime, ros::Duration(5));
00153                 m_tfListener.lookupTransform(par.frameId, robotBaseFrameId, par.currentTime, baseToOmapTf);
00154         }
00155         catch (tf::TransformException& ex) {
00156                 ROS_ERROR_STREAM("Transform error: " << ex.what() << ", quitting callback");
00157                 PERROR( "Transform error.");
00158                 return;
00159         }
00160 
00161 
00162         // World TF to the collision map TF
00163         pcl_ros::transformAsMatrix(omapToCmapTf, m_worldToCMapTM );
00164 
00165         // Disassemble world to cmap translation and rotation
00166         m_worldToCMapRot  = m_worldToCMapTM.block<3, 3> (0, 0);
00167         m_worldToCMapTrans = m_worldToCMapTM.block<3, 1> (0, 3);
00168 
00169         m_bConvertPoint = m_cmapFrameId != par.frameId;
00170 
00171         // Compute robot position in the collision map coordinate system
00172         geometry_msgs::TransformStamped msg;
00173         tf::transformStampedTFToMsg(baseToOmapTf, msg);
00174         m_robotBasePosition.setX( msg.transform.translation.x );
00175         m_robotBasePosition.setY( msg.transform.translation.y );
00176         m_robotBasePosition.setZ( msg.transform.translation.z );
00177 
00178         tButServerOcTree & tree( par.map->getTree() );
00179         srs_env_model::tButServerOcTree::leaf_iterator it, itEnd( tree.end_leafs() );
00180 
00181         // Crawl through nodes
00182         for ( it = tree.begin_leafs(m_crawlDepth); it != itEnd; ++it)
00183         {
00184                 // Node is occupied?
00185                 if (tree.isNodeOccupied(*it))
00186                 {
00187                         handleOccupiedNode(it, par);
00188                 }// Node is occupied?
00189 
00190         } // Iterate through octree
00191 
00192         m_DataTimeStamp = par.currentTime;
00193 
00194         lock.unlock();
00195 
00196         invalidate();
00197 }
00198 
00200 void srs_env_model::CCMapPlugin::handleOccupiedNode(srs_env_model::tButServerOcTree::iterator& it, const SMapWithParameters & mp)
00201 {
00202         if( m_bLocked )
00203                         return;
00204 
00205         // Should we publish something?
00206         if (! m_publishCollisionMap)
00207                 return;
00208 
00209         // Is this point near enough to the robot?
00210         if( ! isNearRobot( btVector3( it.getX(), it.getY(), it.getZ() ), it.getSize() ) )
00211                 return;
00212 
00213         Eigen::Vector3f point( it.getX(), it.getY(), it.getZ() );
00214 
00215         if( m_bConvertPoint )
00216         {
00217             // Transform point from the world to the CMap TF
00218             point = m_worldToCMapRot * point + m_worldToCMapTrans;
00219         }
00220 
00221         // Add point to the collision map
00222         //arm_navigation_msgs::OrientedBoundingBox box;
00223         tBox box;
00224 
00225         double size = it.getSize();
00226         box.extents.x = box.extents.y = box.extents.z = size;
00227         box.axis.x = box.axis.y = 0.0;
00228         box.axis.z = 1.0;
00229         box.angle = 0.0;
00230         box.center.x = point[0];
00231         box.center.y = point[1];
00232         box.center.z = point[2];
00233 
00234 
00235         m_dataBuffer->boxes.push_back(box);
00236 }
00237 
00245 bool srs_env_model::CCMapPlugin::sameCMaps( arm_navigation_msgs::CollisionMap * map1, arm_navigation_msgs::CollisionMap * map2 )
00246 {
00247         // Do not swap maps, if in the locked mode
00248         if( m_bLocked )
00249                 return true;
00250 
00251         // Wrong input
00252         if( map1 == 0 || map2 == 0 )
00253         {
00254 //              std::cerr << "Some null. map1: " << map1 << ", map2: " << map2 << std::endl;
00255                 return false;
00256         }
00257 
00258         // Two maps cannot be the same, if differs in the size
00259         if( map1->boxes.size() != map2->boxes.size() )
00260         {
00261 //              std::cerr << "Maps size different. map1: " << map1->boxes.size() << ", map2: " << map2->boxes.size() << std::endl;
00262                 return false;
00263         }
00264 
00265         // Compare maps box by box
00266         arm_navigation_msgs::CollisionMap::_boxes_type::iterator icm1, icm2;
00267         arm_navigation_msgs::CollisionMap::_boxes_type::iterator end1( map1->boxes.end());
00268 
00269         long num( 0 );
00270         for( icm1 = map1->boxes.begin(), icm2 = map2->boxes.begin(); icm1 != end1; ++icm1, ++icm2 )
00271         {
00272                 if( isGreat( icm1->center.x - icm2->center.x ) ||
00273                                 isGreat( icm1->center.y - icm2->center.y ) ||
00274                                 isGreat( icm1->center.z - icm2->center.z ) ||
00275                                 isGreat( icm1->extents.x - icm2->extents.x ) )
00276                 {
00277 //                      std::cerr << "Point number " << num << " different." << std::endl;
00278                         return false;
00279                 }
00280                 ++num;
00281         }
00282 
00283         return true;
00284 }
00285 
00286 
00287 
00295 bool srs_env_model::CCMapPlugin::isNearRobot( const btVector3 & point, double extent )
00296 {
00297         btScalar s( point.distance( m_robotBasePosition ) );
00298 
00299         return s - extent < m_collisionMapLimitRadius;
00300 }
00301 
00308 bool srs_env_model::CCMapPlugin::getCollisionMapSrvCallback( srs_env_model::GetCollisionMap::Request & req, srs_env_model::GetCollisionMap::Response & res )
00309 {
00310 
00311         PERROR( "Get collision map service called" );
00312 
00313         // Response map version should be current version number
00314         res.current_version = m_collisionMapVersion;
00315 
00316         // Get callers map version and compare to the current version number
00317         if( req.my_version != m_collisionMapVersion )
00318         {
00319                 res.map = *m_data;
00320         }else{
00321                 // No new data needed
00322                 res.map = m_dataEmpty;
00323         }
00324 
00325         return true;
00326 }
00327 
00331 bool srs_env_model::CCMapPlugin::shouldPublish(  )
00332 {
00333         return(m_publishCollisionMap && (m_latchedTopics || m_cmapPublisher.getNumSubscribers() > 0));
00334 }
00335 
00341 bool srs_env_model::CCMapPlugin::isNewCmapSrvCallback( srs_env_model::IsNewCollisionMap::Request & req, srs_env_model::IsNewCollisionMap::Response & res )
00342 {
00343         PERROR( "Is new cmap service called ");
00344 
00345         res.is_newer = req.my_time < m_mapTime;
00346         res.current_time = m_mapTime;
00347 
00348         return true;
00349 }
00350 
00356 bool srs_env_model::CCMapPlugin::lockCmapSrvCallback( srs_env_model::LockCollisionMap::Request & req, srs_env_model::LockCollisionMap::Response & res )
00357 {
00358         boost::mutex::scoped_lock lock( m_lockData );
00359 
00360         bool locked( req.lock != 0 );
00361 
00362         m_bLocked = locked;
00363 /*
00364         if( locked )
00365                 std::cerr << "Locking called. Lock set." << std::endl;
00366         else
00367                 std::cerr << "Locking called. Lock removed." << std::endl;
00368 */
00369         return true;
00370 }
00371 
00375 void srs_env_model::CCMapPlugin::pause( bool bPause, ros::NodeHandle & node_handle )
00376 {
00377         if( bPause )
00378                 m_cmapPublisher.shutdown();
00379         else
00380                 m_cmapPublisher = node_handle.advertise<arm_navigation_msgs::CollisionMap> ( m_cmapPublisherName, 5, m_latchedTopics);
00381 }
00382 
00389 long srs_env_model::CCMapPlugin::removeInsideBox( const tBoxPoint & center, const tBoxPoint & size, tBoxVec & boxes )
00390 {
00391         boost::mutex::scoped_lock lock( m_lockData );
00392 
00393         // Create data copy
00394         tBoxVec buffer( boxes.begin(), boxes.end() );
00395 
00396         // Clear output
00397         boxes.clear();
00398 
00399         // Compute testing box extents
00400         tBoxPoint extents;
00401         extents.x = size.x / 2.0; extents.y = size.y / 2.0; extents.z = size.z / 2.0;
00402 
00403         long counter(0);
00404 
00405         // Add excluded boxes to the data
00406         tBoxVec::iterator it, itEnd( buffer.end() );
00407         for( it = buffer.begin(); it != itEnd; ++it )
00408         {
00409                 if( abs( it->center.x - center.x ) > (it->extents.x + extents.x ) ||
00410                         abs( it->center.y - center.y ) > (it->extents.y + extents.y ) ||
00411                         abs( it->center.z - center.z ) > (it->extents.z + extents.z ) )
00412                 {
00413                         boxes.push_back( *it );
00414                         ++counter;
00415                 }
00416 
00417         }
00418 
00419         // Return number of removed boxes
00420         return buffer.size() - counter;
00421 }
00422 
00423 #define POINT_ADD( p0, p1, p2 ) {p0.x = p1.x + p2.x; p0.y = p1.y + p2.y; p0.z = p1.z + p2.z;}
00424 #define POINT_SUB( p0, p1, p2 ) {p0.x = p1.x - p2.x; p0.y = p1.y - p2.y; p0.z = p1.z - p2.z;}
00425 #define POINT_ABS( p0, p1 ) {p0.x = abs(p1.x); p0.y = abs(p1.y); p0.z = abs(p1.z); }
00426 
00432 bool srs_env_model::CCMapPlugin::removeBoxCallback( srs_env_model::RemoveCube::Request & req, srs_env_model::RemoveCube::Response & res )
00433 {
00434         // Test frame id
00435         if (req.frame_id != m_cmapFrameId)
00436         {
00437                 // Transform size
00438                 geometry_msgs::PointStamped vs, vsout;
00439                 vs.header.frame_id = req.frame_id;
00440                 vs.header.stamp = m_mapTime;
00441                 POINT_ADD( vs.point, req.size, req.pose.position );
00442                 m_tfListener.transformPoint(m_cmapFrameId, vs, vsout);
00443 
00444                 // Transform pose
00445                 geometry_msgs::PoseStamped ps, psout;
00446                 ps.header.frame_id = req.frame_id;
00447                 ps.header.stamp = m_mapTime;
00448                 ps.pose = req.pose;
00449 
00450                 m_tfListener.transformPose(m_cmapFrameId, ps, psout);
00451                 req.pose = psout.pose;
00452 
00453                 // Finalize size transform
00454                 POINT_SUB(req.size, vsout.point, psout.pose.position);
00455                 POINT_ABS(req.size, req.size);
00456 
00457         }
00458 
00459         tBoxPoint center, size;
00460 
00461         // Convert point type
00462         center.x = req.pose.position.x; center.y = req.pose.position.y; center.z = req.pose.position.z;
00463         size.x = req.size.x; size.y = req.size.y; size.z = req.size.z;
00464 
00465         // Remove boxes
00466         long count =
00467         removeInsideBox( center, size, m_data->boxes );
00468 
00469         std::cerr << "Removed " << count << " boxes..." << std::endl;
00470 
00471         invalidate();
00472 
00473         return true;
00474 }
00475 
00481 void srs_env_model::CCMapPlugin::addBox( const tBoxPoint & center, const tBoxPoint & size, tBoxVec & boxes )
00482 {
00483         boost::mutex::scoped_lock lock( m_lockData );
00484         tBox box;
00485 
00486 //      PERROR( "Adding box: " << std::endl << center << std::endl << size << std::endl )
00487 
00488         box.extents.x = size.x / 2.0;
00489         box.extents.y = size.y / 2.0;
00490         box.extents.z = size.z / 2.0;
00491         box.axis.x = box.axis.y = 0.0;
00492         box.axis.z = 1.0;
00493         box.angle = 0.0;
00494         box.center.x = center.x;
00495         box.center.y = center.y;
00496         box.center.z = center.z;
00497 
00498         boxes.push_back(box);
00499 }
00500 
00506 bool srs_env_model::CCMapPlugin::addBoxCallback( srs_env_model::RemoveCube::Request & req, srs_env_model::RemoveCube::Response & res )
00507 {
00508         // Test frame id
00509         if (req.frame_id != m_cmapFrameId)
00510         {
00511                 // Transform size
00512                 geometry_msgs::PointStamped vs, vsout;
00513                 vs.header.frame_id = req.frame_id;
00514                 vs.header.stamp = m_mapTime;
00515                 POINT_ADD( vs.point, req.size, req.pose.position );
00516                 m_tfListener.transformPoint(m_cmapFrameId, vs, vsout);
00517 
00518                 // Transform pose
00519                 geometry_msgs::PoseStamped ps, psout;
00520                 ps.header.frame_id = req.frame_id;
00521                 ps.header.stamp = m_mapTime;
00522                 ps.pose = req.pose;
00523 
00524                 m_tfListener.transformPose(m_cmapFrameId, ps, psout);
00525                 req.pose = psout.pose;
00526 
00527                 // Finalize size transform
00528                 POINT_SUB(req.size, vsout.point, psout.pose.position);
00529                 POINT_ABS(req.size, req.size);
00530 
00531         }
00532 
00533 
00534         tBoxPoint center, size;
00535 
00536         // Convert point type
00537         center.x = req.pose.position.x; center.y = req.pose.position.y; center.z = req.pose.position.z;
00538         size.x = req.size.x; size.y = req.size.y; size.z = req.size.z;
00539 
00540         // Add box
00541 //      std::cerr << "Adding box. " << m_data->boxes.size() << " -> ";
00542         addBox( center, size, m_data->boxes );
00543 //      std::cerr << m_data->boxes.size() << std::endl;
00544 
00545         invalidate();
00546 
00547         return true;
00548 }
00549 
00554 void srs_env_model::CCMapPlugin::retransformTF( const ros::Time & currentTime )
00555 {
00556         // Listen and store current collision map transform matrix
00557         tf::StampedTransform lockedToCurrentTF;
00558 
00559         try
00560         {
00561                 m_tfListener.waitForTransform( m_cmapFrameId, currentTime, m_cmapFrameId, m_mapTime, FIXED_FRAME, ros::Duration(5) );
00562                 m_tfListener.lookupTransform( m_cmapFrameId, currentTime, m_cmapFrameId, m_mapTime, FIXED_FRAME, lockedToCurrentTF );
00563         }
00564         catch (tf::TransformException& ex) {
00565                         ROS_ERROR_STREAM("Transform error: " << ex.what() << ", quitting callback");
00566                         PERROR( "Transform error.");
00567                         return;
00568         }
00569 
00570         Eigen::Matrix4f m;
00571 
00572         // Get transform matrix
00573         pcl_ros::transformAsMatrix( lockedToCurrentTF, m );
00574 
00575         // Transform data front buffer
00576         tBoxVec::iterator it, itEnd( m_data->boxes.end() );
00577         for( it = m_data->boxes.begin(); it != itEnd; ++it )
00578         {
00579                 // Copy values to the eigen vectors
00580                 Eigen::Vector4f position( it->center.x, it->center.y, it->center.z, 1.0f );
00581                 Eigen::Vector4f extents( it->extents.x, it->extents.y, it->extents.z, 1.0f );
00582                 extents += position;
00583 
00584                 // Retransform
00585                 position = m * position;
00586                 extents = m * extents;
00587 
00588                 // Copy values back to the box
00589                 it->center.x = position[0];
00590                 it->center.y = position[1];
00591                 it->center.z = position[2];
00592 
00593                 // Recompute extents
00594                 extents = extents - position;
00595                 it->extents.x = abs(extents[0]);
00596                 it->extents.y = abs(extents[1]);
00597                 it->extents.z = abs(extents[2]);
00598         }
00599 
00600         // Transform back buffer
00601         itEnd = m_dataBuffer->boxes.end();
00602         for( it = m_dataBuffer->boxes.begin(); it != itEnd; ++it )
00603         {
00604                 // Copy values to the eigen vectors
00605                 Eigen::Vector4f position( it->center.x, it->center.y, it->center.z, 1.0f );
00606                 Eigen::Vector4f extents( it->extents.x, it->extents.y, it->extents.z, 1.0f );
00607                 extents += position;
00608 
00609                 // Retransform
00610                 position = m * position;
00611                 extents = m * extents;
00612 
00613                 // Copy values back to the box
00614                 it->center.x = position[0];
00615                 it->center.y = position[1];
00616                 it->center.z = position[2];
00617 
00618                 // Recompute extents
00619                 extents -= position;
00620                 it->extents.x = abs(extents[0]);
00621                 it->extents.y = abs(extents[1]);
00622                 it->extents.z = abs(extents[2]);
00623         }
00624 
00625         // Store timestamp
00626         m_mapTime = currentTime;
00627 }
00628 
00629 
00630 
00631 
00632 


srs_env_model
Author(s): Vit Stancl (stancl@fit.vutbr.cz), Tomas Lokaj, Jan Gorig, Michal Spanel (spanel@fit.vutbr.cz)
autogenerated on Sun Jan 5 2014 11:50:48