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,