From de1ac12519492eb72f554f1e729285f1b97539a3 Mon Sep 17 00:00:00 2001 From: Rainer Kartmann <rainer.kartmann@kit.edu> Date: Tue, 17 Aug 2021 12:19:45 +0200 Subject: [PATCH] Update / fix visualization in RobotStateMemory --- .../armem_robot_state/CMakeLists.txt | 2 + .../common/localization/TransformHelper.cpp | 25 +- .../armem_robot_state/server/common/Visu.cpp | 275 ++++++++---------- .../armem_robot_state/server/common/Visu.h | 16 +- .../server/common/combine.cpp | 64 ++++ .../armem_robot_state/server/common/combine.h | 38 +++ .../proprioception/RobotStateWriter.cpp | 115 ++++---- .../server/proprioception/RobotStateWriter.h | 11 +- .../server/proprioception/Segment.cpp | 22 +- 9 files changed, 334 insertions(+), 234 deletions(-) create mode 100644 source/RobotAPI/libraries/armem_robot_state/server/common/combine.cpp create mode 100644 source/RobotAPI/libraries/armem_robot_state/server/common/combine.h diff --git a/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt b/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt index 2d1842b46..c86ed671e 100644 --- a/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt @@ -39,6 +39,7 @@ armarx_add_library( server/forward_declarations.h server/common/Visu.h + server/common/combine.h server/localization/Segment.h @@ -68,6 +69,7 @@ armarx_add_library( client/localization/TransformWriter.cpp server/common/Visu.cpp + server/common/combine.cpp server/localization/Segment.cpp diff --git a/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp b/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp index 18b84d7c6..f20f68cf8 100644 --- a/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp @@ -125,8 +125,7 @@ namespace armarx::armem::common::robot_state::localization std::vector<std::string> chain; - const auto& agentProviderSegment = - localizationCoreSegment.getProviderSegment(query.header.agent); + const auto& agentProviderSegment = localizationCoreSegment.getProviderSegment(query.header.agent); auto addToChain = [&](const std::string & parentFrame, const std::string & frame) { @@ -138,14 +137,14 @@ namespace armarx::armem::common::robot_state::localization } else { - ARMARX_WARNING << deactivateSpam(10) << "Cannot perform tf lookup '" << parentFrame << " -> " << frame - << "'"; + ARMARX_WARNING << deactivateSpam(10) << "Cannot perform tf lookup '" << parentFrame << " -> " << frame << "'"; } }; std::array<std::string, 3> knownChain { - GlobalFrame, MapFrame, OdometryFrame}; // Robot comes next + GlobalFrame, MapFrame, OdometryFrame + }; // Robot comes next auto* frameBeginIt = std::find(knownChain.begin(), knownChain.end(), query.header.parentFrame); @@ -238,10 +237,10 @@ namespace armarx::armem::common::robot_state::localization const armem::base::ProviderSegmentBase<Args...>& agentProviderSegment, const armem::Time& timestamp) { - ARMARX_DEBUG << "getEntity:" + entityName; + // ARMARX_DEBUG << "getEntity:" + entityName; const auto& entity = agentProviderSegment.getEntity(entityName); - ARMARX_DEBUG << "History (size: " << entity.size() << "): " << entity.getTimestamps(); + // ARMARX_DEBUG << "History (size: " << entity.size() << "): " << entity.getTimestamps(); // if (entity.history.empty()) // { @@ -253,27 +252,27 @@ namespace armarx::armem::common::robot_state::localization std::vector<::armarx::armem::robot_state::Transform> transforms; transforms.push_back(_convertEntityToTransform(entity.getLatestSnapshot().getInstance(0))); - ARMARX_DEBUG << "obtaining transform"; + // ARMARX_DEBUG << "obtaining transform"; if (transforms.size() > 1) { // TODO(fabian.reister): remove return transforms.front().transform; - ARMARX_DEBUG << "More than one snapshots received: " << transforms.size(); + // ARMARX_DEBUG << "More than one snapshots received: " << transforms.size(); const auto p = _interpolateTransform(transforms, timestamp); - ARMARX_DEBUG << "Done interpolating transform"; + // ARMARX_DEBUG << "Done interpolating transform"; return p; } // accept this to fail (will raise armem::error::MissingEntry) if (transforms.empty()) { - ARMARX_DEBUG << "empty transform"; + // ARMARX_DEBUG << "empty transform"; throw armem::error::MissingEntry("foo", "bar", "foo2", "bar2", 0); } - ARMARX_DEBUG << "single transform"; + // ARMARX_DEBUG << "single transform"; return transforms.front().transform; } @@ -310,8 +309,6 @@ namespace armarx::armem::common::robot_state::localization const auto poseNextIt = std::find_if(transforms.begin(), transforms.end(), timestampBeyond); - ARMARX_WARNING << "Fooasdfasdjfh"; - ARMARX_CHECK(it == poseNextIt); return poseNextIt; diff --git a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp index 0bcccee6c..051ab03e7 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp @@ -21,16 +21,22 @@ #include <RobotAPI/libraries/armem_robot_state/server/localization/Segment.h> #include <RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h> +#include "combine.h" namespace armarx::armem::server::robot_state { - Visu::Visu(const description::Segment& descriptionSegment, const proprioception::Segment& proprioceptionSegment, const localization::Segment& localizationSegment) + Visu::Visu( + const description::Segment& descriptionSegment, + const proprioception::Segment& proprioceptionSegment, + const localization::Segment& localizationSegment) : descriptionSegment(descriptionSegment), proprioceptionSegment(proprioceptionSegment), localizationSegment(localizationSegment) - {} + { + Logging::setTag("Visu"); + } void Visu::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) @@ -55,6 +61,12 @@ namespace armarx::armem::server::robot_state this->debugObserver = DebugObserverHelper("RobotStateMemory", debugObserver, batchMode); } + if (updateTask) + { + updateTask->stop(); + updateTask->join(); + updateTask = nullptr; + } updateTask = new SimpleRunningTask<>([this]() { this->visualizeRun(); @@ -65,24 +77,21 @@ namespace armarx::armem::server::robot_state void Visu::visualizeRobots(viz::Layer& layer, const robot::Robots& robots) { - const auto visualizeRobot = [&](const robot::Robot & robot) + for (const robot::Robot& robot : robots) { - const auto xmlPath = robot.description.xml.serialize(); + const data::PackagePath xmlPath = robot.description.xml.serialize(); // clang-format off - auto robotVisu = viz::Robot(robot.description.name) - // .file(xmlPath.package, xmlPath.path) - .file(xmlPath.package, xmlPath.path) - .joints(robot.config.jointMap) - .pose(robot.config.globalPose); + viz::Robot robotVisu = viz::Robot(robot.description.name) + .file(xmlPath.package, xmlPath.path) + .joints(robot.config.jointMap) + .pose(robot.config.globalPose); robotVisu.useFullModel(); // clang-format on layer.add(robotVisu); - }; - - std::for_each(robots.begin(), robots.end(), visualizeRobot); + } } @@ -106,161 +115,117 @@ namespace armarx::armem::server::robot_state } - robot::Robots combine( - const std::unordered_map<std::string, robot::RobotDescription>& robotDescriptions, - const std::unordered_map<std::string, Eigen::Affine3f>& globalRobotPoseMap, - const std::unordered_map<std::string, std::map<std::string, float>>& robotJointPositionMap) + void Visu::visualizeRun() { - - robot::Robots robots; - - for (const auto &[robotName, robotDescription] : robotDescriptions) + CycleUtil cycle(static_cast<int>(1000 / p.frequencyHz)); + while (updateTask and not updateTask->isStopped()) { - const auto& globalPose = globalRobotPoseMap.find(robotName); - if (globalPose == globalRobotPoseMap.end()) + if (p.enabled) { - ARMARX_WARNING << deactivateSpam(10) << "No global pose for robot '" << robotName - << "'"; - continue; - } + const Time timestamp = Time::now(); + ARMARX_DEBUG << "Visu task at " << armem::toStringMilliSeconds(timestamp); - const auto& jointMap = robotJointPositionMap.find(robotName); - if (jointMap == robotJointPositionMap.end()) - { - ARMARX_WARNING << deactivateSpam(10) << "No joint positions for robot '" - << robotName << "'"; - continue; + try + { + visualizeOnce(timestamp); + } + catch (const std::exception& e) + { + ARMARX_WARNING << "Caught exception while visualizing robots: \n" << e.what(); + } + catch (...) + { + ARMARX_WARNING << "Caught unknown exception while visualizing robots."; + } + + if (debugObserver.has_value()) + { + debugObserver->sendDebugObserverBatch(); + } } + cycle.waitForCycleDuration(); + } + } - ARMARX_DEBUG << "Found the following joints for robot " << robotName << ": " - << simox::alg::get_keys(jointMap->second); - // TODO(fabian.reister): based on data - const armem::Time timestamp = IceUtil::Time::now(); + void Visu::visualizeOnce(const Time& timestamp) + { + TIMING_START(tVisuTotal); - robots.emplace_back(robot::Robot - { - .description = robotDescription, - .instance = "", // TODO(fabian.reister): set this properly - .config = { - .timestamp = timestamp, - .globalPose = globalPose->second, - .jointMap = jointMap->second - }, - .timestamp = timestamp, - }); - } + // TODO(fabian.reister): use timestamp - return robots; - } + // Get data. + TIMING_START(tVisuGetData); + TIMING_START(tRobotDescriptions); + const description::RobotDescriptionMap robotDescriptions = + descriptionSegment.getRobotDescriptionsLocking(timestamp); + TIMING_END_STREAM(tRobotDescriptions, ARMARX_DEBUG); - void Visu::visualizeRun() - { - CycleUtil cycle(static_cast<int>(1000 / p.frequencyHz)); - while (updateTask && not updateTask->isStopped()) + TIMING_START(tGlobalPoses); + const auto globalPoses = localizationSegment.getRobotGlobalPosesLocking(timestamp); + TIMING_END_STREAM(tGlobalPoses, ARMARX_DEBUG); + + TIMING_START(tRobotFramePoses); + const auto frames = localizationSegment.getRobotFramePosesLocking(timestamp); + TIMING_END_STREAM(tRobotFramePoses, ARMARX_DEBUG); + + TIMING_START(tJointPositions); + const auto jointPositions = + proprioceptionSegment.getRobotJointPositionsLocking( + timestamp, debugObserver ? &*debugObserver : nullptr); + TIMING_END_STREAM(tJointPositions, ARMARX_DEBUG); + + TIMING_END_STREAM(tVisuGetData, ARMARX_DEBUG); + + + // Build layers. + TIMING_START(tVisuBuildLayers); + + // We need all 3 information: + // - robot description + // - global pose + // - joint positions + // => this is nothing but an armem::Robot + ARMARX_DEBUG << "Combining robot ..." + << "\n- " << robotDescriptions.size() << " descriptions" + << "\n- " << globalPoses.size() << " global poses" + << "\n- " << jointPositions.size() << " joint positions"; + + const robot::Robots robots = + combine(robotDescriptions, globalPoses, jointPositions, timestamp); + + ARMARX_DEBUG << "Visualize " << robots.size() << " robots ..."; + viz::Layer layer = arviz.layer("Robots"); + visualizeRobots(layer, robots); + + ARMARX_DEBUG << "Visualize frames ..."; + viz::Layer layerFrames = arviz.layer("Frames"); + visualizeFrames(layerFrames, frames); + + TIMING_END_STREAM(tVisuBuildLayers, ARMARX_DEBUG); + + + // Commit layers. + + ARMARX_DEBUG << "Commit visualization ..."; + TIMING_START(tVisuCommit); + arviz.commit({layer, layerFrames}); + TIMING_END_STREAM(tVisuCommit, ARMARX_DEBUG); + + TIMING_END_STREAM(tVisuTotal, ARMARX_DEBUG); + + if (debugObserver.has_value()) { - { - // std::scoped_lock lock(visuMutex); - ARMARX_DEBUG << "Update task"; - if (p.enabled) - { - TIMING_START(tVisuTotal); - - // TODO(fabian.reister): use timestamp - const Time timestamp = Time::now(); - - try - { - // Get data. - TIMING_START(tVisuGetData); - - TIMING_START(tRobotDescriptions); - const description::Segment::RobotDescriptionMap robotDescriptions = - descriptionSegment.getRobotDescriptionsLocking(timestamp); - TIMING_END_STREAM(tRobotDescriptions, ARMARX_DEBUG); - - TIMING_START(tGlobalRobotPoseMap); - const auto globalRobotPoseMap = - localizationSegment.getRobotGlobalPosesLocking(timestamp); - TIMING_END_STREAM(tGlobalRobotPoseMap, ARMARX_DEBUG); - - TIMING_START(tRobotFramePoses); - const auto frames = localizationSegment.getRobotFramePosesLocking(timestamp); - TIMING_END_STREAM(tRobotFramePoses, ARMARX_DEBUG); - - TIMING_START(tRobotJointPositionMap); - const auto robotJointPositionMap = - proprioceptionSegment.getRobotJointPositionsLocking( - timestamp, debugObserver ? &*debugObserver : nullptr); - TIMING_END_STREAM(tRobotJointPositionMap, ARMARX_DEBUG); - - TIMING_END_STREAM(tVisuGetData, ARMARX_DEBUG); - - - // Build layers. - TIMING_START(tVisuBuildLayers); - - // we need all 3 informations: - // - robot description - // - global pose - // - joint positions - // => this is nothing but a armem::Robot - - const robot::Robots robots = - combine(robotDescriptions, globalRobotPoseMap, robotJointPositionMap); - - ARMARX_DEBUG << "Visualize robots ..."; - viz::Layer layer = arviz.layer("Robots"); - visualizeRobots(layer, robots); - - ARMARX_DEBUG << "Visualize frames ..."; - viz::Layer layerFrames = arviz.layer("Frames"); - visualizeFrames(layerFrames, frames); - - TIMING_END_STREAM(tVisuBuildLayers, ARMARX_DEBUG); - - - // Commit layers. - - ARMARX_DEBUG << "Commit visualization ..."; - TIMING_START(tVisuCommit); - arviz.commit({layer, layerFrames}); - TIMING_END_STREAM(tVisuCommit, ARMARX_DEBUG); - - TIMING_END_STREAM(tVisuTotal, ARMARX_DEBUG); - - if (debugObserver.has_value()) - { - const std::string p = "Visu | "; - debugObserver->setDebugObserverDatafield(p + "t Total (ms)", tVisuTotal.toMilliSecondsDouble()); - debugObserver->setDebugObserverDatafield(p + "t 1 Get Data (ms)", tVisuGetData.toMilliSecondsDouble()); - debugObserver->setDebugObserverDatafield(p + "t 1.1 Descriptions (ms)", tRobotDescriptions.toMilliSecondsDouble()); - debugObserver->setDebugObserverDatafield(p + "t 1.2 Global Pose (ms)", tGlobalRobotPoseMap.toMilliSecondsDouble()); - debugObserver->setDebugObserverDatafield(p + "t 1.3 Frames (ms)", tRobotFramePoses.toMilliSecondsDouble()); - debugObserver->setDebugObserverDatafield(p + "t 1.4 Joint Positions (ms)", tRobotJointPositionMap.toMilliSecondsDouble()); - debugObserver->setDebugObserverDatafield(p + "t 2 Build Layers (ms)", tVisuBuildLayers.toMilliSecondsDouble()); - debugObserver->setDebugObserverDatafield(p + "t 3 Commit (ms)", tVisuCommit.toMilliSecondsDouble()); - } - } - catch (const std::exception& ex) - { - ARMARX_WARNING << "Caught exception while visualizing robots: \n" << ex.what(); - continue; - } - catch (...) - { - ARMARX_WARNING << "Caught unknown exception while visualizing robots."; - continue; - } - - if (debugObserver.has_value()) - { - debugObserver->sendDebugObserverBatch(); - } - } - } - cycle.waitForCycleDuration(); + const std::string p = "Visu | "; + debugObserver->setDebugObserverDatafield(p + "t Total (ms)", tVisuTotal.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(p + "t 1 Get Data (ms)", tVisuGetData.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(p + "t 1.1 Descriptions (ms)", tRobotDescriptions.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(p + "t 1.2 Global Poses (ms)", tGlobalPoses.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(p + "t 1.3 Frames (ms)", tRobotFramePoses.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(p + "t 1.4 Joint Positions (ms)", tJointPositions.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(p + "t 2 Build Layers (ms)", tVisuBuildLayers.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(p + "t 3 Commit (ms)", tVisuCommit.toMilliSecondsDouble()); } } diff --git a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.h b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.h index e407abc0d..ce69772c1 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.h +++ b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.h @@ -55,14 +55,19 @@ namespace armarx::armem::server::robot_state void connect(const viz::Client& arviz, DebugObserverInterfacePrx debugObserver = nullptr); - protected: + private: + + void visualizeRun(); + void visualizeOnce(const Time& timestamp); - static void visualizeRobots( + + static + void visualizeRobots( viz::Layer& layer, - const robot::Robots& robots - ); + const robot::Robots& robots); - static void visualizeFrames( + static + void visualizeFrames( viz::Layer& layerFrames, const std::unordered_map<std::string, std::vector<Eigen::Affine3f>>& frames); @@ -84,7 +89,6 @@ namespace armarx::armem::server::robot_state SimpleRunningTask<>::pointer_type updateTask; - void visualizeRun(); }; diff --git a/source/RobotAPI/libraries/armem_robot_state/server/common/combine.cpp b/source/RobotAPI/libraries/armem_robot_state/server/common/combine.cpp new file mode 100644 index 000000000..abe3f0bbb --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/common/combine.cpp @@ -0,0 +1,64 @@ +#include "combine.h" + +#include <RobotAPI/libraries/armem_robot/types.h> +#include <RobotAPI/libraries/armem/core/Time.h> + +#include <ArmarXCore/core/logging/Logging.h> + +#include <sstream> + + +namespace armarx::armem::server +{ + + robot::Robots + robot_state::combine( + const description::RobotDescriptionMap& robotDescriptions, + const localization::RobotPoseMap& globalPoses, + const proprioception::RobotJointPositionMap& jointPositions, + const armem::Time& timestamp) + { + std::stringstream logs; + + robot::Robots robots; + for (const auto& [robotName, robotDescription] : robotDescriptions) + { + // Handle missing values gracefully instead of skipping the robot altogether. + + robot::Robot& robot = robots.emplace_back(); + + robot.description = robotDescription; + robot.instance = ""; // TODO(fabian.reister): set this properly + robot.config.timestamp = timestamp; + robot.config.globalPose = Eigen::Affine3f::Identity(); + robot.config.jointMap = {}; + robot.timestamp = timestamp; + + if (auto it = globalPoses.find(robotName); it != globalPoses.end()) + { + robot.config.globalPose = it->second; + } + else + { + logs << "\nNo global pose for robot '" << robotName << "'."; + } + if (auto it = jointPositions.find(robotName); it != jointPositions.end()) + { + robot.config.jointMap = it->second; + } + else + { + logs << "\nNo joint positions for robot '" << robotName << "'."; + } + } + + if (not logs.str().empty()) + { + // These are handled, so they are no warnings. + ARMARX_VERBOSE << deactivateSpam(60) << logs.str(); + } + + return robots; + } + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/common/combine.h b/source/RobotAPI/libraries/armem_robot_state/server/common/combine.h new file mode 100644 index 000000000..811599b69 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/common/combine.h @@ -0,0 +1,38 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu ) + * @date 2021 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <RobotAPI/libraries/armem/core/forward_declarations.h> +#include <RobotAPI/libraries/armem_robot_state/server/forward_declarations.h> + + +namespace armarx::armem::server::robot_state +{ + + robot::Robots + combine( + const description::RobotDescriptionMap& robotDescriptions, + const localization::RobotPoseMap& globalPoses, + const proprioception::RobotJointPositionMap& jointPositions, + const armem::Time& timestamp); + +} // namespace armarx::armem::server::robot_state diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp index fd8ace277..c2ed636a9 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp @@ -89,32 +89,40 @@ namespace armarx::armem::server::robot_state::proprioception } if (not batch.empty()) { - Update update = buildUpdate(batch); - auto start = std::chrono::high_resolution_clock::now(); - auto endProprioception = start, endLocalization = start; + auto endBuildUpdate = start, endProprioception = start, endLocalization = start; - armem::CommitResult result; - { - // Commits lock the core segments. + Update update = buildUpdate(batch); + endBuildUpdate = std::chrono::high_resolution_clock::now(); + + // Commits lock the core segments. - result = memory.commitLocking(update.proprioception); - endProprioception = std::chrono::high_resolution_clock::now(); + // Proprioception + armem::CommitResult result = memory.commitLocking(update.proprioception); + endProprioception = std::chrono::high_resolution_clock::now(); - localizationSegment.commitTransformLocking(update.localization); - endLocalization = std::chrono::high_resolution_clock::now(); + // Localization + for (const armem::robot_state::Transform& transform : update.localization) + { + localizationSegment.doLocked([&localizationSegment, &transform]() + { + localizationSegment.commitTransform(transform); + }); } + endLocalization = std::chrono::high_resolution_clock::now(); + if (not result.allSuccess()) { - ARMARX_WARNING << "Could not add data to memory. Error message: " << result.allErrorMessages(); + ARMARX_WARNING << "Could not commit data to memory. Error message: " << result.allErrorMessages(); } if (debugObserver) { auto end = std::chrono::high_resolution_clock::now(); - debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit [ms]", toDurationMs(start, end)); - debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit Proprioception [ms]", toDurationMs(start, endProprioception)); - debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit Localization [ms]", toDurationMs(endProprioception, endLocalization)); + debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit (ms)", toDurationMs(start, end)); + debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit 1. Build Update (ms)", toDurationMs(start, endBuildUpdate)); + debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit 2. Proprioception (ms)", toDurationMs(endBuildUpdate, endProprioception)); + debugObserver->setDebugObserverDatafield("RobotStateWriter | t Commit 3. Localization (ms)", toDurationMs(endProprioception, endLocalization)); } } @@ -130,9 +138,7 @@ namespace armarx::armem::server::robot_state::proprioception RobotStateWriter::Update RobotStateWriter::buildUpdate(std::queue<RobotUnitData>& dataQueue) { ARMARX_CHECK_GREATER(dataQueue.size(), 0); - ARMARX_DEBUG << "RobotStateWriter: Commit batch of " << dataQueue.size() << " timesteps to memory..."; - auto start = std::chrono::high_resolution_clock::now(); // Send batch to memory Update update; @@ -141,52 +147,61 @@ namespace armarx::armem::server::robot_state::proprioception { const RobotUnitData& data = dataQueue.front(); - armem::EntityUpdate& up = update.proprioception.add(); - up.entityID = properties.robotUnitProviderID.withEntityName(properties.robotUnitProviderID.providerSegmentName); - up.timeCreated = data.timestamp; - up.instancesData = { data.proprioception }; + { + armem::EntityUpdate& up = update.proprioception.add(); + up.entityID = properties.robotUnitProviderID.withEntityName(properties.robotUnitProviderID.providerSegmentName); + up.timeCreated = data.timestamp; + up.instancesData = { data.proprioception }; + } - // odometry pose -> localization segment - if (data.proprioception->hasElement("platform")) + // Extract odometry data. + const std::string platformKey = "platform"; + if (data.proprioception->hasElement(platformKey)) { ARMARX_DEBUG << "Found odometry data."; - prop::arondto::Platform platform; - platform.fromAron(aron::datanavigator::DictNavigator::DynamicCastAndCheck(data.proprioception->getElement("platform"))); - const Eigen::Vector3f& relPose = platform.relativePosition; - - Eigen::Affine3f odometryPose = Eigen::Affine3f::Identity(); - odometryPose.translation() << relPose.x(), relPose.y(), 0; // TODO set height - odometryPose.linear() = simox::math::rpy_to_mat3f(0.F, 0.F, relPose.z()); - - armem::robot_state::Transform& transform = update.localization; - transform.header.parentFrame = armarx::OdometryFrame; - transform.header.frame = "root"; // TODO: robot root node - transform.header.agent = properties.robotUnitProviderID.providerSegmentName; - transform.header.timestamp = data.timestamp; - transform.transform = odometryPose; + auto platformData = aron::datanavigator::DictNavigator::DynamicCastAndCheck(data.proprioception->getElement(platformKey)); + update.localization.emplace_back(getTransform(platformData, data.timestamp)); } - // ToDo: Detect that now odometry data was send - /* - else if (!noOdometryDataLogged) + else { - ARMARX_INFO << "No odometry data! (No group with name '" << properties.platformGroupName << "'.). \n" - << "If you are using a mobile platform this should not have happened."; + ARMARX_INFO << "No odometry data! " + << "(No element '" << platformKey << "' in proprioception data.)" + << "\nIf you are using a mobile platform this should not have happened." + << "\nThis error is only logged once." + << "\nThese keys exist: " << data.proprioception->getAllKeys() + ; noOdometryDataLogged = true; } - */ dataQueue.pop(); } - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); - ARMARX_DEBUG << "RobotUnitData: The total runtime of sending a batch to the memory is: " << duration; - if (debugObserver) - { - debugObserver->setDebugObserverDatafield("RobotStateWriter | t Build Update [ms]", duration.count() / 1000.f); - } - return update; } + + armem::robot_state::Transform + RobotStateWriter::getTransform( + const aron::datanavigator::DictNavigatorPtr& platformData, + const Time& timestamp) const + { + prop::arondto::Platform platform; + platform.fromAron(platformData); + + const Eigen::Vector3f& relPose = platform.relativePosition; + + Eigen::Affine3f odometryPose = Eigen::Affine3f::Identity(); + odometryPose.translation() << relPose.x(), relPose.y(), 0; // TODO set height + odometryPose.linear() = simox::math::rpy_to_mat3f(0.f, 0.f, relPose.z()); + + armem::robot_state::Transform transform; + transform.header.parentFrame = armarx::OdometryFrame; + transform.header.frame = "root"; // TODO: robot root node + transform.header.agent = properties.robotUnitProviderID.providerSegmentName; + transform.header.timestamp = timestamp; + transform.transform = odometryPose; + + return transform; + } + } diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h index 3f8d33ef8..10c5a8b9e 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h @@ -67,18 +67,25 @@ namespace armarx::armem::server::robot_state::proprioception struct Update { armem::Commit proprioception; - armem::robot_state::Transform localization; + std::vector<armem::robot_state::Transform> localization; }; Update buildUpdate(std::queue<RobotUnitData>& dataQueue); + private: + + armem::robot_state::Transform + getTransform( + const aron::datanavigator::DictNavigatorPtr& platformData, + const Time& timestamp) const; + + public: struct Properties { unsigned int memoryBatchSize = 50; armem::MemoryID robotUnitProviderID; - std::string platformGroupName = "sens.Platform"; }; Properties properties; diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp index 3f6f24f45..02a98ef64 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp @@ -82,14 +82,23 @@ namespace armarx::armem::server::robot_state::proprioception segment->forEachEntity([&](const wm::Entity & entity) { adn::DictNavigatorPtr data; - TIMING_START(_tFindData) - if (const wm::EntitySnapshot* snapshot = entity.findFirstSnapshotAfterOrAt(timestamp)) { - data = snapshot->findInstanceData(); - } - TIMING_END_COMMENT_STREAM(_tFindData, "tFindData " + std::to_string(i), ARMARX_DEBUG) - tFindData += _tFindData; + TIMING_START(_tFindData) + + const wm::EntitySnapshot* snapshot = entity.findLatestSnapshotBeforeOrAt(timestamp); + if (not snapshot) + { + // Got no snapshot <= timestamp. Take latest instead (if present). + snapshot = entity.findLatestSnapshot(); + } + if (snapshot) + { + data = snapshot->findInstanceData(); + } + TIMING_END_COMMENT_STREAM(_tFindData, "tFindData " + std::to_string(i), ARMARX_DEBUG) + tFindData += _tFindData; + } if (data) { TIMING_START(_tReadJointPositions) @@ -99,7 +108,6 @@ namespace armarx::armem::server::robot_state::proprioception TIMING_END_COMMENT_STREAM(_tReadJointPositions, "tReadJointPositions " + std::to_string(i), ARMARX_DEBUG) tReadJointPositions += _tReadJointPositions; } - ++i; }); TIMING_END_STREAM(tProcessEntities, ARMARX_DEBUG) -- GitLab