23 #include <pcl/keypoints/uniform_sampling.h>    27 #if PCL_VERSION_COMPARE(>=,1,7,0)    37 m_rngEngine(randomSeed),
    40 m_nh(),m_privateNh(
"~"),
    41 m_odomFrameId(
"odom"), m_targetFrameId(
"odom"), m_baseFrameId(
"torso"), m_baseFootprintId(
"base_footprint"), m_globalFrameId(
"map"),
    42 m_useRaycasting(true), m_initFromTruepose(false), m_numParticles(500),
    43 m_sensorSampleDist(0.2),
    44 m_nEffFactor(1.0), m_minParticleWeight(0.0),
    45 m_bestParticleIdx(-1), m_lastIMUMsgBuffer(5),
    46 m_bestParticleAsMean(true),
    47 m_receivedSensorData(false), m_initialized(false), m_initGlobal(false), m_paused(false),
    48 m_syncedTruepose(false),
    49 m_observationThresholdTrans(0.1), m_observationThresholdRot(
M_PI/6),
    50 m_observationThresholdHeadYawRot(0.5), m_observationThresholdHeadPitchRot(0.3),
    51 m_temporalSamplingRange(0.1), m_transformTolerance(0.1),
    52 m_groundFilterPointCloud(true), m_groundFilterDistance(0.04),
    53 m_groundFilterAngle(0.15), m_groundFilterPlaneDistance(0.07),
    54 m_sensorSampleDistGroundFactor(3),
    55 m_headYawRotationLastScan(0.0), m_headPitchRotationLastScan(0.0),
    57 m_constrainMotionZ (false), m_constrainMotionRP(false), m_useTimer(false), m_timerPeriod(0.1)
    92     ROS_WARN(
"Parameter \"num_sensor_beams\" is no longer used, use \"sensor_sampling_dist\" instead");
   129 #ifndef SKIP_ENDPOINT_MODEL   134     ROS_FATAL(
"EndpointModel not compiled due to missing dynamicEDT3D");
   215 #if defined(_BENCH_TIME)   222     geometry_msgs::PoseWithCovarianceStampedPtr posePtr(
new geometry_msgs::PoseWithCovarianceStamped());
   225       geometry_msgs::PoseStamped truePose;
   234       ident.
