28 #include <boost/serialization/vector.hpp>
46 #define MAX_VARIANCE 500.0
47 #define DISTANCE_PENALTY_GAIN 0.2
48 #define ANGLE_PENALTY_GAIN 0.2
213 std::cout <<
"Remove Scan: Failed to find scan in m_Scans" << std::endl;
236 template<
class Archive>
239 ar & BOOST_SERIALIZATION_NVP(
m_Scans);
279 if (pScanManager != NULL)
281 LocalizedRangeScanMap::iterator it = pScanManager->
GetScans().find(scanIndex);
282 if (it != pScanManager->
GetScans().end())
371 std::cout <<
"RemoveScan: Failed to find scan in m_Scans" << std::endl;
411 for (uint i = 0; i != names.size(); i++) {
421 for (uint i = 0; i != names.size(); i++) {
438 LocalizedRangeScanMap::iterator it;
439 for (it = rScans.begin(); it != rScans.end(); ++it)
441 scans.push_back(it->second);
458 iter->second =
nullptr;
497 if (smearDeviation < 0)
501 if (rangeThreshold <= 0)
513 kt_int32u pointReadingMargin =
static_cast<kt_int32u>(ceil(rangeThreshold / resolution));
515 kt_int32s gridSize = searchSpaceSideSize + 2 * pointReadingMargin;
518 assert(gridSize % 2 == 1);
523 searchSpaceSideSize, resolution);
596 doPenalize, rMean, rCovariance,
false);
603 std::cout <<
"Mapper Info: Expanding response search space!" << std::endl;
611 bestResponse =
CorrelateScan(pScan, scanPose, coarseSearchOffset, coarseSearchResolution,
613 doPenalize, rMean, rCovariance,
false);
624 std::cout <<
"Mapper Warning: Unable to calculate response!" << std::endl;
634 bestResponse =
CorrelateScan(pScan, rMean, fineSearchOffset, fineSearchResolution,
637 doPenalize, rMean, rCovariance,
true);
641 std::cout <<
" BEST POSE = " << rMean <<
" BEST RESPONSE = " << bestResponse <<
", VARIANCE = "
642 << rCovariance(0, 0) <<
", " << rCovariance(1, 1) << std::endl;
660 for ( std::vector<kt_double>::const_iterator xIter =
m_xPoses.begin(); xIter !=
m_xPoses.end(); ++xIter )
662 x_pose = std::distance(
m_xPoses.begin(), xIter);
669 assert(gridIndex >= 0);
681 kt_double squaredDistance = squareX + squareY;
691 response *= (distancePenalty * anglePenalty);
695 poseResponseCounter = (y_pose*size_x + x_pose)*(
m_nAngles) + angleIndex;
725 assert(searchAngleResolution != 0.0);
744 2.0 / rSearchSpaceResolution.
GetX()) + 1);
746 for (
kt_int32u xIndex = 0; xIndex < nX; xIndex++)
748 m_xPoses.push_back(startX + xIndex * rSearchSpaceResolution.
GetX());
754 2.0 / rSearchSpaceResolution.
GetY()) + 1);
756 for (
kt_int32u yIndex = 0; yIndex < nY; yIndex++)
758 m_yPoses.push_back(startY + yIndex * rSearchSpaceResolution.
GetY());
771 + startX, rSearchCenter.
GetY() + startY));
779 tbb::parallel_do(
m_yPoses, (*
this) );
783 for (
kt_int32u i = 0; i < poseResponseSize; i++)
800 throw std::runtime_error(
"Mapper FATAL ERROR - unable to get pointer in probability search!");
805 throw std::runtime_error(
"Mapper FATAL ERROR - Index out of range in probability search!");
817 for (
kt_int32u i = 0; i < poseResponseSize; i++)
824 thetaX += cos(heading);
825 thetaY += sin(heading);
832 if (averagePoseCount > 0)
834 averagePosition /= averagePoseCount;
836 thetaX /= averagePoseCount;
837 thetaY /= averagePoseCount;
839 averagePose =
Pose2(averagePosition, atan2(thetaY, thetaX));
843 throw std::runtime_error(
"Mapper FATAL ERROR - Unable to find best position");
851 std::cout <<
"bestPose: " << averagePose << std::endl;
852 std::cout <<
"bestResponse: " << bestResponse << std::endl;
858 rSearchSpaceResolution, searchAngleResolution, rCovariance);
863 searchAngleOffset, searchAngleResolution, rCovariance);
869 std::cout <<
"bestPose: " << averagePose << std::endl;
872 if (bestResponse > 1.0)
894 const Pose2& rSearchCenter,
907 rCovariance(2, 2) = 4 *
math::Square(searchAngleResolution);
931 for (
kt_int32u yIndex = 0; yIndex < nY; yIndex++)
933 kt_double y = startY + yIndex * rSearchSpaceResolution.
GetY();
935 for (
kt_int32u xIndex = 0; xIndex < nX; xIndex++)
937 kt_double x = startX + xIndex * rSearchSpaceResolution.
GetX();
940 rSearchCenter.
GetY() + y));
944 if (
response >= (bestResponse - 0.1))
948 accumulatedVarianceXY += ((x - dx) * (y - dy) *
response);
956 kt_double varianceXX = accumulatedVarianceXX / norm;
957 kt_double varianceXY = accumulatedVarianceXY / norm;
958 kt_double varianceYY = accumulatedVarianceYY / norm;
969 kt_double multiplier = 1.0 / bestResponse;
970 rCovariance(0, 0) = varianceXX * multiplier;
971 rCovariance(0, 1) = varianceXY * multiplier;
972 rCovariance(1, 0) = varianceXY * multiplier;
973 rCovariance(1, 1) = varianceYY * multiplier;
974 rCovariance(2, 2) = varianceTHTH;
1001 const Pose2& rSearchCenter,
1020 kt_double accumulatedVarianceThTh = 0.0;
1021 for (
kt_int32u angleIndex = 0; angleIndex < nAngles; angleIndex++)
1023 angle = startAngle + angleIndex * searchAngleResolution;
1027 if (
response >= (bestResponse - 0.1))
1039 accumulatedVarianceThTh =
math::Square(searchAngleResolution);
1042 accumulatedVarianceThTh /= norm;
1046 accumulatedVarianceThTh = 1000 *
math::Square(searchAngleResolution);
1049 rCovariance(2, 2) = accumulatedVarianceThTh;
1085 if (iter->second == NULL)
1090 AddScan(iter->second, viewPoint);
1127 if (doSmear ==
true)
1149 PointVectorDouble::const_iterator trailingPointIter = rPointReadings.begin();
1158 if (firstTime && !std::isnan(currentPoint.
GetX()) && !std::isnan(currentPoint.
GetY()))
1160 firstPoint = currentPoint;
1172 double a = rViewPoint.
GetY() - firstPoint.
GetY();
1173 double b = firstPoint.
GetX() - rViewPoint.
GetX();
1174 double c = firstPoint.
GetY() * rViewPoint.
GetX() - firstPoint.
GetX() * rViewPoint.
GetY();
1175 double ss = currentPoint.GetX() * a + currentPoint.GetY() * b + c;
1178 firstPoint = currentPoint;
1182 trailingPointIter = iter;
1186 for (; trailingPointIter != iter; ++trailingPointIter)
1188 validPoints.push_back(*trailingPointIter);
1211 assert(pOffsets != NULL);
1225 kt_int32s pointGridIndex = gridPositionIndex + pAngleIndexPointer[i];
1232 response += pByte[pAngleIndexPointer[i]];
1247 template<
typename T>
1280 std::vector<T*> objects;
1283 objects.push_back((*iter)->GetObject());
1297 std::queue<Vertex<T>*> toVisit;
1298 std::set<Vertex<T>*> seenVertices;
1299 std::vector<Vertex<T>*> validVertices;
1301 toVisit.push(pStartVertex);
1302 seenVertices.insert(pStartVertex);
1309 if (pNext != NULL && pVisitor->
Visit(pNext))
1312 validVertices.push_back(pNext);
1320 if (seenVertices.find(pAdjacent) == seenVertices.end())
1322 toVisit.push(pAdjacent);
1323 seenVertices.insert(pAdjacent);
1327 }
while (toVisit.empty() ==
false);
1329 return validVertices;
1333 template<
class Archive>
1366 std::cout <<
"Unable to visit valid vertex elements!" << std::endl;
1376 template<
class Archive>
1415 template<
class Archive>
1431 : m_pMapper(pMapper)
1481 if (pSensorManager->
GetLastScan(rSensorName) != NULL)
1483 assert(previousScanNum >= 0);
1493 std::vector<Matrix3> covariances;
1496 if (pSensorManager->
GetLastScan(rSensorName) == NULL)
1498 assert(pSensorManager->
GetScans(rSensorName).size() == 1);
1500 std::vector<Name> deviceNames = pSensorManager->
GetSensorNames();
1501 forEach(std::vector<Name>, &deviceNames)
1503 const Name& rCandidateSensorName = *iter;
1506 if ((rCandidateSensorName == rSensorName) || (pSensorManager->
GetScans(rCandidateSensorName).empty()))
1514 pSensorManager->
GetScans(rCandidateSensorName),
1515 bestPose, covariance);
1516 LinkScans(pScan, pSensorManager->
GetScan(rCandidateSensorName, 0), bestPose, covariance);
1521 means.push_back(bestPose);
1522 covariances.push_back(covariance);
1530 means.push_back(scanPose);
1531 covariances.push_back(rCovariance);
1552 while (!candidateChain.empty())
1557 bestPose, covariance,
false,
false);
1559 std::stringstream stream;
1560 stream <<
"COARSE RESPONSE: " << coarseResponse
1563 stream <<
" var: " << covariance(0, 0) <<
", " << covariance(1, 1)
1579 bestPose, covariance,
false);
1581 std::stringstream stream1;
1582 stream1 <<
"FINE RESPONSE: " << fineResponse <<
" (>"
1586 if (fineResponse < m_pMapper->m_pLoopMatchMinimumResponseFine->GetValue())
1611 const Pose2& rPose)
const
1614 kt_double bestSquaredDistance = DBL_MAX;
1621 if (squaredDistance < bestSquaredDistance)
1623 bestSquaredDistance = squaredDistance;
1624 pClosestScan = *iter;
1628 return pClosestScan;
1640 std::cout <<
"AddEdge: At least one vertex is invalid." << std::endl;
1674 if (isNewEdge ==
true)
1686 const std::vector<LocalizedRangeScanVector> nearChains =
FindNearChains(pScan);
1687 const_forEach(std::vector<LocalizedRangeScanVector>, &nearChains)
1700 rMeans.push_back(mean);
1701 rCovariances.push_back(covariance);
1713 assert(pClosestScan != NULL);
1720 LinkScans(pClosestScan, pScan, rMean, rCovariance);
1726 std::vector<LocalizedRangeScanVector> nearChains;
1739 if (pNearScan == pScan)
1745 if (find(processed.begin(), processed.end(), pNearScan) != processed.end())
1750 processed.push_back(pNearScan);
1754 std::list<LocalizedRangeScan*> chain;
1757 for (
kt_int32s candidateScanNum = pNearScan->
GetStateId() - 1; candidateScanNum >= 0; candidateScanNum--)
1763 if (pCandidateScan == pScan)
1765 isValidChain =
false;
1769 if (pCandidateScan == NULL)
1779 chain.push_front(pCandidateScan);
1780 processed.push_back(pCandidateScan);
1788 chain.push_back(pNearScan);
1792 for (
kt_int32u candidateScanNum = pNearScan->
GetStateId() + 1; candidateScanNum < end; candidateScanNum++)
1797 if (pCandidateScan == pScan)
1799 isValidChain =
false;
1803 if (pCandidateScan == NULL)
1813 chain.push_back(pCandidateScan);
1814 processed.push_back(pCandidateScan);
1826 std::copy(chain.begin(), chain.end(), std::inserter(tempChain, tempChain.begin()));
1828 nearChains.push_back(tempChain);
1841 return nearLinkedScans;
1847 std::vector<Vertex<LocalizedRangeScan>*> nearLinkedVertices =
m_pTraversal->TraverseForVertices(
GetVertex(pScan), pVisitor);
1850 return nearLinkedVertices;
1862 return nearLinkedScans;
1868 std::map<int, Vertex<LocalizedRangeScan>*>& vertices = vertexMap[name];
1870 std::vector<Vertex<LocalizedRangeScan>*> vertices_to_search;
1871 std::map<int, Vertex<LocalizedRangeScan>*>::iterator it;
1872 for (it = vertices.begin(); it != vertices.end(); ++it)
1876 vertices_to_search.push_back(it->second);
1880 const size_t dim = 2;
1883 const P2KD p2kd(vertices_to_search);
1890 std::vector<std::pair<size_t,double> > ret_matches;
1891 const double query_pt[2] = {refPose.
GetX(), refPose.
GetY()};
1893 const size_t num_results = index.radiusSearch(&query_pt[0], maxDistance, ret_matches, params);
1895 std::vector<Vertex<LocalizedRangeScan>*> rtn_vertices;
1896 rtn_vertices.reserve(ret_matches.size());
1897 for (uint i = 0; i != ret_matches.size(); i++)
1899 rtn_vertices.push_back(vertices_to_search[ret_matches[i].first]);
1901 return rtn_vertices;
1907 std::map<int, Vertex<LocalizedRangeScan>*>& vertices = vertexMap[name];
1909 std::vector<Vertex<LocalizedRangeScan>*> vertices_to_search;
1910 std::map<int, Vertex<LocalizedRangeScan>*>::iterator it;
1911 for (it = vertices.begin(); it != vertices.end(); ++it)
1915 vertices_to_search.push_back(it->second);
1919 size_t num_results = 1;
1920 const size_t dim = 2;
1923 const P2KD p2kd(vertices_to_search);
1930 std::vector<size_t> ret_index(num_results);
1931 std::vector<double> out_dist_sqr(num_results);
1932 const double query_pt[2] = {refPose.
GetX(), refPose.
GetY()};
1933 num_results = index.knnSearch(&query_pt[0], num_results, &ret_index[0], &out_dist_sqr[0]);
1935 if (num_results > 0)
1937 return vertices_to_search[ret_index[0]];
1947 assert(rMeans.size() == rCovariances.size());
1950 std::vector<Matrix3> inverses;
1951 inverses.reserve(rCovariances.size());
1964 Pose2 accumulatedPose;
1968 Pose2Vector::const_iterator meansIter = rMeans.begin();
1971 Pose2 pose = *meansIter;
1973 thetaX += cos(
angle);
1974 thetaY += sin(
angle);
1976 Matrix3 weight = inverseOfSumOfInverses * (*iter);
1977 accumulatedPose += weight * pose;
1982 thetaX /= rMeans.size();
1983 thetaY /= rMeans.size();
1984 accumulatedPose.
SetHeading(atan2(thetaY, thetaX));
1986 return accumulatedPose;
1990 const Name& rSensorName,
2003 for (; rStartNum < nScans; rStartNum++)
2007 if (pCandidateScan == NULL)
2018 if (find(nearLinkedScans.begin(), nearLinkedScans.end(), pCandidateScan) != nearLinkedScans.end())
2024 chain.push_back(pCandidateScan);
2048 if (pSolver != NULL)
2087 m_Initialized(false),
2088 m_Deserialized(false),
2089 m_pSequentialScanMatcher(NULL),
2090 m_pMapperSensorManager(NULL),
2092 m_pScanOptimizer(NULL)
2102 m_Initialized(false),
2103 m_Deserialized(false),
2104 m_pSequentialScanMatcher(NULL),
2105 m_pMapperSensorManager(NULL),
2107 m_pScanOptimizer(NULL)
2126 "When set to true, the mapper will use a scan matching algorithm. "
2127 "In most real-world situations this should be set to true so that the "
2128 "mapper algorithm can correct for noise and errors in odometry and "
2129 "scan data. In some simulator environments where the simulated scan "
2130 "and odometry data are very accurate, the scan matching algorithm can "
2131 "produce worse results. In those cases set this to false to improve "
2137 "UseScanBarycenter",
2138 "Use the barycenter of scan endpoints to define distances between "
2143 "MinimumTimeInterval",
2144 "Sets the minimum time between scans. If a new scan's time stamp is "
2145 "longer than MinimumTimeInterval from the previously processed scan, "
2146 "the mapper will use the data from the new scan. Otherwise, it will "
2147 "discard the new scan if it also does not meet the minimum travel "
2148 "distance and heading requirements. For performance reasons, it is "
2149 "generally it is a good idea to only process scans if a reasonable "
2150 "amount of time has passed. This parameter is particularly useful "
2151 "when there is a need to process scans while the robot is stationary.",
2155 "MinimumTravelDistance",
2156 "Sets the minimum travel between scans. If a new scan's position is "
2157 "more than minimumTravelDistance from the previous scan, the mapper "
2158 "will use the data from the new scan. Otherwise, it will discard the "
2159 "new scan if it also does not meet the minimum change in heading "
2160 "requirement. For performance reasons, generally it is a good idea to "
2161 "only process scans if the robot has moved a reasonable amount.",
2165 "MinimumTravelHeading",
2166 "Sets the minimum heading change between scans. If a new scan's "
2167 "heading is more than MinimumTravelHeading from the previous scan, the "
2168 "mapper will use the data from the new scan. Otherwise, it will "
2169 "discard the new scan if it also does not meet the minimum travel "
2170 "distance requirement. For performance reasons, generally it is a good "
2171 "idea to only process scans if the robot has moved a reasonable "
2177 "Scan buffer size is the length of the scan chain stored for scan "
2178 "matching. \"ScanBufferSize\" should be set to approximately "
2179 "\"ScanBufferMaximumScanDistance\" / \"MinimumTravelDistance\". The "
2180 "idea is to get an area approximately 20 meters long for scan "
2181 "matching. For example, if we add scans every MinimumTravelDistance == "
2182 "0.3 meters, then \"scanBufferSize\" should be 20 / 0.3 = 67.)",
2186 "ScanBufferMaximumScanDistance",
2187 "Scan buffer maximum scan distance is the maximum distance between the "
2188 "first and last scans in the scan chain stored for matching.",
2192 "LinkMatchMinimumResponseFine",
2193 "Scans are linked only if the correlation response value is greater "
2198 "LinkScanMaximumDistance",
2199 "Maximum distance between linked scans. Scans that are farther apart "
2200 "will not be linked regardless of the correlation response value.",
2204 "LoopSearchMaximumDistance",
2205 "Scans less than this distance from the current position will be "
2206 "considered for a match in loop closure.",
2211 "Enable/disable loop closure.",
2215 "LoopMatchMinimumChainSize",
2216 "When the loop closure detection finds a candidate it must be part of "
2217 "a large set of linked scans. If the chain of scans is less than this "
2218 "value we do not attempt to close the loop.",
2222 "LoopMatchMaximumVarianceCoarse",
2223 "The co-variance values for a possible loop closure have to be less "
2224 "than this value to consider a viable solution. This applies to the "
2229 "LoopMatchMinimumResponseCoarse",
2230 "If response is larger then this, then initiate loop closure search at "
2231 "the coarse resolution.",
2235 "LoopMatchMinimumResponseFine",
2236 "If response is larger then this, then initiate loop closure search at "
2237 "the fine resolution.",
2244 "CorrelationSearchSpaceDimension",
2245 "The size of the search grid used by the matcher. The search grid will "
2246 "have the size CorrelationSearchSpaceDimension * "
2247 "CorrelationSearchSpaceDimension",
2251 "CorrelationSearchSpaceResolution",
2252 "The resolution (size of a grid cell) of the correlation grid.",
2256 "CorrelationSearchSpaceSmearDeviation",
2257 "The point readings are smeared by this value in X and Y to create a "
2258 "smoother response.",
2266 "LoopSearchSpaceDimension",
2267 "The size of the search grid used by the matcher.",
2271 "LoopSearchSpaceResolution",
2272 "The resolution (size of a grid cell) of the correlation grid.",
2276 "LoopSearchSpaceSmearDeviation",
2277 "The point readings are smeared by this value in X and Y to create a "
2278 "smoother response.",
2285 "DistanceVariancePenalty",
2286 "Variance of penalty for deviating from odometry when scan-matching. "
2287 "The penalty is a multiplier (less than 1.0) is a function of the "
2288 "delta of the scan position being tested and the odometric pose.",
2292 "AngleVariancePenalty",
2293 "See DistanceVariancePenalty.",
2297 "FineSearchAngleOffset",
2298 "The range of angles to search during a fine search.",
2302 "CoarseSearchAngleOffset",
2303 "The range of angles to search during a coarse search.",
2307 "CoarseAngleResolution",
2308 "Resolution of angles to search during a coarse search.",
2312 "MinimumAnglePenalty",
2313 "Minimum value of the angle penalty multiplier so scores do not become "
2318 "MinimumDistancePenalty",
2319 "Minimum value of the distance penalty multiplier so scores do not "
2320 "become too small.",
2324 "UseResponseExpansion",
2325 "Whether to increase the search space if no good matches are initially "
2673 printf(
"Save To File %s \n",
filename.c_str());
2674 std::ofstream ofs(
filename.c_str());
2675 boost::archive::binary_oarchive oa(ofs, boost::archive::no_codecvt);
2676 oa << BOOST_SERIALIZATION_NVP(*
this);
2681 printf(
"Load From File %s \n",
filename.c_str());
2682 std::ifstream ifs(
filename.c_str());
2683 boost::archive::binary_iarchive ia(ifs, boost::archive::no_codecvt);
2684 ia >> BOOST_SERIALIZATION_NVP(*
this);
2726 if (pLaserRangeFinder == NULL || pScan == NULL || pLaserRangeFinder->
Validate(pScan) ==
false)
2741 if (pLastScan != NULL)
2806 if (pLaserRangeFinder == NULL || pScan == NULL ||
2807 pLaserRangeFinder->
Validate(pScan) ==
false)
2824 closetVertex->
GetObject()->GetStateId());
2865 std::vector<Name> deviceNames =
2876 if (addScanToLocalizationBuffer)
2897 if (pLaserRangeFinder == NULL || pScan == NULL ||
2898 pLaserRangeFinder->
Validate(pScan) ==
false)
2914 if (pLastScan != NULL)
2980 lsv.
vertex = scan_vertex;
2991 oldLSV.
vertex->RemoveObject();
3009 oldLSV.
vertex->RemoveObject();
3021 for (uint i = 0; i != names.size(); i++)
3033 std::vector<Vertex<LocalizedRangeScan>*> adjVerts =
3035 for (
int i = 0; i != adjVerts.size(); i++)
3037 std::vector<Edge<LocalizedRangeScan>*> adjEdges = adjVerts[i]->GetEdges();
3039 for (
int j=0; j!=adjEdges.size(); j++)
3041 if (adjEdges[j]->GetTarget() == vertex_to_remove ||
3042 adjEdges[j]->GetSource() == vertex_to_remove)
3044 adjVerts[i]->RemoveEdge(j);
3046 adjEdges[j]->GetSource()->GetObject()->GetUniqueId(),
3047 adjEdges[j]->GetTarget()->GetObject()->GetUniqueId());
3049 std::vector<Edge<LocalizedRangeScan>*>::iterator edgeGraphIt =
3050 std::find(edges.begin(), edges.end(), adjEdges[j]);
3052 if (edgeGraphIt == edges.end())
3054 std::cout <<
"Edge not found in graph to remove!" << std::endl;
3058 int posEdge = edgeGraphIt - edges.begin();
3060 delete *edgeGraphIt;
3061 *edgeGraphIt = NULL;
3067 std::cout <<
"Failed to find any edge in adj. vertex" <<
3068 " with a matching vertex to current!" << std::endl;
3076 std::map<Name, std::map<int, Vertex<LocalizedRangeScan>*> >
3078 std::map<int, Vertex<LocalizedRangeScan>*> graphVertices =
3079 vertexMap[vertex_to_remove->
GetObject()->GetSensorName()];
3080 std::map<int, Vertex<LocalizedRangeScan>*>::iterator
3081 vertexGraphIt = graphVertices.find(vertex_to_remove->
GetObject()->GetStateId());
3082 if (vertexGraphIt != graphVertices.end())
3085 vertexGraphIt->second->GetObject()->GetStateId());
3089 std::cout <<
"Vertex not found in graph to remove!" << std::endl;
3106 if (pLaserRangeFinder == NULL || pScan == NULL ||
3107 pLaserRangeFinder->
Validate(pScan) ==
false)
3159 std::vector<Name> deviceNames =
3191 if (pLastScan == NULL)
3254 std::vector<MapperListener*>::iterator iter = std::find(
m_Listeners.begin(),
m_Listeners.end(), pListener);
3265 (*iter)->Info(rInfo);
3275 if (pListener != NULL)
3277 pListener->
Debug(rInfo);
3288 if (pListener != NULL)
3301 if (pListener != NULL)
3314 if (pListener != NULL)