38 #include <SimoxUtility/json/json.hpp>
40 #include <IceUtil/UUID.h>
42 #include <Eigen/Geometry>
51 using Line = Eigen::ParametrizedLine<float, 2>;
55 bool anyIsNaN(Eigen::Vector2f
const&
v)
57 return std::isnan(
v.x())
61 bool anyIsNaN(Eigen::Vector3f
const&
v)
63 return std::isnan(
v.x())
68 std::string readWholeFile(std::string
const&
filename)
73 t.seekg(0, std::ios::end);
74 str.reserve(t.tellg());
75 t.seekg(0, std::ios::beg);
77 str.assign(std::istreambuf_iterator<char>(t),
78 std::istreambuf_iterator<char>());
82 Eigen::Vector2f parsePosition(
Json::Value const& pos)
84 Eigen::Vector2f result = Eigen::Vector2f::Zero();
85 if (pos.isArray() && pos.size() == 2)
89 if (x.isNumeric() && y.isNumeric())
91 result[0] = (
float)x.asDouble();
92 result[1] = (
float)y.asDouble();
96 throw std::runtime_error(
"Map format error: Unexpected types in 2D vector");
101 throw std::runtime_error(
"Map format error: Unexpected number of elements in 2D vector");
106 std::vector<LineSegment2Df> loadMapFromFile(std::string
const&
filename)
108 std::string fullFilename;
111 throw std::runtime_error(
"Could not find map file: " +
filename);
114 std::string fileContent = readWholeFile(fullFilename);
120 throw std::runtime_error(
"Map format error: expected a JSON object at root level");
123 float lengthUnit = 1.0f;
125 if (unitValue.isString())
127 std::string unit = unitValue.asString();
130 lengthUnit = 1000.0f;
132 else if (unit ==
"mm")
138 throw std::runtime_error(
"Unknown length unit: " + unit);
145 throw std::runtime_error(
"Map format error: Expected an array at property 'Map'");
148 std::vector<LineSegment2Df> result;
150 for (Json::ArrayIndex i = 0; i < map.size(); ++i)
154 Eigen::Vector2f pos = parsePosition(position);
156 if (!strip.isArray())
158 throw std::runtime_error(
"Map format error: Expected an error at property 'RelativeLineStrip'");
161 Eigen::Vector2f startPos = pos;
162 for (Json::ArrayIndex j = 0; j < strip.size(); ++j)
164 Eigen::Vector2f nextPos = startPos + parsePosition(strip[j]);
166 result.push_back(
LineSegment2Df {lengthUnit * startPos, lengthUnit * nextPos});
174 float lineSegmentToPointDistanceSquared(
LineSegment2Df const& segment, Eigen::Vector2f point)
177 Eigen::Vector2f dir = segment.
end - segment.
start;
178 float l2 = dir.squaredNorm();
181 return (point - segment.
start).squaredNorm();
189 Eigen::Vector2f projection = segment.
start + t * dir;
190 return (point - projection).squaredNorm();
195 Eigen::Vector2f normalizedDir = line.direction();
196 Eigen::Vector2f diff = point - line.origin();
197 float signedDistance = normalizedDir.x() * diff.y() - normalizedDir.y() * diff.x();
198 return std::fabs(signedDistance);
201 Line leastSquareLine(Eigen::Vector2f* begin, Eigen::Vector2f* end,
202 float* maxError =
nullptr,
203 float* averageError =
nullptr,
206 float* det =
nullptr)
213 for (Eigen::Vector2f* point = begin; point != end; ++point)
215 float x = point->x();
216 float y = point->y();
224 float numx = (
float)(end - begin);
225 float calc_det = (numx * sumxx) - (sumx * sumx);
226 float calc_dety = (numx * sumyy) - (sumy * sumy);
228 float calc_as = (sumxx * sumy) - (sumx * sumxy);
229 float calc_bs = (numx * sumxy) - (sumx * sumy);
232 zeroLine.origin() = Eigen::Vector2f::Zero();
233 zeroLine.direction() = Eigen::Vector2f::UnitX();
238 <<
" " <<
VAROUT(calc_bs);
251 if (calc_det > calc_dety)
253 line.direction() = Eigen::Vector2f(calc_det, calc_bs).normalized();
257 line.direction() = Eigen::Vector2f(calc_bs, calc_dety).normalized();
260 line.origin() = Eigen::Vector2f(sumx / numx, sumy / numx);
263 if (numx > 0 && maxError)
265 float this_average_error = 0.0f;
266 float this_max_error = 0.0f;
267 for (Eigen::Vector2f* point = begin; point != end; ++point)
269 float point_error =
distance(line, *point);
270 this_average_error += point_error;
271 this_max_error =
std::max(point_error, this_max_error);
273 this_average_error = this_average_error / numx;
275 *maxError = this_max_error;
279 *averageError = this_average_error;
299 LineSegment2Df leastSquareLineSegmentInOrder(Eigen::Vector2f* begin, Eigen::Vector2f* end,
float* maxError,
float* averageError)
302 if ((end - begin) < 2)
304 segment.
start = Eigen::Vector2f::Zero();
305 segment.
end = Eigen::Vector2f(5000.0f, 5000.0f);
312 *averageError = FLT_MAX;
317 Line line = leastSquareLine(begin, end, maxError, averageError,
nullptr,
nullptr,
nullptr);
318 if (anyIsNaN(line.direction()))
320 segment.
start = Eigen::Vector2f::Zero();
321 segment.
end = Eigen::Vector2f(5000.0f, 5000.0f);
328 *averageError = FLT_MAX;
332 segment.
start = line.projection(*begin);
333 segment.
end = line.projection(*(end - 1));
335 if (anyIsNaN(segment.
start))
339 <<
VAROUT(line.direction());
341 if (anyIsNaN(segment.
end))
345 <<
VAROUT(line.direction());
351 float leastSquareEdge(Eigen::Vector2f* begin, Eigen::Vector2f* end,
LineSegment2Df& segment)
354 float averageError {0};
355 segment = leastSquareLineSegmentInOrder(begin, end, &maxError, &averageError);
369 reportTopicName = getProperty<std::string>(
"ReportTopicName");
370 robotStateComponentName = getProperty<std::string>(
"RobotStateComponentName");
371 platformName = getProperty<std::string>(
"PlatformName");
372 laserScannerUnitName = getProperty<std::string>(
"LaserScannerUnitName");
373 workingMemoryName = getProperty<std::string>(
"WorkingMemoryName");
374 longtermMemoryName = getProperty<std::string>(
"LongtermMemoryName");
375 mapFilename = getProperty<std::string>(
"MapFilename");
376 agentName = getProperty<std::string>(
"AgentName");
377 emergencyStopMasterName = getProperty<std::string>(
"EmergencyStopMasterName");
378 debugObserverName = getProperty<std::string>(
"DebugObserverName");
379 updateWorkingMemory = getProperty<bool>(
"UpdateWorkingMemory");
380 int updatePeriodWorkingMemoryInMs = getProperty<int>(
"UpdatePeriodWorkingMemoryInMs");
381 workingMemoryUpdateFrequency = 1000.0f / updatePeriodWorkingMemoryInMs;
382 int updatePeriodLongtermMemory = getProperty<int>(
"UpdatePeriodLongtermMemoryInMs");
383 longtermMemoryUpdateFrequency = 1000.0f / updatePeriodLongtermMemory;
384 robotPositionZ = getProperty<float>(
"RobotPositionZ");
385 maximalLaserScannerDelay = getProperty<float>(
"MaximalLaserScannerDelay").getValue();
389 map = loadMapFromFile(mapFilename);
392 const auto min = getPropertyAsCSV<float>(
"PlatformRectangleMin");
393 const auto max = getPropertyAsCSV<float>(
"PlatformRectangleMax");
394 std::tie(platformRectMin(0), platformRectMax(0)) = std::minmax(
min.at(0),
max.at(0));
395 std::tie(platformRectMin(1), platformRectMax(1)) = std::minmax(
min.at(1),
max.at(1));
396 ARMARX_INFO <<
"using platform rectangle min / max " << platformRectMin.transpose() <<
" / " << platformRectMax.transpose();
409 robotState = getProxy<RobotStateComponentInterfacePrx>(robotStateComponentName);
410 laserScannerUnit = getProxy<LaserScannerUnitInterfacePrx>(laserScannerUnitName);
412 for (LaserScannerInfo
const& info : laserScannerUnit->getConnectedDevices())
414 FramedPoseBasePtr basePose = sharedRobot->getRobotNode(info.frame)->getPoseInRootFrame();
420 data.mutex = std::make_shared<std::mutex>();
421 scanData.push_back(
data);
424 debugObserver = getTopic<DebugObserverInterfacePrx>(debugObserverName);
426 robotRootFrame = sharedRobot->getRootNode()->getName();
428 workingMemory = getProxy<memoryx::WorkingMemoryInterfacePrx>(workingMemoryName);
429 agentsMemory = workingMemory->getAgentInstancesSegment();
430 if (agentName.empty())
432 agentName = robotState->getRobotName();
435 agentInstance->setSharedRobot(sharedRobot);
436 agentInstance->setAgentFilePath(robotState->getRobotFilename());
437 agentInstance->setName(agentName);
439 longtermMemory = getProxy<memoryx::LongtermMemoryInterfacePrx>(longtermMemoryName);
440 selfLocalisationSegment = longtermMemory->getSelfLocalisationSegment();
443 reportTopic = getTopic<LaserScannerSelfLocalisationListenerPrx>(reportTopicName);
445 platformUnitTopic = getTopic<PlatformUnitListenerPrx>(
"PlatformState");
447 estimatedPose = Eigen::Vector3f::Zero();
448 memoryx::EntityBasePtr poseEntity = selfLocalisationSegment->getEntityByName(agentName);
451 poseEntityId = poseEntity->getId();
452 ARMARX_INFO <<
"Using pose entity from LTM with ID: " << poseEntityId;
453 memoryx::EntityAttributeBasePtr poseAttribute = poseEntity->getAttribute(
"pose");
462 Eigen::Vector2f robotPos = globalPose.block<2, 1>(0, 3);
463 Eigen::Vector2f yWorld(0.0f, 1.0f);
464 Eigen::Vector2f yRobot = robotRot.col(1).head<2>();
465 float robotTheta = acos(yWorld.dot(yRobot));
466 if (yRobot.x() >= 0.0f)
468 robotTheta = -robotTheta;
471 estimatedPose = Eigen::Vector3f(robotPos.x(), robotPos.y(), robotTheta);
475 ARMARX_WARNING <<
"'pose' attribute does not contain a framed pose";
480 ARMARX_WARNING <<
"No attribute 'pose' in entity for agent '" << agentName <<
"' found";
485 ARMARX_WARNING <<
"No pose in longterm memory found for agent: " << agentName;
490 poseEntity->setName(agentName);
491 poseEntity->putAttribute(
"pose", pose);
494 poseEntityId = selfLocalisationSegment->addEntity(poseEntity);
497 ARMARX_INFO <<
"Initial pose: (" << estimatedPose[0] <<
", " << estimatedPose[1] <<
", " << estimatedPose[2] <<
")";
498 resetKalmanFilter(estimatedPose);
500 lastVelocity = Eigen::Vector3f::Zero();
502 usingTopic(laserScannerUnit->getReportTopicName());
506 int updatePeriod = getProperty<int>(
"UpdatePeriodInMs");
516 if (laserScannerFileLoggingData)
533 prop->topic(globalRobotPoseTopic);
540 return reportTopicName;
546 std::unique_lock lock(setPoseMutex);
547 setPose = Eigen::Vector3f(x, y, theta);
548 resetKalmanFilter(*setPose);
557 if (
data.info.device == device)
559 std::unique_lock lock(*
data.mutex);
561 data.measurementTime = IceUtil::Time::microSeconds(timestamp->timestamp);
567 static Eigen::Vector3f addPose(Eigen::Vector3f pose, Eigen::Vector3f add)
569 Eigen::Vector3f result = pose + add;
575 static Eigen::Vector3f integratePose(Eigen::Vector3f pose, Eigen::Vector3f v0, Eigen::Vector3f v1,
float dt)
580 float dTheta = 0.5f *
dt * (v0[2] + v1[2]);
582 float thetaMid = pose[2] + 0.5f * dTheta;
584 Eigen::Vector2f globalV0 = rotation * v0.head<2>();
585 Eigen::Vector2f globalV1 = rotation * v1.head<2>();
586 Eigen::Vector2f globalDeltaPos = 0.5f *
dt * (globalV0 + globalV1);
588 Eigen::Vector3f d(globalDeltaPos.x(), globalDeltaPos.y(), dTheta);
589 return addPose(pose, d);
595 auto elapsedSeconds = now - lastVelocityUpdate;
596 lastVelocityUpdate = now;
598 std::unique_lock lock(kalmanMutex);
599 filter->predict(velX, velY, velTheta, elapsedSeconds);
605 std::unique_lock lock(odometryMutex);
607 reportedVelocities.push_back(
ReportedVelocity {
static_cast<float>(elapsedSeconds.toSecondsDouble()), velX, velY, velTheta});
620 void LaserScannerSelfLocalisation::updateLocalisation()
625 propertyMutex.lock();
626 int halfFrameSize = propSmoothFrameSize / 2;
627 int mergeDistance = propSmoothMergeDistance;
628 float maxDistanceSquared = propMatchingMaxDistance * propMatchingMaxDistance;
629 float minPointsForMatch = propMatchingMinPoints;
630 float matchingCorrectionFactor = propMatchingCorrectionFactor;
631 bool reportPoints = propReportPoints;
632 bool reportEdges = propReportEdges;
633 bool useMapCorrection = propUseMapCorrection;
634 int epsilon = propEdgeEpsilon;
635 int minPointsPerEdge = propEdgeMinPoints;
636 float maxDistanceForEdgeSquared = propEdgeMaxDistance * propEdgeMaxDistance;
637 float pointAddingThreshold = propEdgePointAddingThreshold;
638 float edgeMaxDeltaAngle = propEdgeMaxDeltaAngle;
639 propertyMutex.unlock();
641 Eigen::Vector3f currentPose = estimatedPose;
646 std::unique_lock lock(odometryMutex);
649 Eigen::Vector3f currentVelocity(report.x, report.y, report.theta);
650 Eigen::Vector3f motionPrediction = integratePose(currentPose, lastVelocity, currentVelocity, report.dt);
651 if (anyIsNaN(motionPrediction))
653 ARMARX_WARNING <<
"Motion prediction is NaN: " << motionPrediction;
655 <<
" " <<
VAROUT(lastVelocity)
656 <<
" " <<
VAROUT(currentVelocity)
657 <<
" " <<
VAROUT(report.dt);
661 currentPose = motionPrediction;
664 lastVelocity = currentVelocity;
666 reportedVelocities.clear();
670 std::size_t pointsSize = 0;
674 if (scanData.empty())
676 measurementTime = now;
680 measurementTime =
std::max(measurementTime,
data.measurementTime);
682 std::unique_lock lock(*
data.mutex);
683 if (
data.scan.empty())
688 pointsSize +=
data.scan.size();
691 double deltaMeasurement = (now -
data.measurementTime).toSecondsDouble();
692 if (deltaMeasurement < -0.005)
695 <<
" now: " << now.toDateTime() <<
" measurement: " <<
data.measurementTime.toDateTime();
697 else if (deltaMeasurement > maximalLaserScannerDelay)
700 << deltaMeasurement <<
"s > " << maximalLaserScannerDelay
701 <<
"s). Activating emergency stop!";
703 EmergencyStopMasterInterfacePrx emergencyStopMaster = getProxy<EmergencyStopMasterInterfacePrx>(emergencyStopMasterName);
704 if (emergencyStopMaster)
706 emergencyStopMaster->setEmergencyStopState(eEmergencyStopActive);
710 ARMARX_ERROR <<
"Could not activate emergency stop because proxy for EmergencyStopMaster was not found '"
711 << emergencyStopMasterName <<
"'";
715 if (useMapCorrection && pointsSize > 0)
719 Eigen::Rotation2Df globalRotation = Eigen::Rotation2Df(currentPose[2]);
720 Eigen::Vector2f globalTranslation = currentPose.head<2>();
722 std::unique_lock lock(*
data.mutex);
724 data.points.reserve(
data.scan.size());
725 for (
int stepIndex = 0; stepIndex < (int)
data.scan.size(); ++stepIndex)
727 LaserScanStep
const& step =
data.scan[stepIndex];
730 float distanceSum = 0;
731 int distanceElements = 0;
732 int minFrameIndex =
std::max(0, stepIndex - halfFrameSize);
733 int maxFrameIndex =
std::min((
int)(
data.scan.size()) - 1, stepIndex + halfFrameSize);
734 for (
int frameIndex = minFrameIndex; frameIndex <= maxFrameIndex; ++frameIndex)
736 float frameDistance =
data.scan[frameIndex].distance;
737 int deltaDistance =
std::abs(step.distance - frameDistance);
738 if (deltaDistance <= mergeDistance)
740 distanceSum += frameDistance;
744 if (distanceElements == 0)
746 ARMARX_WARNING <<
"No elements with distance smaller than merge distance found.";
748 <<
" " <<
VAROUT(step.distance)
749 <<
" " <<
VAROUT(mergeDistance);
753 float distance = distanceSum / distanceElements;
756 float sinAngle, cosAngle;
757 sincosf(step.angle, &sinAngle, &cosAngle);
761 Eigen::Vector2f localPoint = (
data.pose * Eigen::Vector4f(x, y, 0, 1)).head<2>();
763 if (anyIsNaN(localPoint))
769 <<
" " <<
VAROUT(step.angle);
774 platformRectMin(0) < localPoint(0) && localPoint(0) < platformRectMax(0) &&
775 platformRectMin(1) < localPoint(1) && localPoint(1) < platformRectMax(1)
782 Eigen::Vector2f globalPoint = globalRotation * localPoint + globalTranslation;
784 if (anyIsNaN(globalPoint))
790 <<
" " <<
VAROUT(step.angle);
794 data.points.push_back(globalPoint);
802 std::vector<armarx::Vector2f> pointsA;
803 pointsA.reserve(pointsSize);
806 for (
auto& p :
data.points)
808 pointsA.push_back(armarx::Vector2f {p.x(), p.y()});
813 reportTopic->begin_reportLaserScanPoints(pointsA);
821 std::size_t edgeCount = 0;
825 auto& points =
data.points;
827 std::vector<float> angles;
828 angles.reserve(points.size());
829 int pointsSize = (int)points.size();
830 for (
int pointIndex = 0; pointIndex < pointsSize; ++pointIndex)
832 int beginIndex =
std::max(pointIndex - epsilon, 0);
833 int endIndex =
std::min(pointIndex + epsilon + 1, pointsSize - 1);
834 Eigen::Vector2f* beginPoint = &
data.points[beginIndex];
835 Eigen::Vector2f* endPoint = &
data.points[endIndex];
836 Line line(leastSquareLine(beginPoint, endPoint));
837 float angle = std::atan2(line.direction().x(), line.direction().y());
838 if (std::isnan(
angle))
842 <<
" " <<
VAROUT(endIndex);
846 angles.push_back(
angle);
851 int endIndex = beginIndex;
852 int maxEndIndex = pointsSize - 1;
853 int minBeginIndex = 0;
855 int maximumPointsInEdge = 0;
859 while (endIndex < maxEndIndex)
861 float yaw = angles[endIndex];
866 while (endIndex < maxEndIndex &&
867 std::fabs(yaw - angles[endIndex + 1]) < edgeMaxDeltaAngle &&
868 (points[endIndex + 1] - points[endIndex]).squaredNorm() < maxDistanceForEdgeSquared)
877 bool frontExtended =
false;
878 bool backExtended =
false;
881 while (beginIndex > minBeginIndex &&
882 (points[beginIndex - 1] - points[beginIndex]).squaredNorm() < maxDistanceForEdgeSquared &&
883 leastSquareEdge(points.data() + beginIndex - 1, points.data() + endIndex + 1, edgeLineSegment[resultIndex]) < pointAddingThreshold)
886 resultIndex = !resultIndex;
887 frontExtended =
true;
891 while (endIndex < maxEndIndex &&
892 (points[endIndex] - points[endIndex + 1]).squaredNorm() < maxDistanceForEdgeSquared &&
893 leastSquareEdge(points.data() + beginIndex, points.data() + endIndex + 1, edgeLineSegment[resultIndex]) < pointAddingThreshold)
896 resultIndex = !resultIndex;
900 if (!frontExtended && !backExtended)
902 leastSquareEdge(points.data() + beginIndex, points.data() + endIndex + 1, edgeLineSegment[!resultIndex]);
906 int numberOfPoints = endIndex - beginIndex + 1;
907 if (numberOfPoints > minPointsPerEdge)
912 Eigen::Vector2f* pointsBegin = points.data() + beginIndex;
913 ExtractedEdge edge {segment, pointsBegin, pointsBegin + numberOfPoints};
914 data.edges.push_back(edge);
916 maximumPointsInEdge =
std::max(numberOfPoints, maximumPointsInEdge);
917 minBeginIndex = endIndex + 1;
921 beginIndex = endIndex + 1;
922 endIndex = beginIndex;
928 std::vector<armarx::LineSegment2D> segments;
929 segments.reserve(edgeCount);
934 armarx::LineSegment2D s;
937 segments.push_back(s);
940 reportTopic->begin_reportExtractedEdges(segments);
943 std::size_t rowCount = 0;
944 Eigen::Vector2f robotPos = currentPose.head<2>();
946 Eigen::MatrixX3f X(pointsSize, 3);
947 Eigen::VectorXf Y(pointsSize);
954 auto& globalPoint = *p;
957 float minDistanceSquared = FLT_MAX;
960 float distanceSquared = lineSegmentToPointDistanceSquared(segment, globalPoint);
961 if (distanceSquared < minDistanceSquared)
963 minDistanceSquared = distanceSquared;
967 if (minDistanceSquared > maxDistanceSquared)
973 ARMARX_WARNING <<
"No line segment closest to point found: " << globalPoint;
977 Eigen::Vector2f
const&
v = globalPoint;
978 Eigen::Vector2f targetDir =
target->end -
target->start;
979 Eigen::Vector2f u = Eigen::Vector2f(-targetDir.y(), targetDir.x()).normalized();
980 float r =
target->start.dot(u);
981 Eigen::Vector2f cToV(
v - robotPos);
982 Eigen::Vector2f cToVOrth(-cToV.y(), cToV.x());
983 float x3 = u.dot(cToVOrth);
984 float y = r - u.dot(
v);
986 X(rowCount, 0) = u(0);
987 X(rowCount, 1) = u(1);
995 Eigen::Vector3f b = Eigen::Vector3f::Zero();
996 float matched =
static_cast<float>(rowCount) / pointsSize;
997 debugObserver->setDebugDatafield(
getName(),
"MatchedDataPointRatio",
new Variant(matched));
998 if (matched < minPointsForMatch)
1001 << rowCount <<
"/" << pointsSize <<
" = " << matched <<
")";
1003 else if (rowCount > 10)
1005 b = X.block(0, 0, rowCount, 3).jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(Y.head(rowCount));
1006 b *= matchingCorrectionFactor;
1014 Eigen::Vector3f newEstimatedPose = addPose(currentPose, b);
1015 if (anyIsNaN(newEstimatedPose))
1022 estimatedPose = newEstimatedPose;
1025 std::unique_lock lock(kalmanMutex);
1026 if (propSensorStdDev > 0)
1028 filter->update(estimatedPose(0), estimatedPose(1), estimatedPose(2));
1034 estimatedPose = currentPose;
1037 Eigen::Vector3f filteredPose;
1038 if (propSensorStdDev > 0)
1040 Eigen::Matrix3d cov = filter->getCovariance();
1041 reportTopic->begin_reportPoseUncertainty(cov(0, 0), cov(1, 1), cov(2, 2));
1043 filteredPose = filter->getPose().cast<
float>();
1047 filteredPose = estimatedPose;
1050 std::unique_lock lock(setPoseMutex);
1053 estimatedPose = *setPose;
1054 resetKalmanFilter(estimatedPose);
1058 reportTopic->begin_reportCorrectedPose(filteredPose[0], filteredPose[1], filteredPose[2]);
1059 PlatformPose newPose;
1060 newPose.timestampInMicroSeconds = measurementTime.toMicroSeconds();
1061 newPose.x = filteredPose[0];
1062 newPose.y = filteredPose[1];
1063 newPose.rotationAroundZ = filteredPose[2];
1067 orientation.block<2, 2>(0, 0) = Eigen::Rotation2Df(filteredPose[2]).matrix();
1068 Eigen::Vector3f position(filteredPose[0], filteredPose[1], robotPositionZ);
1074 header.frame = robotRootFrame;
1075 header.agent = agentName;
1076 header.timestampInMicroSeconds = measurementTime.toMicroSeconds();
1078 TransformStamped globalRobotPose;
1079 globalRobotPose.header = header;
1080 globalRobotPose.transform = reportPose->toEigen();
1082 globalRobotPoseTopic->reportGlobalRobotPose(globalRobotPose);
1086 if (updateWorkingMemory &&
s.checkFrequency(
"workingMemoryUpdate", workingMemoryUpdateFrequency))
1093 agentInstance->setPose(reportPose);
1096 std::string robotAgentId = agentsMemory->upsertEntityByName(agentInstance->getName(), agentInstance);
1097 agentInstance->setId(robotAgentId);
1110 if (
s.checkFrequency(
"longtermMemoryUpdate", longtermMemoryUpdateFrequency))
1113 poseEntity->setName(agentName);
1114 poseEntity->putAttribute(
"pose", reportPose);
1115 poseEntity->setId(poseEntityId);
1117 if (selfLocalisationSegment)
1119 selfLocalisationSegment->upsertEntity(poseEntityId, poseEntity);
1127 catch (IceUtil::Exception
const& ex)
1129 ARMARX_WARNING <<
"Caught exception while updating the memory:\n" << ex;
1132 if (laserScannerFileLoggingData)
1134 laserScannerFileLoggingData->scanDataHistory[now] = (scanData);
1141 #define ARMARX_LSSL_UPDATE_PROPERTY(name) \
1143 auto prop = getProperty<decltype(prop ## name)>(#name); \
1144 if (initial || prop.isSet()) \
1146 prop ## name = prop.getValue(); \
1147 ARMARX_VERBOSE << VAROUT(prop ## name); \
1153 std::unique_lock lock(propertyMutex);
1156 if (
std::abs(propSensorStdDev - getProperty<float>(
"SensorStdDev").
getValue()) > 0.001)
1158 propSensorStdDev = getProperty<float>(
"SensorStdDev");
1162 resetKalmanFilter(estimatedPose);
1165 if (
std::abs(propVelSensorStdDev - getProperty<float>(
"VelSensorStdDev").
getValue()) > 0.00001)
1167 propVelSensorStdDev = getProperty<float>(
"VelSensorStdDev");
1171 resetKalmanFilter(estimatedPose);
1197 if (!propLoggingFilePath.empty())
1199 if (laserScannerFileLoggingData && propRecordData && !getProperty<bool>(
"RecordData").
getValue())
1204 if (!propRecordData && getProperty<bool>(
"RecordData").
getValue())
1207 laserScannerFileLoggingData.reset(
new LaserScannerFileLoggingData());
1208 laserScannerFileLoggingData->filePath = propLoggingFilePath;
1210 propRecordData = getProperty<bool>(
"RecordData").getValue();
1213 useOdometry = propUseOdometry;
1216 catch (std::exception
const& ex)
1221 #undef ARMARX_LSSL_UPDATE_PROPERTY
1226 void LaserScannerSelfLocalisation::resetKalmanFilter(
const Eigen::Vector3f& pose)
1228 ARMARX_INFO <<
"Position Std Dev: " << propSensorStdDev <<
" Vel Std Dev: " << propVelSensorStdDev;
1229 std::unique_lock lock(kalmanMutex);
1231 propSensorStdDev, propSensorStdDev / 100,
1232 propVelSensorStdDev, propVelSensorStdDev ));
1235 void LaserScannerSelfLocalisation::writeLogFile()
1237 if (!laserScannerFileLoggingData)
1242 std::map<IceUtil::Time, std::vector<LaserScanData>> dataMap;
1243 std::string filePath;
1245 std::unique_lock lock(laserScannerFileLoggingData->loggingMutex);
1246 dataMap.swap(laserScannerFileLoggingData->scanDataHistory);
1247 filePath = laserScannerFileLoggingData->filePath;
1249 ARMARX_INFO <<
"Writing " << dataMap.size() <<
" laser scans";
1250 laserScannerFileLoggingData.reset();
1251 nlohmann::json json;
1252 std::ofstream file(filePath, std::ofstream::out | std::ofstream::trunc);
1258 int skipLineAmount = 10;
1260 for (
auto& pair : dataMap)
1262 if (i % skipLineAmount != 0)
1266 const std::vector<LaserScanData>& scanData = pair.second;
1267 for (
auto& elem : scanData)
1271 json[
"DeviceInfo"][scan.
info.device] =
1273 {
"frame", scan.
info.frame},
1274 {
"minAngle", scan.
info.minAngle},
1275 {
"maxAngle", scan.
info.maxAngle},
1276 {
"stepSize", scan.
info.stepSize},
1279 {
"x", scan.
pose(0, 3)},
1280 {
"y", scan.
pose(1, 3)},
1281 {
"z", scan.
pose(2, 3)}
1285 "sensorOrientation", {{
"w", quat.w()},
1293 Ice::IntSeq dataPts;
1294 for (
const auto& pt : scan.
points)
1296 dataPts.push_back(pt(0));
1297 dataPts.push_back(pt(1));
1299 json[
"Data"][scan.
info.device][
"GlobalPoints"] += dataPts;
1300 Ice::IntSeq scanPts;
1301 for (
const LaserScanStep& pt : scan.
scan)
1303 scanPts.push_back(pt.distance);
1305 json[
"Data"][scan.
info.device][
"ScanDistances"] += scanPts;
1309 file << std::setw(1) << json << std::endl;
1315 LineSegment2DSeq result;
1318 armarx::Vector2f start {segment.start.x(), segment.start.y()};
1319 armarx::Vector2f end {segment.end.x(), segment.end.y()};
1320 result.push_back(LineSegment2D {start, end});