From da091486a8fb1e594d2e1c236308ceb54c874610 Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Tue, 17 Sep 2019 17:06:46 +0200
Subject: [PATCH] Return actually used timestamps

---
 .../RobotState/RobotStateComponent.cpp        | 122 +++++++++++-------
 .../RobotState/RobotStateComponent.h          |  12 +-
 2 files changed, 86 insertions(+), 48 deletions(-)

diff --git a/source/RobotAPI/components/RobotState/RobotStateComponent.cpp b/source/RobotAPI/components/RobotState/RobotStateComponent.cpp
index f76939c27..545a9bd0a 100644
--- a/source/RobotAPI/components/RobotState/RobotStateComponent.cpp
+++ b/source/RobotAPI/components/RobotState/RobotStateComponent.cpp
@@ -24,21 +24,24 @@
 
 #include "RobotStateComponent.h"
 #include <boost/foreach.hpp>
-#include <VirtualRobot/XML/RobotIO.h>
-#include <VirtualRobot/Nodes/RobotNode.h>
+#include <boost/format.hpp>
+
 #include <VirtualRobot/RobotNodeSet.h>
 #include <VirtualRobot/math/Helpers.h>
-#include <boost/format.hpp>
-#include <boost/foreach.hpp>
-#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <VirtualRobot/Nodes/RobotNode.h>
+#include <VirtualRobot/XML/RobotIO.h>
+
 #include <ArmarXCore/core/ArmarXManager.h>
 #include <ArmarXCore/core/ArmarXObjectScheduler.h>
 #include <ArmarXCore/core/application/Application.h>
 #include <ArmarXCore/core/rapidxml/wrapper/RapidXmlReader.h>
+#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <ArmarXCore/core/time/TimeUtil.h>
+
 
-using namespace VirtualRobot;
 using namespace Eigen;
 using namespace Ice;
+using namespace VirtualRobot;
 
 
 namespace armarx
@@ -227,7 +230,7 @@ namespace armarx
 
     SharedRobotInterfacePrx RobotStateComponent::getRobotSnapshotAtTimestamp(double _time, const Current&)
     {
-        IceUtil::Time time = IceUtil::Time::microSecondsDouble(_time);
+        const IceUtil::Time time = IceUtil::Time::microSecondsDouble(_time);
 
         if (!_synchronized)
         {
@@ -256,7 +259,7 @@ namespace armarx
     NameValueMap RobotStateComponent::getJointConfigAtTimestamp(double timestamp, const Current&) const
     {
         auto jointAngles = interpolateJoints(IceUtil::Time::microSecondsDouble(timestamp));
-        return jointAngles ? *jointAngles : NameValueMap();
+        return jointAngles ? jointAngles->value : NameValueMap();
     }
 
 
@@ -346,6 +349,7 @@ namespace armarx
         }
     }
 
+
     void RobotStateComponent::reportNewTargetPose(
         Float newPlatformPositionX, Float newPlatformPositionY, Float newPlatformRotation,
         const Current&)
@@ -354,6 +358,7 @@ namespace armarx
         (void) newPlatformPositionX, (void) newPlatformPositionY, (void) newPlatformRotation;
     }
 
+
     void RobotStateComponent::reportPlatformVelocity(
         Float currentPlatformVelocityX, Float currentPlatformVelocityY, Float currentPlatformVelocityRotation,
         const Current&)
@@ -362,12 +367,14 @@ namespace armarx
         (void) currentPlatformVelocityX, (void) currentPlatformVelocityY, (void) currentPlatformVelocityRotation;
     }
 
+
     void RobotStateComponent::reportPlatformOdometryPose(Float x, Float y, Float angle, const Current&)
     {
         // Unused.
         (void) x, (void) y, (void) angle;
     }
 
