polar_match.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  polar_match.cpp - matching laser scans in polar coord system
3  designed for use with SICK LMS in cm res./361 meas. mode
4  only 181 readings (1 deg res) are used (less accuracy but higher
5  speed) - changes made to accomodate other lasers, but not tested properly yet.
6  -------------------
7 begin : Tue Nov 9 2004
8 version : 0.2
9 copyright : (C) 2005,2006,2007,2008,2009 by Albert Diosi and Lindsay Kleeman
10 email : albert.diosi@gmail.com
11 comments : - range units are cm; angle units are deg
12  - don't forget to set the optimization switch!
13  - if it works with float->change fabs-fabsf, floor->floorf
14  - why not add angle as well to the iterative least squares?
15  => bad convergence, error tends to be fixed with rotation
16  - try to make the C - coef for sigmoid function smaller with
17  with the as scanmatching converges, to increase the precision
18  as in dudek
19 changed:
20  05/03/2007- add interpolation to icp
21  04/11/2005- bug fixed in pm_is_corridor. Bug pointed out by Alan Zhang
22  03/08/2005- simple implementation of IDC added not working yet - remove!
23  26/05/2005- projection filter of ICP fixed
24  7/12/2004 - dx,dy estimation interleaved with dth estimation
25  seems to work OK
26  3/12/2004 - iterative range least squares seems to work (for
27  dx,dy only), though it needs to be thoroughly tested
28 
29  26/11/2004
30 
31 edited: (Ivan Dyanovski, ivan.dryanovski@gmail.com)
32 
33  11/08/2010 - removed everything related to visualisation
34  - changed defines to private class members
35  - removed methods and variables not needed for basic
36  matching
37 
38 
39 TODO: change the time measurement approach; do a proper cleanup. have doxygen comments.
40  - Comment colours used when GR is defined.
41  - Document all magic constansts.(pm_psm: change of C after 10 steps)
42 ***************************************************************************/
43 /****************************************************************************
44  This file is part of polar_matching.
45 
46  polar_matching is free software; you can redistribute it and/or modify
47  it under the terms of the GNU General Public License as published by
48  the Free Software Foundation; either version 2 of the License, or
49  (at your option) any later version.
50 
51  polar_matching is distributed in the hope that it will be useful,
52  but WITHOUT ANY WARRANTY; without even the implied warranty of
53  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54  GNU General Public License for more details.
55 
56  You should have received a copy of the GNU General Public License
57  along with polar_matching; if not, write to the Free Software
58  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
59 ****************************************************************************/
60 
62 
63 using namespace std;
64 
66 {
67 
68 }
69 
73 {
74  pm_fi.resize(PM_L_POINTS);
75  pm_si.resize(PM_L_POINTS);
76  pm_co.resize(PM_L_POINTS);
77 
78  PM_FI_MIN = M_PI/2.0 - PM_FOV*PM_D2R/2.0;
79  PM_FI_MAX = M_PI/2.0 + PM_FOV*PM_D2R/2.0;
80  PM_DFI = PM_FOV*PM_D2R/ ( PM_L_POINTS + 1.0 );
81 
82  for ( int i=0;i<PM_L_POINTS;i++ )
83  {
84  pm_fi[i] = ( ( float ) i ) *PM_DFI + PM_FI_MIN;
85  pm_si[i] = sin ( pm_fi[i] );
86  pm_co[i] = cos ( pm_fi[i] );
87  }
88 }//pm_init
89 
90 //-------------------------------------------------------------------------
91 //filters the ranges with a median filter. x,y points are not upadted
92 //ls - laser scan
93 // seems like the median filter is a good thing!
94 //if window is 5, then 3 points are needed in a bunch to surrive!
95 //don't use this function with line fitting!
97 {
98  const int HALF_WINDOW = 2;//2 to left 2 to right
99  const int WINDOW = 2*HALF_WINDOW+1;
100  PM_TYPE r[WINDOW];
101  PM_TYPE w;
102 
103  int i,j,k,l;
104 
105  for ( i=0;i<PM_L_POINTS;i++ )
106  {
107  k=0;
108  for ( j=i-HALF_WINDOW;j<=i+HALF_WINDOW;j++ )
109  {
110  l = ( ( j>=0 ) ?j:0 );
111  r[k]=ls->r[ ( ( l < PM_L_POINTS ) ?l: ( PM_L_POINTS-1 ) ) ];
112  k++;
113  }
114  //bubble sort r
115  for ( j= ( WINDOW-1 );j>0;j-- )
116  for ( k=0;k<j;k++ )
117  if ( r[k]>r[k+1] ) // wrong order? - swap them
118  {
119  w=r[k];
120  r[k]=r[k+1];
121  r[k+1] = w;
122  }
123  ls->r[i] = r[HALF_WINDOW];//choose the middle point
124  }
125 }
126 
127 //-------------------------------------------------------------------------
128 // segments scanpoints into groups based on range discontinuities
129 // number 0 is reserved to segments with size 1
130 // assumptions: too far points PM_MAX_RANGE - divide segments
131 // - bad points are only due to far points and mixed pixels
132 // seems all right, except a far point can be the beginning of a new segment
133 // if the next point is good and close -> it shouldn't make a difference
135 {
136  const PM_TYPE MAX_DIST = 20.0;//max range diff between conseq. points in a seg
137  PM_TYPE dr;
138  int seg_cnt = 0;
139  int i,cnt;
140  bool break_seg;
141 
142  seg_cnt = 1;
143 
144  //init:
145  if ( fabs ( ls->r[0]-ls->r[1] ) <MAX_DIST ) //are they in the same segment?
146  {
147  ls->seg[0] = seg_cnt;
148  ls->seg[1] = seg_cnt;
149  cnt = 2; //2 points in the segment
150  }
151  else
152  {
153  ls->seg[0] = 0; //point is a segment in itself
154  ls->seg[1] = seg_cnt;
155  cnt = 1;
156  }
157 
158  for ( i=2;i<PM_L_POINTS;i++ )
159  {
160  //segment breaking conditions: - bad point;
161  break_seg = false;
162  if ( ls->bad[i] )
163  {
164  break_seg = true;
165  ls->seg[i] = 0;
166  }
167  else
168  {
169  dr = ls->r[i]- ( 2.0*ls->r[i-1]-ls->r[i-2] );//extrapolate & calc difference
170  if ( fabs ( ls->r[i]-ls->r[i-1] ) <MAX_DIST || ( ( ls->seg[i-1]==ls->seg[i-2] )
171  && fabs ( dr ) <MAX_DIST ) )
172  {
173  //not breaking the segment
174  cnt++;
175  ls->seg[i] = seg_cnt;
176  }
177  else
178  break_seg = true;
179  }//if ls
180  if ( break_seg ) // breaking the segment?
181  {
182  if ( cnt==1 )
183  {
184  //check first if the last three are not on a line by coincidence
185  dr = ls->r[i]- ( 2.0*ls->r[i-1]-ls->r[i-2] );
186  if ( ls->seg[i-2] == 0 && ls->bad[i] == 0 && ls->bad[i-1] == 0
187  && ls->bad[i-2] == 0 && fabs ( dr ) <MAX_DIST )
188  {
189  ls->seg[i] = seg_cnt;
190  ls->seg[i-1] = seg_cnt;
191  ls->seg[i-2] = seg_cnt;
192  cnt = 3;
193  }//if ls->
194  else
195  {
196  ls->seg[i-1] = 0;
197  //what if ls[i] is a bad point? - it could be the start of a new
198  //segment if the next point is a good point and is close enough!
199  //in that case it doesn't really matters
200  ls->seg[i] = seg_cnt;//the current point is a new segment
201  cnt = 1;
202  }
203  }//if cnt ==1
204  else
205  {
206  seg_cnt++;
207  ls->seg[i] = seg_cnt;
208  cnt = 1;
209  }//else if cnt
210  }//if break seg
211  }//for
212 }//pm_segment_scan
213 
214 //-------------------------------------------------------------------------
215 // marks point further than a given distance PM_MAX_RANGE as PM_RANGE
217 {
218  for ( int i=0;i<PM_L_POINTS;i++ )
219  {
220  if ( ls->r[i]>PM_MAX_RANGE )
221  ls->bad[i] |= PM_RANGE;
222  }//
223 }
224 
225 //-------------------------------------------------------------------------
226 //calculates an error index expressing the quality of the match
227 //of the actual scan to the reference scan
228 //has to be called after scan matching so the actual scan in expressed
229 //in the reference scan coordinate system
230 //return the average minimum Euclidean distance; MAXIMUM RANGE points
231 //are not considered; number of non maximum range points have to be
232 //smaller than a threshold
233 //actual scan is compared to reference scan and vice versa, maximum is
234 //taken
235 //I could implement it in polar frame as well, would be O(n)
237 {
238  int i,j;
239  PM_TYPE rx[PM_L_POINTS],ry[PM_L_POINTS],ax[PM_L_POINTS],ay[PM_L_POINTS];
240  PM_TYPE x,y;
241  PM_TYPE d,dmin,dsum,dx,dy;
242  PM_TYPE dsum1;
243  int n,n1,rn=0,an=0;
244  const PM_TYPE HUGE_ERROR = 1000000;
245  const int MIN_POINTS = 100;
246 
247  lsa->th = norm_a ( lsa->th );
248  PM_TYPE co = cos ( lsa->th ),si = sin ( lsa->th );
249  PM_TYPE c,sig;
250 
251  //x axis equation si*x-co*y+c=0
252  c = - ( lsa->rx*si-lsa->ry*co );//calc for the x axis of the actual frame
253  //"signum" of a point from the lasers view substituted into the equation
254  sig = si* ( lsa->rx+cos ( lsa->th+0.1 ) )-co* ( lsa->ry+sin ( lsa->th+0.1 ) ) +c;
255 
256  for ( i=0;i<PM_L_POINTS;i++ )
257  {
258  x = lsr->r[i]*pm_co[i];
259  y = lsr->r[i]*pm_si[i];
260  if ( !lsr->bad[i] && sig* ( si*x-co*y+c ) >0 )
261  {
262  rx[rn] = x;
263  ry[rn++] = y;
264  }//if
265  if ( !lsa->bad[i] )
266  {
267  x = lsa->r[i]*pm_co[i];
268  y = lsa->r[i]*pm_si[i];
269  ax[an] = x*co-y*si+lsa->rx;
270  ay[an] = x*si+y*co+lsa->ry;
271  if ( ay[an]>0 )
272  {
273  an++;
274  }
275  }//if
276  }//for i
277 
278  dsum = 0;n=0;
279  for ( i=0;i<an;i++ )
280  {
281  dmin = 10000;
282  for ( j=0;j<rn;j++ )
283  {
284  dx = rx[j]-ax[i];
285  dy = ry[j]-ay[i];
286  d = sqrt ( dx*dx+dy*dy );
287  if ( d<dmin )
288  dmin = d;
289  }//for j
290  if ( dmin<10000 )
291  {
292  n++;
293  dsum+=dmin;
294  }
295  }//for i
296 
297  if ( n>0 )
298  {
299  dsum1 = dsum/ ( PM_TYPE ) n;
300  n1 = n;
301  }
302  else
303  return HUGE_ERROR;
304 
305  //now checking the reference scan agains the actual
306  dsum = 0;n=0;
307  for ( i=0;i<rn;i++ )
308  {
309  dmin = 10000;
310  for ( j=0;j<an;j++ )
311  {
312  dx = rx[i]-ax[j];
313  dy = ry[i]-ay[j];
314  d = sqrt ( dx*dx+dy*dy );
315  if ( d<dmin )
316  dmin = d;
317  }//for j
318  if ( dmin<10000 )
319  {
320  n++;
321  dsum+=dmin;
322  }
323  }//for i
324 
325  if ( n>0 )
326  {
327  dsum = dsum/ ( PM_TYPE ) n;
328  }
329  else
330  return HUGE_ERROR;
331 
332  cout<<"pm_error_index: "<<n1<<" "<<dsum1<<" "<<n<<" "<<dsum<<endl;
333 
334  if ( n1>MIN_POINTS && n>MIN_POINTS )
335  {
336  if ( dsum1>dsum )
337  return dsum1; //return the larger one
338  else
339  return dsum;
340  }
341  return HUGE_ERROR;
342 }
343 
344 //-------------------------------------------------------------------------
345 //estimates the covariance matrix(c11,c12,c22,c33) (x,y,th) of
346 //a scan match based on an error index (err-depends on how good the
347 //match is), and the angle of the corridor if it is a corridor
348 // for non corridors cov matrix is diagonal
349 void PolarMatcher::pm_cov_est ( PM_TYPE err, double *c11,double *c12, double *c22, double *c33,
350  bool corridor, PM_TYPE corr_angle )
351 {
352 #define SQ(x) ((x)*(x))
353  const double cov_x = SQ ( 20 ); //10 // cm
354  const double cov_y = SQ ( 20 );//10 // cm
355  const double cov_th = SQ ( 4.0*M_PI/180.0 ); // 2 deg
356  //for corridors
357  const double cov_along = SQ ( 400 ); // cm
358  const double cov_across = SQ ( 30 ); // cm
359 
360  err = err-5;
361  if ( err<1 )
362  err = 1;
363  if ( corridor ) //was the actual scan taken of a corridor?
364  {
365  double co = cos ( corr_angle );
366  double si = sin ( corr_angle );
367  *c11 = err* ( SQ ( co ) *cov_along+SQ ( si ) *cov_across );
368  *c12 = err* ( -co*si* ( -cov_along+cov_across ) );
369  *c22 = err* ( SQ ( si ) *cov_along+SQ ( co ) *cov_across );
370  *c33 = err*cov_th;
371  }//if
372  else
373  {
374  *c12 = 0;
375  *c11 = err*cov_x;
376  *c22 = err*cov_y;
377  *c33 = err*cov_th;
378  }//else
379 }//pm_cov_est
380 
381 //-------------------------------------------------------------------------
382 // does scan matching using the equations for translation and orietation
383 //estimation as in Lu & milios, however our matching bearing association rule
384 //is used together with our association filter.
385 //have to do an angle search othervise doesn't converge to 0!
386 //weights implemented!
388 {
389 // #define GR //comment out if no graphics necessary
390  PMScan act(PM_L_POINTS), ref(PM_L_POINTS);//copies of actual and reference scans
391  PM_TYPE rx,ry,rth,ax,ay,ath;//robot pos at ref and actual scans
392  PM_TYPE t13,t23;
393  PM_TYPE new_r[PM_L_POINTS];//interpolated r at measurement bearings
394  int new_bad[PM_L_POINTS];//bad flags of the interpolated range readings
395  PM_TYPE C = 70*70;//weighting factor; see dudek00
396  int n = 0;//number of valid points
397  int iter,i,small_corr_cnt=0;
398  PM_TYPE abs_err=0,dx=0,dy=0,dth=0;//match error, actual scan corrections
399 
400  act = *lsa;
401  ref = *lsr;
402 
403  rx = ref.rx; ry = ref.ry; rth = ref.th;
404  ax = act.rx; ay = act.ry; ath = act.th;
405 
406  //transformation of actual scan laser scanner coordinates into reference
407  //laser scanner coordinates
408  t13 = cos(rth) * ax + sin(rth) * ay - sin (rth) * ry - rx * cos(rth);
409  t23 = -sin(rth) * ax + cos(rth) * ay - cos (rth) * ry + rx * sin(rth);
410 
411  ref.rx = 0; ref.ry = 0; ref.th = 0;
412  act.rx = t13; act.ry = t23; act.th = ath-rth;
413 
414  ax = act.rx; ay = act.ry; ath = act.th;
415  //from now on act.rx,.. express the lasers position in the ref frame
416 
417  iter = -1;
418  while ( ++iter<PM_MAX_ITER && small_corr_cnt<3 ) //has to be 5 small corrections before stop
419  {
420  if ( ( fabs ( dx ) +fabs ( dy ) +fabs ( dth ) ) <PM_STOP_COND )
421  small_corr_cnt++;
422  else
423  small_corr_cnt=0;
424 
425  act.rx = ax;act.ry = ay;act.th = ath;
426  // convert range readings into ref frame
427  pm_scan_project(&act, new_r, new_bad);
428 
429  //---------------ORIENTATION SEARCH-----------------------------------
430  //search for angle correction using crosscorrelation
431  if ( iter%4 ==3 ) //(iter%2==1)
432  {
433  dth = pm_orientation_search(&ref, new_r, new_bad);
434  ath += dth;
435  continue;
436  }
437 
438  //------------------------------------------translation-------------
439  if ( iter>10 )
440  C = 100;
441 
442  // do the weighted linear regression on the linearized ...
443  // include angle as well
444  PM_TYPE dr;
445 
446  //computation of the new dx1,dy1,dtheta1
447  PM_TYPE X=0,Y=0,Xp=0,Yp=0,W=0,w;
448  PM_TYPE sxx=0,sxy=0,syx=0, syy=0;
449  PM_TYPE meanpx,meanpy,meanppx,meanppy;
450  meanpx = 0;meanpy = 0;
451  meanppx= 0;meanppy= 0;
452 
453  abs_err=0;
454  n=0;
455  for ( i=0;i<PM_L_POINTS;i++ )
456  {
457  dr = ref.r[i]-new_r[i];
458  abs_err += fabs ( dr );
459  //weight calculation
460  if ( ref.bad[i]==0 && new_bad[i]==0 && new_r[i]<PM_MAX_RANGE && new_r[i]>10.0 && fabs ( dr ) <PM_MAX_ERROR )
461  {
462  // do the cartesian calculations....
463 
464  PM_TYPE x,y,xp,yp;
465  x = new_r[i]*pm_co[i];//actual
466  y = new_r[i]*pm_si[i];
467  xp = ref.r[i]*pm_co[i]; //could speed up this..
468  yp = ref.r[i]*pm_si[i];//reference
469 
470  w = C/ ( dr*dr+C );
471 
472  W += w;
473  X += w*x;
474  Y += w*y;
475  Xp+= w*xp;
476  Yp+= w*yp;
477 
478  sxx += w*xp*x;
479  sxy += w*xp*y;
480  syx += w*yp*x;
481  syy += w*yp*y;
482 
483  n++;
484  }
485  }//for
486  if (n < PM_MIN_VALID_POINTS || W < 0.01 ) //are there enough points?
487  {
488  cerr <<"pm_linearized_match: ERROR not enough points " << n << " " << W << endl;
489  throw 1;//not enough points
490  }
491 
492  dth = atan2 ( - ( X*Yp - Y*Xp + W* ( sxy-syx ) ),- ( X*Xp+Y*Yp-W* ( sxx+syy ) ) );
493  dx = ( Xp-X*cos ( dth ) +Y*sin ( dth ) ) /W;
494  dy = ( Yp-X*sin ( dth )-Y*cos ( dth ) ) /W;
495 
496  //correction thanks to Alan Zhang:
497  PM_TYPE ax_old,ay_old;
498  ax_old = ax;
499  ay_old = ay;
500 
501  ax = cos ( dth ) *ax_old - sin ( dth ) *ay_old + dx;
502  ay = sin ( dth ) *ax_old + cos ( dth ) *ay_old + dy;
503  ath+= dth;
504 
505  dth *=PM_R2D;
506  }//for iter
507 
508  lsa->rx =ax;lsa->ry=ay;lsa->th=ath;
509  return ( abs_err/n );
510 }//pm_psm_c
511 
512 //-------------------------------------------------------------------------
513 // minimizes least square error through changing lsa->rx, lsa->ry,lsa->th
514 // this looks for angle too, like pm_linearized_match_proper,execept it
515 // fits a parabola to the error when searching for the angle and interpolates.
517 {
518  PMScan act(PM_L_POINTS), ref(PM_L_POINTS);//copies of actual and reference scans
519  PM_TYPE rx,ry,rth,ax,ay,ath;//robot pos at ref and actual scans
520  PM_TYPE t13,t23;
521  PM_TYPE new_r[PM_L_POINTS];//interpolated r at measurement bearings
522  int new_bad[PM_L_POINTS];//bad flags of the interpolated range readings
523  PM_TYPE C = 70*70;//weighting factor; see dudek00
524  int iter,small_corr_cnt=0;
525  PM_TYPE dx=0,dy=0,dth=0;//match error, actual scan corrections
526  PM_TYPE avg_err = 100000000.0;
527 
528  act = *lsa;
529  ref = *lsr;
530 
531  rx = ref.rx; ry = ref.ry; rth = ref.th;
532  ax = act.rx; ay = act.ry; ath = act.th;
533 
534  //transformation of actual scan laser scanner coordinates into reference
535  //laser scanner coordinates
536  t13 = cos(rth) * ax + sin(rth) * ay-sin (rth) * ry - rx * cos (rth);
537  t23 = -sin(rth) * ax + cos(rth) * ay-cos (rth) * ry + rx * sin (rth);
538 
539  ref.rx = 0; ref.ry = 0; ref.th = 0;
540  act.rx = t13; act.ry = t23; act.th = ath-rth;
541 
542  ax = act.rx; ay = act.ry; ath = act.th;
543  //from now on act.rx,.. express the lasers position in the ref frame
544 
545  iter = -1;
546  while ( ++iter<PM_MAX_ITER && small_corr_cnt<3 ) //has to be 5 small corrections before stop
547  {
548  if ( ( fabs ( dx ) +fabs ( dy ) +fabs ( dth ) ) <PM_STOP_COND )
549  small_corr_cnt++;
550  else
551  small_corr_cnt=0;
552 
553  act.rx = ax;act.ry = ay;act.th = ath;
554  pm_scan_project(&act, new_r, new_bad);
555 
556  //---------------ORIENTATION SEARCH-----------------------------------
557  //search for angle correction using crosscorrelation
558  if ( iter%2 ==1 )
559  {
560  dth = pm_orientation_search(&ref, new_r, new_bad);
561  ath += dth;
562  continue;
563  }
564 
565  //------------------------------------------translation-------------
566  //reduce C with time to consider only the best matches
567  if ( iter>10 )
568  C = 100;
569 
570  avg_err = pm_translation_estimation(&ref, new_r, new_bad, C, &dx, &dy);
571 
572  ax += dx;
573  ay += dy;
574 
575 // //for SIMULATION iteration results..
576 
577  }//while iter
578 
579  lsa->rx =ax;lsa->ry=ay;lsa->th=ath;
580  return ( avg_err);
581 }//pm_linearized_match_int_angle
582 
583 //-------------------------------------------------------------------------
584 //calculate distance of the point (x3,y3) from a line (defined by (x1,y1)
585 //and (x2,y2)). Returns the distance to the line or -1 if the
586 //projection of (x3,y3) falls outside the line segment defined by (x1,y1)
587 //and (x2,y2).
588 //The projection of (x3,y3) onto the line is also returned in x,y
590  PM_TYPE x3, PM_TYPE y3,PM_TYPE *x, PM_TYPE *y )
591 {
592  PM_TYPE ax,ay,t1,D;
593  ax = x2-x1;
594  ay = y2-y1;
595  D = sqrt ( ax*ax+ay*ay );
596  if ( D <0.0001 )
597  {
598  cerr <<"point_line_distance: unexpected D:" <<D<<endl;
599  return -1;
600  }
601  t1 = - ( -ax*x3 + ay*y1 + ax*x1 - ay*y3 ) / ( ax*ax+ay*ay );
602  if ( t1<0 || t1>1 ) // projection falls outside the line segment
603  {
604  return -1;
605  }
606  *x = x1+t1*ax;
607  *y = y1+t1*ay;
608  return ( sqrt ( ( x3-*x ) * ( x3-*x ) + ( y3-*y ) * ( y3-*y ) ) );//distance of line to p.
609 }// point_line_distance
610 
611 //-------------------------------------------------------------------------
615 void PolarMatcher::pm_scan_project(const PMScan *act, PM_TYPE *new_r, int *new_bad)
616 {
617  PM_TYPE r[PM_L_POINTS],fi[PM_L_POINTS];//actual scan in ref. coord. syst.
618  PM_TYPE x,y;
619  int i;
620  PM_TYPE delta;
621 
622  // convert range readings into ref frame
623  // this can be speeded up, by connecting it with the interpolation
624  for ( i=0;i<PM_L_POINTS;i++ )
625  {
626  delta = act->th + pm_fi[i];
627  x = act->r[i]*cos ( delta ) + act->rx;
628  y = act->r[i]*sin ( delta ) + act->ry;
629  r[i] = sqrt ( x*x+y*y );
630  fi[i] = atan2 ( y,x );
631  //handle discontinuity at pi
632  if(x<0 && y<0)
633  fi[i] += 2.0*M_PI;
634 
635  new_r[i] = 10000;//initialize big interpolated r;
636  new_bad[i]= PM_EMPTY;//for interpolated r;
637 
638  }//for i
639 
640  //------------------------INTERPOLATION------------------------
641  //calculate/interpolate the associations to the ref scan points
642  //algorithm ignores crosings at 0 and 180 -> to make it faster
643  for ( i=1;i<PM_L_POINTS;i++ )
644  {
645  //i points to the angles in the actual scan
646 
647  // i and i-1 has to be in the same segment, both shouldn't be bad
648  // and they should be larger than the minimum angle
649  if ( act->seg[i] != 0 && act->seg[i] == act->seg[i-1] && !act->bad[i] &&
650  !act->bad[i-1] /* && fi[i]>PM_FI_MIN && fi[i-1]>PM_FI_MIN*/ )
651  {
652  //calculation of the "whole" parts of the angles
653  int j0,j1;
654  PM_TYPE r0,r1,a0,a1;
655  bool occluded;
656  if ( fi[i]>fi[i-1] ) //are the points visible?
657  {
658  //visible
659  occluded = false;
660  a0 = fi[i-1];
661  a1 = fi[i];
662 
663  j0 = (int) ceil ( ( fi[i-1] - PM_FI_MIN ) /PM_DFI );
664  j1 = (int) floor ( ( fi[i] - PM_FI_MIN ) /PM_DFI );
665  r0 = r[i-1];
666  r1 = r[i];
667  }
668  else
669  {
670  //invisible - still have to calculate to filter out points which
671  occluded = true; //are covered up by these!
672  //flip the points-> easier to program
673  a0 = fi[i];
674  a1 = fi[i-1];
675 
676  j0 = (int) ceil ( ( fi[i] - PM_FI_MIN ) /PM_DFI );
677  j1 = (int) floor ( ( fi[i-1] - PM_FI_MIN ) /PM_DFI );
678  r0 = r[i];
679  r1 = r[i-1];
680  }
681  //here fi0 is always smaller than fi1!
682 
683  //interpolate for all the measurement bearings beween fi0 and fi1
684  while ( j0<=j1 ) //if at least one measurement point difference, then ...
685  {
686  // cout <<( ( PM_TYPE ) j0*PM_DFI )<<" "<<( ( ( PM_TYPE ) j0*PM_DFI +PM_FI_MIN )-a0 )<<endl;
687  PM_TYPE ri = ( r1-r0 ) / ( a1-a0 ) * ( ( ( PM_TYPE ) j0*PM_DFI+PM_FI_MIN )-a0 ) +r0;
688 
689  //if fi0 -> falls into the measurement range and ri is shorter
690  //than the current range then overwrite it
691  if ( j0>=0 && j0<PM_L_POINTS && new_r[j0]>ri )
692  {
693  new_r[j0] = ri;//overwrite the previous reading
694  new_bad[j0] &=~PM_EMPTY;//clear the empty flag
695  if ( occluded ) //check if it was occluded
696  new_bad[j0] = new_bad[j0]|PM_OCCLUDED;//set the occluded flag
697  else
698  new_bad[j0] = new_bad[j0]&~PM_OCCLUDED;
699  //the new range reading also it has to inherit the other flags
700  new_bad[j0] |= act->bad[i];//superfluos - since act.bad[i] was checked for 0
701  new_bad[j0] |= act->bad[i-1];//superfluos - since act.bad[i-1] was checked for 0
702 
703  }
704  j0++;//check the next measurement angle!
705  }//while
706  }//if act
707  }//for i
708 }//pm_scan_project
709 
710 //-------------------------------------------------------------------------
718 PM_TYPE PolarMatcher::pm_orientation_search(const PMScan *ref, const PM_TYPE *new_r, const int *new_bad)
719 {
720  int i;
721  int window = PM_SEARCH_WINDOW;//20;//+- width of search for correct orientation
722  PM_TYPE dth=0;//\actual scan corrections
723 
724  //pm_fi,ref.r - reference points
725  PM_TYPE e,err[PM_L_POINTS]; // the error rating
726  PM_TYPE beta[PM_L_POINTS];// angle for the corresponding error
727  PM_TYPE n;
728  int k=0;
729 
730  for ( int di=-window;di<=window;di++ )
731  {
732  n=0;e=0;
733 
734  int min_i,max_i;
735  if ( di<=0 )
736  {min_i = -di;max_i=PM_L_POINTS;}
737  else
738  {min_i = 0;max_i=PM_L_POINTS-di;}
739 
740  for ( i=min_i;i<max_i;i++ ) //searching through the actual points
741  {
742  //if fi[i],r[i] isn't viewed from the back, isn't moving
743  // and isn't a solitary point, then try to associate it ..
744  //also fi[i] is within the angle range ...
745 
746  if ( !new_bad[i] && !ref->bad[i+di] )
747  {
748  e += fabs ( new_r[i]-ref->r[i+di] );
749  n++;
750  }
751 
752  }//for i
753 
754  if ( n>0 )
755  err[k] = e/n;//don't forget to correct with n!
756  else
757  err[k] = 10000;//don't forget to correct with n!
758  beta[k] = di;
759  k++;
760  }//for dfi
761 
762  //now search for the global minimum
763  //later I can make it more robust
764  //assumption: monomodal error function!
765  PM_TYPE emin = 1000000;
766  int imin;
767  for ( i=0;i<k;i++ )
768  if ( err[i]<emin )
769  {
770  emin = err[i];
771  imin = i;
772  }
773  if ( err[imin]>=10000 )
774  {
775  cerr <<"Polar Match: orientation search failed" <<err[imin]<<endl;
776  throw 1;
777  }
778  dth = beta[imin]*PM_DFI;
779 
780  //interpolation
781  if ( imin>=1 && imin< ( k-1 ) ) //is it not on the extreme?
782  {
783  //lets try interpolation
784  PM_TYPE D = err[imin-1]+err[imin+1]-2.0*err[imin];
785  PM_TYPE d=1000;
786  if ( fabs ( D ) >0.01 && err[imin-1]>err[imin] && err[imin+1]>err[imin] )
787  d= ( err[imin-1]-err[imin+1] ) /D/2.0;
788 
789  if ( fabs ( d ) <1 )
790  dth+=d*PM_DFI;
791  }//if
792 
793  return(dth);
794 }//pm_orientation_search
795 
796 PM_TYPE PolarMatcher::pm_translation_estimation(const PMScan *ref, const PM_TYPE *new_r, const int *new_bad, PM_TYPE C, PM_TYPE *dx, PM_TYPE *dy)
797 {
798  // do the weighted linear regression on the linearized ...
799  // include angle as well
800  int i;
801  PM_TYPE hi1, hi2,hwi1,hwi2, hw1=0,hw2=0,hwh11=0;
802  PM_TYPE hwh12=0,hwh21=0,hwh22=0,w;
803  PM_TYPE dr;
804  PM_TYPE abs_err = 0;
805  int n = 0;
806  for ( i=0;i<PM_L_POINTS;i++ )
807  {
808  dr = ref->r[i]-new_r[i];
809  abs_err += fabs ( dr );
810 
811  //weight calculation
812  if (ref->bad[i] == 0 &&
813  new_bad[i] == 0 &&
814  new_r[i] < PM_MAX_RANGE &&
815  new_r[i] > 10.0 &&
816  fabs(dr) < PM_MAX_ERROR )
817  {
818  //weighting according to DUDEK00
819 
820  w = C / (dr*dr + C);
821  n++;
822 
823  //proper calculations of the jacobian
824  hi1 = pm_co[i];//xx/new_r[i];//this the correct
825  hi2 = pm_si[i];//yy/new_r[i];
826 
827  hwi1 = hi1*w;
828  hwi2 = hi2*w;
829 
830  //par = (H^t*W*H)^-1*H^t*W*dr
831  hw1 += hwi1*dr;//H^t*W*dr
832  hw2 += hwi2*dr;
833 
834  //H^t*W*H
835  hwh11 += hwi1*hi1;
836  hwh12 += hwi1*hi2;
837  hwh21 += hwi2*hi1; //should take adv. of symmetricity!!
838  hwh22 += hwi2*hi2;
839  }
840  else
841  {
842 /*
843  if (ref->bad[i] != 0) printf("rb ");
844  if (new_bad[i] != 0) printf("nb ");
845  if (new_r[i] < PM_MAX_RANGE) printf("MR ");
846  if (fabs(dr) < PM_MAX_ERROR) printf("ME ");
847  printf(".\n");
848  */
849  }
850  }//for i
851  if ( n<PM_MIN_VALID_POINTS ) //are there enough points?
852  {
853  cerr <<"(i) pm_translation_estimation: ERROR not enough points" << n <<endl;
854  throw 1;//not enough points
855  }
856 
857  //calculation of inverse
858  PM_TYPE D;//determinant
859  PM_TYPE inv11,inv21,inv12,inv22;//inverse matrix
860 
861  D = hwh11*hwh22-hwh12*hwh21;
862  if ( D<0.001 )
863  {
864  cerr <<"pm_linearized_match: ERROR determinant to small! "<<D<<endl;
865  throw 1;
866  }
867  inv11 = hwh22/D;
868  inv12 = -hwh12/D;
869  inv21 = -hwh12/D;
870  inv22 = hwh11/D;
871 
872  *dx = inv11*hw1+inv12*hw2;
873  *dy = inv21*hw1+inv22*hw2;
874  return(abs_err/n);
875 }//pm_translation_estimation
876 
d
#define SQ(x)
PM_TYPE pm_psm(PMScan *lsr, PMScan *lsa)
void pm_init()
Initialises internar variables.
Definition: polar_match.cpp:72
void pm_median_filter(PMScan *ls)
Definition: polar_match.cpp:96
void pm_scan_project(const PMScan *act, PM_TYPE *new_r, int *new_bad)
std::vector< int > bad
Definition: polar_match.h:87
void pm_segment_scan(PMScan *ls)
PM_TYPE pm_orientation_search(const PMScan *ref, const PM_TYPE *new_r, const int *new_bad)
#define PM_EMPTY
Definition: polar_match.h:53
const double PM_R2D
Definition: polar_match.h:65
std::vector< int > seg
Definition: polar_match.h:90
TFSIMD_FORCE_INLINE const tfScalar & y() const
PM_TYPE ry
Definition: polar_match.h:82
const double PM_D2R
Definition: polar_match.h:64
void pm_find_far_points(PMScan *ls)
#define PM_OCCLUDED
Definition: polar_match.h:52
std::vector< PM_TYPE > r
Definition: polar_match.h:84
PM_TYPE pm_error_index(PMScan *lsr, PMScan *lsa)
void pm_cov_est(PM_TYPE err, double *c11, double *c12, double *c22, double *c33, bool corridor=false, PM_TYPE corr_angle=0)
PolarMatcher()
stopping condition; the pose change has to be smaller than ... for ICP, MBICP
Definition: polar_match.cpp:65
TFSIMD_FORCE_INLINE const tfScalar & x() const
#define PM_RANGE
Definition: polar_match.h:49
PM_TYPE pm_translation_estimation(const PMScan *ref, const PM_TYPE *new_r, const int *new_bad, PM_TYPE C, PM_TYPE *dx, PM_TYPE *dy)
PM_TYPE rx
Definition: polar_match.h:81
TFSIMD_FORCE_INLINE const tfScalar & w() const
PM_TYPE th
Definition: polar_match.h:83
#define PM_TYPE
Definition: polar_match.h:46
PM_TYPE point_line_distance(PM_TYPE x1, PM_TYPE y1, PM_TYPE x2, PM_TYPE y2, PM_TYPE x3, PM_TYPE y3, PM_TYPE *x, PM_TYPE *y)
PM_TYPE pm_psm_c(PMScan *lsr, PMScan *lsa)


polar_scan_matcher
Author(s): Ivan Dryanovski
autogenerated on Mon Jun 10 2019 15:08:51