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)