27 #include <Ice/ObjectAdapter.h>
29 #include <VirtualRobot/Nodes/RobotNode.h>
30 #include <VirtualRobot/RobotNodeSet.h>
31 #include <VirtualRobot/XML/RobotIO.h>
32 #include <VirtualRobot/math/Helpers.h>
45 using namespace Eigen;
51 RobotStateComponent::~RobotStateComponent()
57 _synchronizedPrx->unref();
65 RobotStatePropertyDefinitions::RobotStatePropertyDefinitions(std::string prefix) :
68 defineRequiredProperty<std::string>(
"RobotNodeSetName",
69 "Set of nodes that is controlled by the KinematicUnit");
70 defineRequiredProperty<std::string>(
71 "RobotFileName",
"Filename of VirtualRobot robot model (e.g. robot_model.xml)");
72 defineRequiredProperty<std::string>(
73 "AgentName",
"Name of the agent for which the sensor values are provided");
74 defineOptionalProperty<std::string>(
75 "RobotStateReportingTopic",
77 "Name of the topic on which updates of the robot state are reported.");
78 defineOptionalProperty<int>(
79 "HistoryLength", 10000,
"Number of entries in the robot state history")
81 defineOptionalProperty<float>(
"RobotModelScaling", 1.0f,
"Scaling of the robot model");
82 defineOptionalProperty<std::string>(
83 "TopicPrefix",
"",
"Prefix for the sensor value topic name.");
84 defineOptionalProperty<std::string>(
"GlobalRobotPoseLocalizationTopicName",
85 "GlobalRobotPoseLocalization",
86 "Topic where the global robot pose can be reported.");
92 return "RobotStateComponent";
98 robotStateTopicName = getProperty<std::string>(
"RobotStateReportingTopic").getValue();
99 offeringTopic(getProperty<std::string>(
"RobotStateReportingTopic"));
100 const std::size_t historyLength =
101 static_cast<std::size_t
>(getProperty<int>(
"HistoryLength").getValue());
103 jointHistory.clear();
104 jointHistoryLength = historyLength;
107 poseHistoryLength = historyLength;
109 relativeRobotFile = getProperty<std::string>(
"RobotFileName").getValue();
113 throw UserException(
"Could not find robot file " + robotFile);
116 this->_synchronized =
117 VirtualRobot::RobotIO::loadRobot(robotFile, VirtualRobot::RobotIO::eStructure);
118 _synchronized->setName(getProperty<std::string>(
"AgentName").getValue());
120 robotModelScaling = getProperty<float>(
"RobotModelScaling").getValue();
121 ARMARX_INFO <<
"scale factor: " << robotModelScaling;
122 if (robotModelScaling != 1.0f)
124 ARMARX_INFO <<
"Scaling robot model with scale factor " << robotModelScaling;
125 _synchronized = _synchronized->clone(
126 _synchronized->getName(), _synchronized->getCollisionChecker(), robotModelScaling);
129 if (this->_synchronized)
132 <<
". Robot name: " << this->_synchronized->getName();
133 this->_synchronized->setPropagatingJointValuesEnabled(
false);
140 robotNodeSetName = getProperty<std::string>(
"RobotNodeSetName").getValue();
143 if (robotNodeSetName.empty())
145 throw UserException(
"RobotNodeSet not defined");
148 VirtualRobot::RobotNodeSetPtr rns = this->_synchronized->getRobotNodeSet(robotNodeSetName);
152 throw UserException(
"RobotNodeSet not defined");
155 std::vector<RobotNodePtr> nodes = rns->getAllRobotNodes();
157 ARMARX_VERBOSE <<
"Using RobotNodeSet " << robotNodeSetName <<
" with " << nodes.size()
159 for (
const RobotNodePtr& node : nodes)
163 const auto topicPrefix = getProperty<std::string>(
"TopicPrefix").getValue();
164 usingTopic(topicPrefix + robotNodeSetName +
"State");
167 getProperty<std::string>(
"GlobalRobotPoseLocalizationTopicName").getValue());
171 readRobotInfo(robotFile);
173 catch (
const std::exception& e)
175 ARMARX_WARNING <<
"Failed to read robot info from file: " << robotFile
176 <<
".\nReason: " << e.what();
180 ARMARX_WARNING <<
"Failed to read robot info from file: " << robotFile
181 <<
" for unknown reason.";
187 RobotStateComponent::readRobotInfo(
const std::string& robotFile)
191 robotInfo = readRobotInfo(robotNode.
first_node(
"RobotInfo"));
195 RobotStateComponent::readRobotInfo(
const RapidXmlReaderNode& infoNode)
197 std::string name = infoNode.name();
198 std::string profile = infoNode.attribute_value_or_default(
"profile",
"");
199 std::string
value = infoNode.attribute_value_or_default(
"value",
"");
201 std::vector<RobotInfoNodePtr> children;
202 for (
const RapidXmlReaderNode& childNode : infoNode.nodes())
204 children.push_back(readRobotInfo(childNode));
206 return new RobotInfoNode(name, profile,
value, children);
212 robotStateListenerPrx = getTopic<RobotStateListenerInterfacePrx>(
213 getProperty<std::string>(
"RobotStateReportingTopic"));
214 _sharedRobotServant =
216 RobotStateComponentInterfacePrx::uncheckedCast(
getProxy()),
217 robotStateListenerPrx);
218 _sharedRobotServant->ref();
220 _sharedRobotServant->setRobotStateComponent(
221 RobotStateComponentInterfacePrx::uncheckedCast(
getProxy()));
222 this->_synchronizedPrx = SharedRobotInterfacePrx::uncheckedCast(
227 robotStateObs->setRobot(_synchronized);
239 if (!this->_synchronizedPrx)
241 throw NotInitializedException(
"Shared Robot is NULL",
"getSynchronizedRobot");
243 return this->_synchronizedPrx;
253 throw NotInitializedException(
"Shared Robot is NULL",
"getRobotSnapshot");
256 auto clone = this->_synchronized->clone(_synchronized->getName());
259 clone, RobotStateComponentInterfacePrx::uncheckedCast(
getProxy()),
nullptr);
261 IceUtil::Time::microSecondsDouble(_sharedRobotServant->getTimestamp()->timestamp));
264 p->setGlobalPose(
new Pose(_synchronized->getGlobalPose()));
265 return SharedRobotInterfacePrx::uncheckedCast(result);
271 const IceUtil::Time time = IceUtil::Time::microSecondsDouble(_time);
275 throw NotInitializedException(
"Shared Robot is NULL",
"getRobotSnapshot");
279 auto config = interpolate(time);
282 ARMARX_WARNING <<
"Could not find or interpolate a robot state for time "
283 << time.toDateTime();
287 clone->setJointValues(config->jointMap);
289 clone, RobotStateComponentInterfacePrx::uncheckedCast(
getProxy()),
nullptr);
290 p->setTimestamp(time);
293 p->setGlobalPose(config->globalPose);
295 return SharedRobotInterfacePrx::uncheckedCast(result);
308 auto config = interpolate(IceUtil::Time::microSecondsDouble(
timestamp));
309 return config ? *config : RobotStateConfig();
315 return relativeRobotFile;
321 return robotModelScaling;
344 <<
" from timestamp " << time.toDateTime()
345 <<
" a value changed: " << aValueChanged;
350 WriteLockPtr lock = _synchronized->getWriteLock();
357 robotStateObs->updatePoses();
360 if (_sharedRobotServant)
362 _sharedRobotServant->setTimestamp(time);
366 std::unique_lock lock(jointHistoryMutex);
367 jointHistory.emplace_hint(jointHistory.end(), time,
jointAngles);
369 if (jointHistory.size() > jointHistoryLength)
371 jointHistory.erase(jointHistory.begin());
384 std::string localRobotName = _synchronized->getName();
385 ARMARX_DEBUG <<
"Comparing " << localRobotName <<
" and "
386 << globalRobotPose.header.agent <<
".";
387 if (localRobotName == globalRobotPose.header.agent)
390 IceUtil::Time::microSeconds(globalRobotPose.header.timestampInMicroSeconds);
392 insertPose(time, globalRobotPose.transform);
393 _synchronized->setGlobalPose(globalRobotPose.transform);
395 if (_sharedRobotServant)
397 _sharedRobotServant->setGlobalPose(
new Pose(globalRobotPose.transform));
398 _sharedRobotServant->setTimestamp(time);
404 throw NotInitializedException(
"Robot Ptr is NULL",
"reportGlobalRobotPose");
408 std::vector<std::string>
411 std::vector<std::string> result;
415 for (
const std::string& projectName : packages)
417 if (projectName.empty())
422 result.push_back(projectName);
435 (void)jointModes, (
void)
timestamp, (void)aValueChanged;
469 (void)jointAccelerations, (
void)
timestamp, (void)aValueChanged;
489 (void)jointMotorTemperatures, (
void)
timestamp, (void)aValueChanged;
499 (void)jointStatuses, (
void)
timestamp, (void)aValueChanged;
506 std::lock_guard lock(poseHistoryMutex);
510 std::lock_guard lock(jointHistoryMutex);
511 jointHistory.clear();
524 robotStateObs = observer;
532 return _synchronized->getName();
536 throw NotInitializedException(
"Robot Ptr is NULL",
"getName");
543 if (robotNodeSetName.empty())
545 throw NotInitializedException(
"RobotNodeSetName is empty",
"getRobotNodeSetName");
547 return robotNodeSetName;
553 return robotStateTopicName;
562 std::unique_lock lock(poseHistoryMutex);
563 duration = IceUtil::Time::now() - start;
565 poseHistory.emplace_hint(
568 if (poseHistory.size() > poseHistoryLength)
570 poseHistory.erase(poseHistory.begin());
576 robotStateObs->updatePoses();
580 std::optional<RobotStateConfig>
583 auto joints = interpolateJoints(time);
584 auto globalPose = interpolatePose(time);
586 if (joints && globalPose)
588 RobotStateConfig config;
591 config.timestamp =
std::min(joints->timestamp, globalPose->timestamp).toMicroSeconds();
592 config.jointMap = joints->value;
593 config.globalPose = globalPose->value;
603 RobotStateComponent::interpolateJoints(
IceUtil::Time time)
const
604 -> std::optional<Timestamped<NameValueMap>>
606 std::shared_lock lock(jointHistoryMutex);
607 if (jointHistory.empty())
610 <<
"Joint history of robot state component is empty!";
614 const IceUtil::Time newestTimeInHistory = jointHistory.rbegin()->first;
615 if (time > newestTimeInHistory)
617 const IceUtil::Time minOffset = IceUtil::Time::milliSeconds(25);
619 if (time > newestTimeInHistory + maxOffset)
622 <<
"Requested joint timestamp is substantially newer (>"
623 << maxOffset.toSecondsDouble()
624 <<
" sec) than newest available timestamp!"
625 <<
"\n- requested timestamp: \t" << time.toDateTime()
626 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime();
629 else if (time > newestTimeInHistory + minOffset)
632 <<
"Requested joint timestamp is newer than newest available timestamp!"
633 <<
"\n- requested timestamp: \t" << time.toDateTime()
634 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime()
635 <<
"\n- difference: \t"
636 << (time - newestTimeInHistory).toMicroSeconds() <<
" us";
639 return Timestamped<NameValueMap>{jointHistory.rbegin()->first,
640 jointHistory.rbegin()->second};
644 auto nextIt = jointHistory.lower_bound(time);
645 if (nextIt == jointHistory.end())
648 <<
"Could not find or interpolate a robot joint angles for time "
649 << time.toDateTime() <<
"\n- oldest available value: "
650 << jointHistory.begin()->first.toDateTime()
651 <<
"\n- newest available value: " << newestTimeInHistory.toDateTime();
655 if (nextIt == jointHistory.begin())
658 return Timestamped<NameValueMap>{nextIt->first, nextIt->second};
662 auto prevIt = std::prev(nextIt);
670 float t =
static_cast<float>((time - prevTime).toSecondsDouble() /
671 (nextTime - prevTime).toSecondsDouble());
674 auto prevJointIt = prevIt->second.begin();
675 for (
const auto& [name, nextAngle] : next)
677 float value = (1 - t) * prevJointIt->second + t * nextAngle;
683 return Timestamped<NameValueMap>{time, std::move(
jointAngles)};
687 RobotStateComponent::interpolatePose(
IceUtil::Time time)
const
688 -> std::optional<Timestamped<FramedPosePtr>>
690 std::shared_lock lock(poseHistoryMutex);
692 if (poseHistory.empty())
695 <<
"Pose history is empty. This can happen if there is no platform unit.";
697 ReadLockPtr readLock = _synchronized->getReadLock();
701 return Timestamped<FramedPosePtr>{IceUtil::Time::seconds(0), pose};
705 const IceUtil::Time newestTimeInHistory = poseHistory.rbegin()->first;
706 if (time > newestTimeInHistory)
709 if (time <= newestTimeInHistory + maxOffset)
712 <<
"Requested pose timestamp is newer than newest available timestamp!"
713 <<
"\n- requested timestamp: \t" << time.toDateTime()
714 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime()
715 <<
"\n- difference: \t"
716 << (time - newestTimeInHistory).toMicroSeconds() <<
" us";
721 <<
"Requested pose timestamp is substantially newer (>"
722 << maxOffset.toSecondsDouble()
723 <<
" sec) than newest available timestamp!"
724 <<
"\n- requested timestamp: \t" << time.toDateTime()
725 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime();
728 return Timestamped<FramedPosePtr>{poseHistory.rbegin()->first,
729 poseHistory.rbegin()->second};
733 auto nextIt = poseHistory.lower_bound(time);
734 if (nextIt == poseHistory.end())
737 <<
"Could not find or interpolate platform pose for time "
738 << time.toDateTime() <<
"\n- oldest available value: "
739 << jointHistory.begin()->first.toDateTime()
740 <<
"\n- newest available value: " << newestTimeInHistory.toDateTime();
745 if (nextIt == poseHistory.begin())
748 return Timestamped<FramedPosePtr>{nextIt->first, nextIt->second};
751 auto prevIt = std::prev(nextIt);
763 float t =
static_cast<float>((time - prevTime).toSecondsDouble() /
764 (nextTime - prevTime).toSecondsDouble());
781 return Timestamped<FramedPosePtr>{time,