00001 #include <fstream>
00002
00003 #include <boost/version.hpp>
00004 #include <deque>
00005
00006
00007 #include "ros/ros.h"
00008 #include "ros/console.h"
00009 #include "pointmatcher/PointMatcher.h"
00010 #include "pointmatcher/Timer.h"
00011
00012 #include "nabo/nabo.h"
00013
00014 #include "pointmatcher_ros/point_cloud.h"
00015 #include "pointmatcher_ros/transform.h"
00016 #include "pointmatcher_ros/get_params_from_server.h"
00017 #include "pointmatcher_ros/ros_logger.h"
00018
00019 #include "nav_msgs/Odometry.h"
00020 #include "tf/transform_broadcaster.h"
00021 #include "tf_conversions/tf_eigen.h"
00022 #include "tf/transform_listener.h"
00023
00024 #include <message_filters/subscriber.h>
00025 #include <message_filters/synchronizer.h>
00026 #include <message_filters/sync_policies/exact_time.h>
00027
00028 #include <visualization_msgs/Marker.h>
00029
00030 #include "std_msgs/String.h"
00031 #include "std_srvs/Empty.h"
00032
00033 using namespace std;
00034 using namespace PointMatcherSupport;
00035 using namespace visualization_msgs;
00036
00037 typedef PointMatcher<float> PM;
00038 typedef PM::DataPoints DP;
00039
00040 class DynamicTrails
00041 {
00042 typedef PM::TransformationParameters TP;
00043 typedef PM::Matches Matches;
00044
00045 typedef typename Nabo::NearestNeighbourSearch<float> NNS;
00046 typedef typename NNS::SearchType NNSearchType;
00047
00048 ros::NodeHandle& n;
00049 ros::NodeHandle& pn;
00050
00051
00052
00053
00054
00055
00056
00057 ros::Subscriber scanSub;
00058 ros::Subscriber cloudSub;
00059 ros::Subscriber mapSub;
00060 ros::Publisher lastPub;
00061 ros::Publisher dynPub;
00062 ros::Publisher lastProjectedPub;
00063 ros::Publisher dynProjectedPub;
00064 ros::Publisher markerPub;
00065
00066 PM::DataPointsFilters inputFilters;
00067 unique_ptr<PM::Transformation> transformation;
00068 shared_ptr<DP> lastPointCloud;
00069 shared_ptr<DP> trailPointCloud;
00070 PM::DataPoints globalMap;
00071
00072 std::shared_ptr<NNS> globalNNS;
00073 std::shared_ptr<NNS> lastNNS;
00074
00075 boost::mutex usingGlobalMap;
00076
00077 std::deque<shared_ptr<DP>> priors;
00078
00079
00080 tf::TransformListener tfListener;
00081
00082 boost::mutex publishLock;
00083
00084 const float eps;
00085 ros::Time lastInputTime;
00086
00087
00088 const string p_mapFrame;
00089 const float p_minDynamicRatio;
00090 const float p_normalSpaceFactor;
00091 const float p_maxVelocity;
00092 const float p_inputRate;
00093 const int p_windowSize;
00094 const string p_trailFilepName;
00095 const bool p_accumulateMarkers;
00096 const float p_maxGlobalMapDist;
00097 const float p_maxClusterDistance;
00098
00099 int trailCount;
00100
00101 public:
00102 DynamicTrails(ros::NodeHandle& n, ros::NodeHandle& pn);
00103 ~DynamicTrails();
00104
00105 protected:
00106
00107 void gotCloud(const sensor_msgs::PointCloud2ConstPtr& cloudMsgIn);
00108 void gotMap(const sensor_msgs::PointCloud2& cloudMsgIn);
00109 void processCloud(DP cloud, const TP TScannerToMap);
00110 PM::DataPoints extractDynamicPoints(const PM::DataPoints input, const float minDynamicRatio);
00111 void computeVelocity(shared_ptr<DP> reference, shared_ptr<NNS> ref_tree, shared_ptr<DP> reading, shared_ptr<NNS> read_tree, const float maxRadius, const int knn, ros::Publisher debugPub);
00112 float angleWeight(const Eigen::Vector3f &normal, const Eigen::Vector3f &velocity);
00113
00114 void averageWithReference(shared_ptr<DP> reference, shared_ptr<DP> reading, const float dir);
00115
00116 };
00117
00118 DynamicTrails::DynamicTrails(ros::NodeHandle& n, ros::NodeHandle& pn):
00119 n(n),
00120 pn(pn),
00121
00122
00123
00124 transformation(PM::get().REG(Transformation).create("RigidTransformation")),
00125 lastPointCloud(0),
00126 trailPointCloud(0),
00127 tfListener(ros::Duration(30)),
00128 eps(0.0001),
00129 p_mapFrame(getParam<string>("map_frame", "map")),
00130 p_minDynamicRatio(getParam<double>("min_dynamic_ratio", 0.75)),
00131 p_normalSpaceFactor(getParam<double>("normal_space_factor", 1.0)),
00132 p_maxVelocity(getParam<double>("max_velocity", 12.0)),
00133 p_inputRate(getParam<double>("input_rate", 1.5)),
00134 p_windowSize(getParam<int>("window_size", 3)),
00135 p_trailFilepName(getParam<string>("trail_filename", "trailMap.vtk")),
00136 p_accumulateMarkers(getParam<bool>("accumulate_markers", false)),
00137 p_maxGlobalMapDist(getParam<double>("max_global_map_dist", 0.5)),
00138 p_maxClusterDistance(getParam<double>("max_cluster_distance", 0.75)),
00139 trailCount(0)
00140 {
00141
00142
00143 priors.resize(p_windowSize+1);
00144
00145
00146
00147 string configFileName;
00148
00149 if (ros::param::get("~inputFiltersConfig", configFileName))
00150 {
00151 ifstream ifs(configFileName.c_str());
00152 if (ifs.good())
00153 {
00154 inputFilters = PM::DataPointsFilters(ifs);
00155 }
00156 else
00157 {
00158 ROS_ERROR_STREAM("Cannot load input filters config from YAML file " << configFileName);
00159 }
00160 }
00161 else
00162 {
00163 ROS_INFO_STREAM("No input filters config file given, not using these filters");
00164 }
00165
00166
00167
00168
00169
00170 cloudSub = n.subscribe("cloud_in", 10, &DynamicTrails::gotCloud, this);
00171 mapSub = n.subscribe("point_map", 1, &DynamicTrails::gotMap, this);
00172 lastPub = n.advertise<sensor_msgs::PointCloud2>("last_dynamic_points", 2, true);
00173 dynPub = n.advertise<sensor_msgs::PointCloud2>("current_dynamic_points", 2, true);
00174 lastProjectedPub= n.advertise<sensor_msgs::PointCloud2>("last_projected_points", 2, true);
00175 dynProjectedPub= n.advertise<sensor_msgs::PointCloud2>("dyn_projected_points", 2, true);
00176 markerPub = n.advertise<visualization_msgs::Marker>("dynamic_trail", 1);
00177
00178 }
00179
00180 DynamicTrails::~DynamicTrails()
00181 {
00182
00183
00184 if (trailPointCloud)
00185 {
00186 trailPointCloud->save(p_trailFilepName);
00187 }
00188
00189 }
00190
00191
00192 void DynamicTrails::gotMap(const sensor_msgs::PointCloud2& cloudMsgIn)
00193 {
00194 cout << "Map received" << endl;
00195 usingGlobalMap.lock();
00196
00197 globalMap = PointMatcher_ros::rosMsgToPointMatcherCloud<float>(cloudMsgIn);
00198
00199
00200 globalNNS.reset( NNS::create(globalMap.features, globalMap.features.rows() - 1, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00201 usingGlobalMap.unlock();
00202 }
00203
00204
00205
00206 void DynamicTrails::gotCloud(const sensor_msgs::PointCloud2ConstPtr& cloudMsgIn)
00207 {
00208
00209
00210 const ros::Time currentTime = ros::Time::now();
00211 const float currentRate = 1.0/(currentTime - lastInputTime).toSec();
00212
00213 if(currentRate < p_inputRate || p_inputRate == -1)
00214 {
00215 lastInputTime = currentTime;
00216
00217
00218 DP cloud(PointMatcher_ros::rosMsgToPointMatcherCloud<float>(*cloudMsgIn));
00219
00220
00221
00222 TP TScannerToMap;
00223
00224 try
00225 {
00226 tfListener.waitForTransform(p_mapFrame, cloudMsgIn->header.frame_id, cloudMsgIn->header.stamp, ros::Duration(0.5));
00227 TScannerToMap = PointMatcher_ros::transformListenerToEigenMatrix<float>(
00228 tfListener,
00229 p_mapFrame,
00230 cloudMsgIn->header.frame_id,
00231 cloudMsgIn->header.stamp
00232 );
00233 processCloud(cloud, TScannerToMap);
00234 }
00235 catch(tf::ExtrapolationException e)
00236 {
00237 ROS_ERROR_STREAM("Extrapolation Exception. stamp = "<< cloudMsgIn->header.stamp << " now = " << ros::Time::now() << " delta = " << ros::Time::now() - cloudMsgIn->header.stamp);
00238 return;
00239 }
00240
00241 }
00242 else
00243 {
00244 ROS_WARN_STREAM("Skipping point cloud");
00245 }
00246
00247 }
00248
00249
00250 void DynamicTrails::processCloud(DP inputPointCloud, const TP TScannerToMap)
00251 {
00252
00253 ROS_INFO("Processing new point cloud");
00254
00255 timer t;
00256
00257
00258
00259 ROS_INFO_STREAM("Input filters took " << t.elapsed() << " [s]");
00260
00261
00262 inputPointCloud = transformation->compute(inputPointCloud, TScannerToMap);
00263
00264 cerr << "inputPointCloud.features.cols() " << inputPointCloud.features.cols() << endl;
00265
00266 shared_ptr<DP> dynamicPointCloud( new DP(extractDynamicPoints(inputPointCloud, p_minDynamicRatio)));
00267
00268
00269
00270
00271 inputFilters.apply(*dynamicPointCloud);
00272
00273 const int dynamicPtsCount = dynamicPointCloud->features.cols();
00274
00275 cerr << "dynamicPointCloud->features.cols() " << dynamicPtsCount << endl;
00276
00277
00278 if(dynamicPtsCount == 0)
00279 {
00280 ROS_WARN_STREAM("No dynamic points could be found");
00281 return;
00282 }
00283
00284
00285
00286
00287
00288
00289 dynamicPointCloud->addDescriptor("velocity_dir", PM::Matrix::Zero(3,dynamicPtsCount));
00290 dynamicPointCloud->addDescriptor("velocity_mag", PM::Matrix::Zero(1,dynamicPtsCount));
00291 dynamicPointCloud->addDescriptor("velocity_dt", PM::Matrix::Zero(1,dynamicPtsCount));
00292
00293
00294
00295 if(!lastPointCloud)
00296 {
00297 lastPointCloud = dynamicPointCloud;
00298 cerr << lastPointCloud->features.cols() << endl;
00299
00300
00301 DP::View viewOn_normals_last = lastPointCloud->getDescriptorViewByName("normals");
00302
00303
00304 PM::Matrix lastEuclNormal(6, dynamicPtsCount);
00305 lastEuclNormal.topRows(3) = lastPointCloud->features.topRows(3);
00306 lastEuclNormal.bottomRows(3) = viewOn_normals_last*p_normalSpaceFactor;
00307
00308
00309 lastNNS.reset( NNS::create(lastPointCloud->features, lastPointCloud->features.rows() - 1, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00310
00311 ROS_INFO_STREAM("Initializing last point cloud");
00312
00313 return;
00314 }
00315
00316 const int lastPtsCount = lastPointCloud->features.cols();
00317 ROS_INFO_STREAM("lastPtsCount: " << lastPtsCount);
00318
00319
00320 if (dynamicPointCloud->features.rows() != lastPointCloud->features.rows())
00321 {
00322 ROS_ERROR_STREAM("Dimensionality missmatch: incoming cloud is " << dynamicPointCloud->features.rows()-1 << " while lastPointCloud is " << lastPointCloud->features.rows()-1);
00323 return;
00324 }
00325
00326
00327
00328
00329 PM::Matrix priorOn_velocityDir = lastPointCloud->getDescriptorViewByName("velocity_dir");
00330 PM::Matrix priorOn_velocityDt = lastPointCloud->getDescriptorViewByName("velocity_dt");
00331
00332 DP::View v_normals_input = dynamicPointCloud->getDescriptorViewByName("normals");
00333 PM::Matrix inputEuclNormal(6, dynamicPtsCount);
00334 inputEuclNormal.topRows(3) = dynamicPointCloud->features.topRows(3);
00335 inputEuclNormal.bottomRows(3) = v_normals_input*p_normalSpaceFactor;
00336
00337
00338
00339 std::shared_ptr<NNS> inputNNS;
00340
00341 inputNNS.reset( NNS::create(dynamicPointCloud->features, 3, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00342
00343
00344
00345 const int nbIter = 5;
00346 for(int i=0; i<nbIter; i++)
00347 {
00348 computeVelocity(lastPointCloud, lastNNS, dynamicPointCloud, inputNNS, p_maxClusterDistance, nbIter-i, dynProjectedPub);
00349 computeVelocity(dynamicPointCloud, inputNNS, lastPointCloud, lastNNS, p_maxClusterDistance, nbIter-i, lastProjectedPub);
00350
00351 averageWithReference(lastPointCloud, dynamicPointCloud, 1);
00352 averageWithReference(dynamicPointCloud, lastPointCloud, 1);
00353 }
00354
00355
00356 DP::View v_matchId_dyn = dynamicPointCloud->getDescriptorViewByName("match_id");
00357
00358 DP::View v_velocityDir_dyn = dynamicPointCloud->getDescriptorViewByName("velocity_dir");
00359 DP::View v_velocityDt_dyn = dynamicPointCloud->getDescriptorViewByName("velocity_dt");
00360 DP::View v_normal_dyn = dynamicPointCloud->getDescriptorViewByName("normals");
00361
00362
00363 DP::View v_velocityDir_last = lastPointCloud->getDescriptorViewByName("velocity_dir");
00364 DP::View v_velocityDt_last = lastPointCloud->getDescriptorViewByName("velocity_dt");
00365
00366
00367 v_velocityDir_dyn *= -1;
00368
00369
00370 visualization_msgs::Marker marker;
00371
00372 marker.header.frame_id = p_mapFrame;
00373 marker.header.stamp = ros::Time::now();
00374 marker.ns = "basic_shapes";
00375 marker.type = visualization_msgs::Marker::LINE_LIST;
00376
00377 marker.scale.x = 0.3;
00378 marker.scale.y = 0.3;
00379 marker.scale.z = 0.3;
00380
00381 marker.color.r = 1.0f;
00382 marker.color.g = 1.0f;
00383 marker.color.b = 0.0f;
00384
00385 if(p_accumulateMarkers)
00386 {
00387 marker.color.a = 0.2;
00388 marker.id = trailCount;
00389 }
00390 else
00391 {
00392 marker.color.a = 1.0;
00393 marker.id = 0;
00394 }
00395
00396 trailCount++;
00397
00398 marker.lifetime = ros::Duration(2);
00399
00400 DP currenttTrails = dynamicPointCloud->createSimilarEmpty();
00401 int currentTrailPtCount = 0;
00402
00403
00404 for(int i=0; i<dynamicPtsCount; i++)
00405 {
00406 const int id = v_matchId_dyn(0,i);
00407
00408 const Eigen::Vector3f pt = dynamicPointCloud->features.col(i).head(3);
00409 const Eigen::Vector3f pt_last = lastPointCloud->features.col(id).head(3);
00410
00411 const Eigen::Vector3f normal = v_normal_dyn.col(i);
00412 const float w_ang = angleWeight(normal, v_velocityDir_dyn.col(i));
00413
00414 const Eigen::Vector3f lastVelDir = priorOn_velocityDir.col(id);
00415 const Eigen::Vector3f currentVelDir = v_velocityDir_dyn.col(i);
00416 const float w_diffAngle = 1 - acos(lastVelDir.normalized().dot(currentVelDir.normalized()))/M_PI;
00417
00418
00419 int lastID = id;
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 const float lastDt = priorOn_velocityDt(0,id);
00438 const float delta = (pt_last - pt).norm();
00439 const float delta_projected = (pt_last + lastVelDir*lastDt - pt).norm();
00440 const float w_proj = delta_projected/delta;
00441
00442
00443 const float mag = currentVelDir.norm();
00444
00445 if(mag > eps && mag < p_maxVelocity)
00446 {
00447 if(w_diffAngle > 0.25 && w_proj < 0.25)
00448 {
00449
00450
00451 v_velocityDir_dyn.col(i) = (lastVelDir + currentVelDir)/2;
00452
00453 geometry_msgs::Point p;
00454 p.x = dynamicPointCloud->features(0,i);
00455 p.y = dynamicPointCloud->features(1,i);
00456 p.z = dynamicPointCloud->features(2,i);
00457 marker.points.push_back(p);
00458
00459 p.x += v_velocityDir_dyn(0,i);
00460 p.y += v_velocityDir_dyn(1,i);
00461 p.z += v_velocityDir_dyn(2,i);
00462
00463 marker.points.push_back(p);
00464
00465 currenttTrails.setColFrom(currentTrailPtCount, *dynamicPointCloud, i);
00466 currentTrailPtCount++;
00467 }
00468 }
00469 else
00470 {
00471 v_velocityDir_dyn.col(i) = Eigen::Vector3f::Zero();
00472 v_velocityDt_dyn(0,i) = 0;
00473 }
00474
00475 }
00476
00477 currenttTrails.conservativeResize(currentTrailPtCount);
00478
00479 if(currentTrailPtCount > 0)
00480 {
00481
00482
00483
00484
00485
00486
00487
00488
00489 }
00490
00491 markerPub.publish(marker);
00492
00493 dynPub.publish(PointMatcher_ros::pointMatcherCloudToRosMsg<float>(*dynamicPointCloud.get(), p_mapFrame, ros::Time::now()));
00494 lastPub.publish(PointMatcher_ros::pointMatcherCloudToRosMsg<float>(*lastPointCloud.get(), p_mapFrame, ros::Time::now()));
00495
00496
00497 lastPointCloud = dynamicPointCloud;
00498 lastNNS = inputNNS;
00499
00500
00501 if(priors.size() >= p_windowSize)
00502 {
00503 priors.pop_back();
00504 }
00505
00506 priors.push_front(dynamicPointCloud);
00507
00508
00509 ROS_INFO_STREAM("Total trail computation: " << t.elapsed() << " [s]");
00510
00511
00512
00513 }
00514
00515
00516 PM::DataPoints DynamicTrails::extractDynamicPoints (const PM::DataPoints input, const float minDynamicRatio)
00517 {
00518 const int inputPtsCount(input.features.cols());
00519
00520 DP output(input.createSimilarEmpty());
00521
00522 const int knn = 1;
00523 Matches::Dists dists_input(knn, inputPtsCount);
00524 Matches::Ids ids_input(knn, inputPtsCount);
00525
00526 usingGlobalMap.lock();
00527 globalNNS->knn(input.features, ids_input, dists_input, knn, 0, 0, p_maxGlobalMapDist);
00528
00529 if(globalMap.descriptorExists("probabilityStatic") == false ||
00530 globalMap.descriptorExists("probabilityDynamic") == false ||
00531 globalMap.descriptorExists("debug") == false
00532 )
00533 {
00534 ROS_WARN_STREAM("Map descriptors not found");
00535 usingGlobalMap.unlock();
00536 return output;
00537 }
00538
00539
00540 DP::View viewOnProbabilityStatic = globalMap.getDescriptorViewByName("probabilityStatic");
00541 DP::View viewOnProbabilityDynamic = globalMap.getDescriptorViewByName("probabilityDynamic");
00542
00543 int dynamicPtsCount=0;
00544 for(int i=0; i<inputPtsCount; i++)
00545 {
00546 float sumObs = 0;
00547 float dist = numeric_limits<float>::infinity();
00548 float dynRatio = 0;
00549
00550 for(int k=0; k<knn; k++)
00551 {
00552 const int mapId = ids_input(k,i);
00553 sumObs = max(sumObs, viewOnProbabilityDynamic(0,mapId) + viewOnProbabilityStatic(0,mapId));
00554 dist = min(dist, dists_input(k,i));
00555 dynRatio = max(dynRatio, viewOnProbabilityDynamic(0, mapId));
00556 }
00557
00558 {
00559
00560 if(dynRatio > minDynamicRatio || dist == numeric_limits<float>::infinity())
00561 {
00562 output.setColFrom(dynamicPtsCount, input, i);
00563 dynamicPtsCount++;
00564 }
00565 }
00566 }
00567
00568 usingGlobalMap.unlock();
00569
00570 output.conservativeResize(dynamicPtsCount);
00571 return output;
00572
00573 }
00574
00575 void DynamicTrails::computeVelocity(shared_ptr<DP> reference, shared_ptr<NNS> ref_tree, shared_ptr<DP> reading, shared_ptr<NNS> read_tree, const float maxRadius, const int knn, ros::Publisher debugPub)
00576 {
00577
00578 const int readPtsCount = reading->features.cols();
00579 const int refPtsCount = reference->features.cols();
00580
00581
00582 DP::View v_velocityDir_read = reading->getDescriptorViewByName("velocity_dir");
00583 DP::View v_velocityDt_read = reading->getDescriptorViewByName("velocity_dt");
00584 DP::View v_normal_read = reading->getDescriptorViewByName("normals");
00585
00586 DP::View v_Msec_read = reading->getDescriptorViewByName("stamps_Msec");
00587 DP::View v_sec_read = reading->getDescriptorViewByName("stamps_sec");
00588 DP::View v_nsec_read = reading->getDescriptorViewByName("stamps_nsec");
00589
00590
00591 PM::Matrix velocityDir_ref = PM::Matrix::Zero(3,refPtsCount);
00592 PM::Matrix velocityDt_ref = PM::Matrix::Zero(1,refPtsCount);
00593
00594 DP::View v_Msec_ref = reference->getDescriptorViewByName("stamps_Msec");
00595 DP::View v_sec_ref = reference->getDescriptorViewByName("stamps_sec");
00596 DP::View v_nsec_ref = reference->getDescriptorViewByName("stamps_nsec");
00597
00598
00599
00600 PM::Matrix moved_read(3, readPtsCount);
00601
00602
00603 const PM::Matrix static_read = reading->features.topRows(3);
00604
00605
00606
00607
00608
00609
00610
00611 for(int i=0; i<readPtsCount; i++)
00612 {
00613 moved_read.col(i)= reading->features.col(i).head(3) + v_velocityDir_read.col(i)*v_velocityDt_read(0,i);
00614
00615
00616
00617
00618
00619
00620 assert(!isnan(moved_read(0,i)));
00621 assert(!isnan(moved_read(1,i)));
00622 assert(!isnan(moved_read(2,i)));
00623 assert(!isinf(moved_read(0,i)));
00624 assert(!isinf(moved_read(1,i)));
00625 assert(!isinf(moved_read(2,i)));
00626 }
00627
00628
00629
00630 Matches::Dists dists(knn, readPtsCount);
00631 Matches::Ids ids(knn, readPtsCount);
00632
00633 ref_tree->knn(moved_read, ids, dists, knn, 0, 2.0);
00634
00635
00636 PM::Matrix sumVec_ref = PM::Matrix::Zero(3,refPtsCount);
00637
00638
00639
00640
00641 PM::Matrix closeId_read = PM::Matrix::Constant(1,readPtsCount, -1);
00642 PM::Matrix weight_ref = PM::Matrix::Zero(1,refPtsCount);
00643 PM::Matrix sumDt_ref = PM::Matrix::Zero(1,refPtsCount);
00644
00645 for(int i=0; i<readPtsCount; i++)
00646 {
00647 const Eigen::Vector3f pt = reading->features.col(i).head(3);
00648 const double timeRead = v_Msec_read(0,i)*1e6 + v_sec_read(0,i) + v_nsec_read(0,i)*1e-9;
00649
00650
00651 float sumWeight = 0;
00652 float sumDt = 0;
00653 Eigen::Vector3f sumVec = Eigen::Vector3f::Zero(3,1);
00654
00655 int nbMatch = 0;
00656 for(int k=0; k<knn; k++)
00657 {
00658 if(dists(k,i) != numeric_limits<float>::infinity())
00659 {
00660 const int id = ids(k,i);
00661 const Eigen::Vector3f pt_nn = reference->features.col(id).head(3);
00662 const double timeRef = v_Msec_ref(0,id)*1e6 + v_sec_ref(0,id) + v_nsec_ref(0,id)*1e-9;
00663
00664 const Eigen::Vector3f delta = pt_nn - pt;
00665 const Eigen::Vector3f normal_read = v_normal_read.col(i);
00666 const double dt = abs(timeRead - timeRef);
00667
00668 const float distRatio = sqrt(dists(k,i))/delta.norm();
00669 const float w_dist = 1 + eps - std::min(1.0f, distRatio);
00670 const float w_ang = angleWeight(normal_read, delta);
00671
00672 const float w = w_dist;
00673
00674
00675 assert(!isnan(w_dist));
00676 assert(!isnan(w_ang));
00677 assert(dt != 0);
00678
00679
00680 weight_ref(id) += w;
00681 sumDt_ref(id) += w*dt;
00682 sumVec_ref.col(id) += w*delta/dt;
00683
00684
00685 sumWeight += w;
00686 sumDt += w*dt;
00687 sumVec += w*delta/dt;
00688
00689
00690 closeId_read(i) = id;
00691 nbMatch++;
00692 }
00693 }
00694
00695
00696
00697 if(sumWeight > eps && nbMatch > 4)
00698 {
00699 sumDt /= sumWeight;
00700 sumVec /= sumWeight;
00701
00702 const float mag = sumVec.norm();
00703 if( mag < p_maxVelocity)
00704 {
00705
00706 v_velocityDir_read.col(i) = sumVec;
00707 v_velocityDt_read(0,i) = sumDt;
00708 }
00709 }
00710
00711
00712
00713 }
00714
00715
00716
00717 for(int i=0; i<refPtsCount; i++)
00718 {
00719
00720 const float mag = sumVec_ref.col(i).norm();
00721 if(mag > eps)
00722 {
00723
00724 sumDt_ref(i) /= weight_ref(i);
00725 sumVec_ref.col(i) /= weight_ref(i);
00726
00727 if(mag < p_maxVelocity)
00728 {
00729
00730 velocityDir_ref.col(i) = sumVec_ref.col(i);
00731 velocityDt_ref(0,i) = sumDt_ref(i);
00732 }
00733 }
00734 }
00735
00736
00737
00738
00739 for(int i=0; i<readPtsCount; i++)
00740 {
00741 assert(!isnan(v_velocityDir_read(0,i)));
00742 const int id = closeId_read(i);
00743
00744 if(id != -1)
00745 {
00746 const float mag = velocityDir_ref.col(id).norm();
00747 if(mag > eps)
00748 {
00749
00750 v_velocityDir_read.col(i) = velocityDir_ref.col(id);
00751 v_velocityDt_read(0,i) = velocityDt_ref(0,id);
00752 }
00753 }
00754
00755 }
00756
00757
00758
00759 const int maxNN = 100;
00760 Matches::Dists dists_local(maxNN, readPtsCount);
00761 Matches::Ids ids_local(maxNN, readPtsCount);
00762
00763
00764 read_tree->knn(static_read, ids_local, dists_local, maxNN, 0, 0, maxRadius);
00765
00766
00767
00768
00769
00770 PM::Matrix sumVec_read = PM::Matrix::Zero(3,readPtsCount);
00771
00772 PM::Matrix weight_read = PM::Matrix::Zero(1,readPtsCount);
00773 PM::Matrix sumMag_read = PM::Matrix::Zero(1,readPtsCount);
00774 PM::Matrix sumDt_read = PM::Matrix::Zero(1,readPtsCount);
00775
00776 for(int i=0; i<readPtsCount; i++)
00777 {
00778 const Eigen::Vector3f normal_read = v_normal_read.col(i);
00779
00780 for(int k=0; k<maxNN; k++)
00781 {
00782 if(dists_local(k,i) != numeric_limits<float>::infinity())
00783 {
00784 const int id = ids_local(k,i);
00785 const Eigen::Vector3f velocityDir = v_velocityDir_read.col(id);
00786
00787 const float w_dist = eps + (1 - eps)*(1 - sqrt(dists_local(k,i))/maxRadius);
00788 assert(!isnan(w_dist));
00789
00790
00791
00792
00793 const float w = w_dist;
00794
00795
00796 weight_read(i) += w;
00797 sumVec_read.col(i) += w*velocityDir;
00798 sumDt_read(i) += w*v_velocityDt_read(0,id);
00799 }
00800 }
00801
00802 }
00803
00804
00805
00806 for(int i=0; i<readPtsCount; i++)
00807 {
00808 assert(!isnan(v_velocityDir_read(0,i)));
00809
00810 if(weight_read(i) > eps)
00811 {
00812
00813 sumDt_read(i) /= weight_read(i);
00814 sumVec_read.col(i) /= weight_read(i);
00815
00816 const float mag = sumVec_read.col(i).norm();
00817 if(mag > eps && mag < p_maxVelocity)
00818 {
00819
00820 v_velocityDir_read.col(i) = sumVec_read.col(i);
00821 v_velocityDt_read(0,i) = sumDt_read(i);
00822 }
00823 }
00824
00825 assert(isnan(v_velocityDir_read(0,i)) == false);
00826
00827 }
00828 reading->addDescriptor("match_id", closeId_read);
00829
00830
00831
00832 DP projectedPointCloud = *reading;
00833 projectedPointCloud.features.topRows(3) = moved_read.topRows(3);
00834 debugPub.publish(PointMatcher_ros::pointMatcherCloudToRosMsg<float>(projectedPointCloud, p_mapFrame, ros::Time::now()));
00835
00836
00837 }
00838
00839 float DynamicTrails::angleWeight(const Eigen::Vector3f &normal, const Eigen::Vector3f &velocity)
00840 {
00841 const float projDist = min(1.0f, fabs(normal.dot(velocity.normalized())));
00842 assert(projDist <= 1);
00843
00844 return (eps + (1 - eps)*(1 - 2.0*acos(projDist)/M_PI));
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855 }
00856
00857 void DynamicTrails::averageWithReference(shared_ptr<DP> reference, shared_ptr<DP> reading, const float dir)
00858 {
00859
00860 const int refPtsCount = reference->features.cols();
00861
00862
00863 DP::View v_velocityDir_read = reading->getDescriptorViewByName("velocity_dir");
00864 DP::View v_velocityDt_read = reading->getDescriptorViewByName("velocity_dt");
00865 DP::View v_normal_read = reading->getDescriptorViewByName("normals");
00866
00867 DP::View v_matchId_ref = reference->getDescriptorViewByName("match_id");
00868 DP::View v_velocityDir_ref = reference->getDescriptorViewByName("velocity_dir");
00869 DP::View v_velocityDt_ref = reference->getDescriptorViewByName("velocity_dt");
00870
00871 for(int i=0; i<refPtsCount; i++)
00872 {
00873 const int id = v_matchId_ref(0,i);
00874 const float w_read = angleWeight(v_normal_read.col(id), v_velocityDir_read.col(id));
00875 const float w_ref = angleWeight(v_normal_read.col(id), v_velocityDir_ref.col(i));
00876 const float w_sum = w_read + w_ref;
00877
00878 const float mag_ref = v_velocityDir_ref.col(i).norm();
00879 if(w_sum > eps && mag_ref > eps)
00880 {
00881 v_velocityDir_read.col(id) = (w_read*dir*v_velocityDir_read.col(id) - w_ref*dir*v_velocityDir_ref.col(i))/(w_sum);
00882
00883 v_velocityDt_read(0,id) = (w_read*v_velocityDt_read(0,id) + w_ref*v_velocityDt_ref(0,i))/(w_sum);
00884 }
00885 }
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906 }
00907
00908
00909
00910 int main(int argc, char **argv)
00911 {
00912 ros::init(argc, argv, "map_maintainer");
00913 ros::NodeHandle n;
00914 ros::NodeHandle pn("~");
00915 DynamicTrails trails(n, pn);
00916
00917 ros::Rate r(50);
00918 while(ros::ok())
00919 {
00920 ros::spinOnce();
00921 r.sleep();
00922 }
00923
00924 return 0;
00925 }