27 #include <Ice/ObjectAdapter.h>
29 #include <VirtualRobot/RobotNodeSet.h>
30 #include <VirtualRobot/math/Helpers.h>
31 #include <VirtualRobot/Nodes/RobotNode.h>
32 #include <VirtualRobot/XML/RobotIO.h>
44 using namespace Eigen;
51 RobotStateComponent::~RobotStateComponent()
57 _synchronizedPrx->unref();
65 RobotStatePropertyDefinitions::RobotStatePropertyDefinitions(std::string prefix) :
68 defineRequiredProperty<std::string>(
"RobotNodeSetName",
"Set of nodes that is controlled by the KinematicUnit");
69 defineRequiredProperty<std::string>(
"RobotFileName",
"Filename of VirtualRobot robot model (e.g. robot_model.xml)");
70 defineRequiredProperty<std::string>(
"AgentName",
"Name of the agent for which the sensor values are provided");
71 defineOptionalProperty<std::string>(
"RobotStateReportingTopic",
"RobotStateUpdates",
"Name of the topic on which updates of the robot state are reported.");
72 defineOptionalProperty<int>(
"HistoryLength", 10000,
"Number of entries in the robot state history").setMin(0);
73 defineOptionalProperty<float>(
"RobotModelScaling", 1.0f,
"Scaling of the robot model");
74 defineOptionalProperty<std::string>(
"TopicPrefix",
"",
"Prefix for the sensor value topic name.");
75 defineOptionalProperty<std::string>(
"GlobalRobotPoseLocalizationTopicName",
"GlobalRobotPoseLocalization",
"Topic where the global robot pose can be reported.");
81 return "RobotStateComponent";
87 robotStateTopicName = getProperty<std::string>(
"RobotStateReportingTopic").getValue();
88 offeringTopic(getProperty<std::string>(
"RobotStateReportingTopic"));
89 const std::size_t historyLength =
static_cast<std::size_t
>(getProperty<int>(
"HistoryLength").getValue());
92 jointHistoryLength = historyLength;
95 poseHistoryLength = historyLength;
97 relativeRobotFile = getProperty<std::string>(
"RobotFileName").getValue();
101 throw UserException(
"Could not find robot file " + robotFile);
104 this->_synchronized = VirtualRobot::RobotIO::loadRobot(robotFile, VirtualRobot::RobotIO::eStructure);
105 _synchronized->setName(getProperty<std::string>(
"AgentName").getValue());
107 robotModelScaling = getProperty<float>(
"RobotModelScaling").getValue();
108 ARMARX_INFO <<
"scale factor: " << robotModelScaling;
109 if (robotModelScaling != 1.0f)
111 ARMARX_INFO <<
"Scaling robot model with scale factor " << robotModelScaling;
112 _synchronized = _synchronized->clone(_synchronized->getName(), _synchronized->getCollisionChecker(), robotModelScaling);
115 if (this->_synchronized)
117 ARMARX_VERBOSE <<
"Loaded robot from file " << robotFile <<
". Robot name: " << this->_synchronized->getName();
118 this->_synchronized->setPropagatingJointValuesEnabled(
false);
125 robotNodeSetName = getProperty<std::string>(
"RobotNodeSetName").getValue();
128 if (robotNodeSetName.empty())
130 throw UserException(
"RobotNodeSet not defined");
133 VirtualRobot::RobotNodeSetPtr rns = this->_synchronized->getRobotNodeSet(robotNodeSetName);
137 throw UserException(
"RobotNodeSet not defined");
140 std::vector<RobotNodePtr> nodes = rns->getAllRobotNodes();
142 ARMARX_VERBOSE <<
"Using RobotNodeSet " << robotNodeSetName <<
" with " << nodes.size() <<
" robot nodes.";
143 for (
const RobotNodePtr& node : nodes)
147 const auto topicPrefix = getProperty<std::string>(
"TopicPrefix").getValue();
148 usingTopic(topicPrefix + robotNodeSetName +
"State");
150 usingTopic(topicPrefix + getProperty<std::string>(
"GlobalRobotPoseLocalizationTopicName").getValue());
154 readRobotInfo(robotFile);
156 catch (
const std::exception& e)
158 ARMARX_WARNING <<
"Failed to read robot info from file: " << robotFile <<
".\nReason: " << e.what();
162 ARMARX_WARNING <<
"Failed to read robot info from file: " << robotFile <<
" for unknown reason.";
167 void RobotStateComponent::readRobotInfo(
const std::string& robotFile)
171 robotInfo = readRobotInfo(robotNode.
first_node(
"RobotInfo"));
174 RobotInfoNodePtr RobotStateComponent::readRobotInfo(
const RapidXmlReaderNode& infoNode)
176 std::string name = infoNode.name();
177 std::string profile = infoNode.attribute_value_or_default(
"profile",
"");
178 std::string
value = infoNode.attribute_value_or_default(
"value",
"");
180 std::vector<RobotInfoNodePtr> children;
181 for (
const RapidXmlReaderNode& childNode : infoNode.nodes())
183 children.push_back(readRobotInfo(childNode));
185 return new RobotInfoNode(name, profile,
value, children);
191 robotStateListenerPrx = getTopic<RobotStateListenerInterfacePrx>(getProperty<std::string>(
"RobotStateReportingTopic"));
192 _sharedRobotServant =
new SharedRobotServant(this->_synchronized, RobotStateComponentInterfacePrx::uncheckedCast(
getProxy()), robotStateListenerPrx);
193 _sharedRobotServant->ref();
195 _sharedRobotServant->setRobotStateComponent(RobotStateComponentInterfacePrx::uncheckedCast(
getProxy()));
196 this->_synchronizedPrx = SharedRobotInterfacePrx::uncheckedCast(
getObjectAdapter()->addWithUUID(_sharedRobotServant));
200 robotStateObs->setRobot(_synchronized);
211 if (!this->_synchronizedPrx)
213 throw NotInitializedException(
"Shared Robot is NULL",
"getSynchronizedRobot");
215 return this->_synchronizedPrx;
225 throw NotInitializedException(
"Shared Robot is NULL",
"getRobotSnapshot");
228 auto clone = this->_synchronized->clone(_synchronized->getName());
231 p->setTimestamp(IceUtil::Time::microSecondsDouble(_sharedRobotServant->getTimestamp()->timestamp));
234 p->setGlobalPose(
new Pose(_synchronized->getGlobalPose()));
235 return SharedRobotInterfacePrx::uncheckedCast(result);
240 const IceUtil::Time time = IceUtil::Time::microSecondsDouble(_time);
244 throw NotInitializedException(
"Shared Robot is NULL",
"getRobotSnapshot");
248 auto config = interpolate(time);
251 ARMARX_WARNING <<
"Could not find or interpolate a robot state for time " << time.toDateTime();
255 clone->setJointValues(config->jointMap);
257 p->setTimestamp(time);
260 p->setGlobalPose(config->globalPose);
262 return SharedRobotInterfacePrx::uncheckedCast(result);
268 auto jointAngles = interpolateJoints(IceUtil::Time::microSecondsDouble(timestamp));
275 auto config = interpolate(IceUtil::Time::microSecondsDouble(timestamp));
276 return config ? *config : RobotStateConfig();
282 return relativeRobotFile;
287 return robotModelScaling;
307 <<
" from timestamp " << time.toDateTime()
308 <<
" a value changed: " << aValueChanged;
313 WriteLockPtr lock = _synchronized->getWriteLock();
320 robotStateObs->updatePoses();
323 if (_sharedRobotServant)
325 _sharedRobotServant->setTimestamp(time);
329 std::unique_lock lock(jointHistoryMutex);
330 jointHistory.emplace_hint(jointHistory.end(), time,
jointAngles);
332 if (jointHistory.size() > jointHistoryLength)
334 jointHistory.erase(jointHistory.begin());
338 robotStateListenerPrx->reportJointValues(
jointAngles, timestamp, aValueChanged);
344 const TransformStamped& globalRobotPose,
349 std::string localRobotName = _synchronized->getName();
350 ARMARX_DEBUG <<
"Comparing " << localRobotName <<
" and " << globalRobotPose.header.agent <<
".";
351 if (localRobotName == globalRobotPose.header.agent)
353 const IceUtil::Time time = IceUtil::Time::microSeconds(globalRobotPose.header.timestampInMicroSeconds);
355 insertPose(time, globalRobotPose.transform);
356 _synchronized->setGlobalPose(globalRobotPose.transform);
358 if (_sharedRobotServant)
360 _sharedRobotServant->setGlobalPose(
new Pose(globalRobotPose.transform));
361 _sharedRobotServant->setTimestamp(time);
367 throw NotInitializedException(
"Robot Ptr is NULL",
"reportGlobalRobotPose");
374 std::vector<std::string> result;
378 for (
const std::string& projectName : packages)
380 if (projectName.empty())
385 result.push_back(projectName);
394 (void) jointModes, (
void) timestamp, (void) aValueChanged;
399 (void) aValueChanged;
408 (void)
jointTorques, (
void) timestamp, (void) aValueChanged;
414 (void) jointAccelerations, (
void) timestamp, (void) aValueChanged;
419 (void)
jointCurrents, (
void) timestamp, (void) aValueChanged;
424 (void) jointMotorTemperatures, (
void) timestamp, (void) aValueChanged;
429 (void) jointStatuses, (
void) timestamp, (void) aValueChanged;
435 std::lock_guard lock(poseHistoryMutex);
439 std::lock_guard lock(jointHistoryMutex);
440 jointHistory.clear();
452 robotStateObs = observer;
459 return _synchronized->getName();
463 throw NotInitializedException(
"Robot Ptr is NULL",
"getName");
470 if (robotNodeSetName.empty())
472 throw NotInitializedException(
"RobotNodeSetName is empty",
"getRobotNodeSetName");
474 return robotNodeSetName;
479 return robotStateTopicName;
488 std::unique_lock lock(poseHistoryMutex);
489 duration = IceUtil::Time::now() - start;
491 poseHistory.emplace_hint(poseHistory.end(),
494 if (poseHistory.size() > poseHistoryLength)
496 poseHistory.erase(poseHistory.begin());
502 robotStateObs->updatePoses();
506 std::optional<RobotStateConfig> RobotStateComponent::interpolate(
IceUtil::Time time)
const
508 auto joints = interpolateJoints(time);
509 auto globalPose = interpolatePose(time);
511 if (joints && globalPose)
513 RobotStateConfig config;
516 config.timestamp =
std::min(joints->timestamp, globalPose->timestamp).toMicroSeconds();
517 config.jointMap = joints->value;
518 config.globalPose = globalPose->value;
527 auto RobotStateComponent::interpolateJoints(
IceUtil::Time time)
const -> std::optional<Timestamped<NameValueMap>>
529 std::shared_lock lock(jointHistoryMutex);
530 if (jointHistory.empty())
536 const IceUtil::Time newestTimeInHistory = jointHistory.rbegin()->first;
537 if (time > newestTimeInHistory)
539 const IceUtil::Time minOffset = IceUtil::Time::milliSeconds(25);
541 if (time > newestTimeInHistory + maxOffset)
544 << maxOffset.toSecondsDouble() <<
" sec) than newest available timestamp!"
545 <<
"\n- requested timestamp: \t" << time.toDateTime()
546 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime();
549 else if (time > newestTimeInHistory + minOffset)
552 <<
"Requested joint timestamp is newer than newest available timestamp!"
553 <<
"\n- requested timestamp: \t" << time.toDateTime()
554 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime()
555 <<
"\n- difference: \t" << (time - newestTimeInHistory).toMicroSeconds() <<
" us";
558 return Timestamped<NameValueMap> {jointHistory.rbegin()->first, jointHistory.rbegin()->second};
562 auto nextIt = jointHistory.lower_bound(time);
563 if (nextIt == jointHistory.end())
566 <<
"Could not find or interpolate a robot joint angles for time " << time.toDateTime()
567 <<
"\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
568 <<
"\n- newest available value: " << newestTimeInHistory.toDateTime();
572 if (nextIt == jointHistory.begin())
575 return Timestamped<NameValueMap> {nextIt->first, nextIt->second};
579 auto prevIt = std::prev(nextIt);
587 float t =
static_cast<float>((time - prevTime).toSecondsDouble()
588 / (nextTime - prevTime).toSecondsDouble());
591 auto prevJointIt = prevIt->second.begin();
592 for (
const auto& [name, nextAngle] : next)
594 float value = (1 - t) * prevJointIt->second + t * nextAngle;
600 return Timestamped<NameValueMap> {time, std::move(
jointAngles)};
603 auto RobotStateComponent::interpolatePose(
IceUtil::Time time)
const -> std::optional<Timestamped<FramedPosePtr>>
605 std::shared_lock lock(poseHistoryMutex);
607 if (poseHistory.empty())
610 <<
"Pose history is empty. This can happen if there is no platform unit.";
612 ReadLockPtr readLock = _synchronized->getReadLock();
615 return Timestamped<FramedPosePtr> {IceUtil::Time::seconds(0), pose};
619 const IceUtil::Time newestTimeInHistory = poseHistory.rbegin()->first;
620 if (time > newestTimeInHistory)
623 if (time <= newestTimeInHistory + maxOffset)
626 <<
"Requested pose timestamp is newer than newest available timestamp!"
627 <<
"\n- requested timestamp: \t" << time.toDateTime()
628 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime()
629 <<
"\n- difference: \t" << (time - newestTimeInHistory).toMicroSeconds() <<
" us";
634 << maxOffset.toSecondsDouble() <<
" sec) than newest available timestamp!"
635 <<
"\n- requested timestamp: \t" << time.toDateTime()
636 <<
"\n- newest timestamp: \t" << newestTimeInHistory.toDateTime();
639 return Timestamped<FramedPosePtr> {poseHistory.rbegin()->first, poseHistory.rbegin()->second};
643 auto nextIt = poseHistory.lower_bound(time);
644 if (nextIt == poseHistory.end())
647 <<
"Could not find or interpolate platform pose for time " << time.toDateTime()
648 <<
"\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
649 <<
"\n- newest available value: " << newestTimeInHistory.toDateTime();
654 if (nextIt == poseHistory.begin())
657 return Timestamped<FramedPosePtr> {nextIt->first, nextIt->second};
660 auto prevIt = std::prev(nextIt);
672 float t =
static_cast<float>((time - prevTime).toSecondsDouble()
673 / (nextTime - prevTime).toSecondsDouble());