From 4b1a8c780a3c8c8b4077caaf952f793dd118d565 Mon Sep 17 00:00:00 2001 From: Your Name <you@example.com> Date: Sat, 25 Feb 2023 17:52:43 +0100 Subject: [PATCH] ARMAR-DE RobotStreaming converter: adding ToF data --- source/RobotAPI/libraries/armem_robot/types.h | 3 + .../armem_robot_state/aron/Proprioception.xml | 13 + .../armem_robot_state/aron_conversions.cpp | 10 + .../armem_robot_state/aron_conversions.h | 5 + .../armem_robot_state/server/CMakeLists.txt | 2 + .../converters/ArmarDEConverter.cpp | 296 ++++++++++++++++++ .../converters/ArmarDEConverter.h | 78 +++++ .../converters/ConverterRegistry.cpp | 3 +- 8 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.cpp create mode 100644 source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.h diff --git a/source/RobotAPI/libraries/armem_robot/types.h b/source/RobotAPI/libraries/armem_robot/types.h index 345564d4b..6f2980997 100644 --- a/source/RobotAPI/libraries/armem_robot/types.h +++ b/source/RobotAPI/libraries/armem_robot/types.h @@ -40,6 +40,9 @@ namespace armarx::armem::robot Eigen::Vector3f torque; }; + using ToFArray = Eigen::MatrixXf; + + struct RobotState { using JointMap = std::map<std::string, float>; diff --git a/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml index c7ac7670d..e84ccf382 100644 --- a/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml +++ b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml @@ -235,6 +235,13 @@ </Object> + <Object name="armarx::armem::prop::arondto::ToF"> + + <ObjectChild key="array"> + <Matrix rows="-1" cols="-1" type="float32" /> + </ObjectChild> + + </Object> <Object name="armarx::armem::arondto::Proprioception"> @@ -257,6 +264,12 @@ </Dict> </ObjectChild> + <!-- TODO move to separate segment --> + <ObjectChild key="tof"> + <Dict> + <armarx::armem::prop::arondto::ToF/> + </Dict> + </ObjectChild> <ObjectChild key="extraFloats"> <Dict> diff --git a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp index 1c18fe5b7..b079cec2e 100644 --- a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp @@ -97,4 +97,14 @@ namespace armarx::armem aron::toAron(dto.torque, bo.torque); } + + void fromAron(const armarx::armem::prop::arondto::ToF& dto, robot::ToFArray& bo){ + bo = dto.array; + } + + void toAron(armarx::armem::prop::arondto::ToF& dto, const robot::ToFArray& bo){ + dto.array = bo; + } + + } // namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h index 75c339c7f..1912e6c69 100644 --- a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h +++ b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.h @@ -38,6 +38,7 @@ namespace armarx::armem { struct Platform; struct ForceTorque; + struct ToF; } namespace arondto @@ -66,4 +67,8 @@ namespace armarx::armem void toAron(armarx::armem::prop::arondto::ForceTorque& dto, const robot::ForceTorque& bo); + void fromAron(const armarx::armem::prop::arondto::ToF& dto, robot::ToFArray& bo); + void toAron(armarx::armem::prop::arondto::ToF& dto, const robot::ToFArray& bo); + + } // namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt b/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt index 169d59f1a..887cc2eec 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_robot_state/server/CMakeLists.txt @@ -44,6 +44,7 @@ armarx_add_library( proprioception/RobotUnitReader.h proprioception/converters/Armar6Converter.h + proprioception/converters/ArmarDEConverter.h proprioception/converters/ConverterTools.h proprioception/converters/ConverterRegistry.h proprioception/converters/ConverterInterface.h @@ -63,6 +64,7 @@ armarx_add_library( proprioception/RobotUnitReader.cpp proprioception/converters/Armar6Converter.cpp + proprioception/converters/ArmarDEConverter.cpp proprioception/converters/ConverterTools.cpp proprioception/converters/ConverterRegistry.cpp proprioception/converters/ConverterInterface.cpp diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.cpp new file mode 100644 index 000000000..a4ac7a8c3 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.cpp @@ -0,0 +1,296 @@ +#include "ArmarDEConverter.h" +#include <cmath> +#include <string> + +#include <SimoxUtility/algorithm/get_map_keys_values.h> +#include <SimoxUtility/algorithm/advanced.h> +#include "ArmarXCore/core/exceptions/local/ExpressionException.h" + +#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h> + +#include "ConverterTools.h" + + +namespace armarx::armem::server::robot_state::proprioception +{ + + ArmarDEConverter::ArmarDEConverter() : + tools(std::make_unique<ConverterTools>()) + { + } + + + ArmarDEConverter::~ArmarDEConverter() + { + } + + + aron::data::DictPtr + ArmarDEConverter::convert( + const RobotUnitDataStreaming::TimeStep& data, + const RobotUnitDataStreaming::DataStreamingDescription& description) + { + arondto::Proprioception dto; + dto.iterationID = data.iterationId; + + for (const auto& [dataEntryName, dataEntry] : description.entries) + { + process(dto, dataEntryName, {data, dataEntry}); + } + + // resize to square + for(auto& [_, tof] : dto.tof) + { + const int sr = std::sqrt(tof.array.size()); + const bool isSquare = (sr * sr == tof.array.size()); + + if(tof.array.size() > 0 and isSquare) + { + tof.array.resize(sr, sr); + } + } + + + return dto.toAron(); + } + + + void ArmarDEConverter::process( + arondto::Proprioception& dto, + const std::string& entryName, + const ConverterValue& value) + { + const std::vector<std::string> split = simox::alg::split(entryName, ".", false, false); + ARMARX_CHECK_GREATER_EQUAL(split.size(), 3); + const std::set<size_t> acceptedSizes{3, 4, 5}; + ARMARX_CHECK_GREATER(acceptedSizes.count(split.size()), 0) + << "Data entry name could not be parsed (exected 3 or 4 or 5 components between '.'): " + << "\n- split: '" << split << "'"; + + const std::string& category = split.at(0); + const std::string& name = split.at(1); + const std::string& field = split.at(2); + ARMARX_CHECK_EQUAL(category, "sens") << category << " | " << entryName; + + if (name == "Platform") + { + // Platform + processPlatformEntry(dto.platform, field, value); + } + else if (simox::alg::starts_with(name, "FT")) + { + // Force Torque + processForceTorqueEntry(dto.forceTorque, split, value); + } + else if (simox::alg::contains(field, "tofDepth")) + { + // ARMARX_DEBUG << "Processing ToF sensor data"; + processToFEntry(dto.tof, split, value); + } + else + { + // Joint + bool processed = processJointEntry(dto.joints, split, value); + if (not processed) + { + // Fallback: Put in extra. + const std::vector<std::string> comps{simox::alg::advanced(split.begin(), 1), split.end()}; + const std::string key = simox::alg::join(comps, "."); + + switch (value.entry.type) + { + case RobotUnitDataStreaming::NodeTypeFloat: + dto.extraFloats[key] = getValueAs<float>(value); + break; + case RobotUnitDataStreaming::NodeTypeLong: + dto.extraLongs[key] = getValueAs<long>(value); + break; + default: + ARMARX_DEBUG << "Cannot handle extra field '" << key << "' of type " + << RobotUnitDataStreaming::DataEntryNames.to_name(value.entry.type); + break; + } + } + } + } + + + + void ArmarDEConverter::processPlatformEntry( + prop::arondto::Platform& dto, + const std::string& fieldName, + const ConverterValue& value) + { + if (findByPrefix(fieldName, tools->platformIgnored)) + { + return; + } + else if (auto getter = findByPrefix(fieldName, tools->platformPoseGetters)) + { + if (Eigen::Vector3f* dst = getter(dto)) + { + if (auto setter = findBySuffix(fieldName, tools->vector3fSetters)) + { + setter(*dst, getValueAs<float>(value)); + } + } + } + else + { + // No setter for this field. Put in extra. + dto.extra[fieldName] = getValueAs<float>(value); + } + } + + + void ArmarDEConverter::processForceTorqueEntry( + std::map<std::string, prop::arondto::ForceTorque>& fts, + const std::vector<std::string>& split, + const ConverterValue& value) + { + const std::string& name = split.at(1); + std::vector<std::string> splitName = simox::alg::split(name, " ", false, false); + ARMARX_CHECK_EQUAL(splitName.size(), 2); + ARMARX_CHECK_EQUAL(splitName.at(0), "FT"); + + auto it = tools->sidePrefixMap.find(splitName.at(1)); + ARMARX_CHECK(it != tools->sidePrefixMap.end()) << splitName.at(1); + + const std::string& side = it->second; + processForceTorqueEntry(fts[side], split, value); + } + + void ArmarDEConverter::processToFEntry( + std::map<std::string, prop::arondto::ToF>& tofs, + const std::vector<std::string>& split, + const ConverterValue& value) + { + // split e.g. "sens.LeftHand.tofDepth.element_15" (split at dot) + + ARMARX_CHECK_EQUAL(split.size(), 4); + ARMARX_CHECK_EQUAL(split.at(2), "tofDepth"); + + const std::string& name = split.at(1); + + // element 0 sens + // element 1 is either LeftHand or RightHand + + const std::map<std::string, std::string> sidePrefixMap + { + {"LeftHand", "Left"}, + {"RightHand", "Right"} + }; + + auto it = sidePrefixMap.find(name); + ARMARX_CHECK(it != sidePrefixMap.end()) << name; + + const std::string& side = it->second; + processToFEntry(tofs[side], split, value); + } + + void ArmarDEConverter::processToFEntry(prop::arondto::ToF& tof, + const std::vector<std::string>& split, + const ConverterValue& value) + { + // split, e.g., element_12 + const std::vector<std::string> elements = simox::alg::split(split.back(), "_"); + ARMARX_CHECK_EQUAL(elements.size(), 2); + + const int idx = std::stoi(elements.at(1)); + + if(tof.array.size() < (idx +1)) + { + tof.array.resize(idx+1, 1); + } + + tof.array(idx) = getValueAs<float>(value); + } + + + void ArmarDEConverter::processForceTorqueEntry( + prop::arondto::ForceTorque& dto, + const std::vector<std::string>& split, + const ConverterValue& value) + { + const std::string& fieldName = split.at(2); + if (auto getter = findByPrefix(fieldName, tools->ftGetters)) + { + if (Eigen::Vector3f* dst = getter(dto)) + { + if (auto setter = findBySuffix(fieldName, tools->vector3fSetters)) + { + setter(*dst, getValueAs<float>(value)); + } + } + } + else + { + // No setter for this field. Put in extra. + std::string key = split.size() == 4 + ? (fieldName + "." + split.at(3)) + : fieldName; + + switch (value.entry.type) + { + case RobotUnitDataStreaming::NodeTypeFloat: + dto.extra[key] = getValueAs<float>(value); + break; + case RobotUnitDataStreaming::NodeTypeInt: + dto.extra[key] = getValueAs<int>(value); + break; + case RobotUnitDataStreaming::NodeTypeLong: + dto.extra[key] = getValueAs<long>(value); + break; + default: + ARMARX_DEBUG << "Cannot handle extra field '" << key << "' of type " + << RobotUnitDataStreaming::DataEntryNames.to_name(value.entry.type); + break; + } + } + } + + + bool ArmarDEConverter::processJointEntry( + prop::arondto::Joints& dto, + const std::vector<std::string>& split, + const ConverterValue& value) + { + const std::string& jointName = split.at(1); + const std::string& fieldName = split.at(2); + if (false) + { + // Only in simulation. + if (auto getter = findByPrefix(fieldName, tools->jointGetters)) + { + if (std::map<std::string, float>* map = getter(dto)) + { + (*map)[jointName] = getValueAs<float>(value); + } + } + } + + const std::string tempSuffix = "Temperature"; + if (simox::alg::ends_with(split.at(2), tempSuffix)) + { + // Handle "dieTemperature" etc + const std::string name = split.at(2).substr(0, split.at(2).size() - tempSuffix.size()); + dto.temperature[split.at(1)][name] = getValueAs<float>(value); + return true; + } + else if (auto it = tools->jointSetters.find(fieldName); it != tools->jointSetters.end()) + { + const ConverterTools::JointSetter& setter = it->second; + setter(dto, split, value); + return true; + } + else + { + // ARMARX_DEBUG << "Ignoring unhandled field: '" << simox::alg::join(split, ".") << "'"; + return false; + } + } + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.h new file mode 100644 index 000000000..6f5c28715 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ArmarDEConverter.h @@ -0,0 +1,78 @@ +#pragma once + +#include <map> +#include <string> + +#include <Eigen/Core> + +#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h> + +#include "ConverterInterface.h" + + + +namespace armarx::armem::server::robot_state::proprioception +{ + struct ConverterValue; + class ConverterTools; + + + class ArmarDEConverter : public ConverterInterface + { + public: + + ArmarDEConverter(); + virtual ~ArmarDEConverter() override; + + + aron::data::DictPtr + convert( + const RobotUnitDataStreaming::TimeStep& data, + const RobotUnitDataStreaming::DataStreamingDescription& description) override; + + + protected: + + void process(arondto::Proprioception& dto, const std::string& entryName, const ConverterValue& value); + + + + private: + + void processPlatformEntry( + prop::arondto::Platform& dto, + const std::string& fieldName, + const ConverterValue& value); + + void processForceTorqueEntry( + std::map<std::string, prop::arondto::ForceTorque>& fts, + const std::vector<std::string>& split, + const ConverterValue& value); + + void processForceTorqueEntry( + prop::arondto::ForceTorque& ft, + const std::vector<std::string>& split, + const ConverterValue& value); + + void processToFEntry( + std::map<std::string, prop::arondto::ToF>& fts, + const std::vector<std::string>& split, + const ConverterValue& value); + + void processToFEntry( + prop::arondto::ToF& tof, + const std::vector<std::string>& split, + const ConverterValue& value); + + bool processJointEntry( + prop::arondto::Joints& dto, + const std::vector<std::string>& split, + const ConverterValue& value); + + + private: + + std::unique_ptr<ConverterTools> tools; + + }; +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp index 0c6baa3b7..48ea15375 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp @@ -1,6 +1,7 @@ #include "ConverterRegistry.h" #include "Armar6Converter.h" +#include "ArmarDEConverter.h" #include <SimoxUtility/algorithm/get_map_keys_values.h> @@ -11,7 +12,7 @@ namespace armarx::armem::server::robot_state::proprioception ConverterRegistry::ConverterRegistry() { add<Armar6Converter>("Armar6"); - add<Armar6Converter>("ArmarDE"); + add<ArmarDEConverter>("ArmarDE"); add<Armar6Converter>("Armar7"); } -- GitLab