00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <sstream>
00019 #include <fstream>
00020 #include <stdexcept>
00021 #include <queue>
00022 #include <set>
00023 #include <list>
00024 #include <iterator>
00025
00026 #include <math.h>
00027 #include <assert.h>
00028
00029 #include "OpenKarto/Mapper.h"
00030
00031 namespace karto
00032 {
00033
00034
00035
00036
00037 #define MAX_VARIANCE 500.0
00038 #define DISTANCE_PENALTY_GAIN 0.2
00039 #define ANGLE_PENALTY_GAIN 0.2
00040
00044
00048 class ScanManager
00049 {
00050 public:
00054 ScanManager(kt_int32u runningBufferMaximumSize, kt_double runningBufferMaximumDistance)
00055 : m_pLastScan(NULL)
00056 , m_RunningBufferMaximumSize(runningBufferMaximumSize)
00057 , m_RunningBufferMaximumDistance(runningBufferMaximumDistance)
00058 {
00059 }
00060
00064 virtual ~ScanManager()
00065 {
00066 Clear();
00067 }
00068
00069 public:
00074 inline void AddScan(LocalizedRangeScan* pScan, kt_int32s uniqueId)
00075 {
00076
00077 pScan->SetStateId(static_cast<kt_int32u>(m_Scans.size()));
00078
00079
00080 pScan->SetUniqueId(uniqueId);
00081
00082
00083 m_Scans.push_back(pScan);
00084 }
00085
00091 inline LocalizedRangeScan* GetLastScan()
00092 {
00093 return m_pLastScan;
00094 }
00095
00100 inline void SetLastScan(LocalizedRangeScan* pScan)
00101 {
00102 m_pLastScan = pScan;
00103 }
00104
00109 inline LocalizedRangeScanVector& GetScans()
00110 {
00111 return m_Scans;
00112 }
00113
00118 inline LocalizedRangeScanVector& GetRunningScans()
00119 {
00120 return m_RunningScans;
00121 }
00122
00127 void AddRunningScan(LocalizedRangeScan* pScan)
00128 {
00129 m_RunningScans.push_back(pScan);
00130
00131
00132 Pose2 frontScanPose = m_RunningScans.front()->GetSensorPose();
00133 Pose2 backScanPose = m_RunningScans.back()->GetSensorPose();
00134
00135
00136 kt_double squaredDistance = frontScanPose.GetPosition().SquaredDistance(backScanPose.GetPosition());
00137 while (m_RunningScans.size() > m_RunningBufferMaximumSize || squaredDistance > math::Square(m_RunningBufferMaximumDistance) - KT_TOLERANCE)
00138 {
00139
00140 m_RunningScans.erase(m_RunningScans.begin());
00141
00142
00143 frontScanPose = m_RunningScans.front()->GetSensorPose();
00144 backScanPose = m_RunningScans.back()->GetSensorPose();
00145 squaredDistance = frontScanPose.GetPosition().SquaredDistance(backScanPose.GetPosition());
00146 }
00147 }
00148
00152 void Clear()
00153 {
00154 m_Scans.clear();
00155 m_RunningScans.clear();
00156 }
00157
00158 private:
00159 LocalizedRangeScanVector m_Scans;
00160 LocalizedRangeScanVector m_RunningScans;
00161 LocalizedRangeScan* m_pLastScan;
00162
00163 kt_int32u m_RunningBufferMaximumSize;
00164 kt_double m_RunningBufferMaximumDistance;
00165 };
00166
00170
00171 void MapperSensorManager::RegisterSensor(const Name& rSensorName)
00172 {
00173 if(GetScanManager(rSensorName) == NULL)
00174 {
00175 m_ScanManagers[rSensorName] = new ScanManager(m_RunningBufferMaximumSize, m_RunningBufferMaximumDistance);
00176 }
00177 }
00178
00179
00186 LocalizedRangeScan* MapperSensorManager::GetScan(const Name& rSensorName, kt_int32s scanIndex)
00187 {
00188 ScanManager* pScanManager = GetScanManager(rSensorName);
00189 if(pScanManager != NULL)
00190 {
00191 return pScanManager->GetScans().at(scanIndex);
00192 }
00193
00194 assert(false);
00195 return NULL;
00196 }
00197
00203 inline LocalizedRangeScan* MapperSensorManager::GetLastScan(const Name& rSensorName)
00204 {
00205 RegisterSensor(rSensorName);
00206
00207 return GetScanManager(rSensorName)->GetLastScan();
00208 }
00209
00214 inline void MapperSensorManager::SetLastScan(LocalizedRangeScan* pScan)
00215 {
00216 GetScanManager(pScan)->SetLastScan(pScan);
00217 }
00218
00223 void MapperSensorManager::AddScan(LocalizedRangeScan* pScan)
00224 {
00225 GetScanManager(pScan)->AddScan(pScan, m_NextScanId);
00226 m_Scans.push_back(pScan);
00227 m_NextScanId++;
00228 }
00229
00234 inline void MapperSensorManager::AddRunningScan(LocalizedRangeScan* pScan)
00235 {
00236 GetScanManager(pScan)->AddRunningScan(pScan);
00237 }
00238
00244 inline LocalizedRangeScanVector& MapperSensorManager::GetScans(const Name& rSensorName)
00245 {
00246 return GetScanManager(rSensorName)->GetScans();
00247 }
00248
00254 inline LocalizedRangeScanVector& MapperSensorManager::GetRunningScans(const Name& rSensorName)
00255 {
00256 return GetScanManager(rSensorName)->GetRunningScans();
00257 }
00258
00263 LocalizedRangeScanVector MapperSensorManager::GetAllScans()
00264 {
00265 LocalizedRangeScanVector scans;
00266
00267 forEach(ScanManagerMap, &m_ScanManagers)
00268 {
00269 LocalizedRangeScanVector& rScans = iter->second->GetScans();
00270
00271 scans.insert(scans.end(), rScans.begin(), rScans.end());
00272 }
00273
00274 return scans;
00275 }
00276
00280 void MapperSensorManager::Clear()
00281 {
00282
00283
00284 forEach(ScanManagerMap, &m_ScanManagers)
00285 {
00286 delete iter->second;
00287 }
00288
00289 m_ScanManagers.clear();
00290 }
00291
00295
00296 ScanMatcher::~ScanMatcher()
00297 {
00298 delete m_pCorrelationGrid;
00299 delete m_pSearchSpaceProbs;
00300 delete m_pGridLookup;
00301 }
00302
00303 ScanMatcher* ScanMatcher::Create(Mapper* pMapper, kt_double searchSize, kt_double resolution, kt_double smearDeviation, kt_double rangeThreshold)
00304 {
00305
00306 if (resolution <= 0)
00307 {
00308 return NULL;
00309 }
00310 if (searchSize <= 0)
00311 {
00312 return NULL;
00313 }
00314 if (smearDeviation < 0)
00315 {
00316 return NULL;
00317 }
00318 if (rangeThreshold <= 0)
00319 {
00320 return NULL;
00321 }
00322
00323 assert(math::DoubleEqual(math::Round(searchSize / resolution), (searchSize / resolution)));
00324
00325
00326 kt_int32u searchSpaceSideSize = static_cast<kt_int32u>(math::Round(searchSize / resolution) + 1);
00327
00328
00329
00330 kt_int32u pointReadingMargin = static_cast<kt_int32u>(ceil(rangeThreshold / resolution));
00331
00332 kt_int32s gridSize = searchSpaceSideSize + 2 * pointReadingMargin;
00333
00334
00335 assert(gridSize % 2 == 1);
00336 CorrelationGrid* pCorrelationGrid = CorrelationGrid::CreateGrid(gridSize, gridSize, resolution, smearDeviation);
00337
00338
00339 Grid<kt_double>* pSearchSpaceProbs = Grid<kt_double>::CreateGrid(searchSpaceSideSize, searchSpaceSideSize, resolution);
00340
00341 ScanMatcher* pScanMatcher = new ScanMatcher(pMapper);
00342 pScanMatcher->m_pCorrelationGrid = pCorrelationGrid;
00343 pScanMatcher->m_pSearchSpaceProbs = pSearchSpaceProbs;
00344 pScanMatcher->m_pGridLookup = new GridIndexLookup<kt_int8u>(pCorrelationGrid);
00345
00346 return pScanMatcher;
00347 }
00348
00359 kt_double ScanMatcher::MatchScan(LocalizedRangeScan* pScan, const LocalizedRangeScanVector& rBaseScans, Pose2& rMean, Matrix3& rCovariance,
00360 kt_bool doPenalize, kt_bool doRefineMatch)
00361 {
00363
00364
00365
00366 Pose2 scanPose = pScan->GetSensorPose();
00367
00368
00369
00370 if (pScan->GetNumberOfRangeReadings() == 0)
00371 {
00372 rMean = scanPose;
00373
00374
00375 rCovariance(0, 0) = MAX_VARIANCE;
00376 rCovariance(1, 1) = MAX_VARIANCE;
00377 rCovariance(2, 2) = 4 * math::Square(m_pMapper->m_pCoarseAngleResolution->GetValue());
00378
00379 return 0.0;
00380 }
00381
00382
00383 Rectangle2<kt_int32s> roi = m_pCorrelationGrid->GetROI();
00384
00385
00386 Vector2<kt_double> offset;
00387 offset.SetX(scanPose.GetX() - (0.5 * (roi.GetWidth() - 1) * m_pCorrelationGrid->GetResolution()));
00388 offset.SetY(scanPose.GetY() - (0.5 * (roi.GetHeight() - 1) * m_pCorrelationGrid->GetResolution()));
00389
00390
00391 m_pCorrelationGrid->GetCoordinateConverter()->SetOffset(offset);
00392
00394
00395
00396 AddScans(rBaseScans, scanPose.GetPosition());
00397
00398
00399 Vector2<kt_double> searchDimensions(m_pSearchSpaceProbs->GetWidth(), m_pSearchSpaceProbs->GetHeight());
00400 Vector2<kt_double> coarseSearchOffset(0.5 * (searchDimensions.GetX() - 1) * m_pCorrelationGrid->GetResolution(), 0.5 * (searchDimensions.GetY() - 1) * m_pCorrelationGrid->GetResolution());
00401
00402
00403 Vector2<kt_double> coarseSearchResolution(2 * m_pCorrelationGrid->GetResolution(), 2 * m_pCorrelationGrid->GetResolution());
00404
00405
00406 kt_double bestResponse = CorrelateScan(pScan, scanPose, coarseSearchOffset, coarseSearchResolution, m_pMapper->m_pCoarseSearchAngleOffset->GetValue(), m_pMapper->m_pCoarseAngleResolution->GetValue(), doPenalize, rMean, rCovariance, false);
00407
00408 if (m_pMapper->m_pUseResponseExpansion->GetValue() == true)
00409 {
00410 if (math::DoubleEqual(bestResponse, 0.0))
00411 {
00412 #ifdef KARTO_DEBUG
00413 std::cout << "Mapper Info: Expanding response search space!" << std::endl;
00414 #endif
00415
00416 kt_double newSearchAngleOffset = m_pMapper->m_pCoarseSearchAngleOffset->GetValue();
00417 for (kt_int32u i = 0; i < 3; i++)
00418 {
00419 newSearchAngleOffset += math::DegreesToRadians(20);
00420
00421 bestResponse = CorrelateScan(pScan, scanPose, coarseSearchOffset, coarseSearchResolution, newSearchAngleOffset, m_pMapper->m_pCoarseAngleResolution->GetValue(), doPenalize, rMean, rCovariance, false);
00422
00423 if (math::DoubleEqual(bestResponse, 0.0) == false)
00424 {
00425 break;
00426 }
00427 }
00428
00429 #ifdef KARTO_DEBUG
00430 if (math::DoubleEqual(bestResponse, 0.0))
00431 {
00432 std::cout << "Mapper Warning: Unable to calculate response!" << std::endl;
00433 }
00434 #endif
00435 }
00436 }
00437
00438 if (doRefineMatch)
00439 {
00440 Vector2<kt_double> fineSearchOffset(coarseSearchResolution * 0.5);
00441 Vector2<kt_double> fineSearchResolution(m_pCorrelationGrid->GetResolution(), m_pCorrelationGrid->GetResolution());
00442 bestResponse = CorrelateScan(pScan, rMean, fineSearchOffset, fineSearchResolution, 0.5 * m_pMapper->m_pCoarseAngleResolution->GetValue(), m_pMapper->m_pFineSearchAngleOffset->GetValue(), doPenalize, rMean, rCovariance, true);
00443 }
00444
00445 #ifdef KARTO_DEBUG
00446 std::cout << " BEST POSE = " << rMean << " BEST RESPONSE = " << bestResponse << ", VARIANCE = " << rCovariance(0, 0) << ", " << rCovariance(1, 1) << std::endl;
00447 #endif
00448
00449 assert(math::InRange(rMean.GetHeading(), -KT_PI, KT_PI));
00450
00451 return bestResponse;
00452 }
00453
00470 kt_double ScanMatcher::CorrelateScan(LocalizedRangeScan* pScan, const Pose2& rSearchCenter, const Vector2<kt_double>& rSearchSpaceOffset, const Vector2<kt_double>& rSearchSpaceResolution,
00471 kt_double searchAngleOffset, kt_double searchAngleResolution, kt_bool doPenalize, Pose2& rMean, Matrix3& rCovariance, kt_bool doingFineMatch)
00472 {
00473 assert(searchAngleResolution != 0.0);
00474
00475
00476 m_pGridLookup->ComputeOffsets(pScan, rSearchCenter.GetHeading(), searchAngleOffset, searchAngleResolution);
00477
00478
00479 if (!doingFineMatch)
00480 {
00481 m_pSearchSpaceProbs->Clear();
00482
00483
00484 Vector2<kt_double> offset(rSearchCenter.GetPosition() - rSearchSpaceOffset);
00485 m_pSearchSpaceProbs->GetCoordinateConverter()->SetOffset(offset);
00486 }
00487
00488
00489
00490 std::vector<kt_double> xPoses;
00491 kt_int32u nX = static_cast<kt_int32u>(math::Round(rSearchSpaceOffset.GetX() * 2.0 / rSearchSpaceResolution.GetX()) + 1);
00492 kt_double startX = -rSearchSpaceOffset.GetX();
00493 for (kt_int32u xIndex = 0; xIndex < nX; xIndex++)
00494 {
00495 xPoses.push_back(startX + xIndex * rSearchSpaceResolution.GetX());
00496 }
00497 assert(math::DoubleEqual(xPoses.back(), -startX));
00498
00499 std::vector<kt_double> yPoses;
00500 kt_int32u nY = static_cast<kt_int32u>(math::Round(rSearchSpaceOffset.GetY() * 2.0 / rSearchSpaceResolution.GetY()) + 1);
00501 kt_double startY = -rSearchSpaceOffset.GetY();
00502 for (kt_int32u yIndex = 0; yIndex < nY; yIndex++)
00503 {
00504 yPoses.push_back(startY + yIndex * rSearchSpaceResolution.GetY());
00505 }
00506 assert(math::DoubleEqual(yPoses.back(), -startY));
00507
00508
00509 kt_int32u nAngles = static_cast<kt_int32u>(math::Round(searchAngleOffset * 2.0 / searchAngleResolution) + 1);
00510
00511 kt_int32u poseResponseSize = static_cast<kt_int32u>(xPoses.size() * yPoses.size() * nAngles);
00512
00513
00514 std::pair<kt_double, Pose2>* pPoseResponse = new std::pair<kt_double, Pose2>[poseResponseSize];
00515
00516 Vector2<kt_int32s> startGridPoint = m_pCorrelationGrid->WorldToGrid(Vector2<kt_double>(rSearchCenter.GetX() + startX, rSearchCenter.GetY() + startY));
00517
00518 kt_int32u poseResponseCounter = 0;
00519 forEachAs(std::vector<kt_double>, &yPoses, yIter)
00520 {
00521 kt_double y = *yIter;
00522 kt_double newPositionY = rSearchCenter.GetY() + y;
00523 kt_double squareY = math::Square(y);
00524
00525 forEachAs(std::vector<kt_double>, &xPoses, xIter)
00526 {
00527 kt_double x = *xIter;
00528 kt_double newPositionX = rSearchCenter.GetX() + x;
00529 kt_double squareX = math::Square(x);
00530
00531 Vector2<kt_int32s> gridPoint = m_pCorrelationGrid->WorldToGrid(Vector2<kt_double>(newPositionX, newPositionY));
00532 kt_int32s gridIndex = m_pCorrelationGrid->GridIndex(gridPoint);
00533 assert(gridIndex >= 0);
00534
00535 kt_double angle = 0.0;
00536 kt_double startAngle = rSearchCenter.GetHeading() - searchAngleOffset;
00537 for (kt_int32u angleIndex = 0; angleIndex < nAngles; angleIndex++)
00538 {
00539 angle = startAngle + angleIndex * searchAngleResolution;
00540
00541 kt_double response = GetResponse(angleIndex, gridIndex);
00542 if (doPenalize && (math::DoubleEqual(response, 0.0) == false))
00543 {
00544
00545
00546 kt_double squaredDistance = squareX + squareY;
00547 kt_double distancePenalty = 1.0 - (DISTANCE_PENALTY_GAIN * squaredDistance / m_pMapper->m_pDistanceVariancePenalty->GetValue());
00548 distancePenalty = math::Maximum(distancePenalty, m_pMapper->m_pMinimumDistancePenalty->GetValue());
00549
00550 kt_double squaredAngleDistance = math::Square(angle - rSearchCenter.GetHeading());
00551 kt_double anglePenalty = 1.0 - (ANGLE_PENALTY_GAIN * squaredAngleDistance / m_pMapper->m_pAngleVariancePenalty->GetValue());
00552 anglePenalty = math::Maximum(anglePenalty, m_pMapper->m_pMinimumAnglePenalty->GetValue());
00553
00554 response *= (distancePenalty * anglePenalty);
00555 }
00556
00557
00558 pPoseResponse[poseResponseCounter] = std::pair<kt_double, Pose2>(response, Pose2(newPositionX, newPositionY, math::NormalizeAngle(angle)));
00559 poseResponseCounter++;
00560 }
00561
00562 assert(math::DoubleEqual(angle, rSearchCenter.GetHeading() + searchAngleOffset));
00563 }
00564 }
00565
00566 assert(poseResponseSize == poseResponseCounter);
00567
00568
00569 kt_double bestResponse = -1;
00570 for (kt_int32u i = 0; i < poseResponseSize; i++)
00571 {
00572 bestResponse = math::Maximum(bestResponse, pPoseResponse[i].first);
00573
00574
00575 if (!doingFineMatch)
00576 {
00577 const Pose2& rPose = pPoseResponse[i].second;
00578 Vector2<kt_int32s> grid = m_pSearchSpaceProbs->WorldToGrid(rPose.GetPosition());
00579
00580 kt_double* ptr = (kt_double*)m_pSearchSpaceProbs->GetDataPointer(grid);
00581 if (ptr == NULL)
00582 {
00583 throw std::runtime_error("Mapper FATAL ERROR - Index out of range in probability search!");
00584 }
00585
00586 *ptr = math::Maximum(pPoseResponse[i].first, *ptr);
00587 }
00588 }
00589
00590
00591 Vector2<kt_double> averagePosition;
00592 kt_double thetaX = 0.0;
00593 kt_double thetaY = 0.0;
00594 kt_int32s averagePoseCount = 0;
00595 for (kt_int32u i = 0; i < poseResponseSize; i++)
00596 {
00597 if (math::DoubleEqual(pPoseResponse[i].first, bestResponse))
00598 {
00599 averagePosition += pPoseResponse[i].second.GetPosition();
00600
00601 kt_double heading = pPoseResponse[i].second.GetHeading();
00602 thetaX += cos(heading);
00603 thetaY += sin(heading);
00604
00605 averagePoseCount++;
00606 }
00607 }
00608
00609 Pose2 averagePose;
00610 if (averagePoseCount > 0)
00611 {
00612 averagePosition /= averagePoseCount;
00613
00614 thetaX /= averagePoseCount;
00615 thetaY /= averagePoseCount;
00616
00617 averagePose = Pose2(averagePosition, atan2(thetaY, thetaX));
00618 }
00619 else
00620 {
00621 throw std::runtime_error("Mapper FATAL ERROR - Unable to find best position");
00622 }
00623
00624
00625 delete [] pPoseResponse;
00626
00627 #ifdef KARTO_DEBUG
00628 std::cout << "bestPose: " << averagePose << std::endl;
00629 std::cout << "bestResponse: " << bestResponse << std::endl;
00630 #endif
00631
00632 if (!doingFineMatch)
00633 {
00634 ComputePositionalCovariance(averagePose, bestResponse, rSearchCenter, rSearchSpaceOffset, rSearchSpaceResolution, searchAngleResolution, rCovariance);
00635 }
00636 else
00637 {
00638 ComputeAngularCovariance(averagePose, bestResponse, rSearchCenter, searchAngleOffset, searchAngleResolution, rCovariance);
00639 }
00640
00641 rMean = averagePose;
00642
00643 #ifdef KARTO_DEBUG
00644 std::cout << "bestPose: " << averagePose << std::endl;
00645 #endif
00646
00647 if (bestResponse > 1.0)
00648 {
00649 bestResponse = 1.0;
00650 }
00651
00652 assert(math::InRange(bestResponse, 0.0, 1.0));
00653 assert(math::InRange(rMean.GetHeading(), -KT_PI, KT_PI));
00654
00655 return bestResponse;
00656 }
00657
00668 void ScanMatcher::ComputePositionalCovariance(const Pose2& rBestPose, kt_double bestResponse, const Pose2& rSearchCenter,
00669 const Vector2<kt_double>& rSearchSpaceOffset, const Vector2<kt_double>& rSearchSpaceResolution,
00670 kt_double searchAngleResolution, Matrix3& rCovariance)
00671 {
00672
00673 rCovariance.SetToIdentity();
00674
00675
00676 if (bestResponse < KT_TOLERANCE)
00677 {
00678 rCovariance(0, 0) = MAX_VARIANCE;
00679 rCovariance(1, 1) = MAX_VARIANCE;
00680 rCovariance(2, 2) = 4 * math::Square(searchAngleResolution);
00681
00682 return;
00683 }
00684
00685 kt_double accumulatedVarianceXX = 0;
00686 kt_double accumulatedVarianceXY = 0;
00687 kt_double accumulatedVarianceYY = 0;
00688 kt_double norm = 0;
00689
00690 kt_double dx = rBestPose.GetX() - rSearchCenter.GetX();
00691 kt_double dy = rBestPose.GetY() - rSearchCenter.GetY();
00692
00693 kt_double offsetX = rSearchSpaceOffset.GetX();
00694 kt_double offsetY = rSearchSpaceOffset.GetY();
00695
00696 kt_int32u nX = static_cast<kt_int32u>(math::Round(offsetX * 2.0 / rSearchSpaceResolution.GetX()) + 1);
00697 kt_double startX = -offsetX;
00698 assert(math::DoubleEqual(startX + (nX - 1) * rSearchSpaceResolution.GetX(), -startX));
00699
00700 kt_int32u nY = static_cast<kt_int32u>(math::Round(offsetY * 2.0 / rSearchSpaceResolution.GetY()) + 1);
00701 kt_double startY = -offsetY;
00702 assert(math::DoubleEqual(startY + (nY - 1) * rSearchSpaceResolution.GetY(), -startY));
00703
00704 for (kt_int32u yIndex = 0; yIndex < nY; yIndex++)
00705 {
00706 kt_double y = startY + yIndex * rSearchSpaceResolution.GetY();
00707
00708 for (kt_int32u xIndex = 0; xIndex < nX; xIndex++)
00709 {
00710 kt_double x = startX + xIndex * rSearchSpaceResolution.GetX();
00711
00712 Vector2<kt_int32s> gridPoint = m_pSearchSpaceProbs->WorldToGrid(Vector2<kt_double>(rSearchCenter.GetX() + x, rSearchCenter.GetY() + y));
00713 kt_double response = *(m_pSearchSpaceProbs->GetDataPointer(gridPoint));
00714
00715
00716 if (response >= (bestResponse - 0.1))
00717 {
00718 norm += response;
00719 accumulatedVarianceXX += (math::Square(x - dx) * response);
00720 accumulatedVarianceXY += ((x - dx) * (y - dy) * response);
00721 accumulatedVarianceYY += (math::Square(y - dy) * response);
00722 }
00723 }
00724 }
00725
00726 if (norm > KT_TOLERANCE)
00727 {
00728 kt_double varianceXX = accumulatedVarianceXX / norm;
00729 kt_double varianceXY = accumulatedVarianceXY / norm;
00730 kt_double varianceYY = accumulatedVarianceYY / norm;
00731 kt_double varianceTHTH = 4 * math::Square(searchAngleResolution);
00732
00733
00734
00735 kt_double minVarianceXX = 0.1 * math::Square(rSearchSpaceResolution.GetX());
00736 kt_double minVarianceYY = 0.1 * math::Square(rSearchSpaceResolution.GetY());
00737 varianceXX = math::Maximum(varianceXX, minVarianceXX);
00738 varianceYY = math::Maximum(varianceYY, minVarianceYY);
00739
00740
00741 kt_double multiplier = 1.0 / bestResponse;
00742 rCovariance(0, 0) = varianceXX * multiplier;
00743 rCovariance(0, 1) = varianceXY * multiplier;
00744 rCovariance(1, 0) = varianceXY * multiplier;
00745 rCovariance(1, 1) = varianceYY * multiplier;
00746 rCovariance(2, 2) = varianceTHTH;
00747 }
00748
00749
00750
00751 if (math::DoubleEqual(rCovariance(0, 0), 0.0))
00752 {
00753 rCovariance(0, 0) = MAX_VARIANCE;
00754 }
00755
00756 if (math::DoubleEqual(rCovariance(1, 1), 0.0))
00757 {
00758 rCovariance(1, 1) = MAX_VARIANCE;
00759 }
00760 }
00761
00771 void ScanMatcher::ComputeAngularCovariance(const Pose2& rBestPose, kt_double bestResponse, const Pose2& rSearchCenter,
00772 kt_double searchAngleOffset, kt_double searchAngleResolution, Matrix3& rCovariance)
00773 {
00774
00775
00776
00777 kt_double bestAngle = math::NormalizeAngleDifference(rBestPose.GetHeading(), rSearchCenter.GetHeading());
00778
00779 Vector2<kt_int32s> gridPoint = m_pCorrelationGrid->WorldToGrid(rBestPose.GetPosition());
00780 kt_int32s gridIndex = m_pCorrelationGrid->GridIndex(gridPoint);
00781
00782 kt_int32u nAngles = static_cast<kt_int32u>(math::Round(searchAngleOffset * 2 / searchAngleResolution) + 1);
00783
00784 kt_double angle = 0.0;
00785 kt_double startAngle = rSearchCenter.GetHeading() - searchAngleOffset;
00786
00787 kt_double norm = 0.0;
00788 kt_double accumulatedVarianceThTh = 0.0;
00789 for (kt_int32u angleIndex = 0; angleIndex < nAngles; angleIndex++)
00790 {
00791 angle = startAngle + angleIndex * searchAngleResolution;
00792 kt_double response = GetResponse(angleIndex, gridIndex);
00793
00794
00795 if (response >= (bestResponse - 0.1))
00796 {
00797 norm += response;
00798 accumulatedVarianceThTh += (math::Square(angle - bestAngle) * response);
00799 }
00800 }
00801 assert(math::DoubleEqual(angle, rSearchCenter.GetHeading() + searchAngleOffset));
00802
00803 if (norm > KT_TOLERANCE)
00804 {
00805 if (accumulatedVarianceThTh < KT_TOLERANCE)
00806 {
00807 accumulatedVarianceThTh = math::Square(searchAngleResolution);
00808 }
00809
00810 accumulatedVarianceThTh /= norm;
00811 }
00812 else
00813 {
00814 accumulatedVarianceThTh = 1000 * math::Square(searchAngleResolution);
00815 }
00816
00817 rCovariance(2, 2) = accumulatedVarianceThTh;
00818 }
00819
00825 void ScanMatcher::AddScans(const LocalizedRangeScanVector& rScans, Vector2<kt_double> viewPoint)
00826 {
00827 m_pCorrelationGrid->Clear();
00828
00829
00830 const_forEach(LocalizedRangeScanVector, &rScans)
00831 {
00832 AddScan(*iter, viewPoint);
00833 }
00834 }
00835
00842 void ScanMatcher::AddScan(LocalizedRangeScan* pScan, const Vector2<kt_double>& rViewPoint, kt_bool doSmear)
00843 {
00844 PointVectorDouble validPoints = FindValidPoints(pScan, rViewPoint);
00845
00846
00847 const_forEach(PointVectorDouble, &validPoints)
00848 {
00849 Vector2<kt_int32s> gridPoint = m_pCorrelationGrid->WorldToGrid(*iter);
00850 if (!math::IsUpTo(gridPoint.GetX(), m_pCorrelationGrid->GetROI().GetWidth()) || !math::IsUpTo(gridPoint.GetY(), m_pCorrelationGrid->GetROI().GetHeight()))
00851 {
00852
00853 continue;
00854 }
00855
00856 int gridIndex = m_pCorrelationGrid->GridIndex(gridPoint);
00857
00858
00859 if (m_pCorrelationGrid->GetDataPointer()[gridIndex] == GridStates_Occupied)
00860 {
00861
00862 continue;
00863 }
00864
00865 m_pCorrelationGrid->GetDataPointer()[gridIndex] = GridStates_Occupied;
00866
00867
00868 if (doSmear == true)
00869 {
00870 m_pCorrelationGrid->SmearPoint(gridPoint);
00871 }
00872 }
00873 }
00874
00881 PointVectorDouble ScanMatcher::FindValidPoints(LocalizedRangeScan* pScan, const Vector2<kt_double>& rViewPoint) const
00882 {
00883 const PointVectorDouble& rPointReadings = pScan->GetPointReadings();
00884
00885
00886 const kt_double minSquareDistance = math::Square(0.1);
00887
00888
00889
00890 PointVectorDouble::const_iterator trailingPointIter = rPointReadings.begin();
00891 PointVectorDouble validPoints;
00892
00893 Vector2<kt_double> firstPoint;
00894 kt_bool firstTime = true;
00895 const_forEach(PointVectorDouble, &rPointReadings)
00896 {
00897 Vector2<kt_double> currentPoint = *iter;
00898
00899 if (firstTime)
00900 {
00901 firstPoint = currentPoint;
00902 firstTime = false;
00903 }
00904
00905 Vector2<kt_double> delta = firstPoint - currentPoint;
00906 if (delta.SquaredLength() > minSquareDistance)
00907 {
00908
00909
00910
00911
00912
00913 double a = rViewPoint.GetY() - firstPoint.GetY();
00914 double b = firstPoint.GetX() - rViewPoint.GetX();
00915 double c = firstPoint.GetY() * rViewPoint.GetX() - firstPoint.GetX() * rViewPoint.GetY();
00916 double ss = currentPoint.GetX() * a + currentPoint.GetY() * b + c;
00917
00918
00919 firstPoint = currentPoint;
00920
00921 if (ss < 0.0)
00922 {
00923 trailingPointIter = iter;
00924 }
00925 else
00926 {
00927 for (; trailingPointIter != iter; trailingPointIter++)
00928 {
00929 validPoints.push_back(*trailingPointIter);
00930 }
00931 }
00932 }
00933 }
00934
00935 return validPoints;
00936 }
00937
00944 kt_double ScanMatcher::GetResponse(kt_int32u angleIndex, kt_int32s gridPositionIndex) const
00945 {
00946 kt_double response = 0.0;
00947
00948
00949 kt_int8u* pByte = m_pCorrelationGrid->GetDataPointer() + gridPositionIndex;
00950
00951 const LookupArray* pOffsets = m_pGridLookup->GetLookupArray(angleIndex);
00952 assert(pOffsets != NULL);
00953
00954
00955 kt_int32u nPoints = pOffsets->GetSize();
00956 if (nPoints == 0)
00957 {
00958 return response;
00959 }
00960
00961
00962 kt_int32s* pAngleIndexPointer = pOffsets->GetArrayPointer();
00963 for (kt_int32u i = 0; i < nPoints; i++)
00964 {
00965
00966 kt_int32s pointGridIndex = gridPositionIndex + pAngleIndexPointer[i];
00967 if (!math::IsUpTo(pointGridIndex, m_pCorrelationGrid->GetDataSize()))
00968 {
00969 continue;
00970 }
00971
00972
00973 response += pByte[pAngleIndexPointer[i]];
00974 }
00975
00976
00977 response /= (nPoints * GridStates_Occupied);
00978 assert(fabs(response) <= 1.0);
00979
00980 return response;
00981 }
00982
00983
00987
00988 template<typename T>
00989 class BreadthFirstTraversal : public GraphTraversal<T>
00990 {
00991 public:
00995 BreadthFirstTraversal(Graph<T>* pGraph)
00996 : GraphTraversal<T>(pGraph)
00997 {
00998 }
00999
01003 virtual ~BreadthFirstTraversal()
01004 {
01005 }
01006
01007 public:
01014 virtual std::vector<T*> Traverse(Vertex<T>* pStartVertex, Visitor<T>* pVisitor)
01015 {
01016 std::queue<Vertex<T>*> toVisit;
01017 std::set<Vertex<T>*> seenVertices;
01018 std::vector<Vertex<T>*> validVertices;
01019
01020 toVisit.push(pStartVertex);
01021 seenVertices.insert(pStartVertex);
01022
01023 do
01024 {
01025 Vertex<T>* pNext = toVisit.front();
01026 toVisit.pop();
01027
01028 if (pVisitor->Visit(pNext))
01029 {
01030
01031 validVertices.push_back(pNext);
01032
01033 std::vector<Vertex<T>*> adjacentVertices = pNext->GetAdjacentVertices();
01034 forEach(typename std::vector<Vertex<T>*>, &adjacentVertices)
01035 {
01036 Vertex<T>* pAdjacent = *iter;
01037
01038
01039 if (seenVertices.find(pAdjacent) == seenVertices.end())
01040 {
01041 toVisit.push(pAdjacent);
01042 seenVertices.insert(pAdjacent);
01043 }
01044 }
01045 }
01046 } while (toVisit.empty() == false);
01047
01048 std::vector<T*> objects;
01049 forEach(typename std::vector<Vertex<T>*>, &validVertices)
01050 {
01051 objects.push_back((*iter)->GetObject());
01052 }
01053
01054 return objects;
01055 }
01056
01057 };
01058
01062
01063 class NearScanVisitor : public Visitor<LocalizedRangeScan>
01064 {
01065 public:
01066 NearScanVisitor(LocalizedRangeScan* pScan, kt_double maxDistance, kt_bool useScanBarycenter)
01067 : m_MaxDistanceSquared(math::Square(maxDistance))
01068 , m_UseScanBarycenter(useScanBarycenter)
01069 {
01070 m_CenterPose = pScan->GetReferencePose(m_UseScanBarycenter);
01071 }
01072
01073 virtual kt_bool Visit(Vertex<LocalizedRangeScan>* pVertex)
01074 {
01075 LocalizedRangeScan* pScan = pVertex->GetObject();
01076
01077 Pose2 pose = pScan->GetReferencePose(m_UseScanBarycenter);
01078
01079 kt_double squaredDistance = pose.GetPosition().SquaredDistance(m_CenterPose.GetPosition());
01080 return (squaredDistance <= m_MaxDistanceSquared - KT_TOLERANCE);
01081 }
01082
01083 protected:
01084 Pose2 m_CenterPose;
01085 kt_double m_MaxDistanceSquared;
01086 kt_bool m_UseScanBarycenter;
01087
01088 };
01089
01093
01094 MapperGraph::MapperGraph(Mapper* pMapper, kt_double rangeThreshold)
01095 : m_pMapper(pMapper)
01096 {
01097 m_pLoopScanMatcher = ScanMatcher::Create(pMapper, m_pMapper->m_pLoopSearchSpaceDimension->GetValue(), m_pMapper->m_pLoopSearchSpaceResolution->GetValue(), m_pMapper->m_pLoopSearchSpaceSmearDeviation->GetValue(), rangeThreshold);
01098 assert(m_pLoopScanMatcher);
01099
01100 m_pTraversal = new BreadthFirstTraversal<LocalizedRangeScan>(this);
01101 }
01102
01103 MapperGraph::~MapperGraph()
01104 {
01105 delete m_pLoopScanMatcher;
01106 m_pLoopScanMatcher = NULL;
01107
01108 delete m_pTraversal;
01109 m_pTraversal = NULL;
01110 }
01111
01112 void MapperGraph::AddVertex(LocalizedRangeScan* pScan)
01113 {
01114 assert(pScan);
01115
01116 if(pScan != NULL)
01117 {
01118 Vertex<LocalizedRangeScan>* pVertex = new Vertex<LocalizedRangeScan>(pScan);
01119 Graph<LocalizedRangeScan>::AddVertex(pScan->GetSensorName(), pVertex);
01120 if (m_pMapper->m_pScanOptimizer != NULL)
01121 {
01122 m_pMapper->m_pScanOptimizer->AddNode(pVertex);
01123 }
01124 }
01125 }
01126
01127 void MapperGraph::AddEdges(LocalizedRangeScan* pScan, const Matrix3& rCovariance)
01128 {
01129 MapperSensorManager* pSensorManager = m_pMapper->m_pMapperSensorManager;
01130
01131 const Name& rSensorName = pScan->GetSensorName();
01132
01133
01134 kt_int32s previousScanNum = pScan->GetStateId() - 1;
01135 if (pSensorManager->GetLastScan(rSensorName) != NULL)
01136 {
01137 assert(previousScanNum >= 0);
01138 LinkScans(pSensorManager->GetScan(rSensorName, previousScanNum), pScan, pScan->GetSensorPose(), rCovariance);
01139 }
01140
01141 Pose2Vector means;
01142 std::vector<Matrix3> covariances;
01143
01144
01145 if (pSensorManager->GetLastScan(rSensorName) == NULL)
01146 {
01147 assert(pSensorManager->GetScans(rSensorName).size() == 1);
01148
01149 std::vector<Name> deviceNames = pSensorManager->GetSensorNames();
01150 forEach(std::vector<Name>, &deviceNames)
01151 {
01152 const Name& rCandidateSensorName = *iter;
01153
01154
01155 if ((rCandidateSensorName == rSensorName) || (pSensorManager->GetScans(rCandidateSensorName).empty()))
01156 {
01157 continue;
01158 }
01159
01160 Pose2 bestPose;
01161 Matrix3 covariance;
01162 kt_double response = m_pMapper->m_pSequentialScanMatcher->MatchScan(pScan, pSensorManager->GetScans(rCandidateSensorName), bestPose, covariance);
01163 LinkScans(pScan, pSensorManager->GetScan(rCandidateSensorName, 0), bestPose, covariance);
01164
01165
01166 if (response > m_pMapper->m_pLinkMatchMinimumResponseFine->GetValue())
01167 {
01168 means.push_back(bestPose);
01169 covariances.push_back(covariance);
01170 }
01171 }
01172 }
01173 else
01174 {
01175
01176 Pose2 scanPose = pScan->GetSensorPose();
01177 means.push_back(scanPose);
01178 covariances.push_back(rCovariance);
01179 LinkChainToScan(pSensorManager->GetRunningScans(rSensorName), pScan, scanPose, rCovariance);
01180 }
01181
01182
01183 LinkNearChains(pScan, means, covariances);
01184
01185 if (!means.empty())
01186 {
01187 pScan->SetSensorPose(ComputeWeightedMean(means, covariances));
01188 }
01189 }
01190
01191 kt_bool MapperGraph::TryCloseLoop(LocalizedRangeScan* pScan, const Name& rSensorName)
01192 {
01193 kt_bool loopClosed = false;
01194
01195 kt_int32u scanIndex = 0;
01196
01197 LocalizedRangeScanVector candidateChain = FindPossibleLoopClosure(pScan, rSensorName, scanIndex);
01198
01199 while (!candidateChain.empty())
01200 {
01201 Pose2 bestPose;
01202 Matrix3 covariance;
01203 kt_double coarseResponse = m_pLoopScanMatcher->MatchScan(pScan, candidateChain, bestPose, covariance, false, false);
01204
01205 std::stringstream stream;
01206 stream << "COARSE RESPONSE: " << coarseResponse << " (> " << m_pMapper->m_pLoopMatchMinimumResponseCoarse->GetValue() << ")" << std::endl;
01207 stream << " var: " << covariance(0, 0) << ", " << covariance(1, 1) << " (< " << m_pMapper->m_pLoopMatchMaximumVarianceCoarse->GetValue() << ")";
01208 m_pMapper->FireLoopClosureCheck(stream.str());
01209
01210 if ((coarseResponse > m_pMapper->m_pLoopMatchMinimumResponseCoarse->GetValue()) &&
01211 (covariance(0, 0) < m_pMapper->m_pLoopMatchMaximumVarianceCoarse->GetValue()) &&
01212 (covariance(1, 1) < m_pMapper->m_pLoopMatchMaximumVarianceCoarse->GetValue()))
01213 {
01214
01215 Pose2 oldPose = pScan->GetSensorPose();
01216
01217 pScan->SetSensorPose(bestPose);
01218 kt_double fineResponse = m_pMapper->m_pSequentialScanMatcher->MatchScan(pScan, candidateChain, bestPose, covariance, false);
01219
01220 std::stringstream stream1;
01221 stream1 << "FINE RESPONSE: " << fineResponse << " (>" << m_pMapper->m_pLoopMatchMinimumResponseFine->GetValue() << ")" << std::endl;
01222 m_pMapper->FireLoopClosureCheck(stream1.str());
01223
01224 if (fineResponse < m_pMapper->m_pLoopMatchMinimumResponseFine->GetValue())
01225 {
01226
01227 pScan->SetSensorPose(oldPose);
01228
01229 m_pMapper->FireLoopClosureCheck("REJECTED!");
01230 }
01231 else
01232 {
01233 m_pMapper->FireBeginLoopClosure("Closing loop...");
01234
01235 pScan->SetSensorPose(bestPose);
01236 LinkChainToScan(candidateChain, pScan, bestPose, covariance);
01237 CorrectPoses();
01238
01239 m_pMapper->FireEndLoopClosure("Loop closed!");
01240
01241 loopClosed = true;
01242 }
01243 }
01244
01245 candidateChain = FindPossibleLoopClosure(pScan, rSensorName, scanIndex);
01246 }
01247
01248 return loopClosed;
01249 }
01250
01251 LocalizedRangeScan* MapperGraph::GetClosestScanToPose(const LocalizedRangeScanVector& rScans, const Pose2& rPose) const
01252 {
01253 LocalizedRangeScan* pClosestScan = NULL;
01254 kt_double bestSquaredDistance = DBL_MAX;
01255
01256 const_forEach(LocalizedRangeScanVector, &rScans)
01257 {
01258 Pose2 scanPose = (*iter)->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());
01259
01260 kt_double squaredDistance = rPose.GetPosition().SquaredDistance(scanPose.GetPosition());
01261 if (squaredDistance < bestSquaredDistance)
01262 {
01263 bestSquaredDistance = squaredDistance;
01264 pClosestScan = *iter;
01265 }
01266 }
01267
01268 return pClosestScan;
01269 }
01270
01271 Edge<LocalizedRangeScan>* MapperGraph::AddEdge(LocalizedRangeScan* pSourceScan, LocalizedRangeScan* pTargetScan, kt_bool& rIsNewEdge)
01272 {
01273
01274 assert(pSourceScan->GetStateId() < (kt_int32s)m_Vertices[pSourceScan->GetSensorName()].size());
01275 assert(pTargetScan->GetStateId() < (kt_int32s)m_Vertices[pTargetScan->GetSensorName()].size());
01276
01277 Vertex<LocalizedRangeScan>* v1 = m_Vertices[pSourceScan->GetSensorName()][pSourceScan->GetStateId()];
01278 Vertex<LocalizedRangeScan>* v2 = m_Vertices[pTargetScan->GetSensorName()][pTargetScan->GetStateId()];
01279
01280
01281 const_forEach(std::vector<Edge<LocalizedRangeScan>*>, &(v1->GetEdges()))
01282 {
01283 Edge<LocalizedRangeScan>* pEdge = *iter;
01284
01285 if (pEdge->GetTarget() == v2)
01286 {
01287 rIsNewEdge = false;
01288 return pEdge;
01289 }
01290 }
01291
01292 Edge<LocalizedRangeScan>* pEdge = new Edge<LocalizedRangeScan>(v1, v2);
01293 Graph<LocalizedRangeScan>::AddEdge(pEdge);
01294 rIsNewEdge = true;
01295 return pEdge;
01296 }
01297
01298 void MapperGraph::LinkScans(LocalizedRangeScan* pFromScan, LocalizedRangeScan* pToScan, const Pose2& rMean, const Matrix3& rCovariance)
01299 {
01300 kt_bool isNewEdge = true;
01301 Edge<LocalizedRangeScan>* pEdge = AddEdge(pFromScan, pToScan, isNewEdge);
01302
01303
01304 if (isNewEdge == true)
01305 {
01306 pEdge->SetLabel(new LinkInfo(pFromScan->GetSensorPose(), rMean, rCovariance));
01307 if (m_pMapper->m_pScanOptimizer != NULL)
01308 {
01309 m_pMapper->m_pScanOptimizer->AddConstraint(pEdge);
01310 }
01311 }
01312 }
01313
01314 void MapperGraph::LinkNearChains(LocalizedRangeScan* pScan, Pose2Vector& rMeans, std::vector<Matrix3>& rCovariances)
01315 {
01316 const std::vector<LocalizedRangeScanVector> nearChains = FindNearChains(pScan);
01317 const_forEach(std::vector<LocalizedRangeScanVector>, &nearChains)
01318 {
01319 if (iter->size() < m_pMapper->m_pLoopMatchMinimumChainSize->GetValue())
01320 {
01321 continue;
01322 }
01323
01324 Pose2 mean;
01325 Matrix3 covariance;
01326
01327 kt_double response = m_pMapper->m_pSequentialScanMatcher->MatchScan(pScan, *iter, mean, covariance, false);
01328 if (response > m_pMapper->m_pLinkMatchMinimumResponseFine->GetValue() - KT_TOLERANCE)
01329 {
01330 rMeans.push_back(mean);
01331 rCovariances.push_back(covariance);
01332 LinkChainToScan(*iter, pScan, mean, covariance);
01333 }
01334 }
01335 }
01336
01337 void MapperGraph::LinkChainToScan(const LocalizedRangeScanVector& rChain, LocalizedRangeScan* pScan, const Pose2& rMean, const Matrix3& rCovariance)
01338 {
01339 Pose2 pose = pScan->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());
01340
01341 LocalizedRangeScan* pClosestScan = GetClosestScanToPose(rChain, pose);
01342 assert(pClosestScan != NULL);
01343
01344 Pose2 closestScanPose = pClosestScan->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());
01345
01346 kt_double squaredDistance = pose.GetPosition().SquaredDistance(closestScanPose.GetPosition());
01347 if (squaredDistance < math::Square(m_pMapper->m_pLinkScanMaximumDistance->GetValue()) + KT_TOLERANCE)
01348 {
01349 LinkScans(pClosestScan, pScan, rMean, rCovariance);
01350 }
01351 }
01352
01353 std::vector<LocalizedRangeScanVector> MapperGraph::FindNearChains(LocalizedRangeScan* pScan)
01354 {
01355 std::vector<LocalizedRangeScanVector> nearChains;
01356
01357 Pose2 scanPose = pScan->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());
01358
01359
01360 LocalizedRangeScanVector processed;
01361
01362 const LocalizedRangeScanVector nearLinkedScans = FindNearLinkedScans(pScan, m_pMapper->m_pLinkScanMaximumDistance->GetValue());
01363 const_forEach(LocalizedRangeScanVector, &nearLinkedScans)
01364 {
01365 LocalizedRangeScan* pNearScan = *iter;
01366
01367 if (pNearScan == pScan)
01368 {
01369 continue;
01370 }
01371
01372
01373 if (find(processed.begin(), processed.end(), pNearScan) != processed.end())
01374 {
01375 continue;
01376 }
01377
01378 processed.push_back(pNearScan);
01379
01380
01381 kt_bool isValidChain = true;
01382 std::list<LocalizedRangeScan*> chain;
01383
01384
01385 for (kt_int32s candidateScanNum = pNearScan->GetStateId() - 1; candidateScanNum >= 0; candidateScanNum--)
01386 {
01387 LocalizedRangeScan* pCandidateScan = m_pMapper->m_pMapperSensorManager->GetScan(pNearScan->GetSensorName(), candidateScanNum);
01388
01389
01390 if (pCandidateScan == pScan)
01391 {
01392 isValidChain = false;
01393 }
01394
01395 Pose2 candidatePose = pCandidateScan->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());
01396 kt_double squaredDistance = scanPose.GetPosition().SquaredDistance(candidatePose.GetPosition());
01397
01398 if (squaredDistance < math::Square(m_pMapper->m_pLinkScanMaximumDistance->GetValue()) + KT_TOLERANCE)
01399 {
01400 chain.push_front(pCandidateScan);
01401 processed.push_back(pCandidateScan);
01402 }
01403 else
01404 {
01405 break;
01406 }
01407 }
01408
01409 chain.push_back(pNearScan);
01410
01411
01412 kt_int32u end = static_cast<kt_int32u>(m_pMapper->m_pMapperSensorManager->GetScans(pNearScan->GetSensorName()).size());
01413 for (kt_int32u candidateScanNum = pNearScan->GetStateId() + 1; candidateScanNum < end; candidateScanNum++)
01414 {
01415 LocalizedRangeScan* pCandidateScan = m_pMapper->m_pMapperSensorManager->GetScan(pNearScan->GetSensorName(), candidateScanNum);
01416
01417 if (pCandidateScan == pScan)
01418 {
01419 isValidChain = false;
01420 }
01421
01422 Pose2 candidatePose = pCandidateScan->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());;
01423 kt_double squaredDistance = scanPose.GetPosition().SquaredDistance(candidatePose.GetPosition());
01424
01425 if (squaredDistance < math::Square(m_pMapper->m_pLinkScanMaximumDistance->GetValue()) + KT_TOLERANCE)
01426 {
01427 chain.push_back(pCandidateScan);
01428 processed.push_back(pCandidateScan);
01429 }
01430 else
01431 {
01432 break;
01433 }
01434 }
01435
01436 if (isValidChain)
01437 {
01438
01439 LocalizedRangeScanVector tempChain;
01440 std::copy(chain.begin(), chain.end(), std::inserter(tempChain, tempChain.begin()));
01441
01442 nearChains.push_back(tempChain);
01443 }
01444 }
01445
01446 return nearChains;
01447 }
01448
01449 LocalizedRangeScanVector MapperGraph::FindNearLinkedScans(LocalizedRangeScan* pScan, kt_double maxDistance)
01450 {
01451 NearScanVisitor* pVisitor = new NearScanVisitor(pScan, maxDistance, m_pMapper->m_pUseScanBarycenter->GetValue());
01452 LocalizedRangeScanVector nearLinkedScans = m_pTraversal->Traverse(GetVertex(pScan), pVisitor);
01453 delete pVisitor;
01454
01455 return nearLinkedScans;
01456 }
01457
01458 Pose2 MapperGraph::ComputeWeightedMean(const Pose2Vector& rMeans, const std::vector<Matrix3>& rCovariances) const
01459 {
01460 assert(rMeans.size() == rCovariances.size());
01461
01462
01463 std::vector<Matrix3> inverses;
01464 inverses.reserve(rCovariances.size());
01465
01466 Matrix3 sumOfInverses;
01467 const_forEach(std::vector<Matrix3>, &rCovariances)
01468 {
01469 Matrix3 inverse = iter->Inverse();
01470 inverses.push_back(inverse);
01471
01472 sumOfInverses += inverse;
01473 }
01474 Matrix3 inverseOfSumOfInverses = sumOfInverses.Inverse();
01475
01476
01477 Pose2 accumulatedPose;
01478 kt_double thetaX = 0.0;
01479 kt_double thetaY = 0.0;
01480
01481 Pose2Vector::const_iterator meansIter = rMeans.begin();
01482 const_forEach(std::vector<Matrix3>, &inverses)
01483 {
01484 Pose2 pose = *meansIter;
01485 kt_double angle = pose.GetHeading();
01486 thetaX += cos(angle);
01487 thetaY += sin(angle);
01488
01489 Matrix3 weight = inverseOfSumOfInverses * (*iter);
01490 accumulatedPose += weight * pose;
01491
01492 meansIter++;
01493 }
01494
01495 thetaX /= rMeans.size();
01496 thetaY /= rMeans.size();
01497 accumulatedPose.SetHeading(atan2(thetaY, thetaX));
01498
01499 return accumulatedPose;
01500 }
01501
01502 LocalizedRangeScanVector MapperGraph::FindPossibleLoopClosure(LocalizedRangeScan* pScan, const Name& rSensorName, kt_int32u& rStartNum)
01503 {
01504 LocalizedRangeScanVector chain;
01505
01506 Pose2 pose = pScan->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());
01507
01508
01509
01510 const LocalizedRangeScanVector nearLinkedScans = FindNearLinkedScans(pScan, m_pMapper->m_pLoopSearchMaximumDistance->GetValue());
01511
01512 kt_int32u nScans = static_cast<kt_int32u>(m_pMapper->m_pMapperSensorManager->GetScans(rSensorName).size());
01513 for (; rStartNum < nScans; rStartNum++)
01514 {
01515 LocalizedRangeScan* pCandidateScan = m_pMapper->m_pMapperSensorManager->GetScan(rSensorName, rStartNum);
01516
01517 Pose2 candidateScanPose = pCandidateScan->GetReferencePose(m_pMapper->m_pUseScanBarycenter->GetValue());
01518
01519 kt_double squaredDistance = candidateScanPose.GetPosition().SquaredDistance(pose.GetPosition());
01520 if (squaredDistance < math::Square(m_pMapper->m_pLoopSearchMaximumDistance->GetValue()) + KT_TOLERANCE)
01521 {
01522
01523 if (find(nearLinkedScans.begin(), nearLinkedScans.end(), pCandidateScan) != nearLinkedScans.end())
01524 {
01525 chain.clear();
01526 }
01527 else
01528 {
01529 chain.push_back(pCandidateScan);
01530 }
01531 }
01532 else
01533 {
01534
01535 if (chain.size() >= m_pMapper->m_pLoopMatchMinimumChainSize->GetValue())
01536 {
01537 return chain;
01538 }
01539 else
01540 {
01541 chain.clear();
01542 }
01543 }
01544 }
01545
01546 return chain;
01547 }
01548
01549 void MapperGraph::CorrectPoses()
01550 {
01551
01552 ScanSolver* pSolver = m_pMapper->m_pScanOptimizer;
01553 if (pSolver != NULL)
01554 {
01555 pSolver->Compute();
01556
01557 const_forEach(ScanSolver::IdPoseVector, &pSolver->GetCorrections())
01558 {
01559 m_pMapper->m_pMapperSensorManager->GetScan(iter->first)->SetSensorPose(iter->second);
01560 }
01561
01562 pSolver->Clear();
01563 }
01564 }
01565
01569
01573 Mapper::Mapper()
01574 : Module("Mapper")
01575 , m_Initialized(false)
01576 , m_pSequentialScanMatcher(NULL)
01577 , m_pMapperSensorManager(NULL)
01578 , m_pGraph(NULL)
01579 , m_pScanOptimizer(NULL)
01580 {
01581 InitializeParameters();
01582 }
01583
01587 Mapper::Mapper(const std::string& rName)
01588 : Module(rName)
01589 , m_Initialized(false)
01590 , m_pSequentialScanMatcher(NULL)
01591 , m_pMapperSensorManager(NULL)
01592 , m_pGraph(NULL)
01593 , m_pScanOptimizer(NULL)
01594 {
01595 InitializeParameters();
01596 }
01597
01601 Mapper::~Mapper()
01602 {
01603 Reset();
01604
01605 delete m_pMapperSensorManager;
01606 }
01607
01608 void Mapper::InitializeParameters()
01609 {
01618 m_pUseScanMatching = new Parameter<kt_bool>("UseScanMatching", true, GetParameterManager());
01619
01623 m_pUseScanBarycenter = new Parameter<kt_bool>("UseScanBarycenter", true, GetParameterManager());
01624
01633 m_pMinimumTravelDistance = new Parameter<kt_double>("MinimumTravelDistance", 0.2, GetParameterManager());
01634
01643 m_pMinimumTravelHeading = new Parameter<kt_double>("MinimumTravelHeading", math::DegreesToRadians(10), GetParameterManager());
01644
01653 m_pScanBufferSize = new Parameter<kt_int32u>("ScanBufferSize", 70, GetParameterManager());
01654
01660 m_pScanBufferMaximumScanDistance = new Parameter<kt_double>("ScanBufferMaximumScanDistance", 20.0, GetParameterManager());
01661
01666 m_pLinkMatchMinimumResponseFine = new Parameter<kt_double>("LinkMatchMinimumResponseFine", 0.8, GetParameterManager());
01667
01673 m_pLinkScanMaximumDistance = new Parameter<kt_double>("LinkScanMaximumDistance", 10.0, GetParameterManager());
01674
01680 m_pLoopSearchMaximumDistance = new Parameter<kt_double>("LoopSearchMaximumDistance", 4.0, GetParameterManager());
01681
01688 m_pLoopMatchMinimumChainSize = new Parameter<kt_int32u>("LoopMatchMinimumChainSize", 10, GetParameterManager());
01689
01695 m_pLoopMatchMaximumVarianceCoarse = new Parameter<kt_double>("LoopMatchMaximumVarianceCoarse", math::Square(0.4), GetParameterManager());
01696
01701 m_pLoopMatchMinimumResponseCoarse = new Parameter<kt_double>("LoopMatchMinimumResponseCoarse", 0.8, GetParameterManager());
01702
01707 m_pLoopMatchMinimumResponseFine = new Parameter<kt_double>("LoopMatchMinimumResponseFine", 0.8, GetParameterManager());
01708
01710
01711
01716 m_pCorrelationSearchSpaceDimension = new Parameter<kt_double>("CorrelationSearchSpaceDimension", 0.3, GetParameterManager());
01717
01722 m_pCorrelationSearchSpaceResolution = new Parameter<kt_double>("CorrelationSearchSpaceResolution", 0.01, GetParameterManager());
01723
01728 m_pCorrelationSearchSpaceSmearDeviation = new Parameter<kt_double>("CorrelationSearchSpaceSmearDeviation", 0.03, GetParameterManager());
01729
01730
01732
01733
01738 m_pLoopSearchSpaceDimension = new Parameter<kt_double>("LoopSearchSpaceDimension", 8.0, GetParameterManager());
01739
01744 m_pLoopSearchSpaceResolution = new Parameter<kt_double>("LoopSearchSpaceResolution", 0.05, GetParameterManager());
01745
01750 m_pLoopSearchSpaceSmearDeviation = new Parameter<kt_double>("LoopSearchSpaceSmearDeviation", 0.03, GetParameterManager());
01751
01753
01754
01755
01756
01757
01758 m_pDistanceVariancePenalty = new Parameter<kt_double>("DistanceVariancePenalty", math::Square(0.3), GetParameterManager());
01759 m_pAngleVariancePenalty = new Parameter<kt_double>("AngleVariancePenalty", math::Square(math::DegreesToRadians(20)), GetParameterManager());
01760
01761
01762 m_pFineSearchAngleOffset = new Parameter<kt_double>("FineSearchAngleOffset", math::DegreesToRadians(0.2), GetParameterManager());
01763 m_pCoarseSearchAngleOffset = new Parameter<kt_double>("CoarseSearchAngleOffset", math::DegreesToRadians(20), GetParameterManager());
01764
01765
01766 m_pCoarseAngleResolution = new Parameter<kt_double>("CoarseAngleResolution", math::DegreesToRadians(2), GetParameterManager());
01767
01768
01769
01770 m_pMinimumAnglePenalty = new Parameter<kt_double>("MinimumAnglePenalty", 0.9, GetParameterManager());
01771 m_pMinimumDistancePenalty = new Parameter<kt_double>("MinimumDistancePenalty", 0.5, GetParameterManager());
01772
01773
01774 m_pUseResponseExpansion = new Parameter<kt_bool>("UseResponseExpansion", false, GetParameterManager());
01775 }
01776
01777 void Mapper::Initialize(kt_double rangeThreshold)
01778 {
01779 if (m_Initialized == false)
01780 {
01781
01782 m_pSequentialScanMatcher = ScanMatcher::Create(this, m_pCorrelationSearchSpaceDimension->GetValue(), m_pCorrelationSearchSpaceResolution->GetValue(), m_pCorrelationSearchSpaceSmearDeviation->GetValue(), rangeThreshold);
01783 assert(m_pSequentialScanMatcher);
01784
01785 m_pMapperSensorManager = new MapperSensorManager(m_pScanBufferSize->GetValue(), m_pScanBufferMaximumScanDistance->GetValue());
01786
01787 m_pGraph = new MapperGraph(this, rangeThreshold);
01788
01789 m_Initialized = true;
01790 }
01791 }
01792
01793 void Mapper::Reset()
01794 {
01795 delete m_pSequentialScanMatcher;
01796 m_pSequentialScanMatcher = NULL;
01797
01798 delete m_pGraph;
01799 m_pGraph = NULL;
01800
01801 delete m_pMapperSensorManager;
01802 m_pMapperSensorManager = NULL;
01803
01804 m_Initialized = false;
01805 }
01806
01807 kt_bool Mapper::Process(Object* )
01808 {
01809 return true;
01810 }
01811
01812 kt_bool Mapper::Process(LocalizedRangeScan* pScan)
01813 {
01814 if(pScan != NULL)
01815 {
01816 karto::LaserRangeFinder* pLaserRangeFinder = pScan->GetLaserRangeFinder();
01817
01818
01819 if (pLaserRangeFinder == NULL || pScan == NULL || pLaserRangeFinder->Validate(pScan) == false)
01820 {
01821 return false;
01822 }
01823
01824 if (m_Initialized == false)
01825 {
01826
01827 Initialize(pLaserRangeFinder->GetRangeThreshold());
01828 }
01829
01830
01831 LocalizedRangeScan* pLastScan = m_pMapperSensorManager->GetLastScan(pScan->GetSensorName());
01832
01833
01834 if (pLastScan != NULL)
01835 {
01836 Transform lastTransform(pLastScan->GetOdometricPose(), pLastScan->GetCorrectedPose());
01837 pScan->SetCorrectedPose(lastTransform.TransformPose(pScan->GetOdometricPose()));
01838 }
01839
01840
01841 if (!HasMovedEnough(pScan, pLastScan))
01842 {
01843 return false;
01844 }
01845
01846 Matrix3 covariance;
01847 covariance.SetToIdentity();
01848
01849
01850 if (m_pUseScanMatching->GetValue() && pLastScan != NULL)
01851 {
01852 Pose2 bestPose;
01853 m_pSequentialScanMatcher->MatchScan(pScan, m_pMapperSensorManager->GetRunningScans(pScan->GetSensorName()), bestPose, covariance);
01854 pScan->SetSensorPose(bestPose);
01855 }
01856
01857
01858 m_pMapperSensorManager->AddScan(pScan);
01859
01860 if (m_pUseScanMatching->GetValue())
01861 {
01862
01863 m_pGraph->AddVertex(pScan);
01864 m_pGraph->AddEdges(pScan, covariance);
01865
01866 m_pMapperSensorManager->AddRunningScan(pScan);
01867
01868 std::vector<Name> deviceNames = m_pMapperSensorManager->GetSensorNames();
01869 const_forEach(std::vector<Name>, &deviceNames)
01870 {
01871 m_pGraph->TryCloseLoop(pScan, *iter);
01872 }
01873 }
01874
01875 m_pMapperSensorManager->SetLastScan(pScan);
01876
01877 return true;
01878 }
01879
01880 return false;
01881 }
01882
01889 kt_bool Mapper::HasMovedEnough(LocalizedRangeScan* pScan, LocalizedRangeScan* pLastScan) const
01890 {
01891
01892 if (pLastScan == NULL)
01893 {
01894 return true;
01895 }
01896
01897 Pose2 lastScannerPose = pLastScan->GetSensorAt(pLastScan->GetOdometricPose());
01898 Pose2 scannerPose = pScan->GetSensorAt(pScan->GetOdometricPose());
01899
01900
01901 kt_double deltaHeading = math::NormalizeAngle(scannerPose.GetHeading() - lastScannerPose.GetHeading());
01902 if (fabs(deltaHeading) >= m_pMinimumTravelHeading->GetValue())
01903 {
01904 return true;
01905 }
01906
01907
01908 kt_double squaredTravelDistance = lastScannerPose.GetPosition().SquaredDistance(scannerPose.GetPosition());
01909 if (squaredTravelDistance >= math::Square(m_pMinimumTravelDistance->GetValue()) - KT_TOLERANCE)
01910 {
01911 return true;
01912 }
01913
01914 return false;
01915 }
01916
01921 const LocalizedRangeScanVector Mapper::GetAllProcessedScans() const
01922 {
01923 LocalizedRangeScanVector allScans;
01924
01925 if (m_pMapperSensorManager != NULL)
01926 {
01927 allScans = m_pMapperSensorManager->GetAllScans();
01928 }
01929
01930 return allScans;
01931 }
01932
01937 void Mapper::AddListener(MapperListener* pListener)
01938 {
01939 m_Listeners.push_back(pListener);
01940 }
01941
01946 void Mapper::RemoveListener(MapperListener* pListener)
01947 {
01948 std::vector<MapperListener*>::iterator iter = std::find(m_Listeners.begin(), m_Listeners.end(), pListener);
01949 if (iter != m_Listeners.end())
01950 {
01951 m_Listeners.erase(iter);
01952 }
01953 }
01954
01955 void Mapper::FireInfo(const std::string& rInfo) const
01956 {
01957 const_forEach(std::vector<MapperListener*>, &m_Listeners)
01958 {
01959 (*iter)->Info(rInfo);
01960 }
01961 }
01962
01963 void Mapper::FireDebug(const std::string& rInfo) const
01964 {
01965 const_forEach(std::vector<MapperListener*>, &m_Listeners)
01966 {
01967 MapperDebugListener* pListener = dynamic_cast<MapperDebugListener*>(*iter);
01968
01969 if (pListener != NULL)
01970 {
01971 pListener->Debug(rInfo);
01972 }
01973 }
01974 }
01975
01976 void Mapper::FireLoopClosureCheck(const std::string& rInfo) const
01977 {
01978 const_forEach(std::vector<MapperListener*>, &m_Listeners)
01979 {
01980 MapperLoopClosureListener* pListener = dynamic_cast<MapperLoopClosureListener*>(*iter);
01981
01982 if (pListener != NULL)
01983 {
01984 pListener->LoopClosureCheck(rInfo);
01985 }
01986 }
01987 }
01988
01989 void Mapper::FireBeginLoopClosure(const std::string& rInfo) const
01990 {
01991 const_forEach(std::vector<MapperListener*>, &m_Listeners)
01992 {
01993 MapperLoopClosureListener* pListener = dynamic_cast<MapperLoopClosureListener*>(*iter);
01994
01995 if (pListener != NULL)
01996 {
01997 pListener->BeginLoopClosure(rInfo);
01998 }
01999 }
02000 }
02001
02002 void Mapper::FireEndLoopClosure(const std::string& rInfo) const
02003 {
02004 const_forEach(std::vector<MapperListener*>, &m_Listeners)
02005 {
02006 MapperLoopClosureListener* pListener = dynamic_cast<MapperLoopClosureListener*>(*iter);
02007
02008 if (pListener != NULL)
02009 {
02010 pListener->EndLoopClosure(rInfo);
02011 }
02012 }
02013 }
02014
02015 void Mapper::SetScanSolver(ScanSolver* pScanOptimizer)
02016 {
02017 m_pScanOptimizer = pScanOptimizer;
02018 }
02019
02020 MapperGraph* Mapper::GetGraph() const
02021 {
02022 return m_pGraph;
02023 }
02024
02025 ScanMatcher* Mapper::GetSequentialScanMatcher() const
02026 {
02027 return m_pSequentialScanMatcher;
02028 }
02029
02030 ScanMatcher* Mapper::GetLoopScanMatcher() const
02031 {
02032 return m_pGraph->GetLoopScanMatcher();
02033 }
02034 }