+
     std::vector<std::string> RobotStateComponent::getArmarXPackages(const Current&) const
     {
         std::vector<std::string> result;
@@ -469,13 +476,19 @@ namespace armarx
 
     void RobotStateComponent::insertPose(IceUtil::Time timestamp, const Matrix4f& globalPose)
     {
-        boost::unique_lock<SharedMutex> lock(poseHistoryMutex);
-        poseHistory.emplace_hint(poseHistory.end(),
-                                 timestamp, new FramedPose(globalPose, GlobalFrame, ""));
-
-        if (poseHistory.size() > poseHistoryLength)
+        IceUtil::Time duration;
         {
-            poseHistory.erase(poseHistory.begin());
+            IceUtil::Time start = IceUtil::Time::now();
+            boost::unique_lock<SharedMutex> lock(poseHistoryMutex);
+            duration = IceUtil::Time::now() - start;
+
+            poseHistory.emplace_hint(poseHistory.end(),
+                                     timestamp, new FramedPose(globalPose, GlobalFrame, ""));
+
+            if (poseHistory.size() > poseHistoryLength)
+            {
+                poseHistory.erase(poseHistory.begin());
+            }
         }
 
         if (robotStateObs)
@@ -492,9 +505,11 @@ namespace armarx
         if (joints && globalPose)
         {
             RobotStateConfig config;
-            config.timestamp = time.toMicroSeconds();
-            config.jointMap = *joints;
-            config.globalPose = *globalPose;
+            // Use time stamp from interpolation.
+            // config.timestamp = time.toMicroSeconds();
+            config.timestamp = std::min(joints->timestamp, globalPose->timestamp).toMicroSeconds();
+            config.jointMap = joints->value;
+            config.globalPose = globalPose->value;
             return std::move(config);
         }
         else
@@ -503,7 +518,7 @@ namespace armarx
         }
     }
 
-    std::optional<NameValueMap> RobotStateComponent::interpolateJoints(IceUtil::Time time) const
+    auto RobotStateComponent::interpolateJoints(IceUtil::Time time) const -> std::optional<Timestamped<NameValueMap>>
     {
         boost::shared_lock<SharedMutex> lock(jointHistoryMutex);
         if (jointHistory.empty())
@@ -516,15 +531,24 @@ namespace armarx
         if (time > newestTimeInHistory)
         {
             IceUtil::Time maxOffset = IceUtil::Time::seconds(2);
-            if (time > newestTimeInHistory + maxOffset)
+            if (time <= newestTimeInHistory + maxOffset)
             {
-                ARMARX_WARNING << deactivateSpam(1) << "Requested timestamp is substantially newer (>"
+                ARMARX_INFO << deactivateSpam(5)
+                            << "Requested joint timestamp is newer than newest available timestamp!"
+                            << "\n- requested timestamp: \t" << time.toDateTime()
+                            << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime()
+                            << "\n- difference:          \t" << (time - newestTimeInHistory).toMicroSeconds() << " us";
+            }
+            else
+            {
+                ARMARX_WARNING << deactivateSpam(1) << "Requested joint timestamp is substantially newer (>"
                                << maxOffset.toSecondsDouble() << " sec) than newest available timestamp!"
-                               << "\nrequested timestamp: " << time.toDateTime()
-                               << " newest timestamp: " << newestTimeInHistory.toDateTime();
+                               << "\n- requested timestamp: \t" << time.toDateTime()
+                               << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime();
                 return std::nullopt;
             }
-            return jointHistory.rbegin()->second;
+
+            return Timestamped<NameValueMap> {jointHistory.rbegin()->first, jointHistory.rbegin()->second};
         }
 
         // Get the oldest entry whose time >= time.
@@ -532,21 +556,19 @@ namespace armarx
         if (nextIt == jointHistory.end())
         {
             ARMARX_WARNING << deactivateSpam(1)
-                           << "Could not find or interpolate a robot joint angles for time "
-                           << time.toDateTime()
-                           << "\n - oldest available value: " << jointHistory.begin()->first.toDateTime()
-                           << "\n - newest available value: " << newestTimeInHistory.toDateTime();
+                           << "Could not find or interpolate a robot joint angles for time " << time.toDateTime()
+                           << "\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
+                           << "\n- newest available value: " << newestTimeInHistory.toDateTime();
             return std::nullopt;
         }
 
-        const NameValueMap& next = nextIt->second;
-
         if (nextIt == jointHistory.begin())
         {
             // Next was oldest entry.
-            return next;
+            return Timestamped<NameValueMap> {nextIt->first, nextIt->second};
         }
 
+        const NameValueMap& next = nextIt->second;
         auto prevIt = std::prev(nextIt);
 
 
@@ -568,13 +590,12 @@ namespace armarx
             jointAngles.emplace(name, value);
         }
 
-        return std::move(jointAngles);
+        return Timestamped<NameValueMap> {time, std::move(jointAngles)};
     }
 
