diff --git a/data/RobotAPI/robotStateMemoryConfig.txt b/data/RobotAPI/robotStateMemoryConfig.txt index bc928c16990df50ca55c96550f320efac999c332..e6e6498e4ce03f08c6b930cb3b73c678a578f34c 100644 --- a/data/RobotAPI/robotStateMemoryConfig.txt +++ b/data/RobotAPI/robotStateMemoryConfig.txt @@ -1,5 +1,7 @@ // Configuration set for the Humanoid Robot ARMAR-6 -// Left Hand unit + +// Reft Hand + sens.Index L 1 Joint.acceleration => HandL sens.Index L 1 Joint.gravityTorque => HandL sens.Index L 1 Joint.inertiaTorque => HandL @@ -103,7 +105,9 @@ sens.Thumb L 2 Joint.position => HandL sens.Thumb L 2 Joint.torque => HandL sens.Thumb L 2 Joint.velocity => HandL -// Right Hand unit + +// Right Hand + sens.Index R 1 Joint.acceleration => HandR sens.Index R 1 Joint.gravityTorque => HandR sens.Index R 1 Joint.inertiaTorque => HandR @@ -185,7 +189,165 @@ sens.Thumb R 2 Joint.position => HandR sens.Thumb R 2 Joint.torque => HandR sens.Thumb R 2 Joint.velocity => HandR +sens.Pinky R 1 Joint.acceleration => HandR +sens.Pinky R 1 Joint.gravityTorque => HandR +sens.Pinky R 1 Joint.inertiaTorque => HandR +sens.Pinky R 1 Joint.inverseDynamicsTorque => HandR +sens.Pinky R 1 Joint.position => HandR +sens.Pinky R 1 Joint.torque => HandR +sens.Pinky R 1 Joint.velocity => HandR +sens.Pinky R 2 Joint.acceleration => HandR +sens.Pinky R 2 Joint.gravityTorque => HandR +sens.Pinky R 2 Joint.inertiaTorque => HandR +sens.Pinky R 2 Joint.inverseDynamicsTorque => HandR +sens.Pinky R 2 Joint.position => HandR +sens.Pinky R 2 Joint.torque => HandR +sens.Pinky R 2 Joint.velocity => HandR +sens.Pinky R 3 Joint.acceleration => HandR +sens.Pinky R 3 Joint.gravityTorque => HandR +sens.Pinky R 3 Joint.inertiaTorque => HandR +sens.Pinky R 3 Joint.inverseDynamicsTorque => HandR +sens.Pinky R 3 Joint.position => HandR +sens.Pinky R 3 Joint.torque => HandR +sens.Pinky R 3 Joint.velocity => HandR + + +// Arm L + +sens.ArmL1_Cla1.acceleration => ArmL +sens.ArmL1_Cla1.gravityTorque => ArmL +sens.ArmL1_Cla1.inertiaTorque => ArmL +sens.ArmL1_Cla1.inverseDynamicsTorque => ArmL +sens.ArmL1_Cla1.position => ArmL +sens.ArmL1_Cla1.torque => ArmL +sens.ArmL1_Cla1.velocity => ArmL + +sens.ArmL2_Sho1.acceleration => ArmL +sens.ArmL2_Sho1.gravityTorque => ArmL +sens.ArmL2_Sho1.inertiaTorque => ArmL +sens.ArmL2_Sho1.inverseDynamicsTorque => ArmL +sens.ArmL2_Sho1.position => ArmL +sens.ArmL2_Sho1.torque => ArmL +sens.ArmL2_Sho1.velocity => ArmL + +sens.ArmL3_Sho2.acceleration => ArmL +sens.ArmL3_Sho2.gravityTorque => ArmL +sens.ArmL3_Sho2.inertiaTorque => ArmL +sens.ArmL3_Sho2.inverseDynamicsTorque => ArmL +sens.ArmL3_Sho2.position => ArmL +sens.ArmL3_Sho2.torque => ArmL +sens.ArmL3_Sho2.velocity => ArmL + +sens.ArmL4_Sho3.acceleration => ArmL +sens.ArmL4_Sho3.gravityTorque => ArmL +sens.ArmL4_Sho3.inertiaTorque => ArmL +sens.ArmL4_Sho3.inverseDynamicsTorque => ArmL +sens.ArmL4_Sho3.position => ArmL +sens.ArmL4_Sho3.torque => ArmL +sens.ArmL4_Sho3.velocity => ArmL + +sens.ArmL5_Elb1.acceleration => ArmL +sens.ArmL5_Elb1.gravityTorque => ArmL +sens.ArmL5_Elb1.inertiaTorque => ArmL +sens.ArmL5_Elb1.inverseDynamicsTorque => ArmL +sens.ArmL5_Elb1.position => ArmL +sens.ArmL5_Elb1.torque => ArmL +sens.ArmL5_Elb1.velocity => ArmL + +sens.ArmL6_Elb2.acceleration => ArmL +sens.ArmL6_Elb2.gravityTorque => ArmL +sens.ArmL6_Elb2.inertiaTorque => ArmL +sens.ArmL6_Elb2.inverseDynamicsTorque => ArmL +sens.ArmL6_Elb2.position => ArmL +sens.ArmL6_Elb2.torque => ArmL +sens.ArmL6_Elb2.velocity => ArmL + +sens.ArmL7_Wri1.acceleration => ArmL +sens.ArmL7_Wri1.gravityTorque => ArmL +sens.ArmL7_Wri1.inertiaTorque => ArmL +sens.ArmL7_Wri1.inverseDynamicsTorque => ArmL +sens.ArmL7_Wri1.position => ArmL +sens.ArmL7_Wri1.torque => ArmL +sens.ArmL7_Wri1.velocity => ArmL + +sens.ArmL8_Wri2.acceleration => ArmL +sens.ArmL8_Wri2.gravityTorque => ArmL +sens.ArmL8_Wri2.inertiaTorque => ArmL +sens.ArmL8_Wri2.inverseDynamicsTorque => ArmL +sens.ArmL8_Wri2.position => ArmL +sens.ArmL8_Wri2.torque => ArmL +sens.ArmL8_Wri2.velocity => ArmL + + +// Arm R + +sens.ArmR1_Cla1.acceleration => ArmR +sens.ArmR1_Cla1.gravityTorque => ArmR +sens.ArmR1_Cla1.inertiaTorque => ArmR +sens.ArmR1_Cla1.inverseDynamicsTorque => ArmR +sens.ArmR1_Cla1.position => ArmR +sens.ArmR1_Cla1.torque => ArmR +sens.ArmR1_Cla1.velocity => ArmR + +sens.ArmR2_Sho1.acceleration => ArmR +sens.ArmR2_Sho1.gravityTorque => ArmR +sens.ArmR2_Sho1.inertiaTorque => ArmR +sens.ArmR2_Sho1.inverseDynamicsTorque => ArmR +sens.ArmR2_Sho1.position => ArmR +sens.ArmR2_Sho1.torque => ArmR +sens.ArmR2_Sho1.velocity => ArmR + +sens.ArmR3_Sho2.acceleration => ArmR +sens.ArmR3_Sho2.gravityTorque => ArmR +sens.ArmR3_Sho2.inertiaTorque => ArmR +sens.ArmR3_Sho2.inverseDynamicsTorque => ArmR +sens.ArmR3_Sho2.position => ArmR +sens.ArmR3_Sho2.torque => ArmR +sens.ArmR3_Sho2.velocity => ArmR + +sens.ArmR4_Sho3.acceleration => ArmR +sens.ArmR4_Sho3.gravityTorque => ArmR +sens.ArmR4_Sho3.inertiaTorque => ArmR +sens.ArmR4_Sho3.inverseDynamicsTorque => ArmR +sens.ArmR4_Sho3.position => ArmR +sens.ArmR4_Sho3.torque => ArmR +sens.ArmR4_Sho3.velocity => ArmR + +sens.ArmR5_Elb1.acceleration => ArmR +sens.ArmR5_Elb1.gravityTorque => ArmR +sens.ArmR5_Elb1.inertiaTorque => ArmR +sens.ArmR5_Elb1.inverseDynamicsTorque => ArmR +sens.ArmR5_Elb1.position => ArmR +sens.ArmR5_Elb1.torque => ArmR +sens.ArmR5_Elb1.velocity => ArmR + +sens.ArmR6_Elb2.acceleration => ArmR +sens.ArmR6_Elb2.gravityTorque => ArmR +sens.ArmR6_Elb2.inertiaTorque => ArmR +sens.ArmR6_Elb2.inverseDynamicsTorque => ArmR +sens.ArmR6_Elb2.position => ArmR +sens.ArmR6_Elb2.torque => ArmR +sens.ArmR6_Elb2.velocity => ArmR + +sens.ArmR7_Wri1.acceleration => ArmR +sens.ArmR7_Wri1.gravityTorque => ArmR +sens.ArmR7_Wri1.inertiaTorque => ArmR +sens.ArmR7_Wri1.inverseDynamicsTorque => ArmR +sens.ArmR7_Wri1.position => ArmR +sens.ArmR7_Wri1.torque => ArmR +sens.ArmR7_Wri1.velocity => ArmR + +sens.ArmR8_Wri2.acceleration => ArmR +sens.ArmR8_Wri2.gravityTorque => ArmR +sens.ArmR8_Wri2.inertiaTorque => ArmR +sens.ArmR8_Wri2.inverseDynamicsTorque => ArmR +sens.ArmR8_Wri2.position => ArmR +sens.ArmR8_Wri2.torque => ArmR +sens.ArmR8_Wri2.velocity => ArmR + + // Neck + sens.Neck_1_Yaw.acceleration => Neck sens.Neck_1_Yaw.gravityTorque => Neck sens.Neck_1_Yaw.inertiaTorque => Neck @@ -193,10 +355,70 @@ sens.Neck_1_Yaw.inverseDynamicsTorque => Neck sens.Neck_1_Yaw.position => Neck sens.Neck_1_Yaw.torque => Neck sens.Neck_1_Yaw.velocity => Neck + sens.Neck_2_Pitch.acceleration => Neck sens.Neck_2_Pitch.gravityTorque => Neck sens.Neck_2_Pitch.inertiaTorque => Neck -sens.Neck_2_Pitch.inverseDynamicsTorque +sens.Neck_2_Pitch.inverseDynamicsTorque => Neck sens.Neck_2_Pitch.position => Neck sens.Neck_2_Pitch.torque => Neck sens.Neck_2_Pitch.velocity => Neck + + +// Torso + +sens.TorsoJoint.acceleration => Torso +sens.TorsoJoint.gravityTorque => Torso +sens.TorsoJoint.inertiaTorque => Torso +sens.TorsoJoint.inverseDynamicsTorque => Torso +sens.TorsoJoint.position => Torso +sens.TorsoJoint.torque => Torso +sens.TorsoJoint.velocity => Torso + + +// Platform + +sens.Platform.accelerationX => Platform +sens.Platform.accelerationY => Platform +sens.Platform.accelerationRotation => Platform +sens.Platform.absolutePositionX => Platform +sens.Platform.absolutePositionY => Platform +sens.Platform.absolutePositionRotation => Platform +sens.Platform.relativePositionX => Platform +sens.Platform.relativePositionY => Platform +sens.Platform.relativePositionRotation => Platform +sens.Platform.velocityX => Platform +sens.Platform.velocityY => Platform +sens.Platform.velocityRotation => Platform + + +// FT L + +sens.FT L.fx => FT L +sens.FT L.fy => FT L +sens.FT L.fz => FT L +sens.FT L.gravCompFx => FT L +sens.FT L.gravCompFy => FT L +sens.FT L.gravCompFz => FT L +sens.FT L.gravCompTx => FT L +sens.FT L.gravCompTy => FT L +sens.FT L.gravCompTz => FT L +sens.FT L.tx => FT L +sens.FT L.ty => FT L +sens.FT L.tz => FT L + + +// FT R + +sens.FT R.fx => FT R +sens.FT R.fy => FT R +sens.FT R.fz => FT R +sens.FT R.gravCompFx => FT R +sens.FT R.gravCompFy => FT R +sens.FT R.gravCompFz => FT R +sens.FT R.gravCompTx => FT R +sens.FT R.gravCompTy => FT R +sens.FT R.gravCompTz => FT R +sens.FT R.tx => FT R +sens.FT R.ty => FT R +sens.FT R.tz => FT R diff --git a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp index 5f99047a649e80be511efd37c1cfbc8ac438031a..778c2db5fd47742488efb3ee0f8ce6aaae4fe0e3 100644 --- a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp +++ b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp @@ -5,6 +5,7 @@ #include <Inventor/sensors/SoTimerSensor.h> #include <Inventor/nodes/SoUnits.h> +#include <QCoreApplication> #include <thread> @@ -88,11 +89,6 @@ namespace armarx::viz &CoinVisualizerWrapper::onUpdateSuccess, &CoinVisualizerWrapper::onUpdateFailure); root = new SoSeparator; - - //timerSensor = new SoTimerSensor(updateVisualizationCB, this); - - //float cycleTimeMS = 33.0f; - //timerSensor->setInterval(SbTime(cycleTimeMS / 1000.0f)); } CoinVisualizer::~CoinVisualizer() @@ -114,9 +110,6 @@ namespace armarx::viz } state = CoinVisualizerState::STARTING; stateStorage = storage; - - //SoSensorManager* sensor_mgr = SoDB::getSensorManager(); - //sensor_mgr->insertTimerSensor(timerSensor); } void CoinVisualizer::stop() @@ -126,15 +119,12 @@ namespace armarx::viz return; } - SoSensorManager* sensor_mgr = SoDB::getSensorManager(); state = CoinVisualizerState::STOPPING; while (state != CoinVisualizerState::STOPPED) { - sensor_mgr->processTimerQueue(); + QCoreApplication::processEvents(); usleep(1000); } - sensor_mgr->removeTimerSensor(timerSensor); - } CoinVisualizer_ApplyTiming CoinVisualizer::apply(data::LayerUpdate const& update) diff --git a/source/RobotAPI/components/ArViz/Coin/Visualizer.h b/source/RobotAPI/components/ArViz/Coin/Visualizer.h index 49ad2a51bd6f70dfddac1785296b8abc07ba08c9..1494be07dc5615b787f2a50f12a48451b40e045a 100644 --- a/source/RobotAPI/components/ArViz/Coin/Visualizer.h +++ b/source/RobotAPI/components/ArViz/Coin/Visualizer.h @@ -229,7 +229,6 @@ namespace armarx::viz std::mutex storageMutex; viz::StorageInterfacePrx storage; - SoTimerSensor* timerSensor = nullptr; CoinLayerMap layers; std::vector<std::type_index> elementVisualizersTypes; diff --git a/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp b/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp index 487c9c6fc4c732fc1d4fe2f126724cb74c8dd810..72e5b8f33073f716e9d3a299ea26dda288dc6066 100644 --- a/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp +++ b/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp @@ -42,7 +42,7 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/core/Time.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> #include <RobotAPI/libraries/armem_objects/types.h> diff --git a/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.h b/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.h index f85a804e97337e1193ca1f38048beb103e65ce59..b4cab3fc71e6d6b1dd92e3128fd3a90a8c191109 100644 --- a/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.h +++ b/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.h @@ -14,7 +14,7 @@ #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h> #include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/libraries/armem/client/ComponentPlugin.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h> #include <RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.h> diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp index 8ae42e00bd5385886696dd6ead35feb927665947..036d27d2bf49f7d5ac9f84e940bf7e1e88b033b1 100644 --- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp +++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp @@ -34,7 +34,7 @@ #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/core/error.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.aron.generated.h> @@ -260,37 +260,24 @@ namespace armarx if (qResult.success) { - armem::wm::Memory& memory = qResult.memory; - - ARMARX_CHECK_EQUAL(memory.coreSegments().size(), 1); - armem::wm::CoreSegment& coreSeg = memory.coreSegments().begin()->second; + ARMARX_IMPORTANT << "Getting entity via ID"; - ARMARX_CHECK_EQUAL(coreSeg.providerSegments().size(), 1); - armem::wm::ProviderSegment& provSeg = coreSeg.providerSegments().begin()->second; + armem::wm::Memory& memory = qResult.memory; + ARMARX_CHECK_GREATER_EQUAL(memory.size(), 1); - ARMARX_CHECK_EQUAL(provSeg.entities().size(), 1); - armem::wm::Entity& entity = provSeg.entities().begin()->second; + const armem::wm::Entity* entity = memory.findEntity(entityID); + ARMARX_CHECK_NOT_NULL(entity); + ARMARX_CHECK_GREATER_EQUAL(entity->size(), 1); - ARMARX_CHECK_GREATER_EQUAL(entity.history().size(), 1); - armem::wm::EntitySnapshot& snapshot = entity.history().begin()->second; + const armem::wm::EntitySnapshot& snapshot = entity->getLatestSnapshot(); + ARMARX_CHECK_GREATER_EQUAL(snapshot.size(), 1); ARMARX_INFO << "Result: " - << "\n- memory: \t" << memory.name() - << "\n- core segment: \t" << coreSeg.name() - << "\n- prov segment: \t" << provSeg.name() - << "\n- entity: \t" << entity.name() + << "\n- entity: \t" << entity->name() << "\n- snapshot: \t" << snapshot.time() << "\n- #instances: \t" << snapshot.size() ; - ARMARX_IMPORTANT << "Getting entity via ID"; - const armem::wm::Entity& e = memory.getEntity(entityID); - ARMARX_INFO << "Result: " - << "\n- entity: \t" << e.name() - << "\n- snapshot: \t" << e.getLatestSnapshot().time() - << "\n- #instances: \t" << e.getLatestSnapshot().size() - ; - // Show memory contents in remote gui. tab.queryResult = std::move(memory); tab.rebuild = true; diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h index 5680e316a6228021932afea5d73abd02fdcda6d8..ca28ab86bc1e755c49b93649fd77b26aac0a4250 100644 --- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h +++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h @@ -34,7 +34,7 @@ #include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h> #include <RobotAPI/libraries/armem/client/ComponentPlugin.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> namespace armarx diff --git a/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp b/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp index 6650e573785cce732f0f2bbe7c128aa34fc58626..8ab75efc78ddad8492598356df374266947fe515 100644 --- a/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp +++ b/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp @@ -23,7 +23,7 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> #include <RobotAPI/libraries/armem/core/Time.h> diff --git a/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.h b/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.h index 4e1d01f5564e96c7e46ad2db33081835873dd7a6..33770ad5425f8824fca2f40ae45323861f29cc91 100644 --- a/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.h +++ b/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.h @@ -33,7 +33,7 @@ #include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h> #include <RobotAPI/libraries/armem/client/ComponentPlugin.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h> diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp index 3ed4b4612c5dd3f6e0afbd71630dba7a4753f460..e007e8f5e3ad47c57f9bb71c75e517d57af1addf 100644 --- a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp +++ b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp @@ -122,7 +122,7 @@ namespace armarx using namespace armarx::RemoteGui::Client; { - std::scoped_lock lock(workingMemoryMutex); + // Core segments are locked by MemoryRemoteGui. tab.memoryGroup = armem::server::MemoryRemoteGui().makeGroupBox(workingMemory); } diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp b/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp index c5ba35a13aa4ec127f64d0992021d29262d54407..56c9d08f49759de2f75c8085551ea63fb9263935 100644 --- a/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp +++ b/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(test_ExampleData_type) { armarx::aron::typenavigator::ObjectNavigatorPtr type = ExampleData::toAronType(); - BOOST_CHECK_EQUAL(type->childrenSize(), 15); + BOOST_CHECK_EQUAL(type->childrenSize(), 16); armem::wm::Memory memory; armem::wm::CoreSegment& core = memory.addCoreSegment("ExampleData", type); diff --git a/source/RobotAPI/components/armem/server/MotionMemory/MotionMemory.cpp b/source/RobotAPI/components/armem/server/MotionMemory/MotionMemory.cpp index ef176a8ffe85af763135febb8ac3af45f317af4f..350810558ce9d2200e61bda865dd1633da15c128 100644 --- a/source/RobotAPI/components/armem/server/MotionMemory/MotionMemory.cpp +++ b/source/RobotAPI/components/armem/server/MotionMemory/MotionMemory.cpp @@ -42,7 +42,7 @@ namespace armarx } MotionMemory::MotionMemory() : - mdbMotions(armem::server::ComponentPluginUser::iceMemory, armem::server::ComponentPluginUser::workingMemoryMutex) + mdbMotions(armem::server::ComponentPluginUser::iceMemory) { } diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp index 91ea5b23400f568891326f6dd6c79b5e603d229c..c624379b89ae336aa561e364706f3780b7fbf0e9 100644 --- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp +++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp @@ -59,22 +59,27 @@ namespace armarx::armem::server::obj return defs; } + ObjectMemory::ObjectMemory() : server::ComponentPluginUser(), - instance::SegmentAdapter(server::ComponentPluginUser::iceMemory, - server::ComponentPluginUser::workingMemoryMutex), - classSegment(server::ComponentPluginUser::iceMemory, - server::ComponentPluginUser::workingMemoryMutex), - attachmentSegment(server::ComponentPluginUser::iceMemory, - server::ComponentPluginUser::workingMemoryMutex) + instance::SegmentAdapter(server::ComponentPluginUser::iceMemory), + classSegment(server::ComponentPluginUser::iceMemory), + attachmentSegment(server::ComponentPluginUser::iceMemory) + { + } + + + ObjectMemory::~ObjectMemory() { } + std::string ObjectMemory::getDefaultName() const { return "ObjectMemory"; } + void ObjectMemory::onInitComponent() { workingMemory.name() = defaultMemoryName; @@ -114,6 +119,7 @@ namespace armarx::armem::server::obj }); } + void ObjectMemory::onConnectComponent() { // onConnect can be called multiple times, but addRobot will fail if called more than once with the same ID @@ -141,17 +147,17 @@ namespace armarx::armem::server::obj ArVizComponentPluginUser::getArvizClient() ); - attachmentSegment.connect( - ArVizComponentPluginUser::getArvizClient() - ); + attachmentSegment.connect(); RemoteGui_startRunningTask(); } + void ObjectMemory::onDisconnectComponent() { } + void ObjectMemory::onExitComponent() { } diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h index f29b2cef93efb2aa35a7983f4dce87d3db854b80..b90406be31ac76a40172d67076f931ebb1a6ba1a 100644 --- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h +++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h @@ -38,8 +38,6 @@ #include <RobotAPI/libraries/armem_objects/server/class/Segment.h> #include <RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h> -#include <RobotAPI/libraries/armem_objects/server/articulated_object_instance/Segment.h> -#include <RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.h> #include <RobotAPI/libraries/armem_objects/server/attachments/Segment.h> @@ -81,6 +79,7 @@ namespace armarx::armem::server::obj public: ObjectMemory(); + virtual ~ObjectMemory(); /// @see armarx::ManagedIceObject::getDefaultName() diff --git a/source/RobotAPI/components/armem/server/RobotStateMemory/CMakeLists.txt b/source/RobotAPI/components/armem/server/RobotStateMemory/CMakeLists.txt index 137453970c1a97f0f3bd9653c067e959db21b4a5..f49cb33c231a20857aa30458b4f7f5f14c05acdc 100644 --- a/source/RobotAPI/components/armem/server/RobotStateMemory/CMakeLists.txt +++ b/source/RobotAPI/components/armem/server/RobotStateMemory/CMakeLists.txt @@ -2,11 +2,14 @@ armarx_component_set_name("RobotStateMemory") set(COMPONENT_LIBS + # ArmarXCore ArmarXCore ArmarXCoreInterfaces # for DebugObserverInterface + ArmarXCoreComponentPlugins + # ArmarXGUI ArmarXGuiComponentPlugins - RobotAPICore - RobotAPIInterfaces - RobotAPIComponentPlugins + # RobotAPI + RobotAPICore RobotAPIInterfaces + RobotAPIComponentPlugins armem armem_robot_state ) diff --git a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp index 111cced66ba9f678ba852d1005a10ded834d0946..4dde0d39cfc4d248188e9af772af470914c73290 100644 --- a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp +++ b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp @@ -23,46 +23,40 @@ #include "RobotStateMemory.h" // STD -#include <algorithm> -#include <iostream> -#include <fstream> #include <memory> -// Eigen -#include <Eigen/Core> -#include <Eigen/Geometry> - // Simox #include <SimoxUtility/algorithm/string.h> -#include <SimoxUtility/math/convert/rpy_to_mat3f.h> // ArmarX -#include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/system/ArmarXDataPath.h> +#include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h> #include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> -#include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> -#include <RobotAPI/libraries/aron/core/navigator/type/AllNavigators.h> #include <RobotAPI/libraries/armem_robot_state/server/common/Visu.h> -#include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h> -#include <RobotAPI/libraries/core/FramedPose.h> -#include <RobotAPI/libraries/armem/core/Time.h> -#include <RobotAPI/libraries/core/Pose.h> +#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h> + +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h> + namespace armarx::armem::server::robot_state { + RobotStateMemory::RobotStateMemory() - : descriptionSegment(server::ComponentPluginUser::iceMemory, - server::ComponentPluginUser::workingMemoryMutex), - proprioceptionSegment(server::ComponentPluginUser::iceMemory, - server::ComponentPluginUser::workingMemoryMutex), - localizationSegment(server::ComponentPluginUser::iceMemory, - server::ComponentPluginUser::workingMemoryMutex), + : descriptionSegment(server::ComponentPluginUser::iceMemory), + proprioceptionSegment(server::ComponentPluginUser::iceMemory), + localizationSegment(server::ComponentPluginUser::iceMemory), commonVisu(descriptionSegment, proprioceptionSegment, localizationSegment) { + addPlugin(debugObserver); + ARMARX_CHECK_NOT_NULL(debugObserver); + addPlugin(robotUnit.plugin); + ARMARX_CHECK_NOT_NULL(robotUnit.plugin); + robotUnit.reader.setTag(getName()); + robotUnit.writer.setTag(getName()); } RobotStateMemory::~RobotStateMemory() = default; @@ -75,21 +69,25 @@ namespace armarx::armem::server::robot_state const std::string prefix = "mem."; workingMemory.name() = "RobotState"; + longtermMemory.name() = "RobotState"; defs->optional(workingMemory.name(), prefix + "MemoryName", "Name of this memory server."); const std::string robotUnitPrefix{sensorValuePrefix}; - defs->optional(robotUnitSensorPrefix, robotUnitPrefix + "SensorValuePrefix", "Prefix of all sensor values"); - defs->optional(robotUnitMemoryBatchSize, robotUnitPrefix + "MemoryBatchSize", "The size of the entity snapshot to send to the memory. Min is 1"); - defs->optional(robotUnitPollFrequency, robotUnitPrefix + "UpdateFrequency", "The frequency in Hz to store values. All other values get discarded. Min is 1, max is " + std::to_string(ROBOT_UNIT_MAXIMUM_FREQUENCY)); - defs->optional(robotUnitConfigPath, robotUnitPrefix + "ConfigPath", "Specify a configuration file to group the sensor values specifically."); - - descriptionSegment.defineProperties(defs); - proprioceptionSegment.defineProperties(defs); - localizationSegment.defineProperties(defs); - commonVisu.defineProperties(defs); - - setRobotUnitAsOptionalDependency(); + defs->optional(robotUnit.reader.properties.sensorPrefix, robotUnitPrefix + "SensorValuePrefix", + "Prefix of all sensor values."); + defs->optional(robotUnit.writer.properties.memoryBatchSize, robotUnitPrefix + "MemoryBatchSize", + "The size of the entity snapshot to send to the memory. Minimum is 1.") + .setMin(1); + defs->optional(robotUnit.pollFrequency, robotUnitPrefix + "UpdateFrequency", + "The frequency to store values in Hz. All other values get discarded. " + "Minimum is 1, max is " + std::to_string(ROBOT_UNIT_MAXIMUM_FREQUENCY) + ".") + .setMin(1).setMax(ROBOT_UNIT_MAXIMUM_FREQUENCY); + + descriptionSegment.defineProperties(defs, prefix + "desc."); + proprioceptionSegment.defineProperties(defs, prefix + "prop."); + localizationSegment.defineProperties(defs, prefix + "loc."); + commonVisu.defineProperties(defs, prefix + "visu."); return defs; } @@ -103,17 +101,16 @@ namespace armarx::armem::server::robot_state void RobotStateMemory::onInitComponent() { - - descriptionSegment.init(); - proprioceptionSegment.init(); - localizationSegment.init(); + descriptionSegment.onInit(); + proprioceptionSegment.onInit(); + localizationSegment.onInit(); commonVisu.init(); - robotUnitMemoryBatchSize = std::max((unsigned int) 1, robotUnitMemoryBatchSize); - robotUnitPollFrequency = std::clamp(robotUnitPollFrequency, 1, ROBOT_UNIT_MAXIMUM_FREQUENCY); + robotUnit.pollFrequency = std::clamp(robotUnit.pollFrequency, 1, ROBOT_UNIT_MAXIMUM_FREQUENCY); + robotUnit.writer.properties.memoryBatchSize = std::max(static_cast<unsigned int>(1), robotUnit.writer.properties.memoryBatchSize); - Ice::StringSeq includePaths; - auto packages = armarx::Application::GetProjectDependencies(); + std::vector<std::string> includePaths; + std::vector<std::string> packages = armarx::Application::GetProjectDependencies(); packages.push_back(Application::GetProjectName()); for (const std::string& projectName : packages) @@ -124,44 +121,47 @@ namespace armarx::armem::server::robot_state } CMakePackageFinder project(projectName); - auto pathsString = project.getIncludePaths(); - Ice::StringSeq projectIncludePaths = simox::alg::split(pathsString, ";,"); + std::string pathsString = project.getIncludePaths(); + std::vector<std::string> projectIncludePaths = simox::alg::split(pathsString, ";,"); includePaths.insert(includePaths.end(), projectIncludePaths.begin(), projectIncludePaths.end()); } - - ArmarXDataPath::getAbsolutePath(robotUnitConfigPath, robotUnitConfigPath, includePaths); - - // workingMemory.name() = workingMemoryName; } void RobotStateMemory::onConnectComponent() { + ARMARX_CHECK_NOT_NULL(debugObserver->getDebugObserver()); - if (getRobotUnit()) + if (robotUnit.plugin->getRobotUnit()) { - waitUntilRobotUnitIsRunning(); + robotUnit.plugin->waitUntilRobotUnitIsRunning(); } + RobotUnitInterfacePrx robotUnitPrx = robotUnit.plugin->getRobotUnit(); - ARMARX_CHECK_NOT_NULL(getRobotUnit()->getKinematicUnit()); - - descriptionSegment.connect(getArvizClient(), getRobotUnit()); - - proprioceptionSegment.connect(getArvizClient(), getRobotUnit()); - toIce(robotUnitProviderID, proprioceptionSegment.getRobotUnitProviderID()); + descriptionSegment.onConnect(robotUnitPrx); + proprioceptionSegment.onConnect(robotUnitPrx); + localizationSegment.onConnect(); - localizationSegment.connect(getArvizClient()); + commonVisu.connect(getArvizClient(), debugObserver->getDebugObserver()); - commonVisu.connect( - getArvizClient() - ); + robotUnit.reader.connect(*robotUnit.plugin, *debugObserver, + proprioceptionSegment.getRobotUnitProviderID().providerSegmentName); + robotUnit.writer.connect(*debugObserver); + robotUnit.writer.properties.robotUnitProviderID = proprioceptionSegment.getRobotUnitProviderID(); - cfg.loggingNames.emplace_back(robotUnitSensorPrefix); - handler = make_shared<RobotUnitDataStreamingReceiver>(this, getRobotUnit(), cfg); - keys = handler->getDataDescription(); - - robotUnitConversionTask = new PeriodicTask<RobotStateMemory>(this, &RobotStateMemory::convertRobotUnitStreamingDataToAron, (1000 / robotUnitPollFrequency)); - robotUnitStoringTask = new PeriodicTask<RobotStateMemory>(this, &RobotStateMemory::storeConvertedRobotUnitDataInMemory, (1000 / robotUnitPollFrequency)); + robotUnit.reader.task = new SimpleRunningTask<>([this]() + { + robotUnit.reader.run( + robotUnit.pollFrequency, robotUnit.dataQueue, robotUnit.dataMutex + ); + }, "Robot Unit Reader"); + robotUnit.writer.task = new SimpleRunningTask<>([this]() + { + robotUnit.writer.run( + robotUnit.pollFrequency, robotUnit.dataQueue, robotUnit.dataMutex, + iceMemory, localizationSegment + ); + }, "Robot State Writer"); startRobotUnitStream(); } @@ -178,340 +178,45 @@ namespace armarx::armem::server::robot_state stopRobotUnitStream(); } + /*************************************************************/ // RobotUnit Streaming functions /*************************************************************/ - void RobotStateMemory::convertRobotUnitStreamingDataToAron() - { - auto& data = handler->getDataBuffer(); - if (data.size() == 0) - { - return; - } - auto& currentTimestep = data.back(); - - ARMARX_DEBUG << "RobotUnitData: Generating new aron map for current timestep"; - auto start = std::chrono::high_resolution_clock::now(); - - RobotUnitData convertedAndGroupedData; - for (const auto& [nameEntry, dataEntry] : keys.entries) - { - std::string name = nameEntry; - std::string jointOrWhateverName; - - std::string groupName = ""; - if (configSensorMapping.find(name) != configSensorMapping.end()) - { - groupName = configSensorMapping.at(name); - } - else - { - const size_t first_dot_pos = name.find("."); - const size_t second_dot_pos = name.find(".", first_dot_pos + 1); // find second occurence of "." - if (second_dot_pos == std::string::npos) - { - ARMARX_WARNING << "Could not find a groupname for the sensor with name " << name << ". All sensors must be called sens.X.Y where X is the name of the group and Y is the actual sensor. Ignoring this sensor."; - continue; - } - groupName = name.substr(0, second_dot_pos); - - jointOrWhateverName = name.substr(first_dot_pos + 1, second_dot_pos - first_dot_pos - 1); - - name = name.substr(second_dot_pos + 1); // remove the groupName, TODO check if +1 is valid - } - - RobotUnitData::RobotUnitDataGroup e; - if (auto it = convertedAndGroupedData.groups.find(groupName); it == convertedAndGroupedData.groups.end()) - { - // generate new dict for the group - auto dict = std::make_shared<aron::datanavigator::DictNavigator>(); - auto encGroupName = std::make_shared<aron::datanavigator::StringNavigator>(groupName); - dict->addElement("EncoderGroupName", encGroupName); - - auto iterId = std::make_shared<aron::datanavigator::LongNavigator>(currentTimestep.iterationId); - dict->addElement("IterationId", iterId); - - const auto nameId = std::make_shared<aron::datanavigator::StringNavigator>(jointOrWhateverName); - dict->addElement("name", nameId); - - e.timestamp = currentTimestep.timestampUSec; - e.name = groupName; - e.data = dict; - } - else - { - // reuse existing entry - e = it->second; - } - - switch (dataEntry.type) - { - case RobotUnitDataStreaming::NodeTypeFloat: - { - float value = RobotUnitDataStreamingReceiver::GetAs<Ice::Float>(currentTimestep, dataEntry); - auto aron = std::make_shared<aron::datanavigator::FloatNavigator>(value); - e.data->addElement(name, aron); - break; - } - case RobotUnitDataStreaming::NodeTypeBool: - { - bool value = RobotUnitDataStreamingReceiver::GetAs<bool>(currentTimestep, dataEntry); - auto aron = std::make_shared<aron::datanavigator::BoolNavigator>(value); - e.data->addElement(name, aron); - break; - } - case RobotUnitDataStreaming::NodeTypeByte: - { - int value = RobotUnitDataStreamingReceiver::GetAs<Ice::Byte>(currentTimestep, dataEntry); - auto aron = std::make_shared<aron::datanavigator::IntNavigator>(value); - e.data->addElement(name, aron); - break; - } - case RobotUnitDataStreaming::NodeTypeShort: - { - int value = RobotUnitDataStreamingReceiver::GetAs<Ice::Short>(currentTimestep, dataEntry); - auto aron = std::make_shared<aron::datanavigator::IntNavigator>(value); - e.data->addElement(name, aron); - break; - } - case RobotUnitDataStreaming::NodeTypeInt: - { - int value = RobotUnitDataStreamingReceiver::GetAs<Ice::Int>(currentTimestep, dataEntry); - auto aron = std::make_shared<aron::datanavigator::IntNavigator>(value); - e.data->addElement(name, aron); - break; - } - case RobotUnitDataStreaming::NodeTypeLong: - { - long value = RobotUnitDataStreamingReceiver::GetAs<Ice::Long>(currentTimestep, dataEntry); - auto aron = std::make_shared<aron::datanavigator::LongNavigator>(value); - e.data->addElement(name, aron); - break; - } - case RobotUnitDataStreaming::NodeTypeDouble: - { - double value = RobotUnitDataStreamingReceiver::GetAs<Ice::Double>(currentTimestep, dataEntry); - auto aron = std::make_shared<aron::datanavigator::DoubleNavigator>(value); - e.data->addElement(name, aron); - break; - } - default: - throw LocalException("The enum type should not exist! Perhaps someone changed the RobotUnitDataStreaming::NodeType enum definition?"); - } - - convertedAndGroupedData.groups.insert({groupName, e}); - } - { - std::lock_guard g{robotUnitDataMutex}; - robotUnitDataQueue.push(convertedAndGroupedData); - } - auto stop = std::chrono::high_resolution_clock::now(); - ARMARX_DEBUG << "RobotUnitData: The total time needed to convert the data to aron is: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start); - } - - void RobotStateMemory::storeConvertedRobotUnitDataInMemory() - { - unsigned int size = 0; - { - std::lock_guard g{robotUnitDataMutex}; - size = robotUnitDataQueue.size(); // the size can only grow - } - if (size >= robotUnitMemoryBatchSize) - { - ARMARX_DEBUG << "RobotUnitData: Sending batch of " << robotUnitMemoryBatchSize << " timesteps to memory... The size of the queue is: " << size; - auto start = std::chrono::high_resolution_clock::now(); - - // send batch to memory - armem::data::Commit proprioceptionCommit; - armem::data::Commit odometryCommit; - - for (unsigned int i = 0; i < robotUnitMemoryBatchSize; ++i) - { - std::lock_guard g{robotUnitDataMutex}; - const auto& convertedAndGroupedData = robotUnitDataQueue.front(); - for (const auto& [encName, encTimestep] : convertedAndGroupedData.groups) - { - ARMARX_CHECK_EQUAL(encName, encTimestep.name); - - auto entityID = robotUnitProviderID; - entityID.entityName = encName; - - const auto& timeUSec = encTimestep.timestamp; - const auto& aron = encTimestep.data; - - armem::data::EntityUpdate& update = proprioceptionCommit.updates.emplace_back(); - update.entityID = entityID; - update.timeCreatedMicroSeconds = timeUSec; - update.instancesData = {aron->toAronDictPtr()}; - } - - // odometry pose -> localization segment - auto it = convertedAndGroupedData.groups.find("sens.Platform"); - if (it != convertedAndGroupedData.groups.end()) - { - ARMARX_DEBUG << "Found odometry data."; - - const RobotUnitData::RobotUnitDataGroup& timestep = it->second; - const float relPosX = aron::datanavigator::FloatNavigator::DynamicCast(timestep.data->getElement("relativePositionX"))->getValue(); - const float relPosY = aron::datanavigator::FloatNavigator::DynamicCast(timestep.data->getElement("relativePositionY"))->getValue(); - const float relOrientation = aron::datanavigator::FloatNavigator::DynamicCast(timestep.data->getElement("relativePositionRotation"))->getValue(); - - Eigen::Affine3f odometryPose = Eigen::Affine3f::Identity(); - odometryPose.translation() << relPosX, relPosY, 0; // TODO set height - odometryPose.linear() = simox::math::rpy_to_mat3f(0.F, 0.F, relOrientation); - - // const auto timestamp = armem::Time::microSeconds(it->second.timestamp); - const auto timestamp = armem::Time::now(); - - const ::armarx::armem::robot_state::Transform transform - { - .header = - { - .parentFrame = OdometryFrame, - .frame = "root", // TODO: robot root node - .agent = robotUnitProviderID.providerSegmentName, - .timestamp = timestamp - }, - .transform = odometryPose - }; - - localizationSegment.storeTransform(transform); - - } - else - { - ARMARX_INFO << deactivateSpam(1000) << "No odometry data! If you are using a mobile platform this should not have happened"; - } - - - robotUnitDataQueue.pop(); - } - - auto results = commit(proprioceptionCommit); - auto stop = std::chrono::high_resolution_clock::now(); - ARMARX_DEBUG << "RobotUnitData: The total runtime of sending a batch to the memory is: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start); - - for (const auto& result : results.results) - { - if (!result.success) - { - ARMARX_WARNING << "Could not add data to memory. Error message: " << result.errorMessage; - } - } - } - } - - void RobotStateMemory::stopRobotUnitStream() - { - std::lock_guard g{startStopMutex}; - robotUnitConversionTask->stop(); - robotUnitStoringTask->stop(); - } void RobotStateMemory::startRobotUnitStream() { - std::lock_guard g{startStopMutex}; - if (robotUnitConversionTask->isRunning() || robotUnitStoringTask->isRunning()) + std::lock_guard lock{startStopMutex}; + if (robotUnit.reader.task->isRunning() || robotUnit.writer.task->isRunning()) { - if (robotUnitConversionTask->isRunning() && robotUnitStoringTask->isRunning()) + if (robotUnit.reader.task->isRunning() && robotUnit.writer.task->isRunning()) { return; } ARMARX_WARNING << "Found inconsistency in running tasks. Restarting all!"; stopRobotUnitStream(); } - - std::stringstream ss; - ss << "Getting sensor values for:" << std::endl; - for (const auto& [name, dataEntry] : keys.entries) { - std::string type = ""; - switch (dataEntry.type) + std::stringstream ss; + ss << "Getting sensor values for:" << std::endl; + for (const auto& [name, dataEntry] : robotUnit.reader.description.entries) { - case RobotUnitDataStreaming::NodeTypeBool: - { - type = "Bool"; - break; - } - case RobotUnitDataStreaming::NodeTypeByte: - { - type = "Byte"; - break; - } - case RobotUnitDataStreaming::NodeTypeShort: - { - type = "Short"; - break; - } - case RobotUnitDataStreaming::NodeTypeInt: - { - type = "Int"; - break; - } - case RobotUnitDataStreaming::NodeTypeLong: - { - type = "Long"; - break; - } - case RobotUnitDataStreaming::NodeTypeFloat: - { - type = "Float"; - break; - } - case RobotUnitDataStreaming::NodeTypeDouble: - { - type = "Double"; - break; - } + const std::string type = RobotUnitDataStreaming::DataEntryNames.to_name(dataEntry.type); + ss << "\t" << name << " (type: '" << type << "')" << std::endl; } - ss << "\t" << name << " (type: '" << type << "')" << std::endl; + ARMARX_INFO << ss.str(); } - ARMARX_INFO << ss.str(); - // parse config - std::filesystem::path configPath(robotUnitConfigPath); - configSensorMapping.clear(); - if (std::filesystem::is_regular_file(configPath)) - { - ARMARX_INFO << "Found a configuration file at: " << robotUnitConfigPath; - // a simple self-made parser for the config file. Extend it if you need to - std::ifstream in(configPath); - std::string line; - while (std::getline(in, line)) - { - if (line.size() > 0) - { - if (simox::alg::starts_with(line, "//")) - { - continue; - } - - std::vector<std::string> mappings = simox::alg::split(line, ","); - for (const auto& mapping : mappings) - { - std::vector<std::string> split = simox::alg::split(mapping, "=>"); - if (split.size() < 2) - { - ARMARX_WARNING << "A mapping in the RobotUnitConfig file is not valid. Ignoring it: " << mapping; - continue; - } - for (unsigned int i = 0; i < split.size() - 1; ++i) - { - ARMARX_DEBUG << "Setting sensor value '" << split[i] << "' to group '" << split[split.size() - 1] << "'."; - configSensorMapping.insert({split[i], split[split.size() - 1]}); - } - } - } - } - } - else - { - ARMARX_INFO << "The config path '" << robotUnitConfigPath << "' is not valid."; - } + robotUnit.reader.task->start(); + robotUnit.writer.task->start(); + } + - robotUnitConversionTask->start(); - robotUnitStoringTask->start(); + void RobotStateMemory::stopRobotUnitStream() + { + std::lock_guard lock{startStopMutex}; + robotUnit.reader.task->stop(); + robotUnit.writer.task->stop(); } } diff --git a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h index e8174416e9b547f70af5e5c6b578242a0234743d..2cd2be9e3a5838f16b1a385e829416429b7869cd 100644 --- a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h +++ b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.h @@ -24,28 +24,30 @@ // STD #include <atomic> -#include <thread> +#include <optional> #include <queue> -// Simox -#include <SimoxUtility/meta/enum/adapt_enum.h> - // ArmarX #include <ArmarXCore/core/Component.h> -#include <ArmarXCore/core/services/tasks/PeriodicTask.h> - -// BaseClass -#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h> -#include "RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h" +#include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h> #include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h> #include <RobotAPI/libraries/armem/server/ComponentPlugin.h> #include <RobotAPI/libraries/armem_robot_state/server/description/Segment.h> -#include <RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h> #include <RobotAPI/libraries/armem_robot_state/server/localization/Segment.h> #include <RobotAPI/libraries/armem_robot_state/server/common/Visu.h> +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h> +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h> +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h> +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h> + +namespace armarx::plugins +{ + class DebugObserverComponentPlugin; + class RobotUnitComponentPlugin; +} namespace armarx::armem::server::robot_state { @@ -63,44 +65,36 @@ namespace armarx::armem::server::robot_state class RobotStateMemory : virtual public armarx::Component, virtual public armem::server::ComponentPluginUser, - virtual public RobotUnitComponentPluginUser, virtual public armarx::ArVizComponentPluginUser { public: + RobotStateMemory(); + virtual ~RobotStateMemory() override; - virtual ~RobotStateMemory(); - /// @see armarx::ManagedIceObject::getDefaultName() std::string getDefaultName() const override; + protected: - /// @see armarx::ManagedIceObject::onInitComponent() - void onInitComponent() override; - /// @see armarx::ManagedIceObject::onConnectComponent() - void onConnectComponent() override; + armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; - /// @see armarx::ManagedIceObject::onDisconnectComponent() + void onInitComponent() override; + void onConnectComponent() override; void onDisconnectComponent() override; - - /// @see armarx::ManagedIceObject::onExitComponent() void onExitComponent() override; - /// @see PropertyUser::createPropertyDefinitions() - armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; private: - // RobotUnit Streaming - void convertRobotUnitStreamingDataToAron(); - void storeConvertedRobotUnitDataInMemory(); void startRobotUnitStream(); void stopRobotUnitStream(); + private: - std::string workingMemoryName = "RobotStateMemory"; - bool addCoreSegmentOnUsage = false; + + armarx::plugins::DebugObserverComponentPlugin* debugObserver = nullptr; mutable std::recursive_mutex startStopMutex; @@ -118,41 +112,27 @@ namespace armarx::armem::server::robot_state // Joint visu for all segments => robot pose and configuration Visu commonVisu; - // RobotUnit stuff - RobotUnitDataStreaming::DataStreamingDescription keys; - std::vector<RobotUnitDataStreaming::DataEntry> keysList; - RobotUnitDataStreaming::Config cfg; - RobotUnitDataStreamingReceiverPtr handler; - std::map<std::string, std::string> configSensorMapping; - struct RobotUnitData + struct RobotUnit { - struct RobotUnitDataGroup - { - long timestamp; - std::string name; - aron::datanavigator::DictNavigatorPtr data; - }; - - std::map<std::string, RobotUnitDataGroup> groups; + int pollFrequency = 50; + + armarx::plugins::RobotUnitComponentPlugin* plugin = nullptr; + proprioception::RobotUnitReader reader; + proprioception::RobotStateWriter writer; + + // queue + std::queue<proprioception::RobotUnitData> dataQueue; + mutable std::mutex dataMutex; }; + RobotUnit robotUnit; + // params static constexpr int ROBOT_UNIT_MAXIMUM_FREQUENCY = 100; static constexpr const char* sensorValuePrefix = "RobotUnit."; - int robotUnitPollFrequency = 50; - std::string robotUnitSensorPrefix = "sens.*"; - unsigned int robotUnitMemoryBatchSize = 50; - std::string robotUnitConfigPath = "NO CONFIG SET"; - - // queue - std::queue<RobotUnitData> robotUnitDataQueue; - mutable std::mutex robotUnitDataMutex; - // running tasks - armarx::PeriodicTask<RobotStateMemory>::pointer_type robotUnitConversionTask; - armarx::PeriodicTask<RobotStateMemory>::pointer_type robotUnitStoringTask; }; } // namespace armarx::armem::server::robot_state diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp index c0a9fd2f33211d9a130f236b9350836b75b51466..6c86b6afa76fe043b4dea16affb609f7db049caf 100644 --- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp +++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp @@ -29,7 +29,8 @@ #include <ArmarXCore/core/logging/Logging.h> #include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> #include <RobotAPI/libraries/armem_skills/aron_conversions.h> @@ -70,7 +71,7 @@ namespace armarx workingMemory.name() = p.memoryName; { - armarx::armem::wm::CoreSegment& c = workingMemory.addCoreSegment(p.statechartCoreSegmentName, armarx::armem::arondto::Statechart::Transition::toAronType()); + armarx::armem::server::wm::CoreSegment& c = workingMemory.addCoreSegment(p.statechartCoreSegmentName, armarx::armem::arondto::Statechart::Transition::toAronType()); c.addProviderSegment("Transitions", armarx::armem::arondto::Statechart::Transition::toAronType()); } } diff --git a/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt b/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt index 15153b3dca0bac00d1f8a6192191cead86227a05..f1e94f9b2478222809011ad2c150f2b97d0c9e72 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt +++ b/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt @@ -33,7 +33,7 @@ armarx_add_component( # RobotAPI RobotAPICore ## RobotAPIInterfaces - ## RobotAPIComponentPlugins # For ArViz and other plugins. + RobotAPIComponentPlugins # For ArViz and other plugins. # This project ## ${PROJECT_NAME}Interfaces # For ice interfaces from this package. diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp index 6c84b806ffc36dca5a6e981da5d19a2a67f329d2..04fa0b34bf676e53beae6ba6cdaf185598d72447 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp +++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp @@ -39,9 +39,16 @@ namespace armarx switch (runState) { case RunState::scannerInit: - initScanner(); - //read the scanner parameters for initialization - result = scanner->loopOnce(scanData, scanTime, scanInfo, true); + if (initCnt < 5) + { + initCnt++; + initScanner(); + } + else + { + ARMARX_WARNING << "Maximum number of reinitializations reached - going to idle state"; + runState = RunState::scannerFinalize; + } break; case RunState::scannerRun: if (result == sick_scan::ExitSuccess) // OK -> loop again @@ -50,10 +57,10 @@ namespace armarx if (scanTopic) { TimestampVariantPtr scanT(new TimestampVariant(scanTime)); - scanTopic->reportSensorValues(ip, frameName, scanData, scanT); + scanTopic->reportSensorValues(ip, scannerName, scanData, scanT); scanData.clear(); //trigger heartbeat - //heartbeat.heartbeat(channel); + scannerHeartbeat->heartbeat(scannerName); } else { @@ -66,7 +73,8 @@ namespace armarx } break; case RunState::scannerFinalize: - ARMARX_WARNING << "scanner offline"; + ARMARX_WARNING << "Scanner offline - stopping task."; + this->task->stop(); break; default: ARMARX_WARNING << "Invalid run state in task loop"; @@ -77,27 +85,25 @@ namespace armarx void SickLaserScanDevice::initScanner() { - this->isSensorInitialized = false; ARMARX_INFO_S << "Start initialising scanner [Ip: " << this->ip << "] [Port: " << this->port << "]"; // attempt to connect/reconnect - delete this->scanner; // disconnect scanner - if (this->useTcp) + if (this->scanner) { - this->scanner = new SickScanAdapter(this->ip, this->port, this->timelimit, this->parser, 'A'); + ARMARX_WARNING_S << "Scanner already initized."; + this->scanner.reset(); // disconnect scanner } - else + this->scanner = std::make_unique<SickScanAdapter>(this->ip, this->port, this->timelimit, this->parser.get(), 'A'); + this->result = this->scanner->init(); + + if (this->result == sick_scan::ExitSuccess) { - ARMARX_ERROR_S << "TCP is not switched on. Probably hostname or port not set.\n"; - return; + //read the scanner parameters for initialization + this->result = scanner->loopOnce(scanData, scanTime, scanInfo, true); } - result = this->scanner->init(); - - - if (result == sick_scan::ExitSuccess) // OK -> loop again + if (this->result == sick_scan::ExitSuccess) // OK -> loop again { - this->isSensorInitialized = true; - ARMARX_INFO_S << "Scanner initialized."; + ARMARX_INFO_S << "Scanner successfully initialized."; this->runState = RunState::scannerRun; // after initialising switch to run state } else @@ -115,34 +121,35 @@ namespace armarx // Publish to a topic (passing the TopicListenerPrx). // def->topic(myTopicListener); - // Subscribe to a topic (passing the topic name). - def->topic<LaserScannerUnitListenerPrx>(properties.topicName); - // Use (and depend on) another component (passing the ComponentInterfacePrx). // def->component(myComponentProxy) - def->optional(properties.topicName, "topicName", "Name of the topic"); + def->topic(topic, properties.topicName, "TopicName", "Name of the laserscanner topic to report to."); //Scanner parameters def->optional(properties.devices, "devices", "List of Devices in format frame1,ip1,port1;frame2,ip2,port2"); + def->optional(properties.scannerType, "scannerType", "Name of the LaserScanner"); def->optional(properties.timelimit, "timelimit", "timelimit for communication"); - def->required(properties.scannerType, "scannerType", "Name of the LaserScanner"); - def->optional(properties.angleOffset, "angleOffset", "offset to the scanning angle"); def->optional(properties.rangeMin, "rangeMin", "minimum Range of the Scanner"); def->optional(properties.rangeMax, "rangeMax", "maximum Range of the Scanner"); - def->optional(properties.timeIncrement, "timeIncrement", "timeIncrement??"); return def; } + SickLaserUnit::SickLaserUnit() + { + //heartbeat = addPlugin<plugins::HeartbeatComponentPlugin>("SickLaserUnit"); + addPlugin(heartbeat); + ARMARX_CHECK_NOT_NULL(heartbeat); + } + void SickLaserUnit::onInitComponent() { + ARMARX_INFO << "On init"; // Topics and properties defined above are automagically registered. // Keep debug observer data until calling `sendDebugObserverBatch()`. // (Requies the armarx::DebugObserverComponentPluginUser.) // setDebugObserverBatchModeEnabled(true); - ARMARX_INFO_S << "initializing SickLaserUnit."; - std::vector<std::string> splitDeviceStrings = Split(properties.devices, ";"); scanDevices.clear(); scanDevices.reserve(splitDeviceStrings.size()); @@ -152,57 +159,54 @@ namespace armarx if (deviceInfo.size() != 3) { ARMARX_WARNING << "Unexpected format for laser scanner device: " << deviceString - << " (split size: " << deviceInfo.size() << ")"; + << " (split size: " << deviceInfo.size() << ", expected: 3)"; continue; } SickLaserScanDevice& device = scanDevices.emplace_back(); device.scanTopic = topic; - device.isSensorInitialized = false; - device.frameName = deviceInfo[0]; + device.scannerName = deviceInfo[0]; if (deviceInfo[1] != "") { - device.useTcp = true; device.ip = deviceInfo[1]; } + else + { + ARMARX_FATAL << "TCP is not switched on. Probably hostname or port not set."; + return; + + } device.port = deviceInfo[2]; - device.angleOffset = properties.angleOffset; device.timelimit = properties.timelimit; - device.scannerType = properties.scannerType; - device.rangeMin = properties.rangeMin; - device.rangeMax = properties.rangeMax; - device.timeIncrement = properties.timeIncrement; + //scanInfo + device.scanInfo.device = device.ip; + device.scanInfo.frame = device.scannerName; //scanner Parameters try { - device.parser = new sick_scan::SickGenericParser(device.scannerType); + device.parser = std::make_unique<sick_scan::SickGenericParser>(properties.scannerType); device.parser->set_range_min(properties.rangeMin); device.parser->set_range_max(properties.rangeMax); - device.parser->set_time_increment(properties.timeIncrement); + device.parser->getCurrentParamPtr()->setUseBinaryProtocol(false); } catch (std::exception const& e) { ARMARX_ERROR_S << "Could not create parser. Wrong Scanner name."; return; } - device.parser->getCurrentParamPtr()->setUseBinaryProtocol(false); - device.colaDialectId = 'A'; + device.scannerHeartbeat = heartbeat; + device.scannerHeartbeat->configureHeartbeatChannel(device.scannerName, armarx::RobotHealthHeartbeatArgs(100, 200, "No updates available")); } - - //addPlugin(heartbeat); - //configureHeartbeatChannel(); } void SickLaserUnit::onConnectComponent() { - topic = getTopic<LaserScannerUnitListenerPrx>(properties.topicName); - offeringTopic(properties.topicName); - for (SickLaserScanDevice& device : scanDevices) { device.scanTopic = topic; //start the laser scanner if (device.task) { + ARMARX_WARNING << "this should not happen."; device.task->stop(); device.task = nullptr; } @@ -217,23 +221,9 @@ namespace armarx // The data can be viewed in the ObserverView and the LivePlotter. // (Before starting any threads, we don't need to lock mutexes.) { - setDebugObserverDatafield("numBoxes", properties.numBoxes); - setDebugObserverDatafield("boxLayerName", properties.boxLayerName); - sendDebugObserverBatch(); - } - */ - - /* (Requires the armarx::ArVizComponentPluginUser.) - // Draw boxes in ArViz. - // (Before starting any threads, we don't need to lock mutexes.) - drawBoxes(properties, arviz); - */ - - /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) - // Setup the remote GUI. - { - createRemoteGuiTab(); - RemoteGui_startRunningTask(); + setDebugObserverDatafield("numBoxes", properties.numBoxes); + setDebugObserverDatafield("boxLayerName", properties.boxLayerName); + sendDebugObserverBatch(); } */ } @@ -248,99 +238,16 @@ namespace armarx device.task->stop(); device.task = nullptr; } - if (device.scanner) - { - delete device.scanner; - } - if (device.parser) - { - delete device.parser; - } } } - void SickLaserUnit::onExitComponent() {} - - std::string SickLaserUnit::getDefaultName() const - { - return "SickLaserUnit"; - } - - /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) - void SickLaserUnit::createRemoteGuiTab() - { - using namespace armarx::RemoteGui::Client; - - // Setup the widgets. - - tab.boxLayerName.setValue(properties.boxLayerName); - - tab.numBoxes.setValue(properties.numBoxes); - tab.numBoxes.setRange(0, 100); - - tab.drawBoxes.setLabel("Draw Boxes"); - - // Setup the layout. - - GridLayout grid; - int row = 0; - { - grid.add(Label("Box Layer"), {row, 0}).add(tab.boxLayerName, {row, 1}); - ++row; - - grid.add(Label("Num Boxes"), {row, 0}).add(tab.numBoxes, {row, 1}); - ++row; - - grid.add(tab.drawBoxes, {row, 0}, {2, 1}); - ++row; - } - - VBoxLayout root = {grid, VSpacer()}; - RemoteGui_createTab(getName(), root, &tab); - } - - - void SickLaserUnit::RemoteGui_update() - { - if (tab.boxLayerName.hasValueChanged() || tab.numBoxes.hasValueChanged()) - { - std::scoped_lock lock(propertiesMutex); - properties.boxLayerName = tab.boxLayerName.getValue(); - properties.numBoxes = tab.numBoxes.getValue(); - - { - setDebugObserverDatafield("numBoxes", properties.numBoxes); - setDebugObserverDatafield("boxLayerName", properties.boxLayerName); - sendDebugObserverBatch(); - } - } - if (tab.drawBoxes.wasClicked()) + void SickLaserUnit::onExitComponent() { - // Lock shared variables in methods running in seperate threads - // and pass them to functions. This way, the called functions do - // not need to think about locking. - std::scoped_lock lock(propertiesMutex, arvizMutex); - drawBoxes(properties, arviz); } - } - */ - - /* (Requires the armarx::ArVizComponentPluginUser.) - void SickLaserUnit::drawBoxes(const SickLaserUnit::Properties& p, viz::Client& - arviz) - { - // Draw something in ArViz (requires the armarx::ArVizComponentPluginUser. - // See the ArVizExample in RobotAPI for more examples. - viz::Layer layer = arviz.layer(p.boxLayerName); - for (int i = 0; i < p.numBoxes; ++i) + std::string SickLaserUnit::getDefaultName() const { - layer.add(viz::Box("box_" + std::to_string(i)) - .position(Eigen::Vector3f(i * 100, 0, 0)) - .size(20).color(simox::Color::blue())); - } - arviz.commit(layer); + return "SickLaserUnit"; } - */ } // namespace armarx diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h index 69d6385c130969a4d18a6d104f91765ec4d9a876..662260de57aea4188e45bc6052061a9d01d19598 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h +++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h @@ -27,7 +27,8 @@ #include <ArmarXCore/core/Component.h> #include <ArmarXCore/core/services/tasks/RunningTask.h> #include <RobotAPI/interface/units/LaserScannerUnit.h> -// #include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h> +//#include <RobotAPI/interface/components/RobotHealthInterface.h> +#include <RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h> #include <vector> @@ -54,32 +55,24 @@ namespace armarx struct SickLaserScanDevice { - //scanner parameters - std::string scannerType = "sick_tim_5xx"; - double angleOffset = 0.0; - double rangeMin; - double rangeMax; - double timeIncrement; + std::string scannerName = "LaserScannerFront"; //communication parameters std::string ip; std::string port; int timelimit = 5; - bool useTcp = false; - char colaDialectId = 'A'; //data and task pointers IceUtil::Time scanTime; LaserScan scanData; LaserScannerInfo scanInfo; + int initCnt = 0; + int result = sick_scan::ExitError; RunState runState = RunState::scannerFinalize; RunningTask<SickLaserScanDevice>::pointer_type task; - std::string frameName = "LaserScannerFront"; LaserScannerUnitListenerPrx scanTopic; - - sick_scan::SickScanConfig cfg; - sick_scan::SickGenericParser* parser; - SickScanAdapter* scanner; - int result = sick_scan::ExitError; - bool isSensorInitialized = false; + plugins::HeartbeatComponentPlugin* scannerHeartbeat; + //scanner pointers + std::unique_ptr<sick_scan::SickGenericParser> parser; + std::unique_ptr<SickScanAdapter> scanner; void initScanner(); void run(); @@ -98,13 +91,14 @@ namespace armarx class SickLaserUnit : //virtual public armarx::LaserScannerUnitInterface, virtual public armarx::Component - // , virtual public armarx::DebugObserverComponentPluginUser + // , virtual public armarx::RobotHealthComponentUser // , virtual public armarx::LightweightRemoteGuiComponentPluginUser // , virtual public armarx::ArVizComponentPluginUser { public: /// @see armarx::ManagedIceObject::getDefaultName() std::string getDefaultName() const override; + SickLaserUnit(); protected: /// @see PropertyUser::createPropertyDefinitions() @@ -134,39 +128,15 @@ namespace armarx std::string topicName = "SICKLaserScanner"; //scanner parameters std::string devices = "LaserScannerFront,192.168.8.133,2112"; - int timelimit = 5; std::string scannerType = "sick_tim_5xx"; - double angleOffset = 0.0; + int timelimit = 5; double rangeMin = 0.0; double rangeMax = 10.0; - double timeIncrement = 0.1; }; Properties properties; std::vector<SickLaserScanDevice> scanDevices; LaserScannerUnitListenerPrx topic; - //HeartbeatComponentPlugin heartbeat; + plugins::HeartbeatComponentPlugin* heartbeat; - /* Use a mutex if you access variables from different threads - * (e.g. ice functions and RemoteGui_update()). - std::mutex propertiesMutex; - */ - - /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) - /// Tab shown in the Remote GUI. - struct RemoteGuiTab : armarx::RemoteGui::Client::Tab - { - armarx::RemoteGui::Client::LineEdit boxLayerName; - armarx::RemoteGui::Client::IntSpinBox numBoxes; - - armarx::RemoteGui::Client::Button drawBoxes; - }; - RemoteGuiTab tab; - */ - - /* (Requires the armarx::ArVizComponentPluginUser.) - * When used from different threads, an ArViz client needs to be synchronized. - /// Protects the arviz client inherited from the ArViz plugin. - std::mutex arvizMutex; - */ }; } // namespace armarx diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.cpp b/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.cpp index 1e9a011f3b044f6dbab583c5769d8c142fcf9a7c..715265cb484cabb48629d08b770ece7171a567d6 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.cpp +++ b/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.cpp @@ -84,8 +84,8 @@ #define deg2rad_const (0.017453292519943295769236907684886f) -std::vector<unsigned char> exampleData(65536); -std::vector<unsigned char> receivedData(65536); +//std::vector<unsigned char> exampleData(65536); +//std::vector<unsigned char> receivedData(65536); //static long receivedDataLen = 0; static int getDiagnosticErrorCode() @@ -106,12 +106,10 @@ namespace armarx sick_scan::SickScanCommon(parser), socket_(io_service_), deadline_(io_service_), - parser_ptr(parser), hostname_(hostname), port_(port), timelimit_(timelimit) { - if ((cola_dialect_id == 'a') || (cola_dialect_id == 'A')) { this->setProtocolType(CoLa_A); @@ -121,7 +119,7 @@ namespace armarx { this->setProtocolType(CoLa_B); } - assert(this->getProtocolType() != CoLa_Unknown); + ARMARX_CHECK(this->getProtocolType() != CoLa_Unknown); m_numberOfBytesInReceiveBuffer = 0; m_alreadyReceivedBytes = 0; @@ -137,7 +135,7 @@ namespace armarx SickScanAdapter::~SickScanAdapter() { - // stop_scanner(); + //stopScanData(); close_device(); } @@ -147,7 +145,7 @@ namespace armarx /*! - \brief parsing datagram and publishing ros messages + \brief parsing datagram into ARMARX message \return error code */ int SickScanAdapter::loopOnce(LaserScan& scanData, IceUtil::Time& scanTime, LaserScannerInfo& scanInfo, bool updateScannerInfo) @@ -157,6 +155,7 @@ namespace armarx int packetsInLoop = 0; ros::Time recvTimeStamp = ros::Time::now(); // timestamp incoming package, will be overwritten by get_datagram + //use ASCII always int result = get_datagram(recvTimeStamp, receiveBuffer, 65536, &actual_length, false, &packetsInLoop); //ros::Duration dur = recvTimeStampPush - recvTimeStamp; if (result != 0) @@ -169,12 +168,10 @@ namespace armarx return sick_scan::ExitSuccess; } // return success to continue looping - //TODO: convert ros::Time recvTimeStamp to IceUtil + //convert ros::Time recvTimeStamp to IceUtil ros::Time correctedStamp = recvTimeStamp + ros::Duration(config_.time_offset); uint64_t recvMsec = correctedStamp.toNSec() / 1000; - scanTime = IceUtil::Time::milliSeconds(recvMsec); - //scanTime = TimeUtil::GetTime(); - //msg.header.stamp = recvTimeStamp + ros::Duration(config_.time_offset); + scanTime = IceUtil::Time::microSeconds(recvMsec); //datagrams are enclosed in <STX> (0x02), <ETX> (0x03) pairs char* buffer_pos = (char*) receiveBuffer; @@ -347,6 +344,7 @@ namespace armarx // 23: Starting angle (FFF92230) if (updateScannerInfo) { + scanInfo.device = hostname_; uint starting_angle = (uint) - 1; sscanf(fields[23], "%x", &starting_angle); scanInfo.minAngle = (starting_angle / 10000.0) / 180.0 * M_PI - M_PI / 2; @@ -438,7 +436,6 @@ namespace armarx ARMARX_ERROR_S << "Number of distance measurements does not match number of intensity values - Skipping"; return sick_scan::ExitError; } - //TODO: Write ScanSteps with intensity scanData.reserve(distVal.size()); for (int i = 0; i < (int) distVal.size(); i++) { @@ -461,7 +458,6 @@ namespace armarx void SickScanAdapter::disconnectFunction() { - } void SickScanAdapter::disconnectFunctionS(void* obj) diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.h b/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.h index 5b7e772f33217ed39e9c708275c6f7e5d10b2251..1707952d9583de18bd6de004f986e216e9c13781 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.h +++ b/source/RobotAPI/drivers/SickLaserUnit/SickScanAdapter.h @@ -72,10 +72,6 @@ namespace armarx class SickScanAdapter : public sick_scan::SickScanCommon { public: - int loopOnce(LaserScan& scanData, IceUtil::Time& scanTime, LaserScannerInfo& scanInfo, bool updateScannerInfo = false); - - int parseDatagram(char* datagram, size_t datagram_length, LaserScan& scanData, LaserScannerInfo& scanInfo, bool updateScannerInfo = false); - static void disconnectFunctionS(void* obj); SickScanAdapter(const std::string& hostname, const std::string& port, int& timelimit, sick_scan::SickGenericParser* parser, @@ -83,6 +79,10 @@ namespace armarx virtual ~SickScanAdapter(); + int loopOnce(LaserScan& scanData, IceUtil::Time& scanTime, LaserScannerInfo& scanInfo, bool updateScannerInfo = false); + + int parseDatagram(char* datagram, size_t datagram_length, LaserScan& scanData, LaserScannerInfo& scanInfo, bool updateScannerInfo = false); + static void readCallbackFunctionS(void* obj, UINT8* buffer, UINT32& numOfBytes); void readCallbackFunction(UINT8* buffer, UINT32& numOfBytes); @@ -163,7 +163,6 @@ namespace armarx boost::system::error_code ec_; size_t bytes_transfered_; - sick_scan::SickGenericParser* parser_ptr; std::string hostname_; std::string port_; int timelimit_; diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp index 4f7372a5e178ed8ec895049ef094af354d297ee2..e210b778f25dd9ce8f83bfd299ff3ec4c75497e2 100644 --- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp @@ -810,30 +810,34 @@ namespace armarx void ArVizWidgetController::onReplayTimerTick() { - if (mode != ArVizWidgetMode::ReplayingTimed) + if (mode == ArVizWidgetMode::ReplayingTimed) { - return; - } - double replaySpeed = widget.replaySpeedSpinBox->value(); + double replaySpeed = widget.replaySpeedSpinBox->value(); - replayCurrentTimestamp += 33000 * replaySpeed; + long currentRealTime = IceUtil::Time::now().toMicroSeconds(); + long elapsedRealTime = currentRealTime - lastReplayRealTime; - long revision = getRevisionForTimestamp(replayCurrentTimestamp); - if (revision == -2) - { - if (widget.replayLoopbackCheckBox->checkState() == Qt::Checked) + replayCurrentTimestamp += elapsedRealTime * replaySpeed; + + long revision = getRevisionForTimestamp(replayCurrentTimestamp); + if (revision == -2) { - replayCurrentTimestamp = currentRecording.firstTimestampInMicroSeconds; + if (widget.replayLoopbackCheckBox->checkState() == Qt::Checked) + { + replayCurrentTimestamp = currentRecording.firstTimestampInMicroSeconds; + } + else + { + revision = currentRecording.lastRevision; + } } - else + if (revision >= 0) { - revision = currentRecording.lastRevision; + widget.replayRevisionSlider->setValue(revision); } } - if (revision >= 0) - { - widget.replayRevisionSlider->setValue(revision); - } + + lastReplayRealTime = IceUtil::Time::now().toMicroSeconds(); } void ArVizWidgetController::changeMode(ArVizWidgetMode newMode) @@ -917,10 +921,16 @@ namespace armarx auto& entry = recordingBatchCache[batch.header.index]; entry.data = batch; entry.lastUsed = IceUtil::Time::now(); + + limitRecordingBatchCacheSize(); + + recordingWaitingForBatchIndex = -1; } viz::data::RecordingBatch const& ArVizWidgetController::getRecordingBatch(long index) { + ARMARX_TRACE; + IceUtil::Time now = IceUtil::Time::now(); std::unique_lock<std::mutex> lock(recordingBatchCacheMutex); @@ -930,16 +940,23 @@ namespace armarx { // Start prefetching neighbouring batches bool asyncPrefetchIsRunning = callbackResult && !callbackResult->isCompleted(); - if (!asyncPrefetchIsRunning) + if (!asyncPrefetchIsRunning && recordingWaitingForBatchIndex == -1) { if (index + 1 < long(currentRecording.batchHeaders.size()) && recordingBatchCache.count(index + 1) == 0) { + // ARMARX_WARNING << "after begin_getRecordingBatch: " << (index + 1) + // << " waiting for " << recordingWaitingForBatchIndex; callbackResult = storage->begin_getRecordingBatch(currentRecording.id, index + 1, callback); + recordingWaitingForBatchIndex = index + 1; + ARMARX_INFO << "Now waiting for " << recordingWaitingForBatchIndex; } else if (index > 0 && recordingBatchCache.count(index - 1) == 0) { + // ARMARX_WARNING << "before begin_getRecordingBatch: " << (index - 1) + // << " waiting for " << recordingWaitingForBatchIndex; callbackResult = storage->begin_getRecordingBatch(currentRecording.id, index - 1, callback); + recordingWaitingForBatchIndex = index - 1; } } @@ -949,6 +966,19 @@ namespace armarx return entry.data; } + // Maybe there has already been sent a asynchronous request to get + if (index == recordingWaitingForBatchIndex) + { + lock.unlock(); + ARMARX_INFO << "Waiting to receive async batch: " << index; + // Wait until request completes + while (recordingWaitingForBatchIndex != -1) + { + QCoreApplication::processEvents(); + } + return getRecordingBatch(index); + } + ARMARX_INFO << "Batch #" << index << " is not in the cache. Getting synchronously, blocking GUI..."; // Entry is not in the cache, we have to get it from ArVizStorage @@ -956,6 +986,13 @@ namespace armarx newEntry.lastUsed = now; newEntry.data = storage->getRecordingBatch(currentRecording.id, index); + limitRecordingBatchCacheSize(); + + return newEntry.data; + } + + void ArVizWidgetController::limitRecordingBatchCacheSize() + { if (recordingBatchCache.size() > recordingBatchCacheMaxSize) { // Remove the entry with the oldest last used timestamp @@ -972,8 +1009,6 @@ namespace armarx recordingBatchCache.erase(oldestIter); } - - return newEntry.data; } SoNode* ArVizWidgetController::getScene() diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h index 31383a63ea78c510ec781951ff56b5fdbcafee06..4a493dbd19a4c4cab6e05aa2a7ab5376936a3ebe 100644 --- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h +++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h @@ -182,6 +182,7 @@ namespace armarx QTimer* replayTimer; long replayCurrentTimestamp = 0; + long lastReplayRealTime = 0; std::string storageName; armarx::viz::StorageInterfacePrx storage; @@ -207,9 +208,11 @@ namespace armarx }; viz::data::RecordingBatch const& getRecordingBatch(long index); + void limitRecordingBatchCacheSize(); std::size_t recordingBatchCacheMaxSize = 5; std::mutex recordingBatchCacheMutex; + std::atomic<long> recordingWaitingForBatchIndex = -1; std::map<long, TimestampedRecordingBatch> recordingBatchCache; ArVizWidgetMode mode = ArVizWidgetMode::NotConnected; diff --git a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp index dffe7711debc728d596f5ecd7cd851df2527e120..adb7c77bd1e04491b7e16ecb1599119df0ee2ce6 100644 --- a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp @@ -201,7 +201,7 @@ namespace armarx { bool expand = item->childCount() == 0; - TreeWidgetBuilder builder(objectPoses); + TreeWidgetBuilder<objpose::ObjectPose> builder; builder.setNameFn([](const objpose::ObjectPose & pose) { return pose.objectID.str(); @@ -245,7 +245,7 @@ namespace armarx return true; }); - builder.updateTree(item, objectPoses); + builder.updateTreeWithContainer(item, objectPoses); if (expand) { @@ -299,7 +299,7 @@ namespace armarx { (void) dataset; - TreeWidgetBuilder builder(datasetData); + TreeWidgetBuilder<std::pair<std::string, std::string>> builder; builder.setCompareFn([](const std::pair<std::string, std::string>& lhs, QTreeWidgetItem * item) { auto rhs = std::make_pair(item->text(0).toStdString(), item->text(1).toStdString()); @@ -324,7 +324,7 @@ namespace armarx } return true; }); - builder.updateTree(datasetItem, datasetData); + builder.updateTreeWithContainer(datasetItem, datasetData); return true; }); diff --git a/source/RobotAPI/interface/armem/query.ice b/source/RobotAPI/interface/armem/query.ice index 2a1586fece346e89cbe491cd21c026ddab603e0e..936294507f0b05627051fa6974309faa1db4d758 100644 --- a/source/RobotAPI/interface/armem/query.ice +++ b/source/RobotAPI/interface/armem/query.ice @@ -14,8 +14,7 @@ module armarx enum QueryTarget { WM, - LTM, - Disk + LTM }; sequence<QueryTarget> QueryTargets; diff --git a/source/RobotAPI/interface/objectpose/ObjectPoseStorageInterface.ice b/source/RobotAPI/interface/objectpose/ObjectPoseStorageInterface.ice index 3097f6c7596fd3fdf82aedd9d974712081cf503c..1dfe8b9f299d24684a0acdd3d6f53ed61063d397 100644 --- a/source/RobotAPI/interface/objectpose/ObjectPoseStorageInterface.ice +++ b/source/RobotAPI/interface/objectpose/ObjectPoseStorageInterface.ice @@ -81,7 +81,7 @@ module armarx }; struct AttachObjectToRobotNodeOutput { - bool success; + bool success = false; data::ObjectAttachmentInfo attachment; }; @@ -99,7 +99,7 @@ module armarx struct DetachObjectFromRobotNodeOutput { /// Whether the object was attached before. - bool wasAttached; + bool wasAttached = false; }; struct DetachAllObjectsFromRobotNodesInput @@ -113,7 +113,7 @@ module armarx struct DetachAllObjectsFromRobotNodesOutput { /// Number of objects that have been detached. - int numDetached; + int numDetached = 0; }; struct AgentFrames diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice index b00a86caf56aec6a6e3f6c59e734ded8aea893b8..84614f0d5d98bb23fc63a14bc4c0a237189b2779 100644 --- a/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice +++ b/source/RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.ice @@ -306,6 +306,7 @@ module armarx double phaseDist1 = 10; double posToOriRatio = 100; + Ice::FloatSeq Kpos; Ice::FloatSeq Dpos; Ice::FloatSeq Kori; @@ -319,6 +320,13 @@ module armarx float torqueLimit; + + string forceSensorName; + float waitTimeForCalibration; + float forceFilter; + float forceDeadZone; + Eigen::Vector3f forceThreshold; + string forceFrameName = "ArmR8_Wri2"; }; interface NJointTaskSpaceImpedanceDMPControllerInterface extends NJointControllerInterface @@ -328,6 +336,7 @@ module armarx void setUseNullSpaceJointDMP(bool enable); bool isFinished(); + bool isDMPRunning(); void runDMP(Ice::DoubleSeq goals); void runDMPWithTime(Ice::DoubleSeq goals, double timeDuration); @@ -352,6 +361,9 @@ module armarx void setNullspaceVelocityKd(Eigen::VectorXf jointValues); void setNullspaceVelocityKp(Eigen::VectorXf jointValues); + void enableForceStop(); + void disableForceStop(); + void setForceThreshold(Eigen::Vector3f forceThreshold); }; class NJointTaskSpaceAdaptiveDMPControllerConfig extends NJointControllerConfig diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt b/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt index a4ca9b08ad6d3b0937294c5a9050adb6680abfcc..594e05ed14002d7098c2ecaa41a5d627e3f9ea24 100644 --- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt +++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/CMakeLists.txt @@ -25,6 +25,7 @@ set(LIB_FILES NaturalIKComponentPlugin.cpp HandUnitComponentPlugin.cpp FrameTrackingComponentPlugin.cpp + HeartbeatComponentPlugin.cpp ) set(LIB_HEADERS RobotStateComponentPlugin.h @@ -40,6 +41,7 @@ set(LIB_HEADERS NaturalIKComponentPlugin.h HandUnitComponentPlugin.h FrameTrackingComponentPlugin.h + HeartbeatComponentPlugin.h ) armarx_add_library("${LIB_NAME}" "${LIB_FILES}" "${LIB_HEADERS}" "${LIBS}") diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.cpp b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..510ff8933b6e045ec96e1020e6914f2b064636f2 --- /dev/null +++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.cpp @@ -0,0 +1,98 @@ +#include "HeartbeatComponentPlugin.h" + +#include "ArmarXCore/core/Component.h" +#include "ArmarXCore/core/exceptions/local/ExpressionException.h" + +#include <RobotAPI/interface/components/RobotHealthInterface.h> + +namespace armarx::plugins +{ + void + HeartbeatComponentPlugin::configureHeartbeatChannel(const std::string& channel, + const RobotHealthHeartbeatArgs& args) + { + channelHeartbeatConfig.emplace(channel, args); + } + + void + HeartbeatComponentPlugin::heartbeat() + { + + if (robotHealthTopic) + { + robotHealthTopic->heartbeat(componentName, heartbeatArgs); + } + else + { + ARMARX_WARNING << "No robot health topic available!"; + } + } + + void + HeartbeatComponentPlugin::heartbeat(const std::string& channel) + { + const auto argsIt = channelHeartbeatConfig.find(channel); + ARMARX_CHECK(argsIt != channelHeartbeatConfig.end()) + << "heartbeat() called for unknown channel '" << channel << "'." + << "You must register the config using configureHeartbeatChannel(channel) first!"; + + const auto& args = argsIt->second; + + if (robotHealthTopic) + { + robotHealthTopic->heartbeat(componentName + "_" + channel, args); + } + else + { + ARMARX_WARNING << "No robot health topic available!"; + } + } + + void + HeartbeatComponentPlugin::preOnInitComponent() + { + if (topicName.empty()) + { + parent<Component>().getProperty(topicName, makePropertyName(topicPropertyName)); + } + parent<Component>().offeringTopic(topicName); + } + + void + HeartbeatComponentPlugin::postOnInitComponent() + { + } + + void + HeartbeatComponentPlugin::preOnConnectComponent() + { + robotHealthTopic = parent<Component>().getTopic<RobotHealthInterfacePrx>(topicName); + } + + void + HeartbeatComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) + { + if (!properties->hasDefinition(makePropertyName(topicPropertyName))) + { + properties->defineOptionalProperty<std::string>( + makePropertyName(topicPropertyName), + "DebugObserver", + "Name of the topic the DebugObserver listens on"); + } + + if (not properties->hasDefinition(makePropertyName(maximumCycleTimeWarningMSPropertyName))) + { + properties->defineRequiredProperty<std::string>( + makePropertyName(maximumCycleTimeWarningMSPropertyName), + "TODO: maximumCycleTimeWarningMS"); + } + + if (not properties->hasDefinition(makePropertyName(maximumCycleTimeErrorMSPropertyName))) + { + properties->defineRequiredProperty<std::string>( + makePropertyName(maximumCycleTimeErrorMSPropertyName), + "TODO: maximumCycleTimeErrorMS"); + } + } + +} // namespace armarx::plugins diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h new file mode 100644 index 0000000000000000000000000000000000000000..6a4a6c2bd692484c94bbd42bdfff399b0f5a0aa9 --- /dev/null +++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h @@ -0,0 +1,89 @@ +/** + * 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 Fabian Reister ( fabian dot reister at kit dot edu ) + * @date 2021 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <ArmarXCore/core/ComponentPlugin.h> + +#include <RobotAPI/interface/components/RobotHealthInterface.h> + +namespace armarx::plugins +{ + + class HeartbeatComponentPlugin : public ComponentPlugin + { + public: + using ComponentPlugin::ComponentPlugin; + + /** + * @brief Configures a heartbeat subchannel. + * + * @param channel Identifier of the heartbeat channel + * @param args Configuration of this channel's heartbeat properties + */ + void configureHeartbeatChannel(const std::string& channel, + const RobotHealthHeartbeatArgs& args); + + /** + * @brief Sends out a heartbeat using the default config + * + */ + void heartbeat(); + + /** + * @brief Sends out a heartbeat for a subchannel. + * + * Note: You must call configureHeartbeatChannel(...) first to register the channel config! + * + * @param channel Identifier of the heartbeat channel + */ + void heartbeat(const std::string& channel); + + protected: + void preOnInitComponent() override; + void postOnInitComponent() override; + void preOnConnectComponent() override; + + void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override; + + private: + //! heartbeat topic name (outgoing) + std::string topicName; + + //! name of this component used as identifier for heartbeats + std::string componentName; + + // + static constexpr auto topicPropertyName = "heartbeat.TopicName"; + static constexpr auto maximumCycleTimeWarningMSPropertyName = + "heartbeat.maximumCycleTimeWarningMS"; + static constexpr auto maximumCycleTimeErrorMSPropertyName = + "heartbeat.maximumCycleTimeErrorMS"; + + RobotHealthInterfacePrx robotHealthTopic; + + //! default config used in heartbeat(), set via properties + RobotHealthHeartbeatArgs heartbeatArgs; + + //! configs used in heartbeat(channel), set by user via configureHeartbeatChannel(...) + std::unordered_map<std::string, RobotHealthHeartbeatArgs> channelHeartbeatConfig; + }; +} // namespace armarx::plugins diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp index 4e6e7966cc4c71e819da47cd9a7ee06ccd536775..6647cf38585cb868a3df29e9c328bbfe8ac3a677 100644 --- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp +++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.cpp @@ -116,6 +116,19 @@ namespace armarx::plugins } + void RobotUnitComponentPlugin::waitUntilRobotUnitIsRunning(const std::function<bool ()>& termCond) const + { + ARMARX_INFO << "Waiting until robot unit is running ..."; + + while (not(termCond() or not isNullptr(getRobotUnit()) or getRobotUnit()->isRunning())) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + ARMARX_INFO << "Robot unit is up and running."; + } + + } // namespace armarx::plugins diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h index 80357a96e9a3bb6c889d7b73435baef90a385b54..4371934b97182947afbaad3d60fd5295a717615a 100644 --- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h +++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h @@ -34,6 +34,19 @@ namespace armarx } + /** + * @brief Waits until the robot unit is running. + * + * Although the robot unit proxy might be initialized (\see getRobotUnit()), the robot unit might + * not be fully initialized. + * + * @param termCond Termination condition. + * If it evaluates to true, waitUntilRobotUnitIsRunning returns without waiting + * for the robot unit to become available. + */ + void waitUntilRobotUnitIsRunning(const std::function<bool()>& termCond = [] {return false;}) const; + + //controllers public: diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp index 79a090adbae49e70b400ca3cd358b0599a11c9f1..e8a401f485b38a2c85f4a9a718f94d8a1d0a905a 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.cpp @@ -472,6 +472,7 @@ namespace armarx debugRT.getWriteBuffer().targetVel = targetVel; debugRT.getWriteBuffer().adaptK = adaptK; debugRT.getWriteBuffer().isPhaseStop = isPhaseStop; + debugRT.getWriteBuffer().currentTwist = currentTwist; rt2CtrlData.getWriteBuffer().currentPose = currentPose; rt2CtrlData.getWriteBuffer().currentTwist = currentTwist; @@ -673,6 +674,11 @@ namespace armarx datafields["targetVel_y"] = new Variant(targetVel(1)); datafields["targetVel_z"] = new Variant(targetVel(2)); + Eigen::VectorXf currentVel = debugRT.getUpToDateReadBuffer().currentTwist; + datafields["currentVel_x"] = new Variant(currentVel(0)); + datafields["currentVel_y"] = new Variant(currentVel(1)); + datafields["currentVel_z"] = new Variant(currentVel(2)); + Eigen::Vector3f adaptK = debugRT.getUpToDateReadBuffer().adaptK; datafields["adaptK_x"] = new Variant(adaptK(0)); datafields["adaptK_y"] = new Variant(adaptK(1)); diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.h index ebb3b05a5241c338cbdfc73ebd30ef3226d7219d..477feb6900efcdaca0981deb92534cc5dfb0c172 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.h +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointPeriodicTSDMPCompliantController.h @@ -99,6 +99,7 @@ namespace armarx Eigen::Vector3f adaptK; Eigen::VectorXf targetVel; Eigen::Matrix4f currentPose; + Eigen::VectorXf currentTwist; bool isPhaseStop; float manidist; }; diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.cpp b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.cpp index 1c573254359a77ed99e2365a48d9e1c71c67167e..0a08c5396283856d5e5ccc5e8ebfdbb9cb59500c 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.cpp +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.cpp @@ -11,12 +11,14 @@ namespace armarx const armarx::NJointControllerConfigPtr& config, const VirtualRobot::RobotPtr&) { + ARMARX_TRACE; ARMARX_INFO << "creating impedance dmp controller"; cfg = NJointTaskSpaceImpedanceDMPControllerConfigPtr::dynamicCast(config); + ARMARX_CHECK_NOT_NULL(cfg); useSynchronizedRtRobot(); rns = rtGetRobot()->getRobotNodeSet(cfg->nodeSetName); ARMARX_CHECK_EXPRESSION(rns) << cfg->nodeSetName; - + ARMARX_INFO << "1"; for (size_t i = 0; i < rns->getSize(); ++i) { std::string jointName = rns->getNode(i)->getName(); @@ -39,11 +41,20 @@ namespace armarx velocitySensors.push_back(velocitySensor); positionSensors.push_back(positionSensor); }; - + const SensorValueBase* svlf = robotUnit->getSensorDevice(cfg->forceSensorName)->getSensorValue(); + forceSensor = svlf->asA<SensorValueForceTorque>(); + + ARMARX_TRACE; + forceOffset.setZero(); + filteredForce.setZero(); + filteredForceInRoot.setZero(); + ARMARX_INFO << cfg->forceThreshold; + forceThreshold.reinitAllBuffers(cfg->forceThreshold); tcp = rns->getTCP(); ik.reset(new VirtualRobot::DifferentialIK(rns, rtGetRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped)); ik->setDampedSvdLambda(0.0001); + ARMARX_TRACE; numOfJoints = targets.size(); // set DMP TaskSpaceDMPControllerConfig taskSpaceDMPConfig; @@ -80,6 +91,7 @@ namespace armarx } defaultNullSpaceJointValues.reinitAllBuffers(nullspaceValues); + ARMARX_TRACE; Eigen::Vector3f kpos(cfg->Kpos[0], cfg->Kpos[1], cfg->Kpos[2]); Eigen::Vector3f dpos(cfg->Dpos[0], cfg->Dpos[1], cfg->Dpos[2]); Eigen::Vector3f kori(cfg->Kori[0], cfg->Kori[1], cfg->Kori[2]); @@ -114,6 +126,7 @@ namespace armarx controllerSensorData.reinitAllBuffers(initControllerSensorData); firstRun = true; + useForceStop = false; ARMARX_INFO << "Finished controller constructor "; } @@ -127,6 +140,7 @@ namespace armarx void NJointTaskSpaceImpedanceDMPController::rtPreActivateController() { + ARMARX_TRACE; NJointTaskSpaceImpedanceDMPControllerControlData initData; initData.targetPose = tcp->getPoseInRootFrame(); initData.targetVel.resize(6); @@ -140,8 +154,6 @@ namespace armarx void NJointTaskSpaceImpedanceDMPController::controllerRun() { - - if (!dmpCtrl) { return; @@ -234,7 +246,72 @@ namespace armarx void NJointTaskSpaceImpedanceDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) { + + Eigen::Matrix4f currentPose = tcp->getPoseInRootFrame(); + double deltaT = timeSinceLastIteration.toSecondsDouble(); + Eigen::Matrix4f targetPose; + Eigen::VectorXf targetVel; + Eigen::VectorXf desiredNullSpaceJointValues; + if (firstRun) + { + firstRun = false; + targetPose = currentPose; + stopPose = currentPose; + targetVel.setZero(6); + desiredNullSpaceJointValues = defaultNullSpaceJointValues.getUpToDateReadBuffer(); + } + else + { + if (!started) + { + targetPose = stopPose; + targetVel.setZero(6); + desiredNullSpaceJointValues = defaultNullSpaceJointValues.getUpToDateReadBuffer(); + forceOffset = (1 - cfg->forceFilter) * forceOffset + cfg->forceFilter * forceSensor->force; + timeForCalibration = timeForCalibration + timeSinceLastIteration.toSecondsDouble(); + } + else + { + targetPose = rtGetControlStruct().targetPose; + targetVel = rtGetControlStruct().targetVel; + desiredNullSpaceJointValues = rtGetControlStruct().desiredNullSpaceJointValues; + + if (useForceStop) + { + /* handle force stop */ + filteredForce = (1 - cfg->forceFilter) * filteredForce + cfg->forceFilter * (forceSensor->force - forceOffset); + + for (size_t i = 0; i < 3; ++i) + { + if (fabs(filteredForce(i)) > cfg->forceDeadZone) + { + filteredForce(i) -= (filteredForce(i) / fabs(filteredForce(i))) * cfg->forceDeadZone; + } + else + { + filteredForce(i) = 0; + } + } + Eigen::Matrix4f forceFrameInRoot = rtGetRobot()->getRobotNode(cfg->forceFrameName)->getPoseInRootFrame(); + filteredForceInRoot = forceFrameInRoot.block<3, 3>(0, 0) * filteredForce; + + for (size_t i = 0; i < 3; ++i) + { + if (fabs(filteredForceInRoot[i]) > forceThreshold.getUpToDateReadBuffer()[i]) + { + stopPose = currentPose; + targetVel.setZero(6); + desiredNullSpaceJointValues = defaultNullSpaceJointValues.getUpToDateReadBuffer(); + started = false; + break; + } + } + } + + } + } + Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All); @@ -247,7 +324,6 @@ namespace armarx qvel(i) = velocitySensors[i]->velocity; } - Eigen::Matrix4f currentPose = tcp->getPoseInRootFrame(); Eigen::VectorXf currentTwist = jacobi * qvel; controllerSensorData.getWriteBuffer().currentPose = currentPose; @@ -261,24 +337,6 @@ namespace armarx jacobi.block(0, 0, 3, numOfJoints) = 0.001 * jacobi.block(0, 0, 3, numOfJoints); // convert mm to m - - Eigen::Matrix4f targetPose; - Eigen::VectorXf targetVel; - Eigen::VectorXf desiredNullSpaceJointValues; - if (firstRun) - { - firstRun = false; - targetPose = currentPose; - targetVel.setZero(6); - desiredNullSpaceJointValues = defaultNullSpaceJointValues.getUpToDateReadBuffer(); - } - else - { - targetPose = rtGetControlStruct().targetPose; - targetVel = rtGetControlStruct().targetVel; - desiredNullSpaceJointValues = rtGetControlStruct().desiredNullSpaceJointValues; - } - Eigen::Vector3f kpos = ctrlParams.getUpToDateReadBuffer().kpos; Eigen::Vector3f dpos = ctrlParams.getUpToDateReadBuffer().dpos; Eigen::Vector3f kori = ctrlParams.getUpToDateReadBuffer().kori; @@ -315,9 +373,6 @@ namespace armarx jacobi.transpose() * jointControlWrench + (I - jacobi.transpose() * jtpinv) * nullspaceTorque; - - - // torque limit ARMARX_CHECK_EXPRESSION(!targets.empty()); ARMARX_CHECK_LESS(targets.size(), 1000); @@ -487,34 +542,24 @@ namespace armarx void NJointTaskSpaceImpedanceDMPController::runDMPWithTime(const Ice::DoubleSeq& goals, Ice::Double timeDuration, const Ice::Current&) { - firstRun = true; - while (firstRun) - { - usleep(100); - } - - Eigen::Matrix4f pose = interfaceData.getUpToDateReadBuffer().currentTcpPose; - dmpCtrl->prepareExecution(dmpCtrl->eigen4f2vec(pose), goals); - dmpCtrl->canVal = timeDuration; dmpCtrl->config.motionTimeDuration = timeDuration; - finished = false; - - if (isNullSpaceJointDMPLearned && useNullSpaceJointDMP) - { - ARMARX_INFO << "Using Null Space Joint DMP"; - } - - started = true; - stopped = false; - // controllerTask->start(); + runDMP(goals); } void NJointTaskSpaceImpedanceDMPController::runDMP(const Ice::DoubleSeq& goals, const Ice::Current&) { firstRun = true; - while (firstRun) + timeForCalibration = 0; + started = false; + + while (firstRun || timeForCalibration < cfg->waitTimeForCalibration) + { + usleep(100); + } + + while (!interfaceData.updateReadBuffer()) { usleep(100); } diff --git a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.h b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.h index 9ded363e9e110bf803ada28b5523057b69b3bd4f..58fd840fb1121b4a159c185abb2e72fd7470f082 100644 --- a/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.h +++ b/source/RobotAPI/libraries/RobotAPINJointControllers/DMPController/NJointTaskSpaceImpedanceDMPController.h @@ -6,6 +6,7 @@ #include <RobotAPI/components/units/RobotUnit/RobotUnit.h> #include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h> #include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h> +#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h> #include <VirtualRobot/IK/DifferentialIK.h> #include <RobotAPI/interface/units/RobotUnit/NJointTaskSpaceDMPController.h> #include <RobotAPI/libraries/DMPController/TaskSpaceDMPController.h> @@ -55,11 +56,16 @@ namespace armarx return finished; } + bool isDMPRunning(const Ice::Current&) override + { + return started; + } + void setViaPoints(Ice::Double u, const Ice::DoubleSeq& viapoint, const Ice::Current&) override; void setGoals(const Ice::DoubleSeq& goals, const Ice::Current&) override; void learnJointDMPFromFiles(const std::string& fileName, const Ice::FloatSeq& currentJVS, const Ice::Current&) override; - void runDMP(const Ice::DoubleSeq& goals, const Ice::Current&) override; + void runDMP(const Ice::DoubleSeq& goals, const Ice::Current& iceCurrent = Ice::emptyCurrent) override; void runDMPWithTime(const Ice::DoubleSeq& goals, Ice::Double timeDuration, const Ice::Current&) override; Ice::Double getVirtualTime(const Ice::Current&) override @@ -85,7 +91,20 @@ namespace armarx void setUseNullSpaceJointDMP(bool enable, const Ice::Current&) override; void setDefaultNullSpaceJointValues(const Eigen::VectorXf& jointValues, const Ice::Current&) override; + void enableForceStop(const Ice::Current&) override + { + useForceStop = true; + } + void disableForceStop(const Ice::Current&) override + { + useForceStop = false; + } + void setForceThreshold(const Eigen::Vector3f& f, const Ice::Current& current) override + { + forceThreshold.getWriteBuffer() = f; + forceThreshold.commitWrite(); + } protected: virtual void onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx&) override; @@ -180,6 +199,7 @@ namespace armarx WriteBufferedTripleBuffer<CtrlParams> ctrlParams; + DMP::Vec<DMP::DMPState> currentJointState; DMP::UMIDMPPtr nullSpaceJointDMPPtr; @@ -230,6 +250,16 @@ namespace armarx bool started = false; bool stopped = false; + Eigen::Matrix4f stopPose; + + Eigen::Vector3f filteredForce; + Eigen::Vector3f forceOffset; + Eigen::Vector3f filteredForceInRoot; + WriteBufferedTripleBuffer<Eigen::Vector3f> forceThreshold; + std::atomic<bool> useForceStop; + std::atomic<float> timeForCalibration; + const SensorValueForceTorque* forceSensor; + Eigen::Matrix4f oldPose; // NJointController interface protected: diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index eb53706cb8836fc40891372811738240b3522aa0..b08141a6ef60148532ce3f1097eafacb6ae384b9 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -25,38 +25,34 @@ set(LIB_FILES core/Commit.cpp core/MemoryID.cpp core/MemoryID_operators.cpp + core/operations.cpp core/SuccessHeader.cpp core/Time.cpp - core/ice_conversions.cpp core/aron_conversions.cpp + core/ice_conversions.cpp core/json_conversions.cpp core/base/detail/MemoryItem.cpp - core/base/detail/MaxHistorySize.cpp core/base/detail/MemoryContainerBase.cpp core/base/detail/EntityContainerBase.cpp core/base/detail/AronTyped.cpp + core/base/detail/iteration_mixins.cpp + core/base/detail/negative_index_semantics.cpp - core/base/CoreSegmentBase.cpp - core/base/EntityBase.cpp + # core/base/CoreSegmentBase.cpp + # core/base/EntityBase.cpp core/base/EntityInstanceBase.cpp core/base/EntitySnapshotBase.cpp - core/base/MemoryBase.cpp - core/base/ProviderSegmentBase.cpp - - core/workingmemory/ice_conversions.cpp - core/workingmemory/detail/CopyWithoutData.cpp - core/workingmemory/CoreSegment.cpp - core/workingmemory/Entity.cpp - core/workingmemory/EntityInstance.cpp - core/workingmemory/EntitySnapshot.cpp - core/workingmemory/Memory.cpp - core/workingmemory/ProviderSegment.cpp - core/workingmemory/ice_conversions.cpp - core/workingmemory/json_conversions.cpp - core/workingmemory/entityInstance_conversions.cpp - core/workingmemory/visitor/Visitor.cpp - core/workingmemory/visitor/FunctionalVisitor.cpp + # core/base/MemoryBase.cpp + # core/base/ProviderSegmentBase.cpp + core/base/ice_conversions.cpp + + core/wm/memory_definitions.cpp + core/wm/ice_conversions.cpp + core/wm/json_conversions.cpp + core/wm/aron_conversions.cpp + core/wm/visitor/Visitor.cpp + core/wm/visitor/FunctionalVisitor.cpp core/longtermmemory/CoreSegment.cpp core/longtermmemory/Entity.cpp @@ -97,7 +93,13 @@ set(LIB_FILES server/ComponentPlugin.cpp server/MemoryRemoteGui.cpp server/RemoteGuiAronDataVisitor.cpp - server/Segment.cpp + + server/wm/memory_definitions.cpp + server/wm/ice_conversions.cpp + server/wm/detail/MaxHistorySize.cpp + + server/segment/Segment.cpp + server/segment/SpecializedSegment.cpp server/query_proc/base/BaseQueryProcessorBase.cpp server/query_proc/base/EntityQueryProcessorBase.cpp @@ -105,23 +107,9 @@ set(LIB_FILES server/query_proc/base/CoreSegmentQueryProcessorBase.cpp server/query_proc/base/MemoryQueryProcessorBase.cpp - server/query_proc/workingmemory/BaseQueryProcessor.cpp - server/query_proc/workingmemory/EntityQueryProcessor.cpp - server/query_proc/workingmemory/ProviderSegmentQueryProcessor.cpp - server/query_proc/workingmemory/CoreSegmentQueryProcessor.cpp - server/query_proc/workingmemory/MemoryQueryProcessor.cpp - - server/query_proc/longtermmemory/BaseQueryProcessor.cpp - server/query_proc/longtermmemory/EntityQueryProcessor.cpp - server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.cpp - server/query_proc/longtermmemory/CoreSegmentQueryProcessor.cpp - server/query_proc/longtermmemory/MemoryQueryProcessor.cpp - - server/query_proc/diskmemory/BaseQueryProcessor.cpp - server/query_proc/diskmemory/EntityQueryProcessor.cpp - server/query_proc/diskmemory/ProviderSegmentQueryProcessor.cpp - server/query_proc/diskmemory/CoreSegmentQueryProcessor.cpp - server/query_proc/diskmemory/MemoryQueryProcessor.cpp + server/query_proc/diskmemory.cpp + server/query_proc/ltm.cpp + server/query_proc/wm.cpp mns/MemoryNameSystem.cpp mns/ComponentPlugin.cpp @@ -131,15 +119,19 @@ set(LIB_FILES set(LIB_HEADERS core.h + core/forward_declarations.h + core/Commit.h core/DataMode.h core/MemoryID.h core/MemoryID_operators.h + core/operations.h core/SuccessHeader.h core/Time.h core/aron_conversions.h core/json_conversions.h core/ice_conversions.h + core/ice_conversions_boost_templates.h core/ice_conversions_templates.h core/error.h @@ -147,10 +139,11 @@ set(LIB_HEADERS core/error/mns.h core/base/detail/MemoryItem.h - core/base/detail/MaxHistorySize.h core/base/detail/MemoryContainerBase.h core/base/detail/EntityContainerBase.h core/base/detail/AronTyped.h + core/base/detail/iteration_mixins.h + core/base/detail/negative_index_semantics.h core/base/CoreSegmentBase.h core/base/EntityBase.h @@ -158,20 +151,15 @@ set(LIB_HEADERS core/base/EntitySnapshotBase.h core/base/MemoryBase.h core/base/ProviderSegmentBase.h + core/base/ice_conversions.h - core/workingmemory/detail/CopyWithoutData.h - core/workingmemory/CoreSegment.h - core/workingmemory/Entity.h - core/workingmemory/EntityInstance.h - core/workingmemory/EntitySnapshot.h - core/workingmemory/Memory.h - core/workingmemory/ProviderSegment.h - core/workingmemory/ice_conversions.h - core/workingmemory/json_conversions.h - core/workingmemory/entityInstance_conversions.h - core/workingmemory/visitor.h - core/workingmemory/visitor/Visitor.h - core/workingmemory/visitor/FunctionalVisitor.h + core/wm.h + core/wm/memory_definitions.h + core/wm/aron_conversions.h + core/wm/ice_conversions.h + core/wm/json_conversions.h + core/wm/visitor/Visitor.h + core/wm/visitor/FunctionalVisitor.h core/longtermmemory/CoreSegment.h core/longtermmemory/Entity.h @@ -214,43 +202,38 @@ set(LIB_HEADERS client/util/SimpleWriterBase.h server.h + server/forward_declarations.h + server/ComponentPlugin.h server/MemoryToIceAdapter.h server/MemoryRemoteGui.h server/RemoteGuiAronDataVisitor.h - server/Segment.h + + server/wm/memory_definitions.h + server/wm/ice_conversions.h + server/wm/detail/MaxHistorySize.h + + server/segment/Segment.h + server/segment/SpecializedSegment.h server/query_proc.h + + server/query_proc/base.h server/query_proc/base/BaseQueryProcessorBase.h server/query_proc/base/EntityQueryProcessorBase.h server/query_proc/base/ProviderSegmentQueryProcessorBase.h server/query_proc/base/CoreSegmentQueryProcessorBase.h server/query_proc/base/MemoryQueryProcessorBase.h - server/query_proc/workingmemory/BaseQueryProcessor.h - server/query_proc/workingmemory/EntityQueryProcessor.h - server/query_proc/workingmemory/ProviderSegmentQueryProcessor.h - server/query_proc/workingmemory/CoreSegmentQueryProcessor.h - server/query_proc/workingmemory/MemoryQueryProcessor.h - - server/query_proc/longtermmemory/BaseQueryProcessor.h - server/query_proc/longtermmemory/EntityQueryProcessor.h - server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.h - server/query_proc/longtermmemory/CoreSegmentQueryProcessor.h - server/query_proc/longtermmemory/MemoryQueryProcessor.h - - server/query_proc/diskmemory/BaseQueryProcessor.h - server/query_proc/diskmemory/EntityQueryProcessor.h - server/query_proc/diskmemory/ProviderSegmentQueryProcessor.h - server/query_proc/diskmemory/CoreSegmentQueryProcessor.h - server/query_proc/diskmemory/MemoryQueryProcessor.h + server/query_proc/diskmemory.h + server/query_proc/ltm.h + server/query_proc/wm.h mns.h mns/MemoryNameSystem.h mns/ComponentPlugin.h util/util.h - ) armarx_add_library( diff --git a/source/RobotAPI/libraries/armem/client/ComponentPlugin.cpp b/source/RobotAPI/libraries/armem/client/ComponentPlugin.cpp index a68e742cd24489694da91ef73ff557a6e8be1294..a88f374d6bddede5fd0b05eb28481d524f5f6b0a 100644 --- a/source/RobotAPI/libraries/armem/client/ComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem/client/ComponentPlugin.cpp @@ -31,7 +31,8 @@ armarx::armem::client::ComponentPluginUser::setMemoryServer(server::MemoryInterf armarx::armem::data::WaitForMemoryResult armarx::armem::client::ComponentPluginUser::useMemoryServer(const std::string& memoryName) { - armem::data::WaitForMemoryResult result = MemoryNameSystemComponentPluginUser::useMemoryServer(memoryName); + armem::data::WaitForMemoryResult result; + result.proxy = memoryNameSystem.useServer(MemoryID().withMemoryName(memoryName)); if (result.proxy) { setMemoryServer(result.proxy); diff --git a/source/RobotAPI/libraries/armem/client/ComponentPlugin.h b/source/RobotAPI/libraries/armem/client/ComponentPlugin.h index 3bdbde93bd046bcceb361d94183be5fd1c09db23..ae3f26b26557c11046d84cde8a07483e4ba9ad49 100644 --- a/source/RobotAPI/libraries/armem/client/ComponentPlugin.h +++ b/source/RobotAPI/libraries/armem/client/ComponentPlugin.h @@ -2,7 +2,7 @@ // ArmarX -#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/ComponentPlugin.h> // RobotAPI #include <RobotAPI/interface/armem/server/MemoryInterface.h> diff --git a/source/RobotAPI/libraries/armem/client/Query.cpp b/source/RobotAPI/libraries/armem/client/Query.cpp index 1777839f24e6f2522e7f0efb9670f79ff463231b..52000cf3d25f118ea80cf7dfc7c5ea5830cb36f8 100644 --- a/source/RobotAPI/libraries/armem/client/Query.cpp +++ b/source/RobotAPI/libraries/armem/client/Query.cpp @@ -1,6 +1,6 @@ #include "Query.h" -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> namespace armarx::armem::client { diff --git a/source/RobotAPI/libraries/armem/client/Query.h b/source/RobotAPI/libraries/armem/client/Query.h index 916278a8fcde1679545ed39d59531f5772852c13..56b9caa79b06bf598836a8cb4df5ab492177604a 100644 --- a/source/RobotAPI/libraries/armem/client/Query.h +++ b/source/RobotAPI/libraries/armem/client/Query.h @@ -3,10 +3,10 @@ // RobotAPI #include <RobotAPI/interface/armem/query.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/core/SuccessHeader.h> #include <RobotAPI/libraries/armem/core/DataMode.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> namespace armarx::armem::client::query @@ -60,6 +60,38 @@ namespace armarx::armem::client } } + void replaceQueryTarget(const armem::query::data::QueryTarget search, const armem::query::data::QueryTarget replace) + { + for (const auto& memoryQuery : memoryQueries) + { + if (auto it = std::find(memoryQuery->targets.begin(), memoryQuery->targets.end(), search); it != memoryQuery->targets.end()) + { + memoryQuery->targets.push_back(replace); + } + for (const auto& coreSegmentQuery : memoryQuery->coreSegmentQueries) + { + if (auto it = std::find(coreSegmentQuery->targets.begin(), coreSegmentQuery->targets.end(), search); it != coreSegmentQuery->targets.end()) + { + coreSegmentQuery->targets.push_back(replace); + } + for (const auto& providerSegmentQuery : coreSegmentQuery->providerSegmentQueries) + { + if (auto it = std::find(providerSegmentQuery->targets.begin(), providerSegmentQuery->targets.end(), search); it != providerSegmentQuery->targets.end()) + { + providerSegmentQuery->targets.push_back(replace); + } + for (const auto& entityQuery : providerSegmentQuery->entityQueries) + { + if (auto it = std::find(entityQuery->targets.begin(), entityQuery->targets.end(), search); it != entityQuery->targets.end()) + { + entityQuery->targets.push_back(replace); + } + } + } + } + } + } + static QueryInput fromIce(const armem::query::data::Input& ice); armem::query::data::Input toIce() const; }; diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp index a589512f13bcdaaa2536f597a54474eb72f96574..1f0e2ee51717e011de75f9fad4dd9c2c598ada88 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.cpp +++ b/source/RobotAPI/libraries/armem/client/Reader.cpp @@ -6,9 +6,8 @@ #include <RobotAPI/libraries/armem/core/MemoryID_operators.h> #include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/util/util.h> #include "query/Builder.h" @@ -162,30 +161,25 @@ namespace armarx::armem::client } - struct FindLatestSnapshotVisitor : public wm::Visitor - { - std::optional<wm::EntitySnapshot> latest = std::nullopt; - - bool visitEnter(const wm::EntitySnapshot& snapshot) override; - }; - bool FindLatestSnapshotVisitor::visitEnter(const wm::EntitySnapshot& snapshot) - { - if (not latest.has_value() or snapshot.time() < latest->time()) - { - latest = snapshot; - } - return true; - } - - std::optional<wm::EntitySnapshot> Reader::getLatestSnapshotIn(const MemoryID& id, DataMode dataMode) const { client::QueryResult result = getLatestSnapshotsIn(id, dataMode); if (result.success) { - FindLatestSnapshotVisitor visitor; - visitor.applyTo(result.memory); - return visitor.latest; + std::optional<wm::EntitySnapshot> latest = std::nullopt; + result.memory.forEachEntity([&latest](const wm::Entity & entity) + { + if (not entity.empty()) + { + const wm::EntitySnapshot& snapshot = entity.getLatestSnapshot(); + if (not latest.has_value() or latest->time() < snapshot.time()) + { + latest = snapshot; + } + } + return true; + }); + return latest; } else { diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h index 1d69491d2cf33e7bdf460634ef69bc26db4bb52b..e9ee1b69afef7d2befdaaf0169b0117a13edbad5 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.h +++ b/source/RobotAPI/libraries/armem/client/Reader.h @@ -8,8 +8,7 @@ // RobotAPI #include <RobotAPI/interface/armem/server/ReadingMemoryInterface.h> #include <RobotAPI/interface/armem/server/StoringMemoryInterface.h> -#include <RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h> -// #include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "Query.h" diff --git a/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.cpp b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.cpp index 3204c83cc094f3895e4ace10a4b91c9cdfeb1070..3ac9f7438408460c157f7484d313ef0d6a3808a6 100644 --- a/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.cpp @@ -2,6 +2,7 @@ // ArmarX +#include <ArmarXCore/core/Component.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> // RobotAPI @@ -47,11 +48,13 @@ namespace armarx::armem::client armem::data::WaitForMemoryResult ReaderComponentPluginUser::useMemoryServer(const std::string& memoryName) { - armem::data::WaitForMemoryResult result = MemoryNameSystemComponentPluginUser::useMemoryServer(memoryName); + armem::data::WaitForMemoryResult result; + result.proxy = memoryNameSystem.useServer(memoryName); if (result.proxy) { setReadingMemoryServer(result.proxy); } return result; } + } diff --git a/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.h b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.h index 0a2e37ba953e024858090cc64d6510dfebfd8a77..c0139e609e830e2c07517837f6cc3d48aff434db 100644 --- a/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.h +++ b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.h @@ -5,7 +5,7 @@ #include <vector> // ArmarX -#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/ComponentPlugin.h> // RobotAPI #include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> diff --git a/source/RobotAPI/libraries/armem/client/Writer.h b/source/RobotAPI/libraries/armem/client/Writer.h index dd953fa368d9a46363677d3bc39bc71f8da2a9ce..92c7ce04a3d1ec9317f33404bafef2ac58c8c3cd 100644 --- a/source/RobotAPI/libraries/armem/client/Writer.h +++ b/source/RobotAPI/libraries/armem/client/Writer.h @@ -2,7 +2,7 @@ #include <RobotAPI/interface/armem/server/WritingMemoryInterface.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> namespace armarx::armem::client diff --git a/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.cpp b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.cpp index 093f29e6fa2178f19ae13983e21772f17400856d..d4b95ca3565e8552322e7e7cdfac131335ca06f3 100644 --- a/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.cpp @@ -2,6 +2,7 @@ // ArmarX +#include <ArmarXCore/core/Component.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> // RobotAPI @@ -43,9 +44,11 @@ namespace armarx::armem::client memoryWriter.setWritingMemory(memory); } + armem::data::WaitForMemoryResult WriterComponentPluginUser::useMemoryServer(const std::string& memoryName) { - armem::data::WaitForMemoryResult result = MemoryNameSystemComponentPluginUser::useMemoryServer(memoryName); + armem::data::WaitForMemoryResult result; + result.proxy = memoryNameSystem.useServer(MemoryID().withMemoryName(memoryName)); if (result.proxy) { setWritingMemoryServer(result.proxy); diff --git a/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.h b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.h index 435881b48b27b9053dd5da5e87b794d3561f3b3c..3ae9a66bfab912237934d4bea6580a2e32a2c7fb 100644 --- a/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.h +++ b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.h @@ -2,7 +2,7 @@ // ArmarX -#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/ComponentPlugin.h> // RobotAPI #include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> diff --git a/source/RobotAPI/libraries/armem/client/query/selectors.cpp b/source/RobotAPI/libraries/armem/client/query/selectors.cpp index 98e79d06ab3642b25bee40e89daf728ab3dfee2b..ecd3f8c5f4a1b3ed0a7dde04c8dc1ac8a06b5265 100644 --- a/source/RobotAPI/libraries/armem/client/query/selectors.cpp +++ b/source/RobotAPI/libraries/armem/client/query/selectors.cpp @@ -1,7 +1,7 @@ #include "selectors.h" #include "RobotAPI/libraries/armem/core/ice_conversions.h" -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> namespace dq = ::armarx::armem::query::data; diff --git a/source/RobotAPI/libraries/armem/core.h b/source/RobotAPI/libraries/armem/core.h index c8ddee31ce054decbc8fdc33edf7959502601da7..11abe789b8cd0aef6ab2d9017c96cb1237cc5040 100644 --- a/source/RobotAPI/libraries/armem/core.h +++ b/source/RobotAPI/libraries/armem/core.h @@ -6,13 +6,7 @@ #include "core/MemoryID.h" #include "core/Time.h" -#include "core/workingmemory/Memory.h" -#include "core/workingmemory/CoreSegment.h" -#include "core/workingmemory/ProviderSegment.h" -#include "core/workingmemory/Entity.h" -#include "core/workingmemory/EntitySnapshot.h" -#include "core/workingmemory/EntityInstance.h" -#include "core/workingmemory/ice_conversions.h" +#include "core/wm.h" namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem/core/Commit.cpp b/source/RobotAPI/libraries/armem/core/Commit.cpp index fed7ed660b450bb0865a018f9c8d7119dd96a7b4..fed012450b059f50159c659217694c160e8f636a 100644 --- a/source/RobotAPI/libraries/armem/core/Commit.cpp +++ b/source/RobotAPI/libraries/armem/core/Commit.cpp @@ -1,9 +1,11 @@ #include "Commit.h" -#include <SimoxUtility/algorithm/apply.hpp> +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <SimoxUtility/algorithm/apply.hpp> + namespace armarx::armem { diff --git a/source/RobotAPI/libraries/armem/core/Commit.h b/source/RobotAPI/libraries/armem/core/Commit.h index fc69a4b53dcaecc52d703aa42c00405f4162825f..685886a7f27b5d43b78cd0195693e32c3a58fffa 100644 --- a/source/RobotAPI/libraries/armem/core/Commit.h +++ b/source/RobotAPI/libraries/armem/core/Commit.h @@ -1,11 +1,12 @@ #pragma once -#include <vector> +#include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem/core/MemoryID.h> -#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> +#include <RobotAPI/libraries/aron/core/navigator/data/forward_declarations.h> -#include "../core/MemoryID.h" -#include "../core/Time.h" +#include <memory> +#include <vector> namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h index 6dc77c57625b0a8ebd33200885f06045eef49bbf..0de79cccd0af6a85dd396b8891e91c572ee24fb2 100644 --- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h @@ -6,7 +6,7 @@ #include "ProviderSegmentBase.h" #include "detail/AronTyped.h" #include "detail/EntityContainerBase.h" -#include "detail/MaxHistorySize.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -18,8 +18,10 @@ namespace armarx::armem::base template <class _ProviderSegmentT, class _Derived> class CoreSegmentBase : public detail::EntityContainerBase<_ProviderSegmentT, typename _ProviderSegmentT::EntityT, _Derived>, - public detail::MaxHistorySize, - public detail::AronTyped + public detail::AronTyped, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived>, + public detail::ForEachEntityMixin<_Derived> { using Base = detail::EntityContainerBase<_ProviderSegmentT, typename _ProviderSegmentT::EntityT, _Derived>; @@ -50,20 +52,21 @@ namespace armarx::armem::base {} }; + public: CoreSegmentBase() { } - CoreSegmentBase(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : - CoreSegmentBase(MemoryID().withCoreSegmentName(name), aronType) + explicit CoreSegmentBase(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : + CoreSegmentBase(name, MemoryID(), aronType) { } - CoreSegmentBase(const std::string& name, const MemoryID& parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : - CoreSegmentBase(parentID.withProviderSegmentName(name), aronType) + explicit CoreSegmentBase(const std::string& name, const MemoryID& parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : + CoreSegmentBase(parentID.withCoreSegmentName(name), aronType) { } - CoreSegmentBase(const MemoryID& id, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : + explicit CoreSegmentBase(const MemoryID& id, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : Base(id), AronTyped(aronType) { @@ -75,6 +78,8 @@ namespace armarx::armem::base CoreSegmentBase& operator=(CoreSegmentBase&& other) = default; + // READ ACCESS + inline const std::string& name() const { return this->id().coreSegmentName; @@ -85,19 +90,14 @@ namespace armarx::armem::base } - inline const auto& providerSegments() const - { - return this->_container; - } - inline auto& providerSegments() + bool hasProviderSegment(const std::string& name) const { - return this->_container; + return this->_container.count(name) > 0; } - - bool hasProviderSegment(const std::string& name) const + std::vector<std::string> getProviderSegmentNames() const { - return this->_container.count(name) > 0; + return simox::alg::get_keys(this->_container); } ProviderSegmentT& getProviderSegment(const std::string& name) @@ -119,13 +119,13 @@ namespace armarx::armem::base } using Base::getEntity; - const EntityT& getEntity(const MemoryID& id) const override + const EntityT& getEntity(const MemoryID& id) const { this->_checkContainerName(id.coreSegmentName, this->getKeyString()); return getProviderSegment(id.providerSegmentName).getEntity(id); } - const EntityT* findEntity(const MemoryID& id) const override + const EntityT* findEntity(const MemoryID& id) const { this->_checkContainerName(id.coreSegmentName, this->getKeyString()); if (id.hasProviderSegmentName()) @@ -145,6 +145,45 @@ namespace armarx::armem::base } } + + // ITERATION + + /** + * @param func Function like: bool process(ProviderSegmentT& provSeg) + */ + template <class ProviderSegmentFunctionT> + bool forEachProviderSegment(ProviderSegmentFunctionT&& func) + { + return this->forEachChild(func); + } + /** + * @param func Function like: bool process(const ProviderSegmentT& provSeg) + */ + template <class ProviderSegmentFunctionT> + bool forEachProviderSegment(ProviderSegmentFunctionT&& func) const + { + return this->forEachChild(func); + } + + // forEachEntity() is provided by ForEachEntityMixin. + // forEachSnapshot() is provided by ForEachEntitySnapshotMixin. + // forEachInstance() is provided by ForEachEntityInstanceMixin. + + + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline const auto& providerSegments() const + { + return this->_container; + } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline auto& providerSegments() + { + return this->_container; + } + + + // MODIFICATION + /** * @brief Updates an entity's history. * @@ -154,53 +193,61 @@ namespace armarx::armem::base { this->_checkContainerName(update.entityID.coreSegmentName, this->name()); + auto [inserted, provSeg] = addProviderSegmentIfMissing(update.entityID.providerSegmentName); + + + // Update entry. + UpdateResult ret(provSeg->update(update)); + if (inserted) + { + ret.coreSegmentUpdateType = UpdateType::InsertedNew; + } + else + { + ret.coreSegmentUpdateType = UpdateType::UpdatedExisting; + } + return ret; + } + + std::pair<bool, ProviderSegmentT*> addProviderSegmentIfMissing(const std::string& providerSegmentName) + { ProviderSegmentT* provSeg; - UpdateType updateType = UpdateType::InsertedNew; - auto it = this->_container.find(update.entityID.providerSegmentName); + auto it = this->_container.find(providerSegmentName); if (it == this->_container.end()) { if (_addMissingProviderSegmentDuringUpdate) { // Insert into map. - provSeg = &addProviderSegment(update.entityID.providerSegmentName); - provSeg->setMaxHistorySize(_maxHistorySize); - updateType = UpdateType::InsertedNew; + provSeg = &addProviderSegment(providerSegmentName); + return {true, provSeg}; } else { - throw error::MissingEntry::create<EntitySnapshotT>(update.entityID.providerSegmentName, *this); + throw error::MissingEntry::create<ProviderSegmentT>(providerSegmentName, *this); } } else { provSeg = &it->second; - updateType = UpdateType::UpdatedExisting; + return {false, provSeg}; } - - // Update entry. - UpdateResult ret(provSeg->update(update)); - ret.coreSegmentUpdateType = updateType; - return ret; } void append(const _Derived& m) { - ARMARX_INFO << "CoreSegment: Merge name '" << m.name() << "' into '" << name() << "'"; + // ARMARX_INFO << "CoreSegment: Merge name '" << m.name() << "' into '" << name() << "'"; - for (const auto& [k, s] : m.container()) + m.forEachProviderSegment([this](const ProviderSegmentT & provSeg) { - if (const auto& it = this->_container.find(k); it != this->_container.end()) + auto it = this->_container.find(provSeg.name()); + if (it == this->_container.end()) { - // segment already exists - it->second.append(s); + it = this->_container.emplace(provSeg.name(), this->id().withProviderSegmentName(provSeg.name())).first; } - else - { - auto wms = this->_container.emplace(k, this->id().withProviderSegmentName(k)); - wms.first->second.append(s); - } - } + it->second.append(provSeg); + return true; + }); } /** @@ -212,7 +259,7 @@ namespace armarx::armem::base ProviderSegmentT& addProviderSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr providerSegmentType = nullptr) { aron::typenavigator::ObjectNavigatorPtr type = providerSegmentType ? providerSegmentType : this->aronType(); - return addProviderSegment(ProviderSegmentT(name, type)); + return addProviderSegment(ProviderSegmentT(name, this->id(), type)); } /// Copy and insert a provider segment. @@ -227,31 +274,18 @@ namespace armarx::armem::base if (hasProviderSegment(providerSegment.name())) { throw armem::error::ContainerEntryAlreadyExists( - providerSegment.getLevelName(), providerSegment.name(), getLevelName(), this->getKeyString()); + ProviderSegmentT::getLevelName(), providerSegment.name(), getLevelName(), this->getKeyString()); } auto it = this->_container.emplace(providerSegment.name(), std::move(providerSegment)).first; it->second.id().setCoreSegmentID(this->id()); - it->second.setMaxHistorySize(_maxHistorySize); return it->second; } - /** - * @brief Sets the maximum history size of entities in this segment. - * This affects all current entities as well as new ones. - * @see Entity::setMaxHistorySize() - */ - void setMaxHistorySize(long maxSize) override - { - MaxHistorySize::setMaxHistorySize(maxSize); - for (auto& [name, seg] : this->_container) - { - seg.setMaxHistorySize(maxSize); - } - } + // MISC - virtual bool equalsDeep(const CoreSegmentBase& other) const + bool equalsDeep(const DerivedT& other) const { //std::cout << "CoreSegment::equalsDeep" << std::endl; if (this->size() != other.size()) @@ -272,33 +306,17 @@ namespace armarx::armem::base return true; } - std::string getLevelName() const override + static std::string getLevelName() { return "core segment"; } - std::string getKeyString() const override + std::string getKeyString() const { return this->name(); } - protected: - - virtual void _copySelf(DerivedT& other) const override - { - Base::_copySelf(other); - other.aronType() = _aronType; - other._addMissingProviderSegmentDuringUpdate = _addMissingProviderSegmentDuringUpdate; - } - virtual void _copySelfEmpty(DerivedT& other) const override - { - Base::_copySelfEmpty(other); - other.aronType() = _aronType; - other._addMissingProviderSegmentDuringUpdate = _addMissingProviderSegmentDuringUpdate; - } - - private: bool _addMissingProviderSegmentDuringUpdate = true; diff --git a/source/RobotAPI/libraries/armem/core/base/EntityBase.cpp b/source/RobotAPI/libraries/armem/core/base/EntityBase.cpp index 0d2c67b63d566f7170bd9b31cfaf18785b85f87b..d3038a357bdad823f04e8d154a569a7eebaf90d5 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityBase.cpp +++ b/source/RobotAPI/libraries/armem/core/base/EntityBase.cpp @@ -1 +1,2 @@ #include "EntityBase.h" + diff --git a/source/RobotAPI/libraries/armem/core/base/EntityBase.h b/source/RobotAPI/libraries/armem/core/base/EntityBase.h index ab227c33ee321475f129d8f864b5cbf31e3f4845..05cbf780d1e95611d629d320581122b59c5f358c 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntityBase.h @@ -5,14 +5,13 @@ #include <SimoxUtility/algorithm/get_map_keys_values.h> -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include "../../core/Time.h" -#include "../../core/MemoryID.h" +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/core/Time.h> #include "EntitySnapshotBase.h" -#include "detail/MaxHistorySize.h" #include "detail/MemoryContainerBase.h" +#include "detail/iteration_mixins.h" +#include "detail/negative_index_semantics.h" namespace armarx::armem::base @@ -40,7 +39,7 @@ namespace armarx::armem::base template <class _EntitySnapshotT, class _Derived> class EntityBase : public detail::MemoryContainerBase<std::map<Time, _EntitySnapshotT>, _Derived>, - public detail::MaxHistorySize + public detail::ForEachEntityInstanceMixin<_Derived> { using Base = detail::MemoryContainerBase<std::map<Time, _EntitySnapshotT>, _Derived>; @@ -66,11 +65,11 @@ namespace armarx::armem::base EntityBase() { } - EntityBase(const std::string& name, const MemoryID& parentID = {}) : + explicit EntityBase(const std::string& name, const MemoryID& parentID = {}) : EntityBase(parentID.withEntityName(name)) { } - EntityBase(const MemoryID& id) : + explicit EntityBase(const MemoryID& id) : Base(id) { } @@ -82,27 +81,7 @@ namespace armarx::armem::base EntityBase& operator=(EntityBase&& other) = default; - virtual bool equalsDeep(const EntityBase& other) const - { - //std::cout << "Entity::equalsDeep" << std::endl; - if (this->size() != other.size()) - { - return false; - } - for (const auto& [key, snapshot] : this->_container) - { - if (not other.hasSnapshot(key)) - { - return false; - } - if (not snapshot.equalsDeep(other.getSnapshot(key))) - { - return false; - } - } - return true; - } - + // READING inline const std::string& name() const { @@ -113,26 +92,14 @@ namespace armarx::armem::base return const_cast<std::string&>(const_cast<const EntityBase*>(this)->name()); } - - inline const std::map<Time, EntitySnapshotT>& history() const - { - return this->_container; - } - inline std::map<Time, EntitySnapshotT>& history() - { - return const_cast<std::map<Time, EntitySnapshotT>&>(const_cast<const EntityBase*>(this)->history()); - } - - /** * @brief Indicates whether a history entry for the given time exists. */ - virtual bool hasSnapshot(const Time& time) + bool hasSnapshot(const Time& time) { return const_cast<const EntityBase*>(this)->hasSnapshot(time); } - - virtual bool hasSnapshot(const Time& time) const + bool hasSnapshot(const Time& time) const { return this->_container.count(time) > 0; } @@ -154,12 +121,7 @@ namespace armarx::armem::base /** * @brief Get all timestamps in the history. */ - virtual std::vector<Time> getTimestamps() - { - return const_cast<const EntityBase*>(this)->getTimestamps(); - } - - virtual std::vector<Time> getTimestamps() const + std::vector<Time> getTimestamps() const { return simox::alg::get_keys(this->_container); } @@ -172,12 +134,12 @@ namespace armarx::armem::base * * @throws `armem::error::MissingEntry` If there is no such entry. */ - virtual EntitySnapshotT& getSnapshot(const Time& time) + EntitySnapshotT& getSnapshot(const Time& time) { return const_cast<EntitySnapshotT&>(const_cast<const EntityBase*>(this)->getSnapshot(time)); } - virtual const EntitySnapshotT& getSnapshot(const Time& time) const + const EntitySnapshotT& getSnapshot(const Time& time) const { auto it = this->_container.find(time); if (it != this->_container.end()) @@ -210,150 +172,234 @@ namespace armarx::armem::base { return const_cast<EntitySnapshotT&>(const_cast<const EntityBase*>(this)->getLatestSnapshot()); } - const EntitySnapshotT& getLatestSnapshot() const { return getLatestItem().second; } /** - * @brief Return the lastest snapshot before or at time. + * @brief Return the snapshot with the most recent timestamp. + * @return The latest snapshot. + * @throw `armem::error::EntityHistoryEmpty` If the history is empty. + */ + EntitySnapshotT& getFirstSnapshot() + { + return const_cast<EntitySnapshotT&>(const_cast<const EntityBase*>(this)->getFirstSnapshot()); + } + const EntitySnapshotT& getFirstSnapshot() const + { + return getFirstItem().second; + } + + + /** + * @brief Return the lastest snapshot before time. * @param time The time. * @return The latest snapshot. * @throw `armem::error::EntityHistoryEmpty` If the history is empty. * @throw `armem::error::MissingEntry` If no such snapshot */ - virtual const EntitySnapshotT& getLatestSnapshotBeforeOrAt(const Time& time) const + const EntitySnapshotT& getLatestSnapshotBefore(const Time& time) const { - // first element equal or greater - typename std::map<Time, EntitySnapshotT>::const_iterator refIt = this->_container.upper_bound(time); + if (this->empty()) + { + throw error::EntityHistoryEmpty(this->name()); + } - if (refIt == this->_container.begin()) + // We want the rightmost element < time + // lower_bound() gives us the the leftmost >= time, which is probably the right neighbour + typename ContainerT::const_iterator greaterEq = this->_container.lower_bound(time); + // Special cases: + // refIt = begin() => no element < time + if (greaterEq == this->_container.begin()) { - if (refIt->first == time) - { - return refIt->second; - } throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this); } - // last element less than - typename std::map<Time, EntitySnapshotT>::const_iterator refItPrev = std::prev(refIt); + // end(): No element >= time, we can still have one < time (rbegin()) => std::prev(end()) + // empty has been checked above - // ... or we return the element before if possible - if (refItPrev != this->_container.begin()) - { - return refItPrev->second; - } + // std::prev of end() is ok + typename ContainerT::const_iterator less = std::prev(greaterEq); - throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this); + // we return the element before if possible + return less->second; } /** - * @brief Return the lastest snapshot before time. + * @brief Return the lastest snapshot before or at time. * @param time The time. * @return The latest snapshot. * @throw `armem::error::EntityHistoryEmpty` If the history is empty. * @throw `armem::error::MissingEntry` If no such snapshot */ - virtual const EntitySnapshotT& getLatestSnapshotBefore(const Time& time) const + const EntitySnapshotT& getLatestSnapshotBeforeOrAt(const Time& time) const + { + return getLatestSnapshotBefore(time + Time::microSeconds(1)); + } + + /** + * @brief Return first snapshot after or at time. + * @param time The time. + * @return The first snapshot. + * @throw `armem::error::EntityHistoryEmpty` If the history is empty. + * @throw `armem::error::MissingEntry` If no such snapshot + */ + const EntitySnapshotT& getFirstSnapshotAfterOrAt(const Time& time) const { - // first element equal or greater - typename std::map<Time, EntitySnapshotT>::const_iterator refIt = this->_container.upper_bound(time); + // We want the leftmost element >= time. + // That's lower bound. + typename ContainerT::const_iterator greaterEq = this->_container.lower_bound(time); - if (refIt == this->_container.begin()) + if (greaterEq == this->_container.end()) { throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this); } + return greaterEq->second; + } - // last element less than - typename std::map<Time, EntitySnapshotT>::const_iterator refItPrev = std::prev(refIt); + /** + * @brief Return first snapshot after time. + * @param time The time. + * @return The first snapshot. + * @throw `armem::error::EntityHistoryEmpty` If the history is empty. + * @throw `armem::error::MissingEntry` If no such snapshot + */ + const EntitySnapshotT& getFirstSnapshotAfter(const Time& time) const + { + return getFirstSnapshotAfter(time - Time::microSeconds(1)); + } - // we return the element before if possible - if (refItPrev != this->_container.begin()) - { - return refItPrev->second; - } - throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this); + // ITERATION + + /** + * @param func Function like: bool process(EntitySnapshotT& snapshot) + */ + template <class SnapshotFunctionT> + bool forEachSnapshot(SnapshotFunctionT&& func) + { + return this->forEachChild(func); + } + /** + * @param func Function like void process(const EntitySnapshotT& snapshot) + */ + template <class SnapshotFunctionT> + bool forEachSnapshot(SnapshotFunctionT&& func) const + { + return this->forEachChild(func); } + // forEachInstance() is provided by ForEachEntityInstanceMixin. + /** - * @brief Return all snapshots before or at time. + * @brief Return all snapshots before (excluding) time. * @param time The time. * @return The latest snapshots. - * @throw `armem::error::EntityHistoryEmpty` If the history is empty. - * @throw `armem::error::MissingEntry` If no such snapshots */ - virtual const std::vector<std::reference_wrapper<const EntitySnapshotT>> getSnapshotsBefore(const Time& time) const + template <class FunctionT> + void forEachSnapshotBefore(const Time& time, FunctionT&& func) const { - std::vector<std::reference_wrapper<const EntitySnapshotT>> ret; - const EntitySnapshotT& latest = getLatestSnapshotBefore(time); - for (const auto& [timestamp, snapshot] : this->_container) { - ret.emplace_back(snapshot); - if (timestamp == latest.id().timestamp) + if (timestamp >= time) + { + break; + } + if (not call(func, snapshot)) { break; } } - return ret; } /** - * @brief Return first snapshot after or at time. + * @brief Return all snapshots before or at time. * @param time The time. - * @return The first snapshot. - * @throw `armem::error::EntityHistoryEmpty` If the history is empty. - * @throw `armem::error::MissingEntry` If no such snapshot + * @return The latest snapshots. */ - virtual const EntitySnapshotT& getFirstSnapshotAfterOrAt(const Time& time) const + template <class FunctionT> + void forEachSnapshotBeforeOrAt(const Time& time, FunctionT&& func) const { - // first element equal or greater - typename std::map<Time, EntitySnapshotT>::const_iterator refIt = this->_container.upper_bound(time); - - if (refIt == this->_container.end()) - { - throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this); - } - return refIt->second; + getSnapshotsBefore(time + Time::microSeconds(1), func); } + /** - * @brief Return first snapshot after time. - * @param time The time. - * @return The first snapshot. - * @throw `armem::error::EntityHistoryEmpty` If the history is empty. - * @throw `armem::error::MissingEntry` If no such snapshot + * @brief Return all snapshots between, including, min and max. + * @param min The lowest time to include. + * @param min The highest time to include. + * @return The snapshots in [min, max]. */ - virtual const EntitySnapshotT& getFirstSnapshotAfter(const Time& time) const + template <class FunctionT> + void forEachSnapshotInTimeRange(const Time& min, const Time& max, FunctionT&& func) const { - // first element equal or greater - typename std::map<Time, EntitySnapshotT>::const_iterator refIt = this->_container.upper_bound(time); + // Returns an iterator pointing to the first element that is not less than (i.e. greater or equal to) key. + auto begin = min.toMicroSeconds() > 0 ? this->_container.lower_bound(min) : this->_container.begin(); + // Returns an iterator pointing to the first element that is *greater than* key. + auto end = max.toMicroSeconds() > 0 ? this->_container.upper_bound(max) : this->_container.end(); - if (refIt == this->_container.end()) + for (auto it = begin; it != end && it != this->_container.end(); ++it) { - throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this); + if (not call(func, it->second)) + { + break; + } } + } - if (refIt->first > time) + /** + * @brief Return all snapshots from first to last index. + * + * Negative index are counted from the end, e.g. + * last == -1 results in getting all queries until the end. + * + * @param first The first index to include. + * @param first The last index to include. + * @return The snapshots in [first, last]. + */ + template <class FunctionT> + void forEachSnapshotInIndexRange(long first, long last, FunctionT&& func) const + { + if (this->empty()) { - return refIt->second; + return; } - // first element greater than - typename std::map<Time, EntitySnapshotT>::const_iterator refItNext = std::next(refIt); + const size_t first_ = detail::negativeIndexSemantics(first, this->size()); + const size_t last_ = detail::negativeIndexSemantics(last, this->size()); - if (refItNext != this->_container.end()) + if (first_ <= last_) { - return refItNext->second; + auto it = this->_container.begin(); + std::advance(it, first_); + + size_t num = last_ - first_ + 1; // +1 to make last inclusive + for (size_t i = 0; i < num; ++i, ++it) + { + if (not call(func, it->second)) + { + break; + } + } } + } - throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this); + + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline const ContainerT& history() const + { + return this->_container; + } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline ContainerT& history() + { + return const_cast<ContainerT&>(const_cast<const EntityBase*>(this)->history()); } + // MODIFICATION + /** * @brief Add the given update to this entity's history. * @param update The update. @@ -371,7 +417,7 @@ namespace armarx::armem::base { // Insert into history. snapshot = &addSnapshot(update.timeCreated); - ret.removedSnapshots = truncate(); + // ret.removedSnapshots = this->truncate(); ret.entityUpdateType = UpdateType::InsertedNew; } else @@ -380,30 +426,30 @@ namespace armarx::armem::base ret.entityUpdateType = UpdateType::UpdatedExisting; } // Update entry. - snapshot->update(update, this->id()); + snapshot->update(update); ret.id = snapshot->id(); return ret; } + void append(const DerivedT& m) { - ARMARX_INFO << "Entity: Merge name '" << m.name() << "' into '" << name() << "'"; + // ARMARX_INFO << "Entity: Merge name '" << m.name() << "' into '" << name() << "'"; - for (const auto& [k, s] : m.container()) + m.forEachSnapshot([this](const EntitySnapshotT & snapshot) { - if (const auto& it = this->_container.find(k); it != this->_container.end()) - { - // segment already exists - // We assume that a snapshot does not change, so ignore - } - else + auto it = this->_container.find(snapshot.time()); + if (it == this->_container.end()) { - auto snapshot = s.copy(); - snapshot.id() = this->id().withTimestamp(k); // update id (e.g. memory name) if necessary - this->_container.insert(std::make_pair(k, std::move(snapshot))); + EntitySnapshotT copy { snapshot }; + copy.id() = this->id().withTimestamp(snapshot.time()); // update id (e.g. memory name) if necessary + this->_container.emplace(snapshot.time(), copy); } - } + // else: segment already exists + // We assume that a snapshot does not change, so ignore + return true; + }); } /** @@ -418,33 +464,46 @@ namespace armarx::armem::base EntitySnapshotT& addSnapshot(EntitySnapshotT&& snapshot) { - auto it = this->_container.emplace(snapshot.time(), std::move(snapshot)).first; + auto it = this->_container.emplace_hint(this->_container.end(), snapshot.time(), std::move(snapshot)); it->second.id().setEntityID(this->id()); return it->second; } EntitySnapshotT& addSnapshot(const Time& timestamp) { - return addSnapshot(EntitySnapshotT(timestamp)); + return addSnapshot(EntitySnapshotT(timestamp, this->id())); } - /** - * @brief Sets the maximum history size. - * - * The current history is truncated if necessary. - */ - void setMaxHistorySize(long maxSize) override + + // MISC + + bool equalsDeep(const DerivedT& other) const { - MaxHistorySize::setMaxHistorySize(maxSize); - truncate(); + //std::cout << "Entity::equalsDeep" << std::endl; + if (this->size() != other.size()) + { + return false; + } + for (const auto& [key, snapshot] : this->_container) + { + if (not other.hasSnapshot(key)) + { + return false; + } + if (not snapshot.equalsDeep(other.getSnapshot(key))) + { + return false; + } + } + return true; } - std::string getKeyString() const override + std::string getKeyString() const { return this->id().entityName; } - std::string getLevelName() const override + static std::string getLevelName() { return "entity"; } @@ -452,36 +511,37 @@ namespace armarx::armem::base protected: - /// If maximum size is set, ensure `history`'s is not higher. - std::vector<EntitySnapshotT> truncate() + /** + * @brief Return the snapshot with the most recent timestamp. + * @return The latest snapshot. + * @throw `armem::error::EntityHistoryEmpty` If the history is empty. + */ + const typename ContainerT::value_type& + getLatestItem() const { - std::vector<EntitySnapshotT> removedElements; - if (_maxHistorySize >= 0) + if (this->_container.empty()) { - while (this->_container.size() > size_t(_maxHistorySize)) - { - removedElements.push_back(std::move(this->_container.begin()->second)); - this->_container.erase(this->_container.begin()); - } - ARMARX_CHECK_LESS_EQUAL(this->_container.size(), _maxHistorySize); + throw armem::error::EntityHistoryEmpty(name(), "when getting the latest snapshot."); } - return removedElements; + return *this->_container.rbegin(); } /** - * @brief Return the snapshot with the most recent timestamp. - * @return The latest snapshot. + * @brief Return the snapshot with the least recent timestamp. + * @return The first snapshot. * @throw `armem::error::EntityHistoryEmpty` If the history is empty. */ - virtual const typename std::map<Time, EntitySnapshotT>::value_type& getLatestItem() const + const typename ContainerT::value_type& + getFirstItem() const { if (this->_container.empty()) { - throw armem::error::EntityHistoryEmpty(name(), "when getting the latest snapshot."); + throw armem::error::EntityHistoryEmpty(name(), "when getting the first snapshot."); } - return *this->_container.rbegin(); + return *this->_container.begin(); } + }; } diff --git a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.cpp b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.cpp index a6cfc7103728d5a81fecefe4ade6c96efef2814e..1cc2e9544d00ce96d65658acaf853c670418bdce 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.cpp +++ b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.cpp @@ -1 +1,25 @@ #include "EntityInstanceBase.h" + + +namespace armarx::armem::base +{ + bool EntityInstanceMetadata::operator==(const EntityInstanceMetadata& other) const + { + return timeCreated == other.timeCreated + && timeSent == other.timeSent + && timeArrived == other.timeArrived + && std::abs(confidence - other.confidence) < 1e-6f; + } +} + + +std::ostream& armarx::armem::base::operator<<(std::ostream& os, const EntityInstanceMetadata& d) +{ + os << "EntityInstanceMetadata: " + << "\n- t_create = \t" << armem::toStringMicroSeconds(d.timeCreated) << " us" + << "\n- t_sent = \t" << armem::toStringMicroSeconds(d.timeSent) << " us" + << "\n- t_arrived = \t" << armem::toStringMicroSeconds(d.timeArrived) << " us" + << "\n- confidence = \t" << d.confidence << " us" + ; + return os; +} diff --git a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h index 8dd474c667687e6235a96a191e577163ca194cba..fcb1869f791d9094fd793ff3af721e5fb942f111 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h @@ -1,17 +1,53 @@ #pragma once -#include "../../core/Time.h" +#include <RobotAPI/libraries/armem/core/Commit.h> +#include <RobotAPI/libraries/armem/core/Time.h> -#include "../Commit.h" #include "detail/MemoryItem.h" namespace armarx::armem::base { + + /** + * @brief Default data of an entity instance (empty). + */ + struct NoData + { + }; + + + /** + * @brief Metadata of an entity instance. + */ + struct EntityInstanceMetadata + { + /// Time when this value was created. + Time timeCreated; + /// Time when this value was sent to the memory. + Time timeSent; + /// Time when this value has arrived at the memory. + Time timeArrived; + + /// An optional confidence, may be used for things like decay. + float confidence = 1.0; + + + bool operator==(const EntityInstanceMetadata& other) const; + inline bool operator!=(const EntityInstanceMetadata& other) const + { + return !(*this == other); + } + }; + + std::ostream& operator<<(std::ostream& os, const EntityInstanceMetadata& rhs); + + + /** * @brief Data of a single entity instance. */ - template <class _DerivedT> + template <class _DataT = NoData, class _MetadataT = EntityInstanceMetadata> class EntityInstanceBase : public detail::MemoryItem { @@ -19,19 +55,18 @@ namespace armarx::armem::base public: - using DerivedT = _DerivedT; + using MetadataT = _MetadataT; + using DataT = _DataT; - public: - EntityInstanceBase() { } - EntityInstanceBase(int index, const MemoryID& parentID = {}) : + explicit EntityInstanceBase(int index, const MemoryID& parentID = {}) : EntityInstanceBase(parentID.withInstanceIndex(index)) { } - EntityInstanceBase(const MemoryID& id) : + explicit EntityInstanceBase(const MemoryID& id) : Base(id) { } @@ -46,40 +81,47 @@ namespace armarx::armem::base return id().instanceIndex; } - /** - * @brief Fill `*this` with the update's values. - * @param update The update. - * @param index The instances index. - */ - virtual void update(const EntityUpdate& update, int index) = 0; - virtual bool equalsDeep(const DerivedT& other) const = 0; + EntityInstanceMetadata& metadata() + { + return _metadata; + } + const EntityInstanceMetadata& metadata() const + { + return _metadata; + } - virtual DerivedT copy() const + const DataT& data() const { - DerivedT d; - this->_copySelf(d); - return d; + return _data; } + DataT& data() + { + return _data; + } - std::string getLevelName() const override + + static std::string getLevelName() { return "entity instance"; } - std::string getKeyString() const override + std::string getKeyString() const { return std::to_string(index()); } + protected: - virtual void _copySelf(DerivedT& other) const - { - Base::_copySelf(other); - } + /// The metadata. + MetadataT _metadata; + + /// The data. May be nullptr. + DataT _data; + }; diff --git a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.cpp b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.cpp index 5f7899f50d954f16b2d9c0a9569519529895eb20..72b4c48877c78dce70737fa58c58cd1b82b2d2e5 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.cpp +++ b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.cpp @@ -1 +1,11 @@ #include "EntitySnapshotBase.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + + +void armarx::armem::base::detail::throwIfNotEqual(const Time& ownTime, const Time& updateTime) +{ + ARMARX_CHECK_EQUAL(ownTime, updateTime) + << "Cannot update a snapshot to an update with another timestamp. \n" + << "Note: A snapshot's timestamp must not be changed after construction."; +} diff --git a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h index cf68286be26368cb4821fecbbe241e3ef33e0fbe..7653136447dbe968d3d53f878ba47619481594fc 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h @@ -1,15 +1,19 @@ #pragma once -#include <memory> #include <vector> -#include "../MemoryID.h" -#include "../Time.h" +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/core/Time.h> #include "EntityInstanceBase.h" #include "detail/MemoryContainerBase.h" +#include "detail/iteration_mixins.h" +namespace armarx::armem::base::detail +{ + void throwIfNotEqual(const Time& ownTime, const Time& updateTime); +} namespace armarx::armem::base { /** @@ -34,11 +38,11 @@ namespace armarx::armem::base EntitySnapshotBase() { } - EntitySnapshotBase(Time time, const MemoryID& parentID = {}) : + explicit EntitySnapshotBase(Time time, const MemoryID& parentID = {}) : EntitySnapshotBase(parentID.withTimestamp(time)) { } - EntitySnapshotBase(const MemoryID& id) : + explicit EntitySnapshotBase(const MemoryID& id) : Base(id) { } @@ -49,24 +53,7 @@ namespace armarx::armem::base EntitySnapshotBase& operator=(EntitySnapshotBase&& other) = default; - bool equalsDeep(const EntitySnapshotBase& other) const - { - //std::cout << "EntitySnapshot::equalsDeep" << std::endl; - if (this->size() != other.size()) - { - return false; - } - int i = 0; - for (const auto& instance : this->_container) - { - if (not instance.equalsDeep(other.getInstance(i))) - { - return false; - } - i++; - } - return true; - } + // READING inline Time& time() { @@ -78,34 +65,6 @@ namespace armarx::armem::base return this->id().timestamp; } - - inline const std::vector<EntityInstanceT>& instances() const - { - return this->_container; - } - inline std::vector<EntityInstanceT>& instances() - { - return const_cast<std::vector<EntityInstanceT>&>(const_cast<const EntitySnapshotBase*>(this)->instances()); - } - - - void update(const EntityUpdate& update, std::optional<MemoryID> parentID = std::nullopt) - { - if (parentID) - { - this->id() = *parentID; - } - time() = update.timeCreated; - - this->_container.clear(); - for (int i = 0; i < int(update.instancesData.size()); ++i) - { - EntityInstanceT& data = this->_container.emplace_back(i, this->id()); - data.update(update, i); - } - } - - bool hasInstance(int index) const { size_t si = size_t(index); @@ -122,7 +81,6 @@ namespace armarx::armem::base { return const_cast<EntityInstanceT&>(const_cast<const EntitySnapshotBase*>(this)->getInstance(index)); } - const EntityInstanceT& getInstance(int index) const { if (hasInstance(index)) @@ -135,6 +93,23 @@ namespace armarx::armem::base } } + EntityInstanceT* findInstance(int index) + { + return const_cast<EntityInstanceT*>(const_cast<const EntitySnapshotBase*>(this)->findInstance(index)); + } + const EntityInstanceT* findInstance(int index) const + { + if (hasInstance(index)) + { + return &this->_container[static_cast<size_t>(index)]; + } + else + { + return nullptr; + } + } + + /** * @brief Get the given instance. * @param index The instance's index. @@ -157,6 +132,51 @@ namespace armarx::armem::base } + // ITERATION + + /** + * @param func Function like void process(EntityInstanceT& instance)> + */ + template <class InstanceFunctionT> + bool forEachInstance(InstanceFunctionT&& func) + { + return this->forEachChild(func); + } + /** + * @param func Function like void process (const EntityInstanceT& instance) + */ + template <class InstanceFunctionT> + bool forEachInstance(InstanceFunctionT&& func) const + { + return this->forEachChild(func); + } + + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline const std::vector<EntityInstanceT>& instances() const + { + return this->_container; + } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline std::vector<EntityInstanceT>& instances() + { + return const_cast<std::vector<EntityInstanceT>&>(const_cast<const EntitySnapshotBase*>(this)->instances()); + } + + + // MODIFICATION + + void update(const EntityUpdate& update) + { + detail::throwIfNotEqual(time(), update.timeCreated); + + this->_container.clear(); + for (int index = 0; index < int(update.instancesData.size()); ++index) + { + EntityInstanceT& data = this->_container.emplace_back(index, this->id()); + data.update(update); + } + } + /** * @brief Add a single instance with data. * @param instance The instance. @@ -181,27 +201,49 @@ namespace armarx::armem::base "Cannot add an EntityInstance because its index is too big."); } - int new_index = this->_container.size(); - auto& it = this->_container.emplace_back(std::move(instance)); - it.index() = new_index; - return it; + int index = static_cast<int>(this->_container.size()); + EntityInstanceT& added = this->_container.emplace_back(std::move(instance)); + added.id() = this->id().withInstanceIndex(index); + return added; } EntityInstanceT& addInstance() { - int new_index = this->_container.size(); - auto& it = this->_container.emplace_back(EntityInstanceT());; - it.index() = new_index; - it.id() = this->id().withInstanceIndex(new_index); - return it; + int index = static_cast<int>(this->size()); + EntityInstanceT& added = this->_container.emplace_back(EntityInstanceT()); + added.id() = this->id().withInstanceIndex(index); + return added; } - std::string getKeyString() const override + + // MISC + + bool equalsDeep(const DerivedT& other) const + { + //std::cout << "EntitySnapshot::equalsDeep" << std::endl; + if (this->size() != other.size()) + { + return false; + } + int i = 0; + for (const auto& instance : this->_container) + { + if (not instance.equalsDeep(other.getInstance(i))) + { + return false; + } + i++; + } + return true; + } + + + std::string getKeyString() const { return toDateTimeMilliSeconds(this->time()); } - std::string getLevelName() const override + static std::string getLevelName() { return "entity snapshot"; } diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h index d7c8b8cd203fc8b140cbed0b959110f0868a4b83..9865f6da1398ac78dda2c704eff1d621b00442f4 100644 --- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h +++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h @@ -3,10 +3,9 @@ #include <map> #include <string> -#include <ArmarXCore/core/logging/Logging.h> - #include "CoreSegmentBase.h" #include "detail/EntityContainerBase.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -17,7 +16,11 @@ namespace armarx::armem::base */ template <class _CoreSegmentT, class _Derived> class MemoryBase : - public detail::EntityContainerBase<_CoreSegmentT, typename _CoreSegmentT::ProviderSegmentT::EntityT, _Derived> + public detail::EntityContainerBase<_CoreSegmentT, typename _CoreSegmentT::ProviderSegmentT::EntityT, _Derived>, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived>, + public detail::ForEachEntityMixin<_Derived>, + public detail::ForEachProviderSegmentMixin<_Derived> { using Base = detail::EntityContainerBase<_CoreSegmentT, typename _CoreSegmentT::ProviderSegmentT::EntityT, _Derived>; @@ -57,11 +60,11 @@ namespace armarx::armem::base MemoryBase() { } - MemoryBase(const std::string& name) : + explicit MemoryBase(const std::string& name) : MemoryBase(MemoryID().withMemoryName(name)) { } - MemoryBase(const MemoryID& id) : + explicit MemoryBase(const MemoryID& id) : Base(id) { } @@ -72,6 +75,8 @@ namespace armarx::armem::base MemoryBase& operator=(MemoryBase&& other) = default; + // READ ACCESS + inline const std::string& name() const { return this->id().memoryName; @@ -82,19 +87,14 @@ namespace armarx::armem::base } - inline auto& coreSegments() const - { - return this->_container; - } - inline auto& coreSegments() + bool hasCoreSegment(const std::string& name) const { - return this->_container; + return this->_container.count(name) > 0; } - - bool hasCoreSegment(const std::string& name) const + std::vector<std::string> getCoreSegmentNames() const { - return this->_container.count(name) > 0; + return simox::alg::get_keys(this->_container); } CoreSegmentT& getCoreSegment(const std::string& name) @@ -141,13 +141,13 @@ namespace armarx::armem::base using Base::getEntity; - const EntityT& getEntity(const MemoryID& id) const override + const EntityT& getEntity(const MemoryID& id) const { this->_checkContainerName(id.memoryName, this->name()); return getCoreSegment(id.coreSegmentName).getEntity(id); } - const EntityT* findEntity(const MemoryID& id) const override + const EntityT* findEntity(const MemoryID& id) const { this->_checkContainerName(id.memoryName, this->name()); if (id.hasCoreSegmentName()) @@ -167,32 +167,66 @@ namespace armarx::armem::base } } + + // ITERATION + + /** + * @param func Function like: bool process(CoreSegmentT& coreSeg) + */ + template <class CoreSegmentFunctionT> + bool forEachCoreSegment(CoreSegmentFunctionT&& func) + { + return this->forEachChild(func); + } + /** + * @param func Function like: bool process(const CoreSegmentT& coreSeg) + */ + template <class CoreSegmentFunctionT> + bool forEachCoreSegment(CoreSegmentFunctionT&& func) const + { + return this->forEachChild(func); + } + + // forEachProviderSegment() is provided by ForEachProviderSegmentMixin. + // forEachEntity() is provided by ForEachEntityMixin. + // forEachSnapshot() is provided by ForEachEntitySnapshotMixin. + // forEachInstance() is provided by ForEachEntityInstanceMixin. + + + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline auto& coreSegments() const + { + return this->_container; + } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline auto& coreSegments() + { + return this->_container; + } + + + // MODIFICATION + /** * @brief Add an empty core segment with the given name. * @param name The core segment name. * @param coreSegmentType The core segment type (optional). * @return The added core segment. */ - CoreSegmentT& addCoreSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr coreSegmentType = nullptr) + CoreSegmentT& addCoreSegment( + const std::string& name, aron::typenavigator::ObjectNavigatorPtr coreSegmentType = nullptr) { - return addCoreSegment(CoreSegmentT(name, coreSegmentType)); + return _addCoreSegment(name, name, this->id(), coreSegmentType); } /// Copy and insert a core segment. CoreSegmentT& addCoreSegment(const CoreSegmentT& coreSegment) { - return addCoreSegment(CoreSegmentT(coreSegment)); + return _addCoreSegment(coreSegment.name(), CoreSegmentT(coreSegment)); } /// Move and insert a core segment. CoreSegmentT& addCoreSegment(CoreSegmentT&& coreSegment) { - if (this->_container.count(coreSegment.name()) > 0) - { - throw armem::error::ContainerEntryAlreadyExists(coreSegment.getLevelName(), coreSegment.name(), - this->getLevelName(), this->name()); - } - auto it = this->_container.emplace(coreSegment.name(), std::move(coreSegment)).first; - it->second.id().setMemoryID(this->id()); - return it->second; + return _addCoreSegment(coreSegment.name(), coreSegment); } /** @@ -211,7 +245,7 @@ namespace armarx::armem::base } catch (const armem::error::ContainerEntryAlreadyExists& e) { - ARMARX_INFO << e.what() << "\nIgnoring multiple addition."; + // ARMARX_INFO << e.what() << "\nIgnoring multiple addition."; } } return segments; @@ -226,7 +260,7 @@ namespace armarx::armem::base std::vector<UpdateResult> update(const Commit& commit) { std::vector<UpdateResult> results; - for (const auto& update : commit.updates) + for (const EntityUpdate& update : commit.updates) { results.push_back(this->update(update)); } @@ -242,43 +276,43 @@ namespace armarx::armem::base { this->_checkContainerName(update.entityID.memoryName, this->name()); - auto it = this->_container.find(update.entityID.coreSegmentName); - if (it != this->_container.end()) + auto [inserted, coreSeg] = _addCoreSegmentIfMissing(update.entityID.coreSegmentName); + + // Update entry. + UpdateResult ret(coreSeg->update(update)); + if (inserted) { - UpdateResult ret(it->second.update(update)); - ret.memoryUpdateType = UpdateType::UpdatedExisting; - return ret; + ret.memoryUpdateType = UpdateType::InsertedNew; } else { - throw armem::error::MissingEntry::create<CoreSegmentT>(update.entityID.coreSegmentName, *this); + ret.memoryUpdateType = UpdateType::UpdatedExisting; } + return ret; } + /** * @brief Merge another memory into this one. Append all data * @param m The other memory */ void append(const _Derived& m) { - ARMARX_INFO << "Memory: Merge name '" << m.name() << "' into '" << name() << "'"; + // ARMARX_INFO << "Memory: Merge name '" << m.name() << "' into '" << name() << "'"; - for (const auto& [k, s] : m.container()) + m.forEachCoreSegment([this](const CoreSegmentT & coreSeg) { - if (const auto& it = this->_container.find(k); it != this->_container.end()) + auto it = this->_container.find(coreSeg.name()); + if (it == this->_container.end()) { - // segment already exists - it->second.append(s); + it = this->_container.emplace(coreSeg.name(), this->id().withCoreSegmentName(coreSeg.name())).first; } - else - { - auto wms = this->_container.emplace(k, this->id().withCoreSegmentName(k)); - wms.first->second.append(s); - } - } + it->second.append(coreSeg); + return true; + }); } - virtual bool equalsDeep(const MemoryBase& other) const + bool equalsDeep(const MemoryBase& other) const { //std::cout << "Memory::equalsDeep" << std::endl; if (this->size() != other.size()) @@ -299,14 +333,96 @@ namespace armarx::armem::base return true; } - std::string getLevelName() const override + static std::string getLevelName() { return "memory"; } - std::string getKeyString() const override + std::string getKeyString() const { return this->name(); } + + std::string dump() const + { + std::stringstream ss; + ss << "Memory '" << this->name() << "': \n"; + forEachCoreSegment([&ss](const CoreSegmentT & cseg) + { + ss << "+- Core segment '" << cseg.name() << "' (" << cseg.size() << "): \n"; + cseg.forEachProviderSegment([&ss](const ProviderSegmentT & pseg) + { + ss << "| +- Provider segment '" << pseg.name() << "' (" << pseg.size() << "): \n"; + pseg.forEachEntity([&ss](const EntityT & entity) + { + ss << "| | +- Entity '" << entity.name() << "' (" << entity.size() << "): \n"; + return true; + }); + return true; + }); + return true; + }); + return ss.str(); + } + + + private: + + /** + * This function allows to emplace a CoreSegment directly in the + * container from its constructor arguments, instead of constructing + * it outside and moving it. + * This is necessary if CoreSegmentT is not movable. + */ + template <class ...Args> + CoreSegmentT& _addCoreSegment(const std::string& name, Args... args) + { + auto [it, inserted] = this->_container.try_emplace(name, args...); + if (not inserted) + { + throw armem::error::ContainerEntryAlreadyExists( + CoreSegmentT::getLevelName(), name, DerivedT::getLevelName(), this->name()); + } + else + { + it->second.id().setMemoryID(this->id()); + it->second.id().coreSegmentName = name; + return it->second; + } + } + + + std::pair<bool, CoreSegmentT*> _addCoreSegmentIfMissing(const std::string& coreSegmentName) + { + CoreSegmentT* coreSeg; + + auto it = this->_container.find(coreSegmentName); + if (it == this->_container.end()) + { + if (_addMissingCoreSegmentDuringUpdate) + { + // Insert into map. + coreSeg = &addCoreSegment(coreSegmentName); + return {true, coreSeg}; + } + else + { + throw error::MissingEntry::create<CoreSegmentT>(coreSegmentName, *this); + } + } + else + { + coreSeg = &it->second; + return {false, coreSeg}; + } + } + + + public: + + // ToDo: Remove from base structure - this should be specific to the server versions. + // If necessary at all. + bool _addMissingCoreSegmentDuringUpdate = false; + }; } diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h index 57ff3210244fa516551f4906a2ea07c2cc81f09d..e5163241738a0e8dbba5edbd35f8e5a568060746 100644 --- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h @@ -6,7 +6,7 @@ #include "EntityBase.h" #include "detail/AronTyped.h" #include "detail/EntityContainerBase.h" -#include "detail/MaxHistorySize.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -18,8 +18,9 @@ namespace armarx::armem::base template <class _EntityT, class _Derived> class ProviderSegmentBase : public detail::EntityContainerBase<_EntityT, _EntityT, _Derived>, - public detail::MaxHistorySize, - public detail::AronTyped + public detail::AronTyped, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived> { using Base = detail::EntityContainerBase<_EntityT, _EntityT, _Derived>; @@ -53,15 +54,15 @@ namespace armarx::armem::base { } - ProviderSegmentBase(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : - ProviderSegmentBase(MemoryID().withProviderSegmentName(name), aronType) + explicit ProviderSegmentBase(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : + ProviderSegmentBase(name, MemoryID(), aronType) { } - ProviderSegmentBase(const std::string& name, const MemoryID parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : + explicit ProviderSegmentBase(const std::string& name, const MemoryID parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : ProviderSegmentBase(parentID.withProviderSegmentName(name), aronType) { } - ProviderSegmentBase(const MemoryID id, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : + explicit ProviderSegmentBase(const MemoryID id, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) : Base(id), AronTyped(aronType) { @@ -73,6 +74,8 @@ namespace armarx::armem::base ProviderSegmentBase& operator=(ProviderSegmentBase&& other) = default; + // READ ACCESS + inline const std::string& name() const { return this->id().providerSegmentName; @@ -83,23 +86,18 @@ namespace armarx::armem::base } - inline const auto& entities() const - { - return this->_container; - } - inline auto& entities() + bool hasEntity(const std::string& name) const { - return this->_container; + return this->_container.count(name) > 0; } - - bool hasEntity(const std::string& name) const + std::vector<std::string> getEntityNames() const { - return this->_container.count(name) > 0; + return simox::alg::get_keys(this->_container); } using Base::getEntity; - const EntityT& getEntity(const MemoryID& id) const override + const EntityT& getEntity(const MemoryID& id) const { this->_checkContainerName(id.providerSegmentName, this->getKeyString()); return getEntity(id.entityName); @@ -123,7 +121,7 @@ namespace armarx::armem::base } } - const EntityT* findEntity(const MemoryID& id) const override + const EntityT* findEntity(const MemoryID& id) const { this->_checkContainerName(id.providerSegmentName, this->getKeyString()); auto it = this->_container.find(id.entityName); @@ -137,6 +135,46 @@ namespace armarx::armem::base } } + + // ITERATION + + // All functors are taken as universal reference (F&&). + + /** + * @param func Function like: bool process(EntityT& entity) + */ + template <class EntityFunctionT> + bool forEachEntity(EntityFunctionT&& func) + { + return this->forEachChild(func); + } + /** + * @param func Function like: bool process(const EntityT& entity) + */ + template <class EntityFunctionT> + bool forEachEntity(EntityFunctionT&& func) const + { + return this->forEachChild(func); + } + + // forEachSnapshot() is provided by ForEachEntitySnapshotMixin. + // forEachInstance() is provided by ForEachEntityInstanceMixin. + + + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline const ContainerT& entities() const + { + return this->_container; + } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] + inline ContainerT& entities() + { + return this->_container; + } + + + // MODIFICATION + /** * @brief Updates an entity's history. * @@ -154,7 +192,6 @@ namespace armarx::armem::base { // Add entity entry. entity = &addEntity(update.entityID.entityName); - entity->setMaxHistorySize(_maxHistorySize); updateType = UpdateType::InsertedNew; } else @@ -170,27 +207,24 @@ namespace armarx::armem::base void append(const _Derived& m) { - ARMARX_INFO << "ProviderSegment: Merge name '" << m.name() << "' into '" << name() << "'"; + // ARMARX_INFO << "ProviderSegment: Merge name '" << m.name() << "' into '" << name() << "'"; - for (const auto& [k, s] : m.container()) + m.forEachEntity([this](const EntityT & entity) { - if (const auto& it = this->_container.find(k); it != this->_container.end()) + auto it = this->_container.find(entity.name()); + if (it == this->_container.end()) { - // segment already exists - it->second.append(s); + it = this->_container.emplace(entity.name(), this->id().withEntityName(entity.name())).first; } - else - { - auto wms = this->_container.emplace(k, this->id().withEntityName(k)); - wms.first->second.append(s); - } - } + it->second.append(entity); + return true; + }); } /// Add an empty entity with the given name. EntityT& addEntity(const std::string& name) { - return addEntity(EntityT(name)); + return addEntity(EntityT(name, this->id())); } /// Copy and insert an entity. EntityT& addEntity(const EntityT& entity) @@ -206,22 +240,9 @@ namespace armarx::armem::base } - /** - * @brief Sets the maximum history size of container in this segment. - * This affects all current container as well as new ones. - * @see Entity::setMaxHistorySize() - */ - void setMaxHistorySize(long maxSize) override - { - MaxHistorySize::setMaxHistorySize(maxSize); - for (auto& [name, entity] : this->_container) - { - entity.setMaxHistorySize(maxSize); - } - } + // MISC - - virtual bool equalsDeep(const ProviderSegmentBase& other) const + bool equalsDeep(const DerivedT& other) const { //std::cout << "ProviderSegment::equalsDeep" << std::endl; if (this->size() != other.size()) @@ -243,30 +264,17 @@ namespace armarx::armem::base return true; } - std::string getLevelName() const override + + static std::string getLevelName() { return "provider segment"; } - std::string getKeyString() const override + std::string getKeyString() const { return this->name(); } - - protected: - - virtual void _copySelf(DerivedT& other) const override - { - Base::_copySelf(other); - other.aronType() = _aronType; - } - virtual void _copySelfEmpty(DerivedT& other) const override - { - Base::_copySelfEmpty(other); - other.aronType() = _aronType; - } - }; } diff --git a/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.cpp b/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.cpp index ec7ca0402ad128dc6d342aa28279929c376df557..48147758528cb5ac46baa8a952272ee831ed1e01 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.cpp +++ b/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.cpp @@ -1,5 +1,8 @@ #include "AronTyped.h" +#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> + + namespace armarx::armem::base::detail { diff --git a/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.h b/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.h index fb0ad088fb4fb27ca39cf09f034ea7eb3b202cfe..16233556c83f8febb732824a7001c9b2e8d1e2ac 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.h +++ b/source/RobotAPI/libraries/armem/core/base/detail/AronTyped.h @@ -1,6 +1,6 @@ #pragma once -#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> namespace armarx::armem::base::detail @@ -13,7 +13,7 @@ namespace armarx::armem::base::detail { public: - AronTyped(aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); + explicit AronTyped(aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); bool hasAronType() const; diff --git a/source/RobotAPI/libraries/armem/core/base/detail/EntityContainerBase.h b/source/RobotAPI/libraries/armem/core/base/detail/EntityContainerBase.h index 95993d560c6435fd147ddfc7a2a7aa9267d94855..53cddfff656cdf0fb000323afc4aefcc18c2f50f 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/EntityContainerBase.h +++ b/source/RobotAPI/libraries/armem/core/base/detail/EntityContainerBase.h @@ -1,12 +1,12 @@ #pragma once -#include "../../Commit.h" -#include "../../error/ArMemError.h" +#include <RobotAPI/libraries/armem/core/Commit.h> +#include <RobotAPI/libraries/armem/core/error/ArMemError.h> #include "MemoryContainerBase.h" -#include "../EntityBase.h" -#include "../EntitySnapshotBase.h" +#include <RobotAPI/libraries/armem/core/base/EntityBase.h> +#include <RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h> namespace armarx::armem::base::detail @@ -34,8 +34,9 @@ namespace armarx::armem::base::detail public: - using Base::MemoryContainerBase; - using Base::operator=; + // `using Base::MemoryContainerBase` breaks code completion of QtCreator. + using MemoryContainerBase<std::map<std::string, _ValueT>, _Derived>::MemoryContainerBase; + using MemoryContainerBase<std::map<std::string, _ValueT>, _Derived>::operator=; /** * @brief Retrieve an entity. @@ -43,11 +44,11 @@ namespace armarx::armem::base::detail * @return The entity. * @throw An exception deriving from `armem::error::ArMemError` if the entity is missing. */ + // const EntityT& getEntity(const MemoryID& id) const; EntityT& getEntity(const MemoryID& id) { - return const_cast<EntityT&>(const_cast<const EntityContainerBase*>(this)->getEntity(id)); + return const_cast<EntityT&>(const_cast<const EntityContainerBase*>(this)->_derived().getEntity(id)); } - virtual const EntityT& getEntity(const MemoryID& id) const = 0; /** * @brief Find an entity. @@ -61,7 +62,11 @@ namespace armarx::armem::base::detail * @param id The entities ID. * @return A pointer to the first matching entity or `nullptr` if none was found. */ - virtual const EntityT* findEntity(const MemoryID& id) const = 0; + // const EntityT* findEntity(const MemoryID& id) const; + EntityT* findEntity(const MemoryID& id) + { + return const_cast<EntityT*>(const_cast<const EntityContainerBase*>(this)->_derived().findEntity(id)); + } /** @@ -75,12 +80,12 @@ namespace armarx::armem::base::detail */ EntitySnapshotT& getEntitySnapshot(const MemoryID& id) { - return const_cast<EntitySnapshotT&>(const_cast<const EntityContainerBase*>(this)->getEntitySnapshot(id)); + return const_cast<EntitySnapshotT&>(const_cast<const EntityContainerBase*>(this)->_derived().getEntitySnapshot(id)); } const EntitySnapshotT& getEntitySnapshot(const MemoryID& id) const { - const EntityT& entity = getEntity(id); + const EntityT& entity = _derived().getEntity(id); if (id.hasTimestamp()) { @@ -101,6 +106,19 @@ namespace armarx::armem::base::detail { return getEntitySnapshot(id).getInstance(id); } + + + private: + + DerivedT& _derived() + { + return static_cast<DerivedT&>(*this); + } + const DerivedT& _derived() const + { + return static_cast<const DerivedT&>(*this); + } + }; } diff --git a/source/RobotAPI/libraries/armem/core/base/detail/MaxHistorySize.h b/source/RobotAPI/libraries/armem/core/base/detail/MaxHistorySize.h deleted file mode 100644 index 1fc07ed85e54716d24d2447fa17cb95b291f2766..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/base/detail/MaxHistorySize.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - - - -namespace armarx::armem::base::detail -{ - // TODO: Replace by ConstrainedHistorySize (not only max entries, e.g. delete oldest / delete least accessed / ...) - class MaxHistorySize - { - public: - - virtual ~MaxHistorySize(); - - /** - * @brief Sets the maximum history size of entities in this segment. - * This affects all current entities as well as new ones. - * @see Entity::setMaxHistorySize() - */ - virtual void setMaxHistorySize(long maxSize); - virtual long getMaxHistorySize() const; - - - protected: - - /** - * @brief Maximum size of entity histories. - * - * If negative, the size of `history` is not limited. - * - * @see Entity::maxHstorySize - */ - long _maxHistorySize = -1; - - }; -} diff --git a/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h b/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h index 1a6a216653d243da9613ec967363dc5d44b5c503..4d7cbec1877176f511e854eeefa60a9d6159aded 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h +++ b/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h @@ -3,6 +3,7 @@ #include <RobotAPI/libraries/armem/core/error/ArMemError.h> #include "MemoryItem.h" +#include "iteration_mixins.h" namespace armarx::armem::base::detail @@ -18,16 +19,16 @@ namespace armarx::armem::base::detail using Base = MemoryItem; public: + using DerivedT = _DerivedT; using ContainerT = _ContainerT; public: - MemoryContainerBase() {} - MemoryContainerBase(const MemoryID& id) : + explicit MemoryContainerBase(const MemoryID& id) : MemoryItem(id) { } @@ -48,32 +49,56 @@ namespace armarx::armem::base::detail { return _container.size(); } - bool hasData() const - { - return size() > 0; - } void clear() { return _container.clear(); } + + // ITERATION + + /** + * @param func Function like: bool process(ChildT& provSeg) + */ + template <class ChildFunctionT> + bool forEachChild(ChildFunctionT&& func) + { + return base::detail::forEachChild(this->_container, func); + } + /** + * @param func Function like: bool process(const ChildT& provSeg) + */ + template <class ChildFunctionT> + bool forEachChild(ChildFunctionT&& func) const + { + return base::detail::forEachChild(this->_container, func); + } + + + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] typename ContainerT::const_iterator begin() const { return _container.begin(); } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] typename ContainerT::iterator begin() { return _container.begin(); } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] typename ContainerT::const_iterator end() const { return _container.end(); } + [[deprecated("Direct container access is deprecated. Use forEach*() instead.")]] typename ContainerT::iterator end() { return _container.end(); } + + protected: + const ContainerT& container() const { return _container; @@ -83,24 +108,6 @@ namespace armarx::armem::base::detail return _container; } - // Copying - DerivedT copy() const - { - DerivedT d; - this->_copySelf(d); - return d; - } - - /// Make a copy not containing any elements. - DerivedT copyEmpty() const - { - DerivedT d; - this->_copySelfEmpty(d); - return d; - } - - - protected: /** * @throw `armem::error::ContainerNameMismatch` if `gottenName` does not match `actualName`. @@ -110,21 +117,11 @@ namespace armarx::armem::base::detail { if (!((emptyOk && gottenName.empty()) || gottenName == actualName)) { - throw armem::error::ContainerNameMismatch(gottenName, this->getLevelName(), actualName); + throw armem::error::ContainerNameMismatch( + gottenName, DerivedT::getLevelName(), actualName); } } - virtual void _copySelf(DerivedT& other) const - { - Base::_copySelf(other); - other.container() = _container; - } - - virtual void _copySelfEmpty(DerivedT& other) const - { - Base::_copySelf(other); - } - protected: diff --git a/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.cpp b/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.cpp index a6a9f73e17443091503c09472bc3cee7259644ac..8f4a1920f0a1fcd669b9c3fc2193a617b4dba205 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.cpp +++ b/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.cpp @@ -8,33 +8,15 @@ namespace armarx::armem::base::detail { } + MemoryItem::MemoryItem(const MemoryID& id) : _id(id) { } - /* - MemoryItem::MemoryItem(const MemoryItem& other) : - _id(other.id()) - {} - */ - MemoryItem::~MemoryItem() { } - /* - MemoryItem& MemoryItem::operator=(const MemoryItem& other) - { - other._copySelf(*this); - return *this; - } - */ - - void MemoryItem::_copySelf(MemoryItem& other) const - { - other.id() = id(); - } - } diff --git a/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.h b/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.h index 45226e6327520b7bbddc198364c16c2b8229352c..6aea07121aa201fcbbf0f0b18f46ccc3ab4e2aac 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.h +++ b/source/RobotAPI/libraries/armem/core/base/detail/MemoryItem.h @@ -2,7 +2,7 @@ #include <string> -#include "../../MemoryID.h" +#include <RobotAPI/libraries/armem/core/MemoryID.h> namespace armarx::armem::base::detail @@ -16,18 +16,13 @@ namespace armarx::armem::base::detail public: MemoryItem(); - MemoryItem(const MemoryID& id); + explicit MemoryItem(const MemoryID& id); MemoryItem(const MemoryItem& other) = default; MemoryItem(MemoryItem&& other) = default; MemoryItem& operator=(const MemoryItem& other) = default; MemoryItem& operator=(MemoryItem&& other) = default; - virtual ~MemoryItem(); - - - //MemoryItem& operator=(const MemoryItem& other); - inline MemoryID& id() { @@ -39,19 +34,11 @@ namespace armarx::armem::base::detail } - // Introspection - - /// Get a string version of `*this`' key. - virtual std::string getKeyString() const = 0; - - /// Get a readable name of this level for messages, errors etc. - virtual std::string getLevelName() const = 0; - - protected: - /// Copy `*this` to `other`. - virtual void _copySelf(MemoryItem& other) const; + // Protected so we get a compile error if someone tries to destruct a MemoryItem + // instead of a derived type. + ~MemoryItem(); protected: diff --git a/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.cpp b/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.cpp new file mode 100644 index 0000000000000000000000000000000000000000..459cd4d5c7bd694bcb289496352d7e2cad4966cd --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.cpp @@ -0,0 +1,7 @@ +#include "iteration_mixins.h" + + +namespace armarx::armem::base::detail +{ + +} diff --git a/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.h b/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.h new file mode 100644 index 0000000000000000000000000000000000000000..c923a857e1d016b06b313f7e860ab57ec438a9d4 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.h @@ -0,0 +1,214 @@ +#pragma once + +#include <type_traits> + + +namespace armarx::armem::base::detail +{ + + // Helper functions to implement the forEach*() method at the current level. + + // Handle functions with different return type. + template <class FunctionT, class ChildT> + bool call(FunctionT&& func, ChildT&& child) + { + if constexpr(std::is_same_v<decltype(func(child)), bool>) + { + if (!func(child)) + { + return false; + } + return true; + } + else + { + func(child); + return true; + } + } + + + // Single-valued containers. + template <class ContainerT, class FunctionT> + bool forEachChildSingle(ContainerT& container, FunctionT&& func) + { + for (auto& child : container) + { + if (not call(func, child)) + { + return false; + } + } + return true; + } + + + // Pair-valued containers. + template <class ContainerT, class FunctionT> + bool forEachChildPair(ContainerT& container, FunctionT&& func) + { + for (auto& [_, child] : container) + { + if (not call(func, child)) + { + return false; + } + } + return true; + } + + + // see: https://en.cppreference.com/w/cpp/types/void_t + + // primary template handles types that have no nested ::type member: + template< class, class = void > + struct has_mapped_type : std::false_type { }; + + // specialization recognizes types that do have a nested ::type member: + template< class T > + struct has_mapped_type<T, std::void_t<typename T::mapped_type>> : std::true_type { }; + + + template <class ContainerT, class FunctionT> + bool forEachChild(ContainerT& container, FunctionT&& func) + { + if constexpr(has_mapped_type<ContainerT>::value) + { + return forEachChildPair(container, func); + } + else + { + return forEachChildSingle(container, func); + } + } + + + // We use auto instead of, e.g. DerivedT::EntitySnapshotT, + // as we cannot use the typedef before DerivedT was completely defined. + + template <class DerivedT> + struct ForEachEntityInstanceMixin + { + // not: using EntitySnapshotT = typename DerivedT::EntitySnapshotT; + + /** + * @param func Function like: bool process(EntityInstanceT& instance)> + */ + template <class InstanceFunctionT> + bool forEachInstance(InstanceFunctionT&& func) + { + return static_cast<DerivedT*>(this)->forEachSnapshot( + [&func](auto & snapshot) -> bool + { + return snapshot.forEachInstance(func); + }); + } + + /** + * @param func Function like: bool process(const EntityInstanceT& instance) + */ + template <class InstanceFunctionT> + bool forEachInstance(InstanceFunctionT&& func) const + { + return static_cast<const DerivedT*>(this)->forEachSnapshot( + [&func](const auto & snapshot) -> bool + { + return snapshot.forEachInstance(func); + }); + } + }; + + + template <class DerivedT> + struct ForEachEntitySnapshotMixin + { + /** + * @param func Function like: bool process(EntitySnapshotT& snapshot)> + */ + template <class SnapshotFunctionT> + bool forEachSnapshot(SnapshotFunctionT&& func) + { + return static_cast<DerivedT*>(this)->forEachEntity( + [&func](auto & entity) -> bool + { + return entity.forEachSnapshot(func); + }); + } + + /** + * @param func Function like: bool process(const EntitySnapshotT& snapshot) + */ + template <class SnapshotFunctionT> + bool forEachSnapshot(SnapshotFunctionT&& func) const + { + return static_cast<const DerivedT*>(this)->forEachEntity( + [&func](const auto & entity) -> bool + { + return entity.forEachSnapshot(func); + }); + } + }; + + + template <class DerivedT> + struct ForEachEntityMixin + { + /** + * @param func Function like: bool process(EntityT& entity)> + */ + template <class FunctionT> + bool forEachEntity(FunctionT&& func) + { + return static_cast<DerivedT*>(this)->forEachProviderSegment( + [&func](auto & providerSegment) -> bool + { + return providerSegment.forEachEntity(func); + }); + } + + /** + * @param func Function like: bool process(const EntityT& entity) + */ + template <class FunctionT> + bool forEachEntity(FunctionT&& func) const + { + return static_cast<const DerivedT*>(this)->forEachProviderSegment( + [&func](const auto & providerSegment) -> bool + { + return providerSegment.forEachEntity(func); + }); + } + }; + + + template <class DerivedT> + struct ForEachProviderSegmentMixin + { + /** + * @param func Function like: bool process(ProviderSegmentT& providerSegment)> + */ + template <class FunctionT> + bool forEachProviderSegment(FunctionT&& func) + { + return static_cast<DerivedT*>(this)->forEachCoreSegment( + [&func](auto & coreSegment) -> bool + { + return coreSegment.forEachProviderSegment(func); + }); + } + + /** + * @param func Function like: bool process(const ProviderSegmentT& providerSegment) + */ + template <class FunctionT> + bool forEachProviderSegment(FunctionT&& func) const + { + return static_cast<const DerivedT*>(this)->forEachCoreSegment( + [&func](const auto & coreSegment) -> bool + { + return coreSegment.forEachProviderSegment(func); + }); + } + }; + +} diff --git a/source/RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.cpp b/source/RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1875ff53545a3d2574cf9764a14d321946e5514 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.cpp @@ -0,0 +1,17 @@ +#include "negative_index_semantics.h" + +#include <algorithm> + + +size_t armarx::armem::base::detail::negativeIndexSemantics(long index, size_t size) +{ + const size_t max = size > 0 ? size - 1 : 0; + if (index >= 0) + { + return std::clamp<size_t>(static_cast<size_t>(index), 0, max); + } + else + { + return static_cast<size_t>(std::clamp<long>(static_cast<long>(size) + index, 0, static_cast<long>(max))); + } +} diff --git a/source/RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.h b/source/RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.h new file mode 100644 index 0000000000000000000000000000000000000000..4efe169276c83ff12c13400e6de162a8b4db5d8d --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.h @@ -0,0 +1,11 @@ +#pragma once + +#include <stddef.h> + + +namespace armarx::armem::base::detail +{ + + size_t negativeIndexSemantics(long index, size_t size); + +} diff --git a/source/RobotAPI/libraries/armem/core/base/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/base/ice_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48c084154c41b26b174504d2565fe57d3a49d55a --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/base/ice_conversions.cpp @@ -0,0 +1,78 @@ +#include "ice_conversions.h" + +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> +#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> + +#include <RobotAPI/libraries/armem/core/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h> + + +namespace armarx::armem::base +{ + + void detail::toIceItem(data::detail::MemoryItem& ice, const armem::base::detail::MemoryItem& item) + { + toIce(ice.id, item.id()); + } + void detail::fromIceItem(const data::detail::MemoryItem& ice, armem::base::detail::MemoryItem& item) + { + fromIce(ice.id, item.id()); + } + + + void detail::toIce(aron::data::AronDictPtr& ice, const aron::datanavigator::DictNavigatorPtr& data) + { + ice = data ? data->toAronDictPtr() : nullptr; + } + void detail::fromIce(const aron::data::AronDictPtr& ice, aron::datanavigator::DictNavigatorPtr& data) + { + if (ice) + { + data = aron::datanavigator::DictNavigator::FromAronDictPtr(ice); + } + else + { + data = nullptr; + }; + } + + void detail::toIce(aron::type::AronTypePtr& ice, const aron::typenavigator::ObjectNavigatorPtr& bo) + { + ice = bo ? bo->toAronPtr() : nullptr; + } + void detail::fromIce(const aron::type::AronTypePtr& ice, aron::typenavigator::ObjectNavigatorPtr& bo) + { + bo = ice + ? aron::typenavigator::ObjectNavigator::DynamicCastAndCheck(aron::typenavigator::Navigator::FromAronType(ice)) + : nullptr; + } + +} +namespace armarx::armem +{ + void base::toIce(data::EntityInstanceMetadata& ice, const EntityInstanceMetadata& metadata) + { + ice.confidence = metadata.confidence; + toIce(ice.timeArrivedMicroSeconds, metadata.timeArrived); + toIce(ice.timeCreatedMicroSeconds, metadata.timeCreated); + toIce(ice.timeSentMicroSeconds, metadata.timeSent); + } + void base::fromIce(const data::EntityInstanceMetadata& ice, EntityInstanceMetadata& metadata) + { + metadata.confidence = ice.confidence; + fromIce(ice.timeArrivedMicroSeconds, metadata.timeArrived); + fromIce(ice.timeCreatedMicroSeconds, metadata.timeCreated); + fromIce(ice.timeSentMicroSeconds, metadata.timeSent); + } + + + void base::toIce(data::EntityInstanceMetadataPtr& ice, const EntityInstanceMetadata& metadata) + { + armem::toIce<data::EntityInstanceMetadata>(ice, metadata); + } + void base::fromIce(const data::EntityInstanceMetadataPtr& ice, EntityInstanceMetadata& metadata) + { + armem::fromIce<data::EntityInstanceMetadata>(ice, metadata); + } + +} diff --git a/source/RobotAPI/libraries/armem/core/base/ice_conversions.h b/source/RobotAPI/libraries/armem/core/base/ice_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..646754cc4cbfc3d61c0ce0b1e19c333ee2d7f92b --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/base/ice_conversions.h @@ -0,0 +1,195 @@ +#pragma once + +#include "EntityInstanceBase.h" +#include "EntitySnapshotBase.h" +#include "EntityBase.h" +#include "ProviderSegmentBase.h" +#include "CoreSegmentBase.h" +#include "MemoryBase.h" + +#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h> +#include <RobotAPI/libraries/armem/core/ice_conversions.h> + +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> + +#include <RobotAPI/interface/armem/memory.h> + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + + +namespace armarx::armem::base::detail +{ + void toIceItem(data::detail::MemoryItem& ice, const MemoryItem& item); + void fromIceItem(const data::detail::MemoryItem& ice, MemoryItem& item); + + void toIce(aron::data::AronDictPtr& ice, const aron::datanavigator::DictNavigatorPtr& bo); + void fromIce(const aron::data::AronDictPtr& ice, aron::datanavigator::DictNavigatorPtr& bo); + + void toIce(aron::type::AronTypePtr& ice, const aron::typenavigator::ObjectNavigatorPtr& bo); + void fromIce(const aron::type::AronTypePtr& ice, aron::typenavigator::ObjectNavigatorPtr& bo); +} +namespace armarx::armem::base +{ + void toIce(data::EntityInstanceMetadata& ice, const EntityInstanceMetadata& metadata); + void fromIce(const data::EntityInstanceMetadata& ice, EntityInstanceMetadata& metadata); + + void toIce(data::EntityInstanceMetadataPtr& ice, const EntityInstanceMetadata& metadata); + void fromIce(const data::EntityInstanceMetadataPtr& ice, EntityInstanceMetadata& metadata); + + + template <class ...Args> + void toIce(data::EntityInstance& ice, const EntityInstanceBase<Args...>& data) + { + detail::toIceItem(ice, data); + + // detail::toIce(std::ref(ice.data).get(), data.data()); + detail::toIce(ice.data, data.data()); + toIce(ice.metadata, data.metadata()); + } + template <class ...Args> + void fromIce(const data::EntityInstance& ice, EntityInstanceBase<Args...>& data) + { + detail::fromIceItem(ice, data); + + detail::fromIce(ice.data, data.data()); + fromIce(ice.metadata, data.metadata()); + } + + template <class ...Args> + void toIce(data::EntitySnapshot& ice, const EntitySnapshotBase<Args...>& snapshot) + { + detail::toIceItem(ice, snapshot); + + ice.instances.clear(); + snapshot.forEachInstance([&ice](const auto & instance) + { + armem::toIce(ice.instances.emplace_back(), instance); + }); + } + template <class ...Args> + void fromIce(const data::EntitySnapshot& ice, EntitySnapshotBase<Args...>& snapshot) + { + detail::fromIceItem(ice, snapshot); + + snapshot.clear(); + for (const data::EntityInstancePtr& iceInstance : ice.instances) + { + snapshot.addInstance(armem::fromIce<typename EntitySnapshotBase<Args...>::EntityInstanceT>(iceInstance)); + } + } + + template <class ...Args> + void toIce(data::Entity& ice, const EntityBase<Args...>& entity) + { + detail::toIceItem(ice, entity); + + ice.history.clear(); + entity.forEachSnapshot([&ice](const auto & snapshot) + { + armem::toIce(ice.history[armem::toIce<long>(snapshot.time())], snapshot); + }); + } + template <class ...Args> + void fromIce(const data::Entity& ice, EntityBase<Args...>& entity) + { + detail::fromIceItem(ice, entity); + + entity.clear(); + for (const auto& [key, snapshot] : ice.history) + { + entity.addSnapshot(armem::fromIce<typename EntityBase<Args...>::EntitySnapshotT>(snapshot)); + } + } + + + template <class ...Args> + void toIce(data::ProviderSegment& ice, const ProviderSegmentBase<Args...>& providerSegment) + { + detail::toIceItem(ice, providerSegment); + + detail::toIce(ice.aronType, providerSegment.aronType()); + ARMARX_CHECK(!providerSegment.aronType() || ice.aronType); + + // toIce(ice.entities, providerSegment.entities()); + ice.entities.clear(); + providerSegment.forEachEntity([&ice](const auto & entity) + { + armem::toIce(ice.entities[entity.name()], entity); + }); + } + template <class ...Args> + void fromIce(const data::ProviderSegment& ice, ProviderSegmentBase<Args...>& providerSegment) + { + detail::fromIceItem(ice, providerSegment); + + detail::fromIce(ice.aronType, providerSegment.aronType()); + ARMARX_CHECK(!providerSegment.aronType() || ice.aronType); + + // fromIce(ice.entities, providerSegment.entities()); + providerSegment.clear(); + for (const auto& [key, entity] : ice.entities) + { + providerSegment.addEntity( + armem::fromIce<typename ProviderSegmentBase<Args...>::EntityT>(entity)); + } + } + + template <class ...Args> + void toIce(data::CoreSegment& ice, const CoreSegmentBase<Args...>& coreSegment) + { + detail::toIceItem(ice, coreSegment); + + detail::toIce(ice.aronType, coreSegment.aronType()); + ARMARX_CHECK(!coreSegment.aronType() || ice.aronType); + + // toIce(ice.providerSegments, coreSegment.providerSegments()); + ice.providerSegments.clear(); + coreSegment.forEachProviderSegment([&ice](const auto & providerSegment) + { + armem::toIce(ice.providerSegments[providerSegment.name()], providerSegment); + return true; + }); + } + template <class ...Args> + void fromIce(const data::CoreSegment& ice, CoreSegmentBase<Args...>& coreSegment) + { + detail::fromIceItem(ice, coreSegment); + + detail::fromIce(ice.aronType, coreSegment.aronType()); + ARMARX_CHECK(!coreSegment.aronType() || ice.aronType); + + // fromIce(ice.providerSegments, coreSegment.providerSegments()); + coreSegment.clear(); + for (const auto& [key, providerSegment] : ice.providerSegments) + { + coreSegment.addProviderSegment( + armem::fromIce<typename CoreSegmentBase<Args...>::ProviderSegmentT>(providerSegment)); + } + } + + template <class ...Args> + void toIce(data::Memory& ice, const MemoryBase<Args...>& memory) + { + base::detail::toIceItem(ice, memory); + + ice.coreSegments.clear(); + memory.forEachCoreSegment([&ice](const auto & coreSegment) + { + armem::toIce(ice.coreSegments[coreSegment.name()], coreSegment); + return true; + }); + } + template <class ...Args> + void fromIce(const data::Memory& ice, MemoryBase<Args...>& memory) + { + base::detail::fromIceItem(ice, memory); + + memory.clear(); + for (const auto& [key, coreSegment] : ice.coreSegments) + { + // We can avoid using CoreSegment's copy constructor this way: + armem::fromIce(coreSegment, memory.addCoreSegment(coreSegment->id.coreSegmentName)); + } + } + +} diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp index 0f1bd0be881f477908464bcda5a4a858afb54488..204aa8f86e20d99df852abbdc79be3d1a07ef39f 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp +++ b/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp @@ -78,9 +78,9 @@ namespace armarx::armem::d_ltm std::filesystem::create_directories(_fullPath()); TypeIO::writeAronType(_aronType, _fullPath()); - for (const auto& [k, s] : m) + m.forEachProviderSegment([this](const wm::ProviderSegment & s) { - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(s.name()); it != _container.end()) { it->second.append(s); } @@ -88,18 +88,19 @@ namespace armarx::armem::d_ltm { try { - std::filesystem::create_directory(_fullPath() / k); + std::filesystem::create_directory(_fullPath() / s.name()); } catch (...) { ARMARX_WARNING << GetHandledExceptionString(); - return; + return false; } - auto wms = _container.emplace(std::make_pair(k, id().withProviderSegmentName(k))); + auto wms = _container.emplace(s.name(), id().withProviderSegmentName(s.name())); wms.first->second.path = path; wms.first->second.append(s); } - } + return true; + }); } } diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.h b/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.h index 76bb297e76d268ce8517449686ffae1cdb3ed2cd..2d8bd8f29e7027ea63b797d0a19f4b96e116898e 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.h +++ b/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.h @@ -2,8 +2,8 @@ #include <filesystem> -#include "../base/CoreSegmentBase.h" -#include "../workingmemory/CoreSegment.h" +#include <RobotAPI/libraries/armem/core/base/CoreSegmentBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "ProviderSegment.h" @@ -22,7 +22,6 @@ namespace armarx::armem::d_ltm public: using Base::CoreSegmentBase; - using Base::operator=; // Conversion diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp index 5d784a097de4ef68ec2df0bdc1adce94fa737809..d4d0ac233f1fac1e910869f56cc12541928798ce 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp +++ b/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp @@ -1,5 +1,8 @@ #include "Entity.h" +#include <ArmarXCore/core/logging/Logging.h> + + namespace armarx::armem::d_ltm { std::filesystem::path Entity::_fullPath() const @@ -63,20 +66,21 @@ namespace armarx::armem::d_ltm void Entity::append(const wm::Entity& m) { std::filesystem::create_directories(_fullPath()); - for (const auto& [k, s] : m.container()) + m.forEachSnapshot([this](const wm::EntitySnapshot & s) { - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(s.time()); it != _container.end()) { // timestamp already exists // We assume that a snapshot does not change, so ignore } else { - std::filesystem::create_directory(_fullPath() / std::to_string(k.toMicroSeconds())); - auto wms = _container.emplace(std::make_pair(k, id().withTimestamp(k))); + std::filesystem::create_directory(_fullPath() / std::to_string(s.time().toMicroSeconds())); + auto wms = _container.emplace(std::make_pair(s.time(), id().withTimestamp(s.time()))); wms.first->second.path = path; wms.first->second.setTo(s); } - } + return true; + }); } } diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/Entity.h b/source/RobotAPI/libraries/armem/core/diskmemory/Entity.h index 35022275570c93378cbe0c767aad1776da594838..63011ceff58a0ec7ff4b77bf2afeaa0252bbcec0 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/Entity.h +++ b/source/RobotAPI/libraries/armem/core/diskmemory/Entity.h @@ -2,8 +2,8 @@ #include <filesystem> -#include "../base/EntityBase.h" -#include "../workingmemory/Entity.h" +#include <RobotAPI/libraries/armem/core/base/EntityBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "EntitySnapshot.h" @@ -38,7 +38,6 @@ namespace armarx::armem::d_ltm public: using Base::EntityBase; - using Base::operator=; // Conversion diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp index dd0458b83bbb8ed461ddeab50af42181fda843e4..56786756655453bb97952a206ff642b9f65174cb 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp +++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp @@ -1,22 +1,22 @@ #include "EntityInstance.h" -#include <iostream> -#include <fstream> +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/json_conversions.h> -#include "../../core/error.h" -#include "ArmarXCore/core/exceptions/LocalException.h" +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <SimoxUtility/json/json.hpp> + +#include <iostream> +#include <fstream> + + namespace armarx::armem::d_ltm { - EntityInstance::EntityInstance(const EntityInstance& other) : - Base(other), - path(other.path) - { - } - bool EntityInstance::equalsDeep(const EntityInstance& other) const { return id() == other.id(); @@ -24,25 +24,11 @@ namespace armarx::armem::d_ltm - void EntityInstance::update(const EntityUpdate& update, int index) - { - ARMARX_CHECK_FITS_SIZE(index, update.instancesData.size()); - - this->index() = index; - } - - EntityInstance EntityInstance::copy() const + void EntityInstance::update(const EntityUpdate& update) { - EntityInstance d; - this->_copySelf(d); - return d; + ARMARX_CHECK_FITS_SIZE(this->index(), update.instancesData.size()); } - void EntityInstance::_copySelf(EntityInstance& other) const - { - EntityInstanceBase<EntityInstance>::_copySelf(other); - other.path = path; - } std::filesystem::path EntityInstance::_fullPath() const { diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h index 89b96c011fcccb6bfc5471850185b0cea49f77b0..c56a944f264c08e1f26b35df1ecb622dff92c0e6 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h +++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h @@ -2,11 +2,10 @@ #include <filesystem> -#include "../base/EntityInstanceBase.h" -#include "../workingmemory/EntityInstance.h" +#include <RobotAPI/libraries/armem/core/base/EntityInstanceBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -#include "../workingmemory/entityInstance_conversions.h" -#include "../workingmemory/json_conversions.h" +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> namespace armarx::armem::d_ltm @@ -15,30 +14,24 @@ namespace armarx::armem::d_ltm * @brief Data of a single entity instance. */ class EntityInstance : - public base::EntityInstanceBase<EntityInstance> + public base::EntityInstanceBase<base::NoData, base::NoData> { - using Base = base::EntityInstanceBase<EntityInstance>; + using Base = base::EntityInstanceBase<base::NoData, base::NoData>; public: using Base::EntityInstanceBase; - EntityInstance(const EntityInstance& other); - EntityInstance(EntityInstance&& other) = default; - EntityInstance& operator=(const EntityInstance& other) = default; - EntityInstance& operator=(EntityInstance&& other) = default; - /** * @brief Fill `*this` with the update's values. * @param update The update. * @param index The instances index. */ - virtual void update(const EntityUpdate& update, int index) override; + void update(const EntityUpdate& update); - virtual bool equalsDeep(const EntityInstance& other) const override; + bool equalsDeep(const EntityInstance& other) const; - virtual EntityInstance copy() const override; // Conversion wm::EntityInstance convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const; @@ -47,8 +40,6 @@ namespace armarx::armem::d_ltm void reload(const std::shared_ptr<std::filesystem::path>&); void setTo(const wm::EntityInstance&); - protected: - virtual void _copySelf(EntityInstance& other) const override; private: std::filesystem::path _fullPath() const; diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.cpp index ab5b56d2274f78c350818693c269af18f0a4a979..9354ab7d52e0dcbd058aec022892132b753b51ab 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.cpp +++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.cpp @@ -83,7 +83,7 @@ namespace armarx::armem::d_ltm _container.clear(); int i = 0; - for (const auto& s : m.instances()) + m.forEachInstance([this, &i](wm::EntityInstance & s) { try { @@ -92,12 +92,14 @@ namespace armarx::armem::d_ltm catch (...) { ARMARX_WARNING << GetHandledExceptionString(); - continue;; + return true; } auto& wms = _container.emplace_back(id().withInstanceIndex(i++)); wms.path = path; wms.setTo(s); - } + + return true; + }); } } diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.h index 545a8c0d64641c65e7faf7aa26dea77ee9865e0c..9587e3be44435814d4709979a1fb394c67b953c7 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.h +++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntitySnapshot.h @@ -2,11 +2,13 @@ #include <filesystem> -#include "../base/EntitySnapshotBase.h" -#include "../workingmemory/EntitySnapshot.h" +#include <RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "EntityInstance.h" +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> + namespace armarx::armem::d_ltm { @@ -22,7 +24,6 @@ namespace armarx::armem::d_ltm public: using Base::EntitySnapshotBase; - using Base::operator=; // Conversion diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp index 0fb6fba92b2ebc116787bffba2d7ed5bc743227b..3fc60e0496aa21c441cf5e8a60443e43ef741a46 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp +++ b/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp @@ -65,9 +65,9 @@ namespace armarx::armem::d_ltm void Memory::append(const wm::Memory& m) { std::filesystem::create_directories(_fullPath()); - for (const auto& [k, s] : m.container()) + m.forEachCoreSegment([this](const wm::CoreSegment & s) -> bool { - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(s.name()); it != _container.end()) { it->second.append(s); } @@ -75,18 +75,20 @@ namespace armarx::armem::d_ltm { try { - std::filesystem::create_directory(_fullPath() / k); + std::filesystem::create_directory(_fullPath() / s.name()); } catch (...) { ARMARX_WARNING << GetHandledExceptionString(); - return; + return false; } - auto wms = _container.emplace(k, id().withCoreSegmentName(k)); + auto wms = _container.emplace(s.name(), id().withCoreSegmentName(s.name())); wms.first->second.path = path; wms.first->second.append(s); } - } + + return true; + }); } } diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/Memory.h b/source/RobotAPI/libraries/armem/core/diskmemory/Memory.h index 7f7872f7a638cc31122f09b00a95755ede4d9606..aaa1e460a5bff94195ae6da7662a7e53b33861e4 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/Memory.h +++ b/source/RobotAPI/libraries/armem/core/diskmemory/Memory.h @@ -2,8 +2,8 @@ #include <filesystem> -#include "../base/MemoryBase.h" -#include "../workingmemory/Memory.h" +#include <RobotAPI/libraries/armem/core/base/MemoryBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "CoreSegment.h" @@ -22,7 +22,6 @@ namespace armarx::armem::d_ltm public: using Base::MemoryBase; - using Base::operator=; // Conversion diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp index 620e819f6b1fc05d4aeadc285edb087f5ea0e119..08ed0c2b07edc156764f02dc88c5f76160f9d355 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp +++ b/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp @@ -95,9 +95,9 @@ namespace armarx::armem::d_ltm TypeIO::writeAronType(_aronType, _fullPath()); - for (const auto& [k, s] : m.container()) + m.forEachEntity([this](const wm::Entity & s) { - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(s.name()); it != _container.end()) { it->second.append(s); } @@ -106,18 +106,20 @@ namespace armarx::armem::d_ltm try { - std::filesystem::create_directory(_fullPath() / k); + std::filesystem::create_directory(_fullPath() / s.name()); } catch (...) { ARMARX_WARNING << GetHandledExceptionString(); - return; + return false; } - auto wms = _container.emplace(k, id().withEntityName(k)); + auto wms = _container.emplace(s.name(), id().withEntityName(s.name())); wms.first->second.path = path; wms.first->second.append(s); } - } + + return true; + }); } } diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.h b/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.h index 8ad96ea0630af0d5aba8b7270fe229c235c2a010..0e866b08cc5c50f623fd9b5676136834078c953a 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.h +++ b/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.h @@ -2,8 +2,8 @@ #include <filesystem> -#include "../base/ProviderSegmentBase.h" -#include "../workingmemory/ProviderSegment.h" +#include <RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "Entity.h" @@ -22,7 +22,6 @@ namespace armarx::armem::d_ltm public: using Base::ProviderSegmentBase; - using Base::operator=; // Conversion diff --git a/source/RobotAPI/libraries/armem/core/error/ArMemError.h b/source/RobotAPI/libraries/armem/core/error/ArMemError.h index e6843d13be5bc07e71d90b00cf6a911ca717e524..219d489fad038da1098d724bddd9e2bc74b0a5d7 100644 --- a/source/RobotAPI/libraries/armem/core/error/ArMemError.h +++ b/source/RobotAPI/libraries/armem/core/error/ArMemError.h @@ -84,8 +84,8 @@ namespace armarx::armem::error template <class MissingT, class ContainerT> static MissingEntry create(const std::string& missingKey, const ContainerT& container) { - return MissingEntry(MissingT().getLevelName(), missingKey, - container.getLevelName(), container.getKeyString(), container.size()); + return MissingEntry(MissingT::getLevelName(), missingKey, + ContainerT::getLevelName(), container.getKeyString(), container.size()); } diff --git a/source/RobotAPI/libraries/armem/core/forward_declarations.h b/source/RobotAPI/libraries/armem/core/forward_declarations.h new file mode 100644 index 0000000000000000000000000000000000000000..e39274b7c332fe7ee4b0505c3aa7bce8c5c0a8ca --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/forward_declarations.h @@ -0,0 +1,58 @@ +#pragma once + + +namespace IceUtil +{ + class Time; +} + +namespace armarx::armem +{ + using Time = IceUtil::Time; + using Duration = IceUtil::Time; + + class MemoryID; + class Commit; + class EntityUpdate; + class CommitResult; + class EntityUpdateResult; +} + +namespace armarx::armem::base +{ + struct NoData; + struct EntityInstanceMetadata; + + template <class _DataT, class _MetadataT> + class EntityInstanceBase; + template <class _EntityInstanceT, class _Derived> + class EntitySnapshotBase; + template <class _EntitySnapshotT, class _Derived> + class EntityBase; + template <class _EntityT, class _Derived> + class ProviderSegmentBase; + template <class _ProviderSegmentT, class _Derived> + class CoreSegmentBase; + template <class _CoreSegmentT, class _Derived> + class MemoryBase; +} + +namespace armarx::armem::wm +{ + class EntityInstance; + class EntitySnapshot; + class Entity; + class ProviderSegment; + class CoreSegment; + class Memory; +} + +namespace armarx::armem::server::wm +{ + using EntityInstance = armem::wm::EntityInstance; + using EntitySnapshot = armem::wm::EntitySnapshot; + class Entity; + class ProviderSegment; + class CoreSegment; + class Memory; +} diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/ice_conversions.cpp index d79acf1da2b86f94414205131173797e0354bc24..cca45a3b2cf04f26ec76d158e9cf1e711bbfecb2 100644 --- a/source/RobotAPI/libraries/armem/core/ice_conversions.cpp +++ b/source/RobotAPI/libraries/armem/core/ice_conversions.cpp @@ -1,20 +1,20 @@ #include "ice_conversions.h" +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> -namespace armarx + +void IceUtil::toIce(long& ice, const IceUtil::Time& time) { + ice = time.toMicroSeconds(); +} - /* - void armem::fromIce(long ice, Time& time) - { - time = Time::microSeconds(ice); - } +void IceUtil::fromIce(const long& ice, IceUtil::Time& time) +{ + time = Time::microSeconds(ice); +} - void armem::toIce(long& ice, const Time& time) - { - ice = time.toMicroSeconds(); - } - */ +namespace armarx +{ void armem::toIce(data::MemoryID& ice, const MemoryID& id) { @@ -144,14 +144,5 @@ namespace armarx update.timeArrived = timeArrived; } - - void armem::detail::toIceItem(data::detail::MemoryItem& ice, const armem::base::detail::MemoryItem& item) - { - toIce(ice.id, item.id()); - } - - void armem::detail::fromIceItem(const data::detail::MemoryItem& ice, armem::base::detail::MemoryItem& item) - { - fromIce(ice.id, item.id()); - } } + diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions.h b/source/RobotAPI/libraries/armem/core/ice_conversions.h index 874684cac2a6a52b8742c36dcc2bdea8346e1586..e8f104fe04ebcb721b0ffbf4b70b18ada0af234c 100644 --- a/source/RobotAPI/libraries/armem/core/ice_conversions.h +++ b/source/RobotAPI/libraries/armem/core/ice_conversions.h @@ -6,29 +6,21 @@ #include "ice_conversions_templates.h" #include "Commit.h" -#include "base/detail/MemoryItem.h" +#include "MemoryID.h" +#include "Time.h" namespace IceUtil { // Define in original namespace to allow ADL. - inline void toIce(long& ice, const Time& time) - { - ice = time.toMicroSeconds(); - } - inline void fromIce(const long& ice, Time& time) - { - time = Time::microSeconds(ice); - } + void toIce(long& ice, const Time& time); + void fromIce(const long& ice, Time& time); } namespace armarx::armem { - // void fromIce(long ice, Time& time); - // void toIce(long& ice, const Time& time); - void fromIce(const data::MemoryID& ice, MemoryID& id); void toIce(data::MemoryID& ice, const MemoryID& id); @@ -51,12 +43,5 @@ namespace armarx::armem void fromIce(const data::Commit& ice, Commit& commit, Time timeArrived); void fromIce(const data::EntityUpdate& ice, EntityUpdate& update, Time timeArrived); - - namespace detail - { - void toIceItem(data::detail::MemoryItem& ice, const armem::base::detail::MemoryItem& item); - void fromIceItem(const data::detail::MemoryItem& ice, armem::base::detail::MemoryItem& item); - } - } diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions_boost_templates.h b/source/RobotAPI/libraries/armem/core/ice_conversions_boost_templates.h new file mode 100644 index 0000000000000000000000000000000000000000..7b6681236bc3d0517d6fd61656a1dc598a8d6a36 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/ice_conversions_boost_templates.h @@ -0,0 +1,34 @@ +#pragma once + +#include <map> + +#include <boost/container/flat_map.hpp> + + +namespace armarx::armem +{ + // std::map <-> boost::container::flat_map + + template <class IceKeyT, class IceValueT, class CppKeyT, class CppValueT> + void toIce(std::map<IceKeyT, IceValueT>& iceMap, + const boost::container::flat_map<CppKeyT, CppValueT>& cppMap) + { + iceMap.clear(); + for (const auto& [key, value] : cppMap) + { + iceMap.emplace(toIce<IceKeyT>(key), toIce<IceValueT>(value)); + } + } + + template <class IceKeyT, class IceValueT, class CppKeyT, class CppValueT> + void fromIce(const std::map<IceKeyT, IceValueT>& iceMap, + boost::container::flat_map<CppKeyT, CppValueT>& cppMap) + { + cppMap.clear(); + for (const auto& [key, value] : iceMap) + { + cppMap.emplace(fromIce<CppKeyT>(key), fromIce<CppValueT>(value)); + } + } + +} diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions_templates.h b/source/RobotAPI/libraries/armem/core/ice_conversions_templates.h index e0c71faac37cd899d85d174c33196499a29df770..8060e22a0782e23c6bb989fe900fcce99c7ff7c6 100644 --- a/source/RobotAPI/libraries/armem/core/ice_conversions_templates.h +++ b/source/RobotAPI/libraries/armem/core/ice_conversions_templates.h @@ -1,9 +1,12 @@ #pragma once -#include <memory> - #include "Commit.h" +#include <Ice/Handle.h> + +#include <map> +#include <memory> +#include <vector> namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp index a64a5982e143e2627718f5039d3559b2d3479348..1fc021d65fe460b4b91331196446ef8661337aa6 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp @@ -1,8 +1,10 @@ #include "CoreSegment.h" +#include "error.h" + #include <ArmarXCore/core/exceptions/local/ExpressionException.h> -#include "error.h" +#include <SimoxUtility/json/json.hpp> namespace armarx::armem::ltm @@ -10,8 +12,6 @@ namespace armarx::armem::ltm wm::CoreSegment CoreSegment::convert() const { - ARMARX_INFO << "CoreSegment: Converting with connection to: " << dbsettings.toString(); - wm::CoreSegment m(id()); for (const auto& [_, s] : _container) { @@ -24,8 +24,6 @@ namespace armarx::armem::ltm { _container.clear(); - ARMARX_INFO << "CoreSegment: (Re)Establishing connection to: " << dbsettings.toString(); - mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; @@ -37,7 +35,7 @@ namespace armarx::armem::ltm nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); ARMARX_INFO << "CoreSegment: Found foreign key: " << json.at("foreign_key"); - MemoryID i((std::string) json.at("foreign_key")); + MemoryID i = MemoryID::fromString(json.at("foreign_key").get<std::string>()); if (i.coreSegmentName != id().coreSegmentName) { throw error::InvalidMemoryID(i, "A MemoryID in mongodb was invalid. Found the wrong coreSegment name. Expected " + id().coreSegmentName); @@ -45,9 +43,9 @@ namespace armarx::armem::ltm std::string k = i.providerSegmentName; - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(k); it != _container.end()) { - throw error::ArMemError("Somehow after clearing the container a key k = " + k + " was found. Do you have double entries in mongodb?"); + throw error::ArMemError("Somehow after clearing the (core) container a key k = " + k + " was found. Do you have double entries in mongodb?"); } else { @@ -56,6 +54,8 @@ namespace armarx::armem::ltm wms.first->second.reload(); } } + + ARMARX_INFO << "After reload has core segment " << id().str() << " size: " << _container.size(); } void CoreSegment::append(const wm::CoreSegment& m) @@ -64,24 +64,23 @@ namespace armarx::armem::ltm mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; - for (const auto& [k, s] : m.container()) + m.forEachProviderSegment([this, &coll](const wm::ProviderSegment & provSeg) { - if (const auto& it = _container.find(k); it != _container.end()) + auto it = _container.find(provSeg.name()); + if (it == _container.end()) { - it->second.append(s); - } - else - { - auto builder = bsoncxx::builder::stream::document{}; + bsoncxx::builder::stream::document builder; bsoncxx::document::value foreign_key = builder - << "foreign_key" << s.id().withProviderSegmentName(k).str() + << "foreign_key" << provSeg.id().str() << bsoncxx::builder::stream::finalize; coll.insert_one(foreign_key.view()); - auto wms = _container.emplace(k, id().withProviderSegmentName(k)); - wms.first->second.dbsettings = dbsettings; - wms.first->second.append(s); + it = _container.emplace(provSeg.name(), id().withProviderSegmentName(provSeg.name())).first; + it->second.dbsettings = dbsettings; } - } + it->second.append(provSeg); + + return true; + }); } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h index 3a7225058a265949de50e98a63d1d3c6ce5bf371..32f05ef2f773388b6006c573b7017064193d80c3 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h @@ -1,10 +1,10 @@ #pragma once -#include "../base/CoreSegmentBase.h" - #include "ProviderSegment.h" +#include "mongodb/MongoDBConnectionManager.h" -#include "../workingmemory/CoreSegment.h" +#include <RobotAPI/libraries/armem/core/base/CoreSegmentBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> namespace armarx::armem::ltm @@ -21,7 +21,6 @@ namespace armarx::armem::ltm public: using Base::CoreSegmentBase; - using Base::operator=; // Conversion @@ -31,21 +30,10 @@ namespace armarx::armem::ltm void reload(); void append(const wm::CoreSegment&); - protected: - virtual void _copySelf(CoreSegment& other) const override - { - Base::_copySelf(other); - other.dbsettings = dbsettings; - } - - virtual void _copySelfEmpty(CoreSegment& other) const override - { - Base::_copySelfEmpty(other); - other.dbsettings = dbsettings; - } - public: + MongoDBConnectionManager::MongoDBSettings dbsettings; + }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp index 153852eaf50f4d71573c1bafdc44b052c0e1317c..6604c26e935cb4619fc7439d8e9a1f318a14ff63 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp @@ -1,12 +1,15 @@ #include "Entity.h" +#include <ArmarXCore/core/logging/Logging.h> + +#include <SimoxUtility/json/json.hpp> + + namespace armarx::armem::ltm { wm::Entity Entity::convert() const { - ARMARX_INFO << "Entity: Converting with connection to: " << dbsettings.toString(); - wm::Entity m(id()); for (const auto& [_, s] : _container) { @@ -19,8 +22,6 @@ namespace armarx::armem::ltm { _container.clear(); - ARMARX_INFO << "Entity: (Re)Establishing connection to: " << dbsettings.toString(); - mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; @@ -29,19 +30,14 @@ namespace armarx::armem::ltm int i = 0; for (auto doc : cursor) { - if (i > MAX_HISTORY_SIZE) - { - // TODO: Add logic for most queried data? - break; - } nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); auto k = armem::Time::microSeconds(json.at("timestamp")); //ARMARX_INFO << "Entity: Found timestamp: " << std::to_string(k.toMicroSeconds()); - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(k); it != _container.end()) { - throw error::ArMemError("Somehow after clearing the container a key k = " + std::to_string(k.toMicroSeconds()) + " was found. Do you have double entries in mongodb?"); + throw error::ArMemError("Somehow after clearing the (entity) container a key k = " + std::to_string(k.toMicroSeconds()) + " was found. Do you have double entries in mongodb?"); } else { @@ -51,6 +47,8 @@ namespace armarx::armem::ltm } ++i; } + + ARMARX_INFO << "After reload has entity " << id().str() << " size: " << _container.size(); } void Entity::append(const wm::Entity& m) @@ -59,21 +57,22 @@ namespace armarx::armem::ltm mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; - for (const auto& [k, s] : m.container()) + m.forEachSnapshot([this](const wm::EntitySnapshot & snapshot) { - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(snapshot.time()); it != _container.end()) { // timestamp already exists // We assume that a snapshot does not change, so ignore } else { - auto wms = _container.emplace(std::make_pair(k, id().withTimestamp(k))); + auto wms = _container.emplace(std::make_pair(snapshot.time(), id().withTimestamp(snapshot.time()))); wms.first->second.dbsettings = dbsettings; - wms.first->second.setTo(s, k); + wms.first->second.setTo(snapshot, snapshot.time()); //truncateHistoryToSize(); } - } + return true; + }); } bool Entity::hasSnapshot(const Time& time) const @@ -88,25 +87,26 @@ namespace armarx::armem::ltm mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; - bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result = coll.find_one(document{} << "timestamp" << time.toMicroSeconds() << finalize); + bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result = + coll.find_one(document{} << "timestamp" << time.toMicroSeconds() << finalize); if (!maybe_result) { return false; } - auto json = nlohmann::json::parse(bsoncxx::to_json(*maybe_result)); - auto id = MemoryID::fromString(json["id"].get<std::string>()); - auto instances = json["instances"]; + nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(*maybe_result)); + MemoryID id = MemoryID::fromString(json["id"].get<std::string>()); + nlohmann::json instances = json["instances"]; EntitySnapshot snapshot(id); snapshot.dbsettings = dbsettings; - for (unsigned int i = 0; i < instances.size(); ++i) + for (size_t i = 0; i < instances.size(); ++i) { - EntityInstance instance(id.withInstanceIndex(i)); + EntityInstance instance(id.withInstanceIndex(static_cast<int>(i))); snapshot.addInstance(instance); } - _container.insert({time, snapshot}); + _container.emplace(time, snapshot); //truncateHistoryToSize(); return true; } @@ -142,7 +142,7 @@ namespace armarx::armem::ltm return Base::getSnapshot(time); } - const std::map<Time, EntitySnapshot>::value_type& Entity::getLatestItem() const + auto Entity::getLatestItem() const -> const ContainerT::value_type& { // Directly query mongodb (cache cant know whether it is the latest or not) // TODO diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h index a5bca08c7ee0b7aff2a79d2c45aa37fc4baec1c4..99bc3a736f0abe803ec101a81f4b1ac75b87d92e 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h @@ -1,10 +1,10 @@ #pragma once -#include "../base/EntityBase.h" - #include "EntitySnapshot.h" +#include "mongodb/MongoDBConnectionManager.h" -#include "../workingmemory/Entity.h" +#include <RobotAPI/libraries/armem/core/base/EntityBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> namespace armarx::armem::ltm @@ -36,13 +36,7 @@ namespace armarx::armem::ltm public: using Base::EntityBase; - using Base::operator=; - Entity() - { - // the history of snapshots is just a cache of frequently used elements - setMaxHistorySize(MAX_HISTORY_SIZE); - } // Conversion wm::Entity convert() const; @@ -51,33 +45,19 @@ namespace armarx::armem::ltm void reload(); void append(const wm::Entity&); - // virtual overrides for LTM lookups - virtual bool hasSnapshot(const Time& time) const override; - virtual std::vector<Time> getTimestamps() const override; - virtual const EntitySnapshot& getSnapshot(const Time& time) const override; - - protected: - virtual void _copySelf(Entity& other) const override - { - Base::_copySelf(other); - other.dbsettings = dbsettings; - } + // overrides for LTM lookups + bool hasSnapshot(const Time& time) const; + std::vector<Time> getTimestamps() const; + const EntitySnapshot& getSnapshot(const Time& time) const; - virtual void _copySelfEmpty(Entity& other) const override - { - Base::_copySelfEmpty(other); - other.dbsettings = dbsettings; - } protected: - // virtual overrides for LTM storage - virtual const std::map<Time, EntitySnapshot>::value_type& getLatestItem() const override; + // overrides for LTM storage + const ContainerT::value_type& getLatestItem() const; public: MongoDBConnectionManager::MongoDBSettings dbsettings; - private: - const static constexpr int MAX_HISTORY_SIZE = 200; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp index 5e44714904efe74f920b891b665e13497b749508..63fe18145c561e9efda0ba2a14cb07175b029d1c 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp @@ -1,30 +1,19 @@ #include "EntityInstance.h" -#include "../../core/error.h" - #include <ArmarXCore/core/exceptions/local/ExpressionException.h> + namespace armarx::armem::ltm { - bool EntityInstanceMetadata::operator==(const EntityInstanceMetadata& other) const - { - return timeCreated == other.timeCreated - && timeSent == other.timeSent - && timeArrived == other.timeArrived - && std::abs(confidence - other.confidence) < 1e-6f; - } - bool EntityInstance::equalsDeep(const EntityInstance& other) const { return id() == other.id() && _metadata == other.metadata(); } - void EntityInstance::update(const EntityUpdate& update, int index) + void EntityInstance::update(const EntityUpdate& update) { - ARMARX_CHECK_FITS_SIZE(index, update.instancesData.size()); - - this->index() = index; + ARMARX_CHECK_FITS_SIZE(this->index(), update.instancesData.size()); this->_metadata.confidence = update.confidence; this->_metadata.timeCreated = update.timeCreated; @@ -32,16 +21,4 @@ namespace armarx::armem::ltm this->_metadata.timeArrived = update.timeArrived; } - EntityInstance EntityInstance::copy() const - { - EntityInstance d; - this->_copySelf(d); - return d; - } - - void EntityInstance::_copySelf(EntityInstance& other) const - { - Base::_copySelf(other); - other._metadata = _metadata; - } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h index e95ae277e83b2a927172ad1e663c42a700fef849..6046f6ac50902d6f7f770361915dbd30d5a15ec1 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h @@ -1,84 +1,35 @@ #pragma once -#include "../base/EntityInstanceBase.h" +#include <RobotAPI/libraries/armem/core/base/EntityInstanceBase.h> -#include "../workingmemory/EntityInstance.h" -#include "mongodb/MongoDBConnectionManager.h" - -#include "../workingmemory/entityInstance_conversions.h" -#include "../workingmemory/json_conversions.h" namespace armarx::armem::ltm { - /** - * @brief Metadata of an entity instance. - */ - struct EntityInstanceMetadata - { - /// Time when this value was created. - Time timeCreated; - /// Time when this value was sent to the memory. - Time timeSent; - /// Time when this value has arrived at the memory. - Time timeArrived; + using EntityInstanceMetadata = base::EntityInstanceMetadata; - /// An optional confidence, may be used for things like decay. - float confidence = 1.0; - - - bool operator==(const EntityInstanceMetadata& other) const; - inline bool operator!=(const EntityInstanceMetadata& other) const - { - return !(*this == other); - } - }; /** * @brief Data of a single entity instance. */ class EntityInstance : - public base::EntityInstanceBase<EntityInstance> + public base::EntityInstanceBase<base::NoData, EntityInstanceMetadata> { - using Base = base::EntityInstanceBase<EntityInstance>; + using Base = base::EntityInstanceBase<base::NoData, EntityInstanceMetadata>; public: using Base::EntityInstanceBase; - EntityInstance(const EntityInstance& other) = default; - EntityInstance(EntityInstance&& other) = default; - EntityInstance& operator=(const EntityInstance& other) = default; - EntityInstance& operator=(EntityInstance&& other) = default; - - - EntityInstanceMetadata& metadata() - { - return _metadata; - } - inline const EntityInstanceMetadata& metadata() const - { - return _metadata; - } - /** * @brief Fill `*this` with the update's values. * @param update The update. * @param index The instances index. */ - virtual void update(const EntityUpdate& update, int index) override; - - virtual bool equalsDeep(const EntityInstance& other) const override; - - virtual EntityInstance copy() const override; - - protected: - virtual void _copySelf(EntityInstance& other) const override; + void update(const EntityUpdate& update); + bool equalsDeep(const EntityInstance& other) const; - private: - /// The metadata. - EntityInstanceMetadata _metadata; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp index 47a680731f9794c99433a114dd94a9ad22f5cbea..8cbe688125a7571a3e8f0a19031b25722bb79bbf 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp @@ -2,8 +2,11 @@ #include <ArmarXCore/core/exceptions/local/ExpressionException.h> -#include "../workingmemory/entityInstance_conversions.h" -#include "../workingmemory/json_conversions.h" +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> + +#include <RobotAPI/libraries/armem/core/wm/aron_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/json_conversions.h> + #include "error.h" @@ -13,14 +16,11 @@ namespace armarx::armem::ltm wm::EntitySnapshot EntitySnapshot::convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const { - ARMARX_INFO << "EntitySnapshot: Converting with connection to: " << dbsettings.toString(); - mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().getEntityID().str()]; auto res = coll.find_one(document{} << "id" << id().getEntitySnapshotID().str() << finalize); - if (!res) { throw error::ArMemError("Could not load an instance from the memory '" + id().getEntityID().str() + "'. Tried to access: " + id().getEntitySnapshotID().str()); @@ -52,8 +52,6 @@ namespace armarx::armem::ltm { _container.clear(); - ARMARX_INFO << "EntitySnapshot: (Re)Establishing connection to: " << dbsettings.toString(); - mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().getEntityID().str()]; @@ -68,10 +66,8 @@ namespace armarx::armem::ltm nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(*res)); for (unsigned int i = 0; i < json.at("instances").size(); ++i) { - auto wms = _container.emplace_back(id().withInstanceIndex(i)); + _container.emplace_back(id().withInstanceIndex(i)); } - - ARMARX_INFO << "Entity '" + id().str() + "': Found instances in LTM: " << json.at("instances").size(); } void EntitySnapshot::setTo(const wm::EntitySnapshot& m, const armem::Time& t) @@ -91,18 +87,20 @@ namespace armarx::armem::ltm auto array_builder = bsoncxx::builder::basic::array{}; int i = 0; - for (const auto& s : m.container()) + m.forEachInstance([this, &array_builder, &i](const wm::EntityInstance & instance) { auto wms = _container.emplace_back(id().withInstanceIndex(i++)); auto aron = std::make_shared<aron::datanavigator::DictNavigator>(); - to_aron(aron, s); + to_aron(aron, instance); nlohmann::json j; from_aron(aron, j); auto doc_value = bsoncxx::from_json(j.dump(2)); array_builder.append(doc_value); - } + + return true; + }); auto after_array = in_array << array_builder; bsoncxx::document::value doc = after_array << bsoncxx::builder::stream::finalize; diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h index 02361d2e708365303fbce81f56eaa9b49fb07a61..3029f8a7ca0278b9a505ee2fa5a744cfab327359 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h @@ -1,10 +1,12 @@ #pragma once -#include "../base/EntitySnapshotBase.h" - #include "EntityInstance.h" +#include "mongodb/MongoDBConnectionManager.h" + +#include <RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -#include "../workingmemory/EntitySnapshot.h" +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> namespace armarx::armem::ltm @@ -21,7 +23,6 @@ namespace armarx::armem::ltm public: using Base::EntitySnapshotBase; - using Base::operator=; // Conversion @@ -31,20 +32,10 @@ namespace armarx::armem::ltm void reload(); void setTo(const wm::EntitySnapshot&, const armem::Time& t); - protected: - virtual void _copySelf(EntitySnapshot& other) const override - { - Base::_copySelf(other); - other.dbsettings = dbsettings; - } - - virtual void _copySelfEmpty(EntitySnapshot& other) const override - { - Base::_copySelfEmpty(other); - other.dbsettings = dbsettings; - } public: + MongoDBConnectionManager::MongoDBSettings dbsettings; + }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp index fbea444e9d44008407703fe7b7f8b007179726b6..ab4cb5d13ec0a30c0e8dc04125b61bd4b031df99 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp @@ -1,44 +1,106 @@ #include "Memory.h" -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/logging/Logging.h> -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - #include "error.h" +#include <ArmarXCore/core/application/properties/PluginAll.h> +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> + namespace armarx::armem::ltm { + Memory::Memory(const Memory& other) : + Base(other), + dbsettings(other.dbsettings), + periodicTransferSettings(other.periodicTransferSettings), + onFullTransferSettings(other.onFullTransferSettings), + mongoDBMutex() + { + // Do not copy _mutex. + } + + + Memory::Memory(Memory&& other) : + Base(std::move(other)), + dbsettings(other.dbsettings), + periodicTransferSettings(other.periodicTransferSettings), + onFullTransferSettings(other.onFullTransferSettings), + reloaded(other.reloaded) + { + // Do not move _mutex. + } + + + Memory& Memory::operator=(const Memory& other) + { + Base::operator=(other); + + dbsettings = other.dbsettings; + periodicTransferSettings = other.periodicTransferSettings; + onFullTransferSettings = other.onFullTransferSettings; + + // Don't copy _mutex. + return *this; + } + + + Memory& Memory::operator=(Memory&& other) + { + Base::operator=(std::move(other)); + + dbsettings = std::move(other.dbsettings); + periodicTransferSettings = std::move(other.periodicTransferSettings); + onFullTransferSettings = std::move(other.onFullTransferSettings); + reloaded = other.reloaded; + + // Don't move _mutex. + return *this; + } + bool Memory::checkConnection() const { // Check connection: + ARMARX_INFO << "Checking connection"; if (!MongoDBConnectionManager::ConnectionIsValid(dbsettings)) { ARMARX_WARNING << deactivateSpam("ConnectionIsNotValid") << "The connection to mongocxx for memory '" << name() << "' is not valid. Settings are: " << dbsettings.toString() << "\nTo start it, run e.g.: \n" - << "mongod --port " << dbsettings.port << " --dbpath \"/tmp/\"" + << "armarx memory start" << "\n\n"; return false; } - ARMARX_INFO << "Checking connection"; return true; } + void Memory::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) + { + defs->optional(dbsettings.host, prefix + ".ltm.10_host"); + defs->optional(dbsettings.port, prefix + "ltm.11_port"); + defs->optional(dbsettings.user, prefix + "ltm.20_user"); + defs->optional(dbsettings.password, prefix + "ltm.21_password"); + defs->optional(dbsettings.database, prefix + "ltm.22_database"); + defs->optional(periodicTransferSettings.enabled, prefix + "ltm.30_enablePeriodicTransfer", "Enable transfer based on periodic interval."); + defs->optional(onFullTransferSettings.enabled, prefix + "ltm.31_enableOnFullTransfer", "Enable transfer whenever the wm is full (see maxHistorySize)."); + } + wm::Memory Memory::convert() const { + wm::Memory m(id()); + + std::lock_guard l(mongoDBMutex); if (!checkConnection()) { - wm::Memory m(id()); return m; } - ARMARX_INFO << "Converting with connection to: " << dbsettings.toString(); + ARMARX_INFO << "Converting Memory with connection to: " << dbsettings.toString(); TIMING_START(LTM_Convert); - wm::Memory m(id()); for (const auto& [_, s] : _container) { m.addCoreSegment(s.convert()); @@ -50,20 +112,41 @@ namespace armarx::armem::ltm void Memory::reload() { + std::lock_guard l(mongoDBMutex); + reloaded = false; + if (!checkConnection()) { return; } ARMARX_INFO << "(Re)Establishing connection to: " << dbsettings.toString(); + + TIMING_START(LTM_Reload); _container.clear(); mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + if (!client) + { + ARMARX_ERROR << "A client has died. Could not reload."; + return; + } + + auto databases = client.list_databases(); + for (const auto& doc : databases) + { + nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); + ARMARX_INFO << "Found the database: " << json.at("name"); + } + mongocxx::database db = client[dbsettings.database]; + ARMARX_INFO << "Getting collection for id: " << id().str(); mongocxx::collection coll = db[id().str()]; + ARMARX_IMPORTANT << "Memory Container size is: " << _container.size(); + mongocxx::cursor cursor = coll.find({}); - for (auto doc : cursor) + for (const auto& doc : cursor) { nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); ARMARX_INFO << "Memory: Found foreign key: " << json.at("foreign_key"); @@ -76,9 +159,9 @@ namespace armarx::armem::ltm std::string k = i.coreSegmentName; - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(k); it != _container.end()) { - throw error::ArMemError("Somehow after clearing the container a key k = " + k + " was found. Do you have double entries in mongodb?"); + throw error::ArMemError("Somehow after clearing the (memory) container a key k = " + k + " was found. Do you have double entries in mongodb?"); } else { @@ -87,16 +170,26 @@ namespace armarx::armem::ltm wms.first->second.reload(); } } + + reloaded = true; + for (const auto& m : toAppendQueue) + { + _append(m); + } + + TIMING_END(LTM_Reload); + ARMARX_INFO << "After reload memory " << id().str() << " size: " << _container.size() << ". Setting reloaded: " << reloaded; } - void Memory::append(const wm::Memory& m) + void Memory::_append(const wm::Memory& m) { - if (!checkConnection()) + if (!checkConnection() || !reloaded) { + // We ignore if not fully loaded yet return; } - ARMARX_INFO << "Merge memory with name '" << m.name() << "' into the LTM with name '" << name() << "'"; + //ARMARX_INFO << "Merge memory with name '" << m.name() << "' into the LTM with name '" << name() << "'"; TIMING_START(LTM_Append); @@ -104,9 +197,9 @@ namespace armarx::armem::ltm mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; - for (const auto& [k, s] : m.container()) + m.forEachCoreSegment([this, &coll](const wm::CoreSegment & s) { - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(s.name()); it != _container.end()) { // TODO check if foreign key exists it->second.append(s); @@ -115,16 +208,29 @@ namespace armarx::armem::ltm { auto builder = bsoncxx::builder::stream::document{}; bsoncxx::document::value foreign_key = builder - << "foreign_key" << s.id().withCoreSegmentName(k).str() + << "foreign_key" << s.id().withCoreSegmentName(s.name()).str() << bsoncxx::builder::stream::finalize; coll.insert_one(foreign_key.view()); - auto wms = _container.emplace(k, id().withCoreSegmentName(k)); + auto wms = _container.emplace(s.name(), id().withCoreSegmentName(s.name())); wms.first->second.dbsettings = dbsettings; wms.first->second.append(s); } - } + + return true; + }); TIMING_END(LTM_Append); } + + void Memory::append(const wm::Memory& m) + { + std::lock_guard l(mongoDBMutex); + if (!checkConnection() || !reloaded) + { + toAppendQueue.push_back(m); + return; + } + _append(m); + } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h index 86c00cc618e23620540428ba3b024743ecc272ee..41e82bce38b50f9e122e34056c2b5fd74cec4bac 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h @@ -1,10 +1,15 @@ #pragma once -#include "../base/MemoryBase.h" - #include "CoreSegment.h" +#include "mongodb/MongoDBConnectionManager.h" + +#include <RobotAPI/libraries/armem/core/base/MemoryBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> + +#include <ArmarXCore/core/application/properties/forward_declarations.h> + +#include <mutex> -#include "../workingmemory/Memory.h" namespace armarx::armem::ltm { @@ -18,32 +23,41 @@ namespace armarx::armem::ltm public: - using Base::MemoryBase; - using Base::operator=; - - enum class PeriodicTransferMode + struct TransferSettings { - MANUAL, - TRANSFER_PERIODIC_KEEP, - TRANSFER_PERIODIC_DELETE, + bool enabled = false; }; - enum class FilledTransferMode + struct PeriodicTransferSettings : public TransferSettings { - TRANSFER_LATEST, - TRANSFER_LEAST_USED + bool deleteFromWMOnTransfer = false; + int frequencyHz = 1; }; - struct PeriodicTransfer + struct OnFullTransferSettings : public TransferSettings { - PeriodicTransferMode mode = PeriodicTransferMode::MANUAL; + enum class Mode + { + TRANSFER_LATEST, + TRANSFER_LEAST_USED + }; + + Mode mode; + int batch_size = 20; }; - struct FilledTransfer - { - FilledTransferMode mode = FilledTransferMode::TRANSFER_LATEST; - }; + public: + + using Base::MemoryBase; + + Memory(const Memory& other); + Memory(Memory&& other); + Memory& operator=(const Memory& other); + Memory& operator=(Memory&& other); + + // PropertyDefinitions related to LTM + void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); // Conversion wm::Memory convert() const; @@ -52,26 +66,22 @@ namespace armarx::armem::ltm void reload(); void append(const wm::Memory&); - protected: - virtual void _copySelf(Memory& other) const override - { - Base::_copySelf(other); - other.dbsettings = dbsettings; - } - - virtual void _copySelfEmpty(Memory& other) const override - { - Base::_copySelfEmpty(other); - other.dbsettings = dbsettings; - } private: bool checkConnection() const; + void _append(const wm::Memory&); + public: MongoDBConnectionManager::MongoDBSettings dbsettings; - PeriodicTransfer periodic_transfer; - FilledTransferMode filled_transfer; + PeriodicTransferSettings periodicTransferSettings; + OnFullTransferSettings onFullTransferSettings; + + private: + bool reloaded = false; + mutable std::mutex mongoDBMutex; + + std::vector<wm::Memory> toAppendQueue; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp index aac80459904cae59550ecdf33f7057f92ed03aa4..8126867e4db4be01c91dfb582b67c94303751927 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp @@ -1,8 +1,10 @@ #include "ProviderSegment.h" +#include "error.h" + #include <ArmarXCore/core/exceptions/local/ExpressionException.h> -#include "error.h" +#include <SimoxUtility/json/json.hpp> namespace armarx::armem::ltm @@ -10,8 +12,6 @@ namespace armarx::armem::ltm wm::ProviderSegment ProviderSegment::convert() const { - ARMARX_INFO << "ProviderSegment: Converting with connection to: " << dbsettings.toString(); - wm::ProviderSegment m(id()); for (const auto& [_, s] : _container) { @@ -24,8 +24,6 @@ namespace armarx::armem::ltm { _container.clear(); - ARMARX_INFO << "ProviderSegment: (Re)Establishing connection to: " << dbsettings.toString(); - mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; @@ -34,7 +32,6 @@ namespace armarx::armem::ltm for (auto doc : cursor) { nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); - ARMARX_INFO << "ProviderSegment: Found foreign key: " << json.at("foreign_key"); MemoryID i((std::string) json.at("foreign_key")); if (i.providerSegmentName != id().providerSegmentName) @@ -44,9 +41,9 @@ namespace armarx::armem::ltm std::string k = i.entityName; - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(k); it != _container.end()) { - throw error::ArMemError("Somehow after clearing the container a key k = " + k + " was found. Do you have double entries in mongodb?"); + throw error::ArMemError("Somehow after clearing the (provvider) container a key k = " + k + " was found. Do you have double entries in mongodb?"); } else { @@ -55,6 +52,8 @@ namespace armarx::armem::ltm wms.first->second.reload(); } } + + ARMARX_INFO << "After reload has provider segment " << id().str() << " size: " << _container.size(); } void ProviderSegment::append(const wm::ProviderSegment& m) @@ -63,9 +62,9 @@ namespace armarx::armem::ltm mongocxx::database db = client[dbsettings.database]; mongocxx::collection coll = db[id().str()]; - for (const auto& [k, s] : m.container()) + m.forEachEntity([this, &coll](const wm::Entity & s) { - if (const auto& it = _container.find(k); it != _container.end()) + if (auto it = _container.find(s.name()); it != _container.end()) { it->second.append(s); } @@ -73,14 +72,16 @@ namespace armarx::armem::ltm { auto builder = bsoncxx::builder::stream::document{}; bsoncxx::document::value foreign_key = builder - << "foreign_key" << s.id().withEntityName(k).str() + << "foreign_key" << s.id().withEntityName(s.name()).str() << bsoncxx::builder::stream::finalize; coll.insert_one(foreign_key.view()); - auto wms = _container.emplace(k, id().withEntityName(k)); + auto wms = _container.emplace(s.name(), id().withEntityName(s.name())); wms.first->second.dbsettings = dbsettings; wms.first->second.append(s); } - } + + return true; + }); } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h index bb49f232e9fe231e1cd500e3f9739ddaa0d7d83f..bf1d5e3a9f4cbd816e087957d0bb3d6351b0b6cd 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h @@ -1,10 +1,10 @@ #pragma once -#include "../base/ProviderSegmentBase.h" - #include "Entity.h" +#include "mongodb/MongoDBConnectionManager.h" -#include "../workingmemory/ProviderSegment.h" +#include <RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> namespace armarx::armem::ltm @@ -21,7 +21,6 @@ namespace armarx::armem::ltm public: using Base::ProviderSegmentBase; - using Base::operator=; // Conversion @@ -31,19 +30,6 @@ namespace armarx::armem::ltm void reload(); void append(const wm::ProviderSegment&); - protected: - virtual void _copySelf(ProviderSegment& other) const override - { - Base::_copySelf(other); - other.dbsettings = dbsettings; - } - - virtual void _copySelfEmpty(ProviderSegment& other) const override - { - Base::_copySelfEmpty(other); - other.dbsettings = dbsettings; - } - public: MongoDBConnectionManager::MongoDBSettings dbsettings; }; diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.cpp index 6ad44836900e04765790a9a3c2a19881e1288656..fd2bbbb6ccb8aee93c4d343b818dc55872f7838a 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.cpp @@ -20,7 +20,7 @@ namespace armarx::armem::ltm initialize_if(); const auto uri_str = settings.uri(); - const auto& it = Connections.find(uri_str); + auto it = Connections.find(uri_str); if (it == Connections.end()) { mongocxx::uri uri(uri_str); @@ -43,7 +43,7 @@ namespace armarx::armem::ltm if (!force) { const auto uri_str = settings.uri(); - const auto& it = Connections.find(uri_str); + auto it = Connections.find(uri_str); if (it != Connections.end()) { auto admin = it->second["admin"]; @@ -70,7 +70,7 @@ namespace armarx::armem::ltm initialize_if(); const auto uri_str = settings.uri(); - const auto& it = Connections.find(uri_str); + auto it = Connections.find(uri_str); return it != Connections.end(); } } diff --git a/source/RobotAPI/libraries/armem/core/operations.cpp b/source/RobotAPI/libraries/armem/core/operations.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9ebedd316a41494d93bf99b1700fd83c475ba71 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/operations.cpp @@ -0,0 +1,32 @@ +#include "operations.h" + + +namespace armarx +{ + + std::vector<aron::datanavigator::DictNavigatorPtr> + armem::getAronData(const wm::EntitySnapshot& snapshot) + { + std::vector<aron::datanavigator::DictNavigatorPtr> result; + snapshot.forEachChild([&result](const wm::EntityInstance & instance) + { + result.push_back(instance.data()); + return true; + }); + return result; + } + + + armem::EntityUpdate armem::toEntityUpdate(const wm::EntitySnapshot& snapshot) + { + EntityUpdate up; + up.entityID = snapshot.id().getEntityID(); + up.timeCreated = snapshot.time(); + up.instancesData = getAronData(snapshot); + return up; + } + +} + + + diff --git a/source/RobotAPI/libraries/armem/core/operations.h b/source/RobotAPI/libraries/armem/core/operations.h new file mode 100644 index 0000000000000000000000000000000000000000..3b0182e324f32b832c97aaafa04ada90e604c9fa --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/operations.h @@ -0,0 +1,34 @@ +#pragma once + +#include "wm/memory_definitions.h" + + +/* + * Functions performing some "advanced" operations on the memory + * data structure, which are using their public API but should not + * be part of it. + */ + +namespace armarx::armem +{ + + std::vector<aron::datanavigator::DictNavigatorPtr> + getAronData(const wm::EntitySnapshot& snapshot); + + EntityUpdate toEntityUpdate(const wm::EntitySnapshot& snapshot); + + + template <class ContainerT> + Commit toCommit(const ContainerT& container) + { + Commit commit; + container.forEachSnapshot([&commit](const wm::EntitySnapshot & snapshot) + { + commit.add(toEntityUpdate(snapshot)); + return true; + }); + return commit; + } + +} + diff --git a/source/RobotAPI/libraries/armem/core/wm.h b/source/RobotAPI/libraries/armem/core/wm.h new file mode 100644 index 0000000000000000000000000000000000000000..83776ed701261bde89ed1fe2fd1e4ff479f06f44 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm.h @@ -0,0 +1,10 @@ +#pragma once + +#include "wm/memory_definitions.h" + + +namespace armarx::armem::wm +{ + +} + diff --git a/source/RobotAPI/libraries/armem/core/wm/aron_conversions.cpp b/source/RobotAPI/libraries/armem/core/wm/aron_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4a5faa1404129feed5f2573c706c22900c108df --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm/aron_conversions.cpp @@ -0,0 +1,69 @@ +#include "aron_conversions.h" + +#include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> + + +namespace armarx::armem +{ + + constexpr const char* DATA_WRAPPER_DATA_FIELD = "__ARON_DATA"; + constexpr const char* DATA_WRAPPER_TIME_STORED_FIELD = "__WRITER_METADATA__TIME_STORED"; + constexpr const char* DATA_WRAPPER_TIME_CREATED_FIELD = "__ENTITY_METADATA__TIME_CREATED"; + constexpr const char* DATA_WRAPPER_TIME_SENT_FIELD = "__ENTITY_METADATA__TIME_SENT"; + constexpr const char* DATA_WRAPPER_TIME_ARRIVED_FIELD = "__ENTITY_METADATA__TIME_ARRIVED"; + constexpr const char* DATA_WRAPPER_CONFIDENCE_FIELD = "__ENTITY_METADATA__CONFIDENCE"; + +} + + +void armarx::armem::from_aron(const aron::datanavigator::DictNavigatorPtr& dataWrapped, wm::EntityInstance& e) +{ + wm::EntityInstanceMetadata& metadata = e.metadata(); + + if (dataWrapped->hasElement(DATA_WRAPPER_DATA_FIELD)) + { + e.data() = aron::datanavigator::DictNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_DATA_FIELD)); + } + + auto timeCreated = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_CREATED_FIELD)); + metadata.timeCreated = Time::microSeconds(timeCreated->toAronLongPtr()->value); + + auto timeSent = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_SENT_FIELD)); + metadata.timeSent = Time::microSeconds(timeSent->toAronLongPtr()->value); + + auto timeArrived = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_ARRIVED_FIELD)); + metadata.timeArrived = Time::microSeconds(timeArrived->toAronLongPtr()->value); + + auto confidence = aron::datanavigator::DoubleNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_CONFIDENCE_FIELD)); + metadata.confidence = static_cast<float>(confidence->toAronDoublePtr()->value); +} + + +void armarx::armem::to_aron(aron::datanavigator::DictNavigatorPtr& a, const wm::EntityInstance& e) +{ + if (e.data()) + { + a->addElement(DATA_WRAPPER_DATA_FIELD, e.data()); + } + + auto timeWrapped = std::make_shared<aron::datanavigator::LongNavigator>(); + timeWrapped->setValue(Time::now().toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_STORED_FIELD, timeWrapped); + + const wm::EntityInstanceMetadata& metadata = e.metadata(); + auto timeCreated = std::make_shared<aron::datanavigator::LongNavigator>(); + timeCreated->setValue(metadata.timeCreated.toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_CREATED_FIELD, timeCreated); + + auto timeSent = std::make_shared<aron::datanavigator::LongNavigator>(); + timeSent->setValue(metadata.timeSent.toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_SENT_FIELD, timeSent); + + auto timeArrived = std::make_shared<aron::datanavigator::LongNavigator>(); + timeArrived->setValue(metadata.timeArrived.toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_ARRIVED_FIELD, timeArrived); + + auto confidence = std::make_shared<aron::datanavigator::DoubleNavigator>(); + confidence->setValue(static_cast<double>(metadata.confidence)); + a->addElement(DATA_WRAPPER_CONFIDENCE_FIELD, confidence); +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.h b/source/RobotAPI/libraries/armem/core/wm/aron_conversions.h similarity index 59% rename from source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.h rename to source/RobotAPI/libraries/armem/core/wm/aron_conversions.h index f3b25566f110dca844e24dcac4c997f724c74548..f6b43dc8bd468008b9fe8ee470564f5de89e16cb 100644 --- a/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.h +++ b/source/RobotAPI/libraries/armem/core/wm/aron_conversions.h @@ -1,6 +1,9 @@ #pragma once -#include "Memory.h" +#include <RobotAPI/libraries/aron/core/navigator/data/forward_declarations.h> + +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> + namespace armarx::armem { diff --git a/source/RobotAPI/libraries/armem/core/wm/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/wm/ice_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70a905a931fd331a6ecdfbc2c278924b0da9144a --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm/ice_conversions.cpp @@ -0,0 +1,64 @@ +#include "ice_conversions.h" + +#include <RobotAPI/libraries/armem/core/base/ice_conversions.h> + + +namespace armarx::armem +{ + + void wm::toIce(data::EntityInstance& ice, const EntityInstance& data) + { + base::toIce(ice, data); + } + void wm::fromIce(const data::EntityInstance& ice, EntityInstance& data) + { + base::fromIce(ice, data); + } + + + void wm::toIce(data::EntitySnapshot& ice, const EntitySnapshot& snapshot) + { + base::toIce(ice, snapshot); + } + void wm::fromIce(const data::EntitySnapshot& ice, EntitySnapshot& snapshot) + { + base::fromIce(ice, snapshot); + } + + void wm::toIce(data::Entity& ice, const Entity& entity) + { + base::toIce(ice, entity); + } + void wm::fromIce(const data::Entity& ice, Entity& entity) + { + base::fromIce(ice, entity); + } + + void wm::toIce(data::ProviderSegment& ice, const ProviderSegment& providerSegment) + { + base::toIce(ice, providerSegment); + } + void wm::fromIce(const data::ProviderSegment& ice, ProviderSegment& providerSegment) + { + base::fromIce(ice, providerSegment); + } + + void wm::toIce(data::CoreSegment& ice, const CoreSegment& coreSegment) + { + base::toIce(ice, coreSegment); + } + void wm::fromIce(const data::CoreSegment& ice, CoreSegment& coreSegment) + { + base::fromIce(ice, coreSegment); + } + + void wm::toIce(data::Memory& ice, const Memory& memory) + { + base::toIce(ice, memory); + } + void wm::fromIce(const data::Memory& ice, Memory& memory) + { + base::fromIce(ice, memory); + } + +} diff --git a/source/RobotAPI/libraries/armem/core/wm/ice_conversions.h b/source/RobotAPI/libraries/armem/core/wm/ice_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..4a58f16aaa6eef4c6f6685a86ed66298c1407454 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm/ice_conversions.h @@ -0,0 +1,34 @@ +#pragma once + +#include <RobotAPI/interface/armem/commit.h> +#include <RobotAPI/interface/armem/memory.h> + +#include "memory_definitions.h" + + +namespace armarx::armem::wm +{ + + void toIce(data::EntityInstance& ice, const EntityInstance& data); + void fromIce(const data::EntityInstance& ice, EntityInstance& data); + + + void toIce(data::EntitySnapshot& ice, const EntitySnapshot& snapshot); + void fromIce(const data::EntitySnapshot& ice, EntitySnapshot& snapshot); + + void toIce(data::Entity& ice, const Entity& entity); + void fromIce(const data::Entity& ice, Entity& entity); + + + void toIce(data::ProviderSegment& ice, const ProviderSegment& providerSegment); + void fromIce(const data::ProviderSegment& ice, ProviderSegment& providerSegment); + + void toIce(data::CoreSegment& ice, const CoreSegment& coreSegment); + void fromIce(const data::CoreSegment& ice, CoreSegment& coreSegment); + + void toIce(data::Memory& ice, const Memory& memory); + void fromIce(const data::Memory& ice, Memory& memory); +} + +// Must be included after the prototypes. Otherwise the compiler cannot find the correct methods in ice_coversion_templates.h +#include <RobotAPI/libraries/armem/core/ice_conversions.h> diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.cpp b/source/RobotAPI/libraries/armem/core/wm/json_conversions.cpp similarity index 64% rename from source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.cpp rename to source/RobotAPI/libraries/armem/core/wm/json_conversions.cpp index e7499d8b42edf895bbbdb2f0d06a1fe3ed2ee823..fd67c5f822cbfa3783bf1fc23b3de24f06a27f88 100644 --- a/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.cpp +++ b/source/RobotAPI/libraries/armem/core/wm/json_conversions.cpp @@ -1,10 +1,14 @@ #include "json_conversions.h" #include <RobotAPI/libraries/aron/core/Debug.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/visitor/Visitor.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/converter/Converter.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/reader/nlohmannJSON/NlohmannJSONReader.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/writer/nlohmannJSON/NlohmannJSONWriter.h> + namespace armarx::armem { - void from_aron(const aron::datanavigator::DictNavigatorPtr& aron, nlohmann::json& j) { aron::dataIO::writer::NlohmannJSONWriter dataWriter; @@ -12,7 +16,8 @@ namespace armarx::armem j = dataWriter.getResult(); } - void to_aron(aron::datanavigator::DictNavigatorPtr& a, const nlohmann::json& e, const aron::typenavigator::NavigatorPtr& expectedStructure) + void to_aron(aron::datanavigator::DictNavigatorPtr& a, const nlohmann::json& e, + const aron::typenavigator::NavigatorPtr& expectedStructure) { aron::dataIO::reader::NlohmannJSONReader dataReader(e); aron::dataIO::writer::NavigatorWriter navWriter; diff --git a/source/RobotAPI/libraries/armem/core/wm/json_conversions.h b/source/RobotAPI/libraries/armem/core/wm/json_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..4ce93812b606688e642eecc0b7856210adce1a90 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm/json_conversions.h @@ -0,0 +1,14 @@ +#pragma once + +#include <RobotAPI/libraries/aron/core/navigator/data/forward_declarations.h> +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> + +#include <SimoxUtility/json/json.hpp> + + +namespace armarx::armem +{ + void from_aron(const aron::datanavigator::DictNavigatorPtr&, nlohmann::json&); + void to_aron(aron::datanavigator::DictNavigatorPtr&, const nlohmann::json&, + const aron::typenavigator::NavigatorPtr& expectedStructure = nullptr); +} diff --git a/source/RobotAPI/libraries/armem/core/wm/memory_definitions.cpp b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9516fc3b74ce05797d7d8c39b12f83b0bdf740d --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.cpp @@ -0,0 +1,92 @@ +#include "memory_definitions.h" + +#include "error.h" + +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <map> +#include <vector> + + +namespace armarx::armem::wm +{ + + bool EntityInstance::equalsDeep(const EntityInstance& other) const + { + if (_data and other.data()) + { + return id() == other.id() + && _metadata == other.metadata() + && *_data == *other.data(); + } + if (_data or other.data()) + { + return false; + } + return id() == other.id() && _metadata == other.metadata(); + } + + + void EntityInstance::update(const EntityUpdate& update) + { + ARMARX_CHECK_FITS_SIZE(this->index(), update.instancesData.size()); + + this->data() = update.instancesData.at(size_t(this->index())); + + this->_metadata.confidence = update.confidence; + + this->_metadata.timeCreated = update.timeCreated; + this->_metadata.timeSent = update.timeSent; + this->_metadata.timeArrived = update.timeArrived; + } + + + + std::optional<wm::EntitySnapshot> CoreSegment::getLatestEntitySnapshot(const MemoryID& entityID) const + { + const wm::Entity& entity = this->getEntity(entityID); + if (entity.empty()) + { + return std::nullopt; + } + else + { + return entity.getLatestSnapshot(); + } + } + + + std::optional<wm::EntityInstance> CoreSegment::getLatestEntityInstance( + const MemoryID& entityID, int instanceIndex) const + { + auto snapshot = getLatestEntitySnapshot(entityID); + if (snapshot.has_value() + and instanceIndex >= 0 + and static_cast<size_t>(instanceIndex) < snapshot->size()) + { + return snapshot->getInstance(instanceIndex); + } + else + { + return std::nullopt; + } + } + + + armarx::aron::datanavigator::DictNavigatorPtr + CoreSegment::getLatestEntityInstanceData(const MemoryID& entityID, int instanceIndex) const + { + auto instance = getLatestEntityInstance(entityID, instanceIndex); + if (instance.has_value()) + { + return instance->data(); + } + else + { + return nullptr; + } + } + + +} diff --git a/source/RobotAPI/libraries/armem/core/wm/memory_definitions.h b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.h new file mode 100644 index 0000000000000000000000000000000000000000..679153b47809682fec38adb5baea609dd99c5c28 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.h @@ -0,0 +1,135 @@ +#pragma once + +#include <RobotAPI/libraries/armem/core/base/EntityInstanceBase.h> +#include <RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h> +#include <RobotAPI/libraries/armem/core/base/EntityBase.h> +#include <RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h> +#include <RobotAPI/libraries/armem/core/base/CoreSegmentBase.h> +#include <RobotAPI/libraries/armem/core/base/MemoryBase.h> + +#include <optional> + + +namespace armarx::armem::wm +{ + + using EntityInstanceMetadata = base::EntityInstanceMetadata; + using EntityInstanceData = armarx::aron::datanavigator::DictNavigator; + using EntityInstanceDataPtr = armarx::aron::datanavigator::DictNavigatorPtr; + + + /// @see base::EntityInstanceBase + class EntityInstance : + public base::EntityInstanceBase<EntityInstanceDataPtr, EntityInstanceMetadata> + { + using Base = base::EntityInstanceBase<EntityInstanceDataPtr, EntityInstanceMetadata>; + + public: + + using Base::EntityInstanceBase; + + + /** + * @brief Fill `*this` with the update's values. + * @param update The update. + * @param index The instances index. + */ + void update(const EntityUpdate& update); + + bool equalsDeep(const EntityInstance& other) const; + + }; + + + + /// @see base::EntitySnapshotBase + class EntitySnapshot : + public base::EntitySnapshotBase<EntityInstance, EntitySnapshot> + { + public: + + using base::EntitySnapshotBase<EntityInstance, EntitySnapshot>::EntitySnapshotBase; + + }; + + + /// @see base::EntityBase + class Entity : + public base::EntityBase<EntitySnapshot, Entity> + { + public: + + using base::EntityBase<EntitySnapshot, Entity>::EntityBase; + + }; + + + + /// @see base::ProviderSegmentBase + class ProviderSegment : + public base::ProviderSegmentBase<Entity, ProviderSegment> + { + public: + + using base::ProviderSegmentBase<Entity, ProviderSegment>::ProviderSegmentBase; + + }; + + + + /// @see base::CoreSegmentBase + class CoreSegment : + public base::CoreSegmentBase<ProviderSegment, CoreSegment> + { + using Base = base::CoreSegmentBase<ProviderSegment, CoreSegment>; + + public: + + using Base::CoreSegmentBase; + + + // Non-locking interface + + std::optional<wm::EntitySnapshot> getLatestEntitySnapshot( + const MemoryID& entityID) const; + std::optional<wm::EntityInstance> getLatestEntityInstance( + const MemoryID& entityID, int instanceIndex = 0) const; + armarx::aron::datanavigator::DictNavigatorPtr getLatestEntityInstanceData( + const MemoryID& entityID, int instanceIndex = 0) const; + + + template <class AronDtoT> + std::optional<AronDtoT> getLatestEntityInstanceDataAs( + const MemoryID& entityID, int instanceIndex = 0) const + { + wm::EntityInstanceDataPtr data = getLatestEntityInstanceData(entityID, instanceIndex); + if (data) + { + AronDtoT aron; + aron.fromAron(data); + return aron; + } + else + { + return std::nullopt; + } + } + + }; + + + + /// @see base::MemoryBase + class Memory : + public base::MemoryBase<CoreSegment, Memory> + { + using Base = base::MemoryBase<CoreSegment, Memory>; + + public: + + using Base::MemoryBase; + + }; + +} + diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.cpp b/source/RobotAPI/libraries/armem/core/wm/visitor/FunctionalVisitor.cpp similarity index 82% rename from source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.cpp rename to source/RobotAPI/libraries/armem/core/wm/visitor/FunctionalVisitor.cpp index 53016fc6c83d9ef6e24a2e75942a12bced7d0eaa..f72b37c1a7ab68320c8ff2ec8c071dd741e61f22 100644 --- a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.cpp +++ b/source/RobotAPI/libraries/armem/core/wm/visitor/FunctionalVisitor.cpp @@ -2,7 +2,7 @@ #include <ArmarXCore/core/exceptions/local/ExpressionException.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/error.h> @@ -18,6 +18,4 @@ namespace armarx::armem::wm { } - - } diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.h b/source/RobotAPI/libraries/armem/core/wm/visitor/FunctionalVisitor.h similarity index 82% rename from source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.h rename to source/RobotAPI/libraries/armem/core/wm/visitor/FunctionalVisitor.h index 1c1b46e138c7eb2d713ba15b76ba77a2588ea0ce..34390a1823a6f3f1651bbe59ec815a0c1ab48bd6 100644 --- a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/FunctionalVisitor.h +++ b/source/RobotAPI/libraries/armem/core/wm/visitor/FunctionalVisitor.h @@ -53,28 +53,28 @@ namespace armarx::armem::wm bool visitEnter(const Memory& memory) override { - return memoryFn ? memoryConstFn(memory) : Visitor::visitEnter(memory); + return memoryConstFn ? memoryConstFn(memory) : Visitor::visitEnter(memory); } bool visitEnter(const CoreSegment& coreSegment) override { - return coreSegmentFn ? coreSegmentConstFn(coreSegment) : Visitor::visitEnter(coreSegment); + return coreSegmentConstFn ? coreSegmentConstFn(coreSegment) : Visitor::visitEnter(coreSegment); } bool visitEnter(const ProviderSegment& providerSegment) override { - return providerSegmentFn ? providerSegmentConstFn(providerSegment) : Visitor::visitEnter(providerSegment); + return providerSegmentConstFn ? providerSegmentConstFn(providerSegment) : Visitor::visitEnter(providerSegment); } bool visitEnter(const Entity& entity) override { - return entityFn ? entityConstFn(entity) : Visitor::visitEnter(entity); + return entityConstFn ? entityConstFn(entity) : Visitor::visitEnter(entity); } bool visitEnter(const EntitySnapshot& snapshot) override { - return memoryFn ? snapshotConstFn(snapshot) : Visitor::visitEnter(snapshot); + return snapshotConstFn ? snapshotConstFn(snapshot) : Visitor::visitEnter(snapshot); } bool visit(const EntityInstance& instance) override { - return instanceFn ? instanceConstFn(instance) : Visitor::visit(instance); + return instanceConstFn ? instanceConstFn(instance) : Visitor::visit(instance); } diff --git a/source/RobotAPI/libraries/armem/core/wm/visitor/Visitor.cpp b/source/RobotAPI/libraries/armem/core/wm/visitor/Visitor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1140bc11be0a43e41e2e5c690ae8a73132440a6b --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/wm/visitor/Visitor.cpp @@ -0,0 +1,141 @@ +#include "Visitor.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/core/error.h> + + +namespace armarx::armem::wm +{ + + Visitor::Visitor() + { + } + + Visitor::~Visitor() + { + } + + bool Visitor::applyTo(Memory& memory) + { + visitEnter(memory); + bool cont = memory.forEachCoreSegment([this](CoreSegment & coreSeg) + { + return applyTo(coreSeg); + }); + visitExit(memory); + return cont; + } + + bool Visitor::applyTo(CoreSegment& coreSegment) + { + visitEnter(coreSegment); + bool cont = coreSegment.forEachProviderSegment([this](ProviderSegment & provSeg) + { + return applyTo(provSeg); + }); + visitExit(coreSegment); + return cont; + } + + bool Visitor::applyTo(ProviderSegment& providerSegment) + { + visitEnter(providerSegment); + bool cont = providerSegment.forEachEntity([this](Entity & entity) + { + return applyTo(entity); + }); + visitExit(providerSegment); + return cont; + } + + bool Visitor::applyTo(Entity& entity) + { + visitEnter(entity); + bool cont = entity.forEachSnapshot([this](EntitySnapshot & snapshot) + { + return applyTo(snapshot); + }); + visitExit(entity); + return cont; + } + + bool Visitor::applyTo(EntitySnapshot& snapshot) + { + visitEnter(snapshot); + bool cont = snapshot.forEachInstance([this](EntityInstance & instance) + { + return applyTo(instance); + }); + visitExit(snapshot); + return cont; + } + + bool Visitor::applyTo(EntityInstance& instance) + { + return visit(instance); + } + + + bool Visitor::applyTo(const Memory& memory) + { + visitEnter(memory); + bool cont = memory.forEachCoreSegment([this](const CoreSegment & coreSeg) + { + return applyTo(coreSeg); + }); + visitExit(memory); + return cont; + } + + bool Visitor::applyTo(const CoreSegment& coreSegment) + { + visitEnter(coreSegment); + bool cont = coreSegment.forEachProviderSegment([this](const ProviderSegment & provSeg) + { + return applyTo(provSeg); + }); + visitExit(coreSegment); + return cont; + } + + bool Visitor::applyTo(const ProviderSegment& providerSegment) + { + visitEnter(providerSegment); + bool cont = providerSegment.forEachEntity([this](const Entity & entity) + { + return applyTo(entity); + }); + visitExit(providerSegment); + return cont; + } + + bool Visitor::applyTo(const Entity& entity) + { + visitEnter(entity); + bool cont = entity.forEachSnapshot([this](const EntitySnapshot & snapshot) + { + return applyTo(snapshot); + }); + visitExit(entity); + return cont; + } + + bool Visitor::applyTo(const EntitySnapshot& snapshot) + { + visitEnter(snapshot); + bool cont = snapshot.forEachInstance([this](const EntityInstance & instance) + { + return applyTo(instance); + }); + visitExit(snapshot); + return cont; + } + + bool Visitor::applyTo(const EntityInstance& instance) + { + return visit(instance); + } + +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.h b/source/RobotAPI/libraries/armem/core/wm/visitor/Visitor.h similarity index 100% rename from source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.h rename to source/RobotAPI/libraries/armem/core/wm/visitor/Visitor.h diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/CoreSegment.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/CoreSegment.cpp deleted file mode 100644 index 285235b76e397952301c23d8218abb11f1f7aeaf..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/CoreSegment.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "CoreSegment.h" - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include "error.h" - - -namespace armarx::armem::wm -{ - - Commit CoreSegment::toCommit() const - { - Commit c; - for (const auto& [k, s] : _container) - { - c.append(s.toCommit()); - } - return c; - } - - void CoreSegment::_copySelfWithoutData(CoreSegment& other) const - { - other.id() = _id; - other.setMaxHistorySize(_maxHistorySize); - for (const auto& [k, s] : _container) - { - other.addProviderSegment(s.copyWithoutData()); - } - } -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h b/source/RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h deleted file mode 100644 index 7847bbb71cc6a1a269556aeec07738c396e42a68..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "../base/CoreSegmentBase.h" - -#include "ProviderSegment.h" -#include "detail/CopyWithoutData.h" - - -namespace armarx::armem::wm -{ - - /** - * @brief Data of a core segment containing multiple provider segments. - */ - class CoreSegment : - public base::CoreSegmentBase<ProviderSegment, CoreSegment>, - public detail::CopyWithoutData<CoreSegment> - { - using Base = base::CoreSegmentBase<ProviderSegment, CoreSegment>; - - public: - - using Base::CoreSegmentBase; - - CoreSegment(const CoreSegment& other) = default; - CoreSegment(CoreSegment&& other) = default; - CoreSegment& operator=(const CoreSegment& other) = default; - CoreSegment& operator=(CoreSegment&& other) = default; - - /** - * @brief Convert the content of this segmnet into a commit - * @return The resulting commit - */ - Commit toCommit() const; - - protected: - - virtual void _copySelfWithoutData(CoreSegment& other) const override; - - }; - -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Entity.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/Entity.cpp deleted file mode 100644 index e704e96d5454d27bfb095120c1901e000611122a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/Entity.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "Entity.h" - -namespace armarx::armem::wm -{ - - Commit Entity::toCommit() const - { - Commit c; - for (const auto& [k, s] : _container) - { - EntityUpdate& up = c.add(); - up.entityID = id(); - up.timeCreated = k; - up.instancesData = s.getAronData(); - } - return c; - } - - void Entity::_copySelfWithoutData(Entity& other) const - { - other.id() = _id; - other.setMaxHistorySize(_maxHistorySize); - for (const auto& [k, s] : _container) - { - other.addSnapshot(s.copyWithoutData()); - } - } -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Entity.h b/source/RobotAPI/libraries/armem/core/workingmemory/Entity.h deleted file mode 100644 index a6a7621e21272db6447e9e09b695900eefd263c1..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/Entity.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "../base/EntityBase.h" - -#include "EntitySnapshot.h" -#include "detail/CopyWithoutData.h" - - -namespace armarx::armem::wm -{ - /** - * @brief An entity over a period of time. - * - * An entity should be a physical thing or abstract concept existing - * (and potentially evolving) over some time. - * - * Examples are: - * - objects (the green box) - * - agents (robot, human) - * - locations (frige, sink) - * - grasp affordances (general, or for a specific object) - * - images - * - point clouds - * - other sensory values - * - * At each point in time (`EntitySnapshot`), the entity can have a - * (potentially variable) number of instances (`EntityInstance`), - * each containing a single `AronData` object of a specific `AronType`. - */ - class Entity : - public base::EntityBase<EntitySnapshot, Entity>, - public detail::CopyWithoutData<Entity> - { - using Base = base::EntityBase<EntitySnapshot, Entity>; - - public: - - using Base::EntityBase; - - Entity(const Entity& other) = default; - Entity(Entity&& other) = default; - Entity& operator=(const Entity& other) = default; - Entity& operator=(Entity&& other) = default; - - /** - * @brief Convert the content of this segmnet into a commit - * @return The resulting commit - */ - Commit toCommit() const; - - protected: - - virtual void _copySelfWithoutData(Entity& other) const override; - - }; - -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.cpp deleted file mode 100644 index 6149449c77533abd656a460097969f0066d8d88f..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "EntityInstance.h" - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - - -std::ostream& armarx::armem::wm::operator<<(std::ostream& os, const EntityInstanceMetadata& d) -{ - os << "EntityInstanceMetadata: " - << "\n- t_create = \t" << armem::toStringMicroSeconds(d.timeCreated) << " us" - << "\n- t_sent = \t" << armem::toStringMicroSeconds(d.timeSent) << " us" - << "\n- t_arrived = \t" << armem::toStringMicroSeconds(d.timeArrived) << " us" - << "\n- confidence = \t" << d.confidence << " us" - ; - return os; -} - -namespace armarx::armem::wm -{ - - bool EntityInstanceMetadata::operator==(const EntityInstanceMetadata& other) const - { - return timeCreated == other.timeCreated - && timeSent == other.timeSent - && timeArrived == other.timeArrived - && std::abs(confidence - other.confidence) < 1e-6f; - } - - - bool EntityInstance::equalsDeep(const EntityInstance& other) const - { - if (_data and other.data()) - { - return id() == other.id() - && _metadata == other.metadata() - && *_data == *other.data(); - } - if (_data or other.data()) - { - return false; - } - return id() == other.id() && _metadata == other.metadata(); - } - - void EntityInstance::update(const EntityUpdate& update, int index) - { - ARMARX_CHECK_FITS_SIZE(index, update.instancesData.size()); - - this->index() = index; - setData(update.instancesData.at(size_t(index))); - - this->_metadata.confidence = update.confidence; - - this->_metadata.timeCreated = update.timeCreated; - this->_metadata.timeSent = update.timeSent; - this->_metadata.timeArrived = update.timeArrived; - } - - EntityInstance EntityInstance::copy() const - { - EntityInstance d; - this->_copySelf(d); - return d; - } - - void EntityInstance::_copySelf(EntityInstance& other) const - { - Base::_copySelf(other); - other._metadata = _metadata; - other._data = _data; - } - - void EntityInstance::_copySelfWithoutData(EntityInstance& other) const - { - Base::_copySelf(other); - other._metadata = _metadata; - } -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h deleted file mode 100644 index 8e6eb1afe7e673baeab933397ebd16aa1781c18d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include "../base/EntityInstanceBase.h" - -#include "detail/CopyWithoutData.h" - - -namespace armarx::armem::wm -{ - - /** - * @brief Metadata of an entity instance. - */ - struct EntityInstanceMetadata - { - /// Time when this value was created. - Time timeCreated; - /// Time when this value was sent to the memory. - Time timeSent; - /// Time when this value has arrived at the memory. - Time timeArrived; - - /// An optional confidence, may be used for things like decay. - float confidence = 1.0; - - - bool operator==(const EntityInstanceMetadata& other) const; - inline bool operator!=(const EntityInstanceMetadata& other) const - { - return !(*this == other); - } - }; - - std::ostream& operator<<(std::ostream& os, const EntityInstanceMetadata& rhs); - - - /** - * @brief Data of a single entity instance. - */ - class EntityInstance : - public base::EntityInstanceBase<EntityInstance>, - public detail::CopyWithoutData<EntityInstance> - { - using Base = base::EntityInstanceBase<EntityInstance>; - - public: - - using Base::EntityInstanceBase; - - EntityInstance(const EntityInstance& other) = default; - EntityInstance(EntityInstance&& other) = default; - EntityInstance& operator=(const EntityInstance& other) = default; - EntityInstance& operator=(EntityInstance&& other) = default; - - - EntityInstanceMetadata& metadata() - { - return _metadata; - } - inline const EntityInstanceMetadata& metadata() const - { - return _metadata; - } - - inline armarx::aron::datanavigator::DictNavigatorPtr data() const - { - return _data; - } - - void setData(const aron::datanavigator::DictNavigatorPtr& data) - { - this->_data = data; - } - - - /** - * @brief Fill `*this` with the update's values. - * @param update The update. - * @param index The instances index. - */ - virtual void update(const EntityUpdate& update, int index) override; - - virtual bool equalsDeep(const EntityInstance& other) const override; - - virtual EntityInstance copy() const override; - - - protected: - - virtual void _copySelf(EntityInstance& other) const override; - virtual void _copySelfWithoutData(EntityInstance& other) const override; - - - private: - - /// The metadata. - EntityInstanceMetadata _metadata; - - /// The data. May be nullptr. - armarx::aron::datanavigator::DictNavigatorPtr _data; - - }; -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.cpp deleted file mode 100644 index 76d5400131a7ec6a57478f13afb0dfc38a4da174..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "EntitySnapshot.h" - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include "error.h" - - -namespace armarx::armem::wm -{ - std::vector<aron::datanavigator::DictNavigatorPtr> EntitySnapshot::getAronData() const - { - std::vector<aron::datanavigator::DictNavigatorPtr> ret; - for (const auto& aron : _container) - { - ret.push_back(aron.data()); - } - return ret; - } - - void EntitySnapshot::_copySelfWithoutData(EntitySnapshot& other) const - { - other.id() = _id; - for (const auto& s : _container) - { - other.addInstance(s.copyWithoutData()); - } - } -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h deleted file mode 100644 index 3eedb48d0b4aaa5191541d8ca1586ffc59ab5998..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "../base/EntitySnapshotBase.h" - -#include "EntityInstance.h" -#include "detail/CopyWithoutData.h" - - -namespace armarx::armem::wm -{ - - /** - * @brief Data of an entity at one point in time. - */ - class EntitySnapshot : - public base::EntitySnapshotBase<EntityInstance, EntitySnapshot>, - public detail::CopyWithoutData<EntitySnapshot> - { - using Base = base::EntitySnapshotBase<EntityInstance, EntitySnapshot>; - - public: - - using Base::EntitySnapshotBase; - using Base::operator=; - - std::vector<aron::datanavigator::DictNavigatorPtr> getAronData() const; - - protected: - - virtual void _copySelfWithoutData(EntitySnapshot& other) const override; - - }; -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/Memory.cpp deleted file mode 100644 index 3d2efd2249f969308b126608d01533500f3bfa73..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "Memory.h" - - -namespace armarx::armem::wm -{ - Commit Memory::toCommit() const - { - Commit c; - for (const auto& [k, s] : _container) - { - c.append(s.toCommit()); - } - return c; - } - - void Memory::_copySelfWithoutData(Memory& other) const - { - other.id() = _id; - for (const auto& [k, s] : _container) - { - other.addCoreSegment(s.copyWithoutData()); - } - } -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.h b/source/RobotAPI/libraries/armem/core/workingmemory/Memory.h deleted file mode 100644 index 3c64c0841b46a5c95f7f7365af26a1b20226f4dc..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/Memory.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "../base/MemoryBase.h" - -#include "CoreSegment.h" -#include "detail/CopyWithoutData.h" - - -namespace armarx::armem::wm -{ - - /** - * @brief Data of a memory consisting of multiple core segments. - */ - class Memory : - public base::MemoryBase<CoreSegment, Memory>, - public detail::CopyWithoutData<Memory> - { - using Base = base::MemoryBase<CoreSegment, Memory>; - - public: - - using Base::MemoryBase; - - Memory(const Memory& other) = default; - Memory(Memory&& other) = default; - Memory& operator=(const Memory& other) = default; - Memory& operator=(Memory&& other) = default; - - /** - * @brief Convert the content of this memory into a commit - * @return The resulting commit - */ - Commit toCommit() const; - - protected: - - virtual void _copySelfWithoutData(Memory& other) const override; - - }; -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.cpp deleted file mode 100644 index bd03cf21cd8b616a3afcc4d531377288e55c5f2f..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "ProviderSegment.h" - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include "error.h" - - -namespace armarx::armem::wm -{ - - Commit ProviderSegment::toCommit() const - { - Commit c; - for (const auto& [k, s] : _container) - { - c.append(s.toCommit()); - } - return c; - } - - void ProviderSegment::_copySelfWithoutData(ProviderSegment& other) const - { - other.id() = _id; - other.setMaxHistorySize(_maxHistorySize); - for (const auto& [k, s] : _container) - { - other.addEntity(s.copyWithoutData()); - } - } - -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.h b/source/RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.h deleted file mode 100644 index 7d1e9db335ee39433351a8e15113059836bf825d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "../base/ProviderSegmentBase.h" - -#include "Entity.h" -#include "detail/CopyWithoutData.h" - - -namespace armarx::armem::wm -{ - - /** - * @brief Data of a provider segment containing multiple entities. - */ - class ProviderSegment : - public base::ProviderSegmentBase<Entity, ProviderSegment>, - public detail::CopyWithoutData<ProviderSegment> - - { - using Base = base::ProviderSegmentBase<Entity, ProviderSegment>; - - public: - - using Base::ProviderSegmentBase; - - ProviderSegment(const ProviderSegment& other) = default; - ProviderSegment(ProviderSegment&& other) = default; - ProviderSegment& operator=(const ProviderSegment& other) = default; - ProviderSegment& operator=(ProviderSegment&& other) = default; - - /** - * @brief Convert the content of this segmnet into a commit - * @return The resulting commit - */ - Commit toCommit() const; - - - protected: - - virtual void _copySelfWithoutData(ProviderSegment& other) const override; - - }; - -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/detail/CopyWithoutData.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/detail/CopyWithoutData.cpp deleted file mode 100644 index 70441033dd0fcb24a502bcd4e552764c7c2f5d3c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/detail/CopyWithoutData.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CopyWithoutData.h" diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/detail/CopyWithoutData.h b/source/RobotAPI/libraries/armem/core/workingmemory/detail/CopyWithoutData.h deleted file mode 100644 index caabd1e6002c803aa6a1015afd7ce660abd2482f..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/detail/CopyWithoutData.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - - -namespace armarx::armem::wm::detail -{ - - /** - * @class Allows copying `*this` without data in the leaf - * data structures. - */ - template <class DerivedT> - class CopyWithoutData - { - public: - - /// Get a copy of `this` without data. - virtual DerivedT copyWithoutData() const - { - DerivedT t; - _copySelfWithoutData(t); - return t; - } - - - protected: - - virtual void _copySelfWithoutData(DerivedT& other) const = 0; - - }; -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.cpp deleted file mode 100644 index 31538f8d8e2f1eeaf932ed16e50b7040520f0a99..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "json_conversions.h" - -namespace armarx::armem -{ - - constexpr const char* DATA_WRAPPER_DATA_FIELD = "__ARON_DATA"; - constexpr const char* DATA_WRAPPER_TIME_STORED_FIELD = "__WRITER_METADATA__TIME_STORED"; - constexpr const char* DATA_WRAPPER_TIME_CREATED_FIELD = "__ENTITY_METADATA__TIME_CREATED"; - constexpr const char* DATA_WRAPPER_TIME_SENT_FIELD = "__ENTITY_METADATA__TIME_SENT"; - constexpr const char* DATA_WRAPPER_TIME_ARRIVED_FIELD = "__ENTITY_METADATA__TIME_ARRIVED"; - constexpr const char* DATA_WRAPPER_CONFIDENCE_FIELD = "__ENTITY_METADATA__CONFIDENCE"; - - void from_aron(const aron::datanavigator::DictNavigatorPtr& dataWrapped, wm::EntityInstance& e) - { - wm::EntityInstanceMetadata& metadata = e.metadata(); - - if (dataWrapped->hasElement(DATA_WRAPPER_DATA_FIELD)) - { - aron::datanavigator::DictNavigatorPtr data = aron::datanavigator::DictNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_DATA_FIELD)); - e.setData(data); - } - - auto timeCreated = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_CREATED_FIELD)); - metadata.timeCreated = Time::microSeconds(timeCreated->toAronLongPtr()->value); - - auto timeSent = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_SENT_FIELD)); - metadata.timeSent = Time::microSeconds(timeSent->toAronLongPtr()->value); - - auto timeArrived = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_ARRIVED_FIELD)); - metadata.timeArrived = Time::microSeconds(timeArrived->toAronLongPtr()->value); - - auto confidence = aron::datanavigator::DoubleNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_CONFIDENCE_FIELD)); - metadata.confidence = static_cast<float>(confidence->toAronDoublePtr()->value); - } - - void to_aron(aron::datanavigator::DictNavigatorPtr& a, const wm::EntityInstance& e) - { - if (e.data()) - { - a->addElement(DATA_WRAPPER_DATA_FIELD, e.data()); - } - - auto timeWrapped = std::make_shared<aron::datanavigator::LongNavigator>(); - timeWrapped->setValue(Time::now().toMicroSeconds()); - a->addElement(DATA_WRAPPER_TIME_STORED_FIELD, timeWrapped); - - const wm::EntityInstanceMetadata& metadata = e.metadata(); - auto timeCreated = std::make_shared<aron::datanavigator::LongNavigator>(); - timeCreated->setValue(metadata.timeCreated.toMicroSeconds()); - a->addElement(DATA_WRAPPER_TIME_CREATED_FIELD, timeCreated); - - auto timeSent = std::make_shared<aron::datanavigator::LongNavigator>(); - timeSent->setValue(metadata.timeSent.toMicroSeconds()); - a->addElement(DATA_WRAPPER_TIME_SENT_FIELD, timeSent); - - auto timeArrived = std::make_shared<aron::datanavigator::LongNavigator>(); - timeArrived->setValue(metadata.timeArrived.toMicroSeconds()); - a->addElement(DATA_WRAPPER_TIME_ARRIVED_FIELD, timeArrived); - - auto confidence = std::make_shared<aron::datanavigator::DoubleNavigator>(); - confidence->setValue(static_cast<double>(metadata.confidence)); - a->addElement(DATA_WRAPPER_CONFIDENCE_FIELD, confidence); - } -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/ice_conversions.cpp deleted file mode 100644 index bfc049995a6553e53a78be00294cb9c162e80a0d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/ice_conversions.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "ice_conversions.h" - -namespace armarx::armem -{ - void toIce(armarx::armem::data::EntityInstanceMetadata& ice, const armarx::armem::wm::EntityInstanceMetadata& metadata) - { - ice.confidence = metadata.confidence; - toIce(ice.timeArrivedMicroSeconds, metadata.timeArrived); - toIce(ice.timeCreatedMicroSeconds, metadata.timeCreated); - toIce(ice.timeSentMicroSeconds, metadata.timeSent); - } - void fromIce(const armarx::armem::data::EntityInstanceMetadata& ice, armarx::armem::wm::EntityInstanceMetadata& metadata) - { - metadata.confidence = ice.confidence; - fromIce(ice.timeArrivedMicroSeconds, metadata.timeArrived); - fromIce(ice.timeCreatedMicroSeconds, metadata.timeCreated); - fromIce(ice.timeSentMicroSeconds, metadata.timeSent); - } - - void toIce(data::EntityInstance& ice, const wm::EntityInstance& data) - { - detail::toIceItem(ice, data); - - if (data.data()) - { - ice.data = data.data()->toAronDictPtr(); - } - toIce(ice.metadata, data.metadata()); - } - void fromIce(const data::EntityInstance& ice, wm::EntityInstance& data) - { - detail::fromIceItem(ice, data); - - if (ice.data) - { - data.setData(aron::datanavigator::DictNavigator::FromAronDictPtr(ice.data)); - } - fromIce(ice.metadata, data.metadata()); - } - - - void toIce(data::EntitySnapshot& ice, const wm::EntitySnapshot& snapshot) - { - detail::toIceItem(ice, snapshot); - - toIce(ice.instances, snapshot.instances()); - } - void fromIce(const data::EntitySnapshot& ice, wm::EntitySnapshot& snapshot) - { - detail::fromIceItem(ice, snapshot); - - fromIce(ice.instances, snapshot.instances()); - } - - void toIce(data::Entity& ice, const wm::Entity& entity) - { - detail::toIceItem(ice, entity); - - toIce(ice.history, entity.history()); - } - void fromIce(const data::Entity& ice, wm::Entity& entity) - { - detail::fromIceItem(ice, entity); - - fromIce(ice.history, entity.history()); - } - - - void toIce(data::ProviderSegment& ice, const wm::ProviderSegment& providerSegment) - { - detail::toIceItem(ice, providerSegment); - - if (providerSegment.hasAronType()) - { - ice.aronType = providerSegment.aronType()->toAronPtr(); - } - ARMARX_CHECK(!providerSegment.aronType() || ice.aronType); - toIce(ice.entities, providerSegment.entities()); - } - void fromIce(const data::ProviderSegment& ice, wm::ProviderSegment& providerSegment) - { - detail::fromIceItem(ice, providerSegment); - - if (ice.aronType) - { - providerSegment.aronType() = aron::typenavigator::ObjectNavigator::DynamicCastAndCheck(aron::typenavigator::Navigator::FromAronType(ice.aronType)); - } - ARMARX_CHECK(!providerSegment.aronType() || ice.aronType); - fromIce(ice.entities, providerSegment.entities()); - } - - void toIce(data::CoreSegment& ice, const wm::CoreSegment& coreSegment) - { - detail::toIceItem(ice, coreSegment); - - if (coreSegment.hasAronType()) - { - ice.aronType = coreSegment.aronType()->toAronPtr(); - } - ARMARX_CHECK(!coreSegment.aronType() || ice.aronType); - toIce(ice.providerSegments, coreSegment.providerSegments()); - } - void fromIce(const data::CoreSegment& ice, wm::CoreSegment& coreSegment) - { - detail::fromIceItem(ice, coreSegment); - - if (ice.aronType) - { - coreSegment.aronType() = aron::typenavigator::ObjectNavigator::DynamicCastAndCheck(aron::typenavigator::Navigator::FromAronType(ice.aronType)); - } - ARMARX_CHECK(!coreSegment.aronType() || ice.aronType); - fromIce(ice.providerSegments, coreSegment.providerSegments()); - } - - void toIce(data::Memory& ice, const wm::Memory& memory) - { - detail::toIceItem(ice, memory); - - toIce(ice.coreSegments, memory.coreSegments()); - } - void fromIce(const data::Memory& ice, wm::Memory& memory) - { - detail::fromIceItem(ice, memory); - - fromIce(ice.coreSegments, memory.coreSegments()); - } - -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h b/source/RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h deleted file mode 100644 index 4d14e6b0d04e9086e701cc38a159e516e533d95c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <RobotAPI/interface/armem/commit.h> -#include <RobotAPI/interface/armem/memory.h> - -#include "Memory.h" - - -namespace armarx::armem -{ - void toIce(data::EntityInstanceMetadata& ice, const wm::EntityInstanceMetadata& metadata); - void fromIce(const data::EntityInstanceMetadata& ice, wm::EntityInstanceMetadata& metadata); - - void toIce(data::EntityInstance& ice, const wm::EntityInstance& data); - void fromIce(const data::EntityInstance& ice, wm::EntityInstance& data); - - - void toIce(data::EntitySnapshot& ice, const wm::EntitySnapshot& snapshot); - void fromIce(const data::EntitySnapshot& ice, wm::EntitySnapshot& snapshot); - - void toIce(data::Entity& ice, const wm::Entity& entity); - void fromIce(const data::Entity& ice, wm::Entity& entity); - - - void toIce(data::ProviderSegment& ice, const wm::ProviderSegment& providerSegment); - void fromIce(const data::ProviderSegment& ice, wm::ProviderSegment& providerSegment); - - void toIce(data::CoreSegment& ice, const wm::CoreSegment& coreSegment); - void fromIce(const data::CoreSegment& ice, wm::CoreSegment& coreSegment); - - void toIce(data::Memory& ice, const wm::Memory& memory); - void fromIce(const data::Memory& ice, wm::Memory& memory); -} - -// Must be included after the prototypes. Otherwise the compiler cannot find the correct methods in ice_coversion_templates.h -#include "../ice_conversions.h" diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.h b/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.h deleted file mode 100644 index d132d88f7d7fb694be8b3dc086c87dcafa276e6a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "Memory.h" - -#include <RobotAPI/libraries/aron/core/io/dataIO/converter/Converter.h> -#include <RobotAPI/libraries/aron/core/io/dataIO/visitor/Visitor.h> -#include <RobotAPI/libraries/aron/core/io/dataIO/reader/nlohmannJSON/NlohmannJSONReader.h> -#include <RobotAPI/libraries/aron/core/io/dataIO/writer/nlohmannJSON/NlohmannJSONWriter.h> - - -namespace armarx::armem -{ - void from_aron(const aron::datanavigator::DictNavigatorPtr&, nlohmann::json&); - void to_aron(aron::datanavigator::DictNavigatorPtr&, const nlohmann::json&, const aron::typenavigator::NavigatorPtr& expectedStructure = nullptr); -} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor.h b/source/RobotAPI/libraries/armem/core/workingmemory/visitor.h deleted file mode 100644 index 815ee1b34908dc5916e7d909e709bc735409f63c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/visitor.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#include "visitor/FunctionalVisitor.h" -#include "visitor/Visitor.h" diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp deleted file mode 100644 index ede63a494a7aff26c54ba1d7149200c91be7d987..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "Visitor.h" - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/core/error.h> - - -namespace armarx::armem::wm -{ - - Visitor::Visitor() - { - } - - Visitor::~Visitor() - { - } - - bool Visitor::applyTo(Memory& memory) - { - bool cont = true; - visitEnter(memory); - for (auto& [_, coreSeg] : memory) - { - if (!applyTo(coreSeg)) - { - cont = false; - break; - } - } - visitExit(memory); - return cont; - } - - bool Visitor::applyTo(CoreSegment& coreSegment) - { - bool cont = true; - visitEnter(coreSegment); - for (auto& [_, provSeg] : coreSegment) - { - if (!applyTo(provSeg)) - { - cont = false; - break; - } - } - visitExit(coreSegment); - return cont; - } - - bool Visitor::applyTo(ProviderSegment& providerSegment) - { - bool cont = true; - visitEnter(providerSegment); - for (auto& [_, entity] : providerSegment) - { - if (!applyTo(entity)) - { - cont = false; - break; - } - } - visitExit(providerSegment); - return cont; - } - - bool Visitor::applyTo(Entity& entity) - { - bool cont = true; - visitEnter(entity); - for (auto& [_, snapshot] : entity) - { - if (!applyTo(snapshot)) - { - cont = false; - break; - } - } - visitExit(entity); - return cont; - } - - bool Visitor::applyTo(EntitySnapshot& snapshot) - { - bool cont = true; - visitEnter(snapshot); - for (auto& instance : snapshot) - { - if (!applyTo(instance)) - { - cont = false; - break; - } - } - visitExit(snapshot); - return cont; - } - - bool Visitor::applyTo(EntityInstance& instance) - { - return visit(instance); - } - - - bool Visitor::applyTo(const Memory& memory) - { - bool cont = true; - visitEnter(memory); - for (const auto& [_, coreSeg] : memory) - { - if (!applyTo(coreSeg)) - { - cont = false; - break; - } - } - visitExit(memory); - return cont; - } - - bool Visitor::applyTo(const CoreSegment& coreSegment) - { - bool cont = true; - visitEnter(coreSegment); - for (const auto& [_, provSeg] : coreSegment) - { - if (!applyTo(provSeg)) - { - cont = false; - break; - } - } - visitExit(coreSegment); - return cont; - } - - bool Visitor::applyTo(const ProviderSegment& providerSegment) - { - bool cont = true; - visitEnter(providerSegment); - for (const auto& [_, entity] : providerSegment) - { - if (!applyTo(entity)) - { - cont = false; - break; - } - } - visitExit(providerSegment); - return cont; - } - - bool Visitor::applyTo(const Entity& entity) - { - bool cont = true; - visitEnter(entity); - for (const auto& [_, snapshot] : entity) - { - if (!applyTo(snapshot)) - { - cont = false; - break; - } - } - visitExit(entity); - return cont; - } - - bool Visitor::applyTo(const EntitySnapshot& snapshot) - { - bool cont = true; - visitEnter(snapshot); - for (const auto& instance : snapshot) - { - if (!applyTo(instance)) - { - cont = false; - break; - } - } - visitExit(snapshot); - return cont; - } - - bool Visitor::applyTo(const EntityInstance& instance) - { - return visit(instance); - } - -} diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp b/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp index 7b3a1d05817c9c25675abe2e5b8ab011aba1d92d..ae847a803dc64e68b53c432b222cb6ddbe2fcd86 100644 --- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp @@ -1,18 +1,16 @@ #include "ComponentPlugin.h" -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include "MemoryToIceAdapter.h" #include <RobotAPI/libraries/armem/core/error.h> -#include "MemoryToIceAdapter.h" - -//#include <RobotAPI/libraries/armem/core/io/diskWriter/NlohmannJSON/NlohmannJSONDiskWriter.h> +#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> namespace armarx::armem::server::plugins { - ComponentPlugin::~ComponentPlugin() - {} + ComponentPlugin::~ComponentPlugin() = default; void ComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) @@ -22,12 +20,8 @@ namespace armarx::armem::server::plugins ComponentPluginUser& parent = this->parent<ComponentPluginUser>(); properties->topic(memoryListener, parent.memoryListenerDefaultName); - properties->optional(parent.longtermMemoryEnabled, "ltm.00_enabled"); - properties->optional(parent.longtermMemory.dbsettings.host, "ltm.10_host"); - properties->optional(parent.longtermMemory.dbsettings.port, "ltm.11_port"); - properties->optional(parent.longtermMemory.dbsettings.user, "ltm.20_user"); - properties->optional(parent.longtermMemory.dbsettings.password, "ltm.21_password"); - properties->optional(parent.longtermMemory.dbsettings.database, "ltm.22_database"); + properties->optional(parent.longtermMemoryEnabled, "memory.ltm.00_enabled"); + parent.longtermMemory.defineProperties(properties, "memory"); } @@ -118,6 +112,8 @@ namespace armarx::armem::server addPlugin(plugin); } + ComponentPluginUser::~ComponentPluginUser() = default; + // WRITING data::AddSegmentsResult ComponentPluginUser::addSegments(const data::AddSegmentsInput& input, const Ice::Current&) @@ -128,7 +124,7 @@ namespace armarx::armem::server data::AddSegmentsResult ComponentPluginUser::addSegments(const data::AddSegmentsInput& input, bool addCoreSegments) { - std::scoped_lock lock(workingMemoryMutex); + // std::scoped_lock lock(workingMemoryMutex); data::AddSegmentsResult result = iceMemory.addSegments(input, addCoreSegments); return result; } @@ -136,7 +132,7 @@ namespace armarx::armem::server data::CommitResult ComponentPluginUser::commit(const data::Commit& commitIce, const Ice::Current&) { - std::scoped_lock lock(workingMemoryMutex); + // std::scoped_lock lock(workingMemoryMutex); return iceMemory.commit(commitIce); } @@ -144,19 +140,20 @@ namespace armarx::armem::server // READING armem::query::data::Result ComponentPluginUser::query(const armem::query::data::Input& input, const Ice::Current&) { - std::scoped_lock lock(workingMemoryMutex); + // std::scoped_lock lock(workingMemoryMutex); return iceMemory.query(input); } - // LTM LOADING + + // LTM STORING data::StoreResult ComponentPluginUser::store(const data::StoreInput& input, const Ice::Current&) { - std::scoped_lock lock(workingMemoryMutex, longtermMemoryMutex); + std::scoped_lock lock(/*workingMemoryMutex,*/ longtermMemoryMutex); return iceMemory.store(input); } - // LTM STORING + // LTM LOADING armem::query::data::Result ComponentPluginUser::load(const armem::query::data::Input& input, const Ice::Current&) { std::scoped_lock lock(longtermMemoryMutex); diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h b/source/RobotAPI/libraries/armem/server/ComponentPlugin.h index 5f9ef1d574df06b1644d733e494273ce0660dbbf..0b2b872c1ff4686eecefd8ae8508bcfc45600d5f 100644 --- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h +++ b/source/RobotAPI/libraries/armem/server/ComponentPlugin.h @@ -2,16 +2,16 @@ #include <mutex> -#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/ComponentPlugin.h> #include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/interface/armem/client/MemoryListenerInterface.h> #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h> - #include <RobotAPI/libraries/armem/client/MemoryNameSystemComponentPlugin.h> + #include "MemoryToIceAdapter.h" @@ -73,7 +73,7 @@ namespace armarx::armem::server public: ComponentPluginUser(); - virtual ~ComponentPluginUser() override = default; + virtual ~ComponentPluginUser() override; // WritingInterface interface @@ -96,9 +96,11 @@ namespace armarx::armem::server public: + /// The actual memory. - wm::Memory workingMemory; - std::mutex workingMemoryMutex; + server::wm::Memory workingMemory; + // [[deprecated ("The global working memory mutex is deprecated. Use the core segment mutexes instead.")]] + // std::mutex workingMemoryMutex; bool longtermMemoryEnabled = true; ltm::Memory longtermMemory; @@ -112,6 +114,7 @@ namespace armarx::armem::server private: + plugins::ComponentPlugin* plugin = nullptr; }; diff --git a/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp b/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp index 9ab34efd946541a37ae825d6338a355aec0dd722..6664288a0fa5f86da4df906819cba3be385cbcb9 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp +++ b/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.cpp @@ -1,107 +1,96 @@ #include "MemoryRemoteGui.h" -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include "RemoteGuiAronDataVisitor.h" #include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> #include <RobotAPI/libraries/aron/core/navigator/visitors/DataVisitor.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + #include <SimoxUtility/meta/type_name.h> -#include "RemoteGuiAronDataVisitor.h" +#include <mutex> namespace armarx::armem::server { - MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const wm::Memory& memory) const + template <class ...Args> + MemoryRemoteGui::GroupBox MemoryRemoteGui::_makeGroupBox(const armem::base::MemoryBase<Args...>& memory) const { GroupBox group; - group.setLabel(makeGroupLabel("Memory", memory.name(), memory.coreSegments().size())); + group.setLabel(makeGroupLabel("Memory", memory.name(), memory.size())); - if (memory.coreSegments().empty()) + if (memory.empty()) { group.addChild(Label(makeNoItemsMessage("core segments"))); } - for (const auto& [name, coreSegment] : memory.coreSegments()) + memory.forEachCoreSegment([this, &group](const auto & coreSegment) { - group.addChild(makeGroupBox(coreSegment)); - } - + group.addChild(this->makeGroupBox(coreSegment)); + }); return group; } - - - MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const wm::CoreSegment& coreSegment) const + template <class ...Args> + MemoryRemoteGui::GroupBox MemoryRemoteGui::_makeGroupBox(const armem::base::CoreSegmentBase<Args...>& coreSegment) const { GroupBox group; - group.setLabel(makeGroupLabel("Core Segment", coreSegment.name(), coreSegment.providerSegments().size())); + group.setLabel(makeGroupLabel("Core Segment", coreSegment.name(), coreSegment.size())); - if (coreSegment.providerSegments().empty()) + if (coreSegment.empty()) { group.addChild(Label(makeNoItemsMessage("provider segments"))); } - for (const auto& [name, providerSegment] : coreSegment.providerSegments()) + coreSegment.forEachProviderSegment([this, &group](const auto & providerSegment) { - group.addChild(makeGroupBox(providerSegment)); - } - + group.addChild(this->makeGroupBox(providerSegment)); + }); return group; } - - - MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const wm::ProviderSegment& providerSegment) const + template <class ...Args> + MemoryRemoteGui::GroupBox MemoryRemoteGui::_makeGroupBox(const armem::base::ProviderSegmentBase<Args...>& providerSegment) const { GroupBox group; - group.setLabel(makeGroupLabel("Provider Segment", providerSegment.name(), providerSegment.entities().size())); + group.setLabel(makeGroupLabel("Provider Segment", providerSegment.name(), providerSegment.size())); - if (providerSegment.entities().empty()) + if (providerSegment.empty()) { group.addChild(Label(makeNoItemsMessage("entities"))); } - for (const auto& [name, entity] : providerSegment.entities()) + providerSegment.forEachEntity([this, &group](const auto & entity) { - group.addChild(makeGroupBox(entity)); - } - + group.addChild(this->makeGroupBox(entity)); + }); return group; } - - - MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const wm::Entity& entity) const + template <class ...Args> + MemoryRemoteGui::GroupBox MemoryRemoteGui::_makeGroupBox(const armem::base::EntityBase<Args...>& entity) const { GroupBox group; - group.setLabel(makeGroupLabel("Entity", entity.name(), entity.history().size())); + group.setLabel(makeGroupLabel("Entity", entity.name(), entity.size())); - if (entity.history().empty()) + if (entity.empty()) { group.addChild(Label(makeNoItemsMessage("snapshots"))); } - if (int(entity.history().size()) <= maxHistorySize) + + auto addChild = [this, &group](const armem::wm::EntitySnapshot & snapshot) { - for (const auto& [time, snapshot] : entity.history()) - { - group.addChild(makeGroupBox(snapshot)); - } + group.addChild(makeGroupBox(snapshot)); + }; + + if (int(entity.size()) <= maxHistorySize) + { + entity.forEachSnapshot(addChild); } else { - int margin = 2; - auto it = entity.history().begin(); - auto rit = entity.history().end(); - --rit; - for (int i = 0; i < margin; ++i, ++it) - { - group.addChild(makeGroupBox(it->second)); - --rit; - } - group.addChild(Label("...")); - for (; rit != entity.history().end(); ++rit) - { - group.addChild(makeGroupBox(rit->second)); - } + const int margin = 2; + entity.forEachSnapshotInIndexRange(0, margin, addChild); + entity.forEachSnapshotInIndexRange(-margin, -1, addChild); } group.setCollapsed(true); @@ -109,27 +98,76 @@ namespace armarx::armem::server } + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::server::wm::Memory& memory) const + { + return this->_makeGroupBox(memory); + } + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::wm::Memory& memory) const + { + return this->_makeGroupBox(memory); + } + - MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const wm::EntitySnapshot& snapshot) const + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::server::wm::CoreSegment& coreSegment) const + { + std::scoped_lock lock(coreSegment.mutex()); + return this->_makeGroupBox(coreSegment); + } + + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::wm::CoreSegment& coreSegment) const + { + return this->_makeGroupBox(coreSegment); + } + + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::server::wm::ProviderSegment& providerSegment) const + { + return this->_makeGroupBox(providerSegment); + } + + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::wm::ProviderSegment& providerSegment) const + { + return this->_makeGroupBox(providerSegment); + } + + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::wm::Entity& entity) const + { + return this->_makeGroupBox(entity); + } + + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::server::wm::Entity& entity) const + { + return this->_makeGroupBox(entity); + } + + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::wm::EntitySnapshot& snapshot) const { GroupBox group; group.setLabel(makeGroupLabel("t", armem::toDateTimeMilliSeconds(snapshot.time()), - snapshot.instances().size(), " = ", "")); + snapshot.size(), " = ", "")); - if (snapshot.instances().empty()) + if (snapshot.empty()) { group.addChild(Label(makeNoItemsMessage("instances"))); } - for (const wm::EntityInstance& instance : snapshot.instances()) + snapshot.forEachInstance([this, &group](const armem::wm::EntityInstance & instance) { group.addChild(makeGroupBox(instance)); - } + return true; + }); group.setCollapsed(true); return group; } - MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const wm::EntityInstance& instance) const + + MemoryRemoteGui::GroupBox MemoryRemoteGui::makeGroupBox(const armem::wm::EntityInstance& instance) const { GroupBox group; @@ -153,7 +191,6 @@ namespace armarx::armem::server } - std::string MemoryRemoteGui::makeGroupLabel( const std::string& term, const std::string& name, size_t size, const std::string& namePrefix, const std::string& nameSuffix) const diff --git a/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.h b/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.h index f4a7fad95f1efa38d8ad7044d661e77fef60be31..c6aef5c51546ac203c50d38f80696b89f3b6f3b9 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.h +++ b/source/RobotAPI/libraries/armem/server/MemoryRemoteGui.h @@ -2,7 +2,7 @@ #include <ArmarXGui/libraries/RemoteGui/Client/Widgets.h> -#include "../core/workingmemory/Memory.h" +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> namespace armarx::armem::server @@ -17,12 +17,18 @@ namespace armarx::armem::server using GroupBox = armarx::RemoteGui::Client::GroupBox; using Label = armarx::RemoteGui::Client::Label; - GroupBox makeGroupBox(const wm::Memory& memory) const; - GroupBox makeGroupBox(const wm::CoreSegment& coreSegment) const; - GroupBox makeGroupBox(const wm::ProviderSegment& providerSegment) const; - GroupBox makeGroupBox(const wm::Entity& entity) const; - GroupBox makeGroupBox(const wm::EntitySnapshot& entitySnapshot) const; - GroupBox makeGroupBox(const wm::EntityInstance& instance) const; + + GroupBox makeGroupBox(const armem::wm::Memory& memory) const; + GroupBox makeGroupBox(const armem::wm::CoreSegment& coreSegment) const; + GroupBox makeGroupBox(const armem::wm::ProviderSegment& providerSegment) const; + GroupBox makeGroupBox(const armem::wm::Entity& entity) const; + GroupBox makeGroupBox(const armem::wm::EntitySnapshot& entitySnapshot) const; + GroupBox makeGroupBox(const armem::wm::EntityInstance& instance) const; + + GroupBox makeGroupBox(const armem::server::wm::Memory& memory) const; + GroupBox makeGroupBox(const armem::server::wm::CoreSegment& coreSegment) const; + GroupBox makeGroupBox(const armem::server::wm::ProviderSegment& providerSegment) const; + GroupBox makeGroupBox(const armem::server::wm::Entity& entity) const; std::string makeGroupLabel(const std::string& term, const std::string& name, size_t size, @@ -33,6 +39,17 @@ namespace armarx::armem::server int maxHistorySize = 10; + private: + + template <class ...Args> + MemoryRemoteGui::GroupBox _makeGroupBox(const armem::base::MemoryBase<Args...>& memory) const; + template <class ...Args> + MemoryRemoteGui::GroupBox _makeGroupBox(const armem::base::CoreSegmentBase<Args...>& coreSegment) const; + template <class ...Args> + MemoryRemoteGui::GroupBox _makeGroupBox(const armem::base::ProviderSegmentBase<Args...>& providerSegment) const; + template <class ...Args> + MemoryRemoteGui::GroupBox _makeGroupBox(const armem::base::EntityBase<Args...>& entity) const; + }; diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp index a846cffac89c6118b6c476d3531e47cd49f96f8a..52fb496592390a1f7df893d0709c73937da55ae5 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp @@ -1,12 +1,17 @@ #include "MemoryToIceAdapter.h" -#include "ArmarXCore/core/logging/Logging.h" -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include "query_proc/wm.h" +#include "query_proc/ltm.h" + +#include <RobotAPI/libraries/armem/server/wm/ice_conversions.h> + +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> -#include "../error.h" -#include "../core/workingmemory/ice_conversions.h" -#include "query_proc/workingmemory/MemoryQueryProcessor.h" -#include "query_proc/longtermmemory/MemoryQueryProcessor.h" +#include <RobotAPI/libraries/aron/core/Exception.h> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> namespace armarx::armem::server @@ -33,7 +38,7 @@ namespace armarx::armem::server data::AddSegmentResult output; - armem::wm::CoreSegment* coreSegment = nullptr; + server::wm::CoreSegment* coreSegment = nullptr; try { coreSegment = &workingMemory->getCoreSegment(input.coreSegmentName); @@ -55,6 +60,7 @@ namespace armarx::armem::server if (input.providerSegmentName.size() > 0) { + std::scoped_lock lock(coreSegment->mutex()); try { coreSegment->addProviderSegment(input.providerSegmentName); @@ -64,7 +70,7 @@ namespace armarx::armem::server // This is ok. if (input.clearWhenExists) { - wm::ProviderSegment& provider = coreSegment->getProviderSegment(input.providerSegmentName); + server::wm::ProviderSegment& provider = coreSegment->getProviderSegment(input.providerSegmentName); provider.clear(); } } @@ -94,6 +100,7 @@ namespace armarx::armem::server return output; } + data::CommitResult MemoryToIceAdapter::commit(const data::Commit& commitIce, Time timeArrived) { @@ -140,9 +147,21 @@ namespace armarx::armem::server armem::CommitResult MemoryToIceAdapter::commit(const armem::Commit& commit) + { + return this->_commit(commit, false); + } + + + armem::CommitResult MemoryToIceAdapter::commitLocking(const armem::Commit& commit) + { + return this->_commit(commit, true); + } + + + armem::CommitResult MemoryToIceAdapter::_commit(const armem::Commit& commit, bool locking) { std::vector<data::MemoryID> updatedIDs; - const bool publishUpdates = memoryListenerTopic; + const bool publishUpdates = bool(memoryListenerTopic); CommitResult commitResult; for (const EntityUpdate& update : commit.updates) @@ -150,13 +169,22 @@ namespace armarx::armem::server EntityUpdateResult& result = commitResult.results.emplace_back(); try { - auto updateResult = workingMemory->update(update); + auto updateResult = locking + ? workingMemory->updateLocking(update) + : workingMemory->update(update); result.success = true; result.snapshotID = updateResult.id; result.timeArrived = update.timeArrived; - // TODO: Add if and param here (fabian.peller) + // also store in ltm if transfermode is set to always + // TODO: Move outside of loop? + if (longtermMemory) + { + + } + + // TODO: Consollidate to ltm if onFilledTransfer is enabled (fabian.peller) for (const auto& snapshot : updateResult.removedSnapshots) { ARMARX_DEBUG << "The id " << snapshot.id() << " was removed from wm"; @@ -200,40 +228,60 @@ namespace armarx::armem::server { ARMARX_CHECK_NOT_NULL(workingMemory); - armem::wm::query_proc::MemoryQueryProcessor wm_processor( - input.withData ? armem::DataMode::WithData - : armem::DataMode::NoData); - - armem::query::data::Result result; - wm::Memory wm_result = wm_processor.process(input, *workingMemory, /* execute if: */ { query::data::QueryTarget::WM }); - - armem::ltm::query_proc::MemoryQueryProcessor ltm_processor; - ltm::Memory ltm_result = ltm_processor.process(input, *longtermMemory, /* execute if: */ { query::data::QueryTarget::LTM }); + // Core segment processors will aquire the core segment locks. + query_proc::wm_server::MemoryQueryProcessor wmServerProcessor( + input.withData ? armem::DataMode::WithData : armem::DataMode::NoData); + armem::wm::Memory wmResult = wmServerProcessor.process(input.memoryQueries, *workingMemory); + query_proc::ltm::MemoryQueryProcessor ltmProcessor; + ltm::Memory ltmResult = ltmProcessor.process(input, *longtermMemory); - if (ltm_result.hasData()) + armem::query::data::Result result; + if (not ltmResult.empty()) { + ARMARX_INFO << "The LTM returned data after query"; + // ATTENTION: This code block moves data from LTM back into WM. // However, since some segments are constrained, the WM might send data back to LTM. // This may also affect the data returned by the current query. // However, this is expected behavior, since we copy the data in the processor (copyEmpty) we can safely return the copy and // remove the original memory reference from WM here. - wm::Memory ltm_converted = ltm_result.convert(); - wm_result.append(ltm_converted); + armem::wm::Memory ltmConverted = ltmResult.convert(); + if (ltmConverted.empty()) + { + ARMARX_ERROR << "A converted memory contains no data although the original memory contained data. This indicates that something is wrong."; + } + + wmResult.append(ltmConverted); + if (wmResult.empty()) + { + ARMARX_ERROR << "A merged Memory has no data although at least the LTM result contains data. This indicates that something is wrong."; + } // query again to limit output size (TODO: Skip if querytype is all) - wm::Memory merged_result = wm_processor.process(input, wm_result); + auto queryInput = armem::client::QueryInput::fromIce(input); + queryInput.replaceQueryTarget(query::data::QueryTarget::LTM, query::data::QueryTarget::WM); + + query_proc::wm::MemoryQueryProcessor wm2wmProcessor( + input.withData ? armem::DataMode::WithData : armem::DataMode::NoData); + armem::wm::Memory merged_result = wm2wmProcessor.process(queryInput.toIce(), wmResult); + if (merged_result.empty()) + { + ARMARX_ERROR << "A merged and postprocessed Memory has no data although at least the LTM result contains data. This indicates that something is wrong."; + } + result.memory = toIce<data::MemoryPtr>(merged_result); // also move results of ltm to wm - //this->commit(ltm_converted.toCommit()); + //this->commit(toCommit(ltm_converted)); // mark removed entries of wm in viewer // TODO } else { - result.memory = toIce<data::MemoryPtr>(wm_result); + ARMARX_VERBOSE << "The LTM did not return data after query"; + result.memory = toIce<data::MemoryPtr>(wmResult); } result.success = true; @@ -245,6 +293,13 @@ namespace armarx::armem::server return result; } + + client::QueryResult MemoryToIceAdapter::query(const client::QueryInput& input) + { + return client::QueryResult::fromIce(query(input.toIce())); + } + + // LTM LOADING FROM LTM query::data::Result MemoryToIceAdapter::load(const armem::query::data::Input& query) { @@ -255,6 +310,7 @@ namespace armarx::armem::server return output; } + // LTM STORING data::StoreResult MemoryToIceAdapter::store(const armem::data::StoreInput& input) { @@ -274,7 +330,7 @@ namespace armarx::armem::server if (queryResult.success) { - wm::Memory m; + armem::wm::Memory m; fromIce(queryResult.memory, m); longtermMemory->append(m); } @@ -282,9 +338,8 @@ namespace armarx::armem::server return output; } - client::QueryResult MemoryToIceAdapter::query(const client::QueryInput& input) - { - return client::QueryResult::fromIce(query(input.toIce())); - } + + + } diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h index 919c5fc8dc74ec3f742ac1c33365bc2c680ac768..6aa68b5714ad369e3b2bbad08d7c1ca06ab04bb8 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h @@ -3,15 +3,15 @@ #include <RobotAPI/interface/armem/server/MemoryInterface.h> #include <RobotAPI/interface/armem/client/MemoryListenerInterface.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h> #include <RobotAPI/libraries/armem/client/Query.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> namespace armarx::armem::server { - /** * @brief Helps connecting a Memory server to the Ice interface. * @@ -23,7 +23,8 @@ namespace armarx::armem::server public: /// Construct an MemoryToIceAdapter from an existing Memory. - MemoryToIceAdapter(wm::Memory* workingMemory = nullptr, ltm::Memory* longtermMemory = nullptr); + MemoryToIceAdapter(server::wm::Memory* workingMemory = nullptr, + ltm::Memory* longtermMemory = nullptr); void setMemoryListener(client::MemoryListenerInterfacePrx memoryListenerTopic); @@ -39,6 +40,8 @@ namespace armarx::armem::server data::CommitResult commit(const data::Commit& commitIce, Time timeArrived); data::CommitResult commit(const data::Commit& commitIce); armem::CommitResult commit(const armem::Commit& commit); + armem::CommitResult commitLocking(const armem::Commit& commit); + // READING query::data::Result query(const armem::query::data::Input& input); @@ -52,11 +55,16 @@ namespace armarx::armem::server public: - wm::Memory* workingMemory; + server::wm::Memory* workingMemory; ltm::Memory* longtermMemory; client::MemoryListenerInterfacePrx memoryListenerTopic; + + private: + + armem::CommitResult _commit(const armem::Commit& commit, bool locking); + }; diff --git a/source/RobotAPI/libraries/armem/server/Segment.cpp b/source/RobotAPI/libraries/armem/server/Segment.cpp deleted file mode 100644 index ec25ce7843a6cca3555dc9789f3570e0bfb51425..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/Segment.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Segment.h" diff --git a/source/RobotAPI/libraries/armem/server/Segment.h b/source/RobotAPI/libraries/armem/server/Segment.h deleted file mode 100644 index 5d1c31f4179773a5fa2e96d9ebd211507e91893d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/Segment.h +++ /dev/null @@ -1,160 +0,0 @@ -#pragma once - -// STD/STL -#include <mutex> -#include <string> - -// ArmarX -#include <ArmarXCore/core/logging/Logging.h> -#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> - -#include "MemoryToIceAdapter.h" - - -namespace armarx::armem::server -{ - /** - * @brief A base class for memory servers to manage their segments. - * A segment can inherit this base class and add segment specific code. - * TODO (fabian.peller): add concept to only accept coresegments, providersegments or entitysegments - */ - template <class SegmentType> - class SegmentBase : public armarx::Logging - { - public: - SegmentBase() = delete; - SegmentBase(armem::server::MemoryToIceAdapter& iceMemory, std::mutex& memoryMutex) : - iceMemory(iceMemory), - memoryMutex(memoryMutex) - { - Logging::setTag("armarx::armem::Segment"); - } - - virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") = 0; - virtual void onInit() = 0; - virtual void onConnect() = 0; - - protected: - private: - - public: - protected: - // Memory connection - armem::server::MemoryToIceAdapter& iceMemory; - std::mutex& memoryMutex; - - SegmentType* segment; - - private: - }; - - namespace wm - { - template <class BusinessClassObject> - class CoreSegmentBase : public SegmentBase<armarx::armem::wm::CoreSegment> - { - using Base = SegmentBase<armarx::armem::wm::CoreSegment>; - - public: - CoreSegmentBase(armem::server::MemoryToIceAdapter& iceMemory, std::mutex& memoryMutex): - Base(iceMemory, memoryMutex) - { - Logging::setTag("armarx::armem::wm::Segment"); - } - - virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") override - { - ARMARX_CHECK_NOT_NULL(defs); - - defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the '" + p.coreSegmentName + "' core segment."); - defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of '" + p.coreSegmentName + "' history (-1 for infinite)."); - } - - virtual void onInit() override - { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - segment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName, BusinessClassObject::toAronType()); - segment->setMaxHistorySize(p.maxHistorySize); - } - - virtual void onConnect() override - { - - } - - protected: - private: - - public: - protected: - struct Properties - { - std::string coreSegmentName = ""; - int maxHistorySize = -1; - }; - Properties p; - }; - - - template <class BusinessClassObject> - class ProviderSegmentBase : public SegmentBase<armarx::armem::wm::ProviderSegment> - { - using Base = SegmentBase<armarx::armem::wm::ProviderSegment>; - - public: - ProviderSegmentBase(armem::server::MemoryToIceAdapter& iceMemory, std::mutex& memoryMutex): - Base(iceMemory, memoryMutex) - { - Logging::setTag("armarx::armem::wm::Segment"); - } - - virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") override - { - ARMARX_CHECK_NOT_NULL(defs); - - defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the core segment."); - defs->optional(p.providerSegmentName, prefix + "ProviderSegmentName", "Name of the provider segment."); - defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of history (-1 for infinite)."); - } - - virtual void onInit() override - { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - if (!iceMemory.workingMemory->hasCoreSegment(p.coreSegmentName)) - { - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName); - coreSegment->setMaxHistorySize(p.maxHistorySize); - } - else - { - coreSegment = &iceMemory.workingMemory->getCoreSegment(p.coreSegmentName); - } - - segment = &coreSegment->addProviderSegment(p.providerSegmentName, BusinessClassObject::toAronType()); - segment->setMaxHistorySize(p.maxHistorySize); - } - - virtual void onConnect() override - { - - } - - protected: - private: - - public: - protected: - struct Properties - { - std::string coreSegmentName = ""; - std::string providerSegmentName = ""; - int maxHistorySize = -1; - }; - Properties p; - - armarx::armem::wm::CoreSegment* coreSegment; - }; - } -} diff --git a/source/RobotAPI/libraries/armem/server/forward_declarations.h b/source/RobotAPI/libraries/armem/server/forward_declarations.h new file mode 100644 index 0000000000000000000000000000000000000000..6872e2584352195ca8e587043e275acfbffb3739 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/forward_declarations.h @@ -0,0 +1,18 @@ +#pragma once + +#include <RobotAPI/libraries/armem/core/forward_declarations.h> + + +namespace armarx::armem::server +{ + class MemoryToIceAdapter; +} +namespace armarx::armem::server::wm +{ + using EntityInstance = armem::wm::EntityInstance; + using EntitySnapshot = armem::wm::EntitySnapshot; + class Entity; + class ProviderSegment; + class CoreSegment; + class Memory; +} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base.h b/source/RobotAPI/libraries/armem/server/query_proc/base.h new file mode 100644 index 0000000000000000000000000000000000000000..1d826798cecac7371882ce0783ddc05414a4f237 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/query_proc/base.h @@ -0,0 +1,12 @@ +#pragma once + +#include <RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h> +#include <RobotAPI/libraries/armem/server/query_proc/base/ProviderSegmentQueryProcessorBase.h> +#include <RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h> +#include <RobotAPI/libraries/armem/server/query_proc/base/MemoryQueryProcessorBase.h> + + +namespace armarx::armem::server::query_proc::base +{ + +} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.cpp b/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.cpp index ce437fd67bdd2ba3aa6ac9943093525db99a581e..a3dfb4eb4102e21ee0cc97d7a9919b55c7c83f35 100644 --- a/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.cpp +++ b/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.cpp @@ -1 +1,21 @@ #include "BaseQueryProcessorBase.h" + +#include <ArmarXCore/core/logging/Logging.h> + + +namespace armarx::armem::server::query_proc::base +{ + + std::set<query::data::QueryTarget> + detail::getTargets(const std::vector<query::data::QueryTarget>& _targets) + { + std::set<query::data::QueryTarget> targets(_targets.begin(), _targets.end()); + if (targets.empty()) + { + ARMARX_DEBUG << "Query has no targets - using WM as default."; + targets.insert(query::data::QueryTarget::WM); + } + return targets; + } + +} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.h index f71aede29731259471cf5e8dd660917b3e848bb1..73c662e04ebd734cbe79c3b19f676f684223a88c 100644 --- a/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.h +++ b/source/RobotAPI/libraries/armem/server/query_proc/base/BaseQueryProcessorBase.h @@ -1,88 +1,91 @@ #pragma once -#include <ArmarXCore/core/logging/Logging.h> #include <RobotAPI/interface/armem/query.h> +#include <Ice/Handle.h> -namespace armarx::armem::base::query_proc +#include <set> +#include <vector> + + +namespace armarx::armem::server::query_proc::base::detail +{ + // If empty, e.g. when receiving queries from python, we use WM as default. + // We do it here as (Sl)ice does not support default values for vectors. + std::set<query::data::QueryTarget> getTargets(const std::vector<query::data::QueryTarget>& _targets); +} +namespace armarx::armem::server::query_proc::base { + using QueryTarget = query::data::QueryTarget; + + /** * @brief Base class for memory query processors. */ - template <class DataT, class QueryT> + template <QueryTarget queryTarget, class DataT, class ResultT, class QueryT> class BaseQueryProcessorBase { public: + using QueryPtrT = ::IceInternal::Handle<QueryT>; using QuerySeqT = std::vector<QueryPtrT>; + public: - DataT process(const QueryT& query, const DataT& data, const query::data::QueryTargets& executeIf = {}) const - { - DataT result = data.copyEmpty(); + virtual ~BaseQueryProcessorBase() = default; - for (const auto queryTarget : query.targets) + + ResultT process(const QueryT& query, const DataT& data) const + { + ResultT result { data.id() }; + if (detail::getTargets(query.targets).count(queryTarget)) { - if (std::find(executeIf.begin(), executeIf.end(), queryTarget) != executeIf.end()) - { - this->process(result, query, data); - break; - } + this->process(result, query, data); } return result; } - DataT process(const QueryPtrT& query, const DataT& data, const query::data::QueryTargets& executeIf = {}) const + ResultT process(const QueryPtrT& query, const DataT& data) const { - return this->process(*query, *data, executeIf); + return this->process(*query, *data); } - DataT process(const QuerySeqT& queries, const DataT& data, const query::data::QueryTargets& executeIf = {}) const + ResultT process(const QuerySeqT& queries, const DataT& data) const { - DataT result = data.copyEmpty(); - this->process(result, queries, data, executeIf); + ResultT result { data.id() }; + this->process(result, queries, data); return result; } - void process(DataT& result, const QuerySeqT& queries, const DataT& data, const query::data::QueryTargets& executeIf = {}) const + void process(ResultT& result, const QuerySeqT& queries, const DataT& data) const { if (queries.empty()) { - ARMARX_DEBUG << "There are no queries to process."; - return; - } - - if (executeIf.empty()) - { - ARMARX_DEBUG << "Could not execute query. ExecuteIf s empty."; return; } for (const auto& query : queries) { - if (query->targets.empty()) - { - ARMARX_DEBUG << "The targets of a query are empty"; - continue; - } - - for (const auto queryTarget : query->targets) + if (detail::getTargets(query->targets).count(queryTarget)) { - if (std::find(executeIf.begin(), executeIf.end(), queryTarget) != executeIf.end()) - { - this->process(result, *query, data); - break; - } - else - { - ARMARX_DEBUG << "The query target " << queryTarget << " was not found in executeIf: " << executeIf; - } + this->process(result, *query, data); } } } - virtual void process(DataT& result, const QueryT& query, const DataT& data) const = 0; + + /** + * @brief Process the query and populate `result`. + * + * @param result The result container. + * @param query The query. + * @param data The source container. + */ + virtual void process(ResultT& result, const QueryT& query, const DataT& data) const = 0; + }; + + } diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h index f8ab8c113e510e57a1ab2b53af6a06e60e393ce1..3050e6e4e91a90bfbfa97feff7f3afc6cb804f41 100644 --- a/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h +++ b/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h @@ -1,41 +1,54 @@ #pragma once -#include <RobotAPI/interface/armem/query.h> - -#include "BaseQueryProcessorBase.h" -#include "ProviderSegmentQueryProcessorBase.h" - #include <regex> #include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/interface/armem/query.h> #include <RobotAPI/libraries/armem/core/error.h> +#include "BaseQueryProcessorBase.h" -namespace armarx::armem::base::query_proc +namespace armarx::armem::server::query_proc::base { /** * @brief Handles memory queries. */ - template <class _CoreSegmentT> + template <QueryTarget queryTarget, class _CoreSegmentT, class _ResultCoreSegmentT, class _ChildProcessorT> class CoreSegmentQueryProcessorBase : - virtual public BaseQueryProcessorBase<_CoreSegmentT, armem::query::data::CoreSegmentQuery> + public BaseQueryProcessorBase<queryTarget, _CoreSegmentT, _ResultCoreSegmentT, armem::query::data::CoreSegmentQuery> { - using Base = BaseQueryProcessorBase<_CoreSegmentT, armem::query::data::CoreSegmentQuery>; + using Base = BaseQueryProcessorBase<queryTarget, _CoreSegmentT, _ResultCoreSegmentT, armem::query::data::CoreSegmentQuery>; public: + using CoreSegmentT = _CoreSegmentT; - using ProviderSegmentT = typename _CoreSegmentT::ProviderSegmentT; - using EntityT = typename ProviderSegmentT::EntityT; - using EntitySnapshotT = typename EntityT::EntitySnapshotT; + using ProviderSegmentT = typename CoreSegmentT::ProviderSegmentT; + + using ResultCoreSegmentT = _ResultCoreSegmentT; + using ResultProviderSegmentT = typename ResultCoreSegmentT::ProviderSegmentT; + + using ChildProcessorT = _ChildProcessorT; + + + public: + + CoreSegmentQueryProcessorBase() + { + } + CoreSegmentQueryProcessorBase(ChildProcessorT&& childProcessor) : + childProcessor(childProcessor) + { + } + using Base::process; - void process(_CoreSegmentT& result, - const armem::query::data::CoreSegmentQuery& query, - const _CoreSegmentT& coreSegment) const override + virtual void process(ResultCoreSegmentT& result, + const armem::query::data::CoreSegmentQuery& query, + const CoreSegmentT& coreSegment) const override { if (auto q = dynamic_cast<const armem::query::data::core::All*>(&query)) { @@ -55,24 +68,24 @@ namespace armarx::armem::base::query_proc } } - void process(_CoreSegmentT& result, + void process(ResultCoreSegmentT& result, const armem::query::data::core::All& query, - const _CoreSegmentT& coreSegment) const + const CoreSegmentT& coreSegment) const { - for (const auto& [name, providerSegment] : coreSegment.providerSegments()) + coreSegment.forEachProviderSegment([this, &query, &result](const ProviderSegmentT & providerSegment) { - result.addProviderSegment(providerSegmentProcessorProcess(query.providerSegmentQueries, providerSegment)); - } + childProcessor.process(result.addProviderSegment(providerSegment.name()), query.providerSegmentQueries, providerSegment); + }); } - void process(_CoreSegmentT& result, + void process(ResultCoreSegmentT& result, const armem::query::data::core::Single& query, - const _CoreSegmentT& coreSegment) const + const CoreSegmentT& coreSegment) const { try { const ProviderSegmentT& providerSegment = coreSegment.getProviderSegment(query.providerSegmentName); - result.addProviderSegment(providerSegmentProcessorProcess(query.providerSegmentQueries, providerSegment)); + childProcessor.process(result.addProviderSegment(providerSegment.name()), query.providerSegmentQueries, providerSegment); } catch (const error::MissingEntry&) { @@ -80,21 +93,25 @@ namespace armarx::armem::base::query_proc } } - void process(_CoreSegmentT& result, + void process(ResultCoreSegmentT& result, const armem::query::data::core::Regex& query, - const _CoreSegmentT& coreSegment) const + const CoreSegmentT& coreSegment) const { std::regex regex(query.providerSegmentNameRegex); - for (const auto& [name, providerSegment] : coreSegment.providerSegments()) + coreSegment.forEachProviderSegment( + [this, &result, &query, ®ex](const ProviderSegmentT & providerSegment) { if (std::regex_search(providerSegment.name(), regex)) { - result.addProviderSegment(providerSegmentProcessorProcess(query.providerSegmentQueries, providerSegment)); + childProcessor.process(result.addProviderSegment(providerSegment.name()), query.providerSegmentQueries, providerSegment); } - } + }); } + protected: - virtual ProviderSegmentT providerSegmentProcessorProcess(const armem::query::data::ProviderSegmentQuerySeq& a, const ProviderSegmentT& o) const = 0; + + ChildProcessorT childProcessor; + }; } diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h index 40113207f194c76301fbe8768a6d42c22f8b01db..0c4a842fa2772ae18b475b9e28ad3b13077bb49d 100644 --- a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h +++ b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h @@ -1,41 +1,42 @@ #pragma once -#include <cstdint> -#include <iterator> +#include "BaseQueryProcessorBase.h" + +#include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/ice_conversions.h> #include <RobotAPI/interface/armem/query.h> -#include <ArmarXCore/core/exceptions/LocalException.h> -#include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/logging/Logging.h> -#include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/ice_conversions.h> - -#include "BaseQueryProcessorBase.h" -#include "RobotAPI/libraries/armem/core/Time.h" +#include <cstdint> +#include <iterator> -namespace armarx::armem::base::query_proc +namespace armarx::armem::server::query_proc::base { - /** - * @brief Handles memory queries. - */ - template <class _EntityT> + template <QueryTarget queryTarget, class _EntityT, class _ResultEntityT> class EntityQueryProcessorBase : - virtual public BaseQueryProcessorBase<_EntityT, armem::query::data::EntityQuery> + public BaseQueryProcessorBase<queryTarget, _EntityT, _ResultEntityT, armem::query::data::EntityQuery> { - using Base = BaseQueryProcessorBase<_EntityT, armem::query::data::EntityQuery>; + using Base = BaseQueryProcessorBase<queryTarget, _EntityT, _ResultEntityT, armem::query::data::EntityQuery>; public: + using EntityT = _EntityT; using EntitySnapshotT = typename EntityT::EntitySnapshotT; + using ResultEntityT = _ResultEntityT; + using ResultSnapshotT = typename ResultEntityT::EntitySnapshotT; + + using Base::process; - void process(_EntityT& result, - const armem::query::data::EntityQuery& query, - const _EntityT& entity) const override + virtual void process(ResultEntityT& result, + const armem::query::data::EntityQuery& query, + const EntityT& entity) const override { if (auto q = dynamic_cast<const armem::query::data::entity::All*>(&query)) { @@ -71,22 +72,24 @@ namespace armarx::armem::base::query_proc } } - void process(_EntityT& result, + + void process(ResultEntityT& result, const armem::query::data::entity::All& query, - const _EntityT& entity) const + const EntityT& entity) const { (void) query; // Copy this entitiy and its contents. - for (const auto& [time, snapshot] : entity) + entity.forEachSnapshot([this, &result](const EntitySnapshotT & snapshot) { addResultSnapshot(result, snapshot); - } + }); } - void process(_EntityT& result, + + void process(ResultEntityT& result, const armem::query::data::entity::Single& query, - const _EntityT& entity) const + const EntityT& entity) const { if (query.timestamp < 0) { @@ -131,9 +134,10 @@ namespace armarx::armem::base::query_proc } } - void process(_EntityT& result, + + void process(ResultEntityT& result, const armem::query::data::entity::TimeRange& query, - const _EntityT& entity) const + const EntityT& entity) const { if (query.minTimestamp <= query.maxTimestamp || query.minTimestamp < 0 || query.maxTimestamp < 0) { @@ -143,54 +147,39 @@ namespace armarx::armem::base::query_proc } } - void process(_EntityT& result, + + void process(ResultEntityT& result, const armem::query::data::entity::IndexRange& query, - const _EntityT& entity) const + const EntityT& entity) const { - if (entity.empty()) - { - return; - } - - size_t first = negativeIndexSemantics(query.first, entity.history().size()); - size_t last = negativeIndexSemantics(query.last, entity.history().size()); - - if (first <= last) + entity.forEachSnapshotInIndexRange( + query.first, query.last, + [this, &result](const EntitySnapshotT & snapshot) { - auto it = entity.begin(); - std::advance(it, first); - - size_t num = last - first + 1; // +1 to make last inclusive - for (size_t i = 0; i < num; ++i, ++it) - { - addResultSnapshot(result, it); - } - } + addResultSnapshot(result, snapshot); + }); } - void process(_EntityT& result, + + void process(ResultEntityT& result, const Time& min, const Time& max, - const _EntityT& entity, + const EntityT& entity, const armem::query::data::EntityQuery& query) const { (void) query; - - // Returns an iterator pointing to the first element that is not less than (i.e. greater or equal to) key. - auto begin = min.toMicroSeconds() > 0 ? entity.history().lower_bound(min) : entity.history().begin(); - // Returns an iterator pointing to the first element that is *greater than* key. - auto end = max.toMicroSeconds() > 0 ? entity.history().upper_bound(max) : entity.history().end(); - - for (auto it = begin; it != end && it != entity.history().end(); ++it) + entity.forEachSnapshotInTimeRange( + min, max, + [this, &result](const EntitySnapshotT & snapshot) { - addResultSnapshot(result, it); - } + addResultSnapshot(result, snapshot); + }); } - void process(_EntityT& result, + void process(ResultEntityT& result, const armem::query::data::entity::BeforeOrAtTime& query, - const _EntityT& entity) const + const EntityT& entity) const { const auto referenceTimestamp = fromIce<Time>(query.timestamp); ARMARX_CHECK(referenceTimestamp.toMicroSeconds() >= 0) << "Reference timestamp is negative!"; @@ -207,39 +196,40 @@ namespace armarx::armem::base::query_proc } - void process(_EntityT& result, + void process(ResultEntityT& result, const armem::query::data::entity::BeforeTime& query, - const _EntityT& entity) const + const EntityT& entity) const { - const auto referenceTimestamp = fromIce<Time>(query.timestamp); - ARMARX_CHECK(referenceTimestamp.toMicroSeconds() >= 0) << "Reference timestamp is negative!"; + const armem::Time referenceTimestamp = fromIce<Time>(query.timestamp); + ARMARX_CHECK(referenceTimestamp.toMicroSeconds() >= 0) << "Reference timestamp must be non-negative."; - const auto maxEntries = fromIce<std::int64_t>(query.maxEntries); - - try + std::vector<const EntitySnapshotT*> befores; + entity.forEachSnapshotBefore(referenceTimestamp, [&befores](const EntitySnapshotT & s) { - const auto before = entity.getSnapshotsBefore(referenceTimestamp); + befores.push_back(&s); + }); - int i = 0; - for (const auto& snapshot : before) - { - if (maxEntries >= 0 && i >= maxEntries) - { - break; - } - addResultSnapshot(result, snapshot); - ++i; - } + size_t num = 0; + if (query.maxEntries < 0) + { + num = befores.size(); } - catch (const error::MissingEntry&) + else { - // Leave empty. + num = std::min(befores.size(), static_cast<size_t>(query.maxEntries)); + } + + for (size_t r = 0; r < num; ++r) + { + size_t i = befores.size() - 1 - r; + addResultSnapshot(result, *befores[i]); } } - void process(_EntityT& result, + + void process(ResultEntityT& result, const armem::query::data::entity::TimeApprox& query, - const _EntityT& entity) const + const EntityT& entity) const { const auto referenceTimestamp = fromIce<Time>(query.timestamp); ARMARX_CHECK(referenceTimestamp.toMicroSeconds() >= 0) << "Reference timestamp is negative!"; @@ -285,26 +275,16 @@ namespace armarx::armem::base::query_proc } catch (const armem::error::MissingEntry&) { - } } - static size_t negativeIndexSemantics(long index, size_t size) - { - const size_t max = size > 0 ? size - 1 : 0; - if (index >= 0) - { - return std::clamp<size_t>(static_cast<size_t>(index), 0, max); - } - else - { - return static_cast<size_t>(std::clamp<long>(static_cast<long>(size) + index, 0, static_cast<long>(max))); - } - } protected: - virtual void addResultSnapshot(_EntityT& result, typename _EntityT::ContainerT::const_iterator it) const = 0; - virtual void addResultSnapshot(_EntityT& result, const typename _EntityT::EntitySnapshotT& snapshot) const = 0; + + void addResultSnapshot(ResultEntityT& result, const EntitySnapshotT& snapshot) const + { + result.addSnapshot(snapshot); + } }; } diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/MemoryQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/MemoryQueryProcessorBase.h index cc06defc93976ea018ab8a7d3823a00d6121543d..df71683c29f2cb17db976e8be971725934b03348 100644 --- a/source/RobotAPI/libraries/armem/server/query_proc/base/MemoryQueryProcessorBase.h +++ b/source/RobotAPI/libraries/armem/server/query_proc/base/MemoryQueryProcessorBase.h @@ -1,47 +1,56 @@ #pragma once -#include <regex> - -#include <RobotAPI/interface/armem/query.h> - #include "BaseQueryProcessorBase.h" -#include "CoreSegmentQueryProcessorBase.h" +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/interface/armem/query.h> #include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> -#include <RobotAPI/libraries/armem/core/error.h> +#include <regex> -namespace armarx::armem::base::query_proc +namespace armarx::armem::server::query_proc::base { - /** - * @brief Handles memory queries. - */ - template <class _MemoryT> + + template <QueryTarget queryTarget, class _MemoryT, class _ResultMemoryT, class _ChildProcessorT> class MemoryQueryProcessorBase : - virtual public BaseQueryProcessorBase<_MemoryT, armem::query::data::MemoryQuery> + public BaseQueryProcessorBase<queryTarget, _MemoryT, _ResultMemoryT, armem::query::data::MemoryQuery> { - using Base = BaseQueryProcessorBase<_MemoryT, armem::query::data::MemoryQuery>; + using Base = BaseQueryProcessorBase<queryTarget, _MemoryT, _ResultMemoryT, armem::query::data::MemoryQuery>; public: + using MemoryT = _MemoryT; using CoreSegmentT = typename MemoryT::CoreSegmentT; - using ProviderSegmentT = typename CoreSegmentT::ProviderSegmentT; - using EntityT = typename ProviderSegmentT::EntityT; - using EntitySnapshotT = typename EntityT::EntitySnapshotT; + + using ResultMemoryT = _ResultMemoryT; + using ResultCoreSegmentT = typename ResultMemoryT::CoreSegmentT; + + using ChildProcessorT = _ChildProcessorT; + + + public: + + MemoryQueryProcessorBase() + { + } + MemoryQueryProcessorBase(ChildProcessorT&& childProcessor) : + childProcessor(childProcessor) + { + } using Base::process; - _MemoryT process(const armem::query::data::Input& input, const _MemoryT& memory, const std::vector<query::data::QueryTarget>& executeIf = {}) const + ResultMemoryT process(const armem::query::data::Input& input, const MemoryT& memory) const { - return this->process(input.memoryQueries, memory, executeIf); + return this->process(input.memoryQueries, memory); } - void process(_MemoryT& result, - const armem::query::data::MemoryQuery& query, - const _MemoryT& memory) const override + virtual void process(ResultMemoryT& result, + const armem::query::data::MemoryQuery& query, + const MemoryT& memory) const override { if (auto q = dynamic_cast<const armem::query::data::memory::All*>(&query)) { @@ -57,49 +66,52 @@ namespace armarx::armem::base::query_proc } else { - throw armem::error::UnknownQueryType("memory segment", query); + throw armem::error::UnknownQueryType(MemoryT::getLevelName(), query); } } - void process(_MemoryT& result, + void process(ResultMemoryT& result, const armem::query::data::memory::All& query, - const _MemoryT& memory) const + const MemoryT& memory) const { - for (const auto& [name, coreSegment] : memory.coreSegments()) + memory.forEachCoreSegment([this, &result, &query](const CoreSegmentT & coreSegment) { - result.addCoreSegment(coreSegmentProcessorProcess(query.coreSegmentQueries, coreSegment)); - } + childProcessor.process(result.addCoreSegment(coreSegment.name()), query.coreSegmentQueries, coreSegment); + }); } - void process(_MemoryT& result, + void process(ResultMemoryT& result, const armem::query::data::memory::Single& query, - const _MemoryT& memory) const + const MemoryT& memory) const { try { const CoreSegmentT& coreSegment = memory.getCoreSegment(query.coreSegmentName); - result.addCoreSegment(coreSegmentProcessorProcess(query.coreSegmentQueries, coreSegment)); + childProcessor.process(result.addCoreSegment(coreSegment.name()), query.coreSegmentQueries, coreSegment); } catch (const error::MissingEntry&) { } } - void process(_MemoryT& result, + void process(ResultMemoryT& result, const armem::query::data::memory::Regex& query, - const _MemoryT& memory) const + const MemoryT& memory) const { - std::regex regex(query.coreSegmentNameRegex); - for (const auto& [name, coreSegment] : memory.coreSegments()) + const std::regex regex(query.coreSegmentNameRegex); + memory.forEachCoreSegment([this, &result, &query, ®ex](const CoreSegmentT & coreSegment) { if (std::regex_search(coreSegment.name(), regex)) { - result.addCoreSegment(coreSegmentProcessorProcess(query.coreSegmentQueries, coreSegment)); + childProcessor.process(result.addCoreSegment(coreSegment.name()), query.coreSegmentQueries, coreSegment); } - } + }); } + protected: - virtual CoreSegmentT coreSegmentProcessorProcess(const armem::query::data::CoreSegmentQuerySeq& a, const CoreSegmentT& o) const = 0; + + ChildProcessorT childProcessor; + }; } diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/ProviderSegmentQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/ProviderSegmentQueryProcessorBase.h index b3b7da7ffa9cc1d06aeadabef58c5aebba3974de..5102a12829c106e58159e7dcc35a7df0890f93d5 100644 --- a/source/RobotAPI/libraries/armem/server/query_proc/base/ProviderSegmentQueryProcessorBase.h +++ b/source/RobotAPI/libraries/armem/server/query_proc/base/ProviderSegmentQueryProcessorBase.h @@ -1,39 +1,50 @@ #pragma once -#include <RobotAPI/interface/armem/query.h> - #include "BaseQueryProcessorBase.h" -#include "EntityQueryProcessorBase.h" -#include <regex> +#include <RobotAPI/libraries/armem/core/error.h> -#include <ArmarXCore/core/logging/Logging.h> -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/interface/armem/query.h> -#include <RobotAPI/libraries/armem/core/error.h> +#include <regex> -namespace armarx::armem::base::query_proc +namespace armarx::armem::server::query_proc::base { - /** - * @brief Handles memory queries. - */ - template <class _ProviderSegmentT> + template <QueryTarget queryTarget, class _ProviderSegmentT, class _ResultProviderSegmentT, class _ChildProcessorT> class ProviderSegmentQueryProcessorBase : - virtual public BaseQueryProcessorBase<_ProviderSegmentT, armem::query::data::ProviderSegmentQuery> + public BaseQueryProcessorBase<queryTarget, _ProviderSegmentT, _ResultProviderSegmentT, armem::query::data::ProviderSegmentQuery> { - using Base = BaseQueryProcessorBase<_ProviderSegmentT, armem::query::data::ProviderSegmentQuery>; + using Base = BaseQueryProcessorBase<queryTarget, _ProviderSegmentT, _ResultProviderSegmentT, armem::query::data::ProviderSegmentQuery>; + public: + using ProviderSegmentT = _ProviderSegmentT; using EntityT = typename ProviderSegmentT::EntityT; - using EntitySnapshotT = typename EntityT::EntitySnapshotT; + + using ResultProviderSegmentT = _ResultProviderSegmentT; + using ResultEntityT = typename ResultProviderSegmentT::EntityT; + + using ChildProcessorT = _ChildProcessorT; + + + public: + + ProviderSegmentQueryProcessorBase() + { + } + ProviderSegmentQueryProcessorBase(ChildProcessorT&& childProcessor) : + childProcessor(childProcessor) + { + } + using Base::process; - void process(_ProviderSegmentT& result, - const armem::query::data::ProviderSegmentQuery& query, - const _ProviderSegmentT& providerSegment) const override + virtual void process(ResultProviderSegmentT& result, + const armem::query::data::ProviderSegmentQuery& query, + const ProviderSegmentT& providerSegment) const override { if (auto q = dynamic_cast<const armem::query::data::provider::All*>(&query)) { @@ -49,28 +60,28 @@ namespace armarx::armem::base::query_proc } else { - throw armem::error::UnknownQueryType("provider segment", query); + throw armem::error::UnknownQueryType(ProviderSegmentT::getLevelName(), query); } } - void process(_ProviderSegmentT& result, + void process(ResultProviderSegmentT& result, const armem::query::data::provider::All& query, - const _ProviderSegmentT& providerSegment) const + const ProviderSegmentT& providerSegment) const { - for (const auto& [name, entity] : providerSegment.entities()) + providerSegment.forEachEntity([this, &result, &query](const EntityT & entity) { - result.addEntity(entityProcessorProcess(query.entityQueries, entity)); - } + childProcessor.process(result.addEntity(entity.name()), query.entityQueries, entity); + }); } - void process(_ProviderSegmentT& result, + void process(ResultProviderSegmentT& result, const armem::query::data::provider::Single& query, - const _ProviderSegmentT& providerSegment) const + const ProviderSegmentT& providerSegment) const { try { const EntityT& entity = providerSegment.getEntity(query.entityName); - result.addEntity(entityProcessorProcess(query.entityQueries, entity)); + childProcessor.process(result.addEntity(entity.name()), query.entityQueries, entity); } catch (const error::MissingEntry&) { @@ -78,21 +89,25 @@ namespace armarx::armem::base::query_proc } } - void process(_ProviderSegmentT& result, + void process(ResultProviderSegmentT& result, const armem::query::data::provider::Regex& query, - const _ProviderSegmentT& providerSegment) const + const ProviderSegmentT& providerSegment) const { - std::regex regex(query.entityNameRegex); - for (const auto& [name, entity] : providerSegment.entities()) + const std::regex regex(query.entityNameRegex); + providerSegment.forEachEntity([this, &result, &query, ®ex](const EntityT & entity) { if (std::regex_search(entity.name(), regex)) { - result.addEntity(entityProcessorProcess(query.entityQueries, entity)); + childProcessor.process(result.addEntity(entity.name()), query.entityQueries, entity); } - } + return true; + }); } + protected: - virtual EntityT entityProcessorProcess(const armem::query::data::EntityQuerySeq& a, const EntityT& o) const = 0; + + ChildProcessorT childProcessor; + }; } diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory.cpp b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a695cf43d51dcbbc2329fa1c48fbe8e63565c24f --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory.cpp @@ -0,0 +1,7 @@ +#include "diskmemory.h" + + +namespace armarx::armem::server::query_proc::d_ltm +{ +} + diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory.h b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory.h new file mode 100644 index 0000000000000000000000000000000000000000..0f2ffe791d192b9bc2b5f2a2be311735808427a4 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory.h @@ -0,0 +1,32 @@ +#pragma once + +#include <RobotAPI/libraries/armem/core/diskmemory/Memory.h> +#include <RobotAPI/libraries/armem/server/query_proc/base.h> + + +namespace armarx::armem::server::query_proc::d_ltm +{ + static const base::QueryTarget queryTarget = query::data::QueryTarget::LTM; + + + class EntityQueryProcessor : + public base::EntityQueryProcessorBase<queryTarget, armem::d_ltm::Entity, armem::d_ltm::Entity> + { + }; + + class ProviderSegmentQueryProcessor : + public base::ProviderSegmentQueryProcessorBase <queryTarget, armem::d_ltm::ProviderSegment, armem::d_ltm::ProviderSegment, EntityQueryProcessor > + { + }; + + class CoreSegmentQueryProcessor : + public base::CoreSegmentQueryProcessorBase<queryTarget, armem::d_ltm::CoreSegment, armem::d_ltm::CoreSegment, ProviderSegmentQueryProcessor> + { + }; + + class MemoryQueryProcessor : + public base::MemoryQueryProcessorBase <queryTarget, armem::d_ltm::Memory, armem::d_ltm::Memory, CoreSegmentQueryProcessor > + { + }; + +} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/BaseQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/BaseQueryProcessor.cpp deleted file mode 100644 index 68821bcd95cdf2aaccf7126d4055495d39d0393d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/BaseQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "BaseQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/BaseQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/BaseQueryProcessor.h deleted file mode 100644 index 84f967795fd26d79d173a14e71498dbec7d56ee1..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/BaseQueryProcessor.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <RobotAPI/interface/armem/query.h> -#include <RobotAPI/libraries/armem/core/DataMode.h> - -#include "../base/BaseQueryProcessorBase.h" - - -namespace armarx::armem::d_ltm::query_proc -{ - /** - * @brief Base class for memory query processors. - */ - template <class DataT, class QueryT> - class BaseQueryProcessor : - virtual public base::query_proc::BaseQueryProcessorBase<DataT, QueryT> - { - using Base = base::query_proc::BaseQueryProcessorBase<DataT, QueryT>; - - public: - BaseQueryProcessor() - {} - - protected: - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/CoreSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/CoreSegmentQueryProcessor.cpp deleted file mode 100644 index afbe35ad15eea0342b0b0d4df0200aaf0d32aa2a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/CoreSegmentQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CoreSegmentQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/CoreSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/CoreSegmentQueryProcessor.h deleted file mode 100644 index 1c40f7fc64b0a2c59fdc3e54d968c6627480cbb0..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/CoreSegmentQueryProcessor.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/CoreSegmentQueryProcessorBase.h" - -#include "../../../core/diskmemory/CoreSegment.h" - -#include "ProviderSegmentQueryProcessor.h" - - -namespace armarx::armem::d_ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class CoreSegmentQueryProcessor : - virtual public BaseQueryProcessor<d_ltm::CoreSegment, armem::query::data::CoreSegmentQuery>, - virtual public base::query_proc::CoreSegmentQueryProcessorBase<d_ltm::CoreSegment> - { - using Base = BaseQueryProcessor<d_ltm::CoreSegment, armem::query::data::CoreSegmentQuery>; - - public: - CoreSegmentQueryProcessor() : - Base() - {} - - protected: - virtual ProviderSegmentT providerSegmentProcessorProcess(const armem::query::data::ProviderSegmentQuerySeq& q, const ProviderSegmentT& s) const override - { - return providerSegmentProcessor.process(q, s, {armem::query::data::QueryTarget::Disk}); - } - - private: - ProviderSegmentQueryProcessor providerSegmentProcessor; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/EntityQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/EntityQueryProcessor.cpp deleted file mode 100644 index c1c321b026b173c6552758fb9d8b9fdf722ea5a4..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/EntityQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "EntityQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/EntityQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/EntityQueryProcessor.h deleted file mode 100644 index 4d1b9e14e21804f1e44f1a2fd6456da37a113c03..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/EntityQueryProcessor.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/EntityQueryProcessorBase.h" - -#include "../../../core/diskmemory/Entity.h" - -#include "EntityQueryProcessor.h" - -namespace armarx::armem::d_ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class EntityQueryProcessor : - virtual public BaseQueryProcessor<d_ltm::Entity, armem::query::data::EntityQuery>, - virtual public base::query_proc::EntityQueryProcessorBase<d_ltm::Entity> - { - using Base = BaseQueryProcessor<d_ltm::Entity, armem::query::data::EntityQuery>; - - public: - EntityQueryProcessor() : - Base() - {} - - private: - void addResultSnapshot(d_ltm::Entity& result, d_ltm::Entity::ContainerT::const_iterator it) const override - { - addResultSnapshot(result, it->second); - } - - void addResultSnapshot(d_ltm::Entity& result, const d_ltm::EntitySnapshot& snapshot) const override - { - result.addSnapshot(snapshot.copy()); - } - - }; - -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/MemoryQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/MemoryQueryProcessor.cpp deleted file mode 100644 index 69b04de6c9e623286a5bda836dddfdc8b551b64a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/MemoryQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "MemoryQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/MemoryQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/MemoryQueryProcessor.h deleted file mode 100644 index 2abdcc1ccc7c25a317edc67e36835cb4a4df2f9b..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/MemoryQueryProcessor.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/MemoryQueryProcessorBase.h" - -#include "../../../core/diskmemory/Memory.h" - -#include "CoreSegmentQueryProcessor.h" - -namespace armarx::armem::d_ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class MemoryQueryProcessor : - virtual public BaseQueryProcessor<d_ltm::Memory, armem::query::data::MemoryQuery>, - virtual public base::query_proc::MemoryQueryProcessorBase<d_ltm::Memory> - { - using Base = BaseQueryProcessor<d_ltm::Memory, armem::query::data::MemoryQuery>; - - public: - MemoryQueryProcessor() : - Base() - {} - - protected: - virtual CoreSegmentT coreSegmentProcessorProcess(const armem::query::data::CoreSegmentQuerySeq& q, const CoreSegmentT& s) const override - { - return coreSegmentProcessor.process(q, s, {armem::query::data::QueryTarget::Disk}); - } - - private: - CoreSegmentQueryProcessor coreSegmentProcessor; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/ProviderSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/ProviderSegmentQueryProcessor.cpp deleted file mode 100644 index 9a2a4405001f0904b74fc6afcf96813eef0879cd..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/ProviderSegmentQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "ProviderSegmentQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/ProviderSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/ProviderSegmentQueryProcessor.h deleted file mode 100644 index 94c2e756875c1152f8018f70c5e0d691a5704582..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/diskmemory/ProviderSegmentQueryProcessor.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/ProviderSegmentQueryProcessorBase.h" - -#include "../../../core/diskmemory/ProviderSegment.h" - -#include "EntityQueryProcessor.h" - -namespace armarx::armem::d_ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class ProviderSegmentQueryProcessor : - virtual public BaseQueryProcessor<d_ltm::ProviderSegment, armem::query::data::ProviderSegmentQuery>, - virtual public base::query_proc::ProviderSegmentQueryProcessorBase<d_ltm::ProviderSegment> - { - using Base = BaseQueryProcessor<d_ltm::ProviderSegment, armem::query::data::ProviderSegmentQuery>; - - public: - ProviderSegmentQueryProcessor() : - Base() - {} - - protected: - virtual EntityT entityProcessorProcess(const armem::query::data::EntityQuerySeq& q, const EntityT& s) const override - { - return entityProcessor.process(q, s, {armem::query::data::QueryTarget::Disk}); - } - - private: - EntityQueryProcessor entityProcessor; - - }; - -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/BaseQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/BaseQueryProcessor.cpp deleted file mode 100644 index 68821bcd95cdf2aaccf7126d4055495d39d0393d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/BaseQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "BaseQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/BaseQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/BaseQueryProcessor.h deleted file mode 100644 index 458128e5305139db33a6c25d6ff19e3e92772fd5..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/BaseQueryProcessor.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <RobotAPI/interface/armem/query.h> -#include <RobotAPI/libraries/armem/core/DataMode.h> - -#include "../base/BaseQueryProcessorBase.h" - - -namespace armarx::armem::ltm::query_proc -{ - /** - * @brief Base class for memory query processors. - */ - template <class DataT, class QueryT> - class BaseQueryProcessor : - virtual public base::query_proc::BaseQueryProcessorBase<DataT, QueryT> - { - using Base = base::query_proc::BaseQueryProcessorBase<DataT, QueryT>; - - public: - BaseQueryProcessor() - {} - - protected: - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/CoreSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/CoreSegmentQueryProcessor.cpp deleted file mode 100644 index afbe35ad15eea0342b0b0d4df0200aaf0d32aa2a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/CoreSegmentQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CoreSegmentQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/CoreSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/CoreSegmentQueryProcessor.h deleted file mode 100644 index e333dd816aedabbb8dfa7209c687caf727d9ccf9..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/CoreSegmentQueryProcessor.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/CoreSegmentQueryProcessorBase.h" - -#include "../../../core/longtermmemory/CoreSegment.h" - -#include "ProviderSegmentQueryProcessor.h" - - -namespace armarx::armem::ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class CoreSegmentQueryProcessor : - virtual public BaseQueryProcessor<ltm::CoreSegment, armem::query::data::CoreSegmentQuery>, - virtual public base::query_proc::CoreSegmentQueryProcessorBase<ltm::CoreSegment> - { - using Base = BaseQueryProcessor<ltm::CoreSegment, armem::query::data::CoreSegmentQuery>; - - public: - CoreSegmentQueryProcessor() : - Base() - {} - - protected: - virtual ProviderSegmentT providerSegmentProcessorProcess(const armem::query::data::ProviderSegmentQuerySeq& q, const ProviderSegmentT& s) const override - { - return providerSegmentProcessor.process(q, s, {armem::query::data::QueryTarget::LTM}); - } - - private: - ProviderSegmentQueryProcessor providerSegmentProcessor; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/EntityQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/EntityQueryProcessor.cpp deleted file mode 100644 index c1c321b026b173c6552758fb9d8b9fdf722ea5a4..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/EntityQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "EntityQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/EntityQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/EntityQueryProcessor.h deleted file mode 100644 index 5ec4c5dde481e16f0af30589d57ff2a447d81221..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/EntityQueryProcessor.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/EntityQueryProcessorBase.h" - -#include "../../../core/longtermmemory/Entity.h" - -#include "EntityQueryProcessor.h" - -namespace armarx::armem::ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class EntityQueryProcessor : - virtual public BaseQueryProcessor<ltm::Entity, armem::query::data::EntityQuery>, - virtual public base::query_proc::EntityQueryProcessorBase<ltm::Entity> - { - using Base = BaseQueryProcessor<ltm::Entity, armem::query::data::EntityQuery>; - - public: - EntityQueryProcessor() : - Base() - {} - - private: - void addResultSnapshot(ltm::Entity& result, ltm::Entity::ContainerT::const_iterator it) const override - { - addResultSnapshot(result, it->second); - } - - void addResultSnapshot(ltm::Entity& result, const ltm::EntitySnapshot& snapshot) const override - { - result.addSnapshot(snapshot.copy()); - } - - }; - -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/MemoryQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/MemoryQueryProcessor.cpp deleted file mode 100644 index 69b04de6c9e623286a5bda836dddfdc8b551b64a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/MemoryQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "MemoryQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/MemoryQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/MemoryQueryProcessor.h deleted file mode 100644 index 569014d6579eeb6c99996e4be5b7cb68f65457b1..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/MemoryQueryProcessor.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/MemoryQueryProcessorBase.h" - -#include "../../../core/longtermmemory/Memory.h" - -#include "CoreSegmentQueryProcessor.h" - -namespace armarx::armem::ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class MemoryQueryProcessor : - virtual public BaseQueryProcessor<ltm::Memory, armem::query::data::MemoryQuery>, - virtual public base::query_proc::MemoryQueryProcessorBase<ltm::Memory> - { - using Base = BaseQueryProcessor<ltm::Memory, armem::query::data::MemoryQuery>; - - public: - MemoryQueryProcessor() : - Base() - {} - - protected: - virtual CoreSegmentT coreSegmentProcessorProcess(const armem::query::data::CoreSegmentQuerySeq& q, const CoreSegmentT& s) const override - { - return coreSegmentProcessor.process(q, s, {armem::query::data::QueryTarget::LTM}); - } - - private: - CoreSegmentQueryProcessor coreSegmentProcessor; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.cpp deleted file mode 100644 index 9a2a4405001f0904b74fc6afcf96813eef0879cd..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "ProviderSegmentQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.h deleted file mode 100644 index 5443acfd6594b98250711cf2acfd434a98414066..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/longtermmemory/ProviderSegmentQueryProcessor.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/ProviderSegmentQueryProcessorBase.h" - -#include "../../../core/longtermmemory/ProviderSegment.h" - -#include "EntityQueryProcessor.h" - -namespace armarx::armem::ltm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class ProviderSegmentQueryProcessor : - virtual public BaseQueryProcessor<ltm::ProviderSegment, armem::query::data::ProviderSegmentQuery>, - virtual public base::query_proc::ProviderSegmentQueryProcessorBase<ltm::ProviderSegment> - { - using Base = BaseQueryProcessor<ltm::ProviderSegment, armem::query::data::ProviderSegmentQuery>; - - public: - ProviderSegmentQueryProcessor() : - Base() - {} - - protected: - virtual EntityT entityProcessorProcess(const armem::query::data::EntityQuerySeq& q, const EntityT& s) const override - { - return entityProcessor.process(q, s, {armem::query::data::QueryTarget::LTM}); - } - - private: - EntityQueryProcessor entityProcessor; - - }; - -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/ltm.cpp b/source/RobotAPI/libraries/armem/server/query_proc/ltm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..238cc4b8d1601bf1ffae131caabbf8ca8435899a --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/query_proc/ltm.cpp @@ -0,0 +1,7 @@ +#include "ltm.h" + + +namespace armarx::armem::server::query_proc::ltm +{ +} + diff --git a/source/RobotAPI/libraries/armem/server/query_proc/ltm.h b/source/RobotAPI/libraries/armem/server/query_proc/ltm.h new file mode 100644 index 0000000000000000000000000000000000000000..ae0dc778c821ae138c98b8554a22237bf26e5989 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/query_proc/ltm.h @@ -0,0 +1,32 @@ +#pragma once + +#include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h> +#include <RobotAPI/libraries/armem/server/query_proc/base.h> + + +namespace armarx::armem::server::query_proc::ltm +{ + static const base::QueryTarget queryTarget = query::data::QueryTarget::LTM; + + + class EntityQueryProcessor : + public base::EntityQueryProcessorBase<queryTarget, armem::ltm::Entity, armem::ltm::Entity> + { + }; + + class ProviderSegmentQueryProcessor : + public base::ProviderSegmentQueryProcessorBase <queryTarget, armem::ltm::ProviderSegment, armem::ltm::ProviderSegment, EntityQueryProcessor > + { + }; + + class CoreSegmentQueryProcessor : + public base::CoreSegmentQueryProcessorBase <queryTarget, armem::ltm::CoreSegment, armem::ltm::CoreSegment, ProviderSegmentQueryProcessor> + { + }; + + class MemoryQueryProcessor : + public base::MemoryQueryProcessorBase <queryTarget, armem::ltm::Memory, armem::ltm::Memory, CoreSegmentQueryProcessor > + { + }; + +} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/wm.cpp b/source/RobotAPI/libraries/armem/server/query_proc/wm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e968623d63aa57213507879608c81823d31c7d6 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/query_proc/wm.cpp @@ -0,0 +1,70 @@ +#include "wm.h" + + + +namespace armarx::armem::server::query_proc::wm::detail +{ + + HasDataMode::HasDataMode(armem::DataMode dataMode) : dataMode(dataMode) + { + } + +} + + +namespace armarx::armem::server::query_proc::wm +{ + + ProviderSegmentQueryProcessor::ProviderSegmentQueryProcessor(DataMode dataMode) : + ProviderSegmentQueryProcessorBase(dataMode), HasDataMode(dataMode) + { + } + + + CoreSegmentQueryProcessor::CoreSegmentQueryProcessor(DataMode dataMode) : + CoreSegmentQueryProcessorBase(dataMode), HasDataMode(dataMode) + { + } + + + MemoryQueryProcessor::MemoryQueryProcessor(DataMode dataMode) : + MemoryQueryProcessorBase(dataMode), HasDataMode(dataMode) + { + } + +} + + +namespace armarx::armem::server::query_proc::wm_server +{ + ProviderSegmentQueryProcessor::ProviderSegmentQueryProcessor(DataMode dataMode) : + ProviderSegmentQueryProcessorBase(dataMode), HasDataMode(dataMode) + { + } + + + CoreSegmentQueryProcessor::CoreSegmentQueryProcessor(DataMode dataMode) : + CoreSegmentQueryProcessorBase(dataMode), + HasDataMode(dataMode) + { + } + + + void CoreSegmentQueryProcessor::process( + armem::wm::CoreSegment& result, + const armem::query::data::CoreSegmentQuery& query, + const CoreSegment& coreSegment) const + { + std::scoped_lock lock(coreSegment.mutex()); + CoreSegmentQueryProcessorBase::process(result, query, coreSegment); + } + + + MemoryQueryProcessor::MemoryQueryProcessor(DataMode dataMode) : + MemoryQueryProcessorBase(dataMode), + HasDataMode(dataMode) + { + } + + +} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/wm.h b/source/RobotAPI/libraries/armem/server/query_proc/wm.h new file mode 100644 index 0000000000000000000000000000000000000000..aa52b4ab22fe1c6ef194ef37d4e38f5c7720d6c5 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/query_proc/wm.h @@ -0,0 +1,164 @@ +#pragma once + +#include <RobotAPI/libraries/armem/core/DataMode.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/query_proc/base.h> + + +namespace armarx::armem::server::query_proc::wm +{ + static const base::QueryTarget queryTarget = query::data::QueryTarget::WM; +} +namespace armarx::armem::server::query_proc::wm::detail +{ + + class HasDataMode + { + public: + + HasDataMode(armem::DataMode dataMode); + + + protected: + + armem::DataMode dataMode; + + }; + + + + template <class SourceEntityT> + class EntityQueryProcessor : + public base::EntityQueryProcessorBase<queryTarget, SourceEntityT, armem::wm::Entity>, + public HasDataMode + { + public: + + EntityQueryProcessor(DataMode dataMode = DataMode::WithData) : + HasDataMode(dataMode) + {} + + + protected: + + void addResultSnapshot(armem::wm::Entity& result, const typename SourceEntityT::EntitySnapshotT& snapshot) const + { + bool withData = (dataMode == DataMode::WithData); + if (withData) + { + result.addSnapshot(server::wm::EntitySnapshot{ snapshot }); + } + else + { + server::wm::EntitySnapshot copy = snapshot; + copy.forEachInstance([](server::wm::EntityInstance & i) + { + i.data() = nullptr; + return true; + }); + result.addSnapshot(std::move(copy)); + } + } + + }; +} + + +namespace armarx::armem::server::query_proc::wm +{ + + using EntityQueryProcessor = detail::EntityQueryProcessor<armem::wm::Entity>; + + + class ProviderSegmentQueryProcessor : + public base::ProviderSegmentQueryProcessorBase<queryTarget, armem::wm::ProviderSegment, armem::wm::ProviderSegment, EntityQueryProcessor >, + public detail::HasDataMode + { + public: + + ProviderSegmentQueryProcessor(DataMode dataMode = DataMode::WithData); + + }; + + + class CoreSegmentQueryProcessor : + public base::CoreSegmentQueryProcessorBase <queryTarget, armem::wm::CoreSegment, armem::wm::CoreSegment, ProviderSegmentQueryProcessor >, + public detail::HasDataMode + { + using Base = base::CoreSegmentQueryProcessorBase<queryTarget, armem::wm::CoreSegment, armem::wm::CoreSegment, ProviderSegmentQueryProcessor>; + using CoreSegment = armem::wm::CoreSegment; + using ProviderSegment = armem::wm::ProviderSegment; + + public: + + CoreSegmentQueryProcessor(DataMode dataMode = DataMode::WithData); + + }; + + + class MemoryQueryProcessor : + public base::MemoryQueryProcessorBase<queryTarget, armem::wm::Memory, armem::wm::Memory, CoreSegmentQueryProcessor>, + public detail::HasDataMode + { + public: + + MemoryQueryProcessor(DataMode dataMode = DataMode::WithData); + + }; + +} + + +namespace armarx::armem::server::query_proc::wm_server +{ + + using EntityQueryProcessor = wm::detail::EntityQueryProcessor<server::wm::Entity>; + + + class ProviderSegmentQueryProcessor : + public base::ProviderSegmentQueryProcessorBase<wm::queryTarget, server::wm::ProviderSegment, armem::wm::ProviderSegment, EntityQueryProcessor >, + public wm::detail::HasDataMode + { + public: + + ProviderSegmentQueryProcessor(DataMode dataMode = DataMode::WithData); + + }; + + + class CoreSegmentQueryProcessor : + public base::CoreSegmentQueryProcessorBase <wm::queryTarget, server::wm::CoreSegment, armem::wm::CoreSegment, ProviderSegmentQueryProcessor >, + public wm::detail::HasDataMode + { + using Base = base::CoreSegmentQueryProcessorBase<wm::queryTarget, server::wm::CoreSegment, armem::wm::CoreSegment, ProviderSegmentQueryProcessor>; + using CoreSegment = server::wm::CoreSegment; + using ProviderSegment = server::wm::ProviderSegment; + + public: + + CoreSegmentQueryProcessor(DataMode dataMode = DataMode::WithData); + + + using Base::process; + + /// Locks the core segment, then delegates back to `CoreSegmentQueryProcessorBase`. + void process( + armem::wm::CoreSegment& result, + const armem::query::data::CoreSegmentQuery& query, + const CoreSegment& coreSegment) const override; + + }; + + + class MemoryQueryProcessor : + public base::MemoryQueryProcessorBase<wm::queryTarget, server::wm::Memory, armem::wm::Memory, CoreSegmentQueryProcessor>, + public wm::detail::HasDataMode + { + public: + + MemoryQueryProcessor(DataMode dataMode = DataMode::WithData); + + }; + +} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/BaseQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/BaseQueryProcessor.cpp deleted file mode 100644 index 68821bcd95cdf2aaccf7126d4055495d39d0393d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/BaseQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "BaseQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/BaseQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/BaseQueryProcessor.h deleted file mode 100644 index 99811dcc72d168dfecb0c5864f0760c4d5634a6e..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/BaseQueryProcessor.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> - -#include <RobotAPI/interface/armem/query.h> -#include <RobotAPI/libraries/armem/core/DataMode.h> - -#include "../base/BaseQueryProcessorBase.h" - - -namespace armarx::armem::wm::query_proc -{ - /** - * @brief Base class for memory query processors. - */ - template <class DataT, class QueryT> - class BaseQueryProcessor : - virtual public base::query_proc::BaseQueryProcessorBase<DataT, QueryT> - { - using Base = base::query_proc::BaseQueryProcessorBase<DataT, QueryT>; - - public: - BaseQueryProcessor(DataMode dataMode = DataMode::WithData) : - dataMode(dataMode) - {} - - protected: - DataMode dataMode; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/CoreSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/CoreSegmentQueryProcessor.cpp deleted file mode 100644 index afbe35ad15eea0342b0b0d4df0200aaf0d32aa2a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/CoreSegmentQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CoreSegmentQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/CoreSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/CoreSegmentQueryProcessor.h deleted file mode 100644 index 390ab66f656ece6010457f12f09917d9fca413f6..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/CoreSegmentQueryProcessor.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/CoreSegmentQueryProcessorBase.h" - -#include "ProviderSegmentQueryProcessor.h" - - -namespace armarx::armem::wm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class CoreSegmentQueryProcessor : - virtual public BaseQueryProcessor<wm::CoreSegment, armem::query::data::CoreSegmentQuery>, - virtual public base::query_proc::CoreSegmentQueryProcessorBase<wm::CoreSegment> - { - using Base = BaseQueryProcessor<wm::CoreSegment, armem::query::data::CoreSegmentQuery>; - - public: - CoreSegmentQueryProcessor(DataMode dataMode = DataMode::WithData) : - Base(dataMode), providerSegmentProcessor(dataMode) - {} - - using Base::process; - data::CoreSegment processToIce(const armem::query::data::CoreSegmentQuery& query, const wm::CoreSegment& coreSegment) const - { - return toIce<data::CoreSegment>(process(query, coreSegment)); - } - - protected: - virtual ProviderSegmentT providerSegmentProcessorProcess(const armem::query::data::ProviderSegmentQuerySeq& q, const ProviderSegmentT& s) const override - { - return providerSegmentProcessor.process(q, s, {armem::query::data::QueryTarget::WM}); - } - - private: - ProviderSegmentQueryProcessor providerSegmentProcessor; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/EntityQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/EntityQueryProcessor.cpp deleted file mode 100644 index c1c321b026b173c6552758fb9d8b9fdf722ea5a4..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/EntityQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "EntityQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/EntityQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/EntityQueryProcessor.h deleted file mode 100644 index 94dc905e489be501257be508cff03c7efee8f8b8..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/EntityQueryProcessor.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/EntityQueryProcessorBase.h" - -#include "EntityQueryProcessor.h" - -namespace armarx::armem::wm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class EntityQueryProcessor : - virtual public BaseQueryProcessor<wm::Entity, armem::query::data::EntityQuery>, - virtual public base::query_proc::EntityQueryProcessorBase<wm::Entity> - { - using Base = BaseQueryProcessor<wm::Entity, armem::query::data::EntityQuery>; - - public: - EntityQueryProcessor(DataMode dataMode = DataMode::WithData) : - Base(dataMode) - {} - - data::Entity processToIce(const armem::query::data::EntityQuery& query, const wm::Entity& entity) const - { - return toIce<data::Entity>(process(query, entity)); - } - - private: - void addResultSnapshot(wm::Entity& result, wm::Entity::ContainerT::const_iterator it) const override - { - addResultSnapshot(result, it->second); - } - - void addResultSnapshot(wm::Entity& result, const wm::EntitySnapshot& snapshot) const override - { - bool withData = (dataMode == DataMode::WithData); - if (withData) - { - result.addSnapshot(snapshot.copy()); - } - else - { - result.addSnapshot(snapshot.copyWithoutData()); - } - } - - }; - -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/MemoryQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/MemoryQueryProcessor.cpp deleted file mode 100644 index 69b04de6c9e623286a5bda836dddfdc8b551b64a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/MemoryQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "MemoryQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/MemoryQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/MemoryQueryProcessor.h deleted file mode 100644 index 8284df202bbcf602e2433639fe85388ca13d75ff..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/MemoryQueryProcessor.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/MemoryQueryProcessorBase.h" - -#include "CoreSegmentQueryProcessor.h" - -namespace armarx::armem::wm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class MemoryQueryProcessor : - virtual public BaseQueryProcessor<wm::Memory, armem::query::data::MemoryQuery>, - virtual public base::query_proc::MemoryQueryProcessorBase<wm::Memory> - { - using Base = BaseQueryProcessor<wm::Memory, armem::query::data::MemoryQuery>; - - public: - MemoryQueryProcessor(DataMode dataMode = DataMode::WithData) : - Base(dataMode), coreSegmentProcessor(dataMode) - {} - - protected: - virtual CoreSegmentT coreSegmentProcessorProcess(const armem::query::data::CoreSegmentQuerySeq& q, const CoreSegmentT& s) const override - { - return coreSegmentProcessor.process(q, s, {armem::query::data::QueryTarget::WM}); - } - - - private: - CoreSegmentQueryProcessor coreSegmentProcessor; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/ProviderSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/ProviderSegmentQueryProcessor.cpp deleted file mode 100644 index 9a2a4405001f0904b74fc6afcf96813eef0879cd..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/ProviderSegmentQueryProcessor.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "ProviderSegmentQueryProcessor.h" diff --git a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/ProviderSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/ProviderSegmentQueryProcessor.h deleted file mode 100644 index 468138d9e2bbd526db3632019beca6a5a29f8269..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/server/query_proc/workingmemory/ProviderSegmentQueryProcessor.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "BaseQueryProcessor.h" -#include "../base/ProviderSegmentQueryProcessorBase.h" - -#include "EntityQueryProcessor.h" - -namespace armarx::armem::wm::query_proc -{ - /** - * @brief Handles memory queries. - */ - class ProviderSegmentQueryProcessor : - virtual public BaseQueryProcessor<wm::ProviderSegment, armem::query::data::ProviderSegmentQuery>, - virtual public base::query_proc::ProviderSegmentQueryProcessorBase<wm::ProviderSegment> - { - using Base = BaseQueryProcessor<wm::ProviderSegment, armem::query::data::ProviderSegmentQuery>; - - public: - ProviderSegmentQueryProcessor(DataMode dataMode = DataMode::WithData) : - Base(dataMode), entityProcessor(dataMode) - {} - - using Base::process; - data::ProviderSegment processToIce(const armem::query::data::ProviderSegmentQuery& query, const wm::ProviderSegment& providerSegment) const - { - return toIce<data::ProviderSegment>(process(query, providerSegment)); - } - - protected: - virtual EntityT entityProcessorProcess(const armem::query::data::EntityQuerySeq& q, const EntityT& s) const override - { - return entityProcessor.process(q, s, {armem::query::data::QueryTarget::WM}); - } - - private: - EntityQueryProcessor entityProcessor; - }; -} diff --git a/source/RobotAPI/libraries/armem/server/segment/Segment.cpp b/source/RobotAPI/libraries/armem/server/segment/Segment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..050e77d392da77bc5c4e4edfcf11f76ee6e1e051 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/segment/Segment.cpp @@ -0,0 +1,109 @@ +#include "Segment.h" + +#include <ArmarXCore/core/application/properties/PluginAll.h> +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> + +#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> + + +namespace armarx::armem::server::segment +{ + + wm::CoreSegmentBase::CoreSegmentBase( + armem::server::MemoryToIceAdapter& iceMemory, + const std::string& defaultCoreSegmentName, + aron::typenavigator::ObjectNavigatorPtr coreSegmentAronType, + int defaultMaxHistorySize) : + Base(iceMemory), + p({defaultCoreSegmentName, defaultMaxHistorySize}), + coreSegmentAronType(coreSegmentAronType) + { + Logging::setTag("armarx::armem::wm::Segment"); + } + + + wm::CoreSegmentBase::~CoreSegmentBase() + { + } + + + void wm::CoreSegmentBase::defineProperties( + armarx::PropertyDefinitionsPtr defs, + const std::string& prefix) + { + ARMARX_CHECK_NOT_NULL(defs); + + defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the '" + p.coreSegmentName + "' core segment."); + defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of '" + p.coreSegmentName + "' history (-1 for infinite)."); + } + + + void wm::CoreSegmentBase::onInit() + { + ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); + + segment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName, coreSegmentAronType); + segment->setMaxHistorySize(p.maxHistorySize); + } + + + std::mutex& wm::CoreSegmentBase::mutex() const + { + ARMARX_CHECK_NOT_NULL(segment); + return segment->mutex(); + } + + + + wm::ProviderSegmentBase::ProviderSegmentBase( + armem::server::MemoryToIceAdapter& iceMemory, + const std::string& defaultProviderSegmentName, + aron::typenavigator::ObjectNavigatorPtr providerSegmentAronType, + const std::string& defaultCoreSegmentName, + aron::typenavigator::ObjectNavigatorPtr coreSegmentAronType, + int defaultMaxHistorySize) : + + Base(iceMemory), + p({defaultCoreSegmentName, defaultProviderSegmentName, defaultMaxHistorySize}), + coreSegmentAronType(coreSegmentAronType), + providerSegmentAronType(providerSegmentAronType) + { + Logging::setTag("armarx::armem::wm::Segment"); + } + + + wm::ProviderSegmentBase::~ProviderSegmentBase() + { + } + + + void wm::ProviderSegmentBase::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) + { + ARMARX_CHECK_NOT_NULL(defs); + + defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the '" + p.coreSegmentName + "' core segment."); + defs->optional(p.providerSegmentName, prefix + "ProviderSegmentName", "Name of the '" + p.providerSegmentName + "' provider segment."); + defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of '" + p.providerSegmentName + "' history (-1 for infinite)."); + } + + + void wm::ProviderSegmentBase::onInit() + { + ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); + + if (!iceMemory.workingMemory->hasCoreSegment(p.coreSegmentName)) + { + coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName, coreSegmentAronType); + coreSegment->setMaxHistorySize(p.maxHistorySize); + } + else + { + coreSegment = &iceMemory.workingMemory->getCoreSegment(p.coreSegmentName); + } + + segment = &coreSegment->addProviderSegment(p.providerSegmentName, providerSegmentAronType); + segment->setMaxHistorySize(p.maxHistorySize); + } + +} diff --git a/source/RobotAPI/libraries/armem/server/segment/Segment.h b/source/RobotAPI/libraries/armem/server/segment/Segment.h new file mode 100644 index 0000000000000000000000000000000000000000..7808e99d31f4df3543bfbd5b882a408dda143ed5 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/segment/Segment.h @@ -0,0 +1,199 @@ +#pragma once + +// STD/STL +#include <mutex> +#include <string> + +// ArmarX +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/application/properties/forward_declarations.h> + +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> + + +namespace armarx::armem +{ + namespace server + { + class MemoryToIceAdapter; + + namespace wm + { + class CoreSegment; + class ProviderSegment; + } + } +} +namespace armarx::armem::server::segment +{ + namespace detail + { + /** + * @brief A base class for memory servers to manage their segments. + * A segment can inherit this base class and add segment specific code. + * TODO (fabian.peller): add concept to only accept coresegments, providersegments or entitysegments + */ + template <class SegmentType> + class SegmentBase : public armarx::Logging + { + public: + + SegmentBase() = delete; + SegmentBase(MemoryToIceAdapter& iceMemory) : + iceMemory(iceMemory) + { + Logging::setTag("armarx::armem::Segment"); + } + + virtual ~SegmentBase() = default; + + virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") = 0; + virtual void onInit() = 0; + // virtual void onConnect() = 0; + + + protected: + + // Memory connection + MemoryToIceAdapter& iceMemory; + + SegmentType* segment; + + }; + } + + + namespace wm + { + /** + * @brief A base class for core segments + */ + class CoreSegmentBase : public detail::SegmentBase<server::wm::CoreSegment> + { + using Base = detail::SegmentBase<server::wm::CoreSegment>; + + public: + + CoreSegmentBase( + MemoryToIceAdapter& iceMemory, + const std::string& defaultCoreSegmentName = "", + aron::typenavigator::ObjectNavigatorPtr coreSegmentAronType = nullptr, + int defaultMaxHistorySize = -1); + + virtual ~CoreSegmentBase() override; + + + virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") override; + virtual void onInit() override; + // virtual void onConnect() override; + + + std::mutex& mutex() const; + + + protected: + + struct Properties + { + std::string coreSegmentName; + int maxHistorySize; + }; + Properties p; + + aron::typenavigator::ObjectNavigatorPtr coreSegmentAronType; + + }; + + + /** + * @brief A base class for provider segments + */ + class ProviderSegmentBase : public detail::SegmentBase<server::wm::ProviderSegment> + { + using Base = detail::SegmentBase<server::wm::ProviderSegment>; + + public: + + ProviderSegmentBase( + MemoryToIceAdapter& iceMemory, + const std::string& defaultProviderSegmentName = "", + aron::typenavigator::ObjectNavigatorPtr providerSegmentAronType = nullptr, + const std::string& defaultCoreSegmentName = "", + aron::typenavigator::ObjectNavigatorPtr coreSegmentAronType = nullptr, + int defaultMaxHistorySize = -1); + + virtual ~ProviderSegmentBase() override; + + + virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") override; + virtual void onInit() override; + // virtual void onConnect() override; + + + protected: + + struct Properties + { + std::string coreSegmentName; + std::string providerSegmentName; + int maxHistorySize; + }; + Properties p; + + aron::typenavigator::ObjectNavigatorPtr coreSegmentAronType; + aron::typenavigator::ObjectNavigatorPtr providerSegmentAronType; + + server::wm::CoreSegment* coreSegment; + }; + + + + /** + * @brief A base class for provider segments with an aron business object + */ + template <class BusinessClassObject> + class AronTypedCoreSegmentBase : public CoreSegmentBase + { + using Base = CoreSegmentBase; + + public: + + AronTypedCoreSegmentBase( + MemoryToIceAdapter& iceMemory, + const std::string& defaultCoreSegmentName = "", + int defaultMaxHistorySize = -1) : + Base(iceMemory, defaultCoreSegmentName, BusinessClassObject::toAronType(), + defaultMaxHistorySize) + { + } + + virtual ~AronTypedCoreSegmentBase() = default; + }; + + + + /** + * @brief A base class for provider segments with an aron business object + */ + template <class BusinessClassObject> + class AronTypedProviderSegmentBase : public ProviderSegmentBase + { + using Base = ProviderSegmentBase; + + public: + + AronTypedProviderSegmentBase( + MemoryToIceAdapter& iceMemory, + const std::string& defaultProviderSegmentName = "", + const std::string& defaultCoreSegmentName = "", + int defaultMaxHistorySize = -1) : + Base(iceMemory, defaultProviderSegmentName, BusinessClassObject::toAronType(), + defaultCoreSegmentName, nullptr, defaultMaxHistorySize) + { + } + + virtual ~AronTypedProviderSegmentBase() = default; + + }; + } +} diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedSegment.cpp b/source/RobotAPI/libraries/armem/server/segment/SpecializedSegment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8184e27c985877a19aaa873db07883685140b17b --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedSegment.cpp @@ -0,0 +1,79 @@ +#include "SpecializedSegment.h" + +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/application/properties/PluginAll.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> + + +namespace armarx::armem::server::segment +{ + + SpecializedSegment::SpecializedSegment( + server::MemoryToIceAdapter& iceMemory, + aron::typenavigator::ObjectNavigatorPtr aronType, + const std::string& defaultCoreSegmentName, + int64_t defaultMaxHistorySize + ) : + iceMemory(iceMemory), aronType(aronType) + { + setDefaultCoreSegmentName(defaultCoreSegmentName); + setDefaultMaxHistorySize(defaultMaxHistorySize); + } + + + SpecializedSegment::~SpecializedSegment() + { + } + + + void SpecializedSegment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) + { + defs->optional(properties.coreSegmentName, + prefix + "seg.CoreSegmentName", + "Name of the " + properties.coreSegmentName + " core segment."); + + defs->optional(properties.maxHistorySize, + prefix + "seg.MaxHistorySize", + "Maximal size of the " + properties.coreSegmentName + " entity histories (-1 for infinite)."); + } + + + void SpecializedSegment::init() + { + ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); + Logging::setTag(properties.coreSegmentName + " Core Segment"); + + ARMARX_INFO << "Adding core segment '" << properties.coreSegmentName << "'"; + coreSegment = &iceMemory.workingMemory->addCoreSegment(properties.coreSegmentName, aronType); + coreSegment->setMaxHistorySize(properties.maxHistorySize); + } + + + std::mutex& SpecializedSegment::mutex() const + { + ARMARX_CHECK_NOT_NULL(coreSegment); + return coreSegment->mutex(); + } + + + void SpecializedSegment::setDefaultCoreSegmentName(const std::string& coreSegmentName) + { + this->properties.coreSegmentName = coreSegmentName; + } + + + void SpecializedSegment::setDefaultMaxHistorySize(int64_t maxHistorySize) + { + this->properties.maxHistorySize = maxHistorySize; + } + + + void SpecializedSegment::setAronType(aron::typenavigator::ObjectNavigatorPtr aronType) + { + this->aronType = aronType; + } + +} diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedSegment.h b/source/RobotAPI/libraries/armem/server/segment/SpecializedSegment.h new file mode 100644 index 0000000000000000000000000000000000000000..460fbf3f0f0cd4ea6c2835d499071f2e43bf2a7d --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedSegment.h @@ -0,0 +1,75 @@ +#pragma once + +#include <mutex> +#include <string> + +#include <ArmarXCore/core/application/properties/forward_declarations.h> +#include <ArmarXCore/core/logging/Logging.h> + +#include <RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h> + + +namespace armarx::armem +{ + namespace server + { + class MemoryToIceAdapter; + + namespace wm + { + class CoreSegment; + } + } +} + +namespace armarx::armem::server::segment +{ + + /** + * @brief Specialized management of a core segment. + */ + class SpecializedSegment : + public armarx::Logging + { + public: + + SpecializedSegment( + server::MemoryToIceAdapter& iceMemory, + aron::typenavigator::ObjectNavigatorPtr aronType = nullptr, + const std::string& defaultCoreSegmentName = "", + int64_t defaultMaxHistorySize = -1); + + virtual ~SpecializedSegment(); + + + virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); + virtual void init(); + // void connect(); + + std::mutex& mutex() const; + + + protected: + + void setDefaultCoreSegmentName(const std::string& coreSegmentName); + void setDefaultMaxHistorySize(int64_t maxHistorySize); + void setAronType(aron::typenavigator::ObjectNavigatorPtr aronType); + + + protected: + + server::MemoryToIceAdapter& iceMemory; + server::wm::CoreSegment* coreSegment = nullptr; + aron::typenavigator::ObjectNavigatorPtr aronType; + + struct Properties + { + std::string coreSegmentName = ""; + int64_t maxHistorySize = -1; + }; + Properties properties; + + + }; + +} diff --git a/source/RobotAPI/libraries/armem/core/base/detail/MaxHistorySize.cpp b/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.cpp similarity index 72% rename from source/RobotAPI/libraries/armem/core/base/detail/MaxHistorySize.cpp rename to source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.cpp index 2c3b0554c65523826db0a7709599ed8e5140e0a1..d90756691871b6ad444a67fa76a733d0086b5b29 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/MaxHistorySize.cpp +++ b/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.cpp @@ -1,12 +1,8 @@ #include "MaxHistorySize.h" -namespace armarx::armem::base::detail +namespace armarx::armem::server::detail { - MaxHistorySize::~MaxHistorySize() - { - } - void MaxHistorySize::setMaxHistorySize(long maxSize) { this->_maxHistorySize = maxSize; diff --git a/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.h b/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.h new file mode 100644 index 0000000000000000000000000000000000000000..e2f2d498c2945f4456c281abafe0f1ad66074e72 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.h @@ -0,0 +1,58 @@ +#pragma once + + +namespace armarx::armem::server::detail +{ + // TODO: Replace by ConstrainedHistorySize (not only max entries, e.g. delete oldest / delete least accessed / ...) + + class MaxHistorySize + { + public: + + /** + * @brief Set the maximum number of snapshots to be contained in an entity. + * Affected entities are to be update right away. + */ + void setMaxHistorySize(long maxSize); + + long getMaxHistorySize() const; + + + protected: + + /** + * @brief Maximum size of entity histories. + * + * If negative, the size of `history` is not limited. + * + * @see Entity::maxHstorySize + */ + long _maxHistorySize = -1; + + }; + + + + template <class DerivedT> + class MaxHistorySizeParent : public MaxHistorySize + { + public: + + /** + * @brief Sets the maximum history size of entities in this container. + * This affects all current entities as well as new ones. + * + * @see MaxHistorySize::setMaxHistorySize() + */ + void setMaxHistorySize(long maxSize) + { + MaxHistorySize::setMaxHistorySize(maxSize); + static_cast<DerivedT&>(*this).forEachChild([maxSize](auto & child) + { + child.setMaxHistorySize(maxSize); + return true; + }); + } + + }; +} diff --git a/source/RobotAPI/libraries/armem/server/wm/ice_conversions.cpp b/source/RobotAPI/libraries/armem/server/wm/ice_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ba3352d6e8bb443693ebfa5752a46cad9c24267 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/wm/ice_conversions.cpp @@ -0,0 +1,64 @@ +#include "ice_conversions.h" + +#include <RobotAPI/libraries/armem/core/base/ice_conversions.h> + + +namespace armarx::armem::server +{ + + void wm::toIce(data::EntityInstance& ice, const EntityInstance& data) + { + base::toIce(ice, data); + } + void wm::fromIce(const data::EntityInstance& ice, EntityInstance& data) + { + base::fromIce(ice, data); + } + + + void wm::toIce(data::EntitySnapshot& ice, const EntitySnapshot& snapshot) + { + base::toIce(ice, snapshot); + } + void wm::fromIce(const data::EntitySnapshot& ice, EntitySnapshot& snapshot) + { + base::fromIce(ice, snapshot); + } + + void wm::toIce(data::Entity& ice, const Entity& entity) + { + base::toIce(ice, entity); + } + void wm::fromIce(const data::Entity& ice, Entity& entity) + { + base::fromIce(ice, entity); + } + + void wm::toIce(data::ProviderSegment& ice, const ProviderSegment& providerSegment) + { + base::toIce(ice, providerSegment); + } + void wm::fromIce(const data::ProviderSegment& ice, ProviderSegment& providerSegment) + { + base::fromIce(ice, providerSegment); + } + + void wm::toIce(data::CoreSegment& ice, const CoreSegment& coreSegment) + { + base::toIce(ice, coreSegment); + } + void wm::fromIce(const data::CoreSegment& ice, CoreSegment& coreSegment) + { + base::fromIce(ice, coreSegment); + } + + void wm::toIce(data::Memory& ice, const Memory& memory) + { + base::toIce(ice, memory); + } + void wm::fromIce(const data::Memory& ice, Memory& memory) + { + base::fromIce(ice, memory); + } + +} diff --git a/source/RobotAPI/libraries/armem/server/wm/ice_conversions.h b/source/RobotAPI/libraries/armem/server/wm/ice_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..c25b16775bc577c61d0c804cf4525b23ecd5e5d1 --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/wm/ice_conversions.h @@ -0,0 +1,30 @@ +#pragma once + +#include <RobotAPI/interface/armem/memory.h> + +#include "memory_definitions.h" + + +namespace armarx::armem::server::wm +{ + + void toIce(data::EntityInstance& ice, const EntityInstance& data); + void fromIce(const data::EntityInstance& ice, EntityInstance& data); + + + void toIce(data::EntitySnapshot& ice, const EntitySnapshot& snapshot); + void fromIce(const data::EntitySnapshot& ice, EntitySnapshot& snapshot); + + void toIce(data::Entity& ice, const Entity& entity); + void fromIce(const data::Entity& ice, Entity& entity); + + + void toIce(data::ProviderSegment& ice, const ProviderSegment& providerSegment); + void fromIce(const data::ProviderSegment& ice, ProviderSegment& providerSegment); + + void toIce(data::CoreSegment& ice, const CoreSegment& coreSegment); + void fromIce(const data::CoreSegment& ice, CoreSegment& coreSegment); + + void toIce(data::Memory& ice, const Memory& memory); + void fromIce(const data::Memory& ice, Memory& memory); +} diff --git a/source/RobotAPI/libraries/armem/server/wm/memory_definitions.cpp b/source/RobotAPI/libraries/armem/server/wm/memory_definitions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58be8027db2561979d3510b7d481715678b61eae --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/wm/memory_definitions.cpp @@ -0,0 +1,202 @@ +#include "memory_definitions.h" + +#include "error.h" + +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <map> +#include <vector> + + +namespace armarx::armem::server::wm +{ + + void Entity::setMaxHistorySize(long maxSize) + { + MaxHistorySize::setMaxHistorySize(maxSize); + truncate(); + } + + + auto Entity::update(const EntityUpdate& update) -> UpdateResult + { + UpdateResult result = EntityBase::update(update); + result.removedSnapshots = this->truncate(); + return result; + } + + + std::vector<EntitySnapshot> Entity::truncate() + { + std::vector<EntitySnapshot> removedElements; + if (_maxHistorySize >= 0) + { + while (this->_container.size() > size_t(_maxHistorySize)) + { + removedElements.push_back(std::move(this->_container.begin()->second)); + this->_container.erase(this->_container.begin()); + } + ARMARX_CHECK_LESS_EQUAL(this->_container.size(), _maxHistorySize); + } + return removedElements; + } + + + + Entity& ProviderSegment::addEntity(Entity&& entity) + { + Entity& added = ProviderSegmentBase::addEntity(std::move(entity)); + added.setMaxHistorySize(this->getMaxHistorySize()); + return added; + } + + + + std::mutex& CoreSegment::mutex() const + { + return _mutex; + } + + + std::optional<wm::EntitySnapshot> CoreSegment::getLatestEntitySnapshot(const MemoryID& entityID) const + { + const wm::Entity& entity = this->getEntity(entityID); + if (entity.empty()) + { + return std::nullopt; + } + else + { + return entity.getLatestSnapshot(); + } + } + + + std::optional<wm::EntityInstance> CoreSegment::getLatestEntityInstance( + const MemoryID& entityID, int instanceIndex) const + { + auto snapshot = getLatestEntitySnapshot(entityID); + if (snapshot.has_value() + and instanceIndex >= 0 + and static_cast<size_t>(instanceIndex) < snapshot->size()) + { + return snapshot->getInstance(instanceIndex); + } + else + { + return std::nullopt; + } + } + + + armarx::aron::datanavigator::DictNavigatorPtr + CoreSegment::getLatestEntityInstanceData(const MemoryID& entityID, int instanceIndex) const + { + auto instance = getLatestEntityInstance(entityID, instanceIndex); + if (instance.has_value()) + { + return instance->data(); + } + else + { + return nullptr; + } + } + + + ProviderSegment& CoreSegment::addProviderSegment(ProviderSegment&& providerSegment) + { + ProviderSegmentT& added = CoreSegmentBase::addProviderSegment(std::move(providerSegment)); + added.setMaxHistorySize(this->getMaxHistorySize()); + return added; + } + + + std::optional<wm::EntitySnapshot> + CoreSegment::getLatestEntitySnapshotLocking(const MemoryID& entityID) const + { + std::scoped_lock lock(_mutex); + return getLatestEntitySnapshot(entityID); + } + + std::optional<wm::EntityInstance> + CoreSegment::getLatestEntityInstanceLocking(const MemoryID& entityID, int instanceIndex) const + { + std::scoped_lock lock(_mutex); + return getLatestEntityInstance(entityID, instanceIndex); + } + + armarx::aron::datanavigator::DictNavigatorPtr + CoreSegment::getLatestEntityInstanceDataLocking(const MemoryID& entityID, int instanceIndex) const + { + std::scoped_lock lock(_mutex); + return getLatestEntityInstanceData(entityID, instanceIndex); + } + + + // TODO: add core segment if param is set + std::vector<Memory::Base::UpdateResult> + Memory::updateLocking(const Commit& commit) + { + // Group updates by core segment, then update each core segment in a batch to only lock it once. + std::map<std::string, std::vector<const EntityUpdate*>> updatesPerCoreSegment; + for (const EntityUpdate& update : commit.updates) + { + updatesPerCoreSegment[update.entityID.coreSegmentName].push_back(&update); + } + + std::vector<Memory::Base::UpdateResult> result; + // To throw an exception after the commit if a core segment is missing and the memory should not create new ones + std::vector<std::string> missingCoreSegmentNames; + for (const auto& [coreSegmentName, updates] : updatesPerCoreSegment) + { + auto it = this->_container.find(coreSegmentName); + if (it != this->_container.end()) + { + CoreSegment& coreSegment = it->second; + + // Lock the core segment for the whole batch. + std::scoped_lock lock(coreSegment.mutex()); + + for (const EntityUpdate* update : updates) + { + auto r = coreSegment.update(*update); + Base::UpdateResult ret { r }; + ret.memoryUpdateType = UpdateType::UpdatedExisting; + result.push_back(ret); + } + } + else + { + // Perform the other updates first, then throw afterwards. + missingCoreSegmentNames.push_back(coreSegmentName); + } + } + // Throw an exception if something went wrong. + if (not missingCoreSegmentNames.empty()) + { + // Just throw an exception for the first entry. We can extend this exception in the future. + throw armem::error::MissingEntry::create<CoreSegment>(missingCoreSegmentNames.front(), *this); + } + return result; + } + + + // TODO: Add core segment if param is set + Memory::Base::UpdateResult + Memory::updateLocking(const EntityUpdate& update) + { + this->_checkContainerName(update.entityID.memoryName, this->name()); + + CoreSegment& segment = getCoreSegment(update.entityID.coreSegmentName); + Base::UpdateResult result; + { + std::scoped_lock lock(segment.mutex()); + result = segment.update(update); + } + result.memoryUpdateType = UpdateType::UpdatedExisting; + return result; + } + +} diff --git a/source/RobotAPI/libraries/armem/server/wm/memory_definitions.h b/source/RobotAPI/libraries/armem/server/wm/memory_definitions.h new file mode 100644 index 0000000000000000000000000000000000000000..4eb6fdbb3105b0ae2ce3148c8457b915040a170a --- /dev/null +++ b/source/RobotAPI/libraries/armem/server/wm/memory_definitions.h @@ -0,0 +1,189 @@ +#pragma once + +#include "detail/MaxHistorySize.h" + +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/core/base/EntityInstanceBase.h> +#include <RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h> +#include <RobotAPI/libraries/armem/core/base/EntityBase.h> +#include <RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h> +#include <RobotAPI/libraries/armem/core/base/CoreSegmentBase.h> +#include <RobotAPI/libraries/armem/core/base/MemoryBase.h> + +#include <mutex> +#include <optional> + + +namespace armarx::armem::server::wm +{ + using EntityInstanceMetadata = base::EntityInstanceMetadata; + using EntityInstanceData = armarx::aron::datanavigator::DictNavigator; + using EntityInstanceDataPtr = armarx::aron::datanavigator::DictNavigatorPtr; + + using EntityInstance = armem::wm::EntityInstance; + using EntitySnapshot = armem::wm::EntitySnapshot; + + + /// @see base::EntityBase + class Entity : + public base::EntityBase<EntitySnapshot, Entity>, + public detail::MaxHistorySize + { + public: + + using base::EntityBase<EntitySnapshot, Entity>::EntityBase; + + + /** + * @brief Sets the maximum history size. + * + * The current history is truncated if necessary. + */ + void setMaxHistorySize(long maxSize); + + UpdateResult update(const EntityUpdate& update); + + + protected: + + /// If maximum size is set, ensure `history`'s is not higher. + std::vector<EntitySnapshotT> truncate(); + + }; + + + + /// @see base::ProviderSegmentBase + class ProviderSegment : + public base::ProviderSegmentBase<Entity, ProviderSegment>, + public detail::MaxHistorySizeParent<ProviderSegment> + { + public: + + using base::ProviderSegmentBase<Entity, ProviderSegment>::ProviderSegmentBase; + + + using ProviderSegmentBase::addEntity; + EntityT& addEntity(EntityT&& entity); + + }; + + + + /// @brief base::CoreSegmentBase + class CoreSegment : + public base::CoreSegmentBase<ProviderSegment, CoreSegment>, + public detail::MaxHistorySizeParent<CoreSegment> + { + using Base = base::CoreSegmentBase<ProviderSegment, CoreSegment>; + + public: + + using Base::CoreSegmentBase; + + // ToDo: Replace by runLocked() + std::mutex& mutex() const; + + + // Non-locking interface + + std::optional<wm::EntitySnapshot> getLatestEntitySnapshot( + const MemoryID& entityID) const; + std::optional<wm::EntityInstance> getLatestEntityInstance( + const MemoryID& entityID, int instanceIndex = 0) const; + armarx::aron::datanavigator::DictNavigatorPtr getLatestEntityInstanceData( + const MemoryID& entityID, int instanceIndex = 0) const; + + + template <class AronDtoT> + std::optional<AronDtoT> getLatestEntityInstanceDataAs( + const MemoryID& entityID, int instanceIndex = 0) const + { + wm::EntityInstanceDataPtr data = getLatestEntityInstanceData(entityID, instanceIndex); + if (data) + { + AronDtoT aron; + aron.fromAron(data); + return aron; + } + else + { + return std::nullopt; + } + } + + + /// @see base::CoreSegmentBase::addProviderSegment() + using CoreSegmentBase::addProviderSegment; + ProviderSegment& addProviderSegment(ProviderSegment&& providerSegment); + + + // Locking interface + + std::optional<wm::EntitySnapshot> getLatestEntitySnapshotLocking( + const MemoryID& entityID) const; + std::optional<wm::EntityInstance> getLatestEntityInstanceLocking( + const MemoryID& entityID, int instanceIndex = 0) const; + armarx::aron::datanavigator::DictNavigatorPtr getLatestEntityInstanceDataLocking( + const MemoryID& entityID, int instanceIndex = 0) const; + + + template <class AronDtoT> + std::optional<AronDtoT> getLatestEntityInstanceDataLockingAs( + const MemoryID& entityID, int instanceIndex = 0) const + { + // Keep lock to a minimum. + wm::EntityInstanceDataPtr data = nullptr; + { + std::scoped_lock lock(_mutex); + data = getLatestEntityInstanceData(entityID, instanceIndex); + } + if (data) + { + AronDtoT aron; + aron.fromAron(data); + return aron; + } + else + { + return std::nullopt; + } + } + + + protected: + + mutable std::mutex _mutex; + + }; + + + + /// @see base::MemoryBase + class Memory : + public base::MemoryBase<CoreSegment, Memory> + { + using Base = base::MemoryBase<CoreSegment, Memory>; + + public: + + using Base::MemoryBase; + + + /** + * @brief Perform the commit, locking the core segments. + * + * Groups the commits by core segment, and updates each core segment + * in a batch, locking the core segment. + */ + std::vector<Base::UpdateResult> updateLocking(const Commit& commit); + + /** + * @brief Update the memory, locking the updated core segment. + */ + Base::UpdateResult updateLocking(const EntityUpdate& update); + + }; + +} + diff --git a/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc34f7e2d7cb73d7a3e3715064508c3b73cab351 --- /dev/null +++ b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp @@ -0,0 +1,187 @@ +/* + * 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/>. + * + * @package RobotAPI::ArmarXObjects::armem + * @author Simon Ottenhaus ( simon dot ottenhaus at kit dot edu ) + * @date 2020 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#define BOOST_TEST_MODULE RobotAPI::ArmarXLibraries::armem + +#define ARMARX_BOOST_TEST + +#include <RobotAPI/Test.h> +#include <RobotAPI/libraries/armem/core/Commit.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> + +#include <iostream> +#include <set> + + +namespace armem = armarx::armem; + + +template <class ValueT> +static +std::vector<ValueT> toVector(const std::set<ValueT>& set) +{ + return {set.begin(), set.end()}; +} + + + +BOOST_AUTO_TEST_CASE(test_forEach) +{ + using namespace armarx::armem; + + const MemoryID mid("memory"); + const std::set<MemoryID> emptySet; // For comparison. + + wm::Memory memory(mid); + std::set<MemoryID> cids, pids, eids, sids, iids; + + for (size_t c = 0; c <= 2; ++c) + { + const MemoryID cid = mid.withCoreSegmentName("core_" + std::to_string(c)); + cids.insert(cid); + wm::CoreSegment& coreSeg = memory.addCoreSegment(cid.coreSegmentName); + for (size_t p = 0; p <= c; ++p) + { + const MemoryID pid = cid.withProviderSegmentName("prov_" + std::to_string(p)); + pids.insert(pid); + for (size_t e = 0; e <= p; ++e) + { + const MemoryID eid = pid.withEntityName("entity_" + std::to_string(e)); + eids.insert(eid); + for (size_t s = 0; s <= e; ++s) + { + const MemoryID sid = eid.withTimestamp(Time::microSeconds(int(s))); + sids.insert(sid); + + EntityUpdate update; + update.entityID = eid; + update.timeCreated = sid.timestamp; + for (size_t i = 0; i <= s; ++i) + { + const MemoryID iid = sid.withInstanceIndex(int(i)); + iids.insert(iid); + update.instancesData.emplace_back(); + } + auto r = memory.update(update); + + BOOST_CHECK(coreSeg.hasProviderSegment(pid.providerSegmentName)); + } + } + + BOOST_CHECK_EQUAL(coreSeg.size(), p + 1); + } + BOOST_CHECK_EQUAL(memory.size(), c + 1); + } + + BOOST_CHECK_GT(iids.size(), 0); + BOOST_CHECK_GT(sids.size(), 0); + BOOST_CHECK_GT(eids.size(), 0); + BOOST_CHECK_GT(pids.size(), 0); + BOOST_CHECK_GT(cids.size(), 0); + + BOOST_TEST_MESSAGE("Memory: \n" << memory.dump()); + + memory.forEachInstance([&](const wm::EntityInstance & i) -> bool + { + BOOST_TEST_CONTEXT(wm::EntityInstance::getLevelName() << " " << i.id()) + { + BOOST_TEST_INFO(toVector(iids)); + BOOST_CHECK_EQUAL(iids.count(i.id()), 1); + iids.erase(i.id()); + } + return true; + }); + BOOST_TEST_CONTEXT(toVector(iids)) + { + BOOST_CHECK_EQUAL(iids.size(), 0); + } + + memory.forEachSnapshot([&](const wm::EntitySnapshot & s) -> bool + { + BOOST_TEST_CONTEXT(wm::EntitySnapshot::getLevelName() << " " << s.id()) + { + BOOST_TEST_INFO(toVector(sids)); + BOOST_CHECK_EQUAL(sids.count(s.id()), 1); + sids.erase(s.id()); + } + return true; + }); + BOOST_TEST_INFO(toVector(sids)); + BOOST_CHECK_EQUAL(sids.size(), 0); + + memory.forEachEntity([&](const wm::Entity & e) -> bool + { + BOOST_TEST_CONTEXT(wm::Entity::getLevelName() << " " << e.id()) + { + BOOST_TEST_INFO(toVector(eids)); + BOOST_CHECK_EQUAL(eids.count(e.id()), 1); + eids.erase(e.id()); + } + return true; + }); + BOOST_TEST_INFO(toVector(eids)); + BOOST_CHECK_EQUAL(eids.size(), 0); + + memory.forEachProviderSegment([&](const wm::ProviderSegment & p) // -> bool + { + BOOST_TEST_CONTEXT(wm::ProviderSegment::getLevelName() << " " << p.id()) + { + BOOST_TEST_INFO(toVector(pids)); + BOOST_CHECK_EQUAL(pids.count(p.id()), 1); + pids.erase(p.id()); + } + return true; + }); + BOOST_TEST_INFO(toVector(pids)); + BOOST_CHECK_EQUAL(pids.size(), 0); + + memory.forEachCoreSegment([&](const wm::CoreSegment & c) // -> bool + { + BOOST_TEST_CONTEXT(wm::CoreSegment::getLevelName() << " " << c.id()) + { + BOOST_TEST_INFO(toVector(cids)); + BOOST_CHECK_EQUAL(cids.count(c.id()), 1); + cids.erase(c.id()); + } + return true; + }); + BOOST_TEST_INFO(toVector(cids)); + BOOST_CHECK_EQUAL(cids.size(), 0); + +} + + +BOOST_AUTO_TEST_CASE(test_forEach_non_bool_func) +{ + // Check whether this compiles + runs without break. + + armem::wm::Entity entity; + entity.addSnapshot(armem::Time::microSeconds(500)); + entity.addSnapshot(armem::Time::microSeconds(1500)); + + int i = 0; + entity.forEachSnapshot([&i](const armem::wm::EntitySnapshot&) -> void + { + ++i; + }); + BOOST_CHECK_EQUAL(i, 2); +} diff --git a/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp index a835f39bef74f745b22c4ee167e4755a031fec50..9fd00a4cf944f50cbd1c0d7bd06b9b56d812c161 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp @@ -25,7 +25,7 @@ #define ARMARX_BOOST_TEST #include <RobotAPI/Test.h> -#include "../core/workingmemory/ice_conversions.h" +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <iostream> @@ -59,12 +59,12 @@ BOOST_AUTO_TEST_CASE(test_entity) BOOST_CHECK_EQUAL(ice->id.providerSegmentName, entity.id().providerSegmentName); BOOST_CHECK_EQUAL(ice->id.entityName, entity.id().entityName); - BOOST_CHECK_EQUAL(ice->history.size(), entity.history().size()); + BOOST_CHECK_EQUAL(ice->history.size(), entity.size()); armem::wm::Entity entityOut; armem::fromIce(ice, entityOut); - BOOST_CHECK_EQUAL(entityOut.history().size(), entity.history().size()); + BOOST_CHECK_EQUAL(entityOut.size(), entity.size()); std::vector<armem::Time> timestamps = entityOut.getTimestamps(); BOOST_CHECK_EQUAL_COLLECTIONS(timestamps.begin(), timestamps.end(), expectedTimestamps.begin(), expectedTimestamps.end()); diff --git a/source/RobotAPI/libraries/armem/test/ArMemLTMTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemLTMTest.cpp index 24c0a22203aae81bfc52802a9f48fbb9755c9c5f..3ac3d50411854022aa31b781ba011e9ac8d91c75 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemLTMTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemLTMTest.cpp @@ -25,8 +25,8 @@ #define ARMARX_BOOST_TEST #include <RobotAPI/Test.h> -#include "../core/workingmemory/Memory.h" -#include "../core/error.h" +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/error.h> #include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> #include <RobotAPI/libraries/aron/core/navigator/type/AllNavigators.h> @@ -122,7 +122,7 @@ namespace ArMemLTMTest update.instancesData = q; update.timeCreated = armem::Time::now(); BOOST_CHECK_NO_THROW(providerSegment.update(update)); - BOOST_CHECK_EQUAL(providerSegment.entities().size(), 1); + BOOST_CHECK_EQUAL(providerSegment.size(), 1); } BOOST_CHECK(providerSegment.hasEntity("TestEntity")); diff --git a/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp index aad3359b0d57cfed79d463cc27dcced44550ef00..72f09fb225aa22b50ed55a9482e7f973acbf0fd2 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp @@ -25,8 +25,8 @@ #define ARMARX_BOOST_TEST #include <RobotAPI/Test.h> -#include "../core/MemoryID.h" -#include "../core/error.h" +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/core/error.h> #include <iostream> diff --git a/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp index 984c1f8e508ec631527f53d5fdff8ea32081ad6e..376f2ec680f92e64a5c72b496543749a303e8cc1 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp @@ -26,7 +26,8 @@ #include <RobotAPI/Test.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h> #include <RobotAPI/libraries/armem/core/diskmemory/Memory.h> #include <RobotAPI/libraries/armem/core/error.h> @@ -34,6 +35,7 @@ #include <iostream> #include <SimoxUtility/meta/type_name.h> #include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> +#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> namespace armem = armarx::armem; @@ -87,11 +89,11 @@ namespace ArMemMemoryTest using MemoryItem::MemoryItem; using MemoryItem::operator=; - std::string getKeyString() const override + std::string getKeyString() const { return ""; } - std::string getLevelName() const override + std::string getLevelName() const { return ""; } @@ -154,24 +156,29 @@ namespace ArMemMemoryTest using MemoryContainerBase::MemoryContainerBase; using MemoryContainerBase::operator=; - std::string getKeyString() const override + std::string getKeyString() const { return ""; } - std::string getLevelName() const override + std::string getLevelName() const { return ""; } + + void fill() + { + _container = std::vector<int> { -1, 2, -3 }; + } }; struct MemoryContainerCtorOpTestFixture { - const armem::MemoryID id {"A/B/C/123/1"}; - const armem::MemoryID moved {"////1"}; // int is not moved + const armem::MemoryID id {"M/C/P/E/123/1"}; + const armem::MemoryID moved {"////123/1"}; // Time and int are just copied, not moved TestMemoryContainer cont {id}; MemoryContainerCtorOpTestFixture() { - cont.container() = std::vector<int> { -1, 2, -3 }; + cont.fill(); BOOST_CHECK_EQUAL(cont.id(), id); BOOST_CHECK_EQUAL(cont.size(), 3); } @@ -244,17 +251,6 @@ BOOST_AUTO_TEST_CASE(test_key_ctors) } -template <class ...Args> -auto add_element(std::vector<Args...>& vector) -{ - return vector.emplace_back(); -} -template <class ...Args> -auto add_element(std::map<Args...>& map) -{ - return map.emplace(); -} - template <class T> struct CustomChecks @@ -370,14 +366,17 @@ struct CustomChecks<armem::d_ltm::Memory> struct CopyMoveCtorsOpsTestBase { - const armem::MemoryID id {"A/B/C/123000"}; // int index would not be moved - const armem::MemoryID idMoved; + const armem::MemoryID id {"M", "C", "P", "E", armem::Time::microSeconds(123000), 1}; + //const armem::MemoryID idMoved {"", "", "", "", armem::Time::microSeconds(123000), 1}; + armem::MemoryID idMoved = id; std::string typeName; CopyMoveCtorsOpsTestBase(const std::string& typeName) : typeName(typeName) { + armem::MemoryID copy = std::move(idMoved); + (void) copy; } virtual ~CopyMoveCtorsOpsTestBase() { @@ -459,21 +458,25 @@ struct InstanceCopyMoveCtorsOpsTest : public CopyMoveCtorsOpsTestBase } void testMoveCtor() override { + T copy { in }; T out { std::move(in) }; BOOST_CHECK_EQUAL(in.id(), idMoved); BOOST_CHECK_EQUAL(out.id(), id); + CustomChecks<T>::checkEqual(out, copy); CustomChecks<T>::checkMoved(in); } void testMoveOp() override { + T copy { in }; T out; out = std::move(in); BOOST_CHECK_EQUAL(in.id(), idMoved); BOOST_CHECK_EQUAL(out.id(), id); + CustomChecks<T>::checkEqual(out, copy); CustomChecks<T>::checkMoved(in); } }; @@ -492,7 +495,19 @@ struct CopyMoveCtorsOpsTest : public CopyMoveCtorsOpsTestBase void reset() override { in = T {id}; - add_element(in.container()); + if constexpr(std::is_same_v<T, armem::wm::Memory> + || std::is_same_v<T, armem::ltm::Memory> + || std::is_same_v<T, armem::d_ltm::Memory>) + { + in._addMissingCoreSegmentDuringUpdate = true; + } + { + armem::EntityUpdate update; + update.entityID = armem::MemoryID("M", "C", "P", "E", armem::Time::microSeconds(123000), 0); + update.timeCreated = update.entityID.timestamp; + update.instancesData.emplace_back(); + in.update(update); + } BOOST_CHECK_EQUAL(in.id(), id); BOOST_CHECK_EQUAL(in.size(), 1); @@ -652,17 +667,17 @@ BOOST_AUTO_TEST_CASE(test_segment_setup) update.timeCreated = armem::Time::milliSeconds(1000); BOOST_CHECK_NO_THROW(providerSegment.update(update)); - BOOST_CHECK_EQUAL(providerSegment.entities().size(), 1); + BOOST_CHECK_EQUAL(providerSegment.size(), 1); BOOST_CHECK(providerSegment.hasEntity("image")); BOOST_CHECK(!providerSegment.hasEntity("other_image")); armem::wm::Entity& entity = providerSegment.getEntity("image"); BOOST_CHECK_EQUAL(entity.name(), "image"); - BOOST_CHECK_EQUAL(entity.history().size(), 1); - BOOST_CHECK_EQUAL(entity.history().count(update.timeCreated), 1); + BOOST_CHECK_EQUAL(entity.size(), 1); + BOOST_CHECK(entity.hasSnapshot(update.timeCreated)); - armem::wm::EntitySnapshot& entitySnapshot = entity.history().at(update.timeCreated); - BOOST_CHECK_EQUAL(entitySnapshot.instances().size(), update.instancesData.size()); + armem::wm::EntitySnapshot& entitySnapshot = entity.getSnapshot(update.timeCreated); + BOOST_CHECK_EQUAL(entitySnapshot.size(), update.instancesData.size()); // Another update (on memory). @@ -670,16 +685,16 @@ BOOST_AUTO_TEST_CASE(test_segment_setup) update.instancesData = { std::make_shared<aron::datanavigator::DictNavigator>() }; update.timeCreated = armem::Time::milliSeconds(2000); memory.update(update); - BOOST_CHECK_EQUAL(entity.history().size(), 2); - BOOST_CHECK_EQUAL(entity.history().count(update.timeCreated), 1); - BOOST_CHECK_EQUAL(entity.history().at(update.timeCreated).instances().size(), update.instancesData.size()); + BOOST_CHECK_EQUAL(entity.size(), 2); + BOOST_CHECK(entity.hasSnapshot(update.timeCreated)); + BOOST_CHECK_EQUAL(entity.getSnapshot(update.timeCreated).size(), update.instancesData.size()); // A third update (on entity). update.instancesData = { std::make_shared<aron::datanavigator::DictNavigator>() }; update.timeCreated = armem::Time::milliSeconds(3000); entity.update(update); - BOOST_CHECK_EQUAL(entity.history().size(), 3); + BOOST_CHECK_EQUAL(entity.size(), 3); } @@ -687,7 +702,7 @@ BOOST_AUTO_TEST_CASE(test_segment_setup) BOOST_AUTO_TEST_CASE(test_history_size_in_entity) { - armem::wm::Entity entity("entity"); + armem::server::wm::Entity entity("entity"); armem::EntityUpdate update; update.entityID.entityName = entity.name(); @@ -699,38 +714,38 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_entity) entity.update(update); update.timeCreated = armem::Time::milliSeconds(3000); entity.update(update); - BOOST_CHECK_EQUAL(entity.history().size(), 3); + BOOST_CHECK_EQUAL(entity.size(), 3); // Now with maximum history size. entity.setMaxHistorySize(2); - BOOST_CHECK_EQUAL(entity.history().size(), 2); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(1000)), 0); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(2000)), 1); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(3000)), 1); + BOOST_CHECK_EQUAL(entity.size(), 2); + BOOST_CHECK(not entity.hasSnapshot(armem::Time::milliSeconds(1000))); + BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(2000))); + BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000))); update.timeCreated = armem::Time::milliSeconds(4000); entity.update(update); - BOOST_CHECK_EQUAL(entity.history().size(), 2); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(2000)), 0); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(3000)), 1); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(4000)), 1); + BOOST_CHECK_EQUAL(entity.size(), 2); + BOOST_CHECK(not entity.hasSnapshot(armem::Time::milliSeconds(2000))); + BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000))); + BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(4000))); // Disable maximum history size. entity.setMaxHistorySize(-1); update.timeCreated = armem::Time::milliSeconds(5000); entity.update(update); - BOOST_CHECK_EQUAL(entity.history().size(), 3); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(3000)), 1); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(4000)), 1); - BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(5000)), 1); + BOOST_CHECK_EQUAL(entity.size(), 3); + BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000))); + BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(4000))); + BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(5000))); } BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment) { - armem::wm::ProviderSegment providerSegment("SomeRGBImageProvider"); + armem::server::wm::ProviderSegment providerSegment("SomeRGBImageProvider"); armem::EntityUpdate update; update.entityID.providerSegmentName = providerSegment.name(); @@ -753,22 +768,22 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment) update.timeCreated = armem::Time::milliSeconds(4000); providerSegment.update(update); - BOOST_CHECK_EQUAL(providerSegment.getEntity("A").history().size(), 3); - BOOST_CHECK_EQUAL(providerSegment.getEntity("B").history().size(), 4); + BOOST_CHECK_EQUAL(providerSegment.getEntity("A").size(), 3); + BOOST_CHECK_EQUAL(providerSegment.getEntity("B").size(), 4); // Employ maximum history size. providerSegment.setMaxHistorySize(3); - BOOST_CHECK_EQUAL(providerSegment.getEntity("A").history().size(), 3); - BOOST_CHECK_EQUAL(providerSegment.getEntity("B").history().size(), 3); + BOOST_CHECK_EQUAL(providerSegment.getEntity("A").size(), 3); + BOOST_CHECK_EQUAL(providerSegment.getEntity("B").size(), 3); providerSegment.setMaxHistorySize(2); - BOOST_CHECK_EQUAL(providerSegment.getEntity("A").history().size(), 2); - BOOST_CHECK_EQUAL(providerSegment.getEntity("B").history().size(), 2); + BOOST_CHECK_EQUAL(providerSegment.getEntity("A").size(), 2); + BOOST_CHECK_EQUAL(providerSegment.getEntity("B").size(), 2); providerSegment.setMaxHistorySize(3); - BOOST_CHECK_EQUAL(providerSegment.getEntity("A").history().size(), 2); - BOOST_CHECK_EQUAL(providerSegment.getEntity("B").history().size(), 2); + BOOST_CHECK_EQUAL(providerSegment.getEntity("A").size(), 2); + BOOST_CHECK_EQUAL(providerSegment.getEntity("B").size(), 2); // Add new entity. providerSegment.setMaxHistorySize(2); @@ -784,7 +799,7 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment) // Check correctly inherited history size. BOOST_CHECK_EQUAL(providerSegment.getEntity("C").getMaxHistorySize(), 2); // Check actual history size. - BOOST_CHECK_EQUAL(providerSegment.getEntity("C").history().size(), 2); + BOOST_CHECK_EQUAL(providerSegment.getEntity("C").size(), 2); // Remove maximum. providerSegment.setMaxHistorySize(-1); @@ -795,58 +810,6 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment) update.entityID.entityName = name; update.timeCreated = armem::Time::milliSeconds(5000); providerSegment.update(update); - BOOST_CHECK_EQUAL(providerSegment.getEntity(name).history().size(), 3); + BOOST_CHECK_EQUAL(providerSegment.getEntity(name).size(), 3); } } - - - -template <class T> -struct CopyTest -{ - CopyTest() - { - } - - void test() - { - // At least check whether they can be called. - T t; - T t2 = t.copy(); - - if constexpr(!std::is_base_of_v<armem::base::EntityInstanceBase<T>, T>) - { - t2 = t.copyEmpty(); - } - } -}; - - -BOOST_AUTO_TEST_CASE(test_copy) -{ - { - CopyTest<armem::wm::EntityInstance>().test(); - CopyTest<armem::wm::EntitySnapshot>().test(); - CopyTest<armem::wm::Entity>().test(); - CopyTest<armem::wm::ProviderSegment>().test(); - CopyTest<armem::wm::CoreSegment>().test(); - CopyTest<armem::wm::Memory>().test(); - } - { - CopyTest<armem::ltm::EntityInstance>().test(); - CopyTest<armem::ltm::EntitySnapshot>().test(); - CopyTest<armem::ltm::Entity>().test(); - CopyTest<armem::ltm::ProviderSegment>().test(); - CopyTest<armem::ltm::CoreSegment>().test(); - CopyTest<armem::ltm::Memory>().test(); - } - { - CopyTest<armem::d_ltm::EntityInstance>().test(); - CopyTest<armem::d_ltm::EntitySnapshot>().test(); - CopyTest<armem::d_ltm::Entity>().test(); - CopyTest<armem::d_ltm::ProviderSegment>().test(); - CopyTest<armem::d_ltm::CoreSegment>().test(); - CopyTest<armem::d_ltm::Memory>().test(); - } -} - diff --git a/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp index 535735b09eeb61d41cdf0dbaf658cebcdb08f4db..78d3077c082e41f32bf6dfd398e9e7d474e19dc3 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp @@ -25,9 +25,10 @@ #define ARMARX_BOOST_TEST #include <RobotAPI/Test.h> -#include "../client/query/Builder.h" -#include "../client/query/query_fns.h" -#include "../core/workingmemory/ice_conversions.h" +#include <RobotAPI/libraries/armem/client/query/Builder.h> +#include <RobotAPI/libraries/armem/client/query/query_fns.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> + #include <iostream> diff --git a/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp index 4b83fd43261e1d97da45495f5da94279931e606f..656842b3dcd23d49a84a51a04fc02143c14cada2 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp @@ -20,28 +20,26 @@ * GNU General Public License */ -#include "ArmarXCore/core/exceptions/LocalException.h" -#include <RobotAPI/interface/armem/query.h> -#include <boost/test/tools/old/interface.hpp> #define BOOST_TEST_MODULE RobotAPI::ArmarXLibraries::armem #define ARMARX_BOOST_TEST #include <RobotAPI/Test.h> -#include "../server/query_proc/workingmemory/EntityQueryProcessor.h" -#include "../error.h" - - -#include <iostream> +#include <RobotAPI/interface/armem/query.h> +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/base/detail/negative_index_semantics.h> +#include <RobotAPI/libraries/armem/server/query_proc/wm.h> #include <SimoxUtility/algorithm/get_map_keys_values.h> #include <SimoxUtility/algorithm/string.h> +#include <iostream> + namespace armem = armarx::armem; namespace aron = armarx::aron; namespace query = armarx::armem::query::data; -using EntityQueryProcessor = armarx::armem::wm::query_proc::EntityQueryProcessor; +using EntityQueryProcessor = armarx::armem::server::query_proc::wm::EntityQueryProcessor; namespace ArMemQueryTest @@ -55,8 +53,7 @@ namespace ArMemQueryTest { armem::wm::Entity entity; - armem::wm::query_proc::EntityQueryProcessor processor; - query::EntityQueryPtr entityQuery; + armem::server::query_proc::wm::EntityQueryProcessor processor; std::vector<armem::wm::Entity> results; @@ -85,10 +82,10 @@ namespace ArMemQueryTest template <class QueryT> void addResults(QueryT query = {}) { - entityQuery = new QueryT(query); - + // Test whether we get the same result when we pass the concrete type + // (static resolution) and when we pass the base type (dynamic resolution). results.emplace_back(processor.process(query, entity)); - results.emplace_back(processor.process(*entityQuery, entity)); + results.emplace_back(processor.process(static_cast<query::EntityQuery const&>(query), entity)); } }; @@ -126,8 +123,8 @@ BOOST_AUTO_TEST_CASE(test_entity_Single_latest) { BOOST_CHECK_EQUAL(result.name(), entity.name()); BOOST_CHECK_EQUAL(result.size(), 1); - BOOST_CHECK_EQUAL(result.history().begin()->second.time(), entity.getLatestSnapshot().time()); - BOOST_CHECK_NE(&result.history().begin()->second, &entity.history().rbegin()->second); + const armem::wm::EntitySnapshot& first = result.getFirstSnapshotAfterOrAt(armem::Time::microSeconds(0)); + BOOST_CHECK_EQUAL(first.time(), armem::Time::microSeconds(5000)); } } @@ -140,8 +137,8 @@ BOOST_AUTO_TEST_CASE(test_entity_Single_existing) for (const armem::wm::Entity& result : results) { BOOST_CHECK_EQUAL(result.name(), entity.name()); - BOOST_CHECK_EQUAL(result.size(), 1); - BOOST_CHECK_EQUAL(result.history().begin()->second.time(), armem::Time::microSeconds(3000)); + BOOST_REQUIRE_EQUAL(result.size(), 1); + BOOST_CHECK_EQUAL(result.getFirstSnapshot().time(), armem::Time::microSeconds(3000)); } } @@ -168,12 +165,13 @@ BOOST_AUTO_TEST_CASE(test_entity_All) { BOOST_CHECK_EQUAL(result.name(), entity.name()); BOOST_CHECK_EQUAL(result.size(), entity.size()); - auto jt = entity.history().begin(); - for (auto it = result.history().begin(); it != result.history().end(); ++it, ++jt) + for (armem::Time time : entity.getTimestamps()) { - BOOST_CHECK_EQUAL(it->first, jt->first); - BOOST_CHECK_EQUAL(it->second.time(), jt->second.time()); - BOOST_CHECK_NE(&it->second, &jt->second); + BOOST_REQUIRE(result.hasSnapshot(time)); + const armem::wm::EntitySnapshot& rs = result.getSnapshot(time); + const armem::wm::EntitySnapshot& es = entity.getSnapshot(time); + BOOST_CHECK_EQUAL(rs.time(), es.time()); + BOOST_CHECK_NE(&rs, &es); } } } @@ -191,7 +189,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_slice) BOOST_CHECK_EQUAL(result.size(), 2); - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); std::vector<armem::Time> expected { armem::Time::microSeconds(2000), armem::Time::microSeconds(3000) @@ -212,7 +210,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_exact) BOOST_CHECK_EQUAL(result.size(), 3); - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); std::vector<armem::Time> expected { armem::Time::microSeconds(2000), armem::Time::microSeconds(3000), armem::Time::microSeconds(4000) @@ -233,8 +231,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_all) BOOST_CHECK_EQUAL(result.size(), entity.size()); - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); - std::vector<armem::Time> expected = simox::alg::get_keys(entity.history()); + const std::vector<armem::Time> times = result.getTimestamps(); + const std::vector<armem::Time> expected = entity.getTimestamps(); BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end()); } } @@ -266,7 +264,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_from_start) BOOST_CHECK_EQUAL(result.size(), 2); - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + const std::vector<armem::Time> times = result.getTimestamps(); std::vector<armem::Time> expected { armem::Time::microSeconds(1000), armem::Time::microSeconds(2000) @@ -284,10 +282,9 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_to_end) for (const armem::wm::Entity& result : results) { BOOST_CHECK_EQUAL(result.name(), entity.name()); - BOOST_CHECK_EQUAL(result.size(), 3); - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + const std::vector<armem::Time> times = result.getTimestamps(); std::vector<armem::Time> expected { armem::Time::microSeconds(3000), armem::Time::microSeconds(4000), armem::Time::microSeconds(5000) @@ -307,12 +304,11 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_1) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + const std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 1); - BOOST_REQUIRE_EQUAL(times.front(), armem::Time::microSeconds(3000)); + BOOST_CHECK_EQUAL(times.front(), armem::Time::microSeconds(3000)); } - } BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_2) @@ -323,7 +319,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_2) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + const std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 2); std::vector<armem::Time> expected @@ -348,7 +344,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_before) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 1); BOOST_REQUIRE_EQUAL(times.front(), armem::Time::microSeconds(3000)); @@ -363,7 +359,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_at) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 1); BOOST_REQUIRE_EQUAL(times.front(), armem::Time::microSeconds(3000)); @@ -378,7 +374,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_lookup_past) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE(times.empty()); } } @@ -398,7 +394,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_no_limit) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 2); std::vector<armem::Time> expected @@ -424,7 +420,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_600) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 2); std::vector<armem::Time> expected @@ -450,7 +446,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_too_small) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 0); } @@ -469,7 +465,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_next) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 1); std::vector<armem::Time> expected @@ -494,7 +490,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_previous) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 1); std::vector<armem::Time> expected @@ -519,7 +515,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_perfect_match) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 1); std::vector<armem::Time> expected @@ -544,7 +540,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_past) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE(times.empty()); } } @@ -562,7 +558,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE(times.empty()); } } @@ -580,7 +576,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future_valid) for (const auto& result : results) { - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); BOOST_REQUIRE_EQUAL(times.size(), 1); std::vector<armem::Time> expected @@ -601,33 +597,33 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_invalid_timestamp) BOOST_AUTO_TEST_CASE(test_negative_index_semantics) { - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(0, 0), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(0, 1), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(0, 10), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(0, 0), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(0, 1), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(0, 10), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(1, 1), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(5, 1), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(1, 1), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(5, 1), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(1, 5), 1); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(5, 5), 4); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(5, 6), 5); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(5, 10), 5); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(1, 5), 1); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(5, 5), 4); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(5, 6), 5); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(5, 10), 5); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-1, 0), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 0), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-1, 0), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-5, 0), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-1, 1), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 1), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-1, 1), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-5, 1), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-1, 2), 1); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 2), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-1, 2), 1); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-5, 2), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-1, 5), 4); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 5), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 6), 1); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-5, 10), 5); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-10, 10), 0); - BOOST_CHECK_EQUAL(EntityQueryProcessor::negativeIndexSemantics(-20, 10), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-1, 5), 4); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-5, 5), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-5, 6), 1); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-5, 10), 5); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-10, 10), 0); + BOOST_CHECK_EQUAL(armem::base::detail::negativeIndexSemantics(-20, 10), 0); } @@ -643,8 +639,8 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_all_default) BOOST_CHECK_EQUAL(result.size(), entity.size()); - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); - std::vector<armem::Time> expected = simox::alg::get_keys(entity.history()); + const std::vector<armem::Time> times = result.getTimestamps(); + const std::vector<armem::Time> expected = entity.getTimestamps(); BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end()); } @@ -666,7 +662,7 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_slice) BOOST_CHECK_EQUAL(result.size(), 3); - std::vector<armem::Time> times = simox::alg::get_keys(result.history()); + std::vector<armem::Time> times = result.getTimestamps(); std::vector<armem::Time> expected { armem::Time::microSeconds(2000), armem::Time::microSeconds(3000), armem::Time::microSeconds(4000) diff --git a/source/RobotAPI/libraries/armem/test/CMakeLists.txt b/source/RobotAPI/libraries/armem/test/CMakeLists.txt index e7fa876c119596f5c49352cfd0dca757ab01019c..b10935f95fedd6a1309248007422c53783d2c9e4 100644 --- a/source/RobotAPI/libraries/armem/test/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/test/CMakeLists.txt @@ -8,3 +8,4 @@ armarx_add_test(ArMemMemoryIDTest ArMemMemoryIDTest.cpp "${LIBS}") armarx_add_test(ArMemQueryTest ArMemQueryTest.cpp "${LIBS}") armarx_add_test(ArMemLTMTest ArMemLTMTest.cpp "${LIBS}") armarx_add_test(ArMemQueryBuilderTest ArMemQueryBuilderTest.cpp "${LIBS}") +armarx_add_test(ArMemForEachTest ArMemForEachTest.cpp "${LIBS}") diff --git a/source/RobotAPI/libraries/armem/util/util.h b/source/RobotAPI/libraries/armem/util/util.h index 35fc1538b78df0b817e7ae0676be68e9675d1f0f..3045d583a6a4144ed996a286257eb5ba2910b9c5 100644 --- a/source/RobotAPI/libraries/armem/util/util.h +++ b/source/RobotAPI/libraries/armem/util/util.h @@ -24,12 +24,12 @@ #include <vector> #include <optional> -#include "ArmarXCore/core/logging/Logging.h" +#include <ArmarXCore/core/logging/Logging.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Entity.h> -#include <RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/aron/core/codegenerator/codeWriter/cpp/AronCppClass.h> + namespace armarx::armem { @@ -52,10 +52,13 @@ namespace armarx::armem return std::nullopt; } +#if 0 + // item.data() is by definition a DictNavigator if (item.data()->getDescriptor() != aron::data::Descriptor::eDict) { return std::nullopt; } +#endif try { diff --git a/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.cpp b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.cpp index 5016db50bf5da8dc10d0fac5b5c004b9178ddc40..38e4d8c88719541e7c4fca92964cfb069c22ba5e 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.cpp @@ -4,6 +4,7 @@ #include <QLineEdit> #include <QTimer> #include <QHBoxLayout> +#include <QFileDialog> #include <cmath> @@ -16,32 +17,53 @@ namespace armarx::armem::gui setSizePolicy(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Fixed); auto vlayout = new QVBoxLayout(); - auto hlayout = new QHBoxLayout(); + auto hlayout1 = new QHBoxLayout(); + auto hlayout2 = new QHBoxLayout(); + + hlayout1->setContentsMargins(10, 2, 10, 2); + hlayout2->setContentsMargins(10, 2, 10, 2); const int margin = 0; vlayout->setContentsMargins(margin, margin, margin, margin); _lineEdit = new QLineEdit("/tmp/MemoryExport", this); _lineEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); - _lineEdit->setMinimumWidth(400); + _lineEdit->setMinimumWidth(150); + + _openFileBrowserButton = new QPushButton("Search files", this); + + _storeOnDiskButton = new QPushButton("Store query (Disk)", this); + _storeInLTMButton = new QPushButton("Store query (LTM)", this); - _storeOnDiskButton = new QPushButton("Store current result on local Disk", this); + hlayout1->addWidget(_lineEdit); + hlayout1->addWidget(_openFileBrowserButton); - _storeInLTMButton = new QPushButton("Store current result in LTM", this); + hlayout2->addWidget(_storeOnDiskButton); + hlayout2->addWidget(_storeInLTMButton); - vlayout->addWidget(_lineEdit); - hlayout->addWidget(_storeOnDiskButton); - hlayout->addWidget(_storeInLTMButton); - vlayout->addItem(hlayout); + vlayout->addItem(hlayout1); + vlayout->addItem(hlayout2); this->setLayout(vlayout); // Private connections. // Public connections. + connect(_openFileBrowserButton, &QPushButton::pressed, this, &This::openFileBrowser); connect(_storeInLTMButton, &QPushButton::pressed, this, &This::storeInLTM); connect(_storeOnDiskButton, &QPushButton::pressed, this, &This::storeOnDisk); } + void MemoryControlWidget::openFileBrowser() + { + QFileDialog dialog; + dialog.setFileMode(QFileDialog::DirectoryOnly); + //dialog.setOption(QFileDialog::DontUseNativeDialog, true); + dialog.setOption(QFileDialog::ShowDirsOnly, false); + dialog.exec(); + QString open = dialog.directory().path(); + _lineEdit->setText(open); + } + QLineEdit* MemoryControlWidget::pathInputBox() { return _lineEdit; diff --git a/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.h b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.h index 19831694acc7b9251c7d372b8381f755df1bc292..c6b156db313b01180a7f5884959ffc21b0a73f9d 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.h +++ b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.h @@ -4,6 +4,7 @@ class QPushButton; class QLineEdit; +class QFileDialog; namespace armarx::armem::gui { @@ -20,11 +21,15 @@ namespace armarx::armem::gui QLineEdit* pathInputBox(); QString getEnteredPath(); + QPushButton* openFileBrowserButton(); + QPushButton* storeInLTMButton(); QPushButton* storeOnDiskButton(); public slots: + void openFileBrowser(); + signals: void storeInLTM(); @@ -40,6 +45,8 @@ namespace armarx::armem::gui QLineEdit* _lineEdit; + QPushButton* _openFileBrowserButton; + QPushButton* _storeInLTMButton; QPushButton* _storeOnDiskButton; diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp index 5037bad396c0e7a83b7704b4895a25225ae8106f..802de477cdd143051b6e45f8f2c4d995ebfa4e29 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp @@ -1,12 +1,12 @@ #include "MemoryViewer.h" -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem_gui/gui_utils.h> #include <RobotAPI/libraries/armem/core/diskmemory/Memory.h> -#include <RobotAPI/libraries/armem/server/query_proc/diskmemory/MemoryQueryProcessor.h> -#include <RobotAPI/libraries/armem/server/query_proc/workingmemory/MemoryQueryProcessor.h> +#include <RobotAPI/libraries/armem/server/query_proc/diskmemory.h> +#include <RobotAPI/libraries/armem/server/query_proc/wm.h> #include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h> @@ -26,6 +26,8 @@ #include <QSettings> #include <filesystem> +#include <iomanip> + namespace armarx::armem::gui { @@ -216,108 +218,82 @@ namespace armarx::armem::gui void MemoryViewer::updateMemories() { - memoryReaders.clear(); - memoryData.clear(); + int errorCount = 0; + memoryData.clear(); memoryReaders = mns.getAllReaders(true); - bool dataChanged = false; - - QString qs = memoryControlWidget->getEnteredPath(); - std::string utf8_text = qs.toUtf8().constData(); + std::filesystem::path path(memoryControlWidget->getEnteredPath().toStdString()); - std::filesystem::path p(utf8_text); + armem::client::QueryInput input = memoryGroup->queryWidget()->queryInput(); // first check if the local file system should be queried if (memoryGroup->queryWidget()->alsoQueryLocalDisk()) { - if (std::filesystem::is_directory(p)) + if (std::filesystem::is_directory(path)) { - for (const auto& d : std::filesystem::directory_iterator(p)) + for (const auto& directory : std::filesystem::directory_iterator(path)) { - if (d.is_directory()) + if (directory.is_directory()) { - std::string k = d.path().filename(); + std::string k = directory.path().filename(); armem::d_ltm::Memory dMem(k); - dMem.reload(p / k); + dMem.reload(path / k); - armem::client::QueryInput input = memoryGroup->queryWidget()->queryInput(); - input.addQueryTargetToAll(armem::query::data::QueryTarget::Disk); + input.addQueryTargetToAll(armem::query::data::QueryTarget::LTM); // We use LTM as query target for the disk - armem::d_ltm::query_proc::MemoryQueryProcessor d_ltm_processor; - dMem = d_ltm_processor.process(input.toIce(), dMem, /* execute if: */ { query::data::QueryTarget::Disk }); + armem::server::query_proc::d_ltm::MemoryQueryProcessor d_ltm_processor; + dMem = d_ltm_processor.process(input.toIce(), dMem); wm::Memory converted = dMem.convert(); memoryData[k] = std::move(converted); - dataChanged = true; } } } else { - ARMARX_WARNING << "Could not import a memory from '" << utf8_text << "'. Skipping import."; + ARMARX_WARNING << "Could not import a memory from '" << path << "'. Skipping import."; } } - - armem::client::QueryInput input = memoryGroup->queryWidget()->queryInput(); - for (auto& [name, reader] : memoryReaders) + else { - TIMING_START(MemoryQuery); + for (auto& [name, reader] : memoryReaders) { - armem::client::QueryResult result = reader.query(input); - if (result) + TIMING_START(MemoryQuery); { - if (result.memory.hasData()) + armem::client::QueryResult result = reader.query(input); + if (result.success) { - if (const auto& it = memoryData.find(name); it != memoryData.end()) - { - result.memory.append(it->second); - - // requery (e.g. to get only the last n values instead of the last n from disk and the last n from wm) - armem::wm::query_proc::MemoryQueryProcessor wm_processor; - result.memory = wm_processor.process(input.toIce(), result.memory, /* execute if: */ { query::data::QueryTarget::WM }); - - if (!result.memory.hasData()) - { - ARMARX_ERROR << "A memory which had data before lost data. This indicates that there is something wrong."; - } - } - - dataChanged = true; - memoryData[name] = std::move(result.memory); + memoryData[name] = result.memory; } else { - ARMARX_INFO << "The memory " << name << " has no data after querying."; + ARMARX_INFO << "A query for memory '" << name << "' produced an error: " << result.errorMessage; + errorCount++; } } - else + TIMING_END_STREAM(MemoryQuery, ARMARX_VERBOSE); + + if (debugObserver) { - ARMARX_WARNING << "A query for memory '" + name + "' produced an error: " << result.errorMessage; - if (statusLabel) - { - statusLabel->setText(QString::fromStdString(result.errorMessage)); - } + debugObserver->setDebugDatafield(Logging::tag.tagName, "Memory Query [ms]", new Variant(MemoryQuery.toMilliSecondsDouble())); } } - TIMING_END_STREAM(MemoryQuery, ARMARX_VERBOSE); - - if (debugObserver) - { - debugObserver->setDebugDatafield(Logging::tag.tagName, "Memory Query [ms]", new Variant(MemoryQuery.toMilliSecondsDouble())); - } } - if (dataChanged) - { - emit memoryDataChanged(); - } - else + emit memoryDataChanged(); + + // Code to output status label information + if (statusLabel and errorCount > 0) { - if (statusLabel) - { - statusLabel->setText("No query result."); - } + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + + std::stringstream ss; + ss << "Last update: " << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); + ss << "\nThe query produced " << errorCount << " errors! Please check log."; + + statusLabel->setText(QString::fromStdString(ss.str())); } } @@ -444,17 +420,10 @@ namespace armarx::armem::gui std::map<std::string, const armem::wm::Memory*> convMap; for (auto& [name, data] : memoryData) { - /*if (data.has_value()) - { - convMap[name] = &data.value(); - }*/ convMap[name] = &data; } - if (convMap.empty()) - { - return; - } + // if convMap.empty(), we still need to update to remove existing entries. TIMING_START(GuiUpdate); memoryGroup->tree()->update(convMap); diff --git a/source/RobotAPI/libraries/armem_gui/PeriodicUpdateWidget.cpp b/source/RobotAPI/libraries/armem_gui/PeriodicUpdateWidget.cpp index a62659cd78d4448bb72913ae432fc22f8f2b6eae..dd51a5e7f055f387e7580196874128c1f4bf2b12 100644 --- a/source/RobotAPI/libraries/armem_gui/PeriodicUpdateWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/PeriodicUpdateWidget.cpp @@ -28,7 +28,7 @@ namespace armarx::armem::gui _frequencySpinBox->setValue(frequency); _frequencySpinBox->setMinimum(0); _frequencySpinBox->setMaximum(maxFrequency); - _frequencySpinBox->setSingleStep(1.0); + _frequencySpinBox->setSingleStep(0.5); _frequencySpinBox->setSuffix(" Hz"); diff --git a/source/RobotAPI/libraries/armem_gui/TreeWidgetBuilder.h b/source/RobotAPI/libraries/armem_gui/TreeWidgetBuilder.h index 37de7699ce2c8d9245ced9e26fa8625d9b62159e..f3ca45cf17b05c72936a5afb8958e4eb5686aaab 100644 --- a/source/RobotAPI/libraries/armem_gui/TreeWidgetBuilder.h +++ b/source/RobotAPI/libraries/armem_gui/TreeWidgetBuilder.h @@ -16,10 +16,10 @@ namespace armarx * A class to efficiently build and maintain sorted items of `QTreeWidget` * or `QTreeWidgetItem` based on a sorted container matching the intended structure. */ - template <class ContainerT> + template <class _ElementT> struct TreeWidgetBuilder { - using ElementT = typename ContainerT::value_type; + using ElementT = _ElementT; /// Return < 0 if `element < item`, 0 if `element == item`, and > 0 if `element > item`. using CompareFn = std::function<int(const ElementT& element, QTreeWidgetItem* item)>; @@ -30,14 +30,15 @@ namespace armarx TreeWidgetBuilder() = default; /// Constructor to automatically derive the template argument. - TreeWidgetBuilder(const ContainerT&) + TreeWidgetBuilder(const ElementT&) {} TreeWidgetBuilder(CompareFn compareFn, MakeItemFn makeItemFn, UpdateItemFn updateItemFn = NoUpdate) : compareFn(compareFn), makeItemFn(makeItemFn), updateItemFn(updateItemFn) {} - TreeWidgetBuilder(NameFn nameFn, MakeItemFn makeItemFn, UpdateItemFn updateItemFn = NoUpdate) : - compareFn(MakeCompareNameFn(nameFn)), makeItemFn(makeItemFn), updateItemFn(updateItemFn) + TreeWidgetBuilder(NameFn nameFn, MakeItemFn makeItemFn, UpdateItemFn updateItemFn = NoUpdate, + int nameColumn = 0) : + compareFn(MakeCompareNameFn(nameFn, nameColumn)), makeItemFn(makeItemFn), updateItemFn(updateItemFn) {} @@ -45,9 +46,9 @@ namespace armarx { this->compareFn = compareFn; } - void setNameFn(NameFn nameFn) + void setNameFn(NameFn nameFn, int nameColumn = 0) { - compareFn = MakeCompareNameFn(nameFn); + compareFn = MakeCompareNameFn(nameFn, nameColumn); } void setMakeItemFn(MakeItemFn makeItemFn) { @@ -64,8 +65,31 @@ namespace armarx } - template <class ParentT> - void updateTree(ParentT* parent, const ContainerT& elements); + /** + * @brief Update the tree according to the elements iterated over by `iteratorFn`. + * + * @param parent + * The parent, i.e. the tree widget or a tree widget item. + * @param iteratorFn + * Function taking a function `bool fn(const ElementT& element)` + * and calling it for each element in the underlying container, i.e. like: + * void iteratorFn(bool (*elementFn)(const ElementT& element)); + */ + template <class ParentT, class IteratorFn> + void updateTreeWithIterator(ParentT* parent, IteratorFn&& iteratorFn); + + /** + * @brief Update the tree with the iterable container. + * + * @param parent + * The parent, i.e. the tree widget or a tree widget item. + * @param iteratorFn + * Function taking a function `bool fn(const ElementT& element)` + * and calling it for each element in the underlying container, i.e. like: + * void iteratorFn(bool (*elementFn)(const ElementT& element)); + */ + template <class ParentT, class ContainerT> + void updateTreeWithContainer(ParentT* parent, const ContainerT& elements); /// No update function (default). @@ -76,7 +100,7 @@ namespace armarx } /// Uses the name for comparison. - static CompareFn MakeCompareNameFn(NameFn nameFn); + static CompareFn MakeCompareNameFn(NameFn nameFn, int nameColumn); private: @@ -100,7 +124,7 @@ namespace armarx struct MapTreeWidgetBuilder { using MapT = std::map<KeyT, ValueT>; - using Base = TreeWidgetBuilder<MapT>; + using Base = TreeWidgetBuilder<typename MapT::value_type>; using ElementT = typename Base::ElementT; using CompareFn = std::function<int(const ElementT& element, QTreeWidgetItem* item)>; @@ -170,7 +194,7 @@ namespace armarx template <class ParentT> void updateTree(ParentT* tree, const MapT& elements) { - builder.updateTree(tree, elements); + builder.updateTreeWithContainer(tree, elements); } @@ -200,7 +224,7 @@ namespace armarx private: - TreeWidgetBuilder<MapT> builder; + TreeWidgetBuilder<typename MapT::value_type> builder; }; @@ -273,30 +297,52 @@ namespace armarx } - template <class ContainerT> - auto TreeWidgetBuilder<ContainerT>::MakeCompareNameFn(NameFn nameFn) -> CompareFn + template <class ElementT> + auto TreeWidgetBuilder<ElementT>::MakeCompareNameFn(NameFn nameFn, int nameColumn) -> CompareFn { - return [nameFn](const ElementT & element, QTreeWidgetItem * item) + return [nameFn, nameColumn](const ElementT & element, QTreeWidgetItem * item) { - return detail::compare(nameFn(element), item->text(0).toStdString()); + return detail::compare(nameFn(element), item->text(nameColumn).toStdString()); }; } - template <class ContainerT> - template <typename ParentT> - void TreeWidgetBuilder<ContainerT>::updateTree(ParentT* parent, const ContainerT& elements) + template <class ElementT> + template <class ParentT, class ContainerT> + void TreeWidgetBuilder<ElementT>::updateTreeWithContainer(ParentT* parent, const ContainerT& elements) + { + this->updateTreeWithIterator(parent, [&elements](auto&& elementFn) + { + for (const auto& element : elements) + { + if (not elementFn(element)) + { + break; + } + } + }); + } + + + template <class ElementT> + template <class ParentT, class IteratorFn> + void TreeWidgetBuilder<ElementT>::updateTreeWithIterator(ParentT* parent, IteratorFn&& iteratorFn) { using api = detail::ParentAPI<ParentT>; + ARMARX_CHECK_NOT_NULL(makeItemFn) << "makeItemFn must be set"; + ARMARX_CHECK_NOT_NULL(updateItemFn) << "updateItemFn must be set"; + ARMARX_CHECK_NOT_NULL(compareFn) << "compareFn must be set"; + int currentIndex = 0; - for (const auto& element : elements) + iteratorFn([this, &parent, ¤tIndex](const auto & element) { bool inserted = false; QTreeWidgetItem* item = nullptr; if (currentIndex >= api::getItemCount(parent)) { // Add elements to the end of the list. + ARMARX_CHECK_NOT_NULL(makeItemFn); item = makeItemFn(element); api::insertItem(parent, api::getItemCount(parent), item); ++currentIndex; @@ -331,11 +377,8 @@ namespace armarx { item->setExpanded(true); } - if (!cont) - { - break; - } - } + return cont; + }); // Remove superfluous items. (currentIndex must point behind the last item) while (api::getItemCount(parent) > currentIndex) { diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceView.h b/source/RobotAPI/libraries/armem_gui/instance/InstanceView.h index 26f9d3be5fccfdce4fdb17a9ddbe430c2f334433..c331f2b450990614733819a7df47e61e8e20fb60 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/InstanceView.h +++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceView.h @@ -7,7 +7,7 @@ #include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> class QGroupBox; diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceViewList.h b/source/RobotAPI/libraries/armem_gui/instance/InstanceViewList.h index 5f937f419cd3111daf1146a6640e0ea9348f6d42..8dc24e0dcd9759f3ab89e21e33ff600ad253f082 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/InstanceViewList.h +++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceViewList.h @@ -6,7 +6,7 @@ #include <RobotAPI/libraries/aron/aroncore/navigators/typenavigator/AronObjectTypeNavigator.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> class QGroupBox; diff --git a/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp b/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp index b8f568c79cdd1d84fa803df9ffaee737e24c9ea2..ebb4473bb1941a713526d646b37744f5a3314c1c 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp @@ -33,7 +33,11 @@ namespace armarx::armem::gui::instance // Timestamp in human-readable format if (id.hasTimestamp()) { - child(4)->setText(valueColumn, QString::fromStdString(toDateTimeMilliSeconds(id.timestamp))); + static const char* mu = "\u03BC"; + std::stringstream ss; + ss << toDateTimeMilliSeconds(id.timestamp) + << " (" << id.timestamp.toMicroSeconds() << " " << mu << "s)"; + child(4)->setText(valueColumn, QString::fromStdString(ss.str())); } } diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp index a2811c0bc5a01ef29fbb9cc41d7b5f47118f5a9a..6793fd79513dd7b2ac7a287f4d9934a97e2d7c91 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp @@ -22,7 +22,7 @@ namespace armarx::armem::gui::instance return true; }); - builder.updateTree(parent, data->getAllKeys()); + builder.updateTreeWithContainer(parent, data->getAllKeys()); } void DataTreeBuilder::updateTree(QTreeWidgetItem* parent, const aron::datanavigator::ListNavigatorPtr& data) @@ -36,7 +36,7 @@ namespace armarx::armem::gui::instance return true; }); - builder.updateTree(parent, getIndex(children.size())); + builder.updateTreeWithContainer(parent, getIndex(children.size())); } diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilderBase.h b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilderBase.h index b26a422ea71c90c2b769217a274eac7887eb8f9d..b225a093d4664d60313b882c1b3de750b48f96e8 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilderBase.h +++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilderBase.h @@ -28,8 +28,8 @@ namespace armarx::armem::gui::instance protected: - using DictBuilder = armarx::TreeWidgetBuilder<std::vector<std::string>>; - using ListBuilder = armarx::TreeWidgetBuilder<std::vector<size_t>>; + using DictBuilder = armarx::TreeWidgetBuilder<std::string>; + using ListBuilder = armarx::TreeWidgetBuilder<size_t>; DictBuilder getDictBuilder() const; ListBuilder getListBuilder() const; diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp index 56d204abf42573540c363c0973f4bf10db357317..4673f22f68c40dc54a8048291db623c79a82442a 100644 --- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp +++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp @@ -40,7 +40,7 @@ namespace armarx::armem::gui::instance return true; }); - builder.updateTree(parent, data.getAllKeys()); + builder.updateTreeWithContainer(parent, data.getAllKeys()); } } @@ -76,7 +76,7 @@ namespace armarx::armem::gui::instance return true; }); - builder.updateTree(parent, type.getAllKeys()); + builder.updateTreeWithContainer(parent, type.getAllKeys()); } @@ -100,7 +100,7 @@ namespace armarx::armem::gui::instance return true; }); - builder.updateTree(parent, getIndex(children.size())); + builder.updateTreeWithContainer(parent, getIndex(children.size())); } } @@ -126,7 +126,7 @@ namespace armarx::armem::gui::instance return true; }); - builder.updateTree(parent, getIndex(data.childrenSize())); + builder.updateTreeWithContainer(parent, getIndex(data.childrenSize())); } @@ -150,7 +150,7 @@ namespace armarx::armem::gui::instance return true; }); - builder.updateTree(parent, getIndex(type.getAcceptedTypes().size())); + builder.updateTreeWithContainer(parent, getIndex(type.getAcceptedTypes().size())); } diff --git a/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp b/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp index 1d4a2b908eba38fbb4be2d028030598c220aae44..29c137093ac9c75f0c904c6745c72473c205f1ec 100644 --- a/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp @@ -66,13 +66,18 @@ namespace armarx::armem::gui::memory return true; }); + auto nameFn = [](const auto & element) + { + return element.name(); + }; workingmemoryCoreSegmentBuilder.setExpand(true); - workingmemoryCoreSegmentBuilder.setMakeItemFn([this](const std::string & name, const wm::CoreSegment & coreSeg) + workingmemoryCoreSegmentBuilder.setNameFn(nameFn, int(Columns::KEY)); + workingmemoryCoreSegmentBuilder.setMakeItemFn([this](const wm::CoreSegment & coreSeg) { - return makeItem(name, coreSeg); + return makeItem(coreSeg.name(), coreSeg); }); - workingmemoryCoreSegmentBuilder.setUpdateItemFn([this](const std::string&, const wm::CoreSegment & coreSeg, QTreeWidgetItem * coreSegItem) + workingmemoryCoreSegmentBuilder.setUpdateItemFn([this](const wm::CoreSegment & coreSeg, QTreeWidgetItem * coreSegItem) { updateContainerItem(coreSeg, coreSegItem); updateChildren(coreSeg, coreSegItem); @@ -80,11 +85,12 @@ namespace armarx::armem::gui::memory }); workingmemoryProvSegmentBuilder.setExpand(true); - workingmemoryProvSegmentBuilder.setMakeItemFn([this](const std::string & name, const wm::ProviderSegment & provSeg) + workingmemoryProvSegmentBuilder.setNameFn(nameFn, int(Columns::KEY)); + workingmemoryProvSegmentBuilder.setMakeItemFn([this](const wm::ProviderSegment & provSeg) { - return makeItem(name, provSeg); + return makeItem(provSeg.name(), provSeg); }); - workingmemoryProvSegmentBuilder.setUpdateItemFn([this](const std::string&, const wm::ProviderSegment & provSeg, QTreeWidgetItem * provSegItem) + workingmemoryProvSegmentBuilder.setUpdateItemFn([this](const wm::ProviderSegment & provSeg, QTreeWidgetItem * provSegItem) { updateContainerItem(provSeg, provSegItem); updateChildren(provSeg, provSegItem); @@ -92,30 +98,30 @@ namespace armarx::armem::gui::memory }); // entityBuilder.setExpand(true); - workingmemoryEntityBuilder.setMakeItemFn([this](const std::string & name, const wm::Entity & entity) + workingmemoryEntityBuilder.setNameFn(nameFn, int(Columns::KEY)); + workingmemoryEntityBuilder.setMakeItemFn([this](const wm::Entity & entity) { - return makeItem(name, entity); + return makeItem(entity.name(), entity); }); - workingmemoryEntityBuilder.setUpdateItemFn([this](const std::string&, const wm::Entity & entity, QTreeWidgetItem * entityItem) + workingmemoryEntityBuilder.setUpdateItemFn([this](const wm::Entity & entity, QTreeWidgetItem * entityItem) { updateContainerItem(entity, entityItem); updateChildren(entity, entityItem); return true; }); - workingmemorySnapshotBuilder.setMakeItemFn([this](const armem::Time & time, const wm::EntitySnapshot & snapshot) + workingmemorySnapshotBuilder.setMakeItemFn([this](const wm::EntitySnapshot & snapshot) { - QTreeWidgetItem* item = makeItem(toDateTimeMilliSeconds(time), snapshot); + QTreeWidgetItem* item = makeItem(toDateTimeMilliSeconds(snapshot.time()), snapshot); item->setData(int(Columns::KEY), Qt::ItemDataRole::UserRole, QVariant(static_cast<qlonglong>(snapshot.time().toMicroSeconds()))); return item; }); - workingmemorySnapshotBuilder.setCompareFn([](const auto & pair, QTreeWidgetItem * item) + workingmemorySnapshotBuilder.setCompareFn([](const wm::EntitySnapshot & snapshot, QTreeWidgetItem * item) { - const wm::EntitySnapshot& snapshot = pair.second; return armarx::detail::compare(static_cast<qlonglong>(snapshot.time().toMicroSeconds()), item->data(int(Columns::KEY), Qt::ItemDataRole::UserRole).toLongLong()); }); - workingmemorySnapshotBuilder.setUpdateItemFn([this](const armem::Time&, const wm::EntitySnapshot & snapshot, QTreeWidgetItem * snapshotItem) + workingmemorySnapshotBuilder.setUpdateItemFn([this](const wm::EntitySnapshot & snapshot, QTreeWidgetItem * snapshotItem) { updateContainerItem(snapshot, snapshotItem); updateChildren(snapshot, snapshotItem); @@ -183,27 +189,27 @@ namespace armarx::armem::gui::memory _selectedID = id; const std::string levelName = item->data(int(Columns::LEVEL), Qt::UserRole).toString().toStdString(); - if (levelName == wm::Memory().getLevelName()) + if (levelName == wm::Memory::getLevelName()) { emit memorySelected(*_selectedID); } - else if (levelName == wm::CoreSegment().getLevelName()) + else if (levelName == wm::CoreSegment::getLevelName()) { emit coreSegmentSelected(*_selectedID); } - else if (levelName == wm::ProviderSegment().getLevelName()) + else if (levelName == wm::ProviderSegment::getLevelName()) { emit providerSegmentSelected(*_selectedID); } - else if (levelName == wm::Entity().getLevelName()) + else if (levelName == wm::Entity::getLevelName()) { emit entitySelected(*_selectedID); } - else if (levelName == wm::EntitySnapshot().getLevelName()) + else if (levelName == wm::EntitySnapshot::getLevelName()) { emit snapshotSelected(*_selectedID); } - else if (levelName == wm::EntityInstance().getLevelName()) + else if (levelName == wm::EntityInstance::getLevelName()) { emit instanceSelected(*_selectedID); } @@ -213,6 +219,16 @@ namespace armarx::armem::gui::memory emit selectedItemChanged(*_selectedID); } + template <class ContainerT> + static + auto makeIteratorFn(const ContainerT& container) + { + return [&container](auto&& elementFn) + { + container.forEachChild(elementFn); + }; + } + void TreeWidget::updateChildren(const armem::wm::Memory& memory, QTreeWidget* tree) { @@ -227,27 +243,27 @@ namespace armarx::armem::gui::memory void TreeWidget::updateChildren(const armem::wm::Memory& memory, QTreeWidgetItem* memoryItem) { - workingmemoryCoreSegmentBuilder.updateTree(memoryItem, memory.coreSegments()); + workingmemoryCoreSegmentBuilder.updateTreeWithIterator(memoryItem, makeIteratorFn(memory)); } void TreeWidget::updateChildren(const armem::wm::CoreSegment& coreSeg, QTreeWidgetItem* coreSegItem) { - workingmemoryProvSegmentBuilder.updateTree(coreSegItem, coreSeg.providerSegments()); + workingmemoryProvSegmentBuilder.updateTreeWithIterator(coreSegItem, makeIteratorFn(coreSeg)); } void TreeWidget::updateChildren(const armem::wm::ProviderSegment& provSeg, QTreeWidgetItem* provSegItem) { - workingmemoryEntityBuilder.updateTree(provSegItem, provSeg.entities()); + workingmemoryEntityBuilder.updateTreeWithIterator(provSegItem, makeIteratorFn(provSeg)); } void TreeWidget::updateChildren(const armem::wm::Entity& entity, QTreeWidgetItem* entityItem) { - workingmemorySnapshotBuilder.updateTree(entityItem, entity.history()); + workingmemorySnapshotBuilder.updateTreeWithIterator(entityItem, makeIteratorFn(entity)); } void TreeWidget::updateChildren(const armem::wm::EntitySnapshot& snapshot, QTreeWidgetItem* snapshotItem) { - workingmemoryInstanceBuilder.updateTree(snapshotItem, snapshot.instances()); + workingmemoryInstanceBuilder.updateTreeWithIterator(snapshotItem, makeIteratorFn(snapshot)); } void TreeWidget::updateChildren(const armem::wm::EntityInstance& data, QTreeWidgetItem* dataItem) @@ -255,19 +271,25 @@ namespace armarx::armem::gui::memory (void) data, (void) dataItem; } - QTreeWidgetItem* TreeWidget::makeItem(const std::string& key, const armem::base::detail::MemoryItem& memoryItem) + template <class MemoryItemT> + QTreeWidgetItem* TreeWidget::makeItem(const std::string& key, const MemoryItemT& memoryItem) { (void) key; + return makeItem(memoryItem.getKeyString(), MemoryItemT::getLevelName(), memoryItem.id()); + } + + QTreeWidgetItem* TreeWidget::makeItem(const std::string& key, const std::string& levelName, const MemoryID& id) + { QStringList columns; - columns.insert(int(Columns::KEY), QString::fromStdString(memoryItem.getKeyString())); + columns.insert(int(Columns::KEY), QString::fromStdString(key)); columns.insert(int(Columns::SIZE), ""); columns.insert(int(Columns::TYPE), ""); - columns.insert(int(Columns::LEVEL), QString::fromStdString(simox::alg::capitalize_words(memoryItem.getLevelName()))); - columns.insert(int(Columns::ID), QString::fromStdString(memoryItem.id().str())); + columns.insert(int(Columns::LEVEL), QString::fromStdString(simox::alg::capitalize_words(levelName))); + columns.insert(int(Columns::ID), QString::fromStdString(id.str())); QTreeWidgetItem* item = new QTreeWidgetItem(columns); - item->setData(int(Columns::LEVEL), Qt::UserRole, QString::fromStdString(memoryItem.getLevelName())); - item->setData(int(Columns::ID), Qt::UserRole, QString::fromStdString(memoryItem.id().str())); + item->setData(int(Columns::LEVEL), Qt::UserRole, QString::fromStdString(levelName)); + item->setData(int(Columns::ID), Qt::UserRole, QString::fromStdString(id.str())); item->setTextAlignment(int(Columns::SIZE), Qt::AlignRight); return item; } diff --git a/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.h b/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.h index 2bcf0fa1b6135534407044a3ce341b86afeab442..72987cda1ef736a9f8943161cb8756a6e56b2cdc 100644 --- a/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.h +++ b/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.h @@ -4,7 +4,7 @@ #include <QTreeWidget> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h> #include <RobotAPI/libraries/armem_gui/TreeWidgetBuilder.h> @@ -67,7 +67,9 @@ namespace armarx::armem::gui::memory void updateChildren(const armem::wm::EntityInstance& data, QTreeWidgetItem* parent); - QTreeWidgetItem* makeItem(const std::string& key, const armem::base::detail::MemoryItem& container); + template <class MemoryItemT> + QTreeWidgetItem* makeItem(const std::string& key, const MemoryItemT& memoryItem); + QTreeWidgetItem* makeItem(const std::string& key, const std::string& levelName, const MemoryID& id); void updateItemItem(const armem::base::detail::MemoryItem& level, QTreeWidgetItem* item); template <class... T> @@ -77,11 +79,11 @@ namespace armarx::armem::gui::memory private: MapTreeWidgetBuilder<std::string, const wm::Memory*> workingmemoryBuilder; - MapTreeWidgetBuilder<std::string, wm::CoreSegment> workingmemoryCoreSegmentBuilder; - MapTreeWidgetBuilder<std::string, wm::ProviderSegment> workingmemoryProvSegmentBuilder; - MapTreeWidgetBuilder<std::string, wm::Entity> workingmemoryEntityBuilder; - MapTreeWidgetBuilder<armem::Time, wm::EntitySnapshot> workingmemorySnapshotBuilder; - TreeWidgetBuilder<std::vector<wm::EntityInstance>> workingmemoryInstanceBuilder; + TreeWidgetBuilder<wm::CoreSegment> workingmemoryCoreSegmentBuilder; + TreeWidgetBuilder<wm::ProviderSegment> workingmemoryProvSegmentBuilder; + TreeWidgetBuilder<wm::Entity> workingmemoryEntityBuilder; + TreeWidgetBuilder<wm::EntitySnapshot> workingmemorySnapshotBuilder; + TreeWidgetBuilder<wm::EntityInstance> workingmemoryInstanceBuilder; std::optional<MemoryID> _selectedID; /// While this is false, do not handle selection updates. diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp index e41bed15cecbc599c7c97b4266a04e0e9a70e47e..9d5cc9ea6064bb6977892623649518791dcaffec 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp @@ -26,11 +26,23 @@ namespace armarx::armem::gui { targets.push_back(query::data::QueryTarget::LTM); } - if (_DiskMemoryQueryTargetCheckBox->isChecked()) + return targets; + } + + void SnapshotSelectorWidget::localDiskStateChanged() + { + if (_LocalDiskMemoryQueryTargetCheckBox->isChecked()) { - targets.push_back(query::data::QueryTarget::Disk); + _WMQueryTargetCheckBox->setChecked(false); + _LTMQueryTargetCheckBox->setChecked(false); + _WMQueryTargetCheckBox->setEnabled(false); + _LTMQueryTargetCheckBox->setEnabled(false); + } + else + { + _WMQueryTargetCheckBox->setEnabled(true); + _LTMQueryTargetCheckBox->setEnabled(true); } - return targets; } bool SnapshotSelectorWidget::queryTargetContainsLocalDisk() const @@ -59,13 +71,13 @@ namespace armarx::armem::gui // query type select box auto queryTargetLayout = new QHBoxLayout(); _WMQueryTargetCheckBox = new QCheckBox("WM"); - _LTMQueryTargetCheckBox = new QCheckBox("LTM (MongoDB)"); - _DiskMemoryQueryTargetCheckBox = new QCheckBox("LTM (Disk)"); + _LTMQueryTargetCheckBox = new QCheckBox("LTM"); _LocalDiskMemoryQueryTargetCheckBox = new QCheckBox("Local Disk"); + connect(_LocalDiskMemoryQueryTargetCheckBox, &QCheckBox::stateChanged, this, &This::localDiskStateChanged); + queryTargetLayout->addWidget(_WMQueryTargetCheckBox); queryTargetLayout->addWidget(_LTMQueryTargetCheckBox); - queryTargetLayout->addWidget(_DiskMemoryQueryTargetCheckBox); queryTargetLayout->addWidget(_LocalDiskMemoryQueryTargetCheckBox); _WMQueryTargetCheckBox->setChecked(true); diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h index 6f6422c3cdbc7fd0e1899bce47efbaaa32589062..a0b69eb1b6f362e64880ab400c0bea29bcdc73fc 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h @@ -45,14 +45,13 @@ namespace armarx::armem::gui signals: void queryChanged(); - private slots: //void updateSelector(); void hideAllForms(); void showSelectedFormForQuery(QString selected); - + void localDiskStateChanged(); signals: void queryOutdated(); @@ -68,7 +67,6 @@ namespace armarx::armem::gui QComboBox* _queryComboBox; QCheckBox* _WMQueryTargetCheckBox; QCheckBox* _LTMQueryTargetCheckBox; - QCheckBox* _DiskMemoryQueryTargetCheckBox; QCheckBox* _LocalDiskMemoryQueryTargetCheckBox; /// The forms for the different query types. Hidden when not selected. std::map<QString, SnapshotForm*> _queryForms; diff --git a/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp b/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp index 4f259c7af5a50ff198b139084eb604bfd06fead5..303a319bcd30566b8000e1d10cc6ab3ef812093d 100644 --- a/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp +++ b/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp @@ -44,13 +44,13 @@ BOOST_AUTO_TEST_CASE(test_sanitizeTypeName) BOOST_CHECK_EQUAL(sanitizeTypeName(dict.getName()), "Dict<Float>"); } { - ListNavigator dict; - dict.setAcceptedType(std::make_shared<LongNavigator>()); - BOOST_CHECK_EQUAL(sanitizeTypeName(dict.getName()), "Dict<Long>"); + ListNavigator list; + list.setAcceptedType(std::make_shared<LongNavigator>()); + BOOST_CHECK_EQUAL(sanitizeTypeName(list.getName()), "List<Long>"); } { - ObjectNavigator dict; - dict.setObjectName("namespace::MyObjectName"); - BOOST_CHECK_EQUAL(sanitizeTypeName(dict.getName()), "namespace::MyObjectName"); + ObjectNavigator obj; + obj.setObjectName("namespace::MyObjectName"); + BOOST_CHECK_EQUAL(sanitizeTypeName(obj.getName()), "MyObjectName (namespace)"); } } diff --git a/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.cpp b/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.cpp index c9aec94015f490d7c992919b96fdbce33b4f1718..5860b2f48f9659c7ac631e1270425f112a0efcab 100644 --- a/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.cpp +++ b/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.cpp @@ -1,19 +1,26 @@ -// STD / STL -#include <iostream> -#include <fstream> -#include <sstream> - // BaseClass #include "Segment.h" // ArmarX #include "MotionConverter.h" + #include <RobotAPI/libraries/PriorKnowledge/motions/MotionFinder.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> + +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/application/properties/ProxyPropertyDefinition.h> + +// STD / STL +#include <iostream> +#include <fstream> +#include <sstream> + namespace armarx::armem::server::motions::mdb { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : - Base(memoryToIceAdapter, memoryMutex) + Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : + Base(memoryToIceAdapter) { } @@ -72,13 +79,14 @@ namespace armarx::armem::server::motions::mdb instance.metadata().timeSent = IceUtil::Time::now(); instance.metadata().timeArrived = IceUtil::Time::now(); instance.metadata().confidence = 1.0; - instance.setData(op->toAron()); + instance.data() = op->toAron(); } else { ARMARX_WARNING << "Found an invalid path to a motion file: " << pathToInfoJson; } - }IceUtil::Time::now(); + } + IceUtil::Time::now(); loadedMotions += allMotions.size(); } diff --git a/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.h b/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.h index 10dd57dee5f3c7c177a980ac29ed6dc45c845905..f0dc4d726f83895876e23ab3bc52af36895df5b3 100644 --- a/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.h +++ b/source/RobotAPI/libraries/armem_motions/server/MotionDatabase/MDBMotions/Segment.h @@ -5,7 +5,7 @@ #include <string> // BaseClass -#include <RobotAPI/libraries/armem/server/Segment.h> +#include <RobotAPI/libraries/armem/server/segment/Segment.h> // ArmarX #include <RobotAPI/libraries/armem_motions/aron/MDBReference.aron.generated.h> @@ -13,16 +13,16 @@ namespace armarx::armem::server::motions::mdb { - class Segment : public armem::server::wm::ProviderSegmentBase<armarx::armem::mdb::MDBReference> + class Segment : public armem::server::segment::wm::AronTypedProviderSegmentBase<armarx::armem::mdb::MDBReference> { - using Base = armem::server::wm::ProviderSegmentBase<armarx::armem::mdb::MDBReference>; + using Base = armem::server::segment::wm::AronTypedProviderSegmentBase<armarx::armem::mdb::MDBReference>; public: - Segment(armem::server::MemoryToIceAdapter& iceMemory, std::mutex& memoryMutex); + Segment(armem::server::MemoryToIceAdapter& iceMemory); virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") override; virtual void onInit() override; - virtual void onConnect() override; + virtual void onConnect(); private: int loadByMotionFinder(const std::string&); diff --git a/source/RobotAPI/libraries/armem_objects/CMakeLists.txt b/source/RobotAPI/libraries/armem_objects/CMakeLists.txt index 54eb919e1804ce099efe5ade4ea14294a202e0bb..ab26b1f8a38b5e18b16dc49a498c9369d6d918db 100644 --- a/source/RobotAPI/libraries/armem_objects/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_objects/CMakeLists.txt @@ -16,6 +16,7 @@ armarx_add_library( RobotAPI::Core RobotAPI::armem RobotAPI::armem_robot + HEADERS aron_conversions.h aron_forward_declarations.h @@ -32,11 +33,6 @@ armarx_add_library( server/instance/Visu.h server/instance/ArticulatedObjectVisu.h - # server/articulated_object_class/Segment.h - # server/articulated_object_instance/Segment.h - # server/articulated_object/SegmentAdapter.h - # server/articulated_object_instance/Visu.h - server/attachments/Segment.h client/articulated_object/Reader.h @@ -64,12 +60,6 @@ armarx_add_library( server/instance/Visu.cpp server/instance/ArticulatedObjectVisu.cpp - server/articulated_object_class/Segment.cpp - - # server/articulated_object_instance/Segment.cpp - # server/articulated_object/SegmentAdapter.cpp - # server/articulated_object_instance/Visu.cpp - server/attachments/Segment.cpp client/articulated_object/Reader.cpp diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp index c973cf24801967244589677f9b044be099f5c306..976d5bf9abb8a7d7586a0501568e6c8240c1e45c 100644 --- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp +++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp @@ -16,7 +16,7 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/core/Time.h> #include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/workingmemory/CoreSegment.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> diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp index d0bfb35708104712d2bebc33b4d7676b999ddac5..27d1cd851dd4500a2d3c6373a2b7c1cd2c5eb3e5 100644 --- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp +++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Reader.cpp @@ -13,7 +13,7 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/core/Time.h> #include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/workingmemory/CoreSegment.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> @@ -242,32 +242,19 @@ namespace armarx::armem::articulated_object .getCoreSegment(properties.coreInstanceSegmentName); // clang-format on - for (const auto& [_, providerSegment] : coreSegment.providerSegments()) + std::optional<wm::EntityInstance> instance; + coreSegment.forEachInstance([&instance](const wm::EntityInstance & i) { - - const auto entities = simox::alg::get_values(providerSegment.entities()); - - if (entities.empty()) - { - ARMARX_WARNING << "No entity found"; - continue; - } - - const auto entitySnapshots = simox::alg::get_values(entities.front().history()); - - if (entitySnapshots.empty()) - { - ARMARX_WARNING << "No entity snapshots found"; - continue; - } - - // TODO(fabian.reister): check if 0 available - const armem::wm::EntityInstance& instance = entitySnapshots.front().getInstance(0); - - return robot::convertRobotState(instance); + instance = i; + }); + if (instance.has_value()) + { + return robot::convertRobotState(instance.value()); + } + else + { + return std::nullopt; } - - return std::nullopt; } @@ -275,67 +262,43 @@ namespace armarx::armem::articulated_object Reader::getRobotDescription(const armarx::armem::wm::Memory& memory) const { // clang-format off - const armem::wm::CoreSegment& coreSegment = memory - .getCoreSegment(properties.coreClassSegmentName); + const armem::wm::CoreSegment& coreSegment = memory.getCoreSegment(properties.coreClassSegmentName); // clang-format on - for (const auto& [_, providerSegment] : coreSegment.providerSegments()) + std::optional<wm::EntityInstance> instance; + coreSegment.forEachInstance([&instance](const wm::EntityInstance & i) { - const auto entities = simox::alg::get_values(providerSegment.entities()); - - if (entities.empty()) - { - ARMARX_WARNING << "No entity found"; - continue; - } - - const auto entitySnapshots = simox::alg::get_values(entities.front().history()); - - if (entitySnapshots.empty()) - { - ARMARX_WARNING << "No entity snapshots found"; - continue; - } - - if (entitySnapshots.front().hasInstance(0)) - { - const armem::wm::EntityInstance& instance = entitySnapshots.front().getInstance(0); - return convertRobotDescription(instance); - } + instance = i; + }); + if (instance.has_value()) + { + return convertRobotDescription(instance.value()); + } + else + { + return std::nullopt; } - - return std::nullopt; } + std::vector<robot::RobotDescription> Reader::getRobotDescriptions(const armarx::armem::wm::Memory& memory) const { - std::vector<robot::RobotDescription> descriptions; - const armem::wm::CoreSegment& coreSegment = memory.getCoreSegment(properties.coreClassSegmentName); - for (const auto& [providerName, providerSegment] : coreSegment.providerSegments()) + std::vector<robot::RobotDescription> descriptions; + coreSegment.forEachEntity([&descriptions](const wm::Entity & entity) { - for (const auto& [name, entity] : providerSegment.entities()) + if (not entity.empty()) { - if (entity.empty()) - { - ARMARX_WARNING << "No entity found"; - continue; - } - - const auto entitySnapshots = simox::alg::get_values(entity.history()); - const armem::wm::EntityInstance& instance = entitySnapshots.front().getInstance(0); - - const auto robotDescription = convertRobotDescription(instance); - + const auto robotDescription = convertRobotDescription(entity.getFirstSnapshot().getInstance(0)); if (robotDescription) { descriptions.push_back(*robotDescription); } } - } + }); return descriptions; } diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/utils.h b/source/RobotAPI/libraries/armem_objects/client/articulated_object/utils.h index 2e51a9e4b336bd4550027227d30a0236efa0f217..9c5b48f39864b16637739b022c0d1908de69c9a5 100644 --- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/utils.h +++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/utils.h @@ -2,7 +2,7 @@ #include <optional> -#include "RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h" +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "RobotAPI/libraries/armem_robot/types.h" #include <RobotAPI/libraries/armem_objects/aron/ObjectClass.aron.generated.h> diff --git a/source/RobotAPI/libraries/armem_objects/client/attachment/Reader.cpp b/source/RobotAPI/libraries/armem_objects/client/attachment/Reader.cpp index f723f30b2eb2d704dcfae73f47e9351cf659b7ad..938ba098681aca145efbeb131af9c7a6a1b6c054 100644 --- a/source/RobotAPI/libraries/armem_objects/client/attachment/Reader.cpp +++ b/source/RobotAPI/libraries/armem_objects/client/attachment/Reader.cpp @@ -9,7 +9,7 @@ #include <RobotAPI/libraries/armem/core/Time.h> #include <RobotAPI/libraries/armem/core/error.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> -#include <RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/util/util.h> #include <RobotAPI/libraries/armem_robot/robot_conversions.h> #include <RobotAPI/libraries/armem_robot/aron_conversions.h> @@ -25,50 +25,42 @@ namespace armarx::armem::attachment namespace { - template<typename AronClass, typename ArmemClass> + template <typename AronClass, typename ArmemClass> auto getAttachments(const armarx::armem::wm::Memory& memory) { // using ArmemClass = decltype(fromAron(AronClass())); using ArmemClassVector = std::vector<ArmemClass>; ArmemClassVector attachments; - - for (const auto&[_, coreSegment] : memory.coreSegments()) + memory.forEachEntity([&attachments](const wm::Entity & entity) { - for (const auto& [providerName, providerSegment] : coreSegment.providerSegments()) + if (entity.empty()) { - for (const auto& [name, entity] : providerSegment.entities()) + ARMARX_WARNING << "No entity snapshot found"; + return true; + } + + const armem::wm::EntityInstance& instance = entity.getFirstSnapshot().getInstance(0); + try + { + AronClass aronAttachment; + aronAttachment.fromAron(instance.data()); + + ArmemClass attachment; + fromAron(aronAttachment, attachment); + + if (attachment.active) { - if (entity.empty()) - { - ARMARX_WARNING << "No entity found"; - continue; - } - - const auto entitySnapshots = simox::alg::get_values(entity.history()); - const armem::wm::EntityInstance& instance = entitySnapshots.front().getInstance(0); - - try - { - AronClass aronAttachment; - aronAttachment.fromAron(instance.data()); - - ArmemClass attachment; - fromAron(aronAttachment, attachment); - - if (attachment.active) - { - attachments.push_back(attachment); - } - - } - catch (const armarx::aron::error::AronException&) - { - continue; - } + attachments.push_back(attachment); } + } - } + catch (const armarx::aron::error::AronException&) + { + return true; + } + return true; + }); return attachments; } @@ -131,7 +123,9 @@ namespace armarx::armem::attachment return {}; } - return getAttachments<::armarx::armem::arondto::attachment::ObjectAttachment, ::armarx::armem::attachment::ObjectAttachment>(qResult.memory); + return getAttachments < + ::armarx::armem::arondto::attachment::ObjectAttachment, + ::armarx::armem::attachment::ObjectAttachment > (qResult.memory); } std::vector<ObjectAttachment> Reader::queryObjectAttachments(const armem::Time& timestamp, const std::string& providerName) const diff --git a/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.cpp deleted file mode 100644 index 425b5af02da13e58f4a654a0784029f5fbe9a9e0..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "Segment.h" - -#include <SimoxUtility/algorithm/get_map_keys_values.h> -#include <sstream> - -#include <ArmarXCore/core/time/TimeUtil.h> -#include "ArmarXCore/core/logging/Logging.h" - -#include "RobotAPI/libraries/aron/common/aron_conversions.h" - -#include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> -#include "RobotAPI/libraries/armem/core/MemoryID.h" -#include <RobotAPI/libraries/armem/client/Writer.h> -#include <RobotAPI/libraries/armem/client/query/Builder.h> -#include <RobotAPI/libraries/armem/client/query/query_fns.h> -#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> - -#include "RobotAPI/libraries/armem_robot/robot_conversions.h" -#include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h> -#include <RobotAPI/libraries/armem_robot/aron_conversions.h> - - -namespace armarx::armem::server::obj::articulated_object_class -{ - - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), - memoryMutex(memoryMutex) - { - Logging::setTag("ArticulatedObjectInstanceSegment"); - } - - Segment::~Segment() = default; - - void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) - { - defs->optional(p.coreClassSegmentName, prefix + "CoreSegmentName", "Name of the object instance core segment."); - defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of object poses history (-1 for infinite)."); - - defs->optional(p.objectsPackage, prefix + "ObjectsPackage", "Name of the objects package to load from."); - defs->optional(p.loadFromObjectsPackage, prefix + "LoadFromObjectsPackage", - "If true, load the objects from the objects package on startup."); - - } - - void Segment::init() - { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreClassSegmentName, arondto::RobotDescription::toAronType()); - coreSegment->setMaxHistorySize(p.maxHistorySize); - - if (p.loadFromObjectsPackage) - { - loadByObjectFinder(p.objectsPackage); - } - } - - void Segment::connect(viz::Client arviz) - { - // this->visu = std::make_unique<Visu>(arviz, *this); - } - - void Segment::loadByObjectFinder(const std::string& package) - { - ObjectFinder finder(package); - - const auto knownArticulatedObjectDescriptions = finder.findAllArticulatedObjectsByDataset(true); - ARMARX_DEBUG << "Found " << knownArticulatedObjectDescriptions.size() << " articulated objects"; - - loadObjectsIntoMemory(knownArticulatedObjectDescriptions, package); - } - - void Segment::loadObjectsIntoMemory(const std::unordered_map<std::string, std::vector<armem::articulated_object::ArticulatedObjectDescription>>& datasets, const std::string& package) - { - const Time now = TimeUtil::GetTime(); - - const MemoryID providerID = coreSegment->id().withProviderSegmentName(package); - coreSegment->addProviderSegment(providerID.providerSegmentName); - - // ARMARX_INFO << "Loading up to " << infos.size() << " object classes from '" - // << objectFinder.getPackageName() << "' ..."; - Commit commit; - - for (const auto& [datasetName, descriptions] : datasets) - { - - for (const armem::articulated_object::ArticulatedObjectDescription& desc : descriptions) - { - EntityUpdate& update = commit.updates.emplace_back(); - update.entityID = providerID.withEntityName(desc.name); - update.timeArrived = update.timeCreated = update.timeSent = now; - - arondto::RobotDescription aronRobotDescription; - toAron(aronRobotDescription, desc); - // TODO toAron(aronRobotDescription.timestamp, now); - - update.instancesData = { aronRobotDescription.toAron()}; - } - - ARMARX_INFO << "Loaded " << commit.updates.size() << " articulated object classes from '" - << package << "' in dataset '" << datasetName << "'."; - } - iceMemory.commit(commit); - } - - - - std::unordered_map<armem::MemoryID, ::armarx::armem::articulated_object::ArticulatedObjectDescription> Segment::getKnownObjectClasses() const - { - std::unordered_map<armem::MemoryID, ::armarx::armem::articulated_object::ArticulatedObjectDescription> objects; - - for (const auto& [_, provSeg] : iceMemory.workingMemory->getCoreSegment(p.coreClassSegmentName)) - { - for (const auto& [name, entity] : provSeg.entities()) - { - for (const auto& snapshot : simox::alg::get_values(entity.history())) - { - const auto& entityInstance = snapshot.getInstance(0); - const auto description = robot::convertRobotDescription(entityInstance); - - if (not description) - { - ARMARX_WARNING << "Could not convert entity instance to 'RobotDescription'"; - continue; - } - - ARMARX_DEBUG << "Key is " << armem::MemoryID(snapshot.id()); - - objects.emplace(armem::MemoryID(snapshot.id()), *description); - } - } - } - - ARMARX_INFO << deactivateSpam(10) << "Number of known articulated object classes: " << objects.size(); - - return objects; - } - - - - // void Segment::RemoteGui::setup(const Segment& data) - // { - // using namespace armarx::RemoteGui::Client; - - // maxHistorySize.setValue(std::max(1, int(data.p.maxHistorySize))); - // maxHistorySize.setRange(1, 1e6); - // infiniteHistory.setValue(data.p.maxHistorySize == -1); - // discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); - - // GridLayout grid; - // int row = 0; - // grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); - // row++; - // grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); - // row++; - // grid.add(Label("Discard Snapshots while Attached"), {row, 0}).add(discardSnapshotsWhileAttached, {row, 1}); - // row++; - - // group.setLabel("Data"); - // group.addChild(grid); - // } - - // void Segment::RemoteGui::update(Segment& data) - // { - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() - // || discardSnapshotsWhileAttached.hasValueChanged()) - // { - // std::scoped_lock lock(data.memoryMutex); - - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) - // { - // data.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); - // if (data.coreSegment) - // { - // data.coreSegment->setMaxHistorySize(long(data.p.maxHistorySize)); - // } - // } - - // data.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); - // } - // } - -} // namespace armarx::armem::server::obj::articulated_object_class diff --git a/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.h b/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.h deleted file mode 100644 index e2a7bbc6fbf2c875e11fb25427f5a7a8809aee4c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 Fabian Reister ( fabian dot reister at kit dot edu ) - * @date 2021 - * @copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ - -#pragma once - -#include <string> -#include <optional> -#include <mutex> -#include <unordered_map> - -#include <ArmarXCore/core/logging/Logging.h> -#include "ArmarXCore/core/application/properties/PropertyDefinitionContainer.h" - -// #include "ArmarXGui/libraries/RemoteGui/Client/Widgets.h" - -#include "RobotAPI/components/ArViz/Client/Client.h" - -#include "RobotAPI/libraries/armem/core/MemoryID.h" -#include "RobotAPI/libraries/armem_objects/types.h" - -#include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h> - -namespace armarx::armem -{ - namespace server - { - class MemoryToIceAdapter; - } - - namespace wm - { - class CoreSegment; - } -} // namespace armarx::armem - - -namespace armarx::armem::server::obj::articulated_object_class -{ - class Visu; - - class Segment : public armarx::Logging - { - public: - Segment(server::MemoryToIceAdapter& iceMemory, - std::mutex& memoryMutex); - - virtual ~Segment(); - - void connect(viz::Client arviz); - - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); - - void init(); - - std::unordered_map<armem::MemoryID, ::armarx::armem::articulated_object::ArticulatedObjectDescription> getKnownObjectClasses() const; - - - private: - void loadByObjectFinder(const std::string& package); - void loadObjectsIntoMemory(const std::unordered_map<std::string, std::vector<armem::articulated_object::ArticulatedObjectDescription>>& datasets, const std::string& package); - - server::MemoryToIceAdapter& iceMemory; - wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; - - struct Properties - { - std::string coreClassSegmentName = "ArticulatedObjectClass"; - int64_t maxHistorySize = -1; - - std::string objectsPackage = ObjectFinder::DefaultObjectsPackageName; - bool loadFromObjectsPackage = true; - }; - Properties p; - - // std::unique_ptr<Visu> visu; - - public: - - // struct RemoteGui - // { - // armarx::RemoteGui::Client::GroupBox group; - - // armarx::RemoteGui::Client::IntSpinBox maxHistorySize; - // armarx::RemoteGui::Client::CheckBox infiniteHistory; - // armarx::RemoteGui::Client::CheckBox discardSnapshotsWhileAttached; - - // void setup(const Segment& data); - // void update(Segment& data); - // }; - - }; - -} // namespace armarx::armem::server::obj::articulated_object_class diff --git a/source/RobotAPI/libraries/armem_objects/server/articulated_object_instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/articulated_object_instance/Segment.cpp deleted file mode 100644 index dba8c91a83e3449fd0dc2a4bdb8ef79632a572e0..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem_objects/server/articulated_object_instance/Segment.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "Segment.h" - -#include <sstream> - -#include <SimoxUtility/algorithm/get_map_keys_values.h> - -#include <ArmarXCore/core/time/TimeUtil.h> -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include <RobotAPI/libraries/core/remoterobot/RemoteRobot.h> - -#include <RobotAPI/libraries/aron/common/aron_conversions.h> - -#include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/client/Writer.h> -#include <RobotAPI/libraries/armem/client/query/Builder.h> -#include <RobotAPI/libraries/armem/client/query/query_fns.h> -#include <RobotAPI/libraries/armem/aron/MemoryID.aron.generated.h> - -#include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h> -#include <RobotAPI/libraries/armem_robot/aron/RobotDescription.aron.generated.h> -#include <RobotAPI/libraries/armem_robot/aron_conversions.h> -#include <RobotAPI/libraries/armem_robot/robot_conversions.h> - -#include <RobotAPI/libraries/armem_objects/server/articulated_object_class/Segment.h> - -#include "Visu.h" - - -namespace armarx::armem::server::obj::articulated_object_instance -{ - - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), - memoryMutex(memoryMutex) - { - Logging::setTag("ArticulatedObjectInstanceSegment"); - } - - Segment::~Segment() = default; - - void Segment::defineProperties(armarx::PropertyDefinitionsPtr& defs, const std::string& prefix) - { - defs->optional(p.coreInstanceSegmentName, prefix + "CoreSegmentName", "Name of the object instance core segment."); - defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of object poses history (-1 for infinite)."); - } - - void Segment::init() - { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreInstanceSegmentName, arondto::Robot::toAronType()); - coreSegment->setMaxHistorySize(p.maxHistorySize); - - } - - void Segment::connect(viz::Client arviz) - { - this->visu = std::make_unique<Visu>(arviz, *this); - visu->init(); - } - - void Segment::setArticulatedObjectClassSegment(const articulated_object_class::Segment& segment) - { - classSegment = &segment; - } - - ::armarx::armem::articulated_object::ArticulatedObjects Segment::getArticulatedObjects() const - { - ARMARX_CHECK_NOT_NULL(classSegment); - const auto knownObjectClasses = classSegment->getKnownObjectClasses(); - - ARMARX_DEBUG << "Class segment has " << knownObjectClasses.size() << " known articulated objects"; - - const auto escape = [](std::string & v) - { - v = simox::alg::replace_all(v, "/", "\\/"); - }; - - const auto resolveDescriptionLink = [&](auto & articulatedObject, const auto & aronDescriptionLink) -> bool - { - armem::MemoryID descriptionLink; - fromAron(aronDescriptionLink, descriptionLink); - - escape(descriptionLink.providerSegmentName); - - ARMARX_DEBUG << "Lookup key is " << descriptionLink; - - // const auto keys = simox::alg::get_keys(knownObjectClasses); - // ARMARX_DEBUG << "Known keys " << keys; - - const auto it = knownObjectClasses.find(descriptionLink); - if (it == knownObjectClasses.end()) - { - ARMARX_WARNING << "Unknown object class " << descriptionLink - << "Known classes are " << simox::alg::get_keys(knownObjectClasses); - return false; - } - - articulatedObject.description = it->second; - return true; - }; - - ::armarx::armem::articulated_object::ArticulatedObjects objects; - for (const auto& [_, provSeg] : iceMemory.workingMemory->getCoreSegment(p.coreInstanceSegmentName)) - { - for (const auto& [_, entity] : provSeg.entities()) - { - const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - - arondto::Robot aronArticulatedObject; - aronArticulatedObject.fromAron(entityInstance.data()); - - armem::articulated_object::ArticulatedObject articulatedObject; - fromAron(aronArticulatedObject, articulatedObject); - - // resolve memory link for description - const arondto::MemoryID& aronDescriptionLink = aronArticulatedObject.description; - if (not resolveDescriptionLink(articulatedObject, aronDescriptionLink)) - { - continue; - } - - objects.push_back(articulatedObject); - } - } - - return objects; - } - - - - // void Segment::RemoteGui::setup(const Segment& data) - // { - // using namespace armarx::RemoteGui::Client; - - // maxHistorySize.setValue(std::max(1, int(data.p.maxHistorySize))); - // maxHistorySize.setRange(1, 1e6); - // infiniteHistory.setValue(data.p.maxHistorySize == -1); - // discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); - - // GridLayout grid; - // int row = 0; - // grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); - // row++; - // grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); - // row++; - // grid.add(Label("Discard Snapshots while Attached"), {row, 0}).add(discardSnapshotsWhileAttached, {row, 1}); - // row++; - - // group.setLabel("Data"); - // group.addChild(grid); - // } - - // void Segment::RemoteGui::update(Segment& data) - // { - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() - // || discardSnapshotsWhileAttached.hasValueChanged()) - // { - // std::scoped_lock lock(data.memoryMutex); - - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) - // { - // data.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); - // if (data.coreSegment) - // { - // data.coreSegment->setMaxHistorySize(long(data.p.maxHistorySize)); - // } - // } - - // data.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); - // } - // } - -} // namespace armarx::armem::server::obj::articulated_object_instance diff --git a/source/RobotAPI/libraries/armem_objects/server/articulated_object_instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/articulated_object_instance/Segment.h deleted file mode 100644 index 2d50be817effddb795e8cd6adf1bda992d177e87..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem_objects/server/articulated_object_instance/Segment.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 Fabian Reister ( fabian dot reister at kit dot edu ) - * @date 2021 - * @copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ - -#pragma once - -#include <cstdint> -#include <map> -#include <string> -#include <optional> -#include <mutex> - -#include "ArmarXCore/core/application/properties/PropertyDefinitionContainer.h" - -#include "ArmarXGui/libraries/RemoteGui/Client/Widgets.h" - -#include <RobotAPI/interface/core/RobotState.h> - -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> - -#include "RobotAPI/components/ArViz/Client/Client.h" - -#include "RobotAPI/libraries/armem_objects/types.h" - - -namespace armarx::armem::server::obj::articulated_object_class -{ - class Segment; -} - -namespace armarx::armem::server::obj::articulated_object_instance -{ - class Visu; - - class Segment : public armarx::Logging - { - public: - - struct CommitStats - { - int numUpdated = 0; - }; - - - Segment(server::MemoryToIceAdapter& iceMemory, - std::mutex& memoryMutex); - - virtual ~Segment(); - - void connect(viz::Client arviz); - - void defineProperties(armarx::PropertyDefinitionsPtr& defs, const std::string& prefix = ""); - - void init(); - - void setArticulatedObjectClassSegment(const articulated_object_class::Segment& segment); - - ::armarx::armem::articulated_object::ArticulatedObjects getArticulatedObjects() const; - - private: - - server::MemoryToIceAdapter& iceMemory; - wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; - - articulated_object_class::Segment const* classSegment; - - - struct Properties - { - std::string coreInstanceSegmentName = "ArticulatedObjectInstance"; - int64_t maxHistorySize = -1; - }; - Properties p; - - std::unique_ptr<Visu> visu; - - public: - - // struct RemoteGui - // { - // armarx::RemoteGui::Client::GroupBox group; - - // armarx::RemoteGui::Client::IntSpinBox maxHistorySize; - // armarx::RemoteGui::Client::CheckBox infiniteHistory; - // armarx::RemoteGui::Client::CheckBox discardSnapshotsWhileAttached; - - // void setup(const Segment& data); - // void update(Segment& data); - // }; - - }; - -} // namespace armarx::armem::server::obj::articulated_object_instance diff --git a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp index f2490c841d0042a133fb1c8cf58740eb2af614cd..2ddcc827d80c0700f59cb5f9ee8638322f4e5633 100644 --- a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp @@ -3,14 +3,15 @@ #include <sstream> #include <ArmarXCore/core/time/TimeUtil.h> -#include "ArmarXCore/core/logging/Logging.h" +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/application/properties/PluginAll.h> -#include "RobotAPI/libraries/armem/util/util.h" -#include "RobotAPI/libraries/aron/common/aron_conversions.h" +#include <RobotAPI/libraries/armem/util/util.h> +#include <RobotAPI/libraries/aron/common/aron_conversions.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> -#include "RobotAPI/libraries/armem/core/MemoryID.h" +#include <RobotAPI/libraries/armem/core/MemoryID.h> #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> @@ -23,9 +24,8 @@ namespace armarx::armem::server::obj::attachments { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), - memoryMutex(memoryMutex) + Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : + iceMemory(memoryToIceAdapter) { Logging::setTag("Attachments"); } @@ -34,7 +34,7 @@ namespace armarx::armem::server::obj::attachments void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { - defs->optional(p.coreClassSegmentName, prefix + "CoreSegmentName", "Name of the object instance core segment."); + defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the object instance core segment."); defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of object poses history (-1 for infinite)."); } @@ -42,85 +42,42 @@ namespace armarx::armem::server::obj::attachments { ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreClassSegmentName, arondto::Robot::toAronType()); + coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName, arondto::Robot::toAronType()); coreSegment->setMaxHistorySize(p.maxHistorySize); } - void Segment::connect(viz::Client arviz) + void Segment::connect() { - // this->visu = std::make_unique<Visu>(arviz, *this); } - std::vector<armarx::armem::attachment::ObjectAttachment> Segment::getAttachments(const armem::Time& timestamp) const + std::vector<armarx::armem::attachment::ObjectAttachment> + Segment::getAttachments(const armem::Time& timestamp) const { - std::vector<armarx::armem::attachment::ObjectAttachment> attachments; + ARMARX_CHECK_NOT_NULL(coreSegment); + std::scoped_lock(coreSegment->mutex()); - for (const auto& [_, provSeg] : iceMemory.workingMemory->getCoreSegment(p.coreClassSegmentName)) + std::vector<armarx::armem::attachment::ObjectAttachment> attachments; + coreSegment->forEachEntity([this, &attachments](const wm::Entity & entity) { - for (const auto& [name, entity] : provSeg.entities()) - { - const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - const auto aronAttachment = tryCast<armarx::armem::arondto::attachment::ObjectAttachment>(entityInstance); + const wm::EntityInstance& entityInstance = entity.getLatestSnapshot().getInstance(0); - if (not aronAttachment) - { - ARMARX_WARNING << "Could not convert entity instance to 'ObjectAttachment'"; - continue; - } + const auto aronAttachment = tryCast<armarx::armem::arondto::attachment::ObjectAttachment>(entityInstance); + if (not aronAttachment) + { + ARMARX_WARNING << "Could not convert entity instance to 'ObjectAttachment'"; + return true; + } - ARMARX_DEBUG << "Key is " << armem::MemoryID(entity.id()); + ARMARX_DEBUG << "Key is " << armem::MemoryID(entity.id()); - armarx::armem::attachment::ObjectAttachment attachment; - fromAron(*aronAttachment, attachment); + armarx::armem::attachment::ObjectAttachment attachment; + fromAron(*aronAttachment, attachment); - attachments.push_back(attachment); - } - } + attachments.push_back(attachment); + return true; + }); return attachments; } - - // void Segment::RemoteGui::setup(const Segment& data) - // { - // using namespace armarx::RemoteGui::Client; - - // maxHistorySize.setValue(std::max(1, int(data.p.maxHistorySize))); - // maxHistorySize.setRange(1, 1e6); - // infiniteHistory.setValue(data.p.maxHistorySize == -1); - // discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); - - // GridLayout grid; - // int row = 0; - // grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); - // row++; - // grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); - // row++; - // grid.add(Label("Discard Snapshots while Attached"), {row, 0}).add(discardSnapshotsWhileAttached, {row, 1}); - // row++; - - // group.setLabel("Data"); - // group.addChild(grid); - // } - - // void Segment::RemoteGui::update(Segment& data) - // { - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() - // || discardSnapshotsWhileAttached.hasValueChanged()) - // { - // std::scoped_lock lock(data.memoryMutex); - - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) - // { - // data.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); - // if (data.coreSegment) - // { - // data.coreSegment->setMaxHistorySize(long(data.p.maxHistorySize)); - // } - // } - - // data.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); - // } - // } - } // namespace armarx::armem::server::obj::attachments diff --git a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.h b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.h index 3817bc22a51227422848ebbe1e4296aa570fee24..4f8cd20ccd9a0ce456bb664f5f5eb8a25f1981e0 100644 --- a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.h +++ b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.h @@ -21,54 +21,31 @@ #pragma once -#include <string> -#include <optional> -#include <mutex> -#include <unordered_map> +#include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem/core/forward_declarations.h> +#include <RobotAPI/libraries/armem/server/forward_declarations.h> +#include <RobotAPI/libraries/armem_objects/types.h> +#include <ArmarXCore/core/application/properties/forward_declarations.h> #include <ArmarXCore/core/logging/Logging.h> -#include "ArmarXCore/core/application/properties/PropertyDefinitionContainer.h" - -// #include "ArmarXGui/libraries/RemoteGui/Client/Widgets.h" - -#include "RobotAPI/components/ArViz/Client/Client.h" -#include "RobotAPI/libraries/armem/core/MemoryID.h" -#include "RobotAPI/libraries/armem/core/Time.h" -#include "RobotAPI/libraries/armem_objects/types.h" - -namespace armarx::armem -{ - namespace server - { - class MemoryToIceAdapter; - } - - namespace wm - { - class CoreSegment; - } -} // namespace armarx::armem +#include <string> namespace armarx::armem::server::obj::attachments { - class Visu; - class Segment : public armarx::Logging { public: - Segment(server::MemoryToIceAdapter& iceMemory, - std::mutex& memoryMutex); + Segment(server::MemoryToIceAdapter& iceMemory); virtual ~Segment(); - void connect(viz::Client arviz); - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); void init(); + void connect(); std::vector<armarx::armem::attachment::ObjectAttachment> getAttachments(const armem::Time& timestamp) const; @@ -77,31 +54,14 @@ namespace armarx::armem::server::obj::attachments server::MemoryToIceAdapter& iceMemory; wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; struct Properties { - std::string coreClassSegmentName = "Attachments"; + std::string coreSegmentName = "Attachments"; int64_t maxHistorySize = -1; }; Properties p; - // std::unique_ptr<Visu> visu; - - public: - - // struct RemoteGui - // { - // armarx::RemoteGui::Client::GroupBox group; - - // armarx::RemoteGui::Client::IntSpinBox maxHistorySize; - // armarx::RemoteGui::Client::CheckBox infiniteHistory; - // armarx::RemoteGui::Client::CheckBox discardSnapshotsWhileAttached; - - // void setup(const Segment& data); - // void update(Segment& data); - // }; - }; } // namespace armarx::armem::server::obj::attachments diff --git a/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.cpp b/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.cpp index 08927d1e77d1963234f42ea9ab861ec9a33f86c4..1e9957aff7b0d093d3bd1d6e16f289d6a2a04afd 100644 --- a/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.cpp @@ -1,6 +1,7 @@ #include "FloorVis.h" -#include <RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> #include <RobotAPI/libraries/armem_objects/aron/ObjectClass.aron.generated.h> #include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> @@ -13,16 +14,19 @@ namespace armarx::armem::server::obj::clazz { } + void FloorVis::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { properties.define(defs, prefix); } + void FloorVis::setArViz(armarx::viz::Client arviz) { this->arviz = arviz; } + void FloorVis::updateFloorObject(const wm::CoreSegment& classCoreSegment) { viz::Layer layer = arviz.layer(properties.layerName); @@ -42,6 +46,7 @@ namespace armarx::armem::server::obj::clazz arviz.commit(layer); } + armarx::viz::Object FloorVis::makeFloorObject(const wm::Entity& classEntity) { const wm::EntityInstance& instance = classEntity.getLatestSnapshot().getInstance(0); @@ -50,6 +55,7 @@ namespace armarx::armem::server::obj::clazz return makeFloorObject(classEntity.name(), data); } + armarx::viz::Object FloorVis::makeFloorObject( const std::string& name, const arondto::ObjectClass& objectClass) @@ -61,7 +67,6 @@ namespace armarx::armem::server::obj::clazz } - void FloorVis::Properties::define(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { defs->optional(show, prefix + "Show", "Whether to show the floor."); diff --git a/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.h b/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.h index dcce63977438bdd0d646b50aa8e5dd9679354df8..49f8a6ddd71f5c24172ddfbbfd8e312dcea2fd3f 100644 --- a/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.h +++ b/source/RobotAPI/libraries/armem_objects/server/class/FloorVis.h @@ -10,7 +10,7 @@ namespace armarx { using PropertyDefinitionsPtr = IceUtil::Handle<class PropertyDefinitionContainer>; } -namespace armarx::armem::wm +namespace armarx::armem::server::wm { class CoreSegment; class Entity; diff --git a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp index 3e6ecfed37e3d75d60b3d509f97520c7627f0fcc..cd10a49c91957e5fa86094597c7903f76fb04c13 100644 --- a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp @@ -3,9 +3,11 @@ #include <RobotAPI/libraries/aron/core/Exception.h> #include <RobotAPI/libraries/aron/common/aron_conversions.h> #include <RobotAPI/libraries/ArmarXObjects/aron_conversions.h> +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem_objects/aron_conversions.h> +#include <RobotAPI/libraries/armem_objects/aron/ObjectClass.aron.generated.h> -#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> #include <ArmarXCore/core/time/TimeUtil.h> #include <SimoxUtility/color/Color.h> @@ -19,17 +21,21 @@ namespace armarx::armem::server::obj::clazz { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), - memoryMutex(memoryMutex) + Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : + SpecializedSegment(memoryToIceAdapter, + arondto::ObjectClass::toAronType(), "Class", -1) { - Logging::setTag("ClassSegment"); } + + Segment::~Segment() + { + } + + void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { - defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the object clazz core segment."); - defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of object poses history (-1 for infinite)."); + SpecializedSegment::defineProperties(defs, prefix); defs->optional(p.objectsPackage, prefix + "ObjectsPackage", "Name of the objects package to load from."); defs->optional(p.loadFromObjectsPackage, prefix + "LoadFromObjectsPackage", @@ -38,12 +44,10 @@ namespace armarx::armem::server::obj::clazz floorVis.defineProperties(defs, prefix + "Floor."); } + void Segment::init() { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName, arondto::ObjectClass::toAronType()); - coreSegment->setMaxHistorySize(p.maxHistorySize); + SpecializedSegment::init(); if (p.loadFromObjectsPackage) { @@ -51,6 +55,7 @@ namespace armarx::armem::server::obj::clazz } } + void Segment::connect(viz::Client arviz) { this->arviz = arviz; @@ -65,12 +70,14 @@ namespace armarx::armem::server::obj::clazz loadByObjectFinder(ObjectFinder(objectsPackage)); } + void Segment::loadByObjectFinder(const ObjectFinder& finder) { this->objectFinder = finder; loadByObjectFinder(); } + void Segment::loadByObjectFinder() { const Time now = TimeUtil::GetTime(); @@ -79,11 +86,6 @@ namespace armarx::armem::server::obj::clazz std::vector<ObjectInfo> infos = objectFinder.findAllObjects(checkPaths); const MemoryID providerID = coreSegment->id().withProviderSegmentName(objectFinder.getPackageName()); - if (not coreSegment->hasProviderSegment(providerID.providerSegmentName)) - { - coreSegment->addProviderSegment(providerID.providerSegmentName); - } - ARMARX_INFO << "Loading up to " << infos.size() << " object classes from '" << objectFinder.getPackageName() << "' ..."; Commit commit; @@ -91,7 +93,7 @@ namespace armarx::armem::server::obj::clazz { info.setLogError(false); - EntityUpdate& update = commit.updates.emplace_back(); + EntityUpdate& update = commit.add(); update.entityID = providerID.withEntityName(info.id().str()); update.timeArrived = update.timeCreated = update.timeSent = now; @@ -103,9 +105,10 @@ namespace armarx::armem::server::obj::clazz } ARMARX_INFO << "Loaded " << commit.updates.size() << " object classes from '" << objectFinder.getPackageName() << "'."; - iceMemory.commit(commit); + iceMemory.commitLocking(commit); } + void Segment::visualizeClass(const MemoryID& entityID, bool showAABB, bool showOOBB) { const Eigen::Matrix4f pose = Eigen::Matrix4f::Identity(); @@ -121,31 +124,32 @@ namespace armarx::armem::server::obj::clazz { try { - const armem::wm::Entity& entity = coreSegment->getEntity(entityID); - const armem::wm::EntityInstance& instance = entity.getLatestSnapshot().getInstance(0); - - arondto::ObjectClass aron; - aron.fromAron(instance.data()); + std::optional<arondto::ObjectClass> aron = + coreSegment->getLatestEntityInstanceDataLockingAs<arondto::ObjectClass>(entityID, 0); + if (not aron.has_value()) + { + return; + } - if (!aron.simoxXmlPath.package.empty()) + if (not aron->simoxXmlPath.package.empty()) { layerObject.add(viz::Object(entityID.str()) - .file(aron.simoxXmlPath.package, aron.simoxXmlPath.path) + .file(aron->simoxXmlPath.package, aron->simoxXmlPath.path) .pose(pose)); } if (showAABB) { layerAABB.add(viz::Box("AABB") - .pose(pose * simox::math::pose(aron.aabb.center)) - .size(aron.aabb.extents) + .pose(pose * simox::math::pose(aron->aabb.center)) + .size(aron->aabb.extents) .color(simox::Color::cyan(255, 64))); } if (showOOBB) { layerOOBB.add(viz::Box("OOBB") - .pose(pose * simox::math::pose(aron.oobb.center, aron.oobb.orientation)) - .size(aron.oobb.extents) + .pose(pose * simox::math::pose(aron->oobb.center, aron->oobb.orientation)) + .size(aron->oobb.extents) .color(simox::Color::lime(255, 64))); } } @@ -164,17 +168,16 @@ namespace armarx::armem::server::obj::clazz arviz.commit(layerObject, layerOrigin, layerAABB, layerOOBB); } + arondto::ObjectClass Segment::objectClassFromInfo(const ObjectInfo& info) { namespace fs = std::filesystem; arondto::ObjectClass data; - toAron(data.id, info.id()); - auto setPathIfExists = []( - armarx::arondto::PackagePath & aron, - const PackageFileLocation & location) + auto setPathIfExists = [](armarx::arondto::PackagePath & aron, + const PackageFileLocation & location) { if (fs::is_regular_file(location.absolutePath)) { @@ -223,21 +226,23 @@ namespace armarx::armem::server::obj::clazz group.addChildren({layout, VSpacer()}); } + void Segment::RemoteGui::update(Segment& segment) { data.update(segment); visu.update(segment); } + void Segment::RemoteGui::Data::setup(const Segment& segment) { using namespace armarx::RemoteGui::Client; reloadButton.setLabel("Reload"); - maxHistorySize.setValue(std::max(1, int(segment.p.maxHistorySize))); + maxHistorySize.setValue(std::max(1, int(segment.properties.maxHistorySize))); maxHistorySize.setRange(1, 1e6); - infiniteHistory.setValue(segment.p.maxHistorySize == -1); + infiniteHistory.setValue(segment.properties.maxHistorySize == -1); GridLayout grid; int row = 0; @@ -253,43 +258,40 @@ namespace armarx::armem::server::obj::clazz group.addChild(grid); } + void Segment::RemoteGui::Data::update(Segment& segment) { if (reloadButton.wasClicked()) { - std::scoped_lock lock(segment.memoryMutex); + // Core segment mutex will be locked on commit. segment.loadByObjectFinder(); rebuild = true; } if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) { - std::scoped_lock lock(segment.memoryMutex); - segment.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); + std::scoped_lock lock(segment.mutex()); + segment.properties.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); if (segment.coreSegment) { - segment.coreSegment->setMaxHistorySize(long(segment.p.maxHistorySize)); + segment.coreSegment->setMaxHistorySize(long(segment.properties.maxHistorySize)); } } } - void Segment::RemoteGui::Visu::setup(const Segment& segment) { using namespace armarx::RemoteGui::Client; showComboBox = {}; showOptionsIndex.clear(); - for (const auto& [_, prov] : *segment.coreSegment) + segment.coreSegment->forEachEntity([this](const wm::Entity & entity) { - for (const auto& [_, entity] : prov) - { - std::stringstream option; - option << entity.id().entityName << " (" << entity.id().providerSegmentName << ")"; - showComboBox.addOption(option.str()); - showOptionsIndex.push_back(entity.id()); - } - } + std::stringstream option; + option << entity.id().entityName << " (" << entity.id().providerSegmentName << ")"; + showComboBox.addOption(option.str()); + showOptionsIndex.push_back(entity.id()); + }); if (showOptionsIndex.empty()) { showComboBox.addOption("<none>"); @@ -308,6 +310,7 @@ namespace armarx::armem::server::obj::clazz group.addChild(grid); } + void Segment::RemoteGui::Visu::update(Segment& segment) { if (showButton.wasClicked()) @@ -315,7 +318,6 @@ namespace armarx::armem::server::obj::clazz const size_t index = static_cast<size_t>(showComboBox.getIndex()); if (/*index >= 0 &&*/ index < showOptionsIndex.size()) { - std::scoped_lock lock(segment.memoryMutex); segment.visualizeClass(showOptionsIndex.at(index)); } } diff --git a/source/RobotAPI/libraries/armem_objects/server/class/Segment.h b/source/RobotAPI/libraries/armem_objects/server/class/Segment.h index 88eaedbefb6529b873dfe6033e6a2857672c0586..3e9717b3e51dc07491e55761664e5cc76add574b 100644 --- a/source/RobotAPI/libraries/armem_objects/server/class/Segment.h +++ b/source/RobotAPI/libraries/armem_objects/server/class/Segment.h @@ -3,36 +3,37 @@ #include <mutex> #include <string> -#include <ArmarXCore/core/logging/Logging.h> -#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> - #include <ArmarXGui/libraries/RemoteGui/Client/Widgets.h> #include <RobotAPI/components/ArViz/Client/Client.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectID.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> -#include <RobotAPI/libraries/armem_objects/aron/ObjectClass.aron.generated.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/segment/SpecializedSegment.h> #include <RobotAPI/libraries/armem_objects/server/class/FloorVis.h> +namespace armarx::armem::arondto +{ + class ObjectClass; +} namespace armarx::armem::server::obj::clazz { - class Segment : public armarx::Logging + class Segment : public segment::SpecializedSegment { public: - Segment(armem::server::MemoryToIceAdapter& iceMemory, - std::mutex& memoryMutex); + Segment(armem::server::MemoryToIceAdapter& iceMemory); + virtual ~Segment() override; - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); - void init(); + void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") override; + void init() override; void connect(viz::Client arviz); + void loadByObjectFinder(const std::string& objectsPackage); void loadByObjectFinder(const ObjectFinder& finder); void loadByObjectFinder(); @@ -45,10 +46,6 @@ namespace armarx::armem::server::obj::clazz private: - armem::server::MemoryToIceAdapter& iceMemory; - armem::wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; - ObjectFinder objectFinder; viz::Client arviz; @@ -57,9 +54,6 @@ namespace armarx::armem::server::obj::clazz struct Properties { - std::string coreSegmentName = "Class"; - long maxHistorySize = -1; - std::string objectsPackage = ObjectFinder::DefaultObjectsPackageName; bool loadFromObjectsPackage = true; }; diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp index db706075c9bd5431fefd2b04b7634cf5e8ff6747..d6d224fe0580e4aa73656515a671ba5753e33326 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp @@ -1,15 +1,16 @@ #include "Segment.h" #include <RobotAPI/libraries/armem_objects/aron/ObjectClass.aron.generated.h> +#include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h> #include <RobotAPI/libraries/armem_objects/aron_conversions.h> #include <RobotAPI/libraries/armem_objects/SceneSnapshot.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> #include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem/util/util.h> #include <RobotAPI/libraries/aron/common/aron_conversions.h> @@ -24,8 +25,9 @@ #include <RobotAPI/libraries/core/FramedPose.h> #include <RobotAPI/libraries/core/remoterobot/RemoteRobot.h> -#include <ArmarXCore/core/time/TimeUtil.h> +#include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/system/cmake/CMakePackageFinder.h> +#include <ArmarXCore/core/time/TimeUtil.h> #include <SimoxUtility/algorithm/get_map_keys_values.h> #include <SimoxUtility/json.h> @@ -42,12 +44,10 @@ namespace armarx::armem::server::obj::instance { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), - memoryMutex(memoryMutex) + Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : + SpecializedSegment(memoryToIceAdapter, + arondto::ObjectInstance::toAronType(), "Instance", 64) { - Logging::setTag("InstanceSegment"); - oobbCache.setFetchFn([this](const ObjectID & id) -> std::optional<simox::OrientedBoxf> { // Try to get OOBB from repository. @@ -79,10 +79,15 @@ namespace armarx::armem::server::obj::instance } + Segment::~Segment() + { + } + + void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { - defs->optional(p.coreSegmentName, prefix + "CoreSegmentName", "Name of the object instance core segment."); - defs->optional(p.maxHistorySize, prefix + "MaxHistorySize", "Maximal size of object poses history (-1 for infinite)."); + SpecializedSegment::defineProperties(defs, prefix); + defs->optional(p.discardSnapshotsWhileAttached, prefix + "DiscardSnapshotsWhileAttached", "If true, no new snapshots are stored while an object is attached to a robot node.\n" "If false, new snapshots are stored, but the attachment is kept in the new snapshots."); @@ -102,11 +107,7 @@ namespace armarx::armem::server::obj::instance void Segment::init() { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreSegmentName, arondto::ObjectInstance::toAronType()); - coreSegment->setMaxHistorySize(p.maxHistorySize); - + SpecializedSegment::init(); if (not p.sceneSnapshotToLoad.empty()) { @@ -115,14 +116,17 @@ namespace armarx::armem::server::obj::instance } } + void Segment::connect(viz::Client arviz) { + (void) arviz; // ARMARX_INFO << "ArticulatedObjectVisu"; // this->visu = std::make_unique<ArticulatedObjectVisu>(arviz, *this); // visu->init(); } + Segment::CommitStats Segment::commitObjectPoses( const std::string& providerName, const objpose::data::ProvidedObjectPoseSeq& providedPoses, @@ -135,11 +139,11 @@ namespace armarx::armem::server::obj::instance stats.numUpdated = 0; for (const objpose::data::ProvidedObjectPose& provided : providedPoses) { - const IceUtil::Time timestamp = IceUtil::Time::microSeconds(provided.timestampMicroSeconds); + const Time timestamp = Time::microSeconds(provided.timestampMicroSeconds); // Check whether we have an old snapshot for this object. std::optional<objpose::ObjectPose> previousPose; - const armem::wm::Entity* entity = findObjectEntity(armarx::fromIce(provided.objectID), providerName); + const wm::Entity* entity = findObjectEntity(armarx::fromIce(provided.objectID), providerName); if (entity) { const arondto::ObjectInstance data = getLatestInstanceData(*entity); @@ -208,9 +212,9 @@ namespace armarx::armem::server::obj::instance void Segment::commitObjectPoses(const ObjectPoseSeq& objectPoses, const std::string& providerName) { - ARMARX_CHECK_NOT_NULL(coreSegment); Time now = TimeUtil::GetTime(); + ARMARX_CHECK_NOT_NULL(coreSegment); const MemoryID coreSegmentID = coreSegment->id(); Commit commit; @@ -241,25 +245,29 @@ namespace armarx::armem::server::obj::instance update.instancesData.push_back(dto.toAron()); } + // Commit non-locking. iceMemory.commit(commit); } - wm::CoreSegment& Segment::getCoreSegment() + wm::CoreSegment& + Segment::getCoreSegment() { ARMARX_CHECK_NOT_NULL(coreSegment); return *coreSegment; } - const wm::CoreSegment& Segment::getCoreSegment() const + const wm::CoreSegment& + Segment::getCoreSegment() const { ARMARX_CHECK_NOT_NULL(coreSegment); return *coreSegment; } - objpose::ObjectPoseMap Segment::getObjectPoses(IceUtil::Time now) + objpose::ObjectPoseMap + Segment::getObjectPoses(IceUtil::Time now) { ObjectPoseMap objectPoses = getLatestObjectPoses(); updateObjectPoses(objectPoses, now); @@ -268,7 +276,8 @@ namespace armarx::armem::server::obj::instance - objpose::ObjectPoseMap Segment::getObjectPosesByProvider( + objpose::ObjectPoseMap + Segment::getObjectPosesByProvider( const std::string& providerName, IceUtil::Time now) { @@ -279,27 +288,31 @@ namespace armarx::armem::server::obj::instance } - armem::wm::Entity* Segment::findObjectEntity(const ObjectID& objectID, const std::string& providerName) + wm::Entity* + Segment::findObjectEntity(const ObjectID& objectID, const std::string& providerName) { ARMARX_CHECK_NOT_NULL(coreSegment); armem::MemoryID entityID = armem::MemoryID().withEntityName(objectID.str()); if (providerName.empty()) { - for (auto& [_, prov] : *coreSegment) + wm::Entity* result = nullptr; + coreSegment->forEachProviderSegment([&result, &entityID](wm::ProviderSegment & prov) { if (prov.hasEntity(entityID.entityName)) { - return &prov.getEntity(entityID); + result = &prov.getEntity(entityID); + return false; } - } - return nullptr; + return true; + }); + return result; } else { entityID.providerSegmentName = providerName; if (coreSegment->hasProviderSegment(providerName)) { - armem::wm::ProviderSegment& prov = coreSegment->getProviderSegment(providerName); + wm::ProviderSegment& prov = coreSegment->getProviderSegment(providerName); return prov.hasEntity(entityID.entityName) ? &prov.getEntity(entityID) : nullptr; } else @@ -382,14 +395,16 @@ namespace armarx::armem::server::obj::instance } - objpose::ObjectPoseMap Segment::getLatestObjectPoses() const + objpose::ObjectPoseMap + Segment::getLatestObjectPoses() const { ARMARX_CHECK_NOT_NULL(coreSegment); return getLatestObjectPoses(*coreSegment); } - objpose::ObjectPoseMap Segment::getLatestObjectPoses(const armem::wm::CoreSegment& coreSeg) + objpose::ObjectPoseMap + Segment::getLatestObjectPoses(const wm::CoreSegment& coreSeg) { ObjectPoseMap result; getLatestObjectPoses(coreSeg, result); @@ -397,7 +412,8 @@ namespace armarx::armem::server::obj::instance } - objpose::ObjectPoseMap Segment::getLatestObjectPoses(const armem::wm::ProviderSegment& provSeg) + objpose::ObjectPoseMap + Segment::getLatestObjectPoses(const wm::ProviderSegment& provSeg) { ObjectPoseMap result; getLatestObjectPoses(provSeg, result); @@ -405,7 +421,8 @@ namespace armarx::armem::server::obj::instance } - objpose::ObjectPose Segment::getLatestObjectPose(const armem::wm::Entity& entity) + objpose::ObjectPose + Segment::getLatestObjectPose(const wm::Entity& entity) { ObjectPose result; getLatestObjectPose(entity, result); @@ -413,18 +430,18 @@ namespace armarx::armem::server::obj::instance } - void Segment::getLatestObjectPoses(const armem::wm::CoreSegment& coreSeg, ObjectPoseMap& out) + void Segment::getLatestObjectPoses(const wm::CoreSegment& coreSeg, ObjectPoseMap& out) { - for (const auto& [_, provSegment] : coreSeg) + coreSeg.forEachProviderSegment([&out](const wm::ProviderSegment & provSegment) { getLatestObjectPoses(provSegment, out); - } + }); } - void Segment::getLatestObjectPoses(const armem::wm::ProviderSegment& provSegment, ObjectPoseMap& out) + void Segment::getLatestObjectPoses(const wm::ProviderSegment& provSegment, ObjectPoseMap& out) { - for (const auto& [_, entity] : provSegment) + provSegment.forEachEntity([&out](const wm::Entity & entity) { if (!entity.empty()) { @@ -440,29 +457,29 @@ namespace armarx::armem::server::obj::instance } } } - } + }); } - void Segment::getLatestObjectPose(const armem::wm::Entity& entity, ObjectPose& out) + void Segment::getLatestObjectPose(const wm::Entity& entity, ObjectPose& out) { - for (const armem::wm::EntityInstance& instance : entity.getLatestSnapshot()) + entity.getLatestSnapshot().forEachInstance([&out](const wm::EntityInstance & instance) { arondto::ObjectInstance dto; dto.fromAron(instance.data()); fromAron(dto, out); - } + }); } - arondto::ObjectInstance Segment::getLatestInstanceData(const armem::wm::Entity& entity) + arondto::ObjectInstance Segment::getLatestInstanceData(const wm::Entity& entity) { ARMARX_CHECK_GREATER_EQUAL(entity.size(), 1); - const armem::wm::EntitySnapshot& snapshot = entity.getLatestSnapshot(); + const wm::EntitySnapshot& snapshot = entity.getLatestSnapshot(); ARMARX_CHECK_EQUAL(snapshot.size(), 1); - const armem::wm::EntityInstance& instance = snapshot.getInstance(0); + const wm::EntityInstance& instance = snapshot.getInstance(0); arondto::ObjectInstance data; data.fromAron(instance.data()); @@ -471,7 +488,8 @@ namespace armarx::armem::server::obj::instance } - ::armarx::armem::articulated_object::ArticulatedObjects Segment::getArticulatedObjects() + ::armarx::armem::articulated_object::ArticulatedObjects + Segment::getArticulatedObjects() { objpose::ObjectPoseMap objectPoses = getObjectPoses(IceUtil::Time::now()); @@ -584,7 +602,7 @@ namespace armarx::armem::server::obj::instance // Find object pose (provider name can be empty). - armem::wm::Entity* objectEntity = this->findObjectEntity(objectID, input.providerName); + wm::Entity* objectEntity = this->findObjectEntity(objectID, input.providerName); if (!objectEntity || objectEntity->empty()) { ARMARX_WARNING << "Tried to attach object " << objectID << " to node '" << frameName @@ -645,7 +663,8 @@ namespace armarx::armem::server::obj::instance } - objpose::DetachObjectFromRobotNodeOutput Segment::detachObjectFromRobotNode( + objpose::DetachObjectFromRobotNodeOutput + Segment::detachObjectFromRobotNode( const objpose::DetachObjectFromRobotNodeInput& input) { const armem::Time now = armem::Time::now(); @@ -657,7 +676,7 @@ namespace armarx::armem::server::obj::instance { // Remove from latest pose (if it was cached). // Find object pose (provider name can be empty). - armem::wm::Entity* entity = this->findObjectEntity(objectID, input.providerName); + wm::Entity* entity = this->findObjectEntity(objectID, input.providerName); if (entity) { const arondto::ObjectInstance data = getLatestInstanceData(*entity); @@ -668,7 +687,6 @@ namespace armarx::armem::server::obj::instance // Store non-attached pose in new snapshot. storeDetachedSnapshot(*entity, data, now, input.commitAttachedPose); } - if (providerName.empty()) { providerName = data.pose.providerName; @@ -693,48 +711,26 @@ namespace armarx::armem::server::obj::instance } - struct DetachVisitor : public armem::wm::Visitor - { - Segment& owner; - armem::Time now; - bool commitAttachedPose; - - int numDetached = 0; - - DetachVisitor(Segment& owner, armem::Time now, bool commitAttachedPose) : - owner(owner), now(now), commitAttachedPose(commitAttachedPose) - { - } - - virtual bool visitEnter(armem::wm::Entity& entity) override; - }; - - - bool DetachVisitor::visitEnter(armem::wm::Entity& entity) - { - const arondto::ObjectInstance data = owner.getLatestInstanceData(entity); - if (data.pose.attachmentValid) - { - numDetached++; - // Store non-attached pose in new snapshot. - owner.storeDetachedSnapshot(entity, data, now, commitAttachedPose); - } - return false; // Stop descending. - } - - - objpose::DetachAllObjectsFromRobotNodesOutput Segment::detachAllObjectsFromRobotNodes( + objpose::DetachAllObjectsFromRobotNodesOutput + Segment::detachAllObjectsFromRobotNodes( const objpose::DetachAllObjectsFromRobotNodesInput& input) { ARMARX_CHECK_NOT_NULL(coreSegment); const armem::Time now = armem::Time::now(); - DetachVisitor visitor(*this, now, input.commitAttachedPose); - visitor.applyTo(*coreSegment); - objpose::DetachAllObjectsFromRobotNodesOutput output; - output.numDetached = visitor.numDetached; + output.numDetached = 0; + coreSegment->forEachEntity([this, now, &input, &output](wm::Entity & entity) + { + const arondto::ObjectInstance data = this->getLatestInstanceData(entity); + if (data.pose.attachmentValid) + { + ++output.numDetached; + // Store non-attached pose in new snapshot. + this->storeDetachedSnapshot(entity, data, now, input.commitAttachedPose); + } + }); ARMARX_INFO << "Detached all objects (" << output.numDetached << ") from robot nodes."; @@ -743,9 +739,9 @@ namespace armarx::armem::server::obj::instance void Segment::storeDetachedSnapshot( - armem::wm::Entity& entity, + wm::Entity& entity, const arondto::ObjectInstance& data, - armem::Time now, + Time now, bool commitAttachedPose) { armem::EntityUpdate update; @@ -777,21 +773,29 @@ namespace armarx::armem::server::obj::instance } - std::optional<wm::EntityInstance> Segment::findClassInstance(const ObjectID& objectID) const + std::optional<wm::EntityInstance> + Segment::findClassInstance(const ObjectID& objectID) const { const ObjectID classID = { objectID.dataset(), objectID.className() }; try { - for (const auto& [_, provSeg] : iceMemory.workingMemory->getCoreSegment("Class")) + std::optional<wm::EntityInstance> result; + iceMemory.workingMemory->getCoreSegment("Class").forEachProviderSegment( + [&classID, &result](const wm::ProviderSegment & provSeg) { if (provSeg.hasEntity(classID.str())) { - return provSeg.getEntity(classID.str()).getLatestSnapshot().getInstance(0); + result = provSeg.getEntity(classID.str()).getLatestSnapshot().getInstance(0); + return false; } - } + return true; + }); - ARMARX_WARNING << "No provider segment for classID " << classID.str() << " found"; - return std::nullopt; + if (not result.has_value()) + { + ARMARX_WARNING << "No provider segment for classID " << classID.str() << " found"; + } + return result; } catch (const armem::error::ArMemError& e) { @@ -820,7 +824,8 @@ namespace armarx::armem::server::obj::instance } - std::optional<armem::obj::SceneSnapshot> Segment::loadScene(const std::string& filename) + std::optional<armem::obj::SceneSnapshot> + Segment::loadScene(const std::string& filename) { if (const std::optional<std::filesystem::path> path = resolveSceneFilename(filename)) { @@ -833,7 +838,8 @@ namespace armarx::armem::server::obj::instance } - std::optional<armem::obj::SceneSnapshot> Segment::loadScene(const std::filesystem::path& path) + std::optional<armem::obj::SceneSnapshot> + Segment::loadScene(const std::filesystem::path& path) { ARMARX_INFO << "Loading scene snapshot from: \n" << path; nlohmann::json j; @@ -855,7 +861,8 @@ namespace armarx::armem::server::obj::instance const std::string Segment::timestampPlaceholder = "%TIMESTAMP"; - std::optional<std::filesystem::path> Segment::resolveSceneFilename(const std::string& _filename) + std::optional<std::filesystem::path> + Segment::resolveSceneFilename(const std::string& _filename) { std::string filename = _filename; @@ -890,9 +897,7 @@ namespace armarx::armem::server::obj::instance armem::obj::SceneSnapshot Segment::getSceneSnapshot() const { armem::obj::SceneSnapshot scene; - - wm::FunctionalVisitor visitor; - visitor.entityFn = [&scene](wm::Entity & entity) + coreSegment->forEachEntity([&scene](wm::Entity & entity) { try { @@ -912,10 +917,8 @@ namespace armarx::armem::server::obj::instance { ARMARX_WARNING_S << e.what(); } - return false; - }; + }); - visitor.applyTo(*coreSegment); return scene; } @@ -973,7 +976,6 @@ namespace armarx::armem::server::obj::instance if (lockMemory) { - std::scoped_lock lock(memoryMutex); commitSceneSnapshot(snapshot.value(), filename.string()); } else @@ -989,9 +991,9 @@ namespace armarx::armem::server::obj::instance { using namespace armarx::RemoteGui::Client; - maxHistorySize.setValue(std::max(1, int(data.p.maxHistorySize))); + maxHistorySize.setValue(std::max(1, int(data.properties.maxHistorySize))); maxHistorySize.setRange(1, 1e6); - infiniteHistory.setValue(data.p.maxHistorySize == -1); + infiniteHistory.setValue(data.properties.maxHistorySize == -1); discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); storeLoadLine.setValue("Scene_" + timestampPlaceholder); @@ -1026,39 +1028,39 @@ namespace armarx::armem::server::obj::instance } - void Segment::RemoteGui::update(Segment& data) + void Segment::RemoteGui::update(Segment& segment) { if (loadButton.wasClicked()) { bool lockMemory = true; - data.commitSceneSnapshotFromFilename(storeLoadLine.getValue(), lockMemory); + segment.commitSceneSnapshotFromFilename(storeLoadLine.getValue(), lockMemory); } if (storeButton.wasClicked()) { armem::obj::SceneSnapshot scene; { - std::scoped_lock lock(data.memoryMutex); - scene = data.getSceneSnapshot(); + std::scoped_lock lock(segment.mutex()); + scene = segment.getSceneSnapshot(); } - data.storeScene(storeLoadLine.getValue(), scene); + segment.storeScene(storeLoadLine.getValue(), scene); } if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() || discardSnapshotsWhileAttached.hasValueChanged()) { - std::scoped_lock lock(data.memoryMutex); + std::scoped_lock lock(segment.mutex()); if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) { - data.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); - if (data.coreSegment) + segment.properties.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); + if (segment.coreSegment) { - data.coreSegment->setMaxHistorySize(long(data.p.maxHistorySize)); + segment.coreSegment->setMaxHistorySize(long(segment.properties.maxHistorySize)); } } - data.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); + segment.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); } } diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h index 3ec6a2f22f41569945cc0c0ed3f5fd0a4021241e..27ffbc746af05451b5fdd54f15a3afc4c7822e08 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h @@ -8,34 +8,35 @@ #include <SimoxUtility/caching/CacheMap.h> #include <SimoxUtility/shapes/OrientedBox.h> -#include <ArmarXCore/core/logging/Logging.h> - -#include "RobotAPI/components/ArViz/Client/Client.h" #include <RobotAPI/interface/core/RobotState.h> #include <RobotAPI/interface/objectpose/ObjectPoseStorageInterface.h> +#include <RobotAPI/components/ArViz/Client/Client.h> + #include <RobotAPI/libraries/ArmarXObjects/ObjectID.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectPose.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> -#include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h> - -#include "Decay.h" +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/segment/SpecializedSegment.h> #include "ArticulatedObjectVisu.h" +#include "Decay.h" namespace armarx::armem::obj { struct SceneSnapshot; } +namespace armarx::armem::arondto +{ + class ObjectInstance; +} namespace armarx::armem::server::obj::instance { - class Segment : public armarx::Logging + class Segment : public segment::SpecializedSegment { public: @@ -50,14 +51,12 @@ namespace armarx::armem::server::obj::instance public: - Segment(server::MemoryToIceAdapter& iceMemory, - std::mutex& memoryMutex); + Segment(server::MemoryToIceAdapter& iceMemory); + virtual ~Segment() override; - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); - - void init(); - + void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "") override; + void init() override; void connect(viz::Client arviz); @@ -179,16 +178,8 @@ namespace armarx::armem::server::obj::instance private: - server::MemoryToIceAdapter& iceMemory; - wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; - - struct Properties { - std::string coreSegmentName = "Instance"; - // -1 would be infinite, but this can let the RAM grow quickly. - long maxHistorySize = 25; bool discardSnapshotsWhileAttached = true; /// Package containing the scene snapshots @@ -209,6 +200,7 @@ namespace armarx::armem::server::obj::instance static const std::string timestampPlaceholder; + public: struct RemoteGui @@ -227,7 +219,9 @@ namespace armarx::armem::server::obj::instance void update(Segment& data); }; + private: + std::unique_ptr<ArticulatedObjectVisu> visu; }; diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp index e0577877f2ac9e9c7e97e8aaa50d99c438fe4c9f..7cd8b1202ac34600f8bfc6ecc912037b49d8bee6 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp @@ -37,17 +37,18 @@ namespace armarx::armem::server::obj::instance { - SegmentAdapter::SegmentAdapter(MemoryToIceAdapter& iceMemory, std::mutex& memoryMutex) : - segment(iceMemory, memoryMutex), - memoryMutex(memoryMutex) + SegmentAdapter::SegmentAdapter(MemoryToIceAdapter& iceMemory) : + segment(iceMemory) { } + std::string SegmentAdapter::getName() const { return Logging::tag.tagName; } + void SegmentAdapter::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { calibration.defineProperties(defs, prefix + "calibration."); @@ -56,6 +57,7 @@ namespace armarx::armem::server::obj::instance visu.defineProperties(defs, prefix + "visu."); } + void SegmentAdapter::init() { segment.setTag(getName()); @@ -66,6 +68,7 @@ namespace armarx::armem::server::obj::instance segment.init(); } + void SegmentAdapter::connect( RobotStateComponentInterfacePrx robotStateComponent, VirtualRobot::RobotPtr robot, @@ -97,6 +100,7 @@ namespace armarx::armem::server::obj::instance segment.connect(arviz); } + void SegmentAdapter::reportProviderAvailable(const std::string& providerName, const objpose::ProviderInfo& info, const Ice::Current&) { updateProviderInfo(providerName, info); @@ -120,7 +124,7 @@ namespace armarx::armem::server::obj::instance return; } { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); std::stringstream ss; for (const auto& id : info.supportedObjects) { @@ -161,7 +165,7 @@ namespace armarx::armem::server::obj::instance } { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); RemoteRobot::synchronizeLocalClone(segment.robot, segment.robotStateComponent); if (segment.robot->hasRobotNode(calibration.robotNode)) @@ -215,7 +219,7 @@ namespace armarx::armem::server::obj::instance TIMING_START(tGetObjectPoses); TIMING_START(tGetObjectPosesLock); - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); TIMING_END_STREAM(tGetObjectPosesLock, ARMARX_VERBOSE); const IceUtil::Time now = TimeUtil::GetTime(); @@ -240,7 +244,7 @@ namespace armarx::armem::server::obj::instance TIMING_START(GetObjectPoses); TIMING_START(GetObjectPosesLock); - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); TIMING_END_STREAM(GetObjectPosesLock, ARMARX_VERBOSE); const IceUtil::Time now = TimeUtil::GetTime(); @@ -292,7 +296,7 @@ namespace armarx::armem::server::obj::instance } else { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); for (const auto& objectID : input.request.objectIDs) { bool found = true; @@ -336,27 +340,31 @@ namespace armarx::armem::server::obj::instance return output; } + objpose::ProviderInfoMap SegmentAdapter::getAvailableProvidersInfo(const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); return segment.providers; } + Ice::StringSeq SegmentAdapter::getAvailableProviderNames(const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); return simox::alg::get_keys(segment.providers); } + objpose::ProviderInfo SegmentAdapter::getProviderInfo(const std::string& providerName, const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); return segment.getProviderInfo(providerName); } + bool SegmentAdapter::hasProvider(const std::string& providerName, const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); return segment.providers.count(providerName) > 0; } @@ -364,28 +372,30 @@ namespace armarx::armem::server::obj::instance objpose::AttachObjectToRobotNodeOutput SegmentAdapter::attachObjectToRobotNode( const objpose::AttachObjectToRobotNodeInput& input, const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); return segment.attachObjectToRobotNode(input); } + objpose::DetachObjectFromRobotNodeOutput SegmentAdapter::detachObjectFromRobotNode( const objpose::DetachObjectFromRobotNodeInput& input, const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); return segment.detachObjectFromRobotNode(input); } + objpose::DetachAllObjectsFromRobotNodesOutput SegmentAdapter::detachAllObjectsFromRobotNodes( const objpose::DetachAllObjectsFromRobotNodesInput& input, const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); return segment.detachAllObjectsFromRobotNodes(input); } objpose::AgentFramesSeq SegmentAdapter::getAttachableFrames(const Ice::Current&) { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); objpose::AgentFramesSeq output; std::vector<VirtualRobot::RobotPtr> agents = { segment.robot }; @@ -398,6 +408,7 @@ namespace armarx::armem::server::obj::instance return output; } + objpose::SignalHeadMovementOutput SegmentAdapter::signalHeadMovement(const objpose::SignalHeadMovementInput& input, const Ice::Current&) { @@ -423,7 +434,7 @@ namespace armarx::armem::server::obj::instance objpose::ObjectPoseMap objectPoses; visu.minConfidence = -1; { - std::scoped_lock lock(memoryMutex); + std::scoped_lock lock(segment.mutex()); const IceUtil::Time now = TimeUtil::GetTime(); @@ -493,6 +504,7 @@ namespace armarx::armem::server::obj::instance group.addChild(layout); } + void SegmentAdapter::RemoteGui::update(SegmentAdapter& adapter) { // Non-atomic variables need to be guarded by a mutex if accessed by multiple threads @@ -502,7 +514,7 @@ namespace armarx::armem::server::obj::instance } this->segment.update(adapter.segment); { - std::scoped_lock lock(adapter.memoryMutex); + std::scoped_lock lock(adapter.segment.mutex()); this->decay.update(adapter.segment.decay); } { diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h index a1e356e53c77608937b0df952798d0427a3cc86b..353f2e0644dc044edfd1f260a76eb0c5d7857a11 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h +++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h @@ -55,7 +55,7 @@ namespace armarx::armem::server::obj::instance { public: - SegmentAdapter(MemoryToIceAdapter& iceMemory, std::mutex& memoryMutex); + SegmentAdapter(MemoryToIceAdapter& iceMemory); std::string getName() const; void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); @@ -127,7 +127,6 @@ namespace armarx::armem::server::obj::instance DebugObserverInterfacePrx debugObserver; instance::Segment segment; - std::mutex& memoryMutex; instance::RobotHeadMovement robotHead; std::mutex robotHeadMutex; diff --git a/source/RobotAPI/libraries/armem_objects/types.h b/source/RobotAPI/libraries/armem_objects/types.h index 976f438e7c39009fd5d37fb6afdf19378da488c4..5ca91ff285e5fc92d1d3523a504379d582dda8b5 100644 --- a/source/RobotAPI/libraries/armem_objects/types.h +++ b/source/RobotAPI/libraries/armem_objects/types.h @@ -21,13 +21,11 @@ #pragma once -#include "RobotAPI/libraries/armem/core/Time.h" -#include <vector> - #include <Eigen/Geometry> -#include <RobotAPI/libraries/armem_robot/types.h> #include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem_robot/types.h> namespace armarx::armem::attachment @@ -97,4 +95,4 @@ namespace armarx::armem::articulated_object using ArticulatedObject = armarx::armem::robot::Robot; using ArticulatedObjects = armarx::armem::robot::Robots; -} // namespace armarx::armem::articulated_object \ No newline at end of file +} // namespace armarx::armem::articulated_object diff --git a/source/RobotAPI/libraries/armem_robot/robot_conversions.cpp b/source/RobotAPI/libraries/armem_robot/robot_conversions.cpp index 3bf4171486e35c33a1cca23a666baac2233a8356..6ba61bba4b70f7a4cbbdf8cb2d18b11e4b50bbd6 100644 --- a/source/RobotAPI/libraries/armem_robot/robot_conversions.cpp +++ b/source/RobotAPI/libraries/armem_robot/robot_conversions.cpp @@ -4,7 +4,7 @@ #include <RobotAPI/libraries/aron/common/aron_conversions.h> -#include "RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h" +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> #include <RobotAPI/libraries/armem_robot/aron/RobotDescription.aron.generated.h> diff --git a/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt b/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt index 498a422fb201bf435cfb8ddbfdc43b71ba1944a0..a2e87f027e868fdc33689eee860577c4083c04d5 100644 --- a/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_robot_state/CMakeLists.txt @@ -6,76 +6,96 @@ armarx_set_target("Library: ${LIB_NAME}") find_package(Eigen3 QUIET) armarx_build_if(Eigen3_FOUND "Eigen3 not available") + armarx_add_library( LIBS # ArmarX ArmarXCore ArmarXCoreInterfaces + DebugObserverHelper + # ArmarXGui ArmarXGuiComponentPlugins # This package RobotAPICore RobotAPIInterfaces RobotAPI::armem RobotAPI::armem_robot + aroncommon + # System / External Eigen3::Eigen - aroncommon + HEADERS - ./common/localization/types.h - ./common/localization/TransformHelper.h + common/localization/types.h + common/localization/TransformHelper.h - ./client/common/RobotReader.h - ./client/common/VirtualRobotReader.h + client/common/RobotReader.h + client/common/VirtualRobotReader.h - ./client/localization/interfaces.h - ./client/localization/TransformReader.h - ./client/localization/TransformWriter.h + client/localization/interfaces.h + client/localization/TransformReader.h + client/localization/TransformWriter.h - ./server/common/Visu.h + server/common/Visu.h - ./server/localization/Segment.h - # ./server/localization/Visu.h + server/localization/Segment.h - ./server/proprioception/Segment.h - # ./server/proprioception/Visu.h + server/proprioception/Segment.h + server/proprioception/aron_conversions.h + server/proprioception/RobotStateWriter.h + server/proprioception/RobotUnitData.h + server/proprioception/RobotUnitReader.h - ./server/description/Segment.h + server/proprioception/converters/Armar6Converter.h + server/proprioception/converters/ConverterTools.h + server/proprioception/converters/ConverterRegistry.h + server/proprioception/converters/ConverterInterface.h + server/description/Segment.h + + aron_conversions.h + utils.h - ./aron_conversions.h - ./utils.h SOURCES - ./common/localization/TransformHelper.cpp + common/localization/TransformHelper.cpp - ./client/common/RobotReader.cpp - ./client/common/VirtualRobotReader.cpp + client/common/RobotReader.cpp + client/common/VirtualRobotReader.cpp - ./client/localization/TransformReader.cpp - ./client/localization/TransformWriter.cpp + client/localization/TransformReader.cpp + client/localization/TransformWriter.cpp - ./server/common/Visu.cpp + server/common/Visu.cpp - ./server/localization/Segment.cpp - # ./server/localization/Visu.cpp + server/localization/Segment.cpp - ./server/proprioception/Segment.cpp - # ./server/proprioception/Visu.cpp + server/proprioception/Segment.cpp + server/proprioception/aron_conversions.cpp + server/proprioception/RobotStateWriter.cpp + server/proprioception/RobotUnitData.cpp + server/proprioception/RobotUnitReader.cpp - ./server/description/Segment.cpp + server/proprioception/converters/Armar6Converter.cpp + server/proprioception/converters/ConverterTools.cpp + server/proprioception/converters/ConverterRegistry.cpp + server/proprioception/converters/ConverterInterface.cpp - ./aron_conversions.cpp - ./utils.cpp + server/description/Segment.cpp + aron_conversions.cpp + utils.cpp ) armarx_enable_aron_file_generation_for_target( TARGET_NAME "${LIB_NAME}" + ARON_FILES + aron/JointState.xml + aron/Proprioception.xml aron/TransformHeader.xml aron/Transform.xml - aron/JointState.xml ) diff --git a/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml new file mode 100644 index 0000000000000000000000000000000000000000..99900b7b0766613a555fb060fa19fddf987def7f --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/aron/Proprioception.xml @@ -0,0 +1,277 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- +(Armar6) Robot proprioception. +--> +<AronTypeDefinition> + <CodeIncludes> + <Include include="<Eigen/Core>" /> + <Include include="<Eigen/Geometry>" /> + </CodeIncludes> + + <GenerateTypes> + + <Object name="armarx::armem::prop::arondto::Joints"> + + <ObjectChild key="position"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="velocity"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="acceleration"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + + <ObjectChild key="relativePosition"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="filteredVelocity"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + + <ObjectChild key="currentTarget"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + <ObjectChild key="positionTarget"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="velocityTarget"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + + <ObjectChild key="torque"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="inertiaTorque"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="gravityTorque"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="gravityCompensatedTorque"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="inverseDynamicsTorque"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="torqueTicks"> + <Dict> + <Int /> + </Dict> + </ObjectChild> + + + <ObjectChild key="orientation"> + <Dict> + <EigenMatrix rows="4" cols="1" type="float" /> + <!--Orientation /--> + </Dict> + </ObjectChild> + + <ObjectChild key="angularVelocity"> + <Dict> + <EigenMatrix rows="3" cols="1" type="float" /> + </Dict> + </ObjectChild> + + <ObjectChild key="linearAcceleration"> + <Dict> + <EigenMatrix rows="3" cols="1" type="float" /> + </Dict> + </ObjectChild> + + + <ObjectChild key="temperature"> + <Dict> + <Dict> + <Float /> + </Dict> + </Dict> + </ObjectChild> + + + <ObjectChild key="motorCurrent"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="maxTargetCurrent"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + + <ObjectChild key="sensorBoardUpdateRate"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="I2CUpdateRate"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + + <ObjectChild key="JointStatusEmergencyStop"> + <Dict> + <Bool /> + </Dict> + </ObjectChild> + + <ObjectChild key="JointStatusEnabled"> + <Dict> + <Bool /> + </Dict> + </ObjectChild> + + <ObjectChild key="JointStatusError"> + <Dict> + <Int /> + </Dict> + </ObjectChild> + + <ObjectChild key="JointStatusOperation"> + <Dict> + <Int /> + </Dict> + </ObjectChild> + + </Object> + + + <Object name="armarx::armem::prop::arondto::Platform"> + + <ObjectChild key="relativePosition"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild> + + <!-- Global pose is not part of proprioception. --> + <!--ObjectChild key="absolutePosition"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild--> + + <ObjectChild key="velocity"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild> + + <ObjectChild key="acceleration"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild> + + <ObjectChild key="extra"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + </Object> + + + <Object name="armarx::armem::prop::arondto::ForceTorque"> + + <ObjectChild key="force"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild> + + <ObjectChild key="torque"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild> + + <ObjectChild key="gravityCompensationForce"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild> + + <ObjectChild key="gravityCompensationTorque"> + <EigenMatrix rows="3" cols="1" type="float" /> + </ObjectChild> + + <ObjectChild key="extra"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + </Object> + + + + <Object name="armarx::armem::arondto::Proprioception"> + + <ObjectChild key="iterationID"> + <long /> + </ObjectChild> + + <ObjectChild key="joints"> + <armarx::armem::prop::arondto::Joints/> + </ObjectChild> + + <ObjectChild key="platform"> + <armarx::armem::prop::arondto::Platform/> + </ObjectChild> + + <ObjectChild key="forceTorque"> + <Dict> + <armarx::armem::prop::arondto::ForceTorque/> + </Dict> + </ObjectChild> + + + <ObjectChild key="extraFloats"> + <Dict> + <Float /> + </Dict> + </ObjectChild> + + <ObjectChild key="extraLongs"> + <Dict> + <Long /> + </Dict> + </ObjectChild> + + </Object> + + + </GenerateTypes> +</AronTypeDefinition> 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 7a500d1391c0f0942795b49af65740f350eecbed..85370141f880a72b26039c0af0c765f929e6a902 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp @@ -10,7 +10,7 @@ #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/workingmemory/CoreSegment.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.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> @@ -214,30 +214,31 @@ namespace armarx::armem::robot_state const armem::wm::ProviderSegment& providerSegment = memory .getCoreSegment(properties.proprioceptionCoreSegment) .getProviderSegment(name); - // clang-format on - const auto entities = simox::alg::get_values(providerSegment.entities()); // TODO entitiesToRobotState() - if (entities.empty()) + if (providerSegment.empty()) { ARMARX_WARNING << "No entity found"; return std::nullopt; } - const auto entitySnapshots = simox::alg::get_values(entities.front().history()); + // clang-format on - if (entitySnapshots.empty()) + const armem::wm::EntityInstance* instance = nullptr; + providerSegment.forEachInstance([&instance](const wm::EntityInstance & i) + { + instance = &i; + return false; // break + }); + if (!instance) { ARMARX_WARNING << "No entity snapshots found"; return std::nullopt; } - // TODO(fabian.reister): check if 0 available - const armem::wm::EntityInstance& instance = entitySnapshots.front().getInstance(0); - // Here, we access the RobotUnit streaming data stored in the proprioception segment. - return robot::convertRobotState(instance); + return robot::convertRobotState(*instance); } // FIXME remove this, use armem/util/util.h @@ -271,24 +272,19 @@ namespace armarx::armem::robot_state .getCoreSegment(properties.proprioceptionCoreSegment); // clang-format on - for (const auto &[_, providerSegment] : coreSegment.providerSegments()) + coreSegment.forEachEntity([&jointMap](const wm::Entity & entity) { + const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - for (const auto &[name, entity] : providerSegment.entities()) + const auto jointState = tryCast<::armarx::armem::arondto::JointState>(entityInstance); + if (not jointState) { - const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - - const auto jointState = tryCast<::armarx::armem::arondto::JointState>(entityInstance); - - if (not jointState) - { - // ARMARX_WARNING << "Could not convert entity instance to 'JointState'"; - continue; - } - - jointMap.emplace(jointState->name, jointState->position); + // ARMARX_WARNING << "Could not convert entity instance to 'JointState'"; + return; } - } + + jointMap.emplace(jointState->name, jointState->position); + }); if (jointMap.empty()) { @@ -307,26 +303,19 @@ namespace armarx::armem::robot_state .getCoreSegment(properties.descriptionCoreSegment) .getProviderSegment(name); // TODO(fabian.reister): all // clang-format on - const auto entities = simox::alg::get_values(providerSegment.entities()); - if (entities.empty()) + const armem::wm::EntityInstance* instance = nullptr; + providerSegment.forEachInstance([&instance](const wm::EntityInstance & i) { - ARMARX_WARNING << "No entity found"; - return std::nullopt; - } - - const auto entitySnapshots = simox::alg::get_values(entities.front().history()); - - if (entitySnapshots.empty()) + instance = &i; + }); + if (!instance) { ARMARX_WARNING << "No entity snapshots found"; return std::nullopt; } - // TODO(fabian.reister): check if 0 available - const armem::wm::EntityInstance& instance = entitySnapshots.front().getInstance(0); - - return robot::convertRobotDescription(instance); + return robot::convertRobotDescription(*instance); } } // namespace armarx::armem::robot_state 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 13b5572d382059bcff17ce2bb5bfb04cc819b04b..b3f71e59ac2b33c19ff97fd0c238f5540503b6ee 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h +++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h @@ -82,7 +82,7 @@ namespace armarx::armem::robot_state struct Properties { - std::string memoryName = "RobotStateMemory"; + std::string memoryName = "RobotState"; std::string descriptionCoreSegment = "Description"; std::string localizationCoreSegment = "Localization"; std::string proprioceptionCoreSegment = "Proprioception"; diff --git a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformReader.cpp b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformReader.cpp index 6aa026431e7d9efd0128a9007d23918b291b54bc..32da2d6450e67eb228e7d8099123842a4b8f84d9 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformReader.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformReader.cpp @@ -48,9 +48,9 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> #include <RobotAPI/libraries/aron/core/navigator/type/NavigatorFactory.h> #include <RobotAPI/libraries/core/FramedPose.h> diff --git a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp index 47660fc439e597f4c8f59bbcff666223c5964e18..608dfa3947153985dc4f528bb0746ab95df706fc 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp @@ -37,9 +37,9 @@ #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> #include <RobotAPI/libraries/aron/core/navigator/type/NavigatorFactory.h> #include <RobotAPI/libraries/core/FramedPose.h> @@ -63,22 +63,21 @@ namespace armarx::armem::client::robot_state::localization { ARMARX_DEBUG << "TransformWriter: registerPropertyDefinitions"; - def->optional(properties.localizationSegment, - propertyPrefix + "localizationSegment", + def->optional(properties.coreSegmentID.memoryName, propertyPrefix + "MemoryName"); + def->optional(properties.coreSegmentID.coreSegmentName, + propertyPrefix + "LocalizationSegmentName", "Name of the localization memory core segment to use."); - - def->optional(properties.memoryName, propertyPrefix + "Memory"); } void TransformWriter::connect() { // Wait for the memory to become available and add it as dependency. - ARMARX_IMPORTANT << "TransformWriter: Waiting for memory '" << properties.memoryName + ARMARX_IMPORTANT << "TransformWriter: Waiting for memory '" << properties.coreSegmentID.memoryName << "' ..."; try { - memoryWriter = memoryNameSystem.useWriter(properties.memoryName); - ARMARX_IMPORTANT << "TransformWriter: Connected to memory '" << properties.memoryName << "'"; + memoryWriter = memoryNameSystem.useWriter(properties.coreSegmentID); + ARMARX_IMPORTANT << "TransformWriter: Connected to memory for '" << properties.coreSegmentID << "'"; } catch (const armem::error::CouldNotResolveMemoryServer& e) { @@ -91,50 +90,19 @@ namespace armarx::armem::client::robot_state::localization { std::lock_guard g{memoryWriterMutex}; - ARMARX_DEBUG << "Trying to create core segment + provider segment"; - - const auto providerId = [&]() -> std::optional<armem::MemoryID> - { - try - { - const auto result = - memoryWriter.addSegment(properties.localizationSegment, transform.header.agent); - - if (not result.success) - { - ARMARX_WARNING << "Could not obtain provider id! Reason: " << result.errorMessage; - return std::nullopt; - } - - return armem::MemoryID(result.segmentID); - } - catch (...) - { - ARMARX_WARNING << "Could not obtain provider id!"; - return std::nullopt; - } - }(); - - if (not providerId) - { - return false; - } - + const MemoryID providerId = properties.coreSegmentID.withProviderSegmentName(transform.header.agent); // const auto& timestamp = transform.header.timestamp; - const auto timestamp = IceUtil::Time::now(); // FIXME remove - - - const auto entityID = providerId->withEntityName(transform.header.parentFrame + "," + - transform.header.frame).withTimestamp(timestamp); + const MemoryID entityID = providerId.withEntityName( + transform.header.parentFrame + "," + transform.header.frame); + const Time timestamp = Time::now(); // FIXME remove armem::EntityUpdate update; - update.entityID = entityID; + update.entityID = entityID; + update.timeCreated = timestamp; arondto::Transform aronTransform; toAron(aronTransform, transform); - update.instancesData = {aronTransform.toAron()}; - update.timeCreated = timestamp; ARMARX_DEBUG << "Committing " << update << " at time " << transform.header.timestamp; armem::EntityUpdateResult updateResult = memoryWriter.commit(update); @@ -149,10 +117,4 @@ namespace armarx::armem::client::robot_state::localization return updateResult.success; } - // const std::string& TransformWriter::getPropertyPrefix() const - // { - // return propertyPrefix; - // } - - } // namespace armarx::armem::client::robot_state::localization diff --git a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.h b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.h index 299c79b69222accb8290a7064229a9dfe59e8572..e553b073464e5fcf1444e14a4fef48e2034e808c 100644 --- a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.h +++ b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.h @@ -61,6 +61,7 @@ namespace armarx::armem::client::robot_state::localization bool commitTransform(const ::armarx::armem::robot_state::Transform& transform) override; + private: armem::client::MemoryNameSystem& memoryNameSystem; @@ -70,8 +71,7 @@ namespace armarx::armem::client::robot_state::localization // Properties struct Properties { - std::string memoryName = "RobotState"; - std::string localizationSegment = "Localization"; + MemoryID coreSegmentID { "RobotState", "Localization" }; } properties; const std::string propertyPrefix = "mem.robot_state."; 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 a59aa5a4c6cdd3ebe552522c0ffd532e873da82a..18b84d7c665c593369b4bd15dd5505d5c5fa88d1 100644 --- a/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.cpp @@ -2,104 +2,119 @@ #include <SimoxUtility/algorithm/get_map_keys_values.h> #include <SimoxUtility/algorithm/string/string_tools.h> -#include <SimoxUtility/color/cmaps.h> #include <SimoxUtility/math/pose/interpolate.h> -#include "ArmarXCore/core/exceptions/LocalException.h" -#include "RobotAPI/libraries/core/FramedPose.h" +#include <ArmarXCore/core/exceptions/LocalException.h> +#include <RobotAPI/libraries/core/FramedPose.h> -#include "RobotAPI/libraries/aron/common/aron_conversions.h" +#include <RobotAPI/libraries/aron/common/aron_conversions.h> -#include "RobotAPI/libraries/armem/core/error/ArMemError.h" -#include "RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h" -#include "RobotAPI/libraries/armem/core/workingmemory/Memory.h" +#include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem/core/error/ArMemError.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> #include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h> #include <RobotAPI/libraries/armem_robot_state/aron_conversions.h> + namespace armarx::armem::common::robot_state::localization { - TransformChainResult TransformHelper::lookupTransformChain(const armem::wm::CoreSegment& localizationCoreSegment, - const TransformQuery& query) + template <class ...Args> + TransformResult + TransformHelper::_lookupTransform( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const TransformQuery& query) { - const std::vector<std::string> tfChain = - buildTransformChain(localizationCoreSegment, query); - + const std::vector<std::string> tfChain = _buildTransformChain(localizationCoreSegment, query); if (tfChain.empty()) { - return {.header = query.header, - .transforms = std::vector<Eigen::Affine3f>{}, - .status = TransformChainResult::Status::ErrorFrameNotAvailable, + return {.transform = {.header = query.header}, + .status = TransformResult::Status::ErrorFrameNotAvailable, .errorMessage = "Cannot create tf lookup chain '" + query.header.parentFrame + " -> " + query.header.frame + "'"}; } - const std::vector<Eigen::Affine3f> transforms = obtainTransforms( + const std::vector<Eigen::Affine3f> transforms = _obtainTransforms( localizationCoreSegment, tfChain, query.header.agent, query.header.timestamp); - if (transforms.empty()) { ARMARX_WARNING << deactivateSpam(1) << "No transform available."; - return {.header = query.header, - .transforms = {}, - .status = TransformChainResult::Status::ErrorFrameNotAvailable, + return {.transform = {.header = query.header}, + .status = TransformResult::Status::ErrorFrameNotAvailable, .errorMessage = "Error in TF loookup: '" + query.header.parentFrame + " -> " + query.header.frame + "'. No memory data in time range."}; } + const Eigen::Affine3f transform = std::accumulate(transforms.begin(), + transforms.end(), + Eigen::Affine3f::Identity(), + std::multiplies<>()); ARMARX_DEBUG << "Found valid transform"; - return {.header = query.header, - .transforms = transforms, - .status = TransformChainResult::Status::Success}; + return {.transform = {.header = query.header, .transform = transform}, + .status = TransformResult::Status::Success}; } - TransformResult TransformHelper::lookupTransform(const armem::wm::CoreSegment& localizationCoreSegment, - const TransformQuery& query) - { - const std::vector<std::string> tfChain = - buildTransformChain(localizationCoreSegment, query); + template <class ...Args> + TransformChainResult + TransformHelper::_lookupTransformChain( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const TransformQuery& query) + { + const std::vector<std::string> tfChain = _buildTransformChain(localizationCoreSegment, query); if (tfChain.empty()) { - return {.transform = {.header = query.header}, - .status = TransformResult::Status::ErrorFrameNotAvailable, - .errorMessage = "Cannot create tf lookup chain '" + - query.header.parentFrame + " -> " + query.header.frame + - "'"}; + return + { + .header = query.header, + .transforms = std::vector<Eigen::Affine3f>{}, + .status = TransformChainResult::Status::ErrorFrameNotAvailable, + .errorMessage = "Cannot create tf lookup chain '" + + query.header.parentFrame + " -> " + query.header.frame + + "'" + }; } - const std::vector<Eigen::Affine3f> transforms = obtainTransforms( + const std::vector<Eigen::Affine3f> transforms = _obtainTransforms( localizationCoreSegment, tfChain, query.header.agent, query.header.timestamp); - if (transforms.empty()) { ARMARX_WARNING << deactivateSpam(1) << "No transform available."; - return {.transform = {.header = query.header}, - .status = TransformResult::Status::ErrorFrameNotAvailable, - .errorMessage = "Error in TF loookup: '" + query.header.parentFrame + - " -> " + query.header.frame + - "'. No memory data in time range."}; + return + { + .header = query.header, + .transforms = {}, + .status = TransformChainResult::Status::ErrorFrameNotAvailable, + .errorMessage = "Error in TF loookup: '" + query.header.parentFrame + + " -> " + query.header.frame + + "'. No memory data in time range." + }; } - const Eigen::Affine3f transform = std::accumulate(transforms.begin(), - transforms.end(), - Eigen::Affine3f::Identity(), - std::multiplies<>()); ARMARX_DEBUG << "Found valid transform"; - return {.transform = {.header = query.header, .transform = transform}, - .status = TransformResult::Status::Success}; + return + { + .header = query.header, + .transforms = transforms, + .status = TransformChainResult::Status::Success + }; } + + + template <class ...Args> std::vector<std::string> - TransformHelper::buildTransformChain(const armem::wm::CoreSegment& localizationCoreSegment, - const TransformQuery& query) + TransformHelper::_buildTransformChain( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const TransformQuery& query) { ARMARX_DEBUG << "Building transform chain"; @@ -123,7 +138,7 @@ namespace armarx::armem::common::robot_state::localization } else { - ARMARX_WARNING << deactivateSpam(1) << "Cannot perform tf lookup '" << parentFrame << " -> " << frame + ARMARX_WARNING << deactivateSpam(10) << "Cannot perform tf lookup '" << parentFrame << " -> " << frame << "'"; } }; @@ -172,8 +187,100 @@ namespace armarx::armem::common::robot_state::localization return chain; } - inline ::armarx::armem::robot_state::Transform - convertEntityToTransform(const armem::wm::EntityInstance& item) + + template <class ...Args> + std::vector<Eigen::Affine3f> + TransformHelper::_obtainTransforms( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const std::vector<std::string>& tfChain, + const std::string& agent, + const armem::Time& timestamp) + { + const auto& agentProviderSegment = localizationCoreSegment.getProviderSegment(agent); + + ARMARX_DEBUG << "Provider segments" << localizationCoreSegment.getProviderSegmentNames(); + ARMARX_DEBUG << "Entities: " << agentProviderSegment.getEntityNames(); + + try + { + std::vector<Eigen::Affine3f> transforms; + transforms.reserve(tfChain.size()); + std::transform(tfChain.begin(), + tfChain.end(), + std::back_inserter(transforms), + [&](const std::string & entityName) + { + return _obtainTransform(entityName, agentProviderSegment, timestamp); + }); + return transforms; + } + catch (const armem::error::MissingEntry& missingEntryError) + { + ARMARX_WARNING << missingEntryError.what(); + } + catch (const ::armarx::exceptions::local::ExpressionException& ex) + { + ARMARX_WARNING << "local exception: " << ex.what(); + } + catch (...) + { + ARMARX_WARNING << "Error: " << GetHandledExceptionString(); + } + + return {}; + } + + + template <class ...Args> + Eigen::Affine3f + TransformHelper::_obtainTransform( + const std::string& entityName, + const armem::base::ProviderSegmentBase<Args...>& agentProviderSegment, + const armem::Time& timestamp) + { + ARMARX_DEBUG << "getEntity:" + entityName; + const auto& entity = agentProviderSegment.getEntity(entityName); + + ARMARX_DEBUG << "History (size: " << entity.size() << "): " << entity.getTimestamps(); + + // if (entity.history.empty()) + // { + // // TODO(fabian.reister): fixme boom + // ARMARX_ERROR << "No snapshots received."; + // return Eigen::Affine3f::Identity(); + // } + + std::vector<::armarx::armem::robot_state::Transform> transforms; + transforms.push_back(_convertEntityToTransform(entity.getLatestSnapshot().getInstance(0))); + + 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(); + const auto p = _interpolateTransform(transforms, timestamp); + ARMARX_DEBUG << "Done interpolating transform"; + return p; + } + + // accept this to fail (will raise armem::error::MissingEntry) + if (transforms.empty()) + { + ARMARX_DEBUG << "empty transform"; + + throw armem::error::MissingEntry("foo", "bar", "foo2", "bar2", 0); + } + + ARMARX_DEBUG << "single transform"; + + return transforms.front().transform; + } + + + ::armarx::armem::robot_state::Transform + TransformHelper::_convertEntityToTransform(const armem::wm::EntityInstance& item) { arondto::Transform aronTransform; aronTransform.fromAron(item.data()); @@ -211,8 +318,9 @@ namespace armarx::armem::common::robot_state::localization } Eigen::Affine3f - interpolateTransform(const std::vector<::armarx::armem::robot_state::Transform>& queue, - armem::Time timestamp) + TransformHelper::_interpolateTransform( + const std::vector<::armarx::armem::robot_state::Transform>& queue, + armem::Time timestamp) { ARMARX_TRACE; @@ -255,109 +363,33 @@ namespace armarx::armem::common::robot_state::localization return simox::math::interpolatePose(posePreIt->transform, poseNextIt->transform, static_cast<float>(t)); } - std::vector<Eigen::Affine3f> - TransformHelper::obtainTransforms(const armem::wm::CoreSegment& localizationCoreSegment, - const std::vector<std::string>& tfChain, - const std::string& agent, - const armem::Time& timestamp) - { - const auto& agentProviderSegment = localizationCoreSegment.getProviderSegment(agent); - - ARMARX_DEBUG << "Provider segments" - << simox::alg::get_keys(localizationCoreSegment.providerSegments()); - - ARMARX_DEBUG << "Entities: " << simox::alg::get_keys(agentProviderSegment.entities()); - - try - { - std::vector<Eigen::Affine3f> transforms; - transforms.reserve(tfChain.size()); - std::transform(tfChain.begin(), - tfChain.end(), - std::back_inserter(transforms), - [&](const std::string & entityName) - { - return obtainTransform( - entityName, agentProviderSegment, timestamp); - }); - return transforms; - } - catch (const armem::error::MissingEntry& missingEntryError) - { - ARMARX_WARNING << missingEntryError.what(); - } - catch (const ::armarx::exceptions::local::ExpressionException& ex) - { - ARMARX_WARNING << "local exception: " << ex.what(); - } - catch (...) - { - ARMARX_WARNING << "Error: " << GetHandledExceptionString(); - } - - - return {}; + TransformResult TransformHelper::lookupTransform( + const armem::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query) + { + return _lookupTransform(localizationCoreSegment, query); } - - Eigen::Affine3f - TransformHelper::obtainTransform(const std::string& entityName, - const armem::wm::ProviderSegment& agentProviderSegment, - const armem::Time& timestamp) + TransformResult TransformHelper::lookupTransform( + const armem::server::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query) { + return _lookupTransform(localizationCoreSegment, query); + } - ARMARX_DEBUG << "getEntity:" + entityName; - const auto& entity = agentProviderSegment.getEntity(entityName); - - ARMARX_DEBUG << "History (size: " << entity.history().size() << ")" - << simox::alg::get_keys(entity.history()); - - // if (entity.history.empty()) - // { - // // TODO(fabian.reister): fixme boom - // ARMARX_ERROR << "No snapshots received."; - // return Eigen::Affine3f::Identity(); - // } - - std::vector<::armarx::armem::robot_state::Transform> transforms; - transforms.reserve(entity.history().size()); - - // const auto entitySnapshots = simox::alg::get_values(entity.history()); - - const std::vector<wm::EntitySnapshot> entitySnapshots = {entity.getLatestSnapshot()}; - - std::transform( - entitySnapshots.begin(), - entitySnapshots.end(), - std::back_inserter(transforms), - [](const auto & entitySnapshot) - { - return convertEntityToTransform(entitySnapshot.getInstance(0)); - }); - - 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(); - const auto p = interpolateTransform(transforms, timestamp); - ARMARX_DEBUG << "Done interpolating transform"; - return p; - } - - // accept this to fail (will raise armem::error::MissingEntry) - if (transforms.empty()) - { - ARMARX_DEBUG << "empty transform"; - throw armem::error::MissingEntry("foo", "bar", "foo2", "bar2", 0); - } + TransformChainResult TransformHelper::lookupTransformChain( + const armem::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query) + { + return _lookupTransformChain(localizationCoreSegment, query); + } + TransformChainResult TransformHelper::lookupTransformChain( + const armem::server::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query) + { + return _lookupTransformChain(localizationCoreSegment, query); + } - ARMARX_DEBUG << "single transform"; - return transforms.front().transform; - } } // namespace armarx::armem::common::robot_state::localization diff --git a/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.h b/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.h index cafbedcbca60f859f6fe158190a5985350ddad65..9de1fbd994f5a17c00987ce70d31525db7d9d1dd 100644 --- a/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.h +++ b/source/RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.h @@ -26,44 +26,102 @@ #include <Eigen/Core> #include <Eigen/Geometry> +#include <RobotAPI/libraries/armem/core/forward_declarations.h> #include <RobotAPI/libraries/armem_robot_state/common/localization/types.h> -namespace armarx::armem::wm -{ - class CoreSegment; - class ProviderSegment; -} // namespace armarx::armem::wm namespace armarx::armem::common::robot_state::localization { using armarx::armem::common::robot_state::localization::TransformQuery; using armarx::armem::common::robot_state::localization::TransformResult; + + class TransformHelper { public: - static TransformResult - lookupTransform(const armem::wm::CoreSegment& localizationCoreSegment, - const TransformQuery& query); - static TransformChainResult - lookupTransformChain(const armem::wm::CoreSegment& localizationCoreSegment, - const TransformQuery& query); + static + TransformResult + lookupTransform( + const armem::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query); + + static + TransformResult + lookupTransform( + const armem::server::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query); + + + static + TransformChainResult + lookupTransformChain( + const armem::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query); + + static + TransformChainResult + lookupTransformChain( + const armem::server::wm::CoreSegment& localizationCoreSegment, + const TransformQuery& query); + private: - static std::vector<std::string> - buildTransformChain(const armem::wm::CoreSegment& localizationCoreSegment, - const TransformQuery& query); - - static std::vector<Eigen::Affine3f> - obtainTransforms(const armem::wm::CoreSegment& localizationCoreSegment, - const std::vector<std::string>& tfChain, - const std::string& agent, - const armem::Time& timestamp); - - static Eigen::Affine3f - obtainTransform(const std::string& entityName, - const armem::wm::ProviderSegment& agentProviderSegment, - const armem::Time& timestamp); + + template <class ...Args> + static + TransformResult + _lookupTransform( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const TransformQuery& query); + + + template <class ...Args> + static + TransformChainResult + _lookupTransformChain( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const TransformQuery& query); + + + template <class ...Args> + static + std::vector<std::string> + _buildTransformChain( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const TransformQuery& query); + + + template <class ...Args> + static + std::vector<Eigen::Affine3f> + _obtainTransforms( + const armem::base::CoreSegmentBase<Args...>& localizationCoreSegment, + const std::vector<std::string>& tfChain, + const std::string& agent, + const armem::Time& timestamp); + + + template <class ...Args> + static + Eigen::Affine3f + _obtainTransform( + const std::string& entityName, + const armem::base::ProviderSegmentBase<Args...>& agentProviderSegment, + const armem::Time& timestamp); + + + static + Eigen::Affine3f + _interpolateTransform( + const std::vector<::armarx::armem::robot_state::Transform>& queue, + armem::Time timestamp); + + static + ::armarx::armem::robot_state::Transform + _convertEntityToTransform( + const armem::wm::EntityInstance& item); + }; -} // namespace armarx::armem::common::robot_state::localization \ No newline at end of file +} // namespace armarx::armem::common::robot_state::localization 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 9762ea0339755892ac79ef62dbfcc88353995b00..d6dcddd7d3fd568216a63657bfe6ae5ca1f10f9c 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp @@ -1,7 +1,8 @@ #include "Visu.h" -#include <Eigen/src/Geometry/Transform.h> #include <algorithm> +#include <exception> +#include <string> #include <Eigen/Geometry> @@ -10,23 +11,29 @@ #include <SimoxUtility/algorithm/get_map_keys_values.h> #include <SimoxUtility/math/pose.h> -#include "ArmarXCore/core/logging/Logging.h" -#include "ArmarXCore/core/time/CycleUtil.h" +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/CycleUtil.h> #include <ArmarXCore/core/time/TimeUtil.h> -#include "RobotAPI/components/ArViz/Client/Elements.h" -#include "RobotAPI/libraries/armem/core/Time.h" +#include <RobotAPI/components/ArViz/Client/Elements.h> +#include <RobotAPI/libraries/armem/core/Time.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h> -#include <exception> -#include <string> #include "../description/Segment.h" #include "../localization/Segment.h" #include "../proprioception/Segment.h" + namespace armarx::armem::server::robot_state { + Visu::Visu(const description::Segment& descriptionSegment, const proprioception::Segment& proprioceptionSegment, const localization::Segment& localizationSegment) + : descriptionSegment(descriptionSegment), + proprioceptionSegment(proprioceptionSegment), + localizationSegment(localizationSegment) + {} + + void Visu::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) { defs->optional( @@ -34,9 +41,31 @@ namespace armarx::armem::server::robot_state defs->optional(p.frequencyHz, prefix + "frequenzyHz", "Frequency of visualization."); } - void Visu::visualizeRobots(viz::Layer& layer, const robot::Robots& robots) + + void Visu::init() { + } + + + void Visu::connect(const viz::Client& arviz, DebugObserverInterfacePrx debugObserver) + { + this->arviz = arviz; + if (debugObserver) + { + bool batchMode = true; + this->debugObserver = DebugObserverHelper("RobotStateMemory", debugObserver, batchMode); + } + + updateTask = new SimpleRunningTask<>([this]() + { + this->visualizeRun(); + }); + updateTask->start(); + } + + void Visu::visualizeRobots(viz::Layer& layer, const robot::Robots& robots) + { const auto visualizeRobot = [&](const robot::Robot & robot) { const auto xmlPath = robot.description.xml.serialize(); @@ -57,6 +86,7 @@ namespace armarx::armem::server::robot_state std::for_each(robots.begin(), robots.end(), visualizeRobot); } + void Visu::visualizeFrames( viz::Layer& layerFrames, const std::unordered_map<std::string, std::vector<Eigen::Affine3f>>& frames) @@ -69,79 +99,13 @@ namespace armarx::armem::server::robot_state for (const auto& frame : robotFrames) { Eigen::Affine3f from = pose; + Eigen::Affine3f to = pose * frame; - pose = pose * frame; // to - - Eigen::Affine3f to = pose; - - const auto arr = viz::Arrow(robotName + std::to_string(++i)).fromTo(from.translation(), to.translation()); - layerFrames.add(arr); + layerFrames.add(viz::Arrow(robotName + std::to_string(++i)).fromTo(from.translation(), to.translation())); } } } - void Visu::init() {} - - void Visu::connect(const viz::Client& arviz) - { - this->arviz = arviz; - - updateTask = new SimpleRunningTask<>([this]() - { - this->visualizeRun(); - }); - updateTask->start(); - } - - // void Visu::RemoteGui::setup(const Visu& visu) - // { - // using namespace armarx::RemoteGui::Client; - - // enabled.setValue(visu.enabled); - // inGlobalFrame.setValue(visu.inGlobalFrame); - // alpha.setRange(0, 1.0); - // alpha.setValue(visu.alpha); - // alphaByConfidence.setValue(visu.alphaByConfidence); - // oobbs.setValue(visu.oobbs); - // objectFrames.setValue(visu.objectFrames); - // { - // float max = 10000; - // objectFramesScale.setRange(0, max); - // objectFramesScale.setDecimals(2); - // objectFramesScale.setSteps(int(10 * max)); - // objectFramesScale.setValue(visu.objectFramesScale); - // } - - // GridLayout grid; - // int row = 0; - // grid.add(Label("Enabled"), {row, 0}).add(enabled, {row, 1}); - // row++; - // grid.add(Label("Global Frame"), {row, 0}).add(inGlobalFrame, {row, 1}); - // row++; - // grid.add(Label("Alpha"), {row, 0}).add(alpha, {row, 1}, {1, 3}); - // row++; - // grid.add(Label("Alpha by Confidence"), {row, 0}).add(alphaByConfidence, {row, 1}); - // row++; - // grid.add(Label("OOBB"), {row, 0}).add(oobbs, {row, 1}); - // row++; - // grid.add(Label("Object Frames"), {row, 0}).add(objectFrames, {row, 1}); - // grid.add(Label("Scale:"), {row, 2}).add(objectFramesScale, {row, 3}); - // row++; - - // group.setLabel("Visualization"); - // group.addChild(grid); - // } - - // void Visu::RemoteGui::update(Visu& visu) - // { - // visu.enabled = enabled.getValue(); - // visu.inGlobalFrame = inGlobalFrame.getValue(); - // visu.alpha = alpha.getValue(); - // visu.alphaByConfidence = alphaByConfidence.getValue(); - // visu.oobbs = oobbs.getValue(); - // visu.objectFrames = objectFrames.getValue(); - // visu.objectFramesScale = objectFramesScale.getValue(); - // } robot::Robots combine( const std::unordered_map<std::string, robot::RobotDescription>& robotDescriptions, @@ -191,34 +155,52 @@ namespace armarx::armem::server::robot_state return robots; } + void Visu::visualizeRun() { - CycleUtil cycle(static_cast<int>(1000 / p.frequencyHz)); while (updateTask && not updateTask->isStopped()) { { // std::scoped_lock lock(visuMutex); ARMARX_DEBUG << "Update task"; - if (p.enabled) { - TIMING_START(Visu); + TIMING_START(tVisuTotal); // TODO(fabian.reister): use timestamp - - const auto timestamp = IceUtil::Time::now(); + const Time timestamp = Time::now(); try { - const auto robotDescriptions = - descriptionSegment.getRobotDescriptions(timestamp); + // 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.getRobotGlobalPoses(timestamp); + 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.getRobotJointPositions(timestamp); + proprioceptionSegment.getRobotJointPositionsLocking( + timestamp, debugObserver ? &*debugObserver : nullptr); + TIMING_END_STREAM(tRobotJointPositionMap, ARMARX_DEBUG); + + TIMING_END_STREAM(tVisuGetData, ARMARX_DEBUG); - const auto frames = localizationSegment.getRobotFramePoses(timestamp); + + // Build layers. + TIMING_START(tVisuBuildLayers); // we need all 3 informations: // - robot description @@ -228,44 +210,55 @@ namespace armarx::armem::server::robot_state const robot::Robots robots = combine(robotDescriptions, globalRobotPoseMap, robotJointPositionMap); - viz::Layer layer = arviz.layer("Robots"); - ARMARX_DEBUG << "visualizing robots"; + ARMARX_DEBUG << "Visualize robots ..."; + viz::Layer layer = arviz.layer("Robots"); visualizeRobots(layer, robots); - ARMARX_DEBUG << "Committing robots"; - + ARMARX_DEBUG << "Visualize frames ..."; viz::Layer layerFrames = arviz.layer("Frames"); - - ARMARX_DEBUG << "visualizing frames"; visualizeFrames(layerFrames, frames); - ARMARX_DEBUG << "Committing frames"; - - arviz.commit({layer, layerFrames}); + TIMING_END_STREAM(tVisuBuildLayers, ARMARX_DEBUG); - ARMARX_DEBUG << "Done committing"; - TIMING_END_STREAM(Visu, ARMARX_VERBOSE); + // Commit layers. - // if (debugObserver) - // { - // debugObserver->setDebugChannel(getName(), - // { - // { "t Visualize [ms]", new Variant(Visu.toMilliSecondsDouble()) }, - // }); - // } + 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 << ex.what(); + ARMARX_WARNING << "Caught exception while visualizing robots: \n" << ex.what(); continue; } catch (...) { - ARMARX_WARNING << "Unknown exception"; + ARMARX_WARNING << "Caught unknown exception while visualizing robots."; continue; } + + if (debugObserver.has_value()) + { + debugObserver->sendDebugObserverBatch(); + } } } cycle.waitForCycleDuration(); 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 7e4b3814ce3a2c03f4ea8fb38846d4378c3a18c6..95efae41963c63669e4e4bb11b202ba9ef948ec9 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.h +++ b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.h @@ -21,10 +21,11 @@ #pragma once +#include <optional> + #include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/services/tasks/TaskUtil.h> - -// #include <ArmarXGui/libraries/RemoteGui/Client/Widgets.h> +#include <ArmarXCore/libraries/DebugObserverHelper/DebugObserverHelper.h> #include <RobotAPI/components/ArViz/Client/Client.h> @@ -42,12 +43,10 @@ namespace armarx::armem::server::robot_state { class Segment; } - namespace proprioception { class Segment; } - namespace description { class Segment; @@ -64,17 +63,13 @@ namespace armarx::armem::server::robot_state Visu(const description::Segment& descriptionSegment, const proprioception::Segment& proprioceptionSegment, - const localization::Segment& localizationSegment) - : descriptionSegment(descriptionSegment), - proprioceptionSegment(proprioceptionSegment), - localizationSegment(localizationSegment) - {} + const localization::Segment& localizationSegment); - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "visu."); + void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "visu."); void init(); + void connect(const viz::Client& arviz, DebugObserverInterfacePrx debugObserver = nullptr); - void connect(const viz::Client& arviz); protected: @@ -89,7 +84,9 @@ namespace armarx::armem::server::robot_state private: + viz::Client arviz; + std::optional<DebugObserverHelper> debugObserver; const description::Segment& descriptionSegment; const proprioception::Segment& proprioceptionSegment; @@ -105,23 +102,6 @@ namespace armarx::armem::server::robot_state SimpleRunningTask<>::pointer_type updateTask; void visualizeRun(); - // struct RemoteGui - // { - // armarx::RemoteGui::Client::GroupBox group; - - // armarx::RemoteGui::Client::CheckBox enabled; - - // armarx::RemoteGui::Client::CheckBox inGlobalFrame; - // armarx::RemoteGui::Client::FloatSlider alpha; - // armarx::RemoteGui::Client::CheckBox alphaByConfidence; - // armarx::RemoteGui::Client::CheckBox oobbs; - // armarx::RemoteGui::Client::CheckBox objectFrames; - // armarx::RemoteGui::Client::FloatSpinBox objectFramesScale; - - // // void setup(const Visu& visu); - // // void update(Visu& visu); - // }; - }; } // namespace armarx::armem::server::robot_state diff --git a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp index d50d965608f7cf4ad8541467d75442303a293211..8fd1077e58c9c13ca6eeb3b429aacf569c837950 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp @@ -1,79 +1,53 @@ #include "Segment.h" -#include <IceUtil/Time.h> -#include <RobotAPI/libraries/armem_robot/aron/RobotDescription.aron.generated.h> -#include <sstream> - -#include "ArmarXCore/core/exceptions/local/ExpressionException.h" -#include "ArmarXCore/core/logging/Logging.h" +#include <ArmarXCore/core/application/properties/PluginAll.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/system/ArmarXDataPath.h> +#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h> #include <ArmarXCore/core/time/TimeUtil.h> -#include "ArmarXCore/core/system/ArmarXDataPath.h" -#include "ArmarXCore/core/system/cmake/CMakePackageFinder.h" -#include "RobotAPI/libraries/armem_robot/types.h" -#include "RobotAPI/libraries/aron/common/aron_conversions.h" +#include <RobotAPI/libraries/armem_robot/types.h> +#include <RobotAPI/libraries/aron/common/aron_conversions.h> -#include "RobotAPI/libraries/armem/core/MemoryID.h" +#include <RobotAPI/libraries/armem/core/MemoryID.h> #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.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 <thread> +#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h> + namespace armarx::armem::server::robot_state::description { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, - std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), memoryMutex(memoryMutex) + Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : + Base(memoryToIceAdapter, "Description") { - Logging::setTag("DescriptionSegment"); } Segment::~Segment() = default; - void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) - { - defs->optional(p.coreSegment, - prefix + "seg.description.CoreSegment", - "Name of the robot description core segment."); - defs->optional(p.maxHistorySize, - prefix + "seg.description.MaxHistorySize", - "Maximal size of object poses history (-1 for infinite)."); - } - - void Segment::init() - { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - ARMARX_INFO << "Adding core segment '" << p.coreSegment << "'"; - - coreSegment = &iceMemory.workingMemory->addCoreSegment( - p.coreSegment, arondto::RobotDescription::toAronType()); - coreSegment->setMaxHistorySize(p.maxHistorySize); - } - void Segment::connect(const viz::Client& arviz, const RobotUnitInterfacePrx& robotUnitPrx) + void Segment::onConnect(const RobotUnitInterfacePrx& robotUnitPrx) { - // this->visu = std::make_unique<Visu>(arviz, *this); robotUnit = robotUnitPrx; // store the robot description linked to the robot unit in this segment updateRobotDescription(); } - void Segment::storeRobotDescription(const robot::RobotDescription& robotDescription) + + void Segment::commitRobotDescription(const robot::RobotDescription& robotDescription) { const Time now = TimeUtil::GetTime(); - const MemoryID providerID = coreSegment->id().withProviderSegmentName(robotDescription.name); - coreSegment->addProviderSegment(providerID.providerSegmentName, arondto::RobotDescription::toAronType()); + const MemoryID providerID = segment->id().withProviderSegmentName(robotDescription.name); + segment->addProviderSegment(providerID.providerSegmentName, arondto::RobotDescription::toAronType()); EntityUpdate update; update.entityID = providerID.withEntityName("description"); @@ -88,139 +62,70 @@ namespace armarx::armem::server::robot_state::description Commit commit; commit.updates.push_back(update); - - { - // std::lock_guard g{memoryMutex}; - iceMemory.commit(commit); - } - + iceMemory.commitLocking(commit); } + void Segment::updateRobotDescription() { ARMARX_CHECK_NOT_NULL(robotUnit); - auto kinematicUnit = robotUnit->getKinematicUnit(); - - ARMARX_CHECK_NOT_NULL(kinematicUnit); + KinematicUnitInterfacePrx kinematicUnit = robotUnit->getKinematicUnit(); + if (kinematicUnit) + { + const std::string robotName = kinematicUnit->getRobotName(); + const std::string robotFilename = kinematicUnit->getRobotFilename(); - const auto robotName = kinematicUnit->getRobotName(); - const auto robotFilename = kinematicUnit->getRobotFilename(); + const std::vector<std::string> packages = armarx::CMakePackageFinder::FindAllArmarXSourcePackages(); + const std::string package = armarx::ArmarXDataPath::getProject(packages, robotFilename); - const auto packages = armarx::CMakePackageFinder::FindAllArmarXSourcePackages(); - const auto package = armarx::ArmarXDataPath::getProject(packages, robotFilename); + ARMARX_INFO << "Robot description '" << robotFilename << "' found in package " << package; - ARMARX_INFO << "Robot description '" << robotFilename << "' found in package " << package; + const robot::RobotDescription robotDescription + { + .name = kinematicUnit->getRobotName(), + .xml = {package, kinematicUnit->getRobotFilename()} + }; // FIXME - const robot::RobotDescription robotDescription + commitRobotDescription(robotDescription); + } + else { - .name = kinematicUnit->getRobotName(), - .xml = {package, kinematicUnit->getRobotFilename()}}; // FIXME + ARMARX_WARNING << "Robot unit '" << robotUnit->ice_getIdentity().name << "' does not have a kinematic unit." + << "\n Cannot commit robot description."; + } + } + - storeRobotDescription(robotDescription); + Segment::RobotDescriptionMap Segment::getRobotDescriptionsLocking(const armem::Time& timestamp) const + { + std::scoped_lock lock(mutex()); + return getRobotDescriptions(timestamp); } + Segment::RobotDescriptionMap Segment::getRobotDescriptions(const armem::Time& timestamp) const { + ARMARX_CHECK_NOT_NULL(segment); + (void) timestamp; // Unused RobotDescriptionMap robotDescriptions; - + segment->forEachEntity([this, &robotDescriptions](const wm::Entity & entity) { - // std::lock_guard g{memoryMutex}; - - for (const auto &[_, provSeg] : iceMemory.workingMemory->getCoreSegment(p.coreSegment)) + const wm::EntityInstance& entityInstance = entity.getLatestSnapshot().getInstance(0); + const auto description = robot::convertRobotDescription(entityInstance); + if (description) { - for (const auto &[name, entity] : provSeg.entities()) - { - const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - const auto description = robot::convertRobotDescription(entityInstance); - - if (not description) - { - ARMARX_WARNING << "Could not convert entity instance to " - "'RobotDescription'"; - continue; - } - - ARMARX_DEBUG << "Key is " << armem::MemoryID(entity.id()); - - robotDescriptions.emplace(description->name, *description); - } + ARMARX_DEBUG << "Key is " << armem::MemoryID(entity.id()); + robotDescriptions.emplace(description->name, *description); } - } - - ARMARX_INFO << deactivateSpam(10) << "Number of known robot descriptions: " << robotDescriptions.size(); + else + { + ARMARX_WARNING << "Could not convert entity instance to 'RobotDescription'"; + } + }); + ARMARX_INFO << deactivateSpam(60) << "Number of known robot descriptions: " << robotDescriptions.size(); return robotDescriptions; } - // std::unordered_map<armem::MemoryID, ::armarx::armem::articulated_object::ArticulatedObjectDescription> Segment::getKnownObjectClasses() const - // { - // std::unordered_map<armem::MemoryID, ::armarx::armem::articulated_object::ArticulatedObjectDescription> objects; - - // for (const auto& [_, provSeg] : iceMemory.workingMemory->getCoreSegment(p.coreClassSegmentName)) - // { - // for (const auto& [name, entity] : provSeg.entities()) - // { - // const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - // const auto description = articulated_object::convertRobotDescription(entityInstance); - - // if (not description) - // { - // ARMARX_WARNING << "Could not convert entity instance to 'RobotDescription'"; - // continue; - // } - - // ARMARX_INFO << "Key is " << armem::MemoryID(entity.id()); - - // objects.emplace(armem::MemoryID(entity.id()), *description); - // } - // } - - // ARMARX_IMPORTANT << "Number of known articulated object classes: " << objects.size(); - - // return objects; - // } - - // void Segment::RemoteGui::setup(const Segment& data) - // { - // using namespace armarx::RemoteGui::Client; - - // maxHistorySize.setValue(std::max(1, int(data.p.maxHistorySize))); - // maxHistorySize.setRange(1, 1e6); - // infiniteHistory.setValue(data.p.maxHistorySize == -1); - // discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); - - // GridLayout grid; - // int row = 0; - // grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); - // row++; - // grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); - // row++; - // grid.add(Label("Discard Snapshots while Attached"), {row, 0}).add(discardSnapshotsWhileAttached, {row, 1}); - // row++; - - // group.setLabel("Data"); - // group.addChild(grid); - // } - - // void Segment::RemoteGui::update(Segment& data) - // { - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() - // || discardSnapshotsWhileAttached.hasValueChanged()) - // { - // std::scoped_lock lock(data.memoryMutex); - - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) - // { - // data.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); - // if (data.coreSegment) - // { - // data.coreSegment->setMaxHistorySize(long(data.p.maxHistorySize)); - // } - // } - - // data.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); - // } - // } - } // namespace armarx::armem::server::robot_state::description diff --git a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.h b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.h index 2f603cf4961d90342fbd74770a0ef4d0d181c033..c62821c4afacbf6caa87b5540a4c05c778254f25 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.h +++ b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.h @@ -21,94 +21,53 @@ #pragma once -#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h> +// STD / STL #include <string> #include <optional> #include <mutex> #include <unordered_map> -#include <ArmarXCore/core/logging/Logging.h> -#include "ArmarXCore/core/application/properties/PropertyDefinitionContainer.h" - -// #include "ArmarXGui/libraries/RemoteGui/Client/Widgets.h" - -#include "RobotAPI/components/ArViz/Client/Client.h" +// ArmarX +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> -#include "RobotAPI/libraries/armem/core/MemoryID.h" -#include "RobotAPI/libraries/armem_objects/types.h" - -namespace armarx::armem -{ - namespace server - { - class MemoryToIceAdapter; - } +#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h> +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/server/segment/Segment.h> +#include <RobotAPI/libraries/armem_objects/types.h> - namespace wm - { - class CoreSegment; - } -} // namespace armarx::armem +// Aron +#include <RobotAPI/libraries/armem_robot/aron/RobotDescription.aron.generated.h> namespace armarx::armem::server::robot_state::description { - class Visu; - - class Segment : public armarx::Logging + class Segment : public segment::wm::AronTypedCoreSegmentBase<arondto::RobotDescription> { + using Base = segment::wm::AronTypedCoreSegmentBase<arondto::RobotDescription>; + public: - Segment(server::MemoryToIceAdapter& iceMemory, - std::mutex& memoryMutex); - virtual ~Segment(); + Segment(server::MemoryToIceAdapter& iceMemory); + virtual ~Segment() override; - void connect(const viz::Client& arviz, const RobotUnitInterfacePrx& robotUnitPrx); - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); + void onConnect(const RobotUnitInterfacePrx& robotUnitPrx); - void init(); /// mapping "robot name" -> "robot description" using RobotDescriptionMap = std::unordered_map<std::string, robot::RobotDescription>; RobotDescriptionMap getRobotDescriptions(const armem::Time& timestamp) const; + RobotDescriptionMap getRobotDescriptionsLocking(const armem::Time& timestamp) const; + private: - void storeRobotDescription(const robot::RobotDescription& robotDescription); + void commitRobotDescription(const robot::RobotDescription& robotDescription); void updateRobotDescription(); - - server::MemoryToIceAdapter& iceMemory; - wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; - RobotUnitInterfacePrx robotUnit; - struct Properties - { - std::string coreSegment = "Description"; - int64_t maxHistorySize = -1; - }; - Properties p; - - // std::unique_ptr<Visu> visu; - - public: - - // struct RemoteGui - // { - // armarx::RemoteGui::Client::GroupBox group; - - // armarx::RemoteGui::Client::IntSpinBox maxHistorySize; - // armarx::RemoteGui::Client::CheckBox infiniteHistory; - // armarx::RemoteGui::Client::CheckBox discardSnapshotsWhileAttached; - - // void setup(const Segment& data); - // void update(Segment& data); - // }; - }; } // namespace armarx::armem::server::robot_state::description diff --git a/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp index e0dcf6c2bcd9d86012d98cf5aded6fee585ed866..4eb19d15583fd12493d5dd2a6312c6154931e15f 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.cpp @@ -1,7 +1,6 @@ #include "Segment.h" // STL - #include <iterator> #include <sstream> @@ -12,6 +11,8 @@ #include <Eigen/Core> #include <Eigen/Geometry> +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/application/properties/PluginAll.h> #include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/time/TimeUtil.h> @@ -25,77 +26,60 @@ #include <RobotAPI/libraries/armem/core/MemoryID.h> #include <RobotAPI/libraries/armem/core/Time.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h> #include <RobotAPI/libraries/armem_robot/robot_conversions.h> -#include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h> #include <RobotAPI/libraries/armem_robot_state/aron_conversions.h> #include <RobotAPI/libraries/armem_robot_state/common/localization/TransformHelper.h> #include <RobotAPI/libraries/armem_robot_state/common/localization/types.h> + namespace armarx::armem::server::robot_state::localization { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, - std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), memoryMutex(memoryMutex) + Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : + Base(memoryToIceAdapter, "Localization", 1024) { - Logging::setTag("LocalizationSegment"); } + Segment::~Segment() = default; - void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) + void Segment::onConnect() { - defs->optional(p.coreSegment, - prefix + "seg.localization.CoreSegment", - "Name of the object instance core segment."); - defs->optional(p.maxHistorySize, - prefix + "seg.localization.MaxHistorySize", - "Maximal size of object poses history (-1 for infinite)."); } - void Segment::init() - { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - - ARMARX_INFO << "Adding core segment '" << p.coreSegment << "'"; - - coreSegment = &iceMemory.workingMemory->addCoreSegment( - p.coreSegment, arondto::Transform::toAronType()); - coreSegment->setMaxHistorySize(p.maxHistorySize); - } - void Segment::connect(viz::Client arviz) + Segment::RobotFramePoseMap + Segment::getRobotFramePosesLocking(const armem::Time& timestamp) const { - // this->visu = std::make_unique<Visu>(arviz, *this); + std::scoped_lock lock(mutex()); + return getRobotFramePoses(timestamp); } - std::unordered_map<std::string, std::vector<Eigen::Affine3f>> - Segment::getRobotFramePoses(const armem::Time& timestamp) const + + Segment::RobotFramePoseMap + Segment::getRobotFramePoses(const armem::Time& timestamp) const { using common::robot_state::localization::TransformHelper; using common::robot_state::localization::TransformQuery; - std::unordered_map<std::string, std::vector<Eigen::Affine3f>> frames; - - const auto& localizationCoreSegment = - iceMemory.workingMemory->getCoreSegment(p.coreSegment); - const auto knownRobots = simox::alg::get_keys(localizationCoreSegment); - - for (const auto& robotName : knownRobots) + RobotFramePoseMap frames; + for (const std::string& robotName : segment->getProviderSegmentNames()) { - - TransformQuery query{.header{.parentFrame = GlobalFrame, - .frame = "root", // TODO, FIXME - .agent = robotName, - .timestamp = timestamp}}; - - const auto result = TransformHelper::lookupTransformChain(localizationCoreSegment, query); - + TransformQuery query + { + .header{ + .parentFrame = GlobalFrame, + .frame = "root", // TODO, FIXME + .agent = robotName, + .timestamp = timestamp + } + }; + + const auto result = TransformHelper::lookupTransformChain(*segment, query); if (not result) { // TODO @@ -105,144 +89,92 @@ namespace armarx::armem::server::robot_state::localization frames.emplace(robotName, result.transforms); } - ARMARX_INFO << deactivateSpam(10) + ARMARX_INFO << deactivateSpam(60) << "Number of known robot pose chains: " << frames.size(); return frames; } - std::unordered_map<std::string, Eigen::Affine3f> - Segment::getRobotGlobalPoses(const armem::Time& timestamp) const + + Segment::RobotPoseMap + Segment::getRobotGlobalPosesLocking(const armem::Time& timestamp) const { + std::scoped_lock lock(mutex()); + return getRobotGlobalPoses(timestamp); + } + + Segment::RobotPoseMap + Segment::getRobotGlobalPoses(const armem::Time& timestamp) const + { using common::robot_state::localization::TransformHelper; using common::robot_state::localization::TransformQuery; - std::unordered_map<std::string, Eigen::Affine3f> robotGlobalPoses; - - const auto& localizationCoreSegment = - iceMemory.workingMemory->getCoreSegment(p.coreSegment); - const auto knownRobots = simox::alg::get_keys(localizationCoreSegment); - - for (const auto& robotName : knownRobots) + RobotPoseMap robotGlobalPoses; + for (const std::string& robotName : segment->getProviderSegmentNames()) { - - TransformQuery query{.header{.parentFrame = GlobalFrame, - .frame = "root", // TODO, FIXME - .agent = robotName, - .timestamp = timestamp}}; - - const auto result = TransformHelper::lookupTransform(localizationCoreSegment, query); - - if (not result) + TransformQuery query + { + .header{ + .parentFrame = GlobalFrame, + .frame = "root", // TODO, FIXME + .agent = robotName, + .timestamp = timestamp + } + }; + + const auto result = TransformHelper::lookupTransform(*segment, query); + if (result) + { + robotGlobalPoses.emplace(robotName, result.transform.transform); + } + else { // TODO - continue; } - - robotGlobalPoses.emplace(robotName, result.transform.transform); } - ARMARX_INFO << deactivateSpam(10) + ARMARX_INFO << deactivateSpam(60) << "Number of known robot poses: " << robotGlobalPoses.size(); return robotGlobalPoses; } - bool Segment::storeTransform(const armarx::armem::robot_state::Transform& transform) + + bool Segment::commitTransform(const armarx::armem::robot_state::Transform& transform) { - const auto& timestamp = transform.header.timestamp; + Commit commit; + commit.add(makeUpdate(transform)); + + const armem::CommitResult result = iceMemory.commit(commit); + return result.allSuccess(); + } - const MemoryID providerID = - coreSegment->id().withProviderSegmentName(transform.header.agent); - if (not coreSegment->hasProviderSegment(providerID.providerSegmentName)) - { - coreSegment->addProviderSegment(providerID.providerSegmentName, arondto::Transform::toAronType()); - } + bool Segment::commitTransformLocking(const armarx::armem::robot_state::Transform& transform) + { Commit commit; + commit.add(makeUpdate(transform)); + + const armem::CommitResult result = iceMemory.commitLocking(commit); + return result.allSuccess(); + } - EntityUpdate& update = commit.updates.emplace_back(); - update.entityID = - providerID.withEntityName(transform.header.parentFrame + "," + transform.header.frame); + + EntityUpdate Segment::makeUpdate(const armarx::armem::robot_state::Transform& transform) const + { + const armem::Time& timestamp = transform.header.timestamp; + const MemoryID providerID = segment->id().withProviderSegmentName(transform.header.agent); + + EntityUpdate update; + update.entityID = providerID.withEntityName(transform.header.parentFrame + "," + transform.header.frame); update.timeArrived = update.timeCreated = update.timeSent = timestamp; arondto::Transform aronTransform; toAron(aronTransform, transform); update.instancesData = {aronTransform.toAron()}; - const armem::CommitResult result = iceMemory.commit(commit); - return result.allSuccess(); + return update; } - // std::unordered_map<armem::MemoryID, ::armarx::armem::articulated_object::ArticulatedObjectDescription> Segment::getKnownObjectClasses() const - // { - // std::unordered_map<armem::MemoryID, ::armarx::armem::articulated_object::ArticulatedObjectDescription> objects; - - // for (const auto& [_, provSeg] : iceMemory.workingMemory->getCoreSegment(p.coreClassSegmentName)) - // { - // for (const auto& [name, entity] : provSeg.entities()) - // { - // const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - // const auto description = articulated_object::convertRobotDescription(entityInstance); - - // if (not description) - // { - // ARMARX_WARNING << "Could not convert entity instance to 'RobotDescription'"; - // continue; - // } - - // ARMARX_INFO << "Key is " << armem::MemoryID(entity.id()); - - // objects.emplace(armem::MemoryID(entity.id()), *description); - // } - // } - - // ARMARX_IMPORTANT << "Number of known articulated object classes: " << objects.size(); - - // return objects; - // } - - // void Segment::RemoteGui::setup(const Segment& data) - // { - // using namespace armarx::RemoteGui::Client; - - // maxHistorySize.setValue(std::max(1, int(data.p.maxHistorySize))); - // maxHistorySize.setRange(1, 1e6); - // infiniteHistory.setValue(data.p.maxHistorySize == -1); - // discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); - - // GridLayout grid; - // int row = 0; - // grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); - // row++; - // grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); - // row++; - // grid.add(Label("Discard Snapshots while Attached"), {row, 0}).add(discardSnapshotsWhileAttached, {row, 1}); - // row++; - - // group.setLabel("Data"); - // group.addChild(grid); - // } - - // void Segment::RemoteGui::update(Segment& data) - // { - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() - // || discardSnapshotsWhileAttached.hasValueChanged()) - // { - // std::scoped_lock lock(data.memoryMutex); - - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) - // { - // data.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); - // if (data.coreSegment) - // { - // data.coreSegment->setMaxHistorySize(long(data.p.maxHistorySize)); - // } - // } - - // data.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); - // } - // } - } // namespace armarx::armem::server::robot_state::localization diff --git a/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.h b/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.h index 307eaae17babf66aa9d0a1e759cbc348cbb05008..31fffb4207e7bfe40a0d3f6ed23b554069076a6a 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.h +++ b/source/RobotAPI/libraries/armem_robot_state/server/localization/Segment.h @@ -21,88 +21,62 @@ #pragma once +// STD / STL #include <string> #include <optional> -#include <mutex> #include <unordered_map> -#include <ArmarXCore/core/logging/Logging.h> -#include "ArmarXCore/core/application/properties/PropertyDefinitionContainer.h" +// Eigen +#include <Eigen/Geometry> -// #include "ArmarXGui/libraries/RemoteGui/Client/Widgets.h" - -#include "RobotAPI/components/ArViz/Client/Client.h" +// ArmarX +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/server/segment/Segment.h> +#include <RobotAPI/libraries/armem_objects/types.h> +#include <RobotAPI/libraries/armem_robot_state/types.h> -#include "RobotAPI/libraries/armem/core/MemoryID.h" -#include "RobotAPI/libraries/armem_objects/types.h" +// Aron +#include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h> -#include <RobotAPI/libraries/armem_robot_state/types.h> namespace armarx::armem { - namespace server - { - class MemoryToIceAdapter; - } - - namespace wm - { - class CoreSegment; - } + struct EntityUpdate; } // namespace armarx::armem - namespace armarx::armem::server::robot_state::localization { - class Visu; - - class Segment : public armarx::Logging + class Segment : public segment::wm::AronTypedCoreSegmentBase<arondto::Transform> { - public: - Segment(server::MemoryToIceAdapter& iceMemory, - std::mutex& memoryMutex); + using Base = segment::wm::AronTypedCoreSegmentBase<arondto::Transform>; - virtual ~Segment(); + public: - void connect(viz::Client arviz); + using RobotPoseMap = std::unordered_map<std::string, Eigen::Affine3f>; + using RobotFramePoseMap = std::unordered_map<std::string, std::vector<Eigen::Affine3f>>; - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); - void init(); + public: - std::unordered_map<std::string, Eigen::Affine3f> getRobotGlobalPoses(const armem::Time& timestamp) const; - std::unordered_map<std::string, std::vector<Eigen::Affine3f>> getRobotFramePoses(const armem::Time& timestamp) const; + Segment(server::MemoryToIceAdapter& iceMemory); + virtual ~Segment() override; - bool storeTransform(const armarx::armem::robot_state::Transform& transform); + void onConnect(); - private: + RobotPoseMap getRobotGlobalPoses(const armem::Time& timestamp) const; + RobotPoseMap getRobotGlobalPosesLocking(const armem::Time& timestamp) const; - server::MemoryToIceAdapter& iceMemory; - wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; + RobotFramePoseMap getRobotFramePoses(const armem::Time& timestamp) const; + RobotFramePoseMap getRobotFramePosesLocking(const armem::Time& timestamp) const; - struct Properties - { - std::string coreSegment = "Localization"; - int64_t maxHistorySize = -1; - }; - Properties p; + bool commitTransform(const armarx::armem::robot_state::Transform& transform); + bool commitTransformLocking(const armarx::armem::robot_state::Transform& transform); - // std::unique_ptr<Visu> visu; - public: - - // struct RemoteGui - // { - // armarx::RemoteGui::Client::GroupBox group; + private: - // armarx::RemoteGui::Client::IntSpinBox maxHistorySize; - // armarx::RemoteGui::Client::CheckBox infiniteHistory; - // armarx::RemoteGui::Client::CheckBox discardSnapshotsWhileAttached; + EntityUpdate makeUpdate(const armarx::armem::robot_state::Transform& transform) const; - // void setup(const Segment& data); - // void update(Segment& data); - // }; }; diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd8ace277ea412ae1ac2553e043ba515040e6ec5 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.cpp @@ -0,0 +1,192 @@ +/* + * 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/>. + * + * @package RobotAPI::ArmarXObjects::RobotSensorMemory + * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu ) + * @date 2020 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include "RobotStateWriter.h" + +// STL +#include <chrono> + +// Simox +#include <SimoxUtility/math/convert/rpy_to_mat3f.h> + +// ArmarX +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/time/CycleUtil.h> +#include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h> + +#include <RobotAPI/libraries/core/FramedPose.h> +#include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> +#include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem/core/ice_conversions.h> +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> +#include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h> +#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h> +#include <RobotAPI/libraries/armem_robot_state/server/localization/Segment.h> + + +namespace armarx::armem::server::robot_state::proprioception +{ + + void RobotStateWriter::connect(armarx::plugins::DebugObserverComponentPlugin& debugObserver) + { + // Thread-local copy of debug observer helper. + this->debugObserver = + DebugObserverHelper(Logging::tag.tagName, debugObserver.getDebugObserver(), true); + } + + + static float toDurationMs( + std::chrono::high_resolution_clock::time_point start, + std::chrono::high_resolution_clock::time_point end) + { + auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + return duration.count() / 1000.f; + } + + + void RobotStateWriter::run( + float pollFrequency, + std::queue<RobotUnitData>& dataQueue, + std::mutex& dataMutex, + MemoryToIceAdapter& memory, + localization::Segment& localizationSegment) + { + CycleUtil cycle(static_cast<int>(1000.f / pollFrequency)); + while (task and not task->isStopped()) + { + size_t queueSize = 0; + std::queue<RobotUnitData> batch; + { + std::lock_guard lock{dataMutex}; + queueSize = dataQueue.size(); + if (dataQueue.size() >= properties.memoryBatchSize) + { + std::swap(batch, dataQueue); + } + } + if (debugObserver) + { + debugObserver->setDebugObserverDatafield("RobotStateWriter | Queue Size", queueSize); + } + if (not batch.empty()) + { + Update update = buildUpdate(batch); + + auto start = std::chrono::high_resolution_clock::now(); + auto endProprioception = start, endLocalization = start; + + armem::CommitResult result; + { + // Commits lock the core segments. + + result = memory.commitLocking(update.proprioception); + endProprioception = std::chrono::high_resolution_clock::now(); + + localizationSegment.commitTransformLocking(update.localization); + endLocalization = std::chrono::high_resolution_clock::now(); + } + if (not result.allSuccess()) + { + ARMARX_WARNING << "Could not add 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)); + } + } + + if (debugObserver) + { + debugObserver->sendDebugObserverBatch(); + } + cycle.waitForCycleDuration(); + } + } + + + 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; + + while (dataQueue.size() > 0) + { + 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 }; + + // odometry pose -> localization segment + if (data.proprioception->hasElement("platform")) + { + 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; + } + // ToDo: Detect that now odometry data was send + /* + else if (!noOdometryDataLogged) + { + ARMARX_INFO << "No odometry data! (No group with name '" << properties.platformGroupName << "'.). \n" + << "If you are using a mobile platform this should not have happened."; + 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; + } + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..3f8d33ef8b0c2b18f5515ad130579ec973722877 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotStateWriter.h @@ -0,0 +1,97 @@ +/* + * 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/>. + * + * @package RobotAPI::ArmarXObjects::RobotSensorMemory + * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu ) + * @date 2020 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#pragma once + +#include <optional> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/services/tasks/TaskUtil.h> +#include <ArmarXCore/libraries/DebugObserverHelper/DebugObserverHelper.h> + +#include <RobotAPI/libraries/armem/core/Commit.h> +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem_robot_state/types.h> + +#include "RobotUnitData.h" + + +namespace armarx::plugins +{ + class DebugObserverComponentPlugin; +} +namespace armarx::armem::server +{ + class MemoryToIceAdapter; +} +namespace armarx::armem::server::robot_state::localization +{ + class Segment; +} +namespace armarx::armem::server::robot_state::proprioception +{ + class RobotStateWriter : public armarx::Logging + { + public: + + void connect(armarx::plugins::DebugObserverComponentPlugin& debugObserver); + + /// Reads data from `dataQueue` and commits to the memory. + void run(float pollFrequency, + std::queue<RobotUnitData>& dataQueue, std::mutex& dataMutex, + MemoryToIceAdapter& memory, + localization::Segment& localizationSegment + ); + + + struct Update + { + armem::Commit proprioception; + armem::robot_state::Transform localization; + }; + Update buildUpdate(std::queue<RobotUnitData>& dataQueue); + + + public: + + struct Properties + { + unsigned int memoryBatchSize = 50; + armem::MemoryID robotUnitProviderID; + std::string platformGroupName = "sens.Platform"; + }; + Properties properties; + + std::optional<DebugObserverHelper> debugObserver; + + + armarx::SimpleRunningTask<>::pointer_type task = nullptr; + + + private: + + bool noOdometryDataLogged = false; + + }; + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4262bf76e634ff03445a7460cd4fd55a4df861d9 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.cpp @@ -0,0 +1,9 @@ +#include "RobotUnitData.h" + +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> + + +namespace armarx::armem::server::robot_state::proprioception +{ + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h new file mode 100644 index 0000000000000000000000000000000000000000..4045742af416c96ad2d101d98f4559d8cef1dce9 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitData.h @@ -0,0 +1,22 @@ +#pragma once + +#include <memory> + +#include <RobotAPI/libraries/armem/core/Time.h> + + +namespace armarx::aron::datanavigator +{ + using DictNavigatorPtr = std::shared_ptr<class DictNavigator>; +} +namespace armarx::armem::server::robot_state::proprioception +{ + + struct RobotUnitData + { + Time timestamp; + aron::datanavigator::DictNavigatorPtr proprioception; + }; + +} + diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4b79b65ffd31a41ef2f0ea9bc193bbf3e1ec12e --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp @@ -0,0 +1,128 @@ +#include "RobotUnitReader.h" + +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/converters/Armar6Converter.h> +#include <RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h> +#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h> + +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> +#include <RobotAPI/libraries/aron/core/navigator/data/primitive/Long.h> +#include <RobotAPI/libraries/aron/core/navigator/data/primitive/String.h> + +#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h> + +#include <ArmarXCore/core/time/CycleUtil.h> +#include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h> + +#include <SimoxUtility/algorithm/string/string_tools.h> + +#include <istream> +#include <filesystem> +#include <fstream> + + +namespace armarx::armem::server::robot_state::proprioception +{ + + RobotUnitReader::RobotUnitReader() + { + } + + + void RobotUnitReader::connect( + armarx::plugins::RobotUnitComponentPlugin& robotUnitPlugin, + armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin, + const std::string& robotTypeName) + { + { + converter = converterRegistry.get(robotTypeName); + ARMARX_CHECK_NOT_NULL(converter) + << "No converter for robot type '" << robotTypeName << "' available. \n" + << "Known are: " << converterRegistry.getKeys(); + + config.loggingNames.push_back(properties.sensorPrefix); + receiver = robotUnitPlugin.startDataSatreming(config); + description = receiver->getDataDescription(); + } + { + // Thread-local copy of debug observer helper. + debugObserver = + DebugObserverHelper(Logging::tag.tagName, debugObserverPlugin.getDebugObserver(), true); + } + } + + + void RobotUnitReader::run( + float pollFrequency, + std::queue<RobotUnitData>& dataQueue, + std::mutex& dataMutex) + { + CycleUtil cycle(static_cast<int>(1000.f / pollFrequency)); + while (task and not task->isStopped()) + { + if (std::optional<RobotUnitData> commit = fetchAndConvertLatestRobotUnitData()) + { + std::lock_guard g{dataMutex}; + dataQueue.push(std::move(commit.value())); + } + + if (debugObserver) + { + debugObserver->sendDebugObserverBatch(); + } + cycle.waitForCycleDuration(); + } + } + + + std::optional<RobotUnitData> RobotUnitReader::fetchAndConvertLatestRobotUnitData() + { + ARMARX_CHECK_NOT_NULL(converter); + + const std::optional<RobotUnitDataStreaming::TimeStep> data = fetchLatestData(); + if (not data.has_value()) + { + return std::nullopt; + } + + ARMARX_DEBUG << "RobotUnitReader: Converting data current timestep to commit"; + auto start = std::chrono::high_resolution_clock::now(); + + RobotUnitData result; + result.proprioception = converter->convert(data.value(), description); + result.timestamp = Time::microSeconds(data->timestampUSec);; + + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); + ARMARX_DEBUG << "RobotUnitReader: The total time needed to convert the data to commit s: " << duration; + + if (debugObserver) + { + debugObserver->setDebugObserverDatafield("RobotUnitReader | t Read+Group [ms]", duration.count() / 1000.f); + } + + return result; + } + + + std::optional<RobotUnitDataStreaming::TimeStep> RobotUnitReader::fetchLatestData() + { + std::deque<RobotUnitDataStreaming::TimeStep>& data = receiver->getDataBuffer(); + if (debugObserver) + { + debugObserver->setDebugObserverDatafield("RobotUnitReader | Buffer Size", data.size()); + } + if (data.empty()) + { + return std::nullopt; + } + else + { + RobotUnitDataStreaming::TimeStep currentTimestep = data.back(); + data.clear(); + return currentTimestep; + } + } + + +} + diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h new file mode 100644 index 0000000000000000000000000000000000000000..efb7a0d8175de36ebf963fd035d176442df822f2 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.h @@ -0,0 +1,84 @@ +#pragma once + +#include <queue> +#include <map> +#include <memory> +#include <optional> +#include <string> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/services/tasks/TaskUtil.h> +#include <ArmarXCore/libraries/DebugObserverHelper/DebugObserverHelper.h> + +#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h> +#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h> + +#include "RobotUnitData.h" +#include "converters/ConverterRegistry.h" +#include "converters/ConverterInterface.h" + + +namespace armarx::plugins +{ + class RobotUnitComponentPlugin; + class DebugObserverComponentPlugin; +} +namespace armarx +{ + using RobotUnitDataStreamingReceiverPtr = std::shared_ptr<class RobotUnitDataStreamingReceiver>; +} + +namespace armarx::armem::server::robot_state::proprioception +{ + class RobotUnitReader : public armarx::Logging + { + public: + + RobotUnitReader(); + + + void connect( + armarx::plugins::RobotUnitComponentPlugin& robotUnitPlugin, + armarx::plugins::DebugObserverComponentPlugin& debugObserverPlugin, + const std::string& robotTypeName); + + + + /// Reads data from `handler` and fills `dataQueue`. + void run(float pollFrequency, + std::queue<RobotUnitData>& dataQueue, + std::mutex& dataMutex); + + std::optional<RobotUnitData> fetchAndConvertLatestRobotUnitData(); + + + private: + + /// Fetch the latest timestep and clear the robot unit buffer. + std::optional<RobotUnitDataStreaming::TimeStep> fetchLatestData(); + + + public: + + struct Properties + { + std::string sensorPrefix = "sens.*"; + }; + Properties properties; + + std::optional<DebugObserverHelper> debugObserver; + + + RobotUnitDataStreaming::Config config; + RobotUnitDataStreamingReceiverPtr receiver; + RobotUnitDataStreaming::DataStreamingDescription description; + + ConverterRegistry converterRegistry; + ConverterInterface* converter = nullptr; + + armarx::SimpleRunningTask<>::pointer_type task = nullptr; + + }; + +} + 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 ac5e5e1c36e66d47251700ec6565a9fb61ce5430..a63610cf6f7727feaebf60ca2139ab09c0d6e6af 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp @@ -1,176 +1,172 @@ #include "Segment.h" -#include <mutex> -#include <sstream> - +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/time/TimeUtil.h> -#include "ArmarXCore/core/logging/Logging.h" +#include <ArmarXCore/libraries/DebugObserverHelper/DebugObserverHelper.h> -#include "RobotAPI/libraries/armem_robot_state/types.h" -#include "RobotAPI/libraries/aron/common/aron_conversions.h" +#include <RobotAPI/libraries/aron/common/aron_conversions.h> +#include <RobotAPI/libraries/armem_robot_state/types.h> #include <RobotAPI/libraries/armem/core/aron_conversions.h> -#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h> -#include "RobotAPI/libraries/armem/core/MemoryID.h" +#include <RobotAPI/libraries/armem/core/MemoryID.h> #include <RobotAPI/libraries/armem/client/Writer.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> +#include <RobotAPI/libraries/armem/util/util.h> -#include "RobotAPI/libraries/armem_robot/robot_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_objects/types.h> #include <RobotAPI/libraries/armem_objects/aron_conversions.h> - -#include <RobotAPI/libraries/armem/util/util.h> +#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h> namespace armarx::armem::server::robot_state::proprioception { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : - iceMemory(memoryToIceAdapter), - memoryMutex(memoryMutex) + Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : + Base(memoryToIceAdapter, "Proprioception", arondto::Proprioception::toAronType(), 1024) { - Logging::setTag("ProprioceptionSegment"); } Segment::~Segment() = default; - void Segment::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix) - { - defs->optional(p.coreSegment, prefix + "seg.proprioception.CoreSegment", "Name of the object instance core segment."); - defs->optional(p.maxHistorySize, prefix + "seg.proprioception.MaxHistorySize", "Maximal size of object poses history (-1 for infinite)."); - } - void Segment::init() + void Segment::onConnect(RobotUnitInterfacePrx robotUnitPrx) { - ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); + this->robotUnit = robotUnitPrx; - ARMARX_INFO << "Adding core segment '" << p.coreSegment << "'"; - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreSegment); - coreSegment->setMaxHistorySize(p.maxHistorySize); + std::string providerSegmentName = "Robot"; + KinematicUnitInterfacePrx kinematicUnit = robotUnit->getKinematicUnit(); + if (kinematicUnit) + { + providerSegmentName = kinematicUnit->getRobotName(); + } + else + { + ARMARX_WARNING << "Robot unit '" << robotUnit->ice_getIdentity().name << "' does not have a kinematic unit." + << "\n Falling back to provider segment name '" << providerSegmentName << "'."; + } + this->robotUnitProviderID = segment->id().withProviderSegmentName(providerSegmentName); } - void Segment::connect(viz::Client arviz, RobotUnitInterfacePrx robotUnitPrx) - { - robotUnit = robotUnitPrx; - auto kinematicUnit = robotUnit->getKinematicUnit(); - const auto providerSegmentName = kinematicUnit->getRobotName(); - // TODO what is the purpose? - auto encoderEntryType = std::make_shared<aron::typenavigator::ObjectNavigator>("RobotUnitEncoderEntry"); - auto encoderNameType = std::make_shared<aron::typenavigator::StringNavigator>(); - auto encoderIterationIDType = std::make_shared<aron::typenavigator::LongNavigator>(); - encoderEntryType->addMemberType("EncoderGroupName", encoderNameType); - encoderEntryType->addMemberType("IterationId", encoderIterationIDType); - //auto encoderValueType = std::make_shared<aron::typenavigator::AnyType>(); - //encoderEntryType->addMemberType("value", encoderValueType); + Segment::RobotJointPositionMap Segment::getRobotJointPositionsLocking( + const armem::Time& timestamp, + DebugObserverHelper* debugObserver) const + { + TIMING_START(tRobotJointPositionsLock); + std::scoped_lock lock(mutex()); + TIMING_END_STREAM(tRobotJointPositionsLock, ARMARX_DEBUG); + if (debugObserver) + { + debugObserver->setDebugObserverDatafield(dp + "t 0 Lock Core Segment (ms)", tRobotJointPositionsLock.toMilliSecondsDouble()); + } + return getRobotJointPositions(timestamp, debugObserver); + } - ARMARX_INFO << "Adding provider segment " << p.coreSegment << "/" << providerSegmentName; - armem::data::AddSegmentInput input; - input.coreSegmentName = p.coreSegment; - input.providerSegmentName = providerSegmentName; + static + aron::datanavigator::DictNavigatorPtr + getDictElement(const aron::datanavigator::DictNavigator& dict, const std::string& key) + { + if (dict.hasElement(key)) { - std::lock_guard g{memoryMutex}; - auto result = iceMemory.addSegments({input})[0]; - - if (!result.success) - { - ARMARX_ERROR << "Could not add segment " << p.coreSegment << "/" << providerSegmentName << ". The error message is: " << result.errorMessage; - } + return aron::datanavigator::DictNavigator::DynamicCastAndCheck(dict.getElement(key)); } - - robotUnitProviderID.memoryName = iceMemory.workingMemory->id().memoryName; - robotUnitProviderID.coreSegmentName = p.coreSegment; - robotUnitProviderID.providerSegmentName = providerSegmentName; + return nullptr; } - std::unordered_map<std::string, std::map<std::string, float>> Segment::getRobotJointPositions(const armem::Time& timestamp) const + + Segment::RobotJointPositionMap Segment::getRobotJointPositions( + const armem::Time& timestamp, + DebugObserverHelper* debugObserver) const { - std::unordered_map<std::string, std::map<std::string, float>> jointMap; + namespace adn = aron::datanavigator; + ARMARX_CHECK_NOT_NULL(segment); - std::lock_guard g{memoryMutex}; + RobotJointPositionMap jointMap; - for (const auto& [robotName, provSeg] : iceMemory.workingMemory->getCoreSegment(p.coreSegment)) + TIMING_START(tProcessProviders); + segment->forEachProviderSegment([&](const wm::ProviderSegment & provSeg) { - for (const auto& [name, entity] : provSeg.entities()) + TIMING_START(tProcessEntities); + int i = 0; + + std::map<std::string, float>& robotJointMap = jointMap[provSeg.name()]; + provSeg.forEachEntity([&](const wm::Entity & entity) { - try + TIMING_START(tProcessEntity); + + TIMING_START(tGetLatestInstance); + if (entity.empty()) + { + return true; + } + const wm::EntitySnapshot& snapshot = entity.getLatestSnapshot(); + if (snapshot.empty()) { - const auto& entityInstance = entity.getLatestSnapshot().getInstance(0); - const auto jointState = tryCast<armarx::armem::arondto::JointState>(entityInstance); + return true; + } + const wm::EntityInstance& entityInstance = snapshot.getInstance(0); + TIMING_END_COMMENT_STREAM(tGetLatestInstance, "tGetLatestInstance " + std::to_string(i), ARMARX_DEBUG); - if (not jointState) + TIMING_START(tCastAndEmplaceJointState); + // Only cast the joint angles while avoiding throwing an exception. + adn::DictNavigatorPtr joints = getDictElement(*entityInstance.data(), "joints"); + if (joints) + { + adn::DictNavigatorPtr jointPositions = getDictElement(*joints, "position"); + if (jointPositions) { - // ARMARX_WARNING << "Could not convert entity instance to 'JointState'"; - continue; + for (const auto& [name, value] : jointPositions->getElements()) + { + const float jointPosition = adn::FloatNavigator::DynamicCastAndCheck(value)->getValue(); + robotJointMap.emplace(name, jointPosition); + } } - jointMap[robotName].emplace(jointState->name, jointState->position); - } - catch (...) // empty history etc - { + TIMING_END_COMMENT_STREAM(tCastAndEmplaceJointState, "tCastAndEmplaceJointState " + std::to_string(i), ARMARX_DEBUG); + + TIMING_END_COMMENT_STREAM(tProcessEntity, "tProcessEntity " + std::to_string(i), ARMARX_DEBUG); + if (debugObserver) + { + debugObserver->setDebugObserverDatafield(dp + "t 1.1.1.1 GetLatestInstance (ms)", tGetLatestInstance.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(dp + "t 1.1.1.2 CastAndEmplaceJointState (ms)", tCastAndEmplaceJointState.toMilliSecondsDouble()); + debugObserver->setDebugObserverDatafield(dp + "t 1.1.1.T Process Entity (ms)", tProcessEntity.toMilliSecondsDouble()); } + ++i; + + return true; + }); + + TIMING_END_STREAM(tProcessEntities, ARMARX_DEBUG); + if (debugObserver) + { + debugObserver->setDebugObserverDatafield(dp + "t 1.1 Process Entities (ms)", tProcessEntities.toMilliSecondsDouble()); } - } + }); + TIMING_END_STREAM(tProcessProviders, ARMARX_DEBUG); - ARMARX_INFO << deactivateSpam(10) << "Number of known robot joint maps: " << jointMap.size(); + ARMARX_INFO << deactivateSpam(60) << "Number of known robot joint maps: " << jointMap.size(); + + if (debugObserver) + { + debugObserver->setDebugObserverDatafield(dp + "t 1 Process Providers (ms)", tProcessProviders.toMilliSecondsDouble()); + } return jointMap; } + const armem::MemoryID& Segment::getRobotUnitProviderID() const { return robotUnitProviderID; } - - - // void Segment::RemoteGui::setup(const Segment& data) - // { - // using namespace armarx::RemoteGui::Client; - - // maxHistorySize.setValue(std::max(1, int(data.p.maxHistorySize))); - // maxHistorySize.setRange(1, 1e6); - // infiniteHistory.setValue(data.p.maxHistorySize == -1); - // discardSnapshotsWhileAttached.setValue(data.p.discardSnapshotsWhileAttached); - - // GridLayout grid; - // int row = 0; - // grid.add(Label("Max History Size"), {row, 0}).add(maxHistorySize, {row, 1}); - // row++; - // grid.add(Label("Infinite History Size"), {row, 0}).add(infiniteHistory, {row, 1}); - // row++; - // grid.add(Label("Discard Snapshots while Attached"), {row, 0}).add(discardSnapshotsWhileAttached, {row, 1}); - // row++; - - // group.setLabel("Data"); - // group.addChild(grid); - // } - - // void Segment::RemoteGui::update(Segment& data) - // { - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged() - // || discardSnapshotsWhileAttached.hasValueChanged()) - // { - // std::scoped_lock lock(data.memoryMutex); - - // if (infiniteHistory.hasValueChanged() || maxHistorySize.hasValueChanged()) - // { - // data.p.maxHistorySize = infiniteHistory.getValue() ? -1 : maxHistorySize.getValue(); - // if (data.coreSegment) - // { - // data.coreSegment->setMaxHistorySize(long(data.p.maxHistorySize)); - // } - // } - - // data.p.discardSnapshotsWhileAttached = discardSnapshotsWhileAttached.getValue(); - // } - // } - } // namespace armarx::armem::server::robot_state::proprioception diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h index bc83a946bcadafbc85a15d55cff79c3a18af970f..c1c3e44a7251d45bdccc384ad266d7bf518caaa2 100644 --- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.h @@ -21,89 +21,58 @@ #pragma once -#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h> -#include <string> +// STD / STL +#include <map> #include <optional> -#include <mutex> +#include <string> #include <unordered_map> -#include <ArmarXCore/core/logging/Logging.h> -#include "ArmarXCore/core/application/properties/PropertyDefinitionContainer.h" - -// #include "ArmarXGui/libraries/RemoteGui/Client/Widgets.h" +// ArmarX +#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h> -#include "RobotAPI/components/ArViz/Client/Client.h" +// RobotAPI +#include <RobotAPI/components/ArViz/Client/Client.h> +#include <RobotAPI/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/server/segment/Segment.h> -#include "RobotAPI/libraries/armem/core/MemoryID.h" -#include "RobotAPI/libraries/armem_objects/types.h" -namespace armarx::armem +namespace armarx { - namespace server - { - class MemoryToIceAdapter; - } - - namespace wm - { - class CoreSegment; - } -} // namespace armarx::armem - - + class DebugObserverHelper; +} namespace armarx::armem::server::robot_state::proprioception { - class Visu; - - class Segment : public armarx::Logging + class Segment : public segment::wm::CoreSegmentBase { + using Base = segment::wm::CoreSegmentBase; + public: - Segment(server::MemoryToIceAdapter& iceMemory, std::mutex& memoryMutex); - virtual ~Segment(); + using RobotJointPositionMap = std::unordered_map<std::string, std::map<std::string, float>>; - void connect(viz::Client arviz, RobotUnitInterfacePrx robotUnitPrx); + public: + + Segment(server::MemoryToIceAdapter& iceMemory); + virtual ~Segment() override; - void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = ""); + void onConnect(RobotUnitInterfacePrx robotUnitPrx); - void init(); - std::unordered_map<std::string, std::map<std::string, float>> getRobotJointPositions(const armem::Time& timestamp) const; + RobotJointPositionMap getRobotJointPositions( + const armem::Time& timestamp, DebugObserverHelper* debugObserver = nullptr) const; + RobotJointPositionMap getRobotJointPositionsLocking( + const armem::Time& timestamp, DebugObserverHelper* debugObserver = nullptr) const; const armem::MemoryID& getRobotUnitProviderID() const; - private: - server::MemoryToIceAdapter& iceMemory; - wm::CoreSegment* coreSegment = nullptr; - std::mutex& memoryMutex; + private: RobotUnitInterfacePrx robotUnit; - armem::MemoryID robotUnitProviderID; - struct Properties - { - std::string coreSegment = "Proprioception"; - int64_t maxHistorySize = -1; - }; - Properties p; - - // std::unique_ptr<Visu> visu; - - public: - - // struct RemoteGui - // { - // armarx::RemoteGui::Client::GroupBox group; - - // armarx::RemoteGui::Client::IntSpinBox maxHistorySize; - // armarx::RemoteGui::Client::CheckBox infiniteHistory; - // armarx::RemoteGui::Client::CheckBox discardSnapshotsWhileAttached; - - // void setup(const Segment& data); - // void update(Segment& data); - // }; + // Debug Observer prefix + const std::string dp = "Proprioception::getRobotJointPositions() | "; }; diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8caf73057ac54df453f6e3c2d67295dc7e69ab89 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.cpp @@ -0,0 +1,69 @@ +#include "aron_conversions.h" + +#include <RobotAPI/libraries/aron/core/navigator/data/AllNavigators.h> +#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h> + +#include <ArmarXCore/core/exceptions/local/UnexpectedEnumValueException.h> + + +namespace armarx +{ + aron::datanavigator::NavigatorPtr RobotUnitDataStreaming::toAron( + const TimeStep& timestep, + const DataEntry& dataEntry) + { + switch (dataEntry.type) + { + case RobotUnitDataStreaming::NodeTypeFloat: + { + float value = RobotUnitDataStreamingReceiver::GetAs<Ice::Float>(timestep, dataEntry); + return std::make_shared<aron::datanavigator::FloatNavigator>(value); + } + case RobotUnitDataStreaming::NodeTypeBool: + { + bool value = RobotUnitDataStreamingReceiver::GetAs<bool>(timestep, dataEntry); + return std::make_shared<aron::datanavigator::BoolNavigator>(value); + } + case RobotUnitDataStreaming::NodeTypeByte: + { + int value = RobotUnitDataStreamingReceiver::GetAs<Ice::Byte>(timestep, dataEntry); + return std::make_shared<aron::datanavigator::IntNavigator>(value); + } + case RobotUnitDataStreaming::NodeTypeShort: + { + int value = RobotUnitDataStreamingReceiver::GetAs<Ice::Short>(timestep, dataEntry); + return std::make_shared<aron::datanavigator::IntNavigator>(value); + } + case RobotUnitDataStreaming::NodeTypeInt: + { + int value = RobotUnitDataStreamingReceiver::GetAs<Ice::Int>(timestep, dataEntry); + return std::make_shared<aron::datanavigator::IntNavigator>(value); + } + case RobotUnitDataStreaming::NodeTypeLong: + { + long value = RobotUnitDataStreamingReceiver::GetAs<Ice::Long>(timestep, dataEntry); + return std::make_shared<aron::datanavigator::LongNavigator>(value); + } + case RobotUnitDataStreaming::NodeTypeDouble: + { + double value = RobotUnitDataStreamingReceiver::GetAs<Ice::Double>(timestep, dataEntry); + return std::make_shared<aron::datanavigator::DoubleNavigator>(value); + } + default: + ARMARX_UNEXPECTED_ENUM_VALUE(RobotUnitDataStreaming::NodeType, dataEntry.type); + } + } + + + const simox::meta::EnumNames<RobotUnitDataStreaming::DataEntryType> RobotUnitDataStreaming::DataEntryNames = + { + { NodeTypeBool, "Bool" }, + { NodeTypeByte, "Byte" }, + { NodeTypeShort, "Short" }, + { NodeTypeInt, "Int" }, + { NodeTypeLong, "Long" }, + { NodeTypeFloat, "Float" }, + { NodeTypeDouble, "Double" }, + }; + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..dd2177c9e2f167af3946119f381dcd7ec43d170c --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/aron_conversions.h @@ -0,0 +1,23 @@ +#pragma once + +#include <memory> + +#include <SimoxUtility/meta/enum/EnumNames.hpp> + +#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h> + + +namespace armarx::aron::datanavigator +{ + using NavigatorPtr = std::shared_ptr<class Navigator>; +} + +namespace armarx::RobotUnitDataStreaming +{ + aron::datanavigator::NavigatorPtr toAron( + const TimeStep& timestep, + const DataEntry& dataEntry); + + extern const simox::meta::EnumNames<DataEntryType> DataEntryNames; + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/Armar6Converter.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/Armar6Converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c7171a746e0815d2fca648f2b91e0faa31a669e --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/Armar6Converter.cpp @@ -0,0 +1,209 @@ +#include "Armar6Converter.h" + +#include <SimoxUtility/algorithm/get_map_keys_values.h> +#include <SimoxUtility/algorithm/advanced.h> + +#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h> +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> + +#include "ConverterTools.h" + + +namespace armarx::armem::server::robot_state::proprioception +{ + + Armar6Converter::Armar6Converter() : + tools(std::make_unique<ConverterTools>()) + { + } + + + Armar6Converter::~Armar6Converter() + { + } + + + aron::datanavigator::DictNavigatorPtr + Armar6Converter::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}); + } + return dto.toAron(); + } + + + void Armar6Converter::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}; + ARMARX_CHECK_GREATER(acceptedSizes.count(split.size()), 0) + << "Data entry name could not be parsed (exected 3 or 4 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 + { + // Joint + bool processed = processJointEntry(dto.joints, split, value); + + if (!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: + break; + } + } + } + } + + + + void Armar6Converter::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 Armar6Converter::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 Armar6Converter::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; + dto.extra[key] = getValueAs<float>(value); + } + } + + + bool Armar6Converter::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/Armar6Converter.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/Armar6Converter.h new file mode 100644 index 0000000000000000000000000000000000000000..f7a0da8f3d166fda4b497fd960398ffd861dfc61 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/Armar6Converter.h @@ -0,0 +1,69 @@ +#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 Armar6Converter : public ConverterInterface + { + public: + + Armar6Converter(); + virtual ~Armar6Converter() override; + + + aron::datanavigator::DictNavigatorPtr + 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); + + 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/ConverterInterface.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterInterface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ddf012be951db403448f855966b026efe33ba8f --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterInterface.cpp @@ -0,0 +1,11 @@ +#include "ConverterInterface.h" + + +namespace armarx::armem::server::robot_state::proprioception +{ + + ConverterInterface::~ConverterInterface() + { + } + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterInterface.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..1162623895611e89d69740f6bf7d014c325f1427 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterInterface.h @@ -0,0 +1,36 @@ +#pragma once + +#include <memory> + + +namespace armarx::RobotUnitDataStreaming +{ + struct TimeStep; + struct DataStreamingDescription; + struct DataEntry; +} +namespace armarx::armem::arondto +{ + class Proprioception; +} +namespace armarx::aron::datanavigator +{ + using DictNavigatorPtr = std::shared_ptr<class DictNavigator>; +} + +namespace armarx::armem::server::robot_state::proprioception +{ + class ConverterInterface + { + public: + + virtual ~ConverterInterface(); + + virtual + aron::datanavigator::DictNavigatorPtr convert( + const RobotUnitDataStreaming::TimeStep& data, + const RobotUnitDataStreaming::DataStreamingDescription& description) = 0; + + }; +} + 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 new file mode 100644 index 0000000000000000000000000000000000000000..a04ca4cbab6b876b3eb2e8f146ca7858a35f0bc4 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.cpp @@ -0,0 +1,30 @@ +#include "ConverterRegistry.h" + +#include "Armar6Converter.h" + +#include <SimoxUtility/algorithm/get_map_keys_values.h> + + +namespace armarx::armem::server::robot_state::proprioception +{ + + ConverterRegistry::ConverterRegistry() + { + add<Armar6Converter>("Armar6"); + } + + + ConverterInterface* + ConverterRegistry::get(const std::string& key) const + { + auto it = converters.find(key); + return it != converters.end() ? it->second.get() : nullptr; + } + + + std::vector<std::string> ConverterRegistry::getKeys() const + { + return simox::alg::get_keys(converters); + } + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.h new file mode 100644 index 0000000000000000000000000000000000000000..f62f808f6ee305f67aba8ba0bff24e414baaa802 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterRegistry.h @@ -0,0 +1,37 @@ +#pragma once + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "ConverterInterface.h" + + +namespace armarx::armem::server::robot_state::proprioception +{ + class ConverterRegistry + { + public: + + ConverterRegistry(); + + + template <class ConverterT, class ...Args> + void add(const std::string& key, Args... args) + { + converters[key].reset(new ConverterT(args...)); + } + + + ConverterInterface* get(const std::string& key) const; + std::vector<std::string> getKeys() const; + + + private: + + std::map<std::string, std::unique_ptr<ConverterInterface>> converters; + + }; +} + diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterTools.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterTools.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7cc2fc128b55dc9af794804cc569d91b75ba7071 --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterTools.cpp @@ -0,0 +1,179 @@ +#include "ConverterTools.h" + +#include <SimoxUtility/algorithm/get_map_keys_values.h> +#include <SimoxUtility/algorithm/advanced.h> + +#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h> +#include <RobotAPI/libraries/aron/core/navigator/data/container/Dict.h> + + +namespace armarx::armem::server::robot_state +{ + + std::optional<std::string> + proprioception::findByPrefix(const std::string& key, const std::set<std::string>& prefixes) + { + for (const auto& prefix : prefixes) + { + if (simox::alg::starts_with(key, prefix)) + { + return prefix; + } + } + return std::nullopt; + } +} + + +namespace armarx::armem::server::robot_state::proprioception +{ + ConverterTools::ConverterTools() + { + { + vector3fSetters["X"] = [](Eigen::Vector3f & v, float f) + { + v.x() = f; + }; + vector3fSetters["Y"] = [](Eigen::Vector3f & v, float f) + { + v.y() = f; + }; + vector3fSetters["Z"] = [](Eigen::Vector3f & v, float f) + { + v.z() = f; + }; + vector3fSetters["x"] = vector3fSetters["X"]; + vector3fSetters["y"] = vector3fSetters["Y"]; + vector3fSetters["z"] = vector3fSetters["Z"]; + vector3fSetters["Rotation"] = vector3fSetters["Z"]; + } + { + platformPoseGetters["acceleration"] = [](prop::arondto::Platform & p) + { + return &p.acceleration; + }; + platformPoseGetters["relativePosition"] = [](prop::arondto::Platform & p) + { + return &p.relativePosition; + }; + platformPoseGetters["velocity"] = [](prop::arondto::Platform & p) + { + return &p.velocity; + }; + platformIgnored.insert("absolutePosition"); + } + { + ftGetters["gravCompF"] = [](prop::arondto::ForceTorque & ft) + { + return &ft.gravityCompensationForce; + }; + ftGetters["gravCompT"] = [](prop::arondto::ForceTorque & ft) + { + return &ft.gravityCompensationTorque; + }; + ftGetters["f"] = [](prop::arondto::ForceTorque & ft) + { + return &ft.force; + }; + ftGetters["t"] = [](prop::arondto::ForceTorque & ft) + { + return &ft.torque; + }; + } + { + jointGetters["acceleration"] = [](prop::arondto::Joints & j) + { + return &j.acceleration; + }; + jointGetters["gravityTorque"] = [](prop::arondto::Joints & j) + { + return &j.gravityTorque; + }; + jointGetters["inertiaTorque"] = [](prop::arondto::Joints & j) + { + return &j.inertiaTorque; + }; + jointGetters["inverseDynamicsTorque"] = [](prop::arondto::Joints & j) + { + return &j.inverseDynamicsTorque; + }; + jointGetters["position"] = [](prop::arondto::Joints & j) + { + return &j.position; + }; + jointGetters["torque"] = [](prop::arondto::Joints & j) + { + return &j.torque; + }; + jointGetters["velocity"] = [](prop::arondto::Joints & j) + { + return &j.velocity; + }; + } + { + +#define ADD_SCALAR_SETTER(container, name, type) \ + container [ #name ] = []( \ + prop::arondto::Joints & dto, \ + const std::vector<std::string>& split, \ + const ConverterValue & value) \ + { \ + dto. name [split.at(1)] = getValueAs< type >(value); \ + } + + ADD_SCALAR_SETTER(jointSetters, position, float); + ADD_SCALAR_SETTER(jointSetters, velocity, float); + ADD_SCALAR_SETTER(jointSetters, acceleration, float); + + ADD_SCALAR_SETTER(jointSetters, relativePosition, float); + ADD_SCALAR_SETTER(jointSetters, filteredVelocity, float); + + ADD_SCALAR_SETTER(jointSetters, currentTarget, float); + ADD_SCALAR_SETTER(jointSetters, positionTarget, float); + ADD_SCALAR_SETTER(jointSetters, velocityTarget, float); + + ADD_SCALAR_SETTER(jointSetters, torque, float); + ADD_SCALAR_SETTER(jointSetters, inertiaTorque, float); + ADD_SCALAR_SETTER(jointSetters, gravityTorque, float); + ADD_SCALAR_SETTER(jointSetters, gravityCompensatedTorque, float); + ADD_SCALAR_SETTER(jointSetters, inverseDynamicsTorque, float); + ADD_SCALAR_SETTER(jointSetters, torqueTicks, int); + + ADD_SCALAR_SETTER(jointSetters, positionTarget, float); + ADD_SCALAR_SETTER(jointSetters, currentTarget, float); + ADD_SCALAR_SETTER(jointSetters, positionTarget, float); + + // "temperature" handled below + // ADD_SCALAR_SETTER(jointSetters, temperature, float); + + ADD_SCALAR_SETTER(jointSetters, motorCurrent, float); + ADD_SCALAR_SETTER(jointSetters, maxTargetCurrent, float); + + ADD_SCALAR_SETTER(jointSetters, sensorBoardUpdateRate, float); + ADD_SCALAR_SETTER(jointSetters, I2CUpdateRate, float); + + ADD_SCALAR_SETTER(jointSetters, JointStatusEmergencyStop, bool); + ADD_SCALAR_SETTER(jointSetters, JointStatusEnabled, bool); + ADD_SCALAR_SETTER(jointSetters, JointStatusError, int); + ADD_SCALAR_SETTER(jointSetters, JointStatusOperation, int); + + +#define ADD_VECTOR3_SETTER(container, name, type) \ + container [ #name ] = [this]( \ + prop::arondto::Joints & dto, \ + const std::vector<std::string>& split, \ + const ConverterValue & value) \ + { \ + auto& vec = dto. name [split.at(1)]; \ + auto& setter = this->vector3fSetters.at(split.at(3)); \ + setter(vec, getValueAs< type >(value)); \ + } + + ADD_VECTOR3_SETTER(jointSetters, angularVelocity, float); + ADD_VECTOR3_SETTER(jointSetters, linearAcceleration, float); + + // ADD_GETTER(jointVectorGetters, orientation, float); + } + } + +} diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterTools.h b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterTools.h new file mode 100644 index 0000000000000000000000000000000000000000..ff667a1b578c074126e2a2bfb5db9100dafa964d --- /dev/null +++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/converters/ConverterTools.h @@ -0,0 +1,107 @@ +#pragma once + +#include <map> +#include <set> +#include <string> + +#include <Eigen/Core> + +#include <SimoxUtility/algorithm/string/string_tools.h> + +#include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h> +#include <RobotAPI/libraries/RobotUnitDataStreamingReceiver/RobotUnitDataStreamingReceiver.h> + +#include "ConverterInterface.h" + + +namespace armarx::armem::server::robot_state::proprioception +{ + + struct ConverterValue + { + const RobotUnitDataStreaming::TimeStep& data; + const RobotUnitDataStreaming::DataEntry& entry; + }; + + + template <class T> + T + getValueAs(const ConverterValue& value) + { + return RobotUnitDataStreamingReceiver::GetAs<T>(value.data, value.entry); + } + + + /** + * @brief Search + * @param key + * @param prefixes + * @return + */ + std::optional<std::string> + findByPrefix(const std::string& key, const std::set<std::string>& prefixes); + + + template <class ValueT> + ValueT + findByPrefix(const std::string& key, const std::map<std::string, ValueT>& map) + { + for (const auto& [prefix, value] : map) + { + if (simox::alg::starts_with(key, prefix)) + { + return value; + } + } + return nullptr; + } + + + template <class ValueT> + ValueT + findBySuffix(const std::string& key, const std::map<std::string, ValueT>& map) + { + for (const auto& [suffix, value] : map) + { + if (simox::alg::ends_with(key, suffix)) + { + return value; + } + } + return nullptr; + } + + + + class ConverterTools + { + public: + + ConverterTools(); + + + public: + + std::map<std::string, std::function<void(Eigen::Vector3f&, float)> > vector3fSetters; + + std::map<std::string, std::function<std::map<std::string, float>*(prop::arondto::Joints&)> > jointGetters; + std::map<std::string, std::function<std::map<std::string, Eigen::Vector3f>*(prop::arondto::Joints&)> > jointVectorGetters; + + using JointSetter = std::function<void(prop::arondto::Joints& dto, const std::vector<std::string>& split, const ConverterValue& value)>; + std::map<std::string, JointSetter> jointSetters; + + std::map<std::string, std::function<Eigen::Vector3f*(prop::arondto::Platform&)> > platformPoseGetters; + std::set<std::string> platformIgnored; + + std::map<std::string, std::function<Eigen::Vector3f*(prop::arondto::ForceTorque&)> > ftGetters; + + + std::map<std::string, std::string> sidePrefixMap + { + { "R", "Right" }, + { "L", "Left" }, + }; + + }; +} + diff --git a/source/RobotAPI/libraries/armem_vision/client/laser_scans/Reader.cpp b/source/RobotAPI/libraries/armem_vision/client/laser_scans/Reader.cpp index 9c46b0c4729dfe6ca038c1f31ef81255f56d4968..4bc22306d7d26603d1edba2c8fc8f8aed40b1a8d 100644 --- a/source/RobotAPI/libraries/armem_vision/client/laser_scans/Reader.cpp +++ b/source/RobotAPI/libraries/armem_vision/client/laser_scans/Reader.cpp @@ -33,22 +33,20 @@ #include <RobotAPI/libraries/aron/core/navigator/data/complex/NDArray.h> // RobotAPI Armem +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/util/util.h> + #include <RobotAPI/libraries/armem/client/Query.h> #include <RobotAPI/libraries/armem/client/Reader.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/selectors.h> -#include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Entity.h> -#include <RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h> -#include <RobotAPI/libraries/armem/util/util.h> #include <RobotAPI/libraries/armem_vision/aron/LaserScan.aron.generated.h> #include <RobotAPI/libraries/armem_vision/aron_conversions.h> #include <RobotAPI/libraries/armem_vision/types.h> + namespace armarx::armem::vision::laser_scans::client { @@ -124,11 +122,10 @@ namespace armarx::armem::vision::laser_scans::client } std::vector<LaserScanStamped> - asLaserScans(const std::map<std::string, wm::Entity>& entities) + asLaserScans(const wm::ProviderSegment& providerSegment) { std::vector<LaserScanStamped> outV; - - if (entities.empty()) + if (providerSegment.empty()) { ARMARX_WARNING << "No entities!"; } @@ -153,29 +150,25 @@ namespace armarx::armem::vision::laser_scans::client }; // loop over all entities and their snapshots - for (const auto& [s, entity] : entities) + providerSegment.forEachEntity([&outV, &convert](const wm::Entity & entity) { + // If we don't need this warning, we could directly iterate over the snapshots. if (entity.empty()) { - ARMARX_WARNING << "Empty history for " << s; + ARMARX_WARNING << "Empty history for " << entity.id(); } - ARMARX_DEBUG << "History size: " << entity.size(); - for (const auto& [ss, entitySnapshot] : entity) + entity.forEachInstance([&outV, &convert](const wm::EntityInstance & entityInstance) { - for (const auto& entityInstance : entitySnapshot.instances()) + if (const auto o = tryCast<arondto::LaserScanStamped>(entityInstance)) { - const auto o = - tryCast<arondto::LaserScanStamped>(entityInstance); - - if (o) - { - outV.push_back(convert(*o, entityInstance)); - } + outV.push_back(convert(*o, entityInstance)); } - } - } + return true; + }); + return true; + }); return outV; } @@ -202,13 +195,16 @@ namespace armarx::armem::vision::laser_scans::client } // now create result from memory - const auto& entities = - qResult.memory.getCoreSegment(properties.memoryName) - .getProviderSegment(query.agent) - .entities(); + const wm::ProviderSegment& providerSegment = + qResult.memory.getCoreSegment(properties.memoryName).getProviderSegment(query.agent); - const auto laserScans = asLaserScans(entities); - const auto sensors = simox::alg::get_keys(entities); + const auto laserScans = asLaserScans(providerSegment); + std::vector<std::string> sensors; + providerSegment.forEachEntity([&sensors](const wm::Entity & entity) + { + sensors.push_back(entity.name()); + return true; + }); return {.laserScans = laserScans, .sensors = sensors, diff --git a/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp b/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp index 7358e504ffecf3a2a710bd77b1631437e3818a42..861e02c4c9fcabbc40caebba3451b69e81e5016c 100644 --- a/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp +++ b/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp @@ -1,7 +1,7 @@ #include "Writer.h" #include <RobotAPI/libraries/armem/core/error.h> -#include "RobotAPI/libraries/armem_vision/aron_conversions.h" +#include <RobotAPI/libraries/armem_vision/aron_conversions.h> #include <RobotAPI/libraries/armem_vision/aron/LaserScan.aron.generated.h> diff --git a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.cpp b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.cpp index ba7edf547d1d45873609d723b92934b18d7f5c88..717a2ec98e5283515a5454bfa31eb7c00636b01c 100644 --- a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.cpp +++ b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.cpp @@ -19,13 +19,13 @@ #include <SimoxUtility/algorithm/get_map_keys_values.h> // ArmarXCore -#include "ArmarXCore/core/exceptions/LocalException.h" +#include <ArmarXCore/core/exceptions/LocalException.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> #include <ArmarXCore/core/logging/LogSender.h> #include <ArmarXCore/core/logging/Logging.h> // RobotAPI Interfaces -#include "RobotAPI/libraries/aron/converter/eigen/EigenConverter.h" +#include <RobotAPI/libraries/aron/converter/eigen/EigenConverter.h> #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h> #include <RobotAPI/interface/armem/server/ReadingMemoryInterface.h> #include <RobotAPI/interface/units/LaserScannerUnit.h> @@ -40,11 +40,7 @@ #include <RobotAPI/libraries/armem/client/Reader.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/client/query/selectors.h> -#include <RobotAPI/libraries/armem/core/workingmemory/CoreSegment.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Entity.h> -#include <RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h> -#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> -#include <RobotAPI/libraries/armem/core/workingmemory/ProviderSegment.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/util/util.h> #include <RobotAPI/libraries/armem_vision/aron/LaserScan.aron.generated.h> #include <RobotAPI/libraries/armem_vision/aron_conversions.h> @@ -68,20 +64,23 @@ namespace armarx::armem::vision::occupancy_grid::client return qb; } - OccupancyGrid asOccupancyGrid(const std::map<std::string, wm::Entity>& entities) + OccupancyGrid asOccupancyGrid(const wm::ProviderSegment& providerSegment) { - ARMARX_CHECK(not entities.empty()) << "No entities"; - ARMARX_CHECK(entities.size() == 1) << "There should be only one entity!"; + ARMARX_CHECK(not providerSegment.empty()) << "No entities"; + ARMARX_CHECK(providerSegment.size() == 1) << "There should be only one entity!"; - const wm::Entity& entity = entities.begin()->second; - ARMARX_CHECK(not entity.empty()) << "No snapshots"; - - const auto& entitySnapshot = entity.getLatestSnapshot(); - ARMARX_CHECK(not entitySnapshot.empty()) << "No entity snapshot instances"; + const wm::EntityInstance* entityInstance = nullptr; + providerSegment.forEachEntity([&entityInstance](const wm::Entity & entity) + { + const auto& entitySnapshot = entity.getLatestSnapshot(); + ARMARX_CHECK(not entitySnapshot.empty()) << "No entity snapshot instances"; - const auto& entityInstance = entitySnapshot.instances().front(); + entityInstance = &entitySnapshot.getInstance(0); + return false; + }); + ARMARX_CHECK_NOT_NULL(entityInstance); - const auto aronDto = tryCast<arondto::OccupancyGrid>(entityInstance); + const auto aronDto = tryCast<arondto::OccupancyGrid>(*entityInstance); ARMARX_CHECK(aronDto) << "Failed casting to OccupancyGrid"; OccupancyGrid occupancyGrid; @@ -89,7 +88,7 @@ namespace armarx::armem::vision::occupancy_grid::client // direct access to grid data const auto ndArrayNavigator = aron::datanavigator::NDArrayNavigator::DynamicCast( - entityInstance.data()->getElement("grid")); + entityInstance->data()->getElement("grid")); ARMARX_CHECK_NOT_NULL(ndArrayNavigator); occupancyGrid.grid = aron::converter::AronEigenConverter::ConvertToArray<float>(*ndArrayNavigator); @@ -118,11 +117,10 @@ namespace armarx::armem::vision::occupancy_grid::client } // now create result from memory - const auto& entities = qResult.memory.getCoreSegment(properties().memoryName) - .getProviderSegment(query.providerName) - .entities(); + const wm::ProviderSegment& providerSegment = qResult.memory.getCoreSegment(properties().memoryName) + .getProviderSegment(query.providerName); - if (entities.empty()) + if (providerSegment.empty()) { ARMARX_WARNING << "No entities."; return {.occupancyGrid = std::nullopt, @@ -132,7 +130,7 @@ namespace armarx::armem::vision::occupancy_grid::client try { - const auto occupancyGrid = asOccupancyGrid(entities); + const auto occupancyGrid = asOccupancyGrid(providerSegment); return Result{.occupancyGrid = occupancyGrid, .status = Result::Status::Success}; } diff --git a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.h b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.h index a43c2c7c1151223358d5b1ab608f824fd3cdf66f..eaf9b2fdfa2021db7f8e1215baedc6aba907dec3 100644 --- a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.h +++ b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Reader.h @@ -23,9 +23,9 @@ #include <mutex> -#include "RobotAPI/libraries/armem/client/util/SimpleReaderBase.h" -#include "RobotAPI/libraries/armem/core/Time.h" -#include "RobotAPI/libraries/armem_vision/types.h" +#include <RobotAPI/libraries/armem/client/util/SimpleReaderBase.h> +#include <RobotAPI/libraries/armem/core/Time.h> +#include <RobotAPI/libraries/armem_vision/types.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> namespace armarx::armem::vision::occupancy_grid::client diff --git a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp index f2930f14f479d9ae68ee222f2643edf327392a43..ce5883afb6eeb72c7ebb9337d0b4980eee7e462e 100644 --- a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp +++ b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp @@ -1,8 +1,9 @@ #include "Writer.h" -#include "RobotAPI/libraries/armem_vision/aron_conversions.h" +#include <RobotAPI/libraries/armem_vision/aron_conversions.h> #include <RobotAPI/libraries/armem_vision/aron/OccupancyGrid.aron.generated.h> + namespace armarx::armem::vision::occupancy_grid::client { Writer::~Writer() = default; @@ -67,4 +68,4 @@ namespace armarx::armem::vision::occupancy_grid::client return SimpleWriterBase::Properties{.memoryName = "Vision", .coreSegmentName = "OccupancyGrid"}; } -} // namespace armarx::armem::vision::occupancy_grid::client \ No newline at end of file +} // namespace armarx::armem::vision::occupancy_grid::client diff --git a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.h b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.h index bf1268444c333d10bb3c2f9efb68da11fe697cc8..b2a900321224d2c4617cab541c7b1cf77f41d1f1 100644 --- a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.h +++ b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.h @@ -24,8 +24,8 @@ #include <mutex> -#include "RobotAPI/libraries/armem/client/util/SimpleWriterBase.h" -#include "RobotAPI/libraries/armem_vision/types.h" +#include <RobotAPI/libraries/armem/client/util/SimpleWriterBase.h> +#include <RobotAPI/libraries/armem_vision/types.h> namespace armarx::armem::vision::occupancy_grid::client { diff --git a/source/RobotAPI/libraries/aron/core/CMakeLists.txt b/source/RobotAPI/libraries/aron/core/CMakeLists.txt index 62548c29719f3942afee49a45e9a3f24a4232634..c5282fb54aba97b583f15f2df1876c0dde3e4ead 100644 --- a/source/RobotAPI/libraries/aron/core/CMakeLists.txt +++ b/source/RobotAPI/libraries/aron/core/CMakeLists.txt @@ -151,6 +151,7 @@ set(LIB_HEADERS navigator/data/primitive/Bool.h navigator/data/AllNavigators.h navigator/data/NavigatorFactory.h + navigator/data/forward_declarations.h navigator/type/Navigator.h navigator/type/detail/NavigatorBase.h @@ -181,6 +182,7 @@ set(LIB_HEADERS navigator/type/primitive/Time.h navigator/type/AllNavigators.h navigator/type/NavigatorFactory.h + navigator/type/forward_declarations.h navigator/visitors/DataVisitor.h navigator/visitors/TypedDataVisitor.h diff --git a/source/RobotAPI/libraries/aron/core/Randomizer.h b/source/RobotAPI/libraries/aron/core/Randomizer.h index bdc05099f108f0abaecb8db68cc58f47b8688a6c..00f355baa9c01e66792a886b027ad4186b808016 100644 --- a/source/RobotAPI/libraries/aron/core/Randomizer.h +++ b/source/RobotAPI/libraries/aron/core/Randomizer.h @@ -55,6 +55,7 @@ namespace armarx::aron { nextMaybeType = getRandomElement(type::ALL_MAYBE_TYPES); } + (void) nextMaybeType; // Unused switch (nextType) { diff --git a/source/RobotAPI/libraries/aron/core/navigator/data/forward_declarations.h b/source/RobotAPI/libraries/aron/core/navigator/data/forward_declarations.h new file mode 100644 index 0000000000000000000000000000000000000000..d76939c317aafd2acc4eb797d38d1ba1ff96da26 --- /dev/null +++ b/source/RobotAPI/libraries/aron/core/navigator/data/forward_declarations.h @@ -0,0 +1,22 @@ +#pragma once + +#include <memory> + + +namespace armarx::aron::datanavigator +{ + class Navigator; + using NavigatorPtr = std::shared_ptr<Navigator>; + + using DictNavigatorPtr = std::shared_ptr<class DictNavigator>; + using ListNavigatorPtr = std::shared_ptr<class ListNavigator>; + using NDArrayNavigatorPtr = std::shared_ptr<class NDArrayNavigator>; + + using IntNavigatorPtr = std::shared_ptr<class IntNavigator>; + using LongNavigatorPtr = std::shared_ptr<class LongNavigator>; + using FloatNavigatorPtr = std::shared_ptr<class FloatNavigator>; + using DoubleNavigatorPtr = std::shared_ptr<class DoubleNavigator>; + using StringNavigatorPtr = std::shared_ptr<class StringNavigator>; + using BoolNavigatorPtr = std::shared_ptr<class BoolNavigator>; + +} diff --git a/source/RobotAPI/libraries/aron/core/navigator/type/AllNavigators.h b/source/RobotAPI/libraries/aron/core/navigator/type/AllNavigators.h index 51ea5a762037da7b7e4a3808c42d36a468d9c6b1..82702de998bb7e6b0972afd9e96ae027b433eae3 100644 --- a/source/RobotAPI/libraries/aron/core/navigator/type/AllNavigators.h +++ b/source/RobotAPI/libraries/aron/core/navigator/type/AllNavigators.h @@ -12,7 +12,6 @@ #include "ndarray/OpenCVMat.h" #include "ndarray/Orientation.h" #include "ndarray/PCLPointCloud.h" -#include "ndarray/PCLPointCloud.h" #include "ndarray/Pose.h" #include "ndarray/Position.h" #include "enum/IntEnum.h" diff --git a/source/RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h b/source/RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h new file mode 100644 index 0000000000000000000000000000000000000000..af5d62e7c0decbc296cea942fa1983b0e0cb5924 --- /dev/null +++ b/source/RobotAPI/libraries/aron/core/navigator/type/forward_declarations.h @@ -0,0 +1,34 @@ +#pragma once + +#include <memory> + + +namespace armarx::aron::typenavigator +{ + using NavigatorPtr = std::shared_ptr<class Navigator>; + + using DictNavigatorPtr = std::shared_ptr<class DictNavigator>; + using ListNavigatorPtr = std::shared_ptr<class ListNavigator>; + using ObjectNavigatorPtr = std::shared_ptr<class ObjectNavigator>; + using PoseNavigatorPtr = std::shared_ptr<class PoseNavigator>; + using TupleNavigatorPtr = std::shared_ptr<class TupleNavigator>; + using NDArrayNavigatorPtr = std::shared_ptr<class NDArrayNavigator>; + using EigenMatrixNavigatorPtr = std::shared_ptr<class EigenMatrixNavigator>; + using EigenQuaternionNavigatorPtr = std::shared_ptr<class EigenQuaternionNavigator>; + using IVTCByteImageNavigatorPtr = std::shared_ptr<class IVTCByteImageNavigator>; + using OpenCVMatNavigatorPtr = std::shared_ptr<class OpenCVMatNavigator>; + using OrientationNavigatorPtr = std::shared_ptr<class OrientationNavigator>; + using PCLPointCloudNavigatorPtr = std::shared_ptr<class PCLPointCloudNavigator>; + using PositionNavigatorPtr = std::shared_ptr<class PositionNavigator>; + using IntEnumNavigatorPtr = std::shared_ptr<class IntEnumNavigator>; + + using IntNavigatorPtr = std::shared_ptr<class IntNavigator>; + using LongNavigatorPtr = std::shared_ptr<class LongNavigator>; + using FloatNavigatorPtr = std::shared_ptr<class FloatNavigator>; + using DoubleNavigatorPtr = std::shared_ptr<class DoubleNavigator>; + using StringNavigatorPtr = std::shared_ptr<class StringNavigator>; + using BoolNavigatorPtr = std::shared_ptr<class BoolNavigator>; + using TimeNavigatorPtr = std::shared_ptr<class TimeNavigator>; + +} +