diff --git a/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp b/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp index 426511a9a8a59dd5cba9545f08f8479c0104d96c..21e579c803afd33d2ad5864de6c4b283ae69733c 100644 --- a/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp +++ b/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp @@ -123,4 +123,16 @@ namespace armarx::armem ARMARX_ERROR << "Not implemented yet."; } + void robot::fromAron(const armarx::armem::prop::arondto::ForceTorque& dto, robot::ForceTorque& bo) + { + bo.force = dto.force; + bo.torque = dto.torque; + } + + void robot::toAron(armarx::armem::prop::arondto::ForceTorque& dto, const robot::ForceTorque& bo) + { + dto.force = bo.force; + dto.torque = bo.torque; + } + } // namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem_robot/aron_conversions.h b/source/RobotAPI/libraries/armem_robot/aron_conversions.h index e6b462fa866d0c011cb0d899f08ad4e804e3f210..62744724f1d4c42ebe882cf4072e87d43428dd02 100644 --- a/source/RobotAPI/libraries/armem_robot/aron_conversions.h +++ b/source/RobotAPI/libraries/armem_robot/aron_conversions.h @@ -30,6 +30,9 @@ namespace armarx::armem::robot void fromAron(const armarx::armem::prop::arondto::Platform& dto, PlatformState& bo); void toAron(armarx::armem::prop::arondto::Platform& dto, const PlatformState& bo); + void fromAron(const armarx::armem::prop::arondto::ForceTorque& dto, ForceTorque& bo); + void toAron(armarx::armem::prop::arondto::ForceTorque& dto, const ForceTorque& bo); + void fromAron(const arondto::ObjectClass& dto, RobotDescription& bo); void toAron(arondto::ObjectClass& dto, const RobotDescription& bo); diff --git a/source/RobotAPI/libraries/armem_robot/types.h b/source/RobotAPI/libraries/armem_robot/types.h index ad7454d6fb4f74b49b6909a3a6d362c302203fc9..0a8473073f5b30dce3cb9f2d96682b4184a6a9b3 100644 --- a/source/RobotAPI/libraries/armem_robot/types.h +++ b/source/RobotAPI/libraries/armem_robot/types.h @@ -35,6 +35,12 @@ namespace armarx::armem::robot Twist twist; }; + struct ForceTorque + { + Eigen::Vector3f force; + Eigen::Vector3f torque; + }; + struct RobotState { using JointMap = std::map<std::string, float>; @@ -46,6 +52,7 @@ namespace armarx::armem::robot JointMap jointMap; }; + struct Robot { RobotDescription description; diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp index 4da91df52e77ecd83fe4c061d0a969bce8bae32f..6645b8d6c4c86d4d6db30c6d0b5244e71c9cfffd 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp @@ -4,18 +4,18 @@ #include <optional> #include "ArmarXCore/core/exceptions/local/ExpressionException.h" -#include "RobotAPI/libraries/armem_robot/types.h" +#include <ArmarXCore/core/PackagePath.h> #include <ArmarXCore/core/exceptions/LocalException.h> #include <ArmarXCore/core/logging/Logging.h> -#include <ArmarXCore/core/PackagePath.h> +#include "RobotAPI/libraries/armem_robot/types.h" #include <RobotAPI/libraries/armem/client/query/Builder.h> -#include <RobotAPI/libraries/armem/core/error.h> #include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem/core/error.h> #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h> #include <RobotAPI/libraries/armem_robot/aron_conversions.h> #include <RobotAPI/libraries/armem_robot/robot_conversions.h> -#include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h> #include <RobotAPI/libraries/armem_robot_state/aron/JointState.aron.generated.h> #include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h> @@ -24,14 +24,15 @@ namespace fs = ::std::filesystem; namespace armarx::armem::robot_state { - + RobotReader::RobotReader(armem::client::MemoryNameSystem& memoryNameSystem) : memoryNameSystem(memoryNameSystem), transformReader(memoryNameSystem) { } - void RobotReader::registerPropertyDefinitions(::armarx::PropertyDefinitionsPtr& def) + void + RobotReader::registerPropertyDefinitions(::armarx::PropertyDefinitionsPtr& def) { transformReader.registerPropertyDefinitions(def); @@ -42,7 +43,8 @@ namespace armarx::armem::robot_state propertyPrefix + "proprioceptionSegment"); } - void RobotReader::connect() + void + RobotReader::connect() { transformReader.connect(); @@ -51,7 +53,8 @@ namespace armarx::armem::robot_state try { memoryReader = memoryNameSystem.useReader(properties.memoryName); - ARMARX_IMPORTANT << "RobotReader: Connected to memory '" << properties.memoryName << "'"; + ARMARX_IMPORTANT << "RobotReader: Connected to memory '" << properties.memoryName + << "'"; } catch (const armem::error::CouldNotResolveMemoryServer& e) { @@ -60,8 +63,8 @@ namespace armarx::armem::robot_state } } - std::optional<robot::Robot> RobotReader::get(const std::string& name, - const armem::Time& timestamp) + std::optional<robot::Robot> + RobotReader::get(const std::string& name, const armem::Time& timestamp) { const auto description = queryDescription(name, timestamp); @@ -74,20 +77,21 @@ namespace armarx::armem::robot_state return get(*description, timestamp); } - robot::Robot RobotReader::get(const robot::RobotDescription& description, - const armem::Time& timestamp) + robot::Robot + RobotReader::get(const robot::RobotDescription& description, const armem::Time& timestamp) { robot::Robot robot{.description = description, - .instance = "", // TODO(fabian.reister): - .config = {}, // will be populated by synchronize - .timestamp = timestamp}; + .instance = "", // TODO(fabian.reister): + .config = {}, // will be populated by synchronize + .timestamp = timestamp}; synchronize(robot, timestamp); return robot; } - bool RobotReader::synchronize(robot::Robot& obj, const armem::Time& timestamp) + bool + RobotReader::synchronize(robot::Robot& obj, const armem::Time& timestamp) { auto state = queryState(obj.description, timestamp); @@ -119,7 +123,8 @@ namespace armarx::armem::robot_state if (not memoryReader) { - ARMARX_WARNING << "Memory reader is null. Did you forget to call RobotReader::connect() in onConnectComponent()?"; + ARMARX_WARNING << "Memory reader is null. Did you forget to call " + "RobotReader::connect() in onConnectComponent()?"; return std::nullopt; } @@ -162,8 +167,7 @@ namespace armarx::armem::robot_state return std::nullopt; } - return robot::RobotState - { + return robot::RobotState{ .timestamp = timestamp, .globalPose = *globalPose, .jointMap = *jointMap}; } @@ -200,10 +204,9 @@ namespace armarx::armem::robot_state } - std::optional<robot::PlatformState> RobotReader::queryPlatformState(const robot::RobotDescription& description, - const armem::Time& timestamp) const + const armem::Time& timestamp) const { // TODO(fabian.reister): how to deal with multiple providers? @@ -266,11 +269,12 @@ namespace armarx::armem::robot_state // clang-format on const armem::wm::EntityInstance* instance = nullptr; - providerSegment.forEachInstance([&instance](const wm::EntityInstance & i) - { - instance = &i; - return false; // break - }); + providerSegment.forEachInstance( + [&instance](const wm::EntityInstance& i) + { + instance = &i; + return false; // break + }); if (!instance) { ARMARX_WARNING << "No entity snapshots found"; @@ -283,10 +287,10 @@ namespace armarx::armem::robot_state // FIXME remove this, use armem/util/util.h template <typename AronClass> - std::optional<AronClass> tryCast(const wm::EntityInstance& item) + std::optional<AronClass> + tryCast(const wm::EntityInstance& item) { - static_assert(std::is_base_of<armarx::aron::cppserializer::AronCppClass, - AronClass>::value); + static_assert(std::is_base_of<armarx::aron::cppserializer::AronCppClass, AronClass>::value); try { @@ -312,28 +316,29 @@ namespace armarx::armem::robot_state .getCoreSegment(properties.proprioceptionCoreSegment); // clang-format on - coreSegment.forEachEntity([&jointMap](const wm::Entity & entity) - { - const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); + coreSegment.forEachEntity( + [&jointMap](const wm::Entity& entity) + { + const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - const auto proprioception = tryCast<::armarx::armem::arondto::Proprioception>(entityInstance); - ARMARX_CHECK(proprioception.has_value()); + const auto proprioception = + tryCast<::armarx::armem::arondto::Proprioception>(entityInstance); + ARMARX_CHECK(proprioception.has_value()); - const armarx::armem::prop::arondto::Joints& joints = proprioception->joints; - + const armarx::armem::prop::arondto::Joints& joints = proprioception->joints; - // const auto jointState = tryCast<::armarx::armem::arondto::JointState>(entityInstance); - // if (not jointState) - // { - // ARMARX_WARNING << "Could not convert entity instance to 'JointState'"; - // return; - // } + // const auto jointState = tryCast<::armarx::armem::arondto::JointState>(entityInstance); + // if (not jointState) + // { + // ARMARX_WARNING << "Could not convert entity instance to 'JointState'"; + // return; + // } - jointMap = joints.position; + jointMap = joints.position; - // jointMap.emplace(jointState->name, jointState->position); - }); + // jointMap.emplace(jointState->name, jointState->position); + }); if (jointMap.empty()) { @@ -343,9 +348,43 @@ namespace armarx::armem::robot_state return jointMap; } - std::optional<robot::PlatformState> - RobotReader::getRobotPlatformState (const armarx::armem::wm::Memory& memory, - const std::string& name) const + + // force torque for left and right + std::optional<std::map<RobotReader::Hand, robot::ForceTorque>> + RobotReader::queryForceTorque(const robot::RobotDescription& description, + const armem::Time& timestamp) const + { + + // Query all entities from provider. + armem::client::query::Builder qb; + + ARMARX_DEBUG << "Querying force torques description for robot: " << description; + + // clang-format off + qb + .coreSegments().withName(properties.proprioceptionCoreSegment) + .providerSegments().withName(description.name) // agent + .entities().all() // TODO + .snapshots().beforeOrAtTime(timestamp); + // clang-format on + + const armem::client::QueryResult qResult = memoryReader.query(qb.buildQueryInput()); + + ARMARX_DEBUG << "Lookup result in reader: " << qResult; + + if (not qResult.success) /* c++20 [[unlikely]] */ + { + ARMARX_WARNING << qResult.errorMessage; + return std::nullopt; + } + + return getForceTorque(qResult.memory, description.name); + } + + + std::optional<robot::PlatformState> + RobotReader::getRobotPlatformState(const armarx::armem::wm::Memory& memory, + const std::string& name) const { std::optional<robot::PlatformState> platformState; @@ -354,21 +393,70 @@ namespace armarx::armem::robot_state .getCoreSegment(properties.proprioceptionCoreSegment); // clang-format on - coreSegment.forEachEntity([&platformState](const wm::Entity & entity) - { - const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - - const auto proprioception = tryCast<::armarx::armem::arondto::Proprioception>(entityInstance); - ARMARX_CHECK(proprioception.has_value()); + coreSegment.forEachEntity( + [&platformState](const wm::Entity& entity) + { + const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - platformState = robot::PlatformState(); // initialize optional - robot::fromAron(proprioception->platform, platformState.value()); + const auto proprioception = + tryCast<::armarx::armem::arondto::Proprioception>(entityInstance); + ARMARX_CHECK(proprioception.has_value()); - }); + platformState = robot::PlatformState(); // initialize optional + robot::fromAron(proprioception->platform, platformState.value()); + }); return platformState; } + inline RobotReader::Hand fromHandName(const std::string& name) + { + if(name == "Left") + { + return RobotReader::Hand::Left; + } + + if(name == "Right") + { + return RobotReader::Hand::Right; + } + + throw LocalException("Unknown hand name `" + name + "`!"); + } + + std::map<RobotReader::Hand, robot::ForceTorque> + RobotReader::getForceTorque(const armarx::armem::wm::Memory& memory, + const std::string& name) const + { + std::map<RobotReader::Hand, robot::ForceTorque> forceTorques; + + // clang-format off + const armem::wm::CoreSegment& coreSegment = memory + .getCoreSegment(properties.proprioceptionCoreSegment); + // clang-format on + + coreSegment.forEachEntity( + [&forceTorques](const wm::Entity& entity) + { + const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); + + const auto proprioception = + tryCast<::armarx::armem::arondto::Proprioception>(entityInstance); + ARMARX_CHECK(proprioception.has_value()); + + + for(const auto& [handName, dtoFt]: proprioception->forceTorque) + { + robot::ForceTorque forceTorque; + robot::fromAron(dtoFt, forceTorque); + + const auto hand = fromHandName(handName); + forceTorques.emplace(hand, forceTorque); + } + }); + + return forceTorques; + } std::optional<robot::RobotDescription> @@ -382,10 +470,8 @@ namespace armarx::armem::robot_state // clang-format on const armem::wm::EntityInstance* instance = nullptr; - providerSegment.forEachInstance([&instance](const wm::EntityInstance & i) - { - instance = &i; - }); + providerSegment.forEachInstance([&instance](const wm::EntityInstance& i) + { instance = &i; }); if (!instance) { ARMARX_WARNING << "No entity snapshots found"; diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h index e24bc65fa8a9ca14213bfe79007fc8519f02d176..51fe24008eaba3a4edb6953a76753436c31595ef 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h +++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h @@ -26,10 +26,8 @@ #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h> #include <RobotAPI/libraries/armem/client/Reader.h> - #include <RobotAPI/libraries/armem_robot/client/interfaces.h> #include <RobotAPI/libraries/armem_robot/types.h> - #include <RobotAPI/libraries/armem_robot_state/client/localization/TransformReader.h> @@ -59,10 +57,10 @@ namespace armarx::armem::robot_state const armem::Time& timestamp) override; std::optional<robot::RobotDescription> queryDescription(const std::string& name, - const armem::Time& timestamp); + const armem::Time& timestamp); std::optional<robot::RobotState> queryState(const robot::RobotDescription& description, - const armem::Time& timestamp); + const armem::Time& timestamp); std::optional<robot::RobotState::JointMap> queryJointState(const robot::RobotDescription& description, @@ -76,25 +74,40 @@ namespace armarx::armem::robot_state queryPlatformState(const robot::RobotDescription& description, const armem::Time& timestamp) const; + + enum class Hand + { + Left, + Right + }; + + std::optional<std::map<Hand, robot::ForceTorque>> + queryForceTorque(const robot::RobotDescription& description, + const armem::Time& timestamp) const; + private: std::optional<robot::RobotState> getRobotState(const armarx::armem::wm::Memory& memory, - const std::string& name) const; + const std::string& name) const; std::optional<robot::RobotDescription> getRobotDescription(const armarx::armem::wm::Memory& memory, const std::string& name) const; - + std::optional<robot::RobotState::JointMap> getRobotJointState(const armarx::armem::wm::Memory& memory, const std::string& name) const; std::optional<robot::PlatformState> - getRobotPlatformState(const armarx::armem::wm::Memory& memory, const std::string& name) const; + getRobotPlatformState(const armarx::armem::wm::Memory& memory, + const std::string& name) const; + + std::map<RobotReader::Hand, robot::ForceTorque> + getForceTorque(const armarx::armem::wm::Memory& memory, const std::string& name) const; struct Properties { - std::string memoryName = "RobotState"; - std::string descriptionCoreSegment = "Description"; - std::string localizationCoreSegment = "Localization"; + std::string memoryName = "RobotState"; + std::string descriptionCoreSegment = "Description"; + std::string localizationCoreSegment = "Localization"; std::string proprioceptionCoreSegment = "Proprioception"; } properties;