00001 #include "kalman.hpp"
00002
00003 EKFnode::EKFnode(const ros::NodeHandle& nh, const double & spin_rate, const double & voxel_grid_size_) :
00004 nh_(nh),
00005 nh_priv("~"),
00006 listener(new tf::TransformListener(ros::Duration(10.0))),
00007 map_(new pcl::PointCloud<point_type>()),
00008 laser(new pcl::PointCloud<point_type>()),
00009 voxel_grid_size(voxel_grid_size_),
00010 odom_active_(false),
00011 laser_active_(false),
00012 odom_initialized_(false),
00013 laser_initialized_(false),
00014 first_map_received_(false)
00015 {
00016 nh_priv.param<std::string>("base_frame_id",base_link, "base_link");
00017 nh_priv.param<std::string>("odom_frame_id",odom_link, "odom");
00018 nh_priv.param<std::string>("map_frame_id",map_link, "map");
00019 nh_priv.param<std::string>("laser_frame_id",laser_link, "laser_frame");
00020
00021 double x_init, y_init, theta_init, initial_cov_xx, initial_cov_yy, initial_cov_aa;
00022 nh_priv.param("initial_pose_x",x_init, 0.0);
00023 nh_priv.param("initial_pose_y",y_init, 0.0);
00024 nh_priv.param("initial_pose_a",theta_init, 0.0);
00025 nh_priv.param("initial_cov_xx",initial_cov_xx, 0.25);
00026 nh_priv.param("initial_cov_yy",initial_cov_yy, 0.25);
00027 nh_priv.param("initial_cov_aa",initial_cov_aa, pow(M_PI/12.0,2));
00028
00029 nh_priv.param("update_min_d", d_thresh_, 0.2);
00030 nh_priv.param("update_min_a", a_thresh_, M_PI/6.0);
00031
00032 nh_priv.param("alpha_1",alpha_1, 0.05);
00033 nh_priv.param("alpha_2",alpha_2, 0.001);
00034 nh_priv.param("alpha_3",alpha_3, 5.0);
00035 nh_priv.param("alpha_4",alpha_4, 0.05);
00036
00037 nh_priv.param("max_correspondence_distance",max_correspondence_distance, 100.0);
00038 nh_priv.param("max_iterations",max_iterations, 1000);
00039 nh_priv.param("ransac_iterations",ransac_iterations, 1000);
00040 nh_priv.param("ransac_outlier_threshold",ransac_outlier_threshold, 0.1);
00041 nh_priv.param("icp_optimization_epsilon",icp_optimization_epsilon, 0.0000001);
00042 nh_priv.param("icp_score_scale",icp_score_scale, 100.0);
00043 nh_priv.param("laser_max_beams",laser_max_beams_, 30);
00044
00045 nh_priv.param("use_map_topic", use_map_topic_, true);
00046 nh_priv.param("first_map_only", first_map_only_, false);
00047
00048 nh_priv.param("covariance_marker_scale",covariance_marker_scale_, 3.0);
00049
00050 ROS_INFO_STREAM("base_frame_id:"<<base_link);
00051 ROS_INFO_STREAM("odom_frame_id:"<<odom_link);
00052 ROS_INFO_STREAM("map_frame_id:"<<map_link);
00053 ROS_INFO_STREAM("laser_frame_id:"<<laser_link);
00054
00055 ROS_INFO_STREAM("initial_pose_x:"<<x_init);
00056 ROS_INFO_STREAM("initial_pose_y:"<<y_init);
00057 ROS_INFO_STREAM("initial_pose_a:"<<theta_init);
00058
00059 ROS_INFO_STREAM("initial_cov_xx:"<<initial_cov_xx);
00060 ROS_INFO_STREAM("initial_cov_yy:"<<initial_cov_yy);
00061 ROS_INFO_STREAM("initial_cov_aa:"<<initial_cov_aa);
00062
00063 ROS_INFO_STREAM("update_min_d:"<<d_thresh_);
00064 ROS_INFO_STREAM("update_min_a:"<<a_thresh_);
00065
00066 ROS_INFO_STREAM("alpha_1:"<<alpha_1);
00067 ROS_INFO_STREAM("alpha_2:"<<alpha_2);
00068 ROS_INFO_STREAM("alpha_3:"<<alpha_3);
00069 ROS_INFO_STREAM("alpha_4:"<<alpha_4);
00070
00071 ROS_INFO_STREAM("max_correspondence_distance:"<<max_correspondence_distance);
00072 ROS_INFO_STREAM("max_iterations:"<<max_iterations);
00073 ROS_INFO_STREAM("ransac_iterations:"<<ransac_iterations);
00074 ROS_INFO_STREAM("ransac_outlier_threshold:"<<ransac_outlier_threshold);
00075 ROS_INFO_STREAM("icp_optimization_epsilon:"<<icp_optimization_epsilon);
00076 ROS_INFO_STREAM("icp_score_scale:"<<icp_score_scale);
00077 ROS_INFO_STREAM("laser_max_beams:"<<laser_max_beams_);
00078
00079 ROS_INFO_STREAM("covariance_marker_scale:"<<covariance_marker_scale_);
00080
00081
00082 alpha_2=alpha_2*180/M_PI;
00083 alpha_3=alpha_3*M_PI/180;
00084
00085
00086
00087
00088
00089
00090 BFL::ColumnVector sys_noise_mu(3);
00091 sys_noise_mu(1) = 0.0;
00092 sys_noise_mu(2) = 0.0;
00093 sys_noise_mu(3) = 0.0;
00094
00095 BFL::SymmetricMatrix sys_noise_cov(3);
00096 sys_noise_cov = 0.0;
00097 sys_noise_cov(1,1) = 1.0;
00098 sys_noise_cov(2,2) = 1.0;
00099 sys_noise_cov(3,3) = 1.0;
00100
00101 BFL::Gaussian system_uncertainty(sys_noise_mu, sys_noise_cov);
00102 sys_pdf = boost::shared_ptr<BFL::NonLinearAnalyticConditionalGaussianMobile> (new BFL::NonLinearAnalyticConditionalGaussianMobile(system_uncertainty));
00103 sys_model = boost::shared_ptr<BFL::AnalyticSystemModelGaussianUncertainty> (new BFL::AnalyticSystemModelGaussianUncertainty (sys_pdf.get()));
00104
00105
00106
00107
00108
00109
00110 BFL::Matrix H(3,3);
00111 H = 0.0;
00112 H(1,1) = 1.0;
00113 H(2,2) = 1.0;
00114 H(3,3) = 1.0;
00115
00116
00117 BFL::ColumnVector measNoise_Mu(3);
00118 measNoise_Mu = 0.0;
00119
00120 BFL::SymmetricMatrix measNoise_Cov(3);
00121 measNoise_Cov(1,1) = 1.0;
00122 measNoise_Cov(2,2) = 1.0;
00123 measNoise_Cov(3,3) = 1.0;
00124
00125 BFL::Gaussian measurement_uncertainty(measNoise_Mu, measNoise_Cov);
00126
00127
00128 meas_pdf=boost::shared_ptr<BFL::LinearAnalyticConditionalGaussian> (new BFL::LinearAnalyticConditionalGaussian(H, measurement_uncertainty));
00129 meas_model=boost::shared_ptr<BFL::LinearAnalyticMeasurementModelGaussianUncertainty> (new BFL::LinearAnalyticMeasurementModelGaussianUncertainty(meas_pdf.get()));
00130
00131
00132
00133
00134
00135
00136 BFL::ColumnVector prior_mu(3);
00137 prior_mu(1) = x_init;
00138 prior_mu(2) = y_init;
00139 prior_mu(2) = theta_init;
00140 BFL::SymmetricMatrix prior_cov(3);
00141 prior_cov=0.0;
00142 prior_cov(1,1) = initial_cov_xx;
00143 prior_cov(2,2) = initial_cov_yy;
00144 prior_cov(3,3) = initial_cov_aa;
00145 BFL::Gaussian prior(prior_mu,prior_cov);
00146
00147
00148
00149
00150
00151 filter=boost::shared_ptr<BFL::ExtendedKalmanFilter> (new BFL::ExtendedKalmanFilter(&prior));
00152
00153
00154 if(use_map_topic_)
00155 {
00156 map_sub_ = nh_.subscribe("map", 1, &EKFnode::mapReceived, this);
00157 ROS_INFO("Subscribed to map topic.");
00158 } else
00159 {
00160 requestMap();
00161 }
00162 timer_ = nh_.createTimer(ros::Duration(1.0/std::max(spin_rate,1.0)), &EKFnode::spin, this);
00163
00164 laser_sub = nh_.subscribe("scan", 1, &EKFnode::laser_callback, this);
00165 location_undertainty = nh_.advertise<visualization_msgs::Marker>("/location_undertainty",1);
00166 map_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("/map_",1);
00167 local_features_pub = nh_.advertise<sensor_msgs::PointCloud2>("/laser_aligned",1);
00168 }
00169
00170
00171 void EKFnode::laser_callback(const sensor_msgs::LaserScan::ConstPtr& msg)
00172 {
00173 if (!laser_active_)
00174 {
00175 if (!laser_initialized_)
00176 {
00177 laser_initialized_ = true;
00178 laser_last_stamp_ = msg->header.stamp;
00179 laser_init_stamp_ = msg->header.stamp;
00180 ROS_INFO("Initializing Laser sensor");
00181
00182 }
00183 if ( filter_stamp_ >= laser_init_stamp_)
00184 {
00185 laser_active_ = true;
00186 laser_initialized_ = false;
00187 ROS_INFO("Laser sensor activated");
00188 return;
00189 }
00190 else
00191 {
00192 ROS_ERROR("Waiting to activate Laser, because Laser measurements are still %f sec in the future.",
00193 (laser_init_stamp_ - filter_stamp_).toSec());
00194 return;
00195 }
00196 }
00197
00198 tf::StampedTransform laserToBaseTf;
00199 tf::StampedTransform baseDeltaTf;
00200
00201 try
00202 {
00203 listener->waitForTransform(map_link, laser_link, msg->header.stamp, ros::Duration(0.1) );
00204 listener->waitForTransform(map_link, laser_link, msg->header.stamp+ros::Duration().fromSec((msg->ranges.size()-1)*msg->time_increment), ros::Duration(0.1) );
00205 listener->lookupTransform(map_link, laser_link, msg->header.stamp, laserToBaseTf);
00206 listener->lookupTransform(map_link, laser_link, msg->header.stamp+ros::Duration().fromSec((msg->ranges.size()-1)*msg->time_increment), laserToBaseTf);
00207
00208 listener->waitForTransform(base_link, laser_last_stamp_, base_link, msg->header.stamp , odom_link, ros::Duration(0.1) );
00209 listener->lookupTransform(base_link, laser_last_stamp_, base_link, msg->header.stamp, odom_link, baseDeltaTf);
00210 }
00211 catch(tf::TransformException& ex)
00212 {
00213 laser_last_stamp_=msg->header.stamp;
00214 ROS_WARN("%s",ex.what());
00215 return;
00216 }
00217
00218
00219
00220 double dx=baseDeltaTf.getOrigin().getX();
00221 double dy=baseDeltaTf.getOrigin().getY();
00222 double d_theta=baseDeltaTf.getRotation().getAxis()[2]*baseDeltaTf.getRotation().getAngle();
00223
00224
00225 if(!(fabs(dx) > d_thresh_ || fabs(dy) > d_thresh_ || fabs(d_theta) > a_thresh_))
00226 {
00227 return;
00228 }
00229
00230
00231 sensor_msgs::PointCloud2 cloud_msg;
00232 projector_.transformLaserScanToPointCloud(map_link,*msg,
00233 cloud_msg,*listener);
00234
00235
00236 pcl::PCLPointCloud2 pcl_pc;
00237
00238 pcl_conversions::toPCL(cloud_msg,pcl_pc);
00239 pcl::fromPCLPointCloud2(pcl_pc, *laser);
00240
00241
00242 pcl::PointIndices::Ptr inliers (new pcl::PointIndices ());
00243 pcl::removeNaNFromPointCloud((*laser), *laser,inliers->indices);
00244 pcl::PointIndices::Ptr toProcessIndices (new pcl::PointIndices ());
00245
00246 int step = (laser->size() - 1) / (laser_max_beams_ - 1);
00247 for (int i = 0; i < laser->size(); i += step)
00248 {
00249 toProcessIndices->indices.push_back(i);
00250 }
00251
00252 pcl_conversions::toPCL(msg->header.stamp, map_->header.stamp);
00253
00254
00255 pcl::IterativeClosestPoint<point_type, point_type> icp;
00256 icp.setInputSource(laser);
00257 icp.setIndices(toProcessIndices);
00258 icp.setInputTarget(map_);
00259 icp.setTransformationEpsilon (icp_optimization_epsilon);
00260 icp.setMaxCorrespondenceDistance(max_correspondence_distance);
00261
00262 icp.setMaximumIterations(max_iterations);
00263 icp.setRANSACIterations (ransac_iterations);
00264 icp.setRANSACOutlierRejectionThreshold(ransac_outlier_threshold);
00265 pcl::PointCloud<point_type> Final;
00266 icp.align(Final);
00267
00268 Final.header.frame_id=map_link;
00269 pcl_conversions::toPCL(filter_stamp_, Final.header.stamp);
00270
00271 if(icp.hasConverged())
00272 {
00273
00274 Eigen::Matrix4f correction_transform_=icp.getFinalTransformation();
00275
00276 BFL::ColumnVector observation_mean(3);
00277 BFL::Pdf<BFL::ColumnVector> * posterior = filter->PostGet();
00278 double angle=correction_transform_.block<3,3>(0,0).eulerAngles (0,1,2)(2)+posterior->ExpectedValueGet()(3);
00279 angleOverflowCorrect(angle);
00280 observation_mean(1)=correction_transform_(0,3)+posterior->ExpectedValueGet()(1);
00281 observation_mean(2)=correction_transform_(1,3)+posterior->ExpectedValueGet()(2);
00282 observation_mean(3)=angle;
00283 BFL::SymmetricMatrix observation_noise(3);
00284 double icp_fitness_score=icp.getFitnessScore(max_correspondence_distance);
00285 observation_noise=0.0;
00286 observation_noise(1,1) = icp_score_scale*icp_fitness_score;
00287 observation_noise(2,2) = icp_score_scale*icp_fitness_score;
00288 observation_noise(3,3) = icp_score_scale*icp_fitness_score;
00289
00290 meas_pdf->AdditiveNoiseSigmaSet(observation_noise);
00291 filter->Update(meas_model.get(),observation_mean);
00292
00293 if(filter->PostGet()->ExpectedValueGet()(3)>M_PI || filter->PostGet()->ExpectedValueGet()(3)<-M_PI)
00294 {
00295 std::cout << filter->PostGet()->ExpectedValueGet()(3) << std::endl;
00296 exit(-1);
00297 }
00298 broadcast(msg->header.stamp);
00299
00300 laser_last_stamp_=msg->header.stamp;
00301 local_features_pub.publish(Final);
00302 }
00303 else
00304 {
00305 ROS_ERROR("ICP DID NOT CONVERGE");
00306 }
00307
00308 return;
00309 }
00310
00311
00312 bool EKFnode::predict()
00313 {
00314 ros::Time odom_time=ros::Time::now();
00315
00316
00317 if (!odom_active_)
00318 {
00319 if (!odom_initialized_)
00320 {
00321 odom_initialized_ = true;
00322 odom_last_stamp_ = odom_time;
00323 odom_init_stamp_ = odom_time;
00324 ROS_INFO("Initializing Odom sensor");
00325
00326 }
00327 if ( filter_stamp_ >= odom_init_stamp_)
00328 {
00329 odom_active_ = true;
00330 odom_initialized_ = false;
00331 ROS_INFO("Odom sensor activated");
00332 return true;
00333 }
00334 else
00335 {
00336 ROS_ERROR("Waiting to activate Odom, because odom measurements are still %f sec in the future.",
00337 (odom_init_stamp_ - filter_stamp_).toSec());
00338 return false;
00339 }
00340 }
00341
00342 tf::StampedTransform baseDeltaTf;
00343
00344
00345 try
00346 {
00347 listener->waitForTransform(base_link, odom_last_stamp_, base_link, odom_time , odom_link, ros::Duration(0.5) );
00348 listener->lookupTransform(base_link, odom_last_stamp_, base_link, odom_time, odom_link, baseDeltaTf);
00349
00350 }
00351 catch (tf::TransformException &ex)
00352 {
00353
00354
00355 ROS_WARN("%s",ex.what());
00356 return false;
00357 }
00358
00359
00360 double dx=baseDeltaTf.getOrigin().getX();
00361 double dy=baseDeltaTf.getOrigin().getY();
00362 double d_theta=baseDeltaTf.getRotation().getAxis()[2]*baseDeltaTf.getRotation().getAngle();
00363
00364 double delta_rot1=atan2(dy,dx);
00365 double delta_trans=sqrt(dx*dx+dy*dy);
00366 double delta_rot2=d_theta-delta_rot1;
00367
00368 double var_rot1=alpha_1*delta_rot1*delta_rot1+alpha_2*delta_trans*delta_trans;
00369 double var_trans=alpha_3*delta_trans*delta_trans+alpha_4*(delta_rot1*delta_rot1+delta_rot2*delta_rot2);
00370 double var_rot2=alpha_1*delta_rot2*delta_rot2+alpha_2*delta_trans*delta_trans;
00371
00372 BFL::ColumnVector control_mean(3);
00373 control_mean(1)=delta_rot1;
00374 control_mean(2)=delta_trans;
00375 control_mean(3)=delta_rot2;
00376
00377 BFL::Matrix control_noise(3,3);
00378 control_noise=0.0;
00379 control_noise(1,1) = var_rot1;
00380 control_noise(2,2) = var_trans;
00381 control_noise(3,3) = var_rot2;
00382
00383
00384 BFL::Matrix J(3,3);
00385 J(1,1)=-sin(filter->PostGet()->ExpectedValueGet()(3)+delta_rot1)*delta_trans;
00386 J(1,2)=cos(filter->PostGet()->ExpectedValueGet()(3)+delta_rot1);
00387 J(2,2)=0;
00388
00389 J(2,1)=cos(filter->PostGet()->ExpectedValueGet()(3)+delta_rot1)*delta_trans;
00390 J(2,2)=sin(filter->PostGet()->ExpectedValueGet()(3)+delta_rot1);
00391 J(2,3)=0;
00392
00393 J(3,1)=1;
00394 J(3,2)=0;
00395 J(3,3)=1;
00396
00397 BFL::SymmetricMatrix R(J*control_noise*J.transpose());
00398
00399 sys_pdf->AdditiveNoiseSigmaSet(R);
00400 filter->Update(sys_model.get(),control_mean);
00401 if(filter->PostGet()->ExpectedValueGet()(3)>M_PI || filter->PostGet()->ExpectedValueGet()(3)<-M_PI)
00402 {
00403 std::cout << filter->PostGet()->ExpectedValueGet()(3) << std::endl;
00404 exit(-1);
00405 }
00406 broadcast(odom_time);
00407
00408
00409
00410
00411
00412 odom_last_stamp_=odom_time;
00413 return true;
00414 }
00415
00416
00417
00418
00419 void EKFnode::broadcast(const ros::Time & broad_cast_time)
00420 {
00421 BFL::Pdf<BFL::ColumnVector> * posterior = filter->PostGet();
00422
00423 BFL::ColumnVector estimated_mean=posterior->ExpectedValueGet();
00424
00425 BFL::SymmetricMatrix estimated_cov=posterior->CovarianceGet();
00426
00427 tf::Stamped<tf::Pose> odom_to_map;
00428 try
00429 {
00430 tf::Transform tmp_tf(tf::createQuaternionFromYaw(estimated_mean(3)),
00431 tf::Vector3(estimated_mean(1),
00432 estimated_mean(2),
00433 0.0));
00434 tf::Stamped<tf::Pose> tmp_tf_stamped (tmp_tf.inverse(),
00435 broad_cast_time,
00436 base_link);
00437 listener->transformPose(odom_link,
00438 tmp_tf_stamped,
00439 odom_to_map);
00440 }
00441 catch(tf::TransformException)
00442 {
00443 ROS_DEBUG("Failed to subtract base to odom transform");
00444 return;
00445 }
00446
00447 tf::Transform latest_tf_ = tf::Transform(tf::Quaternion(odom_to_map.getRotation()),
00448 tf::Point(odom_to_map.getOrigin()));
00449
00450
00451
00452 tf::StampedTransform tmp_tf_stamped(latest_tf_.inverse(),
00453 broad_cast_time+ros::Duration(0.1),
00454 map_link, odom_link);
00455 tf_broadcaster.sendTransform(tmp_tf_stamped);
00456
00457 filter_stamp_=broad_cast_time;
00458 }
00459
00460 void EKFnode::drawCovariance(const Eigen::Matrix2f& covMatrix)
00461 {
00462 visualization_msgs::Marker tempMarker;
00463 tempMarker.pose.position.x = 0;
00464 tempMarker.pose.position.y = 0;
00465
00466 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2f> eig(covMatrix);
00467
00468 const Eigen::Vector2f& eigValues (eig.eigenvalues());
00469 const Eigen::Matrix2f& eigVectors (eig.eigenvectors());
00470
00471 float angle = (atan2(eigVectors(1, 0), eigVectors(0, 0)));
00472
00473
00474 tempMarker.type = visualization_msgs::Marker::SPHERE;
00475
00476 double lengthMajor = sqrt(eigValues[0]);
00477 double lengthMinor = sqrt(eigValues[1]);
00478
00479 tempMarker.scale.x = covariance_marker_scale_*lengthMajor;
00480 tempMarker.scale.y = covariance_marker_scale_*lengthMinor;
00481 tempMarker.scale.z = 0.001;
00482
00483 tempMarker.color.a = 1.0;
00484 tempMarker.color.r = 1.0;
00485
00486 tempMarker.pose.orientation.w = cos(angle*0.5);
00487 tempMarker.pose.orientation.z = sin(angle*0.5);
00488
00489 tempMarker.header.frame_id=base_link;
00490 tempMarker.id = 0;
00491
00492 location_undertainty.publish(tempMarker);
00493 }
00494
00495
00496 void EKFnode::mapReceived(const nav_msgs::OccupancyGridConstPtr& msg)
00497 {
00498 if( first_map_only_ && first_map_received_ )
00499 {
00500 return;
00501 }
00502
00503 handleMapMessage( *msg );
00504
00505 first_map_received_ = true;
00506 }
00507
00508 void EKFnode::handleMapMessage(const nav_msgs::OccupancyGrid& msg)
00509 {
00510 ROS_INFO("Received a %d X %d map @ %.3f m/pix\n",
00511 msg.info.width,
00512 msg.info.height,
00513 msg.info.resolution);
00514 convertMap(msg);
00515 }
00516
00517 void EKFnode::requestMap()
00518 {
00519
00520
00521
00522 nav_msgs::GetMap::Request req;
00523 nav_msgs::GetMap::Response resp;
00524 ROS_INFO("Requesting the map...");
00525 while(!ros::service::call("static_map", req, resp)&&nh_priv.ok())
00526 {
00527 ROS_WARN("Request for map failed; trying again...");
00528 ros::Duration d(0.5);
00529 d.sleep();
00530 }
00531 handleMapMessage( resp.map );
00532 }
00533
00534 void EKFnode::convertMap( const nav_msgs::OccupancyGrid& map_msg)
00535 {
00536 map_=map_t_ptr (new map_t());
00537 ROS_ASSERT(map_);
00538 map_->is_dense=false;
00539 map_->header.frame_id=map_msg.header.frame_id;
00540 double map_size_x = map_msg.info.width;
00541 double map_size_y = map_msg.info.height;
00542 double map_scale = map_msg.info.resolution;
00543
00544
00545
00546
00547 for(int i=0;i<map_size_x; ++i)
00548 {
00549 for(int j=0;j<map_size_y; ++j)
00550 {
00551 if(map_msg.data[i+j*map_size_x] > 0.0)
00552 {
00553 point_type point;
00554 point.x=map_scale*i+map_msg.info.origin.position.x;
00555 point.y=map_scale*j+map_msg.info.origin.position.y;
00556 point.z=0.0;
00557
00558 map_->push_back(point);
00559 }
00560 }
00561 }
00562
00563 pcl::VoxelGrid<point_type> voxel_grid;
00564 voxel_grid.setLeafSize (voxel_grid_size, voxel_grid_size, voxel_grid_size);
00565 voxel_grid.setInputCloud (map_);
00566 voxel_grid.filter (*map_);
00567
00568 }
00569
00570
00571
00572 void EKFnode::spin(const ros::TimerEvent& e)
00573 {
00574
00575
00576 filter_stamp_ = ros::Time::now();
00577
00578 predict();
00579
00580
00581 ros::spinOnce();
00582
00583
00584 if (odom_active_ || laser_active_)
00585 {
00586 if (odom_active_) filter_stamp_ = std::min(filter_stamp_, odom_last_stamp_);
00587 if (laser_active_) filter_stamp_ = std::min(filter_stamp_, laser_last_stamp_);
00588
00589
00590 Eigen::Matrix2f covMatrix;
00591 BFL::Pdf<BFL::ColumnVector> * posterior = filter->PostGet();
00592 BFL::SymmetricMatrix estimated_cov=posterior->CovarianceGet();
00593
00594 covMatrix(0,0)=estimated_cov(1,1);
00595 covMatrix(0,1)=estimated_cov(1,2);
00596
00597 covMatrix(1,0)=estimated_cov(2,1);
00598 covMatrix(1,1)=estimated_cov(2,2);
00599 drawCovariance(covMatrix);
00600
00601 publishFeatures();
00602 }
00603 }