39#include <Eigen/Geometry>
41#include <IceUtil/UUID.h>
43#include <SimoxUtility/json/json.hpp>
52using 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)
71 std::ifstream t(filename.c_str());
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>());
83 parsePosition(Json::Value
const& pos)
85 Eigen::Vector2f result = Eigen::Vector2f::Zero();
86 if (pos.isArray() && pos.size() == 2)
88 Json::Value
const&
x = pos[0];
89 Json::Value
const& y = pos[1];
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;
127 Json::Value
const& unitValue = j[
"LengthUnit"];
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);
145 Json::Value
const& map = j[
"Map"];
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)
155 Json::Value
const& p = map[i];
156 Json::Value
const& position = p[
"Position"];
157 Eigen::Vector2f pos = parsePosition(position);
158 Json::Value
const& strip = p[
"RelativeLineStrip"];
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();
193 float t = std::max(0.0f, std::min(1.0f, (point - segment.
start).dot(dir) / l2));
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();
242 if (std::abs(calc_as) < 0.001f && std::abs(calc_bs) < 0.001f)
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);
388 int updatePeriodWorkingMemoryInMs =
getProperty<int>(
"UpdatePeriodWorkingMemoryInMs");
389 workingMemoryUpdateFrequency = 1000.0f / updatePeriodWorkingMemoryInMs;
390 int updatePeriodLongtermMemory =
getProperty<int>(
"UpdatePeriodLongtermMemoryInMs");
391 longtermMemoryUpdateFrequency = 1000.0f / updatePeriodLongtermMemory;
397 map = loadMapFromFile(mapFilename);
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();
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);
435 robotRootFrame = sharedRobot->getRootNode()->getName();
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);
449 selfLocalisationSegment = longtermMemory->getSelfLocalisationSegment();
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))
470 Eigen::Matrix4f globalPose = framedPose->toGlobalEigen(sharedRobot);
471 Eigen::Matrix3f robotRot = globalPose.block<3, 3>(0, 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());
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,
581 if (
data.info.device == device)
583 std::unique_lock lock(*
data.mutex);
585 data.measurementTime = IceUtil::Time::microSeconds(
timestamp->timestamp);
590static Eigen::Vector3f
591addPose(Eigen::Vector3f pose, Eigen::Vector3f add)
593 Eigen::Vector3f result = pose + add;
599static Eigen::Vector3f
600integratePose(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;
608 Eigen::Matrix2f rotation = Eigen::Rotation2Df(thetaMid).matrix();
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});
651LaserScannerSelfLocalisation::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;
702 IceUtil::Time measurementTime = IceUtil::Time::seconds(0);
704 if (scanData.empty())
706 measurementTime = now;
708 for (LaserScanData
const& data : scanData)
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 =
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)
752 for (LaserScanData& data : scanData)
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);
838 for (LaserScanData
const& data : scanData)
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;
857 for (LaserScanData& data : scanData)
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;
889 LineSegment2Df edgeLineSegment[2];
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)
953 LineSegment2Df& segment = edgeLineSegment[!resultIndex];
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);
972 for (LaserScanData
const& data : scanData)
974 for (ExtractedEdge
const& e :
data.edges)
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);
990 for (LaserScanData
const& data : scanData)
992 for (ExtractedEdge
const& edge :
data.edges)
996 auto& globalPoint = *p;
998 LineSegment2Df*
target =
nullptr;
999 float minDistanceSquared = FLT_MAX;
1000 for (LineSegment2Df& segment : map)
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];
1113 Eigen::Matrix3f orientation = Eigen::Matrix3f::Identity();
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);
1211 resetKalmanFilter(estimatedPose);
1221 resetKalmanFilter(estimatedPose);
1245 if (!propLoggingFilePath.empty())
1247 if (laserScannerFileLoggingData && propRecordData &&
1255 laserScannerFileLoggingData.reset(
new LaserScannerFileLoggingData());
1256 laserScannerFileLoggingData->filePath = propLoggingFilePath;
1261 useOdometry = propUseOdometry;
1263 catch (std::exception
const& ex)
1268#undef ARMARX_LSSL_UPDATE_PROPERTY
1272LaserScannerSelfLocalisation::resetKalmanFilter(
const Eigen::Vector3f& pose)
1274 ARMARX_INFO <<
"Position Std Dev: " << propSensorStdDev
1275 <<
" Vel Std Dev: " << propVelSensorStdDev;
1276 std::unique_lock lock(kalmanMutex);
1277 filter.reset(
new memoryx::PlatformKalmanFilter(
1278 pose.head<2>().cast<
double>(),
1281 propSensorStdDev / 100,
1282 propVelSensorStdDev,
1283 propVelSensorStdDev ));
1287LaserScannerSelfLocalisation::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)
1322 const LaserScanData& scan = elem;
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)
Eigen::ParametrizedLine< float, 2 > Line
#define ARMARX_LSSL_UPDATE_PROPERTY(name)
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
The JSONObject class is used to represent and (de)serialize JSON objects.
const Json::Value & getJsonValue() const
void fromString(const ::std::string &jsonString, const ::Ice::Current &=Ice::emptyCurrent) override
void onInitComponent() override
void componentPropertiesUpdated(const std::set< std::string > &changedProperties) override
Implement this function if you would like to react to changes in the properties.
LaserScannerSelfLocalisation()
std::string getReportTopicName(const Ice::Current &) override
void onDisconnectComponent() override
void reportPlatformVelocity(Ice::Float velX, Ice::Float velY, Ice::Float velTheta, const Ice::Current &) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
LineSegment2DSeq getMap(const Ice::Current &) override
void onConnectComponent() override
void reportPlatformOdometryPose(Ice::Float, Ice::Float, Ice::Float, const Ice::Current &) override
void setAbsolutePose(Ice::Float x, Ice::Float y, Ice::Float theta, const Ice::Current &) override
void onExitComponent() override
void reportSensorValues(const std::string &device, const std::string &name, const LaserScan &scan, const TimestampBasePtr ×tamp, const Ice::Current &) override
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
std::string getName() const
Retrieve name of object.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
The periodic task executes one thread method repeatedly using the time period specified in the constr...
virtual Eigen::Matrix4f toEigen() const
void getPropertyAsCSV(ContainerT &val, const std::string &name, const std::string &splitBy=",;", bool trimElements=true, bool removeEmptyElements=true)
Property< PropertyType > getProperty(const std::string &name)
Property creation and retrieval.
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
static float angleModPI(float value)
Simple untyped entity class which allows adding arbitrary attributes.
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
std::string const GlobalFrame
Variable of the global coordinate system.
Quaternion< float, 0 > Quaternionf
const VariantTypeId FramedPose
T getValue(nlohmann::json &userConfig, nlohmann::json &defaultConfig, const std::string &entryName)
double v(double t, double v0, double a0, double j)
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
::IceInternal::ProxyHandle<::IceProxy::armarx::SharedRobotInterface > SharedRobotInterfacePrx
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)
IceInternal::Handle< FramedPose > FramedPosePtr
Vertex target(const detail::edge_base< Directed, Vertex > &e, const PCG &)
IceInternal::Handle< SimpleEntity > SimpleEntityPtr
double distance(const Point &a, const Point &b)
double angle(const Point &a, const Point &b, const Point &c)
std::vector< Eigen::Vector2f > points