#include #include #include #include #include #include "gridlinetraversal.h" //#define GENERATE_MAPS namespace GMapping { using namespace std; const double ScanMatcher::nullLikelihood=-.5; ScanMatcher::ScanMatcher(): m_laserPose(0,0,0){ //m_laserAngles=0; m_laserBeams=0; m_optRecursiveIterations=3; m_activeAreaComputed=false; // This are the dafault settings for a grid map of 5 cm 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; /* // This are the dafault settings for a grid map of 10 cm m_llsamplerange=0.1; m_llsamplestep=0.1; m_lasamplerange=0.02; m_lasamplestep=0.01; */ // This are the dafault settings for a grid map of 20/25 cm /* m_llsamplerange=0.2; m_llsamplestep=0.1; m_lasamplerange=0.02; m_lasamplestep=0.01; m_generateMap=false; */ m_linePoints = new IntPoint[20000]; } ScanMatcher::~ScanMatcher(){ delete [] m_linePoints; } void ScanMatcher::invalidateActiveArea(){ m_activeAreaComputed=false; } /* void ScanMatcher::computeActiveArea(ScanMatcherMap& map, const OrientedPoint& p, const double* readings){ if (m_activeAreaComputed) return; HierarchicalArray2D::PointSet activeArea; OrientedPoint lp=p; lp.x+=cos(p.theta)*m_laserPose.x-sin(p.theta)*m_laserPose.y; lp.y+=sin(p.theta)*m_laserPose.x+cos(p.theta)*m_laserPose.y; lp.theta+=m_laserPose.theta; IntPoint p0=map.world2map(lp); const double * angle=m_laserAngles; for (const double* r=readings; rm_laserMaxRange) continue; if (d>m_usableRange) d=m_usableRange; Point phit=lp+Point(d*cos(lp.theta+*angle),d*sin(lp.theta+*angle)); IntPoint p1=map.world2map(phit); d+=map.getDelta(); //Point phit2=lp+Point(d*cos(lp.theta+*angle),d*sin(lp.theta+*angle)); //IntPoint p2=map.world2map(phit2); IntPoint linePoints[20000] ; GridLineTraversalLine line; line.points=linePoints; //GridLineTraversal::gridLine(p0, p2, &line); GridLineTraversal::gridLine(p0, p1, &line); for (int i=0; im_laserMaxRange||*r>m_usableRange) continue; Point phit=lp; phit.x+=*r*cos(lp.theta+*angle); phit.y+=*r*sin(lp.theta+*angle); IntPoint p1=map.world2map(phit); assert(p1.x>=0 && p1.y>=0); IntPoint cp=map.storage().patchIndexes(p1); assert(cp.x>=0 && cp.y>=0); activeArea.insert(cp); } //this allocates the unallocated cells in the active area of the map //cout << "activeArea::size() " << activeArea.size() << endl; map.storage().setActiveArea(activeArea, true); m_activeAreaComputed=true; } */ void ScanMatcher::computeActiveArea(ScanMatcherMap& map, const OrientedPoint& p, const double* readings){ if (m_activeAreaComputed) return; OrientedPoint lp=p; lp.x+=cos(p.theta)*m_laserPose.x-sin(p.theta)*m_laserPose.y; lp.y+=sin(p.theta)*m_laserPose.x+cos(p.theta)*m_laserPose.y; lp.theta+=m_laserPose.theta; IntPoint p0=map.world2map(lp); Point min(map.map2world(0,0)); Point max(map.map2world(map.getMapSizeX()-1,map.getMapSizeY()-1)); if (lp.xmax.x) max.x=lp.x; if (lp.y>max.y) max.y=lp.y; /*determine the size of the area*/ const double * angle=m_laserAngles+m_initialBeamsSkip; for (const double* r=readings+m_initialBeamsSkip; rm_laserMaxRange||*r==0.0||isnan(*r)) continue; double d=*r>m_usableRange?m_usableRange:*r; Point phit=lp; phit.x+=d*cos(lp.theta+*angle); phit.y+=d*sin(lp.theta+*angle); if (phit.xmax.x) max.x=phit.x; if (phit.y>max.y) max.y=phit.y; } //min=min-Point(map.getDelta(),map.getDelta()); //max=max+Point(map.getDelta(),map.getDelta()); if ( !map.isInside(min) || !map.isInside(max)){ Point lmin(map.map2world(0,0)); Point lmax(map.map2world(map.getMapSizeX()-1,map.getMapSizeY()-1)); //cerr << "CURRENT MAP " << lmin.x << " " << lmin.y << " " << lmax.x << " " << lmax.y << endl; //cerr << "BOUNDARY OVERRIDE " << min.x << " " << min.y << " " << max.x << " " << max.y << endl; min.x=( min.x >= lmin.x )? lmin.x: min.x-m_enlargeStep; max.x=( max.x <= lmax.x )? lmax.x: max.x+m_enlargeStep; min.y=( min.y >= lmin.y )? lmin.y: min.y-m_enlargeStep; max.y=( max.y <= lmax.y )? lmax.y: max.y+m_enlargeStep; map.resize(min.x, min.y, max.x, max.y); //cerr << "RESIZE " << min.x << " " << min.y << " " << max.x << " " << max.y << endl; } HierarchicalArray2D::PointSet activeArea; /*allocate the active area*/ angle=m_laserAngles+m_initialBeamsSkip; for (const double* r=readings+m_initialBeamsSkip; rm_laserMaxRange||d==0.0||isnan(d)) continue; if (d>m_usableRange) d=m_usableRange; Point phit=lp+Point(d*cos(lp.theta+*angle),d*sin(lp.theta+*angle)); IntPoint p0=map.world2map(lp); IntPoint p1=map.world2map(phit); //IntPoint linePoints[20000] ; GridLineTraversalLine line; line.points=m_linePoints; GridLineTraversal::gridLine(p0, p1, &line); for (int i=0; i=0 && m_linePoints[i].y>=0); } if (d=0 && cp.y>=0); activeArea.insert(cp); } } else { if (*r>m_laserMaxRange||*r>m_usableRange||*r==0.0||isnan(*r)) continue; Point phit=lp; phit.x+=*r*cos(lp.theta+*angle); phit.y+=*r*sin(lp.theta+*angle); IntPoint p1=map.world2map(phit); assert(p1.x>=0 && p1.y>=0); IntPoint cp=map.storage().patchIndexes(p1); assert(cp.x>=0 && cp.y>=0); activeArea.insert(cp); } //this allocates the unallocated cells in the active area of the map //cout << "activeArea::size() " << activeArea.size() << endl; /* cerr << "ActiveArea="; for (HierarchicalArray2D::PointSet::const_iterator it=activeArea.begin(); it!= activeArea.end(); it++){ cerr << "(" << it->x <<"," << it->y << ") "; } cerr << endl; */ map.storage().setActiveArea(activeArea, true); m_activeAreaComputed=true; } double ScanMatcher::registerScan(ScanMatcherMap& map, const OrientedPoint& p, const double* readings){ if (!m_activeAreaComputed) computeActiveArea(map, p, readings); //this operation replicates the cells that will be changed in the registration operation map.storage().allocActiveArea(); OrientedPoint lp=p; lp.x+=cos(p.theta)*m_laserPose.x-sin(p.theta)*m_laserPose.y; lp.y+=sin(p.theta)*m_laserPose.x+cos(p.theta)*m_laserPose.y; lp.theta+=m_laserPose.theta; IntPoint p0=map.world2map(lp); const double * angle=m_laserAngles+m_initialBeamsSkip; double esum=0; for (const double* r=readings+m_initialBeamsSkip; rm_laserMaxRange||d==0.0||isnan(d)) continue; if (d>m_usableRange) d=m_usableRange; Point phit=lp+Point(d*cos(lp.theta+*angle),d*sin(lp.theta+*angle)); IntPoint p1=map.world2map(phit); //IntPoint linePoints[20000] ; GridLineTraversalLine line; line.points=m_linePoints; GridLineTraversal::gridLine(p0, p1, &line); for (int i=0; im_laserMaxRange||*r>m_usableRange||*r==0.0||isnan(*r)) continue; Point phit=lp; phit.x+=*r*cos(lp.theta+*angle); phit.y+=*r*sin(lp.theta+*angle); IntPoint p1=map.world2map(phit); assert(p1.x>=0 && p1.y>=0); map.cell(p1).update(true,phit); } //cout << "informationGain=" << -esum << endl; return esum; } /* void ScanMatcher::registerScan(ScanMatcherMap& map, const OrientedPoint& p, const double* readings){ if (!m_activeAreaComputed) computeActiveArea(map, p, readings); //this operation replicates the cells that will be changed in the registration operation map.storage().allocActiveArea(); OrientedPoint lp=p; lp.x+=cos(p.theta)*m_laserPose.x-sin(p.theta)*m_laserPose.y; lp.y+=sin(p.theta)*m_laserPose.x+cos(p.theta)*m_laserPose.y; lp.theta+=m_laserPose.theta; IntPoint p0=map.world2map(lp); const double * angle=m_laserAngles; for (const double* r=readings; rm_laserMaxRange) continue; if (d>m_usableRange) d=m_usableRange; Point phit=lp+Point(d*cos(lp.theta+*angle),d*sin(lp.theta+*angle)); IntPoint p1=map.world2map(phit); IntPoint linePoints[20000] ; GridLineTraversalLine line; line.points=linePoints; GridLineTraversal::gridLine(p0, p1, &line); for (int i=0; im_laserMaxRange||*r>m_usableRange) continue; Point phit=lp; phit.x+=*r*cos(lp.theta+*angle); phit.y+=*r*sin(lp.theta+*angle); map.cell(phit).update(true,phit); } } */ double ScanMatcher::icpOptimize(OrientedPoint& pnew, const ScanMatcherMap& map, const OrientedPoint& init, const double* readings) const{ double currentScore; double sc=score(map, init, readings);; OrientedPoint start=init; pnew=init; int iterations=0; do{ currentScore=sc; sc=icpStep(pnew, map, start, readings); //cerr << "pstart=" << start.x << " " <currentScore); cerr << "i="<< iterations << endl; return currentScore; } double ScanMatcher::optimize(OrientedPoint& pnew, const ScanMatcherMap& map, const OrientedPoint& init, const double* readings) const{ double bestScore=-1; OrientedPoint currentPose=init; double currentScore=score(map, currentPose, readings); double adelta=m_optAngularDelta, ldelta=m_optLinearDelta; unsigned int refinement=0; enum Move{Front, Back, Left, Right, TurnLeft, TurnRight, Done}; /* cout << __PRETTY_FUNCTION__<< " readings: "; for (int i=0; i=currentScore){ refinement++; adelta*=.5; ldelta*=.5; } bestScore=currentScore; // cout <<"score="<< currentScore << " refinement=" << refinement; // cout << "pose=" << currentPose.x << " " << currentPose.y << " " << currentPose.theta << endl; OrientedPoint bestLocalPose=currentPose; OrientedPoint localPose=currentPose; Move move=Front; do { localPose=currentPose; switch(move){ case Front: localPose.x+=ldelta; move=Back; break; case Back: localPose.x-=ldelta; move=Left; break; case Left: localPose.y-=ldelta; move=Right; break; case Right: localPose.y+=ldelta; move=TurnLeft; break; case TurnLeft: localPose.theta+=adelta; move=TurnRight; break; case TurnRight: localPose.theta-=adelta; move=Done; break; default:; } double odo_gain=1; if (m_angularOdometryReliability>0.){ double dth=init.theta-localPose.theta; dth=atan2(sin(dth), cos(dth)); dth*=dth; odo_gain*=exp(-m_angularOdometryReliability*dth); } if (m_linearOdometryReliability>0.){ double dx=init.x-localPose.x; double dy=init.y-localPose.y; double drho=dx*dx+dy*dy; odo_gain*=exp(-m_linearOdometryReliability*drho); } double localScore=odo_gain*score(map, localPose, readings); if (localScore>currentScore){ currentScore=localScore; bestLocalPose=localPose; } c_iterations++; } while(move!=Done); currentPose=bestLocalPose; // cout << "currentScore=" << currentScore<< endl; //here we look for the best move; }while (currentScore>bestScore || refinement0.){ double dth=init.theta-localPose.theta; dth=atan2(sin(dth), cos(dth)); dth*=dth; odo_gain*=exp(-m_angularOdometryReliability*dth); } if (m_linearOdometryReliability>0.){ double dx=init.x-localPose.x; double dy=init.y-localPose.y; double drho=dx*dx+dy*dy; odo_gain*=exp(-m_linearOdometryReliability*drho); } localScore=odo_gain*score(map, localPose, readings); //update the score count++; matched=likelihoodAndScore(localScore, localLikelihood, map, localPose, readings); if (localScore>currentScore){ currentScore=localScore; bestLocalPose=localPose; } sm.score=localScore; sm.likelihood=localLikelihood;//+log(odo_gain); sm.pose=localPose; moveList.push_back(sm); //update the move list } while(move!=Done); currentPose=bestLocalPose; //cout << __PRETTY_FUNCTION__ << "currentScore=" << currentScore<< endl; //here we look for the best move; }while (currentScore>bestScore || refinement