#include #include #include #include "gridlinetraversal.h" //#define GENERATE_MAPS using namespace std; namespace GMapping { const double ScanMatcher::nullLikelihood=-1.; 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; /* // 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; */ } ScanMatcher::~ScanMatcher(){ if (m_laserAngles) delete [] m_laserAngles; } 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::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); 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); map.cell(phit).update(true,phit); } } 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}; int c_iterations=0; do{ if (bestScore>=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 localScore=score(map, localPose, readings); if (localScore>currentScore){ currentScore=localScore; bestLocalPose=localPose; } c_iterations++; } while(move!=Done); currentPose=bestLocalPose; //cout << __PRETTY_FUNCTION__ << "currentScore=" << currentScore<< endl; //here we look for the best move; }while (currentScore>bestScore || refinementcurrentScore){ currentScore=localScore; bestLocalPose=localPose; } sm.score=localScore; sm.likelihood=localLikelihood; 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