当前位姿与上一次位姿做差,计算做累计角度偏差和位移偏差。利用激光雷达测得距离做得分处理。非首帧调用scanMatch,upDateTreeWeight,resample。首帧则调用invalidActiveArea,computeActiveArea,registerScan。
第1部分 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 bool GridSlamProcessor::processScan (const RangeReading & reading, int adaptParticles) { OrientedPoint relPose = reading.getPose (); if (!m_count) m_lastPartPose = m_odoPose = relPose; int tmp_size = m_particles.size (); for (ParticleVector::iterator it=m_particles.begin (); it!=m_particles.end (); it++) { OrientedPoint& pose (it->pose) ; pose=m_motionModel.drawFromMotion (it->pose, relPose, m_odoPose); } onOdometryUpdate (); OrientedPoint move = relPose - m_odoPose; move.theta=atan2 (sin (move.theta), cos (move.theta)); m_linearDistance+=sqrt (move*move); m_angularDistance+=fabs (move.theta); if (m_linearDistance > m_distanceThresholdCheck) { } m_odoPose = relPose; bool processed=false ; if ( ! m_count || m_linearDistance >=m_linearThresholdDistance || m_angularDistance >=m_angularThresholdDistance || (period_ >= 0.0 && (reading.getTime () - last_update_time_) > period_) ) { } m_readingCount++; return processed; }
ScanMatcher 构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ScanMatcher::ScanMatcher (): m_laserPose (0 ,0 ,0 ) { line_angle = 0.0 ; m_laserBeams=0 ; m_optRecursiveIterations=9 ; m_activeAreaComputed=false ; m_llsamplerange=0.01 ; m_llsamplestep=0.01 ; m_lasamplerange=0.005 ; m_lasamplestep=0.005 ; m_enlargeStep=10. ; m_fullnessThreshold=0.1 ; m_angularOdometryReliability=0. ; m_linearOdometryReliability=0. ; m_freeCellRatio=sqrt (2. ); m_initialBeamsSkip=0 ; m_linePoints = new IntPoint[20000 ]; }
全是参数赋值,但是全写死,不能通过ROS修改
drawFromMotion 里程计运动模型
p 表示粒子估计的最优位置(机器人上一个时刻的最优位置)
pnew 表示里程计算出来的新的位置
pold 表示建图引擎记录的上一时刻的位姿(即上一个里程计的位置)
不是执行圆加运算,pnew和pold只是用于产生噪声控制量,然后加到p上1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 OrientedPoint MotionModel::drawFromMotion (const OrientedPoint& p, const OrientedPoint& pnew, const OrientedPoint& pold) const { double sxy=0.3 *srr; OrientedPoint delta=absoluteDifference (pnew, pold); OrientedPoint noisypoint (delta) ; noisypoint.x+=sampleGaussian (srr*fabs (delta.x)+str*fabs (delta.theta)+sxy*fabs (delta.y)); noisypoint.y+=sampleGaussian (srr*fabs (delta.y)+str*fabs (delta.theta)+sxy*fabs (delta.x)); noisypoint.theta+=sampleGaussian (stt*fabs (delta.theta)+srt*sqrt (delta.x*delta.x+delta.y*delta.y)); noisypoint.theta=fmod (noisypoint.theta, 2 *M_PI); if (noisypoint.theta>M_PI) noisypoint.theta-=2 *M_PI; return absoluteSum (p,noisypoint); }
这里的MotionModel是一个十分粗糙的运动模型,只是简单的矢量加减运算。 相比于《Probabilistic Robotics》
中提到的速度模型和里程计模型而言,有很多方面都没有考虑,精度上可能有折扣。
第2部分 if中的处理激光数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 last_update_time_ = reading.getTime (); int beam_number = reading.getSize ();double * plainReading = new double [beam_number];for (unsigned int i=0 ; i<beam_number; i++){ plainReading[i]=reading.m_dists[i]; } if (m_count>0 ){ scanMatch (plainReading); onScanmatchUpdate (); updateTreeWeights (false ); std::cerr<<"plainReading:" <<m_beams<<std::endl; resample (plainReading, adaptParticles, reading_copy); } else { for (ParticleVector::iterator it=m_particles.begin (); it!=m_particles.end (); it++) { m_matcher.invalidateActiveArea (); m_matcher.computeActiveArea (it->map, it->pose, plainReading); m_matcher.registerScan (it->map, it->pose, plainReading); TNode* node=new TNode (it->pose, 0. , it->node, 0 ); node->reading = reading_copy; it->node=node; } } updateTreeWeights (false );delete [] plainReading;m_lastPartPose=m_odoPose; m_linearDistance=0 ; m_angularDistance=0 ; m_count++; processed=true ; for (ParticleVector::iterator it=m_particles.begin (); it!=m_particles.end (); it++){ it->previousPose=it->pose; }