00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00058
00059
00060 node_handle.param("collision_map_radius", m_collisionMapLimitRadius, COLLISION_MAP_RADIUS_LIMIT );
00061
00062
00063 node_handle.param("collision_map_publisher", m_cmapPublisherName, COLLISION_MAP_PUBLISHER_NAME );
00064
00065
00066 node_handle.param("collision_map_frame_id", m_cmapFrameId, COLLISION_MAP_FRAME_ID );
00067
00068
00069 m_serviceGetCollisionMap = node_handle.advertiseService( GetCollisionMap_SRV, &CCMapPlugin::getCollisionMapSrvCallback, this);
00070
00071
00072 m_serviceIsNewCMap = node_handle.advertiseService( IsNewCMap_SRV, &CCMapPlugin::isNewCmapSrvCallback, this );
00073
00074
00075 m_serviceLockCMap = node_handle.advertiseService( LockCMap_SRV, &CCMapPlugin::lockCmapSrvCallback, this );
00076
00077
00078 m_serviceRemoveCube = node_handle.advertiseService( RemoveCubeCMP_SRV, &CCMapPlugin::removeBoxCallback, this );
00079
00080
00081 m_serviceAddCube = node_handle.advertiseService( AddCubeCMP_SRV, &CCMapPlugin::addBoxCallback, this );
00082
00083
00084 pause( false, node_handle );
00085 }
00086
00088 void srs_env_model::CCMapPlugin::publishInternal(const ros::Time & timestamp)
00089 {
00090
00091 boost::mutex::scoped_lock lock(m_lockData);
00092
00093
00094 bool publishCollisionMap = m_publishCollisionMap && (m_latchedTopics || m_cmapPublisher.getNumSubscribers() > 0);
00095
00096
00097 if( ! sameCMaps( m_data.get(), m_dataBuffer.get() ) )
00098 {
00099
00100 ++m_collisionMapVersion;
00101 m_mapTime = timestamp;
00102 swap( m_data, m_dataBuffer );
00103
00104 lock.unlock();
00105
00106
00107 invalidate();
00108 }
00109
00110 if( m_bLocked )
00111 {
00112 if( m_mapTime != timestamp )
00113 {
00114 retransformTF(timestamp);
00115 }
00116 }
00117
00118
00119 if (publishCollisionMap) {
00120
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
00135 boost::mutex::scoped_lock lock(m_lockData);
00136
00137
00138 m_dataBuffer->boxes.clear();
00139
00140 std::string robotBaseFrameId("/base_footprint");
00141
00142
00143 tf::StampedTransform omapToCmapTf,
00144 baseToOmapTf,
00145 cmapToWorldTF;
00146 try
00147 {
00148
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
00163 pcl_ros::transformAsMatrix(omapToCmapTf, m_worldToCMapTM );
00164
00165
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
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
00182 for ( it = tree.begin_leafs(m_crawlDepth); it != itEnd; ++it)
00183 {
00184
00185 if (tree.isNodeOccupied(*it))
00186 {
00187 handleOccupiedNode(it, par);
00188 }
00189
00190 }
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
00206 if (! m_publishCollisionMap)
00207 return;
00208
00209
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
00218 point = m_worldToCMapRot * point + m_worldToCMapTrans;
00219 }
00220
00221
00222
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
00248 if( m_bLocked )
00249 return true;
00250
00251
00252 if( map1 == 0 || map2 == 0 )
00253 {
00254
00255 return false;
00256 }
00257
00258
00259 if( map1->boxes.size() != map2->boxes.size() )
00260 {
00261
00262 return false;
00263 }
00264
00265
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
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
00314 res.current_version = m_collisionMapVersion;
00315
00316
00317 if( req.my_version != m_collisionMapVersion )
00318 {
00319 res.map = *m_data;
00320 }else{
00321
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
00365
00366
00367
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
00394 tBoxVec buffer( boxes.begin(), boxes.end() );
00395
00396
00397 boxes.clear();
00398
00399
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
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
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
00435 if (req.frame_id != m_cmapFrameId)
00436 {
00437
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
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
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
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
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
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
00509 if (req.frame_id != m_cmapFrameId)
00510 {
00511
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
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
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
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
00541
00542 addBox( center, size, m_data->boxes );
00543
00544
00545 invalidate();
00546
00547 return true;
00548 }
00549
00554 void srs_env_model::CCMapPlugin::retransformTF( const ros::Time & currentTime )
00555 {
00556
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
00573 pcl_ros::transformAsMatrix( lockedToCurrentTF, m );
00574
00575
00576 tBoxVec::iterator it, itEnd( m_data->boxes.end() );
00577 for( it = m_data->boxes.begin(); it != itEnd; ++it )
00578 {
00579
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
00585 position = m * position;
00586 extents = m * extents;
00587
00588
00589 it->center.x = position[0];
00590 it->center.y = position[1];
00591 it->center.z = position[2];
00592
00593
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
00601 itEnd = m_dataBuffer->boxes.end();
00602 for( it = m_dataBuffer->boxes.begin(); it != itEnd; ++it )
00603 {
00604
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
00610 position = m * position;
00611 extents = m * extents;
00612
00613
00614 it->center.x = position[0];
00615 it->center.y = position[1];
00616 it->center.z = position[2];
00617
00618
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
00626 m_mapTime = currentTime;
00627 }
00628
00629
00630
00631
00632