CGR Localization
 All Classes Namespaces Files Functions Variables Macros Pages
localization_main.cpp
Go to the documentation of this file.
1 //========================================================================
2 // This software is free: you can redistribute it and/or modify
3 // it under the terms of the GNU Lesser General Public License Version 3,
4 // as published by the Free Software Foundation.
5 //
6 // This software is distributed in the hope that it will be useful,
7 // but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // GNU Lesser General Public License for more details.
10 //
11 // You should have received a copy of the GNU Lesser General Public License
12 // Version 3 in the file COPYING that came with this distribution.
13 // If not, see <http://www.gnu.org/licenses/>.
14 //========================================================================
20 //========================================================================
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <limits.h>
25 #include <string.h>
26 
27 #include <ros/ros.h>
28 #include <tf/tf.h>
29 #include <tf/transform_listener.h>
30 #include <tf/transform_broadcaster.h>
31 #include <sensor_msgs/LaserScan.h>
32 #include <sensor_msgs/Image.h>
33 #include <nav_msgs/Odometry.h>
34 #include <geometry_msgs/PoseArray.h>
35 #include <geometry_msgs/PoseWithCovarianceStamped.h>
36 #include <ros/package.h>
37 
38 #include "vectorparticlefilter.h"
39 #include "vector_map.h"
40 #include "popt_pp.h"
41 #include "terminal_utils.h"
42 #include "timer.h"
43 #include "proghelp.h"
44 #include "cgr_localization/DisplayMsg.h"
45 #include "cgr_localization/LocalizationInterfaceSrv.h"
46 #include "cgr_localization/LocalizationMsg.h"
47 #include "configreader.h"
48 #include "plane_filtering.h"
49 
50 using namespace std;
51 
52 bool run = true;
53 bool usePointCloud = false;
54 bool noLidar = false;
55 int numParticles = 20;
56 int debugLevel = -1;
57 
58 vector2f initialLoc;
59 float initialAngle;
60 float locUncertainty, angleUncertainty;
61 
62 VectorLocalization2D *localization;
63 
64 using namespace ros;
65 using namespace cgr_localization;
66 Publisher guiPublisher;
67 Publisher localizationPublisher;
68 Publisher filteredPointCloudPublisher;
69 ServiceServer localizationServer;
70 Publisher particlesPublisher;
71 tf::TransformBroadcaster *transformBroadcaster;
72 tf::TransformListener *transformListener;
73 DisplayMsg guiMsg;
74 sensor_msgs::PointCloud filteredPointCloudMsg;
75 
79 
80 vector<vector2f> pointCloud;
81 vector<vector2f> pointCloudNormals;
82 
83 string curMapName;
84 vector2f curLoc;
85 float curAngle;
86 double curTime;
87 sensor_msgs::LaserScan lastLidarMsg;
88 sensor_msgs::Image lastDepthMsg;
89 geometry_msgs::PoseArray particlesMsg;
90 
91 //Point Cloud parameters
92 GVector::matrix3d<float> kinectToRobotTransform;
93 KinectRawDepthCam kinectDepthCam;
95 PlaneFilter planeFilter;
96 
97 void publishGUI();
98 void lidarCallback(const sensor_msgs::LaserScan& msg);
99 void depthCallback(const sensor_msgs::Image& msg);
100 void publishLocation(bool limitRate=true);
101 
102 bool localizationCallback(LocalizationInterfaceSrv::Request& req, LocalizationInterfaceSrv::Response& res)
103 {
104  vector2f loc(req.loc_x, req.loc_y);
105  if(debugLevel>0) printf("Setting location: %f %f %f\u00b0 on %s\n",V2COMP(loc),DEG(req.orientation),req.map.c_str());
106  localization->setLocation(loc, req.orientation,req.map.c_str(),0.01,RAD(1.0));
107  return true;
108 }
109 
110 void ClearGUI()
111 {
112  guiMsg.lines_p1x.clear();
113  guiMsg.lines_p1y.clear();
114  guiMsg.lines_p2x.clear();
115  guiMsg.lines_p2y.clear();
116  guiMsg.points_x.clear();
117  guiMsg.points_y.clear();
118  guiMsg.lines_col.clear();
119  guiMsg.points_col.clear();
120  guiMsg.circles_x.clear();
121  guiMsg.circles_y.clear();
122  guiMsg.circles_col.clear();
123 
124  guiMsg.windowSize = 1.0;
125 }
126 
127 void drawPointCloud()
128 {
129  //printf("publishing %d points\n",(int) pointCloud.size());
130 
131  for(int i=0; i<(int) pointCloud.size(); i++){
132  guiMsg.points_x.push_back(pointCloud[i].x);
133  guiMsg.points_y.push_back(pointCloud[i].y);
134  guiMsg.points_col.push_back(0xDE2352);
135  }
136 }
137 
138 void publishLocation(bool limitRate)
139 {
140  static double tLast = 0;
141  if(GetTimeSec()-tLast<0.03 && limitRate)
142  return;
143  tLast = GetTimeSec();
144  LocalizationMsg msg;
145  localization->computeLocation(curLoc, curAngle);
146  msg.timeStamp = GetTimeSec();
147  msg.x = curLoc.x;
148  msg.y = curLoc.y;
149  msg.angle = curAngle;
150  msg.map = string(localization->getCurrentMapName());
151 
152  localization->getUncertainty(msg.angleUncertainty, msg.locationUncertainty);
153 
154  VectorLocalization2D::EvalValues laserEval, pointCloudEval;
155  localization->getEvalValues(laserEval,pointCloudEval);
156  msg.laserNumCorrespondences = laserEval.numCorrespondences;
157  msg.laserNumObservedPoints = laserEval.numObservedPoints;
158  msg.laserStage0Weights = laserEval.stage0Weights;
159  msg.laserStageRWeights = laserEval.stageRWeights;
160  msg.laserRunTime = laserEval.runTime;
161  msg.lastLaserRunTime = laserEval.lastRunTime;
162  msg.laserMeanSqError = laserEval.meanSqError;
163 
164  msg.pointCloudNumCorrespondences = pointCloudEval.numCorrespondences;
165  msg.pointCloudNumObservedPoints = pointCloudEval.numObservedPoints;
166  msg.pointCloudStage0Weights = pointCloudEval.stage0Weights;
167  msg.pointCloudStageRWeights = pointCloudEval.stageRWeights;
168  msg.pointCloudRunTime = pointCloudEval.runTime;
169  msg.lastPointCloudRunTime = pointCloudEval.lastRunTime;
170  msg.pointCloudMeanSqError = pointCloudEval.meanSqError;
171 
172  localizationPublisher.publish(msg);
173 
174  //Publish particles
175  vector<Particle2D> particles;
176  localization->getParticles(particles);
177  particlesMsg.poses.resize(particles.size());
178  geometry_msgs::Pose particle;
179  for(unsigned int i=0; i<particles.size(); i++){
180  particle.position.x = particles[i].loc.x;
181  particle.position.y = particles[i].loc.y;
182  particle.position.z = 0;
183  particle.orientation.w = cos(0.5*particles[i].angle);
184  particle.orientation.x = 0;
185  particle.orientation.y = 0;
186  particle.orientation.z = sin(0.5*particles[i].angle);
187  particlesMsg.poses[i] = particle;
188  }
189  particlesPublisher.publish(particlesMsg);
190 
191  //Publish map to base_footprint tf
192  try{
193  tf::StampedTransform odomToBaseTf;
194  transformListener->lookupTransform("odom","base_footprint",ros::Time(0), odomToBaseTf);
195 
196  vector2f map_base_trans = curLoc;
197  float map_base_rot = curAngle;
198 
199  vector2f odom_base_trans(odomToBaseTf.getOrigin().x(), odomToBaseTf.getOrigin().y());
200  float odom_base_rot = 2.0*atan2(odomToBaseTf.getRotation().z(), odomToBaseTf.getRotation().w());
201 
202  vector2f base_odom_trans = -odom_base_trans.rotate(-odom_base_rot);
203  float base_odom_rot = -odom_base_rot;
204 
205  vector2f map_odom_trans = map_base_trans + base_odom_trans.rotate(map_base_rot);
206  float map_odom_rot = angle_mod(map_base_rot + base_odom_rot);
207 
208  tf::Transform mapToOdomTf;
209  mapToOdomTf.setOrigin(tf::Vector3(V2COMP(map_odom_trans), 0.0));
210  mapToOdomTf.setRotation(tf::Quaternion(tf::Vector3(0,0,1),map_odom_rot));
211  transformBroadcaster->sendTransform(tf::StampedTransform(mapToOdomTf, ros::Time::now(), "map", "odom"));
212  }
213  catch (tf::TransformException ex){
214  //Do nothing: We'll just try again next time
215  }
216 }
217 
218 void publishGUI()
219 {
220  static double tLast = 0;
221  static double publishInterval = 0.016;
222  if(debugLevel<0 || GetTimeSec()-tLast<publishInterval)
223  return;
224  tLast = GetTimeSec();
225  ClearGUI();
226  //DrawMap();
227  guiMsg.robotLocX = curLoc.x;
228  guiMsg.robotLocY = curLoc.y;
229  guiMsg.robotAngle = curAngle;
230  localization->drawDisplay(guiMsg.lines_p1x, guiMsg.lines_p1y, guiMsg.lines_p2x, guiMsg.lines_p2y, guiMsg.lines_col, guiMsg.points_x, guiMsg.points_y, guiMsg.points_col, guiMsg.circles_x, guiMsg.circles_y, guiMsg.circles_col, 1.0);
231  //drawPointCloud();
232  guiPublisher.publish(guiMsg);
233 }
234 
235 void LoadParameters()
236 {
237  WatchFiles watch_files;
238  ConfigReader config(ros::package::getPath("cgr_localization").append("/").c_str());
239 
240  config.init(watch_files);
241 
242  config.addFile("config/localization_parameters.cfg");
243  config.addFile("config/kinect_parameters.cfg");
244 
245  if(!config.readFiles()){
246  printf("Failed to read config\n");
247  exit(1);
248  }
249 
250  {
251  ConfigReader::SubTree c(config,"KinectParameters");
252 
253  unsigned int maxDepthVal;
254  bool error = false;
255  error = error || !c.getReal("f",kinectDepthCam.f);
256  error = error || !c.getReal("fovH",kinectDepthCam.fovH);
257  error = error || !c.getReal("fovV",kinectDepthCam.fovV);
258  error = error || !c.getInt("width",kinectDepthCam.width);
259  error = error || !c.getInt("height",kinectDepthCam.height);
260  error = error || !c.getUInt("maxDepthVal",maxDepthVal);
261  kinectDepthCam.maxDepthVal = maxDepthVal;
262 
263  vector3f kinectLoc;
264  float xRot, yRot, zRot;
265  error = error || !c.getVec3f("loc",kinectLoc);
266  error = error || !c.getReal("xRot",xRot);
267  error = error || !c.getReal("yRot",yRot);
268  error = error || !c.getReal("zRot",zRot);
269  kinectToRobotTransform.xyzRotationAndTransformation(xRot,yRot,zRot,kinectLoc);
270 
271  if(error){
272  printf("Error Loading Kinect Parameters!\n");
273  exit(2);
274  }
275  }
276 
277  {
278  ConfigReader::SubTree c(config,"PlaneFilteringParameters");
279 
280  bool error = false;
281  error = error || !c.getUInt("maxPoints",filterParams.maxPoints);
282  error = error || !c.getUInt("numSamples",filterParams.numSamples);
283  error = error || !c.getUInt("numLocalSamples",filterParams.numLocalSamples);
284  error = error || !c.getUInt("planeSize",filterParams.planeSize);
285  error = error || !c.getReal("maxError",filterParams.maxError);
286  error = error || !c.getReal("maxDepthDiff",filterParams.maxDepthDiff);
287  error = error || !c.getReal("minInlierFraction",filterParams.minInlierFraction);
288  error = error || !c.getReal("WorldPlaneSize",filterParams.WorldPlaneSize);
289  error = error || !c.getUInt("numRetries",filterParams.numRetries);
290  filterParams.runPolygonization = false;
291 
292  if(error){
293  printf("Error Loading Plane Filtering Parameters!\n");
294  exit(2);
295  }
296  }
297 
298  {
299  ConfigReader::SubTree c(config,"initialConditions");
300 
301  bool error = false;
302  curMapName = string(c.getStr("mapName"));
303  error = error || curMapName.length()==0;
304  error = error || !c.getVec2f("loc",initialLoc);
305  error = error || !c.getReal("angle", initialAngle);
306  error = error || !c.getReal("locUncertainty", locUncertainty);
307  error = error || !c.getReal("angleUncertainty", angleUncertainty);
308 
309  if(error){
310  printf("Error Loading Initial Conditions!\n");
311  exit(2);
312  }
313  }
314 
315  {
316  ConfigReader::SubTree c(config,"motionParams");
317 
318  bool error = false;
319  error = error || !c.getReal("Alpha1", motionParams.Alpha1);
320  error = error || !c.getReal("Alpha2", motionParams.Alpha2);
321  error = error || !c.getReal("Alpha3", motionParams.Alpha3);
322  error = error || !c.getReal("kernelSize", motionParams.kernelSize);
323 
324 
325  if(error){
326  printf("Error Loading Predict Parameters!\n");
327  exit(2);
328  }
329  }
330 
331  {
332  ConfigReader::SubTree c(config,"lidarParams");
333 
334  bool error = false;
335  // Laser sensor properties
336  error = error || !c.getReal("angleResolution", lidarParams.angleResolution);
337  error = error || !c.getInt("numRays", lidarParams.numRays);
338  error = error || !c.getReal("maxRange", lidarParams.maxRange);
339  error = error || !c.getReal("minRange", lidarParams.minRange);
340 
341  // Pose of laser sensor on robot
342  vector2f laserToBaseTrans;
343  float xRot, yRot, zRot;
344  error = error || !c.getVec2f<vector2f>("laserToBaseTrans", laserToBaseTrans);
345  error = error || !c.getReal("xRot", xRot);
346  error = error || !c.getReal("yRot", yRot);
347  error = error || !c.getReal("zRot", zRot);
348  Matrix3f laserToBaseRot;
349  laserToBaseRot = AngleAxisf(xRot, Vector3f::UnitX()) * AngleAxisf(yRot, Vector3f::UnitY()) * AngleAxisf(zRot, Vector3f::UnitZ());
350  lidarParams.laserToBaseTrans = Vector2f(V2COMP(laserToBaseTrans));
351  lidarParams.laserToBaseRot = laserToBaseRot.block(0,0,2,2);
352 
353  // Parameters related to observation update
354  error = error || !c.getReal("logObstacleProb", lidarParams.logObstacleProb);
355  error = error || !c.getReal("logOutOfRangeProb", lidarParams.logOutOfRangeProb);
356  error = error || !c.getReal("logShortHitProb", lidarParams.logShortHitProb);
357  error = error || !c.getReal("correlationFactor", lidarParams.correlationFactor);
358  error = error || !c.getReal("lidarStdDev", lidarParams.lidarStdDev);
359  error = error || !c.getReal("attractorRange", lidarParams.attractorRange);
360  error = error || !c.getReal("kernelSize", lidarParams.kernelSize);
361 
362  // Parameters related to observation refine
363  error = error || !c.getInt("minPoints", lidarParams.minPoints);
364  error = error || !c.getInt("numSteps", lidarParams.numSteps);
365  error = error || !c.getReal("etaAngle", lidarParams.etaAngle);
366  error = error || !c.getReal("etaLoc", lidarParams.etaLoc);
367  error = error || !c.getReal("maxAngleGradient", lidarParams.maxAngleGradient);
368  error = error || !c.getReal("maxLocGradient", lidarParams.maxLocGradient);
369  error = error || !c.getReal("minCosAngleError", lidarParams.minCosAngleError);
370  error = error || !c.getReal("correspondenceMargin", lidarParams.correspondenceMargin);
371  error = error || !c.getReal("minRefineFraction", lidarParams.minRefineFraction);
372 
373  lidarParams.initialize();
374 
375  if(error){
376  printf("Error Loading Lidar Parameters!\n");
377  exit(2);
378  }
379  }
380 
381  {
382  ConfigReader::SubTree c(config,"pointCloudParams");
383 
384  bool error = false;
385  error = error || !c.getReal("logObstacleProb", pointCloudParams.logObstacleProb);
386  error = error || !c.getReal("logShortHitProb", pointCloudParams.logShortHitProb);
387  error = error || !c.getReal("logOutOfRangeProb", pointCloudParams.logOutOfRangeProb);
388  error = error || !c.getReal("correlationFactor", pointCloudParams.corelationFactor);
389  error = error || !c.getReal("stdDev", pointCloudParams.stdDev);
390  error = error || !c.getReal("kernelSize", pointCloudParams.kernelSize);
391  error = error || !c.getReal("attractorRange", pointCloudParams.attractorRange);
392  error = error || !c.getReal("maxRange", pointCloudParams.maxRange);
393  error = error || !c.getReal("minRange", pointCloudParams.minRange);
394 
395  error = error || !c.getReal("attractorRange", pointCloudParams.attractorRange);
396  error = error || !c.getReal("etaAngle", pointCloudParams.etaAngle);
397  error = error || !c.getReal("etaLoc", pointCloudParams.etaLoc);
398  error = error || !c.getReal("maxAngleGradient", pointCloudParams.maxAngleGradient);
399  error = error || !c.getReal("maxLocGradient", pointCloudParams.maxLocGradient);
400  error = error || !c.getReal("minCosAngleError", pointCloudParams.minCosAngleError);
401  error = error || !c.getInt("numSteps", pointCloudParams.numSteps);
402  error = error || !c.getInt("minPoints", pointCloudParams.minPoints);
403  error = error || !c.getReal("minRange", pointCloudParams.minRange);
404  error = error || !c.getReal("maxRange", pointCloudParams.maxRange);
405  error = error || !c.getReal("correspondenceMargin", pointCloudParams.correspondenceMargin);
406  error = error || !c.getReal("minRefineFraction", pointCloudParams.minRefineFraction);
407 
408  if(error){
409  printf("Error Loading Point Cloud Parameters!\n");
410  exit(2);
411  }
412  }
413 
414  planeFilter.setParameters(&kinectDepthCam,filterParams);
415 }
416 
417 void InitModels(){
418  lidarParams.laserScan = (float*) malloc(lidarParams.numRays*sizeof(float));
419 
420  filteredPointCloudMsg.header.seq = 0;
421  filteredPointCloudMsg.header.frame_id = "base_footprint";
422  filteredPointCloudMsg.channels.clear();
423 
424  return;
425 }
426 
427 void odometryCallback(const nav_msgs::OdometryConstPtr &msg)
428 {
429  static float angle = 0;
430  static vector2f loc(0,0);
431  static bool initialized=false;
432  static double tLast = 0;
433 
434  if(tLast>msg->header.stamp.toSec())
435  initialized = false;
436 
437  if(!initialized){
438  angle = tf::getYaw(msg->pose.pose.orientation);
439  loc = vector2f(msg->pose.pose.position.x, msg->pose.pose.position.y);
440  initialized = true;
441  return;
442  }
443 
444  float newAngle = tf::getYaw(msg->pose.pose.orientation);
445  vector2f newLoc(msg->pose.pose.position.x, msg->pose.pose.position.y);
446 
447  vector2f d = (newLoc-loc).rotate(-angle);
448  double dx = d.x;
449  double dy = d.y;
450  double dtheta = angle_mod(newAngle-angle);
451 
452  if((sq(dx)+sq(dy))>sq(0.4) || fabs(dtheta)>RAD(40)){
453  printf("Odometry out of bounds: x:%7.3f y:%7.3f a:%7.3f\u00b0\n",dx, dy, DEG(dtheta));
454  angle = newAngle;
455  loc = newLoc;
456  return;
457  }
458 
459  if(debugLevel>0) printf("Odometry t:%f x:%7.3f y:%7.3f a:%7.3f\u00b0\n",msg->header.stamp.toSec(), dx, dy, DEG(dtheta));
460 
461  localization->predict(dx, dy, dtheta, motionParams);
462 
463  angle = newAngle;
464  loc = newLoc;
465 }
466 
467 void lidarCallback(const sensor_msgs::LaserScan &msg)
468 {
469  //FunctionTimer ft(__PRETTY_FUNCTION__);
470  if(debugLevel>0){
471  printf("LIDAR n:%d t:%f noLidar:%d\n",(int) msg.ranges.size(), msg.scan_time, noLidar?1:0);
472  }
473 
474  tf::StampedTransform baseLinkToLaser;
475  try{
476  transformListener->lookupTransform("base_footprint", msg.header.frame_id, ros::Time(0), baseLinkToLaser);
477  }
478  catch(tf::TransformException ex){
479  ROS_ERROR("%s",ex.what());
480  }
481  tf::Vector3 translationTf = baseLinkToLaser.getOrigin();
482  tf::Quaternion rotationTf = baseLinkToLaser.getRotation();
483 
484  Quaternionf rotQuat3D(rotationTf.w(), rotationTf.x(), rotationTf.y(), rotationTf.z());
485  Matrix3f rot3D(rotQuat3D);
486  Vector3f trans3D(translationTf.x(), translationTf.y(),translationTf.z());
487 
488  trans3D = rot3D*trans3D;
489  lidarParams.laserToBaseRot = rot3D.topLeftCorner(2,2);
490  lidarParams.laserToBaseTrans = trans3D.topLeftCorner(2,1);
491 
492  bool newLaser = lidarParams.minRange != msg.range_min ||
493  lidarParams.maxRange != msg.range_max ||
494  lidarParams.minAngle != msg.angle_min ||
495  lidarParams.maxAngle != msg.angle_max ||
496  lidarParams.angleResolution != msg.angle_increment ||
497  lidarParams.numRays != int(msg.ranges.size());
498  if(newLaser){
499  lidarParams.minRange = msg.range_min;
500  lidarParams.maxRange = msg.range_max;
501  lidarParams.minAngle = msg.angle_min;
502  lidarParams.maxAngle = msg.angle_max;
503  lidarParams.angleResolution = msg.angle_increment;
504  lidarParams.numRays = int(msg.ranges.size());
505  lidarParams.initialize();
506  }
507 
508  if(int(msg.ranges.size()) != lidarParams.numRays){
509  TerminalWarning("Incorrect number of Laser Scan rays!");
510  printf("received: %d\n",int(msg.ranges.size()));
511  }
512 
513  for(int i=0; i<(int)msg.ranges.size(); i++)
514  lidarParams.laserScan[i] = msg.ranges[i];
515 
516 
517  if(!noLidar){
518  localization->refineLidar(lidarParams);
519  localization->updateLidar(lidarParams, motionParams);
520  localization->resample(VectorLocalization2D::LowVarianceResampling);
521  localization->computeLocation(curLoc,curAngle);
522  }
523 }
524 
525 
526 void depthCallback(const sensor_msgs::Image &msg)
527 {
528  //Copy the depth data
529  if(debugLevel>0){
530  printf("Depth Message t:%f\n", msg.header.stamp.toSec());
531  }
532  const uint8_t* ptrSrc = msg.data.data();
533  uint16_t depth[640*480];
534  memcpy(depth, ptrSrc, 640*480*(sizeof(uint16_t)));
535 
536  if(!usePointCloud)
537  return;
538 
539  tf::StampedTransform baseLinkToKinect;
540  try{
541  transformListener->lookupTransform("base_footprint", msg.header.frame_id, ros::Time(0), baseLinkToKinect);
542  }
543  catch(tf::TransformException ex){
544  ROS_ERROR("%s",ex.what());
545  }
546  tf::Vector3 translationTf = baseLinkToKinect.getOrigin();
547  tf::Quaternion rotationTf = baseLinkToKinect.getRotation();
548  Quaternionf rotQuat3D(rotationTf.w(), rotationTf.x(), rotationTf.y(), rotationTf.z());
549  Matrix3f rotMatrix(rotQuat3D);
550  kinectToRobotTransform.m11 = rotMatrix(0,0);
551  kinectToRobotTransform.m12 = rotMatrix(0,1);
552  kinectToRobotTransform.m13 = rotMatrix(0,2);
553  kinectToRobotTransform.m14 = translationTf.x();
554  kinectToRobotTransform.m21 = rotMatrix(1,0);
555  kinectToRobotTransform.m22 = rotMatrix(1,1);
556  kinectToRobotTransform.m23 = rotMatrix(1,2);
557  kinectToRobotTransform.m24 = translationTf.y();
558  kinectToRobotTransform.m31 = rotMatrix(2,0);
559  kinectToRobotTransform.m32 = rotMatrix(2,1);
560  kinectToRobotTransform.m33 = rotMatrix(2,2);
561  kinectToRobotTransform.m34 = translationTf.z();
562  kinectToRobotTransform.m41 = 0;
563  kinectToRobotTransform.m42 = 0;
564  kinectToRobotTransform.m43 = 0;
565  kinectToRobotTransform.m44 = 1;
566 
567  //Generate filtered point cloud
568  vector<vector3f> filteredPointCloud;
569  vector<vector3f> pointCloudNormals;
570  vector<vector3f> outlierCloud;
571  vector<vector2i> pixelLocs;
572  vector<PlanePolygon> planePolygons;
573 
574  planeFilter.GenerateFilteredPointCloud(depth, filteredPointCloud, pixelLocs, pointCloudNormals, outlierCloud, planePolygons);
575 
576  //Transform from kinect coordinates to robot coordinates
577 
578  for(unsigned int i=0; i<filteredPointCloud.size(); i++){
579  filteredPointCloud[i] = filteredPointCloud[i].transform(kinectToRobotTransform);
580  pointCloudNormals[i] = pointCloudNormals[i].transform(kinectToRobotTransform);
581  }
582 
583 
584  if(debugLevel>0){
585  filteredPointCloudMsg.points.clear();
586  filteredPointCloudMsg.header.stamp = ros::Time::now();
587 
588  vector<geometry_msgs::Point32>* points = &(filteredPointCloudMsg.points);
589  geometry_msgs::Point32 p;
590  for(int i=0; i<(int)filteredPointCloud.size(); i++){
591  p.x = filteredPointCloud[i].x;
592  p.y = filteredPointCloud[i].y;
593  p.z = filteredPointCloud[i].z;
594  points->push_back(p);
595  }
596  filteredPointCloudPublisher.publish(filteredPointCloudMsg);
597  }
598 
599  //Call particle filter
600  {
601  vector<vector2f> pointCloud2D, pointCloudNormals2D;
602 
603  for(unsigned int i=0; i<filteredPointCloud.size(); i++){
604  if(fabs(pointCloudNormals[i].z)>sin(RAD(30.0)))
605  continue;
606 
607  vector2f curNormal(V2COMP(pointCloudNormals[i]));
608  vector2f curPoint(V2COMP(filteredPointCloud[i]));
609  curNormal.normalize();
610  pointCloudNormals2D.push_back(curNormal);
611  pointCloud2D.push_back(curPoint);
612  }
613 
614  localization->refinePointCloud(pointCloud2D, pointCloudNormals2D, pointCloudParams);
615  localization->updatePointCloud(pointCloud2D, pointCloudNormals2D, motionParams, pointCloudParams);
616  localization->resample(VectorLocalization2D::LowVarianceResampling);
617  localization->computeLocation(curLoc,curAngle);
618  }
619 }
620 
621 void initialPoseCallback(const geometry_msgs::PoseWithCovarianceStamped &msg)
622 {
623  float angle = 2.0*asin(msg.pose.pose.orientation.z);
624  vector2f loc(V2COMP(msg.pose.pose.position));
625  printf("Initializing CGR localization at %.3f,%.3f, %.2f\u00b0\n",V2COMP(loc), DEG(angle));
626  //localization->initialize(numParticles,curMapName.c_str(), loc, angle,sqrt(msg.pose.covariance[0]),sqrt(msg.pose.covariance[35]));
627  localization->initialize(numParticles,curMapName.c_str(), loc, angle,0.01,RAD(1.0));
628 }
629 
630 int main(int argc, char** argv)
631 {
632  //========================= Load Parameters from config file ======================
633  LoadParameters();
634 
635  //========================== Set up Command line parameters =======================
636  static struct poptOption options[] = {
637  { "num-particles", 'n', POPT_ARG_INT, &numParticles, 0, "Number of Particles", "NUM"},
638  { "debug", 'd', POPT_ARG_INT, &debugLevel, 0, "Debug Level", "NUM"},
639  { "start-x", 'x', POPT_ARG_DOUBLE, &initialLoc.x, 0, "Starting X location", "NUM"},
640  { "start-y", 'y', POPT_ARG_DOUBLE, &initialLoc.y, 0, "Starting Y location", "NUM"},
641  { "start-angle", 'a', POPT_ARG_DOUBLE, &initialAngle, 0, "Starting Angle", "NUM"},
642  { "use-point-cloud", 'p', POPT_ARG_NONE, &usePointCloud, 0, "Use Point Cloud", "NONE"},
643  { "no-lidar", 'l', POPT_ARG_NONE, &noLidar, 0, "No LIDAR Observations", "NONE"},
644  { "Alpha1-param", 'u', POPT_ARG_DOUBLE, &motionParams.Alpha1, 0, "Alpha1 parameter", "NUM"},
645  { "Alpha2-param", 'v', POPT_ARG_DOUBLE, &motionParams.Alpha2, 0, "Alpha2 parameter", "NUM"},
646  { "Alpha3-param", 'w', POPT_ARG_DOUBLE, &motionParams.Alpha3, 0, "Alpha3 parameter", "NUM"},
647 
648  POPT_AUTOHELP
649  { NULL, 0, 0, NULL, 0, NULL, NULL }
650  };
651  // parse options
652  POpt popt(NULL,argc,(const char**)argv,options,0);
653  int c;
654  while((c = popt.getNextOpt()) >= 0){
655  }
656 
657  //========================= Welcome screen, Load map & log ========================
658  ColourTerminal(TerminalUtils::TERMINAL_COL_WHITE,TerminalUtils::TERMINAL_COL_BLACK,TerminalUtils::TERMINAL_ATTR_BRIGHT);
659  printf("\nVector Localization\n\n");
660  ResetTerminal();
661 
662  if(debugLevel>=0){
663  printf("NumParticles : %d\n",numParticles);
664  printf("Alpha1 : %f\n",motionParams.Alpha1);
665  printf("Alpha2 : %f\n",motionParams.Alpha2);
666  printf("Alpha3 : %f\n",motionParams.Alpha3);
667  printf("UsePointCloud : %d\n",usePointCloud?1:0);
668  printf("UseLIDAR : %d\n",noLidar?0:1);
669  printf("Visualizations : %d\n",debugLevel>=0?1:0);
670  printf("\n");
671  }
672  double seed = floor(fmod(GetTimeSec()*1000000.0,1000000.0));
673  if(debugLevel>-1) printf("Seeding with %d\n",(unsigned int)seed);
674  srand(seed);
675 
676  //Initialize particle filter, sensor model, motion model, refine model
677  string mapsFolder(ros::package::getPath("cgr_localization").append("/maps/"));
678  localization = new VectorLocalization2D(mapsFolder.c_str());
679  InitModels();
680 
681  //Initialize particle filter
682  localization->initialize(numParticles,curMapName.c_str(),initialLoc,initialAngle,locUncertainty,angleUncertainty);
683 
684  //Initialize ros for sensor and odometry topics
685  InitHandleStop(&run);
686  ros::init(argc, argv, "CGR_Localization");
687  ros::NodeHandle n;
688  guiPublisher = n.advertise<DisplayMsg>("localization_gui",1,true);
689  localizationPublisher = n.advertise<LocalizationMsg>("localization",1,true);
690  particlesPublisher = n.advertise<geometry_msgs::PoseArray>("particlecloud",1,false);
691  Sleep(0.1);
692 
693  localizationServer = n.advertiseService("localization_interface", &localizationCallback);
694 
695  //Initialize ros for sensor and odometry topics
696  ros::Subscriber odometrySubscriber = n.subscribe("odom", 20, odometryCallback);
697  ros::Subscriber lidarSubscriber = n.subscribe("scan", 5, lidarCallback);
698  ros::Subscriber kinectSubscriber = n.subscribe("kinect_depth", 1, depthCallback);
699  ros::Subscriber initialPoseSubscriber = n.subscribe("initialpose",1,initialPoseCallback);
700  transformListener = new tf::TransformListener(ros::Duration(10.0));
701  transformBroadcaster = new tf::TransformBroadcaster();
702 
703  filteredPointCloudPublisher = n.advertise<sensor_msgs::PointCloud>("Cobot/Kinect/FilteredPointCloud", 1);
704 
705  while(ros::ok() && run){
706  ros::spinOnce();
707  publishGUI();
708  publishLocation();
709  Sleep(0.005);
710  }
711 
712  if(debugLevel>=0) printf("closing.\n");
713  return 0;
714 }
void getParticles(vector< Particle2D > &_particles)
Returns current particles.
Subroutines to spice up stdout.
void refinePointCloud(const vector< vector2f > &pointCloud, const vector< vector2f > &pointNormals, const VectorLocalization2D::PointCloudParams &pointCloudParams)
Refine proposal distribution based on Point Cloud observations.
C++ Implementation: Particle, VectorLocalization.
C++ Interfaces: VectorMap, LineSection.
void updatePointCloud(vector< vector2f > &pointCloud, vector< vector2f > &pointNormals, const VectorLocalization2D::MotionModelParams &motionParams, const VectorLocalization2D::PointCloudParams &pointCloudParams)
Update distribution based on Point Cloud observations.
float f
focal point
void initialize(int _numParticles, const char *mapName, vector2f loc, float angle, float locationUncertainty=0.0, float angleUncertainty=0.0)
Initialise arrays, and sets initial location to.
Parameters for plane filtering.
VectorLocalization2D::PointCloudParams pointCloudParams
FSPF point cloud.
float Alpha1
Alpha1 = Error in angle per delta in angle.
Definition: popt_pp.h:6
void refineLidar(const VectorLocalization2D::LidarParams &lidarParams)
Refine proposal distribution based on LIDAR observations.
void drawDisplay(vector< float > &lines_p1x, vector< float > &lines_p1y, vector< float > &lines_p2x, vector< float > &lines_p2y, vector< uint32_t > &lines_color, vector< float > &points_x, vector< float > &points_y, vector< uint32_t > &points_color, vector< float > &circles_x, vector< float > &circles_y, vector< uint32_t > &circles_color, float scale=1.0)
Compile lists of drawing primitives that can be visualized for debugging purposes.
void setLocation(vector2f loc, float angle, const char *map, float locationUncertainty, float angleUncertainty)
Set pose with specified uncertainty.
void predict(float dx, float dy, float dtheta, const VectorLocalization2D::MotionModelParams &motionParams)
Predict step of the particle filter. Samples from the motion model.
void computeLocation(vector2f &loc, float &angle)
Compute the maximum likelihood location based on particle spread.
float Alpha2
Alpha2 = Error in angle per delta in translation.
void updateLidar(const VectorLocalization2D::LidarParams &lidarParams, const VectorLocalization2D::MotionModelParams &motionParams)
Update distribution based on LIDAR observations.
void resample(Resample type=LowVarianceResampling)
Resample distribution.
void getEvalValues(EvalValues &_laserEval, EvalValues &_pointCloudEval)
Return evaluation values.
void GenerateFilteredPointCloud(void *depthImage, vector< vector3f > &filteredPointCloud, vector< vector2i > &pixelLocs, vector< vector3f > &pointCloudNormals, vector< vector3f > &outlierCloud, vector< PlanePolygon > &polygons)
Accepts a depth image, returns filtered point cloud + normals, outliers, and all sampled points...
const char * getCurrentMapName()
Returns the current map name.
uint16_t maxDepthVal
Maximum valid depth value.
vector2d< num > rotate(const double a) const MustUseResult
return vector rotated by angle a
Definition: gvector.h:975
Raw Kinect Depth Camera to process raw depth images from libfreenect.
Interface to PlaneFiltering class, to perform plane filtering of 3D point clouds from depth images...
void getUncertainty(float &_angleUnc, float &_locUnc)
Return angle and location uncertainties.
float Alpha3
Alpha3 = Error in translation per delta in translation.