stamp_ = lookupTime;
   239       posePtr->header = truePose.header;
   243       for(
int j=0; j < 6; ++j){
   244         for (
int i = 0; i < 6; ++i){
   248             posePtr->pose.covariance.at(i*6 +j) = 0.0;
   253       posePtr.reset(
new geometry_msgs::PoseWithCovarianceStamped());
   254       for (
int i = 0; i < 6; ++i){
   258       double roll, pitch, 
z;
   263       posePtr->pose.pose.position.x = 
m_initPose(0);
   264       posePtr->pose.pose.position.y = 
m_initPose(1);
   265       posePtr->pose.pose.position.z = z;
   280 #if defined(_BENCH_TIME)   299       ROS_WARN(
"Could not determine current pose height, falling back to init_pose_z");
   307       ROS_WARN(
"Could not determine current roll and pitch, falling back to init_pose_{roll,pitch}");
   321   ROS_DEBUG(
"Laser received (time: %f)", msg->header.stamp.toSec());
   324     ROS_WARN(
"Localization not initialized yet, skipping laser callback.");
   330     ROS_WARN(
"Ignoring received laser data that is %f s older than previous data!", timediff);
   338   if (!
m_motionModel->lookupOdomPose(msg->header.stamp, odomPose))
   342   bool sensor_integrated = 
false;
   347      std::vector<float> laserRangesSparse;
   354   if(!sensor_integrated){ 
   378   double odomRoll, odomPitch, uselessYaw;
   381 #pragma omp parallel for   401   double yaw, pitch, roll;
   410 #if PCL_VERSION_COMPARE(>=,1,7,0)   427   if (!
m_motionModel->lookupLocalTransform(pc_filtered.header.frame_id, t, localSensorFrame))
   437     bool imuMsgOk = 
false;
   438     double angleX, angleY;
   441       imuMsgOk = 
getImuMsg(t, imuStamp, angleX, angleY);
   446         lastOdomPose.getBasis().getRPY(angleX, angleY, dropyaw);
   455         ROS_WARN(
"Could not obtain pose height in localization, skipping Pose integration");
   460       ROS_WARN(
"Could not obtain roll and pitch measurement, skipping Pose integration");
   474   double nEffParticles = 
nEff();
   476   std_msgs::Float32 nEffMsg;
   477   nEffMsg.data = nEffParticles;
   484     ROS_INFO(
"Skipped resampling, nEff=%f, numParticles=%zd", nEffParticles, 
m_particles.size());
   497   unsigned numBeams = laser->ranges.size();
   506   unsigned int numBeamsSkipped = 0;
   516 #if PCL_VERSION_COMPARE(>=,1,7,0)   519   pc.header = laser->header;
   521   pc.points.reserve(50);
   522   for (
unsigned beam_idx = 0; beam_idx < numBeams; beam_idx+= step){
   523     float range = laser->ranges[beam_idx];
   525       double laserAngle = laser->angle_min + beam_idx * laser->angle_increment;
   528       tf::Vector3 pt(laserAngleRotation * laserEndpointTrans);
   530       pc.points.push_back(pcl::PointXYZ(pt.
x(), pt.
y(), pt.
z()));
   531       ranges.push_back(range);
   539   pc.width = pc.points.size();
   543   pcl::UniformSampling<pcl::PointXYZ> uniformSampling;
   544   pcl::PointCloud<pcl::PointXYZ>::Ptr cloudPtr;
   545   cloudPtr.reset(
new pcl::PointCloud<pcl::PointXYZ> (pc));
   546   uniformSampling.setInputCloud(cloudPtr);
   548   pcl::PointCloud<int> sampledIndices;
   549   uniformSampling.compute(sampledIndices);
   550   pcl::copyPointCloud(*cloudPtr, sampledIndices.points, pc);
   552   std::vector<float> rangesSparse;
   553   rangesSparse.resize(sampledIndices.size());
   554   for (
size_t i = 0; i < rangesSparse.size(); ++i){
   555     rangesSparse[i] = ranges[sampledIndices.points[i]];
   557   ranges = rangesSparse;
   558   ROS_INFO(
"Laser PointCloud subsampled: %zu from %zu (%u out of valid range)", pc.size(), cloudPtr->size(), numBeamsSkipped);
   562   int numPoints = 
static_cast<int>(cloud_in.size() );
   563   numSamples = std::min( numSamples, numPoints);
   564   std::vector<unsigned int> indices;
   565   indices.reserve( numPoints );
   566   for (
int i=0; i<numPoints; ++i)
   567     indices.push_back(i);
   568   random_shuffle ( indices.begin(), indices.end());
   570   cloud_out.reserve( cloud_out.size() + numSamples );
   571   for ( 
int i = 0; i < numSamples; ++i)
   573     cloud_out.push_back( cloud_in.at(indices[i]));
   581    ground.header = pc.header;
   582    nonground.header = pc.header;
   585       ROS_WARN(
"Pointcloud in HumanoidLocalization::filterGroundPlane too small, skipping ground plane extraction");
   589       pcl::ModelCoefficients::Ptr coefficients (
new pcl::ModelCoefficients);
   590       pcl::PointIndices::Ptr inliers (
new pcl::PointIndices);
   593       pcl::SACSegmentation<pcl::PointXYZ> seg;
   594       seg.setOptimizeCoefficients (
true);
   596       seg.setModelType(pcl::SACMODEL_PERPENDICULAR_PLANE);
   597       seg.setMethodType(pcl::SAC_RANSAC);
   598       seg.setMaxIterations(200);
   599       seg.setDistanceThreshold (groundFilterDistance);
   600       seg.setAxis(Eigen::Vector3f(0,0,1));
   601       seg.setEpsAngle(groundFilterAngle);
   606       pcl::ExtractIndices<pcl::PointXYZ> extract;
   607       bool groundPlaneFound = 
false;
   609       while(cloud_filtered.size() > 10 && !groundPlaneFound){
   610          seg.setInputCloud(cloud_filtered.makeShared());
   611          seg.segment (*inliers, *coefficients);
   612          if (inliers->indices.size () == 0){
   613             ROS_INFO(
"PCL segmentation did not find any plane.");
   618          extract.setInputCloud(cloud_filtered.makeShared());
   619          extract.setIndices(inliers);
   621          if (std::abs(coefficients->values.at(3)) < groundFilterPlaneDistance){
   622             ROS_DEBUG(
"Ground plane found: %zu/%zu inliers. Coeff: %f %f %f %f", inliers->indices.size(), cloud_filtered.size(),
   623                   coefficients->values.at(0), coefficients->values.at(1), coefficients->values.at(2), coefficients->values.at(3));
   624             extract.setNegative (
false);
   625             extract.filter (ground);
   629             if(inliers->indices.size() != cloud_filtered.size()){
   630                extract.setNegative(
true);
   632                extract.filter(cloud_out);
   633                nonground += cloud_out;
   634                cloud_filtered = cloud_out;
   637             groundPlaneFound = 
true;
   639             ROS_DEBUG(
"Horizontal plane (not ground) found: %zu/%zu inliers. Coeff: %f %f %f %f", inliers->indices.size(), cloud_filtered.size(),
   640                   coefficients->values.at(0), coefficients->values.at(1), coefficients->values.at(2), coefficients->values.at(3));
   641             pcl::PointCloud<pcl::PointXYZ> cloud_out;
   642             extract.setNegative (
false);
   643             extract.filter(cloud_out);
   644             nonground +=cloud_out;
   651             if(inliers->indices.size() != cloud_filtered.size()){
   652                extract.setNegative(
true);
   653                cloud_out.points.clear();
   654                extract.filter(cloud_out);
   655                cloud_filtered = cloud_out;
   657                cloud_filtered.points.clear();
   663       if (!groundPlaneFound){ 
   664          ROS_WARN(
"No ground plane found in scan");
   667          pcl::PassThrough<pcl::PointXYZ> second_pass;
   668          second_pass.setFilterFieldName(
"z");
   669          second_pass.setFilterLimits(-groundFilterPlaneDistance, groundFilterPlaneDistance);
   670          second_pass.setInputCloud(pc.makeShared());
   671          second_pass.filter(ground);
   673          second_pass.setFilterLimitsNegative (
true);
   674          second_pass.filter(nonground);
   699       ROS_ERROR_STREAM( 
"Transform error for pointCloudCallback: " << ex.what() << 
", quitting callback.\n");
   706     pcl::PassThrough<pcl::PointXYZ> pass;
   707     pcl::PointCloud<pcl::PointXYZ>::Ptr pcd_tmp(
new pcl::PointCloud<pcl::PointXYZ>());
   708 #if PCL_VERSION_COMPARE(>=,1,7,0)   709     pcl::PCLPointCloud2 pcd2_tmp;
   711     pcl::fromPCLPointCloud2(pcd2_tmp, *pcd_tmp);
   715     pass.setInputCloud (pcd_tmp);
   716     pass.setFilterFieldName (
"z");
   724         Eigen::Matrix4f matSensorToBaseFootprint, matBaseFootprintToSensor;
   728         pcl::transformPointCloud(pc, pc, matSensorToBaseFootprint );
   733         pcl::PointCloud<int> sampledIndices;
   735         int numFloorPoints = 0;
   736         if (ground.size() > 0){ 
   738           pcl::transformPointCloud(ground, ground, matBaseFootprintToSensor);
   740           pcl::copyPointCloud(ground, sampledIndices.points, pc);
   741           numFloorPoints = sampledIndices.size();
   745         int numNonFloorPoints = 0;
   746         if (nonground.size() > 0){ 
   748           pcl::transformPointCloud(nonground, nonground, matBaseFootprintToSensor);
   750           pcl::copyPointCloud( nonground, sampledIndices.points, nonground);
   751           numNonFloorPoints = sampledIndices.size();
   758         ROS_INFO(
"PointCloudGroundFiltering done. Added %d non-ground points and %d ground points (from %zu). Cloud size is %zu", numNonFloorPoints, numFloorPoints, ground.size(), pc.size());
   760         ranges.resize(pc.size());
   761         for (
unsigned int i=0; i<pc.size(); ++i)
   763            pcl::PointXYZ p = pc.at(i);
   764            ranges[i] = sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
   770        ROS_INFO(
"Starting uniform sampling");
   773        pcl::PointCloud<int> sampledIndices;
   775        pcl::copyPointCloud(pc, sampledIndices.points, pc);
   778        ranges.resize(sampledIndices.size());
   779        for (
size_t i = 0; i < ranges.size(); ++i){
   780           pcl::PointXYZ p = pc[i]; 
   781           ranges[i] = sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
   795    pcl::UniformSampling<pcl::PointXYZ> uniformSampling;
   796    pcl::PointCloud<pcl::PointXYZ>::Ptr cloudPtr;
   797    cloudPtr.reset(
new pcl::PointCloud<pcl::PointXYZ> (pc)); 
   798    uniformSampling.setInputCloud(cloudPtr);
   799    uniformSampling.setRadiusSearch(search_radius);
   800    uniformSampling.compute(sampledIndices);
   804   ROS_DEBUG(
"PointCloud received (time: %f)", msg->header.stamp.toSec());
   807     ROS_WARN(
"Loclization not initialized yet, skipping PointCloud callback.");
   813     ROS_WARN(
"Ignoring received PointCloud data that is %f s older than previous data!", timediff);
   821   if (!
m_motionModel->lookupOdomPose(msg->header.stamp, odomPose))
   825   bool sensor_integrated = 
false;
   829   bool isAboveHeadMotionThreshold = 
false;
   830   double headYaw, headPitch, headRoll;
   832   if (!
m_motionModel->lookupLocalTransform(msg->header.frame_id, msg->header.stamp, torsoToSensor))
   842       isAboveHeadMotionThreshold = 
true;
   849     std::vector<float> rangesSparse;
   852     double maxRange = 10.0; 
   853     ROS_DEBUG(
"Updating Pose Estimate from a PointCloud with %zu points and %zu ranges", pc_filtered.size(), rangesSparse.size());
   857   if(!sensor_integrated){ 
   873   ROS_DEBUG(
"PointCloud callback complete.");
   884   typedef boost::circular_buffer<sensor_msgs::Imu>::const_iterator ItT;
   885   const double maxAge = 0.2;
   886   double closestOlderStamp = std::numeric_limits<double>::max();
   887   double closestNewerStamp = std::numeric_limits<double>::max();
   890     const double age = (stamp - it->header.stamp).toSec();
   891     if(age >= 0.0 && age < closestOlderStamp) {
   892       closestOlderStamp = age;
   894     } 
else if(age < 0.0 && -age < closestNewerStamp) {
   895       closestNewerStamp = -age;
   900   if(closestOlderStamp < maxAge && closestNewerStamp < maxAge && closestOlderStamp + closestNewerStamp > 0.0) {
   902     const double weightOlder = closestNewerStamp / (closestNewerStamp + closestOlderStamp);
   903     const double weightNewer = 1.0 - weightOlder;
   904     imuStamp = 
ros::Time(weightOlder * closestOlder->header.stamp.toSec()
   905                           + weightNewer * closestNewer->header.stamp.toSec());
   906     double olderX, olderY, newerX, newerY;
   907     getRP(closestOlder->orientation, olderX, olderY);
   908     getRP(closestNewer->orientation, newerX, newerY);
   909     angleX   = weightOlder * olderX  + weightNewer * newerX;
   910     angleY   = weightOlder * olderY + weightNewer * newerY;
   911     ROS_DEBUG(
"Msg: %.3f, Interpolate [%.3f .. %.3f .. %.3f]\n", stamp.
toSec(), closestOlder->header.stamp.toSec(),
   912               imuStamp.
toSec(), closestNewer->header.stamp.toSec());
   914   } 
else if(closestOlderStamp < maxAge || closestNewerStamp < maxAge) {
   916     ItT it = (closestOlderStamp < closestNewerStamp) ? closestOlder : closestNewer;
   917     imuStamp = it->header.stamp;
   918     getRP(it->orientation, angleX, angleY);
   921     if(closestOlderStamp < closestNewerStamp)
   922       ROS_WARN(
"Closest IMU message is %.2f seconds too old, skipping pose integration", closestOlderStamp);
   924       ROS_WARN(
"Closest IMU message is %.2f seconds too new, skipping pose integration", closestNewerStamp);
   934     ROS_WARN(
"Frame ID of \"initialpose\" (%s) is different from the global frame %s", msg->header.frame_id.c_str(), 
m_globalFrameId.c_str());
   937   std::vector<double> heights;
   938   double poseHeight = 0.0;
   941     if (heights.size() == 0){
   942       ROS_WARN(
"No ground level to stand on found at map position, assuming 0");
   943       heights.push_back(0.0);
   946     bool poseHeightOk = 
false;
   953         stamp = lastOdomPose.
stamp_;
   957         ROS_WARN(
"Could not determine current pose height, falling back to init_pose_z");
   961       ROS_INFO(
"Use pose height from init_pose_z");
   968   if ((std::abs(msg->pose.covariance.at(6*0+0) - 0.25) < 0.1) && (std::abs(msg->pose.covariance.at(6*1+1) -0.25) < 0.1)
   969       && (std::abs(msg->pose.covariance.at(6*3+3) - 
M_PI/12.0 * 
M_PI/12.0)<0.1)){
   970     ROS_INFO(
"Covariance originates from RViz, using default parameters instead");
   971     initCov = Matrix6d::Zero();
   978       bool useOdometry = 
true;
   981           ROS_WARN(
"Could not determine current roll and pitch because IMU message buffer is empty.");
   984           if(msg->header.stamp.isZero()) {
   990             ok = 
getImuMsg(msg->header.stamp, imuStamp, roll, pitch);
   993             ROS_INFO(
"roll and pitch not set in initPoseCallback, use IMU values (roll = %f, pitch = %f) instead", roll, pitch);
   997             ROS_WARN(
"Could not determine current roll and pitch from IMU, falling back to odometry roll and pitch");
  1004         double roll, pitch, dropyaw;
  1008           lastOdomPose.getBasis().getRPY(roll, pitch, dropyaw);
  1010           ROS_INFO(
"roll and pitch not set in initPoseCallback, use odometry values (roll = %f, pitch = %f) instead", roll, pitch);
  1012           ROS_WARN(
"Could not determine current roll and pitch from odometry, falling back to init_pose_{roll,pitch} parameters");
  1018       ROS_INFO(
"roll and pitch not set in initPoseCallback, use init_pose_{roll,pitch} parameters instead");
  1022     for(
int j=0; j < initCov.cols(); ++j){
  1023       for (
int i = 0; i < initCov.rows(); ++i){
  1024         initCov(i,j) = msg->pose.covariance.at(i*initCov.cols() +j);
  1030   Matrix6d initCovL = initCov.llt().matrixL();
  1035     for (
unsigned i = 0; i < 6; ++i){
  1038     Vector6d poseCovNoise = initCovL * poseNoise; 
  1040     for (
unsigned i = 0; i < 6; ++i){
  1041       if (std::abs(initCov(i,i)) < 0.00001)
  1042         poseCovNoise(i) = 0.0;
  1048     q.
setRPY(poseCovNoise(3), poseCovNoise(4),poseCovNoise(5));
  1053     if (heights.size() > 0){
  1058     it->pose *= transformNoise;
  1074   ros::Time stampPublish = msg->header.stamp;
  1075   if (stampPublish.
isZero()){
  1078     stampPublish = lastOdomPose.
stamp_;
  1079     if (stampPublish.
isZero())
  1100   double wmin = std::numeric_limits<double>::max();
  1101   double wmax = -std::numeric_limits<double>::max();
  1105     assert (!isnan(weight));
  1114     ROS_ERROR_STREAM(
"Error in weights: min=" << wmin <<
", max="<<wmax<<
", 1st particle weight="<< 
m_particles[1].weight<< std::endl);
  1118   double min_normalized_value;
  1122     min_normalized_value = wmin - wmax;
  1124   double max_normalized_value = 0.0; 
  1125   double dn = max_normalized_value-min_normalized_value;
  1126   double dw = wmax-wmin;
  1127   if (dw == 0.0) dw = 1;
  1128   double scale = dn/dw;
  1130     ROS_WARN(
"normalizeWeights: scale is %f < 0, dw=%f, dn=%f", scale, dw, dn );
  1132   double offset = -wmax*scale;
  1133   double weights_sum = 0.0;
  1135 #pragma omp parallel  1139     for (
unsigned i = 0; i < 
m_particles.size(); ++i){
  1141       w = exp(scale*w+offset);
  1148     assert(weights_sum > 0.0);
  1151     for (
unsigned i = 0; i < 
m_particles.size(); ++i){
  1159   double cumWeight=0.0;
  1163     cumWeight += it->weight;
  1171   if (numParticles <= 0)
  1182   std::vector<unsigned> indices(numParticles);
  1185   for (
unsigned i = 0; i < 
m_particles.size(); ++i){
  1187     while(cumWeight > target && n < numParticles){
  1201   double newWeight = 1.0/numParticles;
  1202 #pragma omp parallel for  1203   for (
unsigned i = 0; i < numParticles; ++i){
  1204     m_particles[i].pose = oldParticles[indices[i]].pose;
  1210   ROS_INFO(
"Initializing with uniform distribution");
  1212   double roll, pitch, 
z;
  1218   ROS_INFO(
"Global localization done");
  1238 #pragma omp parallel for  1239   for (
unsigned i = 0; i < 
m_particles.size(); ++i){
  1248   geometry_msgs::PoseWithCovarianceStamped p;
  1249   p.header.stamp = time;
  1265   geometry_msgs::PoseArray bestPose;
  1266   bestPose.header = p.header;
  1267   bestPose.poses.resize(1);
  1276     geometry_msgs::PoseStamped odomPoseMsg;
  1289     ROS_WARN(
"Failed to subtract base to %s transform, will not publish pose estimate: %s", 
m_targetFrameId.c_str(), e.what());
  1300   ros::Time transformExpiration = (time + transformTolerance);
  1310   if (m_bestParticleIdx < 0 || m_bestParticleIdx >= 
m_numParticles){
  1329   double totalWeight = 0.0;
  1333     meanPose.
getOrigin() += it->pose.getOrigin() * it->weight;
  1334     meanPose.
getBasis()[0] += it->pose.getBasis()[0];
  1335     meanPose.
getBasis()[1] += it->pose.getBasis()[1];
  1336     meanPose.
getBasis()[2] += it->pose.getBasis()[2];
  1337     totalWeight += it->weight;
  1339   assert(!isnan(totalWeight));
  1356   double sqrWeights=0.0;
  1358     sqrWeights+=(it->weight * it->weight);
  1361   if (sqrWeights > 0.0)
  1362     return 1./sqrWeights;
  1369 #pragma omp parallel for  1370   for (
unsigned i = 0; i < 
m_particles.size(); ++i){
  1382       ROS_WARN(
"Received a msg to pause localizatzion, but is already paused.");
  1391       ROS_WARN(
"Received a msg to resume localization, is not paused.");
  1404     ROS_WARN(
"Received a request to pause localizatzion, but is already paused.");
  1418     ROS_WARN(
"Received a request to resume localization, but is not paused.");
 tf::TransformBroadcaster m_tfBroadcaster
 
bool pauseLocalizationSrvCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
pause localization by service call 
 
double timediff(const timeval &start, const timeval &stop)
 
virtual void pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr &msg)
 
static tf::Quaternion createQuaternionFromRPY(double roll, double pitch, double yaw)
 
static void poseMsgToTF(const geometry_msgs::Pose &msg, Pose &bt)
 
ros::Publisher m_poseOdomPub
 
double m_observationThresholdRot
 
boost::uniform_real UniformDistributionT
 
void initPoseCallback(const geometry_msgs::PoseWithCovarianceStampedConstPtr &msg)
 
std::string m_baseFrameId
 
std::string m_targetFrameId
 
double m_sensorSampleDistGroundFactor
 
void publish(const boost::shared_ptr< M > &message) const 
 
bool resumeLocalizationSrvCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
unpause localization by service call 
 
double m_headPitchRotationLastScan
absolute, summed pitch angle since last measurement integraton 
 
double m_observationThresholdHeadPitchRot
 
bool isAboveMotionThreshold(const tf::Pose &odomTransform)
 
bool m_bestParticleAsMean
 
double m_headYawRotationLastScan
absolute, summed yaw angle since last measurement integraton 
 
tf::MessageFilter< sensor_msgs::PointCloud2 > * m_pointCloudFilter
 
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
 
int filterUniform(const PointCloud &cloud_in, PointCloud &cloud_out, int numSamples) const 
 
void prepareLaserPointCloud(const sensor_msgs::LaserScanConstPtr &laser, PointCloud &pc, std::vector< float > &ranges) const 
 
unsigned getBestParticleIdx() const 
Returns index of particle with highest weight (log or normal scale) 
 
bool m_useTimer
< True = do not estimate roll and pitch, directly use odometry pose 
 
double m_observationThresholdHeadYawRot
 
static void poseStampedTFToMsg(const Stamped< Pose > &bt, geometry_msgs::PoseStamped &msg)
 
static double getYaw(const Quaternion &bt_q)
 
ros::Publisher m_filteredPointCloudPub
 
bool lookupPoseHeight(const ros::Time &t, double &poseHeight) const 
 
ros::Publisher m_poseArrayPub
 
double m_minParticleWeight
 
double getCumParticleWeight() const 
cumulative weight of all particles (=1 when normalized) 
 
void transformAsMatrix(const tf::Transform &bt, Eigen::Matrix4f &out_mat)
 
void voxelGridSampling(const PointCloud &pc, pcl::PointCloud< int > &sampledIndices, double searchRadius) const 
 
TFSIMD_FORCE_INLINE void setZ(tfScalar z)
 
void publishPoseEstimate(const ros::Time &time, bool publish_eval)
 
tf::MessageFilter< sensor_msgs::LaserScan > * m_laserFilter
 
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
 
ros::Publisher m_poseEvalPub
 
TFSIMD_FORCE_INLINE const tfScalar & getY() const 
 
ros::Time m_lastLaserTime
 
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
 
message_filters::Subscriber< sensor_msgs::LaserScan > * m_laserSub
 
ros::Time m_lastPointCloudTime
 
TFSIMD_FORCE_INLINE const tfScalar & getZ() const 
 
static tf::Quaternion createIdentityQuaternion()
 
void prepareGeneralPointCloud(const sensor_msgs::PointCloud2::ConstPtr &msg, PointCloud &pc, std::vector< float > &ranges) const 
 
virtual ~HumanoidLocalization()
 
bool m_useIMU
True = use IMU for initialization and observation models, false = use orientation from odometry...
 
void timerCallback(const ros::TimerEvent &e)
 
tf::Pose getMeanParticlePose() const 
Returns the 6D pose of the weighted mean particle. 
 
boost::shared_ptr< MapModel > m_mapModel
 
boost::shared_ptr< ObservationModel > m_observationModel
 
TFSIMD_FORCE_INLINE const tfScalar & x() const 
 
tf::TransformListener m_tfListener
 
double m_temporalSamplingRange
 
void fromPCL(const pcl::uint64_t &pcl_stamp, ros::Time &stamp)
 
boost::normal_distribution NormalDistributionT
Boost RNG distribution: 
 
TFSIMD_FORCE_INLINE const tfScalar & z() const 
 
Eigen::Matrix< double, 6, 6 > Matrix6d
 
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)
 
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const 
 
tf::MessageFilter< geometry_msgs::PoseWithCovarianceStamped > * m_initPoseFilter
 
Matrix3x3 scaled(const Vector3 &s) const 
 
void constrainMotion(const tf::Pose &odomPose)
 
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const 
 
message_filters::Subscriber< sensor_msgs::PointCloud2 > * m_pointCloudSub
 
double m_groundFilterAngle
 
static void quaternionTFToMsg(const Quaternion &bt, geometry_msgs::Quaternion &msg)
 
tf::StampedTransform m_latest_transform
 
void initGlobal()
function call for global initialization (called by globalLocalizationCallback) 
 
ros::NodeHandle m_privateNh
 
message_filters::Subscriber< geometry_msgs::PoseWithCovarianceStamped > * m_initPoseSub
 
ros::ServiceServer m_pauseLocSrv
 
double m_sensorSampleDist
 
TFSIMD_FORCE_INLINE const tfScalar & y() const 
 
boost::circular_buffer< sensor_msgs::Imu > m_lastIMUMsgBuffer
 
Eigen::Matrix< double, 6, 1 > Vector6d
 
std::string m_globalFrameId
 
boost::shared_ptr< MotionModel > m_motionModel
 
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
 
ros::Subscriber m_pauseIntegrationSub
 
tf::Pose getParticlePose(unsigned particleIdx) const 
Returns the 6D pose of a particle. 
 
UniformGeneratorT m_rngUniform
uniform distribution [0:1] 
 
ros::ServiceServer m_globalLocSrv
 
bool globalLocalizationCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
 
TFSIMD_FORCE_INLINE const tfScalar & z() const 
 
HumanoidLocalization(unsigned randomSeed)
 
geometry_msgs::PoseArray m_poseArray
 
ros::Publisher m_bestPosePub
 
TFSIMD_FORCE_INLINE const tfScalar & w() const 
 
bool localizeWithMeasurement(const PointCloud &pc_filtered, const std::vector< float > &ranges, double max_range)
 
bool m_constrainMotionRP
< True = do not estimate height, directly use odometry pose 
 
tf::Pose getBestParticlePose() const 
Returns the 6D pose of the best particle (highest weight) 
 
static void poseTFToMsg(const Pose &bt, geometry_msgs::Pose &msg)
 
#define ROS_INFO_STREAM(args)
 
void subscribe(ros::NodeHandle &nh, const std::string &topic, uint32_t queue_size, const ros::TransportHints &transport_hints=ros::TransportHints(), ros::CallbackQueueInterface *callback_queue=0)
 
void resample(unsigned numParticles=0)
 
ros::ServiceServer m_resumeLocSrv
 
bool m_receivedSensorData
 
bool getImuMsg(const ros::Time &stamp, ros::Time &imuStamp, double &angleX, double &angleY) const 
 
bool m_groundFilterPointCloud
 
TFSIMD_FORCE_INLINE const tfScalar & getX() const 
 
virtual void laserCallback(const sensor_msgs::LaserScanConstPtr &msg)
 
double m_observationThresholdTrans
 
void initZRP(double &z, double &roll, double &pitch)
 
bool hasParam(const std::string &key) const 
 
std::string m_baseFootprintId
 
#define ROS_ERROR_STREAM(args)
 
double m_transformTolerance
 
double m_groundFilterDistance
 
static void filterGroundPlane(const PointCloud &pc, PointCloud &ground, PointCloud &nonground, double groundFilterDistance, double groundFilterAngle, double groundFilterPlaneDistance)
 
std::vector< Particle > Particles
 
pcl::PointCloud< pcl::PointXYZ > PointCloud
 
tf::Pose m_lastLocalizedPose
sensor data last integrated at this odom pose, to check if moved enough since then ...
 
void imuCallback(const sensor_msgs::ImuConstPtr &msg)
 
static void getRP(const geometry_msgs::Quaternion &msg_q, double &roll, double &pitch)
 
void pauseLocalizationCallback(const std_msgs::BoolConstPtr &msg)
 
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)
 
Quaternion normalized() const 
 
std::string m_odomFrameId
 
TFSIMD_FORCE_INLINE tfScalar length() const 
 
double m_groundFilterPlaneDistance
 
NormalGeneratorT m_rngNormal
standard normal distribution 
 
Connection registerCallback(const C &callback)