00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include <iostream>
00047
00048 #include <math.h>
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <assert.h>
00052
00053 #ifdef __linux__
00054 #include <time.h>
00055 #endif
00056
00057 #include "polar_match.h"
00058
00059
00060
00061 using namespace std;
00062
00063
00064
00065 PM_TYPE pm_fi[PM_L_POINTS];
00066 PM_TYPE pm_si[PM_L_POINTS];
00067 PM_TYPE pm_co[PM_L_POINTS];
00068 const PM_TYPE PM_D2R = M_PI/180.0;
00069 const PM_TYPE PM_R2D = 180.0/M_PI;
00070 const PM_TYPE PM_FI_MIN = M_PI/2.0 - PM_FOV*PM_D2R/2.0;
00071 const PM_TYPE PM_FI_MAX = M_PI/2.0 + PM_FOV*PM_D2R/2.0;
00072 const PM_TYPE PM_DFI = PM_FOV*PM_D2R/ ( PM_L_POINTS + 1.0 );
00073
00074 void pm_scan_project(const PMScan *act, PM_TYPE *new_r, int *new_bad);
00075 PM_TYPE pm_orientation_search(const PMScan *ref, const PM_TYPE *new_r, const int *new_bad);
00076 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);
00077
00082 double pm_msec(void)
00083 {
00084 #ifdef __linux__
00085 timespec tp;
00086 double time;
00087 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp);
00088 time = tp.tv_sec*1000.0 + ((double)tp.tv_nsec)/1000000.0;
00089 return time;
00090 #else
00091 return -1.0;
00092 #endif
00093 }
00094
00102 inline PM_TYPE norm_a ( PM_TYPE a )
00103 {
00104 int m;
00105 m = (int) ( a / ( 2.0*M_PI ) );
00106 a = a - (PM_TYPE)m * M_PI;
00107 if ( a < (-M_PI) )
00108 a += 2.0*M_PI;
00109 if ( a >= M_PI )
00110 a -= 2.0*M_PI;
00111 return ( a );
00112 }
00113
00126 void pm_init ( const char* filename, FILE **fin )
00127 {
00128 printf("Initializing polar scan matching for: %s\n",PM_LASER_NAME);
00129 size_t len=2000;
00130 char *line;
00131 line = new char[len];
00132 if(fin != NULL)
00133 {
00134 *fin = NULL;
00135 }
00136
00137 if(filename != NULL)
00138 {
00139 *fin=fopen ( filename,"rt" );
00140 if ( *fin==NULL )
00141 {
00142 cerr <<"pm_init: unable to open file:"<<filename<<endl;
00143 throw 1;
00144 }
00145 int ret;
00146 ret = getline ( &line,&len,*fin );
00147 if(ret<0)
00148 perror("get line");
00149
00150 cout <<line<<endl;
00151 delete[] line;
00152 }
00153
00154 for ( int i=0;i<PM_L_POINTS;i++ )
00155 {
00156 pm_fi[i] = ( ( float ) i ) *PM_DFI + PM_FI_MIN;
00157 pm_si[i] = sinf ( pm_fi[i] );
00158 pm_co[i] = cosf ( pm_fi[i] );
00159 }
00160 }
00161
00162
00163
00177 int pm_readScan ( FILE *fin, PMScan *ls )
00178 {
00179 int n=0;
00180 n+=fscanf ( fin,"%lf %lf %lf %lf\n",& ( ls->t ),& ( ls->rx ),& ( ls->ry ),& ( ls->th ) );
00181 ls->t -=PM_TIME_DELAY;
00182 ls->rx *=100.0;
00183 ls->ry *=100.0;
00184 ls->th = norm_a ( ls->th-M_PI/2.0 );
00185
00186 for ( int i=0; i<PM_L_POINTS; i++ )
00187 {
00188 n+=fscanf ( fin,"%lf\n",& ( ls->r[i] ) );
00189 ls->x[i] = ( ls->r[i] ) *pm_co[i];
00190 ls->y[i] = ( ls->r[i] ) *pm_si[i];
00191 ls->bad[i] = 0;
00192
00193 if(i!=(PM_L_POINTS-1))
00194 {
00195 PM_TYPE dummy;
00196 int ret;
00197 ret= fscanf ( fin,"%lf\n",& dummy);
00198 if(ret<0)
00199 perror("fscanf");
00200 }
00201 }
00202 if ( n!= ( PM_L_POINTS+4 ) )
00203 return -1;
00204 return 0;
00205 }
00206
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00265
00266
00267
00268
00269
00270
00288 void pm_median_filter ( PMScan *ls )
00289 {
00290 const int HALF_WINDOW = 2;
00291 const int WINDOW = 2*HALF_WINDOW+1;
00292 PM_TYPE r[WINDOW];
00293 PM_TYPE w;
00294
00295 int i,j,k,l;
00296
00297 for ( i=0;i<PM_L_POINTS;i++ )
00298 {
00299 k=0;
00300 for ( j=i-HALF_WINDOW;j<=i+HALF_WINDOW;j++ )
00301 {
00302 l = ( ( j>=0 ) ?j:0 );
00303 r[k]=ls->r[ ( ( l < PM_L_POINTS ) ?l: ( PM_L_POINTS-1 ) ) ];
00304 k++;
00305 }
00306
00307 for ( j= ( WINDOW-1 );j>0;j-- )
00308 for ( k=0;k<j;k++ )
00309 if ( r[k]>r[k+1] )
00310 {
00311 w=r[k];
00312 r[k]=r[k+1];
00313 r[k+1] = w;
00314 }
00315 ls->r[i] = r[HALF_WINDOW];
00316 }
00317 }
00318
00319
00333 void pm_segment_scan ( PMScan *ls )
00334 {
00335 const PM_TYPE MAX_DIST = PM_SEG_MAX_DIST;
00336 PM_TYPE dr;
00337 int seg_cnt = 0;
00338 int i,cnt;
00339 bool break_seg;
00340
00341 seg_cnt = 1;
00342
00343
00344 if ( fabsf ( ls->r[0]-ls->r[1] ) < MAX_DIST )
00345 {
00346 ls->seg[0] = seg_cnt;
00347 ls->seg[1] = seg_cnt;
00348 cnt = 2;
00349 }
00350 else
00351 {
00352 ls->seg[0] = 0;
00353 ls->seg[1] = seg_cnt;
00354 cnt = 1;
00355 }
00356
00357 for ( i=2;i<PM_L_POINTS;i++ )
00358 {
00359
00360 break_seg = false;
00361 if ( ls->bad[i] )
00362 {
00363 break_seg = true;
00364 ls->seg[i] = 0;
00365 }
00366 else
00367 {
00368 dr = ls->r[i]- ( 2.0*ls->r[i-1] - ls->r[i-2] );
00369
00370
00371 if ( fabsf ( ls->r[i]-ls->r[i-1] ) < MAX_DIST ||
00372 ( ( ls->seg[i-1]==ls->seg[i-2] ) && fabsf ( dr ) <MAX_DIST ) )
00373 {
00374
00375 cnt++;
00376 ls->seg[i] = seg_cnt;
00377 }
00378 else
00379 break_seg = true;
00380 }
00381
00382 if ( break_seg )
00383 {
00384 if ( cnt==1 )
00385 {
00386
00387 dr = ls->r[i]- ( 2.0*ls->r[i-1]-ls->r[i-2] );
00388 if ( ls->seg[i-2] == 0 && ls->bad[i] == 0 && ls->bad[i-1] == 0
00389 && ls->bad[i-2] == 0 && fabsf ( dr ) <MAX_DIST )
00390 {
00391 ls->seg[i] = seg_cnt;
00392 ls->seg[i-1] = seg_cnt;
00393 ls->seg[i-2] = seg_cnt;
00394 cnt = 3;
00395 }
00396 else
00397 {
00398 ls->seg[i-1] = 0;
00399
00400
00401
00402 ls->seg[i] = seg_cnt;
00403 cnt = 1;
00404 }
00405 }
00406 else
00407 {
00408 seg_cnt++;
00409 ls->seg[i] = seg_cnt;
00410 cnt = 1;
00411 }
00412 }
00413 }
00414 }
00415
00421 void pm_find_far_points ( PMScan *ls )
00422 {
00423 for ( int i=0;i<PM_L_POINTS;i++ )
00424 {
00425 if ( ls->r[i]>PM_MAX_RANGE )
00426 ls->bad[i] |= PM_RANGE;
00427 }
00428 }
00429
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00482 void pm_preprocessScan(PMScan *ls)
00483 {
00484 pm_median_filter(ls);
00485 pm_find_far_points(ls);
00486 pm_segment_scan(ls);
00487 }
00488
00513 bool pm_is_corridor ( PMScan *act )
00514 {
00515 PM_TYPE fi1=0,fi2=0,fi3=0;
00516 PM_TYPE sxx=0,sx=0,std1,std2;
00517 PM_TYPE n=0;
00518
00519 for ( int i=0;i< ( PM_L_POINTS-1 );i++ )
00520 {
00521 if ( act->seg[i]==act->seg[i+1] && act->seg[i]!=0 && !act->bad[i] )
00522 {
00523 PM_TYPE x,y,x1,y1,fi;
00524 x = act->r[i]*pm_co[i];
00525 y = act->r[i]*pm_si[i];
00526 x1 = act->r[i+1]*pm_co[i+1];
00527 y1 = act->r[i+1]*pm_si[i+1];
00528 fi = atan2f ( y1-y, x1-x ) * PM_R2D;
00529
00530 if ( fi<0 )
00531 fi+=180.0;
00532 if ( i==0 )
00533 {
00534 fi1 = fi;fi2 = fi;fi3 = fi;
00535 }
00536
00537 fi3=fi2;
00538 fi2=fi1;
00539 fi1=fi;
00540
00541 if ( fi1<=fi2 && fi2<=fi3 )
00542 fi = fi2;
00543 if ( fi2<=fi3 && fi3<=fi1 )
00544 fi = fi3;
00545 if ( fi3<=fi1 && fi1<=fi2 )
00546 fi = fi1;
00547
00548 sx += fi;
00549 sxx += fi*fi;
00550 n += 1.0;
00551 }
00552 }
00553 if ( n>1 )
00554 {
00555 PM_TYPE var = ( sxx-sx*sx/n ) / ( n-1.0 );
00556 if(var > 0)
00557 {
00558 std1 = sqrtf ( var );
00559 }
00560 else
00561 {
00562 std1 = 0;
00563 }
00564 }
00565 else
00566 {
00567 cerr<<"pm_is_corridor: ERROR n<=1"<<endl;
00568 throw 3;
00569 }
00570
00571
00572 sxx = 0;n=0;sx=0;
00573 for ( int i=0;i< ( PM_L_POINTS-1 );i++ )
00574 {
00575 if ( act->seg[i]==act->seg[i+1] && act->seg[i]!=0 && !act->bad[i] )
00576 {
00577 PM_TYPE x,y,x1,y1,fi;
00578 x = act->r[i]*cosf ( pm_fi[i]+M_PI/5.0 );
00579 y = act->r[i]*sinf ( pm_fi[i]+M_PI/5.0 );
00580 x1 = act->r[i+1]*cosf ( pm_fi[i+1]+M_PI/5.0 );
00581 y1 = act->r[i+1]*sinf ( pm_fi[i+1]+M_PI/5.0 );
00582 fi = atan2f ( y1-y,x1-x ) *PM_R2D;
00583
00584 if ( fi<0 )
00585 fi+=180.0;
00586 if ( i==0 )
00587 {
00588 fi1 = fi;fi2 = fi;fi3 = fi;
00589 }
00590 fi1=fi;
00591 fi2=fi1;
00592 fi3=fi2;
00593
00594 if ( fi1<=fi2 && fi2<=fi3 )
00595 fi = fi2;
00596 if ( fi2<=fi3 && fi3<=fi1 )
00597 fi = fi3;
00598 if ( fi3<=fi1 && fi1<=fi2 )
00599 fi = fi1;
00600
00601 sx+=fi;
00602 sxx+=fi*fi;
00603 n+=1.0;
00604 }
00605 }
00606
00607 if ( n>1 )
00608 {
00609 PM_TYPE var = ( sxx-sx*sx/n ) / ( n-1.0 );
00610 if(var > 0)
00611 {
00612 std2 = sqrtf ( var );
00613 }
00614 else
00615 {
00616 std2 = 0;
00617 }
00618 }
00619 else
00620 {
00621 cerr<<"pm_is_corridor: ERROR n<=1"<<endl;
00622 throw 2;
00623 }
00624
00625
00626 PM_TYPE st;
00627 if ( std1 < std2 )
00628 st = std1;
00629 else
00630 st = std2;
00631 if ( st < PM_CORRIDOR_THRESHOLD)
00632 {
00633
00634 return true;
00635 }
00636 else
00637 {
00638
00639 return false;
00640 }
00641 }
00642
00643
00667 PM_TYPE pm_error_index ( PMScan *lsr,PMScan *lsa )
00668 {
00669 int i,j;
00670 PM_TYPE rx[PM_L_POINTS],ry[PM_L_POINTS],ax[PM_L_POINTS],ay[PM_L_POINTS];
00671 PM_TYPE x,y;
00672 PM_TYPE d,dmin,dsum,dx,dy;
00673 PM_TYPE dsum1;
00674 int n,n1,rn=0,an=0;
00675 const PM_TYPE HUGE_ERROR = 1000000;
00676 const PM_TYPE DISTANCE_TRESHOLD = PM_MAX_RANGE / 2;
00677 const int MIN_POINTS = PM_MIN_VALID_POINTS;
00678
00679 lsa->th = norm_a ( lsa->th );
00680 PM_TYPE co = cosf ( lsa->th );
00681 PM_TYPE si = sinf ( lsa->th );
00682
00683
00684
00685
00686 int index360 = ( (PM_L_POINTS-1) * 360)/ PM_FOV;
00687 int indexIncrement = (lsa->th * PM_R2D * (PM_L_POINTS-1)) / PM_FOV;
00688
00689 for ( i=0;i<PM_L_POINTS;i++ )
00690 {
00691
00692
00693 if ( !lsr->bad[i] )
00694 {
00695
00696 int j = (i - indexIncrement + index360) % index360;
00697 assert( (i - indexIncrement + index360) >=0);
00698
00699
00700 if( (j >= 0) && (j < PM_L_POINTS))
00701 {
00702 rx[rn] = lsr->r[i]*pm_co[i];
00703 ry[rn] = lsr->r[i]*pm_si[i];
00704
00705 rn++;
00706 }
00707 }
00708 }
00709
00710
00711 for ( i=0;i<PM_L_POINTS;i++ )
00712 {
00713 if ( !lsa->bad[i] )
00714 {
00715 int j = (i + indexIncrement + index360) % index360;
00716 assert( (i + indexIncrement + index360) >=0);
00717
00718 if( (j >= 0) && (j < PM_L_POINTS))
00719 {
00720 x = lsa->r[i]*pm_co[i];
00721 y = lsa->r[i]*pm_si[i];
00722
00723 ax[an] = x*co-y*si+lsa->rx;
00724 ay[an] = x*si+y*co+lsa->ry;
00725
00726 an++;
00727 }
00728 }
00729 }
00730
00731
00732 dsum = 0;n=0;
00733 for ( i=0;i<an;i++ )
00734 {
00735 dmin = HUGE_ERROR;
00736 for ( j=0;j<rn;j++ )
00737 {
00738 dx = rx[j]-ax[i];
00739 dy = ry[j]-ay[i];
00740 d = sqrtf ( dx*dx+dy*dy );
00741 if ( d<dmin )
00742 dmin = d;
00743 }
00744 if ( dmin < DISTANCE_TRESHOLD )
00745 {
00746 n++;
00747 dsum+=dmin;
00748 }
00749 }
00750
00751 if ( n>0 )
00752 {
00753 dsum1 = dsum/ ( PM_TYPE ) n;
00754 n1 = n;
00755 }
00756 else
00757 return HUGE_ERROR;
00758
00759
00760 dsum = 0;n=0;
00761 for ( i=0;i<rn;i++ )
00762 {
00763 dmin = HUGE_ERROR;
00764 for ( j=0;j<an;j++ )
00765 {
00766 dx = rx[i]-ax[j];
00767 dy = ry[i]-ay[j];
00768 d = sqrtf ( dx*dx+dy*dy );
00769 if ( d<dmin )
00770 dmin = d;
00771 }
00772 if ( dmin < DISTANCE_TRESHOLD )
00773 {
00774 n++;
00775 dsum+=dmin;
00776 }
00777 }
00778
00779 if ( n>0 )
00780 {
00781 dsum = dsum/ ( PM_TYPE ) n;
00782 }
00783 else
00784 return HUGE_ERROR;
00785
00786
00787
00788 if ( n1>MIN_POINTS && n>MIN_POINTS )
00789 {
00790 if ( dsum1>dsum )
00791 return dsum1;
00792 else
00793 return dsum;
00794 }
00795 return HUGE_ERROR;
00796 }
00797
00814 PM_TYPE pm_error_index2 ( PMScan *ref,PMScan *cur, int* associatedPoints )
00815 {
00816
00817 PMScan cur2;
00818 PM_TYPE rx,ry,rth,ax,ay,ath;
00819 PM_TYPE t13,t23,LASER_Y = PM_LASER_Y;
00820 PM_TYPE new_r[PM_L_POINTS];
00821 int new_bad[PM_L_POINTS];
00822 PM_TYPE avg_err = 100000000.0;
00823
00824 rx = ref->rx; ry = ref->ry; rth = ref->th;
00825 ax = cur->rx; ay = cur->ry; ath = cur->th;
00826
00827
00828
00829 t13 = sinf ( rth-ath ) *LASER_Y+cosf ( rth ) *ax+sinf ( rth ) *ay-sinf ( rth ) *ry-rx*cosf ( rth );
00830 t23 = cosf ( rth-ath ) *LASER_Y-sinf ( rth ) *ax+cosf ( rth ) *ay-cosf ( rth ) *ry+rx*sinf ( rth )-LASER_Y;
00831
00832 cur2 = *cur;
00833 cur2.rx = t13; cur2.ry = t23; cur2.th = ath-rth;
00834
00835
00836 pm_scan_project( &cur2, new_r, new_bad );
00837
00838 PM_TYPE e = 0;
00839 int n = 0;
00840 for ( int i=0;i < PM_L_POINTS;i++ )
00841 {
00842 PM_TYPE delta = fabsf ( new_r[i] - ref->r[i] );
00843 if ( !new_bad[i] && !ref->bad[i] && delta < PM_MAX_ERROR / 2.0)
00844 {
00845 e += delta;
00846 n++;
00847 }
00848 }
00849
00850 if ( n > 0 )
00851 avg_err = e/n;
00852 if(associatedPoints != NULL)
00853 {
00854 *associatedPoints = n;
00855 }
00856 return avg_err;
00857 }
00858
00875 PM_TYPE pm_corridor_angle ( PMScan *act )
00876 {
00877 PM_TYPE fi;
00878 int n=0,j,i;
00879 PM_TYPE ang[PM_L_POINTS];
00880 int hist[180];
00881
00882 for ( i=0;i<180;i++ )
00883 hist[i]=0;
00884
00885 for ( i=0;i< ( PM_L_POINTS-1 );i++ )
00886 {
00887 if ( act->seg[i]==act->seg[i+1] && act->seg[i]!=0 && !act->bad[i] )
00888 {
00889 PM_TYPE x,y,x1,y1,fi;
00890 x = act->r[i]*pm_co[i];
00891 y = act->r[i]*pm_si[i];
00892
00893 x1 = act->r[i+1]*pm_co[i+1];
00894 y1 = act->r[i+1]*pm_si[i+1];
00895 fi = atan2f ( y1-y,x1-x ) *PM_R2D;
00896
00897
00898 if ( fi<0 )
00899 fi+=180.0;
00900 ang[n] = fi;
00901 n++;
00902
00903 j = ( 2* ( int ) floor ( fi/2.0+0.5 ) ) % 180;
00904 hist[j%180]++;
00905 }
00906 }
00907
00908
00909 int imax=-1,max = 0;
00910 for ( i=0;i<180;i+=2 )
00911 if ( hist[i]>max )
00912 {
00913 max = hist[i];
00914 imax = i;
00915 }
00916 if ( max ==0 )
00917 {
00918 cerr <<"pm_corridor_angle: ERROR no maximum"<<endl;
00919 throw 1;
00920 }
00921
00922 PM_TYPE m=0;
00923 int cnt=0,d;
00924
00925 for ( i=0;i<n;i++ )
00926 {
00927 fi = ang[i];
00928 j = ( ( int ) floor ( fi+0.5 ) ) %180;
00929 d = abs ( j-imax );
00930 const int TRESHOLD=5;
00931 if ( (d<90 && d%90<TRESHOLD) || (d>=90 && ( 90-d%90 )) <TRESHOLD )
00932 {
00933
00934 cnt++;
00935 if ( imax<10 && j>170 )
00936 m+= 180.0-fi;
00937 else
00938 if ( imax>170 && j<10 )
00939 m+= 180.0+fi;
00940 else
00941 m+= fi;
00942 }
00943 }
00944 m = m/ ( PM_TYPE ) cnt;
00945 return m*PM_D2R;
00946 }
00947
00948
00969 void pm_cov_est ( PM_TYPE err, double *c11,double *c12, double *c22, double *c33,
00970 bool corridor, PM_TYPE corr_angle )
00971 {
00972 #define SQ(x) ((x)*(x))
00973 const double cov_x = SQ ( PM_MIN_STD_XY );
00974 const double cov_y = SQ ( PM_MIN_STD_XY );
00975 const double cov_th = SQ ( PM_MIN_STD_ORIENTATION*M_PI/180.0 );
00976
00977 const double cov_along = SQ ( PM_MIN_STD_XY*20.0 );
00978 const double cov_across = SQ ( PM_MIN_STD_XY*1.5 );
00979
00980 err = err - PM_MATCH_ERROR_OFFSET;
00981 if ( err < 1.0 )
00982 err = 1.0;
00983 if ( corridor )
00984 {
00985 double co = cosf ( corr_angle );
00986 double si = sinf ( corr_angle );
00987 *c11 = err* ( SQ ( co ) *cov_along+SQ ( si ) *cov_across );
00988 *c12 = err* ( -co*si* ( -cov_along+cov_across ) );
00989 *c22 = err* ( SQ ( si ) *cov_along+SQ ( co ) *cov_across );
00990 *c33 = err*cov_th;
00991 }
00992 else
00993 {
00994 *c12 = 0;
00995 *c11 = err*cov_x;
00996 *c22 = err*cov_y;
00997 *c33 = err*cov_th;
00998 }
00999 }
01000
01001
01024 PM_TYPE pm_psm ( const PMScan *lsr,PMScan *lsa )
01025 {
01026 PMScan act, ref;
01027 PM_TYPE rx,ry,rth,ax,ay,ath;
01028 PM_TYPE t13,t23,LASER_Y = PM_LASER_Y;
01029 PM_TYPE new_r[PM_L_POINTS];
01030 int new_bad[PM_L_POINTS];
01031 PM_TYPE C = PM_WEIGHTING_FACTOR;
01032 int iter,small_corr_cnt=0;
01033 PM_TYPE dx=0,dy=0,dth=0;
01034 PM_TYPE avg_err = 100000000.0;
01035
01036 #ifdef PM_GENERATE_RESULTS
01037 double start_tick, dead_tick,end_tick,end_tick2;
01038 FILE *f;
01039 f = fopen ( PM_TIME_FILE,"w" );
01040 dead_tick = 0;
01041 start_tick =pm_msec();
01042 #endif
01043
01044 act = *lsa;
01045 ref = *lsr;
01046
01047 rx = ref.rx; ry = ref.ry; rth = ref.th;
01048 ax = act.rx; ay = act.ry; ath = act.th;
01049
01050
01051
01052 t13 = sinf ( rth-ath ) *LASER_Y+cosf ( rth ) *ax+sinf ( rth ) *ay-sinf ( rth ) *ry-rx*cosf ( rth );
01053 t23 = cosf ( rth-ath ) *LASER_Y-sinf ( rth ) *ax+cosf ( rth ) *ay-cosf ( rth ) *ry+rx*sinf ( rth )-LASER_Y;
01054
01055 ref.rx = 0; ref.ry = 0; ref.th = 0;
01056 act.rx = t13; act.ry = t23; act.th = ath-rth;
01057
01058 ax = act.rx; ay = act.ry; ath = act.th;
01059
01060
01061 iter = -1;
01062 while ( ++iter < PM_MAX_ITER && small_corr_cnt < 3 )
01063 {
01064 if ( ( fabsf ( dx ) +fabsf ( dy ) +fabsf ( dth ) ) < PM_STOP_COND )
01065 small_corr_cnt++;
01066 else
01067 small_corr_cnt=0;
01068
01069 #ifdef PM_GENERATE_RESULTS
01070 end_tick =pm_msec();
01071 fprintf ( f,"%i %lf %lf %lf %lf\n",iter,
01072 end_tick-start_tick-dead_tick ,ax,ay,ath*PM_R2D );
01073 end_tick2 =pm_msec();
01074 dead_tick += end_tick2- end_tick;
01075 #endif
01076
01077
01078 #ifdef GR
01079 dr_erase();
01080 dr_circle ( ax,ay,5.0,"green" );
01081 dr_line ( 0,-100,200,-100,"black" );
01082 dr_line ( 0,-200,200,-200,"black" );
01083 for(int i=0;i<PM_L_POINTS;i++)
01084 {
01085 dr_circle ( ref.r[i]*pm_co[i],ref.r[i]*pm_si[i],4.0,"black" );
01086 dr_circle ( pm_fi[i]*PM_R2D,ref.r[i]/10.0-100,1,"black" );
01087 }
01088 #endif
01089
01090 act.rx = ax;act.ry = ay;act.th = ath;
01091 pm_scan_project(&act, new_r, new_bad);
01092
01093
01094
01095 if ( iter%2 == 0 )
01096 {
01097 dth = pm_orientation_search(&ref, new_r, new_bad);
01098 ath += dth;
01099 continue;
01100 }
01101
01102
01103
01104 if ( iter == PM_CHANGE_WEIGHT_ITER )
01105 C = C/50.0;
01106 #ifdef GR
01107 for(int i=0;i<PM_L_POINTS;i++)
01108 {
01109 dr_circle ( pm_fi[i]*PM_R2D,ref.r[i]/10.0-200,1,"black" );
01110 }
01111 #endif
01112
01113 avg_err = pm_translation_estimation(&ref, new_r, new_bad, C, &dx, &dy);
01114 ax += dx;
01115 ay += dy;
01116
01117 #ifdef GR
01118 cout <<"iter "<<iter<<" "<<ax<<" "<<ay<<" "<<ath*PM_R2D<<" "<<dx<<" "<<dy<<endl;
01119 dr_zoom();
01120 #endif
01121 }
01122
01123 #ifdef PM_GENERATE_RESULTS
01124 end_tick =pm_msec();
01125 fprintf ( f,"%i %lf %lf %lf %lf\n",iter,
01126 end_tick-start_tick-dead_tick ,ax,ay,ath*PM_R2D );
01127 fclose ( f );
01128 #endif
01129
01130
01131 lsa->rx =ax;lsa->ry=ay;lsa->th=ath;
01132 return ( avg_err);
01133 }
01134
01135
01136
01150 PM_TYPE point_line_distance ( PM_TYPE x1, PM_TYPE y1, PM_TYPE x2, PM_TYPE y2,
01151 PM_TYPE x3, PM_TYPE y3,PM_TYPE *x, PM_TYPE *y )
01152 {
01153 PM_TYPE ax,ay,t1,D;
01154 ax = x2-x1;
01155 ay = y2-y1;
01156 D = sqrtf ( ax*ax+ay*ay );
01157 if ( D < 0.0001 )
01158 {
01159 cerr <<"point_line_distance: unexpected D:" << D <<endl;
01160 return -1;
01161 }
01162 t1 = - ( -ax*x3 + ay*y1 + ax*x1 - ay*y3 ) / ( ax*ax+ay*ay );
01163 if ( t1<0 || t1>1 )
01164 {
01165 return -1;
01166 }
01167 *x = x1+t1*ax;
01168 *y = y1+t1*ay;
01169 return ( sqrtf ( ( x3-*x ) * ( x3-*x ) + ( y3-*y ) * ( y3-*y ) ) );
01170 }
01171
01172
01182 PM_TYPE pm_icp ( const PMScan *lsr,PMScan *lsa )
01183 {
01184 #define INTERPOLATE_ICP //comment out if no interpolation of ref. scan points iS necessary
01185 PMScan act, ref;
01186 PM_TYPE rx,ry,rth,ax,ay,ath;
01187 PM_TYPE t13,t23,LASER_Y = PM_LASER_Y;
01188 int new_bad[PM_L_POINTS];
01189 PM_TYPE new_r[PM_L_POINTS];
01190 PM_TYPE nx[PM_L_POINTS];
01191 PM_TYPE ny[PM_L_POINTS];
01192 int index[PM_L_POINTS][2];
01193 PM_TYPE dist[PM_L_POINTS];
01194 int n = 0;
01195 int iter,i,j,small_corr_cnt=0,k,imax;
01196 int window = PM_SEARCH_WINDOW;
01197 PM_TYPE abs_err=0,dx=0,dy=0,dth=0;
01198 PM_TYPE co,si;
01199
01200 #ifdef PM_GENERATE_RESULTS
01201 double start_tick, dead_tick,end_tick,end_tick2;
01202 FILE *f;
01203 f = fopen ( PM_TIME_FILE,"w" );
01204 dead_tick = 0;
01205 start_tick =pm_msec();
01206 #endif
01207
01208 act = *lsa;
01209 ref = *lsr;
01210
01211 rx = ref.rx; ry = ref.ry; rth = ref.th;
01212 ax = act.rx; ay = act.ry; ath = act.th;
01213
01214
01215
01216 t13 = sinf ( rth-ath ) *LASER_Y+cosf ( rth ) *ax+sinf ( rth ) *ay-sinf ( rth ) *ry-rx*cosf ( rth );
01217 t23 = cosf ( rth-ath ) *LASER_Y-sinf ( rth ) *ax+cosf ( rth ) *ay-cosf ( rth ) *ry+rx*sinf ( rth )-LASER_Y;
01218
01219 ref.rx = 0; ref.ry = 0; ref.th = 0;
01220 act.rx = t13; act.ry = t23; act.th = ath-rth;
01221
01222 ax = act.rx; ay = act.ry; ath = act.th;
01223
01224
01225
01226 for ( i=0;i<PM_L_POINTS;i++ )
01227 {
01228 ref.x[i] = ref.r[i]*pm_co[i];
01229 ref.y[i] = ref.r[i]*pm_si[i];
01230
01231 act.x[i] = act.r[i]*pm_co[i];
01232 act.y[i] = act.r[i]*pm_si[i];
01233 }
01234
01235 iter = -1;
01236 while ( ++iter<PM_MAX_ITER_ICP && small_corr_cnt<3 )
01237 {
01238
01239 if ( ( fabsf ( dx ) +fabsf ( dy ) +fabsf ( dth ) *PM_R2D ) <PM_STOP_COND_ICP )
01240 small_corr_cnt++;
01241 else
01242 small_corr_cnt=0;
01243
01244 #ifdef PM_GENERATE_RESULTS
01245 end_tick =pm_msec();
01246 fprintf ( f,"%i %lf %lf %lf %lf\n",iter,
01247 end_tick-start_tick-dead_tick ,ax,ay,ath*PM_R2D );
01248 end_tick2 =pm_msec();
01249 dead_tick += end_tick2- end_tick;
01250 #endif
01251
01252 #ifdef GR
01253 dr_erase();
01254 dr_circle ( ax,ay,5.0,"green" );
01255 dr_line ( 0,-100,200,-100,"black" );
01256 dr_line ( 0,-200,200,-200,"black" );
01257 #endif
01258
01259
01260 act.rx = ax;act.ry = ay;act.th = ath;
01261 pm_scan_project(&act, new_r, new_bad);
01262
01263
01264 co = cosf ( ath );
01265 si = sinf ( ath );
01266 for ( i=0;i<PM_L_POINTS;i++ )
01267 {
01268 nx[i] = act.x[i]*co - act.y[i]*si + ax;
01269 ny[i] = act.x[i]*si + act.y[i]*co + ay;
01270 #ifdef GR
01271 if ( ref.bad[i] )
01272 dr_circle ( ref.x[i],ref.y[i],4,"yellow" );
01273 else
01274 dr_circle ( ref.x[i],ref.y[i],4,"black" );
01275 if ( new_bad[i] )
01276 dr_circle ( nx[i],ny[i],4,"green" );
01277 else
01278 dr_circle ( nx[i],ny[i],4,"blue" );
01279 #endif
01280 }
01281
01282 #ifdef GR
01283 cout <<"interpolated ranges. press enter"<<endl;
01284
01285
01286 dr_zoom();
01287 #endif
01288
01289
01290
01291
01292 n=0;
01293 PM_TYPE d,min_d;
01294 int min_idx;
01295
01296 for ( i=0;i<PM_L_POINTS;i++ )
01297 {
01298 min_d = 1000000;
01299 min_idx = -1;
01300 if ( !new_bad[i] )
01301 {
01302 int imin,imax;
01303 imin = i-window ;
01304 if ( imin<0 )
01305 imin =0;
01306 imax = i+window ;
01307 if ( imax>PM_L_POINTS )
01308 imax =PM_L_POINTS;
01309
01310 for ( j=imin;j<imax;j++ )
01311 {
01312 if ( !ref.bad[j] )
01313 {
01314 d = SQ ( nx[i]-ref.x[j] ) + SQ ( ny[i]-ref.y[j] );
01315 if ( d<min_d )
01316 {
01317 min_d = d;
01318 min_idx = j;
01319 }
01320 }
01321 }
01322 if ( min_idx>=0 && sqrtf ( min_d ) <PM_MAX_ERROR )
01323 {
01324 index[n][0] = i;
01325 index[n][1] = min_idx;
01326 dist[n] = sqrtf ( min_d );
01327 n++;
01328 #ifdef GR
01329 dr_line ( nx[i],ny[i],ref.x[min_idx],ref.y[min_idx],"blue" );
01330 #endif
01331 }
01332 }
01333 }
01334
01335
01336 if ( n<PM_MIN_VALID_POINTS )
01337 {
01338 cerr <<"pm_icp: ERROR not enough points"<<endl;
01339 #ifdef PM_GENERATE_RESULTS
01340 fclose ( f );
01341 #endif
01342 throw 1;
01343 }
01344
01345
01346
01347 imax = ( int ) ( ( double ) n*0.2 );
01348 for ( i=0;i<imax;i++ )
01349 for ( j=1;j< ( n-i );j++ )
01350 {
01351 if ( dist[j]<dist[j-1] )
01352 {
01353
01354 k = index[j][0];
01355 index[j][0] = index[j-1][0];
01356 index[j-1][0] = k;
01357
01358 k = index[j][1];
01359 index[j][1] = index[j-1][1];
01360 index[j-1][1] = k;
01361
01362 d = dist[j];
01363 dist[j] = dist[j-1];
01364 dist[j-1] = d;
01365 }
01366 }
01367
01368 #ifdef INTERPOLATE_ICP
01369
01370
01371 PM_TYPE ix[PM_L_POINTS],iy[PM_L_POINTS];
01372
01373 {
01374
01375 PM_TYPE d0,d1,d2;
01376 PM_TYPE minx1,miny1,minx2,miny2;
01377 int max_i = n-imax;
01378 for ( i=0;i<max_i;i++ )
01379 {
01380
01381
01382
01383 #ifdef GR
01384 dr_circle ( nx[index[i][0]],ny[index[i][0]],1.0,"brown" );
01385 dr_circle ( ref.x[index[i][1]],ref.y[index[i][1]],1.0,"brown" );
01386 dr_circle ( ref.x[index[i][1]-1],ref.y[index[i][1]-1],1.0,"brown" );
01387 dr_circle ( ref.x[index[i][1]+1],ref.y[index[i][1]+1],1.0,"brown" );
01388 #endif
01389 d1=-1;d2=-1;
01390 if ( index[i][1]>0 )
01391 {
01392 d1 = point_line_distance ( ref.x[index[i][1]-1], ref.y[index[i][1]-1],
01393 ref.x[index[i][1]], ref.y[index[i][1]],
01394 nx[index[i][0]], ny[index[i][0]],
01395 &minx1, &miny1 );
01396 }
01397
01398 if ( index[i][1]< ( PM_L_POINTS-1 ) )
01399 {
01400 d2 = point_line_distance ( ref.x[index[i][1]], ref.y[index[i][1]],
01401 ref.x[index[i][1]+1],ref.y[index[i][1]+1],
01402 nx[index[i][0]], ny[index[i][0]],
01403 &minx2, &miny2 );
01404 }
01405
01406 ix[index[i][1]] = ref.x[index[i][1]];
01407 iy[index[i][1]] = ref.y[index[i][1]];
01408 d0 = sqrtf ( SQ ( ref.x[index[i][1]]-nx[index[i][0]] ) + SQ ( ref.y[index[i][1]]-ny[index[i][0]] ) );
01409
01410
01411 if ( d1>0 && d1<d0 )
01412 {
01413 ix[index[i][1]] = minx1;
01414 iy[index[i][1]] = miny1;
01415 d0 = d1;
01416 }
01417
01418
01419 if ( d2>0 && d2<d0 )
01420 {
01421 ix[index[i][1]] = minx2;
01422 iy[index[i][1]] = miny2;
01423 }
01424 #ifdef GR
01425 dr_line ( nx[index[i][0]],ny[index[i][0]],ix[index[i][1]],iy[index[i][1]],"green" );
01426 #endif
01427 }
01428 }
01429 #endif
01430
01431
01432
01433
01434
01435
01436
01437
01438 PM_TYPE sxx=0,sxy=0,syx=0,syy=0;
01439 PM_TYPE meanpx,meanpy,meanppx,meanppy;
01440 meanpx = 0;meanpy = 0;
01441 meanppx= 0;meanppy= 0;
01442
01443 abs_err=0;
01444 imax = n-imax;
01445 for ( i=0;i<imax;i++ )
01446 {
01447
01448
01449 meanpx += nx[index[i][0]];
01450 meanpy += ny[index[i][0]];
01451
01452 #ifdef INTERPOLATE_ICP
01453 meanppx += ix[index[i][1]];
01454 meanppy += iy[index[i][1]];
01455 #else
01456 meanppx += ref.x[index[i][1]];
01457 meanppy += ref.y[index[i][1]];
01458 #endif
01459
01460 #ifdef GR
01461 dr_line ( nx[index[i][0]],ny[index[i][0]],ref.x[index[i][1]],ref.y[index[i][1]],"red" );
01462 #endif
01463 }
01464 meanpx /= imax;
01465 meanpy /= imax;
01466
01467 meanppx /= imax;
01468 meanppy /= imax;
01469
01470 for ( int i=0;i<imax;i++ )
01471 {
01472 #ifdef INTERPOLATE_ICP
01473 sxx += ( nx[index[i][0]] - meanpx ) * ( ix[index[i][1]] - meanppx );
01474 sxy += ( nx[index[i][0]] - meanpx ) * ( iy[index[i][1]] - meanppy );
01475 syx += ( ny[index[i][0]] - meanpy ) * ( ix[index[i][1]] - meanppx );
01476 syy += ( ny[index[i][0]] - meanpy ) * ( iy[index[i][1]] - meanppy );
01477 #else
01478 sxx += ( nx[index[i][0]] - meanpx ) * ( ref.x[index[i][1]] - meanppx );
01479 sxy += ( nx[index[i][0]] - meanpx ) * ( ref.y[index[i][1]] - meanppy );
01480 syx += ( ny[index[i][0]] - meanpy ) * ( ref.x[index[i][1]] - meanppx );
01481 syy += ( ny[index[i][0]] - meanpy ) * ( ref.y[index[i][1]] - meanppy );
01482 #endif
01483 }
01484
01485
01486 dth = atan2f ( sxy-syx,sxx+syy );
01487 dx = meanppx - ax - ( cosf ( dth ) * ( meanpx- ax ) - sinf ( dth ) * ( meanpy - ay ) );
01488 dy = meanppy - ay - ( sinf ( dth ) * ( meanpx- ax ) + cosf ( dth ) * ( meanpy - ay ) );
01489
01490 ax += dx;
01491 ay += dy;
01492 ath+= dth;
01493 ath = norm_a ( ath );
01494
01495
01496
01497 #ifdef GR
01498 cout <<"iter "<<iter<<" "<<ax<<" "<<ay<<" "<<ath*PM_R2D<<" "<<dx<<" "<<dy<<endl;
01499
01500 dr_zoom();
01501 usleep ( 10000 );
01502
01503 #endif
01504
01505 }
01506
01507 #ifdef PM_GENERATE_RESULTS
01508 end_tick =pm_msec();
01509 fprintf ( f,"%i %lf %lf %lf %lf\n",iter,
01510 end_tick-start_tick-dead_tick ,ax,ay,ath*PM_R2D );
01511 fclose ( f );
01512 #endif
01513
01514 lsa->rx =ax;lsa->ry=ay;lsa->th=ath;
01515 return ( abs_err/n );
01516 }
01517
01529 void pm_save_scan ( PMScan *act,const char *filename )
01530 {
01531 FILE *f;
01532 f=fopen ( filename,"w" );
01533 for ( int i=0;i<PM_L_POINTS;i++ )
01534 fprintf ( f,"%f %i %i\n",act->r[i],act->bad[i],act->seg[i] );
01535 fclose ( f );
01536 }
01537
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01686 void pm_scan_project(const PMScan *act, PM_TYPE *new_r, int *new_bad)
01687 {
01688 PM_TYPE r[PM_L_POINTS],fi[PM_L_POINTS];
01689 PM_TYPE x,y;
01690 int i;
01691 PM_TYPE delta;
01692
01693
01694
01695 for ( i=0;i<PM_L_POINTS;i++ )
01696 {
01697 delta = act->th + pm_fi[i];
01698 x = act->r[i]*cosf ( delta ) + act->rx;
01699 y = act->r[i]*sinf ( delta ) + act->ry;
01700 r[i] = sqrtf ( x*x+y*y );
01701 fi[i] = atan2f ( y,x );
01702
01703 if(x<0 && y<0)
01704 fi[i] += 2.0*M_PI;
01705 new_r[i] = 10000;
01706 new_bad[i]= PM_EMPTY;
01707
01708 #ifdef GR
01709
01710 dr_circle ( x,y,4.0,"red" );
01711
01712 dr_circle ( fi[i]*PM_R2D,r[i]/10.0-100,1,"red" );
01713 #endif
01714 }
01715
01716
01717
01718
01719 for ( i=1;i<PM_L_POINTS;i++ )
01720 {
01721
01722
01723
01724
01725 if ( act->seg[i] != 0 && act->seg[i] == act->seg[i-1] && !act->bad[i] && !act->bad[i-1] )
01726 {
01727
01728 int j0,j1;
01729 PM_TYPE r0,r1,a0,a1;
01730 bool occluded;
01731
01732
01733
01734
01735 if( fabsf(fi[i]-fi[i-1]) >= M_PI )
01736 continue;
01737
01738 if ( fi[i]>fi[i-1] )
01739 {
01740
01741 occluded = false;
01742 a0 = fi[i-1];
01743 a1 = fi[i];
01744 j0 = (int) ceil ( ( fi[i-1] - PM_FI_MIN ) /PM_DFI );
01745 j1 = (int) floor ( ( fi[i] - PM_FI_MIN ) /PM_DFI );
01746 r0 = r[i-1];
01747 r1 = r[i];
01748 }
01749 else
01750 {
01751
01752 occluded = true;
01753
01754 a0 = fi[i];
01755 a1 = fi[i-1];
01756 j0 = (int) ceil ( ( fi[i] - PM_FI_MIN ) /PM_DFI );
01757 j1 = (int) floor ( ( fi[i-1] - PM_FI_MIN ) /PM_DFI );
01758 r0 = r[i];
01759 r1 = r[i-1];
01760 }
01761
01762
01763
01764 while ( j0<=j1 )
01765 {
01766 PM_TYPE ri = ( r1-r0 ) / ( a1-a0 ) * ( ( ( PM_TYPE ) j0*PM_DFI+PM_FI_MIN )-a0 ) +r0;
01767
01768
01769
01770 if ( j0>=0 && j0<PM_L_POINTS && new_r[j0]>ri )
01771 {
01772 new_r[j0] = ri;
01773 new_bad[j0] &=~PM_EMPTY;
01774 if ( occluded )
01775 new_bad[j0] = new_bad[j0]|PM_OCCLUDED;
01776 else
01777 new_bad[j0] = new_bad[j0]&~PM_OCCLUDED;
01778
01779 new_bad[j0] |= act->bad[i];
01780 new_bad[j0] |= act->bad[i-1];
01782
01783
01784 #ifdef GR
01785 dr_circle ( pm_fi[j0]*PM_R2D,new_r[j0]/10.0-100,1,"yellow" );
01786 #endif
01787
01788 }
01789 j0++;
01790 }
01791 }
01792 }
01793
01794 #ifdef GR
01795
01796 for ( i=0;i<PM_L_POINTS;i++ )
01797 {
01798 double x,y;
01799 x = new_r[i]*pm_co[i];
01800 y = new_r[i]*pm_si[i];
01801 dr_circle ( x,y,3,"yellow" );
01802 dr_circle ( fi[i]*PM_R2D,new_r[i]/10.0-100,1,"yellow" );
01803 }
01804 dr_zoom();
01805 #endif
01806 }
01807
01808
01828 PM_TYPE pm_orientation_search(const PMScan *ref, const PM_TYPE *new_r, const int *new_bad)
01829 {
01830 int i;
01831 int window = PM_SEARCH_WINDOW;
01832 PM_TYPE dth = 0.0;
01833
01834 PM_TYPE e, err[PM_L_POINTS];
01835 PM_TYPE beta[PM_L_POINTS];
01836 const PM_TYPE LARGE_NUMBER = 10000;
01837 PM_TYPE n;
01838 int k=0;
01839
01840 for ( int di=-window;di<=window;di++ )
01841 {
01842 n=0;e=0;
01843
01844 int min_i,max_i;
01845 if ( di<=0 )
01846 {min_i = -di;max_i=PM_L_POINTS;}
01847 else
01848 {min_i = 0;max_i=PM_L_POINTS-di;}
01849
01852 for ( i=min_i;i<max_i;i++ )
01853 {
01854 PM_TYPE delta = fabsf ( new_r[i]-ref->r[i+di] );
01855 #if PM_LASER == PM_HOKUYO_UTM_30LX
01856
01857
01859 if ( !new_bad[i] && !ref->bad[i+di] && delta < PM_MAX_ERROR)
01860 #else
01861 if ( !new_bad[i] && !ref->bad[i+di] )
01862 #endif
01863 {
01864 e += delta;
01865 n++;
01866 }
01867 }
01868
01869 if ( n > 0 )
01870 err[k] = e/n;
01871 else
01872 err[k] = LARGE_NUMBER;
01873 beta[k] = di;
01874 k++;
01875 }
01876
01877 #ifdef GR
01878 FILE *fo;
01879 fo = fopen ( "angles.txt","w" );
01880 for ( i = 0; i < k; i++ )
01881 {
01882 dr_circle ( beta[i],err[i],1.0,"blue" );
01883 fprintf ( fo,"%f %f\n",beta[i],err[i] );
01884 }
01885 fclose ( fo );
01886 #endif
01887
01888
01889
01890
01891 PM_TYPE emin = LARGE_NUMBER*10.0;
01892 int imin=-1;
01893 for ( i = 0; i < k; i++ )
01894 {
01895 if ( err[i] < emin )
01896 {
01897 emin = err[i];
01898 imin = i;
01899 }
01900 }
01901
01902 if ( err[imin]>=LARGE_NUMBER )
01903 {
01904 cerr <<"Polar Match: orientation search failed" <<err[imin]<<endl;
01905 throw 1;
01906 }
01907 dth = beta[imin]*PM_DFI;
01908
01909
01910 if ( imin >= 1 && imin < ( k-1 ) )
01911 {
01912
01913 PM_TYPE D = err[imin-1]+err[imin+1]-2.0*err[imin];
01914 PM_TYPE d = LARGE_NUMBER;
01915 if ( fabsf ( D ) >0.01 && err[imin-1]>err[imin] && err[imin+1]>err[imin] )
01916 d= ( err[imin-1]-err[imin+1] ) /D/2.0;
01917
01918 if ( fabsf ( d ) < 1.0 )
01919 dth+=d*PM_DFI;
01920 }
01921
01922 #ifdef GR
01923 cout <<"angle correction[deg]: "<<dth*PM_R2D<<endl;
01924 dr_zoom();
01925 #endif
01926 return(dth);
01927 }
01928
01929
01940 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)
01941 {
01942
01943
01944 int i;
01945 PM_TYPE hi1, hi2,hwi1,hwi2, hw1=0,hw2=0,hwh11=0;
01946 PM_TYPE hwh12=0,hwh21=0,hwh22=0,w;
01947 PM_TYPE dr;
01948 PM_TYPE abs_err = 0;
01949 int n = 0;
01950 for ( i=0;i<PM_L_POINTS;i++ )
01951 {
01952 dr = ref->r[i]-new_r[i];
01953 abs_err += fabsf ( dr );
01954
01955 if ( ref->bad[i]==0 && new_bad[i]==0 && new_r[i]<PM_MAX_RANGE && new_r[i]>PM_MIN_RANGE && fabsf ( dr ) <PM_MAX_ERROR )
01956 {
01957
01958
01959 w = C/ ( dr*dr+C );
01960 n++;
01961
01962
01963 hi1 = pm_co[i];
01964 hi2 = pm_si[i];
01965
01966 hwi1 = hi1*w;
01967 hwi2 = hi2*w;
01968
01969
01970 hw1 += hwi1*dr;
01971 hw2 += hwi2*dr;
01972
01973
01974 hwh11 += hwi1*hi1;
01975 hwh12 += hwi1*hi2;
01976
01977 hwh22 += hwi2*hi2;
01978
01979 #ifdef GR
01980
01981 dr_circle ( pm_fi[i]*PM_R2D,new_r[i]/10.0-200,1,"red" );
01982 dr_circle ( pm_fi[i]*PM_R2D,dr/10.0-200,1,"blue" );
01983
01984
01985 {
01986 double x,y;
01987 x = pm_fi[i]*PM_R2D;
01988 y = new_r[i]/10.0-200;
01989 dr_line ( x,y,x+hwi1*dr,y+hwi2*dr,"red" );
01990 x = new_r[i]*pm_co[i];
01991 y = new_r[i]*pm_si[i];
01992 dr_line ( x,y,x+hwi1*dr,y+hwi2*dr,"red" );
01993 }
01994 #endif
01995
01996 }
01997 }
01998 if ( n<PM_MIN_VALID_POINTS )
01999 {
02000 cerr <<"pm_translation_estimation: ERROR not enough points ("<<n<<")"<<endl;
02001 #ifdef GR
02002 dr_zoom();
02003 #endif
02004 throw 1;
02005 }
02006
02007
02008 PM_TYPE D;
02009 PM_TYPE inv11,inv21,inv12,inv22;
02010
02011 D = hwh11*hwh22-hwh12*hwh21;
02012 if ( D<0.001 )
02013 {
02014 cerr <<"pm_linearized_match: ERROR determinant to small! "<<D<<endl;
02015 throw 1;
02016 }
02017 inv11 = hwh22/D;
02018 inv12 = -hwh12/D;
02019 inv21 = -hwh12/D;
02020 inv22 = hwh11/D;
02021
02022 *dx = inv11*hw1+inv12*hw2;
02023 *dy = inv21*hw1+inv22*hw2;
02024 return(abs_err/n);
02025 }
02026
02027
02038 void pm_take_simulated_scan(const PM_TYPE xl, const PM_TYPE yl, const PM_TYPE thl, PMScan *ls,
02039 PM_TYPE wallDistLeft = 150.0, PM_TYPE wallDistFront = 200.0)
02040 {
02041 if(PM_LASER_Y!= 0)
02042 {
02043 cerr <<"simulated_room: ERROR PM_LASER_Y is not 0!!!"<<endl;
02044 throw 4;
02045 }
02046
02047
02048 const int N = 4;
02049 PM_TYPE a[N]= {0, M_PI/2.0, M_PI, -M_PI/2.0};
02050 PM_TYPE d[N]= {wallDistLeft, wallDistFront, wallDistLeft, wallDistFront};
02051
02052 PM_TYPE r,rmin,D,fi;
02053
02054 ls->rx = xl;
02055 ls->ry = yl;
02056 ls->th = thl;
02057
02058
02059 const PM_TYPE LARGE_NUMBER = 100000;
02060 for(int i = 0; i < PM_L_POINTS; i++)
02061 {
02062 rmin = LARGE_NUMBER;
02063 fi = pm_fi[i];
02064 for(int j = 0; j < N; j++)
02065 {
02066 D = cosf(thl+fi)*cosf(a[j]) + sinf(thl+fi)*sinf(a[j]);
02067 if( fabsf(D) > 0.001 )
02068 {
02069 r = ( d[j] - xl*cosf(a[j]) - yl*sinf(a[j]) ) / D;
02070 if( r > 0 && r < rmin )
02071 rmin = r;
02072 }
02073 }
02074 ls->r[i]=rmin;
02075 ls->seg[i]=0;
02076 ls->bad[i]=0;
02077 }
02078 }
02079
02089 void pm_unit_test(int matching_alg, bool interactive)
02090 {
02091 const PM_TYPE eps = 0.5;
02092 const PM_TYPE epsTh = 0.5*PM_D2R;
02093
02094 char* matcherName;
02095 if(matching_alg == PM_PSM)
02096 matcherName = (char*)"PSM";
02097 else
02098 matcherName = (char*)"ICP";
02099
02100 printf("Running scan matching unit test for %s. Compiled for: %s\n",matcherName, PM_LASER_NAME);
02101
02102 pm_init();
02103
02104 if(interactive)
02105 {
02106
02107 }
02108
02109 PMScan lsc;
02110 PMScan lsr;
02111 float xc,yc,thc;
02112 float xr,yr,thr;
02113 int test = -1;
02114
02115 xr=0.0; yr=0.0; thr=0.0;
02116 pm_take_simulated_scan(xr, yr, thr, &lsr);
02117 pm_preprocessScan( &lsr );
02118
02119
02120 xc=0.0; yc=0.0; thc=0.0; test++;
02121 pm_take_simulated_scan(xc, yc, thc, &lsc);
02122 lsc.rx=0.0; lsc.ry=0.0; lsc.th=0.0;
02123 pm_preprocessScan( &lsc );
02124
02125 if(interactive)
02126 {
02127
02128
02129
02130
02131
02132 }
02133
02134 if(matching_alg == PM_PSM)
02135 pm_psm(&lsr, &lsc);
02136 else
02137 pm_icp(&lsr, &lsc);
02138
02139 printf("Test%i:init. pose:(%.1f,%.1f,%.1f); position error:%.2f[cm] orient. error:%.2f[deg]\n",
02140 test,xc,yc,thc*PM_R2D,sqrtf(SQ(xc - lsc.rx)+SQ(yc - lsc.ry)),(thc- lsc.th)*PM_R2D);
02141 if(interactive)
02142 {
02143
02144
02145 }
02146 assert(fabsf(xc - lsc.rx) <= eps);
02147 assert(fabsf(yc - lsc.ry) <= eps);
02148 assert(fabsf(thc - lsc.th) <= epsTh);
02149
02150 xc=0; yc=0; thc=0.1;test++;
02151 pm_take_simulated_scan(xc, yc, thc, &lsc);
02152 lsc.rx=0.0; lsc.ry=0.0; lsc.th=0.0;
02153 pm_preprocessScan( &lsc );
02154 if(matching_alg == PM_PSM)
02155 pm_psm(&lsr, &lsc);
02156 else
02157 pm_icp(&lsr, &lsc);
02158
02159 printf("Test%i:init. pose:(%.1f,%.1f,%.1f); position error:%.2f[cm] orient. error:%.2f[deg]\n",
02160 test,xc,yc,thc*PM_R2D,sqrtf(SQ(xc - lsc.rx)+SQ(yc - lsc.ry)),(thc- lsc.th)*PM_R2D);
02161 if(interactive)
02162 {
02163
02164
02165
02166
02167
02168
02169 }
02170 assert(fabsf(xc - lsc.rx) <= eps);
02171 assert(fabsf(yc - lsc.ry) <= eps);
02172 assert(fabsf(thc- lsc.th) <= epsTh);
02173
02174 xc=10.0; yc=0; thc=0.0; test++;
02175 pm_take_simulated_scan(xc, yc, thc, &lsc);
02176 lsc.rx=0.0; lsc.ry=0.0; lsc.th=0.0;
02177 pm_preprocessScan( &lsc );
02178 if(matching_alg == PM_PSM)
02179 pm_psm(&lsr, &lsc);
02180 else
02181 pm_icp(&lsr, &lsc);
02182
02183 printf("Test%i:init. pose:(%.1f,%.1f,%.1f); position error:%.2f[cm] orient. error:%.2f[deg]\n",
02184 test,xc,yc,thc*PM_R2D,sqrtf(SQ(xc - lsc.rx)+SQ(yc - lsc.ry)),(thc- lsc.th)*PM_R2D);
02185 if(interactive)
02186 {
02187
02188
02189
02190
02191
02192
02193 }
02194 assert(fabsf(xc - lsc.rx) <= eps);
02195 assert(fabsf(yc - lsc.ry) <= eps);
02196 assert(fabsf(thc- lsc.th) <= epsTh);
02197
02198 xc=0.0; yc=10.0; thc=0.0;test++;
02199 pm_take_simulated_scan(xc, yc, thc, &lsc);
02200 lsc.rx=0.0; lsc.ry=0.0; lsc.th=0.0;
02201 pm_preprocessScan( &lsc );
02202 if(matching_alg == PM_PSM)
02203 pm_psm(&lsr, &lsc);
02204 else
02205 pm_icp(&lsr, &lsc);
02206
02207 printf("Test%i:init. pose:(%.1f,%.1f,%.1f); position error:%.2f[cm] orient. error:%.2f[deg]\n",
02208 test,xc,yc,thc*PM_R2D,sqrtf(SQ(xc - lsc.rx)+SQ(yc - lsc.ry)),(thc- lsc.th)*PM_R2D);
02209 if(interactive)
02210 {
02211
02212
02213
02214
02215
02216
02217 }
02218
02219 assert(fabsf(xc - lsc.rx) <= eps);
02220 assert(fabsf(yc - lsc.ry) <= eps);
02221 assert(fabsf(thc- lsc.th) <= epsTh);
02222
02223 assert( pm_is_corridor(&lsc) == false);
02224
02225
02226
02227 xr=0.0; yr=0.0; thr=0.0; test++;
02228 pm_take_simulated_scan(xr, yr, thr, &lsr, 200.0, 1.5*PM_MAX_RANGE);
02229 pm_preprocessScan( &lsr );
02230
02231 xc=10.0; yc=0.0; thc=0.1;
02232 pm_take_simulated_scan(xc, yc, thc, &lsc, 200.0, 1.5*PM_MAX_RANGE);
02233 lsc.rx=0.0; lsc.ry=0.0; lsc.th=0.0;
02234 pm_preprocessScan( &lsc );
02235
02236 if(interactive)
02237 {
02238
02239
02240
02241
02242
02243 }
02244
02245 if(matching_alg == PM_PSM)
02246 pm_psm(&lsr, &lsc);
02247 else
02248 pm_icp(&lsr, &lsc);
02249
02250 printf("Test%i:init. pose:(%.1f,%.1f,%.1f); position error:%.2f[cm] orient. error:%.2f[deg]\n",
02251 test,xc,yc,thc*PM_R2D,sqrtf(SQ(xc - lsc.rx)+SQ(yc - lsc.ry)),(thc- lsc.th)*PM_R2D);
02252
02253 assert(fabsf(xc - lsc.rx) <= eps);
02254 assert(fabsf(thc - lsc.th) <= epsTh);
02255
02256 bool corridor = pm_is_corridor(&lsc);
02257 assert (corridor);
02258 PM_TYPE error = pm_error_index(&lsr, &lsc);
02259 PM_TYPE angle = pm_corridor_angle(&lsr);
02260
02261 double c11,c12, c22, c33;
02262 pm_cov_est(error, &c11,&c12, &c22, &c33,corridor, angle);
02263
02264 printf("Error index:%.1f, angle:%.1f, cov: %.1f,%.1f,%.1f,%.1f\n", error, angle*PM_R2D,sqrt(c11),
02265 c12/sqrt(c11)/sqrt(c22),sqrt(c22),sqrt(c33)*PM_R2D);
02266 if(interactive)
02267 {
02268
02269
02270
02271
02272 }
02273
02274 printf("Unit test......................PASSED\n");
02275 }