-    std::optional<FramedPosePtr> RobotStateComponent::interpolatePose(IceUtil::Time time) const
+    auto RobotStateComponent::interpolatePose(IceUtil::Time time) const -> std::optional<Timestamped<FramedPosePtr>>
     {
         boost::shared_lock<SharedMutex> lock(poseHistoryMutex);
-        // Get the older newer entry of time.
 
         if (poseHistory.empty())
         {
@@ -582,7 +603,9 @@ namespace armarx
                         << "Pose history is empty. This can happen if there is no platform unit.";
 
             ReadLockPtr readLock = _synchronized->getReadLock();
-            return new FramedPose(_synchronized->getGlobalPose(), armarx::GlobalFrame, "");
+
+            FramedPosePtr pose = new FramedPose(_synchronized->getGlobalPose(), armarx::GlobalFrame, "");
+            return Timestamped<FramedPosePtr> {IceUtil::Time::seconds(0), pose};
         }
 
 
@@ -590,15 +613,23 @@ namespace armarx
         if (time > newestTimeInHistory)
         {
             IceUtil::Time maxOffset = IceUtil::Time::seconds(2);
-            if (time > newestTimeInHistory + maxOffset)
+            if (time <= newestTimeInHistory + maxOffset)
             {
-                ARMARX_WARNING << deactivateSpam(1) << "Requested timestamp is substantially newer (>"
+                ARMARX_INFO << deactivateSpam(5)
+                            << "Requested pose timestamp is newer than newest available timestamp!"
+                            << "\n- requested timestamp: \t" << time.toDateTime()
+                            << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime()
+                            << "\n- difference:          \t" << (time - newestTimeInHistory).toMicroSeconds() << " us";
+            }
+            else
+            {
+                ARMARX_WARNING << deactivateSpam(1) << "Requested pose timestamp is substantially newer (>"
                                << maxOffset.toSecondsDouble() << " sec) than newest available timestamp!"
-                               << "\nrequested timestamp: " << time.toDateTime()
-                               << " newest timestamp: " << newestTimeInHistory.toDateTime();
+                               << "\n- requested timestamp: \t" << time.toDateTime()
+                               << "\n- newest timestamp:    \t" << newestTimeInHistory.toDateTime();
                 return std::nullopt;
             }
-            return poseHistory.rbegin()->second;
+            return Timestamped<FramedPosePtr> {poseHistory.rbegin()->first, poseHistory.rbegin()->second};
         }
 
 
@@ -607,23 +638,22 @@ namespace armarx
         {
             ARMARX_WARNING << deactivateSpam(1)
                            << "Could not find or interpolate platform pose for time " << time.toDateTime()
-                           << "\n - oldest available value: " << jointHistory.begin()->first.toDateTime()
-                           << "\n - newest available value: " << newestTimeInHistory.toDateTime();
+                           << "\n- oldest available value: " << jointHistory.begin()->first.toDateTime()
+                           << "\n- newest available value: " << newestTimeInHistory.toDateTime();
             return std::nullopt;
         }
 
 
-        const FramedPosePtr& next = nextIt->second;
-
         if (nextIt == poseHistory.begin())
         {
             // Next was oldest entry.
-            return next;
+            return Timestamped<FramedPosePtr> {nextIt->first, nextIt->second};
         }
 
         auto prevIt = std::prev(nextIt);
-
         ARMARX_CHECK_EXPRESSION(prevIt->second);
+
+        const FramedPosePtr& next = nextIt->second;
         const FramedPosePtr& prev = prevIt->second;
 
 
@@ -650,7 +680,7 @@ namespace armarx
 
         math::Helpers::Orientation(globalPose) = rotNew.toRotationMatrix();
 
-        return new FramedPose(globalPose, armarx::GlobalFrame, "");
+        return Timestamped<FramedPosePtr> {time, new FramedPose(globalPose, armarx::GlobalFrame, "")};
     }
 
 
diff --git a/source/RobotAPI/components/RobotState/RobotStateComponent.h b/source/RobotAPI/components/RobotState/RobotStateComponent.h
index e0fd01378..51f688b3f 100644
--- a/source/RobotAPI/components/RobotState/RobotStateComponent.h
+++ b/source/RobotAPI/components/RobotState/RobotStateComponent.h
@@ -181,12 +181,20 @@ namespace armarx
 
         void insertPose(IceUtil::Time timestamp, const Eigen::Matrix4f& globalPose);
 
+
+        template <class ValueT>
+        struct Timestamped
+        {
+            IceUtil::Time timestamp;
+            ValueT value;
+        };
+
         /// Interpolate the robot state from histories and store it in `config`.
         std::optional<RobotStateConfig> interpolate(IceUtil::Time time) const;
         /// Interpolate the joint angles from history and store it in `jointAngles`.
-        std::optional<NameValueMap> interpolateJoints(IceUtil::Time time) const;
+        std::optional<Timestamped<NameValueMap>> interpolateJoints(IceUtil::Time time) const;
         /// Interpolate the robot pose from history and store it in `pose`.
-        std::optional<FramedPosePtr> interpolatePose(IceUtil::Time time) const;
+        std::optional<Timestamped<FramedPosePtr>> interpolatePose(IceUtil::Time time) const;
 
 
     private:
-- 
GitLab