NimbRo ROS Soccer Package
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Localization.hpp
1 //Localization.hpp
2 // Created on: Apr 20, 2016
3 // Author: Hafez Farazi <farazi@ais.uni-bonn.de>
4 #pragma once
5 #include <opencv2/opencv.hpp>
6 #include <math.h>
7 #include <vision_module/Tools/Parameters.hpp>
8 #include <vision_module/Tools/General.hpp>
9 #include <vision_module/Tools/SortFuntions.hpp>
10 #include <vision_module/Tools/LinearBoundaryChecker.hpp>
11 #include <vision_module/Tools/LineSegment.hpp>
12 #include <vision_module/Projections/CameraProjections.hpp>
13 #include <vision_module/Tools/Kalman.hpp>
14 #include <vision_module/SoccerObjects/ObstacleDetector.hpp>
15 #include <gait_msgs/GaitOdom.h>
16 #include <boost/timer/timer.hpp>
17 #include <algorithm> // std::sort
18 #include <field_model/field_model.h>
19 #include <tf/transform_broadcaster.h>
20 #include <math.h>
21 
22 #include <Eigen/StdVector>
23 #include <g2o/core/sparse_optimizer.h>
24 #include <g2o/core/block_solver.h>
25 #include <g2o/core/hyper_graph.h>
26 #include <g2o/core/solver.h>
27 #include <g2o/core/factory.h>
28 #include <g2o/core/robust_kernel_impl.h>
29 #include <g2o/core/optimization_algorithm_levenberg.h>
30 #include <g2o/solvers/cholmod/linear_solver_cholmod.h>
31 #include <g2o/solvers/dense/linear_solver_dense.h>
32 #include <g2o/types/sba/types_six_dof_expmap.h>
33 #include <g2o/solvers/structure_only/structure_only_solver.h>
34 #include <g2o/solvers/csparse/linear_solver_csparse.h>
35 #include <g2o/types/slam3d/vertex_se3.h>
36 #include <g2o/types/slam2d/edge_se2.h>
37 #include <g2o/types/slam2d/vertex_se2.h>
38 
39 using namespace cv;
40 using namespace Eigen;
41 using namespace g2o;
42 
43 enum LineType
44 {
45  HorUndef,
46  HorCenter,
47  HorGoal,
48  HorGoalNear,
49  VerUndef,
50  VerLeft,
51  VerRight,
52  VerLeftNear,
53  VerRightNear,
54  VerLeftT,
55  VerRightT,
56  LTRES
57 };
58 
59 enum LandmarkType
60 {
61  CenterL = 0, RightL, FrontL, LeftL, BackL
62 };
63 
64 const std::string LineTypeName[LTRES] =
65 { "HorUndef", "HorCenter", "HorGoal", "HorGoalNear", "VerUndef", "VerLeft",
66  "VerRight", "VerLeftNear", "VerRightNear", "VerLeftT", "VerRightT" };
67 class LineContainer
68 {
69 public:
70  inline LineContainer(LineSegment _lineTransformed, LineType _type) :
71  lineTransformed(_lineTransformed), type(_type)
72  {
73 
74  }
75  LineSegment lineTransformed;
76  LineType type;
77 };
78 
79 class FeatureContainer
80 {
81 public:
82  inline FeatureContainer(Point2f _position, string _type) :
83  position(_position), type(_type)
84  {
85 
86  }
87  Point2f position;
88  string type;
89 };
96 {
97 private:
98  inline double getUpdateCoef(double coef, cv::Point2f point)
99  {
100  double distance = GetDistance(point);
101 
102  if (distance > 8)
103  return 0;
104  if (distance < 3)
105  return coef;
106 
107  return coef * (1 - (distance / 8));
108  }
109 
110  inline double getUpdateCoef(double coef, LineSegment line)
111  {
112  return getUpdateCoef(coef,
113  line.GetClosestPointOnLineSegment(cv::Point2d(0, 0)))
114  * line.getProbability();
115  }
116 
117  ros::NodeHandle nodeHandle;
118  ros::Subscriber setLoc_sub;
119  ros::Subscriber robotTracker_sub;
120  ros::Subscriber robotTracker2_sub;
121  ros::Subscriber odom_sub;
122  Point2d location;
123  Point2d locationKalman;
124  KalmanFilterC kalmanI;
125  CameraProjections *_cameraProjections;
126  geometry_msgs::Point robotTrackerLoc;
127  float lastOdomX, lastOdomY;
128  Point3d globalPos;
129  Point3d lastOdom;
130  uint32_t lastOdomID;
131  Point2f ballPos;
132  const field_model::FieldModel* const m_field;
133  // TF transforms
134  tf::TransformBroadcaster tfBroadcaster;
135  tf::StampedTransform tfLocField;
136  vector<ObstacleC> *obstacles;
137  BlockSolverX::LinearSolverType * linearSolver;
138  BlockSolverX* blockSolver;
139  OptimizationAlgorithmLevenberg* optimizationAlgorithm;
140  int CurrentVertexId;
141  int PreviousVertexId;
142  int LandmarkCount;
143  Point2d odomLastGet;
144  bool atLeastOneObservation;
145  ros::Time lastSavedNodeTime;
146  long unsigned int nodeCounter;
147 public:
148  SparseOptimizer optimizer;
149 
150  inline ~Localization()
151  {
152  optimizer.clear();
153  delete optimizationAlgorithm;
154  }
155 
156  inline Localization(vector<ObstacleC> *obstacles) :
157  location(-1.42, 0), locationKalman(location), kalmanI(
158  locationKalman), _cameraProjections(
159  NULL), lastOdomX(0), lastOdomY(0), globalPos(0, 0, 0), lastOdom(0,
160  0, 0), lastOdomID(0), ballPos(0, 0), m_field(
161  field_model::FieldModel::getInstance()), obstacles(
162  obstacles), CurrentVertexId(0), PreviousVertexId(0), LandmarkCount(
163  0), odomLastGet(0, 0), atLeastOneObservation(false), nodeCounter(
164  0)
165  {
166 
167  odom_sub = nodeHandle.subscribe("/gait/odometry", 10,
168  &Localization::dead_reckoning_callback, this);
169  setLoc_sub = nodeHandle.subscribe<geometry_msgs::Point>(
170  "/vision/setLocation", 1, &Localization::setloc_callback, this);
171 
172  A = m_field->length();
173  B = m_field->width();
174  E = m_field->goalAreaDepth();
175  F = m_field->goalAreaWidth();
176  G = m_field->penaltyMarkerDist();
177  H = m_field->centerCircleDiameter();
178  D = m_field->goalWidth();
179  I = m_field->boundary();
180  params.ball->radius.set(m_field->ballDiameter() / 2.);
181  A2 = A / 2.;
182  B2 = B / 2.;
183  H2 = H / 2.;
184  A2 = A / 2.;
185  B2 = B / 2.;
186  E2 = E / 2.;
187  F2 = F / 2.;
188  G2 = G / 2.;
189  H2 = H / 2.;
190  D2 = D / 2.;
191  I2 = I / 2.;
192 
193  // TF transforms
194  tfLocField.frame_id_ = "/ego_floor";
195  tfLocField.child_frame_id_ = "/loc_field";
196  tfLocField.setIdentity();
197 
198  lastSavedNodeTime = ros::Time::now();
199  // create the linear solver
200  linearSolver = new LinearSolverCSparse<BlockSolverX::PoseMatrixType>();
201  // create the block solver on the top of the linear solver
202  blockSolver = new BlockSolverX(linearSolver);
203  //create the algorithm to carry out the optimization
204  optimizationAlgorithm = new OptimizationAlgorithmLevenberg(blockSolver);
205  }
206 
207  inline Point2d getOdometryFromLastGet()
208  {
209  if (PreviousVertexId > 0) //Not the first iteration
210  {
211  Point2d res = odomLastGet;
212  odomLastGet.x = odomLastGet.y = 0;
213  return res;
214  }
215  else
216  return Point2d(0, 0);
217  }
218 
219  inline void updateVertexIdx()
220  {
221  if ((ros::Time::now() - lastSavedNodeTime).toSec() >= 0.03)
222  {
223  nodeCounter++;
224  lastSavedNodeTime = ros::Time::now();
225  PreviousVertexId = CurrentVertexId;
226  CurrentVertexId++;
227  if (CurrentVertexId - LandmarkCount >= 100)
228  {
229  CurrentVertexId = LandmarkCount;
230  }
231 
232  {
233  VertexSE2 * r = new VertexSE2;
234  r->setEstimate(Eigen::Vector3d(location.x, location.y, 0));
235  r->setFixed(false);
236  r->setId(CurrentVertexId);
237  if (optimizer.vertex(CurrentVertexId) != NULL)
238  {
239  optimizer.removeVertex(optimizer.vertex(CurrentVertexId));
240  }
241 
242  optimizer.addVertex(r);
243  }
244 
245  {
246  EdgeSE2 * e = new EdgeSE2;
247  e->vertices()[0] = optimizer.vertex(PreviousVertexId);
248  e->vertices()[1] = optimizer.vertex(CurrentVertexId);
249  Point2d dead_reck = getOdometryFromLastGet();
250  e->setMeasurement(SE2(dead_reck.x, dead_reck.y, 0));
251  Matrix3d information;
252  information.fill(0.);
253  information(0, 0) = 200;
254  information(1, 1) = 200;
255  information(2, 2) = 1;
256  e->setInformation(information);
257  optimizer.addEdge(e);
258  }
259  }
260  }
261  inline bool addObservation(Point2d observation, double xFasher,
262  double yFasher, LandmarkType type)
263  {
264 
265  {
266  EdgeSE2 * e = new EdgeSE2;
267 
268  e->vertices()[0] = optimizer.vertex(type);
269  e->vertices()[1] = optimizer.vertex(CurrentVertexId);
270 
271  switch (type)
272  {
273  case RightL:
274  observation.y += B2;
275  break;
276  case FrontL:
277  observation.x -= A2;
278  break;
279  case LeftL:
280  observation.y -= B2;
281  break;
282  case BackL:
283  observation.x += A2;
284  break;
285  default:
286  break;
287  }
288  e->setMeasurement(SE2(observation.x, observation.y, 0));
289  Matrix3d information;
290  information.fill(0.);
291  information(0, 0) = xFasher;
292  information(1, 1) = yFasher;
293  information(2, 2) = 1;
294  e->setInformation(information);
295 
296  g2o::RobustKernelCauchy* rk = new g2o::RobustKernelCauchy;
297  e->setRobustKernel(rk);
298 
299  optimizer.addEdge(e);
300  }
301  atLeastOneObservation = true;
302  return true;
303  }
304 
305  inline Point2f getBall()
306  {
307  return ballPos;
308  }
309 
310  inline void setBall(Point2f _in)
311  {
312  ballPos = _in;
313  }
314 
315  inline void setloc_callback(const geometry_msgs::Point::ConstPtr& msg)
316  {
317  ROS_INFO("Set location received.");
318  location.x = msg->x;
319  location.y = msg->y;
320  locationKalman.x = msg->x;
321  locationKalman.y = msg->y;
322 
323  {
324  boundry_n(location.x, -A2 - I, A2 + I);
325  boundry_n(location.y, -B2 - I, B2 + I);
326  boundry_n(locationKalman.x, -A2 - I, A2 + I);
327  boundry_n(locationKalman.y, -B2 - I, B2 + I);
328  }
329  }
330 
331  inline void setremoteloc_callback(
332  const geometry_msgs::PointStamped::ConstPtr& msg)
333  {
334  this->robotTrackerLoc.x = msg->point.x;
335  this->robotTrackerLoc.y = msg->point.y;
336  this->robotTrackerLoc.z = msg->point.z;
337  }
338 
339  inline void dead_reckoning_callback(const gait_msgs::GaitOdomConstPtr & msg)
340  {
341  if (_cameraProjections == NULL)
342  {
343  return;
344  }
345  Point3d curOdom;
346  curOdom.x = msg->odom2D.x;
347  curOdom.y = msg->odom2D.y;
348  curOdom.z = msg->odom2D.theta;
349 
350  if (lastOdomID == msg->ID)
351  {
352  Point3d diffOdom = curOdom - lastOdom;
353  globalPos += diffOdom;
354  Point2d diffOdom2D(diffOdom.x, diffOdom.y);
355 
356  Point2d diffOdom2DCancelOdomRotation = RotateAroundPoint(diffOdom2D,
357  Radian2Degree(curOdom.z));
358 
359  Point2d diffAbsolut = RotateAroundPoint(
360  diffOdom2DCancelOdomRotation,
361  -Radian2Degree(_cameraProjections->getHeading()));
362  location.x += diffAbsolut.x;
363  location.y += diffAbsolut.y;
364  robotTrackerLoc.x += diffAbsolut.x;
365  robotTrackerLoc.y += diffAbsolut.y;
366  odomLastGet.x += diffAbsolut.x;
367  odomLastGet.y += diffAbsolut.y;
368 
369  robotTrackerLoc.z = _cameraProjections->getHeading();
370  }
371 
372  lastOdom = curOdom;
373  lastOdomID = msg->ID;
374  }
375 
376  inline Point3d GetLocalization()
377  {
378  Point3d res;
379  res.x = location.x;
380  res.y = location.y;
381  res.z = _cameraProjections->getHeading();
382  if (params.loc->useKalman())
383  {
384  res.x = locationKalman.x;
385  res.y = locationKalman.y;
386  }
387  if (params.loc->forwardRobotTrackerXY())
388  {
389  res.x = robotTrackerLoc.x;
390  res.y = robotTrackerLoc.y;
391  }
392  if (params.loc->forwardRobotTrackerZ())
393  {
394  res.z = robotTrackerLoc.z;
395  }
396 
397  return res;
398  }
399  void SendTransform(ros::Time now);
400  bool Calculate(vector<LineSegment> &, bool circleDetected, const Point2f &,
401  const vector<cv::Point2f> &, const Point2d &,
402  const vector<Point2f> &, const bool &confiused,
403  vector<LineContainer> &, vector<FeatureContainer> &);
404 
405  bool Update(CameraProjections &projection);
406  bool Init(string rName);
407  void InitG2OGraph();
408 
409  double A;
410  double B;
411  double E;
412  double F;
413  double G;
414  double H;
415  double D;
416  double I;
417  double A2;
418  double B2;
419  double E2;
420  double F2;
421  double G2;
422  double H2;
423  double D2;
424  double I2;
425 
426 };
A class for Kalman filter.
Definition: Kalman.hpp:11
For pixel projections.
Definition: CameraProjections.hpp:50
A class representing line segments.
Definition: LineSegment.hpp:17
Model of the soccer field.
Definition: field_model.h:73
For localization in the soccer field.
Definition: Localization.hpp:95