39 #include <Eigen/Geometry>
41 #include <IceUtil/UUID.h>
43 #include <SimoxUtility/json/json.hpp>
52 using Line = Eigen::ParametrizedLine<float, 2>;
57 anyIsNaN(Eigen::Vector2f
const&
v)
59 return std::isnan(
v.x()) || std::isnan(
v.y());
63 anyIsNaN(Eigen::Vector3f
const&
v)
65 return std::isnan(
v.x()) || std::isnan(
v.y()) || std::isnan(
v.z());
69 readWholeFile(std::string
const&
filename)
74 t.seekg(0, std::ios::end);
75 str.reserve(t.tellg());
76 t.seekg(0, std::ios::beg);
78 str.assign(std::istreambuf_iterator<char>(t), std::istreambuf_iterator<char>());
85 Eigen::Vector2f result = Eigen::Vector2f::Zero();
86 if (pos.isArray() && pos.size() == 2)
90 if (x.isNumeric() && y.isNumeric())
92 result[0] = (
float)x.asDouble();
93 result[1] = (
float)y.asDouble();
97 throw std::runtime_error(
"Map format error: Unexpected types in 2D vector");
102 throw std::runtime_error(
103 "Map format error: Unexpected number of elements in 2D vector");
108 std::vector<LineSegment2Df>
109 loadMapFromFile(std::string
const&
filename)
111 std::string fullFilename;
114 throw std::runtime_error(
"Could not find map file: " +
filename);
117 std::string fileContent = readWholeFile(fullFilename);
123 throw std::runtime_error(
"Map format error: expected a JSON object at root level");
126 float lengthUnit = 1.0f;
128 if (unitValue.isString())
130 std::string unit = unitValue.asString();
133 lengthUnit = 1000.0f;
135 else if (unit ==
"mm")
141 throw std::runtime_error(
"Unknown length unit: " + unit);
148 throw std::runtime_error(
"Map format error: Expected an array at property 'Map'");
151 std::vector<LineSegment2Df> result;
153 for (Json::ArrayIndex i = 0; i < map.size(); ++i)
157 Eigen::Vector2f pos = parsePosition(position);
159 if (!strip.isArray())
161 throw std::runtime_error(
162 "Map format error: Expected an error at property 'RelativeLineStrip'");
165 Eigen::Vector2f startPos = pos;
166 for (Json::ArrayIndex j = 0; j < strip.size(); ++j)
168 Eigen::Vector2f nextPos = startPos + parsePosition(strip[j]);
170 result.push_back(
LineSegment2Df{lengthUnit * startPos, lengthUnit * nextPos});
179 lineSegmentToPointDistanceSquared(
LineSegment2Df const& segment, Eigen::Vector2f point)
182 Eigen::Vector2f dir = segment.
end - segment.
start;
183 float l2 = dir.squaredNorm();
186 return (point - segment.
start).squaredNorm();
194 Eigen::Vector2f projection = segment.
start + t * dir;
195 return (point - projection).squaredNorm();
201 Eigen::Vector2f normalizedDir = line.direction();
202 Eigen::Vector2f diff = point - line.origin();
203 float signedDistance = normalizedDir.x() * diff.y() - normalizedDir.y() * diff.x();
204 return std::fabs(signedDistance);
208 leastSquareLine(Eigen::Vector2f* begin,
209 Eigen::Vector2f* end,
210 float* maxError =
nullptr,
211 float* averageError =
nullptr,
214 float* det =
nullptr)
221 for (Eigen::Vector2f* point = begin; point != end; ++point)
223 float x = point->x();
224 float y = point->y();
232 float numx = (
float)(end - begin);
233 float calc_det = (numx * sumxx) - (sumx * sumx);
234 float calc_dety = (numx * sumyy) - (sumy * sumy);
236 float calc_as = (sumxx * sumy) - (sumx * sumxy);
237 float calc_bs = (numx * sumxy) - (sumx * sumy);
240 zeroLine.origin() = Eigen::Vector2f::Zero();
241 zeroLine.direction() = Eigen::Vector2f::UnitX();
256 if (calc_det > calc_dety)
258 line.direction() = Eigen::Vector2f(calc_det, calc_bs).normalized();
262 line.direction() = Eigen::Vector2f(calc_bs, calc_dety).normalized();
265 line.origin() = Eigen::Vector2f(sumx / numx, sumy / numx);
268 if (numx > 0 && maxError)
270 float this_average_error = 0.0f;
271 float this_max_error = 0.0f;
272 for (Eigen::Vector2f* point = begin; point != end; ++point)
274 float point_error =
distance(line, *point);
275 this_average_error += point_error;
276 this_max_error =
std::max(point_error, this_max_error);
278 this_average_error = this_average_error / numx;
280 *maxError = this_max_error;
284 *averageError = this_average_error;
305 leastSquareLineSegmentInOrder(Eigen::Vector2f* begin,
306 Eigen::Vector2f* end,
311 if ((end - begin) < 2)
313 segment.
start = Eigen::Vector2f::Zero();
314 segment.
end = Eigen::Vector2f(5000.0f, 5000.0f);
321 *averageError = FLT_MAX;
326 Line line = leastSquareLine(begin, end, maxError, averageError,
nullptr,
nullptr,
nullptr);
327 if (anyIsNaN(line.direction()))
329 segment.
start = Eigen::Vector2f::Zero();
330 segment.
end = Eigen::Vector2f(5000.0f, 5000.0f);
337 *averageError = FLT_MAX;
341 segment.
start = line.projection(*begin);
342 segment.
end = line.projection(*(end - 1));
344 if (anyIsNaN(segment.
start))
349 if (anyIsNaN(segment.
end))
352 <<
VAROUT(line.direction());
359 leastSquareEdge(Eigen::Vector2f* begin, Eigen::Vector2f* end,
LineSegment2Df& segment)
362 float averageError{0};
363 segment = leastSquareLineSegmentInOrder(begin, end, &maxError, &averageError);
377 reportTopicName = getProperty<std::string>(
"ReportTopicName");
378 robotStateComponentName = getProperty<std::string>(
"RobotStateComponentName");
379 platformName = getProperty<std::string>(
"PlatformName");
380 laserScannerUnitName = getProperty<std::string>(
"LaserScannerUnitName");
381 workingMemoryName = getProperty<std::string>(
"WorkingMemoryName");
382 longtermMemoryName = getProperty<std::string>(
"LongtermMemoryName");
383 mapFilename = getProperty<std::string>(
"MapFilename");
384 agentName = getProperty<std::string>(
"AgentName");
385 emergencyStopMasterName = getProperty<std::string>(
"EmergencyStopMasterName");
386 debugObserverName = getProperty<std::string>(
"DebugObserverName");
387 updateWorkingMemory = getProperty<bool>(
"UpdateWorkingMemory");
388 int updatePeriodWorkingMemoryInMs = getProperty<int>(
"UpdatePeriodWorkingMemoryInMs");
389 workingMemoryUpdateFrequency = 1000.0f / updatePeriodWorkingMemoryInMs;
390 int updatePeriodLongtermMemory = getProperty<int>(
"UpdatePeriodLongtermMemoryInMs");
391 longtermMemoryUpdateFrequency = 1000.0f / updatePeriodLongtermMemory;
392 robotPositionZ = getProperty<float>(
"RobotPositionZ");
393 maximalLaserScannerDelay = getProperty<float>(
"MaximalLaserScannerDelay").getValue();
397 map = loadMapFromFile(mapFilename);
400 const auto min = getPropertyAsCSV<float>(
"PlatformRectangleMin");
401 const auto max = getPropertyAsCSV<float>(
"PlatformRectangleMax");
402 std::tie(platformRectMin(0), platformRectMax(0)) = std::minmax(
min.at(0),
max.at(0));
403 std::tie(platformRectMin(1), platformRectMax(1)) = std::minmax(
min.at(1),
max.at(1));
404 ARMARX_INFO <<
"using platform rectangle min / max " << platformRectMin.transpose() <<
" / "
405 << platformRectMax.transpose();
418 robotState = getProxy<RobotStateComponentInterfacePrx>(robotStateComponentName);
419 laserScannerUnit = getProxy<LaserScannerUnitInterfacePrx>(laserScannerUnitName);
421 for (LaserScannerInfo
const& info : laserScannerUnit->getConnectedDevices())
423 FramedPoseBasePtr basePose = sharedRobot->getRobotNode(info.frame)->getPoseInRootFrame();
429 data.mutex = std::make_shared<std::mutex>();
430 scanData.push_back(
data);
433 debugObserver = getTopic<DebugObserverInterfacePrx>(debugObserverName);
435 robotRootFrame = sharedRobot->getRootNode()->getName();
437 workingMemory = getProxy<memoryx::WorkingMemoryInterfacePrx>(workingMemoryName);
438 agentsMemory = workingMemory->getAgentInstancesSegment();
439 if (agentName.empty())
441 agentName = robotState->getRobotName();
444 agentInstance->setSharedRobot(sharedRobot);
445 agentInstance->setAgentFilePath(robotState->getRobotFilename());
446 agentInstance->setName(agentName);
448 longtermMemory = getProxy<memoryx::LongtermMemoryInterfacePrx>(longtermMemoryName);
449 selfLocalisationSegment = longtermMemory->getSelfLocalisationSegment();
452 reportTopic = getTopic<LaserScannerSelfLocalisationListenerPrx>(reportTopicName);
454 platformUnitTopic = getTopic<PlatformUnitListenerPrx>(
"PlatformState");
456 estimatedPose = Eigen::Vector3f::Zero();
457 memoryx::EntityBasePtr poseEntity = selfLocalisationSegment->getEntityByName(agentName);
460 poseEntityId = poseEntity->getId();
461 ARMARX_INFO <<
"Using pose entity from LTM with ID: " << poseEntityId;
462 memoryx::EntityAttributeBasePtr poseAttribute = poseEntity->getAttribute(
"pose");
466 FramedPosePtr framedPose = armarx::VariantPtr::dynamicCast(poseAttribute->getValueAt(0))
472 Eigen::Vector2f robotPos = globalPose.block<2, 1>(0, 3);
473 Eigen::Vector2f yWorld(0.0f, 1.0f);
474 Eigen::Vector2f yRobot = robotRot.col(1).head<2>();
475 float robotTheta = acos(yWorld.dot(yRobot));
476 if (yRobot.x() >= 0.0f)
478 robotTheta = -robotTheta;
481 estimatedPose = Eigen::Vector3f(robotPos.x(), robotPos.y(), robotTheta);
485 ARMARX_WARNING <<
"'pose' attribute does not contain a framed pose";
490 ARMARX_WARNING <<
"No attribute 'pose' in entity for agent '" << agentName <<
"' found";
495 ARMARX_WARNING <<
"No pose in longterm memory found for agent: " << agentName;
500 poseEntity->setName(agentName);
501 poseEntity->putAttribute(
"pose", pose);
504 poseEntityId = selfLocalisationSegment->addEntity(poseEntity);
507 ARMARX_INFO <<
"Initial pose: (" << estimatedPose[0] <<
", " << estimatedPose[1] <<
", "
508 << estimatedPose[2] <<
")";
509 resetKalmanFilter(estimatedPose);
511 lastVelocity = Eigen::Vector3f::Zero();
513 usingTopic(laserScannerUnit->getReportTopicName());
517 int updatePeriod = getProperty<int>(
"UpdatePeriodInMs");
520 &LaserScannerSelfLocalisation::updateLocalisation,
522 "UpdateLocalisation");
531 if (laserScannerFileLoggingData)
548 prop->topic(globalRobotPoseTopic);
556 return reportTopicName;
566 std::unique_lock lock(setPoseMutex);
567 setPose = Eigen::Vector3f(x, y, theta);
568 resetKalmanFilter(*setPose);
574 const std::string& name,
575 const LaserScan& scan,
576 const TimestampBasePtr& timestamp,
581 if (
data.info.device == device)
583 std::unique_lock lock(*
data.mutex);
585 data.measurementTime = IceUtil::Time::microSeconds(timestamp->timestamp);
590 static Eigen::Vector3f
591 addPose(Eigen::Vector3f pose, Eigen::Vector3f add)
593 Eigen::Vector3f result = pose + add;
599 static Eigen::Vector3f
600 integratePose(Eigen::Vector3f pose, Eigen::Vector3f v0, Eigen::Vector3f v1,
float dt)
605 float dTheta = 0.5f *
dt * (v0[2] + v1[2]);
607 float thetaMid = pose[2] + 0.5f * dTheta;
609 Eigen::Vector2f globalV0 = rotation * v0.head<2>();
610 Eigen::Vector2f globalV1 = rotation * v1.head<2>();
611 Eigen::Vector2f globalDeltaPos = 0.5f *
dt * (globalV0 + globalV1);
613 Eigen::Vector3f d(globalDeltaPos.x(), globalDeltaPos.y(), dTheta);
614 return addPose(pose, d);
624 auto elapsedSeconds = now - lastVelocityUpdate;
625 lastVelocityUpdate = now;
627 std::unique_lock lock(kalmanMutex);
628 filter->predict(velX, velY, velTheta, elapsedSeconds);
634 std::unique_lock lock(odometryMutex);
637 static_cast<float>(elapsedSeconds.toSecondsDouble()), velX, velY, velTheta});
651 LaserScannerSelfLocalisation::updateLocalisation()
656 propertyMutex.lock();
657 int halfFrameSize = propSmoothFrameSize / 2;
658 int mergeDistance = propSmoothMergeDistance;
659 float maxDistanceSquared = propMatchingMaxDistance * propMatchingMaxDistance;
660 float minPointsForMatch = propMatchingMinPoints;
661 float matchingCorrectionFactor = propMatchingCorrectionFactor;
662 bool reportPoints = propReportPoints;
663 bool reportEdges = propReportEdges;
664 bool useMapCorrection = propUseMapCorrection;
665 int epsilon = propEdgeEpsilon;
666 int minPointsPerEdge = propEdgeMinPoints;
667 float maxDistanceForEdgeSquared = propEdgeMaxDistance * propEdgeMaxDistance;
668 float pointAddingThreshold = propEdgePointAddingThreshold;
669 float edgeMaxDeltaAngle = propEdgeMaxDeltaAngle;
670 propertyMutex.unlock();
672 Eigen::Vector3f currentPose = estimatedPose;
677 std::unique_lock lock(odometryMutex);
680 Eigen::Vector3f currentVelocity(report.x, report.y, report.theta);
681 Eigen::Vector3f motionPrediction =
682 integratePose(currentPose, lastVelocity, currentVelocity, report.dt);
683 if (anyIsNaN(motionPrediction))
685 ARMARX_WARNING <<
"Motion prediction is NaN: " << motionPrediction;
691 currentPose = motionPrediction;
694 lastVelocity = currentVelocity;
696 reportedVelocities.clear();
700 std::size_t pointsSize = 0;
704 if (scanData.empty())
706 measurementTime = now;
710 measurementTime =
std::max(measurementTime,
data.measurementTime);
712 std::unique_lock lock(*
data.mutex);
713 if (
data.scan.empty())
718 pointsSize +=
data.scan.size();
721 double deltaMeasurement = (now -
data.measurementTime).toSecondsDouble();
722 if (deltaMeasurement < -0.005)
725 <<
"Delta between now and measurement time is negative: "
726 << deltaMeasurement <<
" now: " << now.toDateTime()
727 <<
" measurement: " <<
data.measurementTime.toDateTime();
729 else if (deltaMeasurement > maximalLaserScannerDelay)
732 <<
"Delta between now and measurement time has exceeded the limit ("
733 << deltaMeasurement <<
"s > " << maximalLaserScannerDelay
734 <<
"s). Activating emergency stop!";
736 EmergencyStopMasterInterfacePrx emergencyStopMaster =
737 getProxy<EmergencyStopMasterInterfacePrx>(emergencyStopMasterName);
738 if (emergencyStopMaster)
740 emergencyStopMaster->setEmergencyStopState(eEmergencyStopActive);
744 ARMARX_ERROR <<
"Could not activate emergency stop because proxy for "
745 "EmergencyStopMaster was not found '"
746 << emergencyStopMasterName <<
"'";
750 if (useMapCorrection && pointsSize > 0)
754 Eigen::Rotation2Df globalRotation = Eigen::Rotation2Df(currentPose[2]);
755 Eigen::Vector2f globalTranslation = currentPose.head<2>();
757 std::unique_lock lock(*
data.mutex);
759 data.points.reserve(
data.scan.size());
760 for (
int stepIndex = 0; stepIndex < (int)
data.scan.size(); ++stepIndex)
762 LaserScanStep
const& step =
data.scan[stepIndex];
765 float distanceSum = 0;
766 int distanceElements = 0;
767 int minFrameIndex =
std::max(0, stepIndex - halfFrameSize);
769 std::min((
int)(
data.scan.size()) - 1, stepIndex + halfFrameSize);
770 for (
int frameIndex = minFrameIndex; frameIndex <= maxFrameIndex; ++frameIndex)
772 float frameDistance =
data.scan[frameIndex].distance;
773 int deltaDistance =
std::abs(step.distance - frameDistance);
774 if (deltaDistance <= mergeDistance)
776 distanceSum += frameDistance;
780 if (distanceElements == 0)
783 <<
"No elements with distance smaller than merge distance found.";
789 float distance = distanceSum / distanceElements;
792 float sinAngle, cosAngle;
793 sincosf(step.angle, &sinAngle, &cosAngle);
797 Eigen::Vector2f localPoint =
798 (
data.pose * Eigen::Vector4f(x, y, 0, 1)).head<2>();
800 if (anyIsNaN(localPoint))
804 <<
" " <<
VAROUT(step.angle);
808 if (platformRectMin(0) < localPoint(0) && localPoint(0) < platformRectMax(0) &&
809 platformRectMin(1) < localPoint(1) && localPoint(1) < platformRectMax(1))
812 <<
"discarding point inside of the platform rectangle: "
813 << localPoint.transpose();
817 Eigen::Vector2f globalPoint = globalRotation * localPoint + globalTranslation;
819 if (anyIsNaN(globalPoint))
827 data.points.push_back(globalPoint);
836 std::vector<armarx::Vector2f> pointsA;
837 pointsA.reserve(pointsSize);
840 for (
auto& p :
data.points)
842 pointsA.push_back(armarx::Vector2f{p.x(), p.y()});
847 reportTopic->begin_reportLaserScanPoints(pointsA);
855 std::size_t edgeCount = 0;
859 auto& points =
data.points;
861 std::vector<float> angles;
862 angles.reserve(points.size());
863 int pointsSize = (int)points.size();
864 for (
int pointIndex = 0; pointIndex < pointsSize; ++pointIndex)
866 int beginIndex =
std::max(pointIndex - epsilon, 0);
867 int endIndex =
std::min(pointIndex + epsilon + 1, pointsSize - 1);
868 Eigen::Vector2f* beginPoint = &
data.points[beginIndex];
869 Eigen::Vector2f* endPoint = &
data.points[endIndex];
870 Line line(leastSquareLine(beginPoint, endPoint));
871 float angle = std::atan2(line.direction().x(), line.direction().y());
872 if (std::isnan(
angle))
879 angles.push_back(
angle);
884 int endIndex = beginIndex;
885 int maxEndIndex = pointsSize - 1;
886 int minBeginIndex = 0;
888 int maximumPointsInEdge = 0;
892 while (endIndex < maxEndIndex)
894 float yaw = angles[endIndex];
899 while (endIndex < maxEndIndex &&
900 std::fabs(yaw - angles[endIndex + 1]) < edgeMaxDeltaAngle &&
901 (points[endIndex + 1] - points[endIndex]).squaredNorm() <
902 maxDistanceForEdgeSquared)
911 bool frontExtended =
false;
912 bool backExtended =
false;
915 while (beginIndex > minBeginIndex &&
916 (points[beginIndex - 1] - points[beginIndex]).squaredNorm() <
917 maxDistanceForEdgeSquared &&
918 leastSquareEdge(points.data() + beginIndex - 1,
919 points.data() + endIndex + 1,
920 edgeLineSegment[resultIndex]) < pointAddingThreshold)
923 resultIndex = !resultIndex;
924 frontExtended =
true;
928 while (endIndex < maxEndIndex &&
929 (points[endIndex] - points[endIndex + 1]).squaredNorm() <
930 maxDistanceForEdgeSquared &&
931 leastSquareEdge(points.data() + beginIndex,
932 points.data() + endIndex + 1,
933 edgeLineSegment[resultIndex]) < pointAddingThreshold)
936 resultIndex = !resultIndex;
940 if (!frontExtended && !backExtended)
942 leastSquareEdge(points.data() + beginIndex,
943 points.data() + endIndex + 1,
944 edgeLineSegment[!resultIndex]);
948 int numberOfPoints = endIndex - beginIndex + 1;
949 if (numberOfPoints > minPointsPerEdge)
954 Eigen::Vector2f* pointsBegin = points.data() + beginIndex;
955 ExtractedEdge edge{segment, pointsBegin, pointsBegin + numberOfPoints};
956 data.edges.push_back(edge);
958 maximumPointsInEdge =
std::max(numberOfPoints, maximumPointsInEdge);
959 minBeginIndex = endIndex + 1;
963 beginIndex = endIndex + 1;
964 endIndex = beginIndex;
970 std::vector<armarx::LineSegment2D> segments;
971 segments.reserve(edgeCount);
976 armarx::LineSegment2D s;
979 segments.push_back(s);
982 reportTopic->begin_reportExtractedEdges(segments);
985 std::size_t rowCount = 0;
986 Eigen::Vector2f robotPos = currentPose.head<2>();
988 Eigen::MatrixX3f X(pointsSize, 3);
989 Eigen::VectorXf Y(pointsSize);
996 auto& globalPoint = *p;
999 float minDistanceSquared = FLT_MAX;
1002 float distanceSquared =
1003 lineSegmentToPointDistanceSquared(segment, globalPoint);
1004 if (distanceSquared < minDistanceSquared)
1006 minDistanceSquared = distanceSquared;
1010 if (minDistanceSquared > maxDistanceSquared)
1016 ARMARX_WARNING <<
"No line segment closest to point found: " << globalPoint;
1020 Eigen::Vector2f
const&
v = globalPoint;
1021 Eigen::Vector2f targetDir =
target->end -
target->start;
1022 Eigen::Vector2f u = Eigen::Vector2f(-targetDir.y(), targetDir.x()).normalized();
1023 float r =
target->start.dot(u);
1024 Eigen::Vector2f cToV(
v - robotPos);
1025 Eigen::Vector2f cToVOrth(-cToV.y(), cToV.x());
1026 float x3 = u.dot(cToVOrth);
1027 float y = r - u.dot(
v);
1029 X(rowCount, 0) = u(0);
1030 X(rowCount, 1) = u(1);
1031 X(rowCount, 2) = x3;
1038 Eigen::Vector3f b = Eigen::Vector3f::Zero();
1039 float matched =
static_cast<float>(rowCount) / pointsSize;
1040 debugObserver->setDebugDatafield(
getName(),
"MatchedDataPointRatio",
new Variant(matched));
1041 if (matched < minPointsForMatch)
1045 <<
"Too few data points could be associated with edges of the map (associated: "
1046 << rowCount <<
"/" << pointsSize <<
" = " << matched <<
")";
1048 else if (rowCount > 10)
1050 b = X.block(0, 0, rowCount, 3)
1051 .jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV)
1052 .solve(Y.head(rowCount));
1053 b *= matchingCorrectionFactor;
1057 <<
" " <<
VAROUT(rowCount);
1061 Eigen::Vector3f newEstimatedPose = addPose(currentPose, b);
1062 if (anyIsNaN(newEstimatedPose))
1069 estimatedPose = newEstimatedPose;
1072 std::unique_lock lock(kalmanMutex);
1073 if (propSensorStdDev > 0)
1075 filter->update(estimatedPose(0), estimatedPose(1), estimatedPose(2));
1081 estimatedPose = currentPose;
1084 Eigen::Vector3f filteredPose;
1085 if (propSensorStdDev > 0)
1087 Eigen::Matrix3d cov = filter->getCovariance();
1088 reportTopic->begin_reportPoseUncertainty(cov(0, 0), cov(1, 1), cov(2, 2));
1090 filteredPose = filter->getPose().cast<
float>();
1094 filteredPose = estimatedPose;
1097 std::unique_lock lock(setPoseMutex);
1100 estimatedPose = *setPose;
1101 resetKalmanFilter(estimatedPose);
1105 reportTopic->begin_reportCorrectedPose(filteredPose[0], filteredPose[1], filteredPose[2]);
1106 PlatformPose newPose;
1107 newPose.timestampInMicroSeconds = measurementTime.toMicroSeconds();
1108 newPose.x = filteredPose[0];
1109 newPose.y = filteredPose[1];
1110 newPose.rotationAroundZ = filteredPose[2];
1114 orientation.block<2, 2>(0, 0) = Eigen::Rotation2Df(filteredPose[2]).matrix();
1115 Eigen::Vector3f position(filteredPose[0], filteredPose[1], robotPositionZ);
1121 header.frame = robotRootFrame;
1122 header.agent = agentName;
1123 header.timestampInMicroSeconds = measurementTime.toMicroSeconds();
1125 TransformStamped globalRobotPose;
1126 globalRobotPose.header = header;
1127 globalRobotPose.transform = reportPose->toEigen();
1129 globalRobotPoseTopic->reportGlobalRobotPose(globalRobotPose);
1133 if (updateWorkingMemory &&
1134 s.checkFrequency(
"workingMemoryUpdate", workingMemoryUpdateFrequency))
1141 agentInstance->setPose(reportPose);
1144 std::string robotAgentId =
1145 agentsMemory->upsertEntityByName(agentInstance->getName(), agentInstance);
1146 agentInstance->setId(robotAgentId);
1159 if (
s.checkFrequency(
"longtermMemoryUpdate", longtermMemoryUpdateFrequency))
1162 poseEntity->setName(agentName);
1163 poseEntity->putAttribute(
"pose", reportPose);
1164 poseEntity->setId(poseEntityId);
1166 if (selfLocalisationSegment)
1168 selfLocalisationSegment->upsertEntity(poseEntityId, poseEntity);
1176 catch (IceUtil::Exception
const& ex)
1178 ARMARX_WARNING <<
"Caught exception while updating the memory:\n" << ex;
1181 if (laserScannerFileLoggingData)
1183 laserScannerFileLoggingData->scanDataHistory[now] = (scanData);
1190 #define ARMARX_LSSL_UPDATE_PROPERTY(name) \
1192 auto prop = getProperty<decltype(prop##name)>(#name); \
1193 if (initial || prop.isSet()) \
1195 prop##name = prop.getValue(); \
1196 ARMARX_VERBOSE << VAROUT(prop##name); \
1202 std::unique_lock lock(propertyMutex);
1205 if (
std::abs(propSensorStdDev - getProperty<float>(
"SensorStdDev").
getValue()) > 0.001)
1207 propSensorStdDev = getProperty<float>(
"SensorStdDev");
1211 resetKalmanFilter(estimatedPose);
1214 if (
std::abs(propVelSensorStdDev - getProperty<float>(
"VelSensorStdDev").
getValue()) >
1217 propVelSensorStdDev = getProperty<float>(
"VelSensorStdDev");
1221 resetKalmanFilter(estimatedPose);
1245 if (!propLoggingFilePath.empty())
1247 if (laserScannerFileLoggingData && propRecordData &&
1248 !getProperty<bool>(
"RecordData").
getValue())
1252 if (!propRecordData && getProperty<bool>(
"RecordData").
getValue())
1255 laserScannerFileLoggingData.reset(
new LaserScannerFileLoggingData());
1256 laserScannerFileLoggingData->filePath = propLoggingFilePath;
1258 propRecordData = getProperty<bool>(
"RecordData").getValue();
1261 useOdometry = propUseOdometry;
1263 catch (std::exception
const& ex)
1268 #undef ARMARX_LSSL_UPDATE_PROPERTY
1272 LaserScannerSelfLocalisation::resetKalmanFilter(
const Eigen::Vector3f& pose)
1274 ARMARX_INFO <<
"Position Std Dev: " << propSensorStdDev
1275 <<
" Vel Std Dev: " << propVelSensorStdDev;
1276 std::unique_lock lock(kalmanMutex);
1278 pose.head<2>().cast<
double>(),
1281 propSensorStdDev / 100,
1282 propVelSensorStdDev,
1283 propVelSensorStdDev ));
1287 LaserScannerSelfLocalisation::writeLogFile()
1289 if (!laserScannerFileLoggingData)
1292 <<
"laserScannerFileLoggingData is NULL - cannot write log file";
1295 std::map<IceUtil::Time, std::vector<LaserScanData>> dataMap;
1296 std::string filePath;
1298 std::unique_lock lock(laserScannerFileLoggingData->loggingMutex);
1299 dataMap.swap(laserScannerFileLoggingData->scanDataHistory);
1300 filePath = laserScannerFileLoggingData->filePath;
1302 ARMARX_INFO <<
"Writing " << dataMap.size() <<
" laser scans";
1303 laserScannerFileLoggingData.reset();
1304 nlohmann::json json;
1305 std::ofstream file(filePath, std::ofstream::out | std::ofstream::trunc);
1311 int skipLineAmount = 10;
1313 for (
auto& pair : dataMap)
1315 if (i % skipLineAmount != 0)
1319 const std::vector<LaserScanData>& scanData = pair.second;
1320 for (
auto& elem : scanData)
1324 json[
"DeviceInfo"][scan.
info.device] = {
1325 {
"frame", scan.
info.frame},
1326 {
"minAngle", scan.
info.minAngle},
1327 {
"maxAngle", scan.
info.maxAngle},
1328 {
"stepSize", scan.
info.stepSize},
1330 {{
"x", scan.
pose(0, 3)}, {
"y", scan.
pose(1, 3)}, {
"z", scan.
pose(2, 3)}}},
1331 {
"sensorOrientation",
1332 {{
"w", quat.w()}, {
"x", quat.x()}, {
"y", quat.y()}, {
"z", quat.z()}}}
1335 Ice::IntSeq dataPts;
1336 for (
const auto& pt : scan.
points)
1338 dataPts.push_back(pt(0));
1339 dataPts.push_back(pt(1));
1341 json[
"Data"][scan.
info.device][
"GlobalPoints"] += dataPts;
1342 Ice::IntSeq scanPts;
1343 for (
const LaserScanStep& pt : scan.
scan)
1345 scanPts.push_back(pt.distance);
1347 json[
"Data"][scan.
info.device][
"ScanDistances"] += scanPts;
1351 file << std::setw(1) << json << std::endl;
1357 LineSegment2DSeq result;
1360 armarx::Vector2f start{segment.start.x(), segment.start.y()};
1361 armarx::Vector2f end{segment.end.x(), segment.end.y()};
1362 result.push_back(LineSegment2D{start, end});
1369 const std::set<std::string>& changedProperties)