diff --git a/source/armarx/navigation/components/CMakeLists.txt b/source/armarx/navigation/components/CMakeLists.txt index 3f13b4075fcc101ef311ed6eb3a35b6e19fff0b3..24217c76ffe05bd0d939b973c210c90a50a47d6d 100644 --- a/source/armarx/navigation/components/CMakeLists.txt +++ b/source/armarx/navigation/components/CMakeLists.txt @@ -4,4 +4,5 @@ add_subdirectory(Navigator) add_subdirectory(dynamic_distance_to_obstacle_costmap_provider) -add_subdirectory(dynamic_scene_provider) \ No newline at end of file +add_subdirectory(dynamic_scene_provider) +add_subdirectory(distance_to_obstacle_costmap_provider) \ No newline at end of file diff --git a/source/armarx/navigation/components/NavigationMemory/CMakeLists.txt b/source/armarx/navigation/components/NavigationMemory/CMakeLists.txt index 06bd40803f1b508891608aadd055e0e24138d3fe..3f8da95e6b5031113f57c490131c7b1abc9d6e52 100644 --- a/source/armarx/navigation/components/NavigationMemory/CMakeLists.txt +++ b/source/armarx/navigation/components/NavigationMemory/CMakeLists.txt @@ -17,6 +17,7 @@ armarx_add_component(navigation_memory ## NavigationMemoryInterfaces # If you defined a component ice interface above. armarx_navigation::graph armarx_navigation::location + armarx_navigation::algorithms SOURCES NavigationMemory.cpp diff --git a/source/armarx/navigation/components/NavigationMemory/NavigationMemory.cpp b/source/armarx/navigation/components/NavigationMemory/NavigationMemory.cpp index 0189ad50d31ceb690c348cf8a7637a6ce4f9ac23..a18764b02624ec4abf73fd5af497d82b2018aaa3 100644 --- a/source/armarx/navigation/components/NavigationMemory/NavigationMemory.cpp +++ b/source/armarx/navigation/components/NavigationMemory/NavigationMemory.cpp @@ -27,6 +27,8 @@ #include <fstream> #include <iostream> +#include "ArmarXCore/core/time/Metronome.h" +#include "ArmarXCore/core/time/forward_declarations.h" #include <ArmarXCore/core/system/ArmarXDataPath.h> #include <ArmarXCore/core/time/CycleUtil.h> #include <ArmarXCore/libraries/DecoupledSingleComponent/Decoupled.h> @@ -429,7 +431,9 @@ namespace armarx::navigation { memory::Visu visu{arviz, workingMemory().getCoreSegment(navigation::location::coreSegmentID), - workingMemory().getCoreSegment(navigation::graph::coreSegmentID)}; + workingMemory().getCoreSegment(navigation::graph::coreSegmentID), + workingMemory().getCoreSegment(memory::constants::CostmapCoreSegmentName)}; + Properties::LocationGraph p; { @@ -437,7 +441,7 @@ namespace armarx::navigation p = properties.locationGraph; } - CycleUtil cycle(static_cast<int>(1000 / p.visuFrequency)); + Metronome metronome(Frequency::HertzDouble(p.visuFrequency)); while (tasks.visuTask and not tasks.visuTask->isStopped()) { ARMARX_TRACE; @@ -455,9 +459,12 @@ namespace armarx::navigation // Graph Edges visu.drawGraphs(layers, p.visuGraphEdges); + // Costmaps + visu.drawCostmaps(layers, p.visuCostmaps); + arviz.commit(layers); - cycle.waitForCycleDuration(); + metronome.waitForNextTick(); } } diff --git a/source/armarx/navigation/components/NavigationMemory/NavigationMemory.h b/source/armarx/navigation/components/NavigationMemory/NavigationMemory.h index 0b4b95a51b1e544ebfaaa2e0401a8b69ae554e8d..c67da7fc5981fd4044b04ab936c5c4126fd5ee32 100644 --- a/source/armarx/navigation/components/NavigationMemory/NavigationMemory.h +++ b/source/armarx/navigation/components/NavigationMemory/NavigationMemory.h @@ -96,6 +96,8 @@ namespace armarx::navigation { bool visuLocations = true; bool visuGraphEdges = true; + bool visuCostmaps = true; + float visuFrequency = 2; }; LocationGraph locationGraph; diff --git a/source/armarx/navigation/components/NavigationMemory/Visu.cpp b/source/armarx/navigation/components/NavigationMemory/Visu.cpp index 07f364bc81a7a9aa862ffe3a0f0f253321468c16..73df72debcb1eabe837036c877fd856d94029151 100644 --- a/source/armarx/navigation/components/NavigationMemory/Visu.cpp +++ b/source/armarx/navigation/components/NavigationMemory/Visu.cpp @@ -22,8 +22,14 @@ #include "Visu.h" +#include <SimoxUtility/color/cmaps/colormaps.h> + +#include "RobotAPI/components/ArViz/Client/Layer.h" #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> +#include "armarx/navigation/conversions/eigen.h" +#include <armarx/navigation/algorithms/aron/Costmap.aron.generated.h> +#include <armarx/navigation/algorithms/aron_conversions.h> #include <armarx/navigation/core/Graph.h> #include <armarx/navigation/core/aron/Graph.aron.generated.h> #include <armarx/navigation/core/aron/Location.aron.generated.h> @@ -35,10 +41,12 @@ namespace armarx::navigation::memory Visu::Visu(viz::Client arviz, const armem::server::wm::CoreSegment& locSegment, - const armem::server::wm::CoreSegment& graphSegment) : + const armem::server::wm::CoreSegment& graphSegment, + const armem::server::wm::CoreSegment& costmapSegment) : arviz(arviz), locSegment(locSegment), graphSegment(graphSegment), + costmapSegment(costmapSegment), visu(std::make_unique<graph::GraphVisu>()) { } @@ -117,4 +125,87 @@ namespace armarx::navigation::memory } } + namespace + { + + void + visualize(const algorithms::Costmap& costmap, viz::Layer& layer, const std::string& name) + { + const auto cmap = simox::color::cmaps::viridis(); + const float vmax = costmap.getGrid().array().maxCoeff(); + + const auto asColor = [&cmap, &vmax](const float distance) -> viz::data::Color + { + const auto color = cmap.at(distance, 0.F, vmax); + return {color.a, color.r, color.g, color.b}; + }; + + const std::int64_t cols = costmap.getGrid().cols(); + const std::int64_t rows = costmap.getGrid().rows(); + + auto mesh = viz::Mesh(name); + + std::vector<std::vector<Eigen::Vector3f>> vertices; + std::vector<std::vector<viz::data::Color>> colors; + + for (int r = 0; r < rows; r++) + { + auto& verticesRow = vertices.emplace_back(cols); + auto& colorsRow = colors.emplace_back(cols); + + for (int c = 0; c < cols; c++) + { + verticesRow.at(c) = conv::to3D(costmap.toPositionGlobal({r, c})); + colorsRow.at(c) = asColor(costmap.getGrid()(r, c)); + } + } + + mesh.grid2D(vertices, colors); + + layer.add(mesh); + } + + } // namespace + + void + Visu::drawCostmaps(std::vector<viz::Layer>& layers, bool enabled) + { + if (not enabled) + { + return; + } + + std::map<std::string, std::vector<std::pair<std::string, algorithms::Costmap>>> + namedProviderCostmaps; + + costmapSegment.doLocked( + [&]() + { + using namespace armem::server; + + costmapSegment.forEachEntity( + [&](const wm::Entity& entity) + { + if (const wm::EntityInstance* instance = entity.findLatestInstance()) + { + navigation::algorithms::Costmap costmap = + algorithms::fromAron(*instance); + + namedProviderCostmaps[instance->id().providerSegmentName].emplace_back( + instance->id().entityName, std::move(costmap)); + } + }); + }); + + for (const auto& [providerName, namedCostmaps] : namedProviderCostmaps) + { + viz::Layer& layer = layers.emplace_back(arviz.layer("costmaps_" + providerName)); + for (const auto& [name, costmap] : namedCostmaps) + { + visualize(costmap, layer, name); + } + } + } + + } // namespace armarx::navigation::memory diff --git a/source/armarx/navigation/components/NavigationMemory/Visu.h b/source/armarx/navigation/components/NavigationMemory/Visu.h index f28fa6d8c7a2a208596e835003d76b19a49c2f33..cfd732adeb4ab69ffe8cc284e830ccff0898a418 100644 --- a/source/armarx/navigation/components/NavigationMemory/Visu.h +++ b/source/armarx/navigation/components/NavigationMemory/Visu.h @@ -25,8 +25,10 @@ #include <memory> #include <vector> +#include "RobotAPI/libraries/armem/server/wm/memory_definitions.h" #include <RobotAPI/components/ArViz/Client/Client.h> #include <RobotAPI/libraries/armem/core/forward_declarations.h> +#include "armarx/navigation/algorithms/Costmap.h" namespace armarx::navigation::graph @@ -42,12 +44,14 @@ namespace armarx::navigation::memory public: Visu(viz::Client arviz, const armem::server::wm::CoreSegment& locSegment, - const armem::server::wm::CoreSegment& graphSegment); + const armem::server::wm::CoreSegment& graphSegment, + const armem::server::wm::CoreSegment& costmapSegment); ~Visu(); void drawLocations(std::vector<viz::Layer>& layers, bool enabled); void drawGraphs(std::vector<viz::Layer>& layers, bool enabled); + void drawCostmaps(std::vector<viz::Layer>& layers, bool enabled); public: @@ -55,6 +59,7 @@ namespace armarx::navigation::memory const armem::server::wm::CoreSegment& locSegment; const armem::server::wm::CoreSegment& graphSegment; + const armem::server::wm::CoreSegment& costmapSegment; std::unique_ptr<navigation::graph::GraphVisu> visu; }; diff --git a/source/armarx/navigation/components/Navigator/Navigator.cpp b/source/armarx/navigation/components/Navigator/Navigator.cpp index 8b56fd6df57d88dbdb32fde8c7f5d259252eea3e..e10c47a84bf8dbd4cbea320a800f8754972097c0 100644 --- a/source/armarx/navigation/components/Navigator/Navigator.cpp +++ b/source/armarx/navigation/components/Navigator/Navigator.cpp @@ -123,7 +123,6 @@ namespace armarx::navigation::components addPlugin(resultsWriterPlugin); addPlugin(graphReaderPlugin); addPlugin(costmapReaderPlugin); - addPlugin(costmapWriterPlugin); addPlugin(virtualRobotReaderPlugin); @@ -174,7 +173,7 @@ namespace armarx::navigation::components ->getRobotName(); const server::scene_provider::SceneProvider::Config cfg{.robotName = robotName}; - sceneProvider = server::scene_provider::SceneProvider(srv, cfg); + sceneProvider.emplace(srv, cfg); } initializeScene(); @@ -449,46 +448,6 @@ namespace armarx::navigation::components return def; } - void - visualize(const algorithms::Costmap& costmap, viz::Client& arviz, const std::string& name) - { - const auto cmap = simox::color::cmaps::viridis(); - const float vmax = costmap.getGrid().array().maxCoeff(); - - const auto asColor = [&cmap, &vmax](const float distance) -> viz::data::Color - { - const auto color = cmap.at(distance, 0.F, vmax); - return {color.a, color.r, color.g, color.b}; - }; - - auto layer = arviz.layer("costmap_" + name); - - const std::int64_t cols = costmap.getGrid().cols(); - const std::int64_t rows = costmap.getGrid().rows(); - - auto mesh = viz::Mesh(""); - - std::vector<std::vector<Eigen::Vector3f>> vertices; - std::vector<std::vector<viz::data::Color>> colors; - - for (int r = 0; r < rows; r++) - { - auto& verticesRow = vertices.emplace_back(cols); - auto& colorsRow = colors.emplace_back(cols); - - for (int c = 0; c < cols; c++) - { - verticesRow.at(c) = conv::to3D(costmap.toPositionGlobal({r, c})); - colorsRow.at(c) = asColor(costmap.getGrid()(r, c)); - } - } - - mesh.grid2D(vertices, colors); - - layer.add(mesh); - - arviz.commit(layer); - } server::Navigator* components::Navigator::activeNavigator() diff --git a/source/armarx/navigation/components/Navigator/Navigator.h b/source/armarx/navigation/components/Navigator/Navigator.h index d20a21012110ec7f7082edbf7382ee3960b76ef4..4c25c56b64ef136970ad3bbe370166277f0dd5b5 100644 --- a/source/armarx/navigation/components/Navigator/Navigator.h +++ b/source/armarx/navigation/components/Navigator/Navigator.h @@ -42,7 +42,6 @@ #include <RobotAPI/libraries/ArmarXObjects/plugins/ObjectPoseClientPlugin.h> #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h> -#include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotStateComponentPlugin.h> #include <RobotAPI/libraries/RobotAPIComponentPlugins/RobotUnitComponentPlugin.h> #include <RobotAPI/libraries/armem/client/plugins.h> #include <RobotAPI/libraries/armem/client/plugins/ReaderWriterPlugin.h> @@ -54,7 +53,6 @@ #include <armarx/navigation/client/ice/NavigatorInterface.h> #include <armarx/navigation/components/Navigator/RemoteGui.h> #include <armarx/navigation/core/types.h> -#include <armarx/navigation/memory/client/costmap/Writer.h> #include <armarx/navigation/memory/client/graph/Reader.h> #include <armarx/navigation/memory/client/parameterization/Reader.h> #include <armarx/navigation/memory/client/stack_result/Writer.h> @@ -195,8 +193,7 @@ namespace armarx::navigation::components graphReaderPlugin = nullptr; armem::client::plugins::ReaderWriterPlugin<memory::client::costmap::Reader>* costmapReaderPlugin = nullptr; - armem::client::plugins::ReaderWriterPlugin<memory::client::costmap::Writer>* - costmapWriterPlugin = nullptr; + // armem::vision::occupancy_grid::client::Reader occupancyGridReader; // `robot_state` memory reader and writer diff --git a/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/CMakeLists.txt b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a637fdcb41aecd9ca6352882e094fd48f1cd5d5d --- /dev/null +++ b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/CMakeLists.txt @@ -0,0 +1,34 @@ +armarx_add_component(distance_to_obstacle_costmap_provider + ICE_FILES + ComponentInterface.ice + ICE_DEPENDENCIES + ArmarXCoreInterfaces + # RobotAPIInterfaces + # ARON_FILES + # aron/my_type.xml + SOURCES + Component.cpp + HEADERS + Component.h + DEPENDENCIES + # ArmarXCore + ArmarXCore + ## ArmarXCoreComponentPlugins # For DebugObserver plugin. + # ArmarXGui + ## ArmarXGuiComponentPlugins # For RemoteGui plugin. + # RobotAPI + armem_vision + armem_robot_state + armem_robot + ## RobotAPICore + ## RobotAPIInterfaces + RobotAPIComponentPlugins # For ArViz and other plugins. + armarx_navigation::memory + armarx_navigation::algorithms + armarx_navigation::util + # DEPENDENCIES_LEGACY + ## Add libraries that do not provide any targets but ${FOO_*} variables. + # FOO + # If you need a separate shared component library you can enable it with the following flag. + # SHARED_COMPONENT_LIBRARY +) diff --git a/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/Component.cpp b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/Component.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c52b133193dd99f6dca56a5f066149c64e8c14a --- /dev/null +++ b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/Component.cpp @@ -0,0 +1,268 @@ +/** + * 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 navigation::ArmarXObjects::distance_to_obstacle_costmap_provider + * @author Fabian Reister ( fabian dot reister at kit dot edu ) + * @date 2022 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#include "Component.h" + +#include <VirtualRobot/SceneObjectSet.h> + +#include "ArmarXCore/core/Component.h" +#include "ArmarXCore/core/services/tasks/RunningTask.h" +#include "ArmarXCore/core/time/Clock.h" +#include "ArmarXCore/core/time/DateTime.h" +#include <ArmarXCore/libraries/DecoupledSingleComponent/Decoupled.h> + +#include "RobotAPI/libraries/ArmarXObjects/forward_declarations.h" + +#include "armarx/navigation/algorithms/CostmapBuilder.h" +#include "armarx/navigation/util/util.h" + + +namespace armarx::navigation::components::distance_to_obstacle_costmap_provider +{ + Component::Component() + { + addPlugin(virtualRobotReaderPlugin); + addPlugin(costmapWriterPlugin); + } + + + const std::string Component::defaultName = "distance_to_obstacle_costmap_provider"; + + + armarx::PropertyDefinitionsPtr + Component::createPropertyDefinitions() + { + armarx::PropertyDefinitionsPtr def = + new armarx::ComponentPropertyDefinitions(getConfigIdentifier()); + + def->optional(properties.robotName, "p.robotName", "Robot name."); + + return def; + } + + + void + Component::onInitComponent() + { + // Topics and properties defined above are automagically registered. + + // Keep debug observer data until calling `sendDebugObserverBatch()`. + // (Requies the armarx::DebugObserverComponentPluginUser.) + // setDebugObserverBatchModeEnabled(true); + } + + + void + Component::onConnectComponent() + { + // Do things after connecting to topics and components. + + /* (Requies the armarx::DebugObserverComponentPluginUser.) + // Use the debug observer to log data over time. + // 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(); + } + */ + + runningTask = new RunningTask<Component>(this, &Component::run, "createAndStoreCostmap"); + runningTask->start(); + } + + + void + Component::run() + { + // FIXME: whenever the static scene changes, update the costmap + + createAndStoreCostmap(); + } + + bool + Component::createAndStoreCostmap() + { + auto robot = virtualRobotReaderPlugin->get().getRobot( + properties.robotName, + armarx::DateTime::Invalid(), + VirtualRobot::RobotIO::RobotDescription::eCollisionModel); + + const auto objectPoseClient = ObjectPoseClientPluginUser::getClient(); + + const objpose::ObjectPoseSeq objectPoses = objectPoseClient.fetchObjectPoses(); + + // remove those objects that belong to an object dataset. the manipulation object / distance computation is broken + const auto objectPosesStatic = + armarx::navigation::util::filterObjects(objectPoses, {"KIT", "HOPE", "MDB", "YCB"}); + + const auto objects = armarx::navigation::util::asSceneObjects(objectPosesStatic); + + ARMARX_CHECK_NOT_NULL(objects); + ARMARX_INFO << objects->getSize() << " objects in the scene"; + + ARMARX_INFO << "Creating costmap"; + ARMARX_CHECK_NOT_NULL(robot); + + // FIXME: move costmap creation out of this component + // FIXME create costmap writer enum: type of costmaps + algorithms::CostmapBuilder costmapBuilder( + robot, + objects, + algorithms::Costmap::Parameters{.binaryGrid = false, .cellSize = 100}, + "Platform-navigation-colmodel"); + + const auto costmap = costmapBuilder.create(); + + ARMARX_INFO << "Storing costmap in the memory."; + return costmapWriterPlugin->get().store( + costmap, "distance_to_obstacles", getName(), armarx::Clock::Now()); + } + + + void + Component::onDisconnectComponent() + { + runningTask->stop(); + } + + + void + Component::onExitComponent() + { + } + + + std::string + Component::getDefaultName() const + { + return Component::defaultName; + } + + + std::string + Component::GetDefaultName() + { + return Component::defaultName; + } + + + /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) + void + Component::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 + Component::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()) + { + // 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 + Component::drawBoxes(const Component::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) + { + 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); + } + */ + + + ARMARX_REGISTER_COMPONENT_EXECUTABLE(Component, Component::GetDefaultName()); + +} // namespace armarx::navigation::components::distance_to_obstacle_costmap_provider diff --git a/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/Component.h b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/Component.h new file mode 100644 index 0000000000000000000000000000000000000000..bd6a9bee222778d1bf311b5487b2828f036209ce --- /dev/null +++ b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/Component.h @@ -0,0 +1,152 @@ +/** + * 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 navigation::ArmarXObjects::distance_to_obstacle_costmap_provider + * @author Fabian Reister ( fabian dot reister at kit dot edu ) + * @date 2022 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#pragma once + + +#include "ArmarXCore/core/services/tasks/RunningTask.h" +#include <ArmarXCore/core/Component.h> + +#include <RobotAPI/libraries/ArmarXObjects/plugins/ObjectPoseClientPlugin.h> +#include <RobotAPI/libraries/armem/client/plugins/ReaderWriterPlugin.h> +#include <RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h> + +#include "armarx/navigation/memory/client/costmap/Writer.h" +#include <armarx/navigation/components/distance_to_obstacle_costmap_provider/ComponentInterface.h> + + +namespace armarx::navigation::components::distance_to_obstacle_costmap_provider +{ + + class Component : + virtual public armarx::Component, + virtual public ObjectPoseClientPluginUser, + virtual public armarx::navigation::components::distance_to_obstacle_costmap_provider:: + ComponentInterface + // , virtual public armarx::DebugObserverComponentPluginUser + // , virtual public armarx::LightweightRemoteGuiComponentPluginUser + // , virtual public armarx::ArVizComponentPluginUser + { + public: + Component(); + + /// @see armarx::ManagedIceObject::getDefaultName() + std::string getDefaultName() const override; + + /// Get the component's default name. + static std::string GetDefaultName(); + + + protected: + /// @see PropertyUser::createPropertyDefinitions() + armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; + + /// @see armarx::ManagedIceObject::onInitComponent() + void onInitComponent() override; + + /// @see armarx::ManagedIceObject::onConnectComponent() + void onConnectComponent() override; + + /// @see armarx::ManagedIceObject::onDisconnectComponent() + void onDisconnectComponent() override; + + /// @see armarx::ManagedIceObject::onExitComponent() + void onExitComponent() override; + + + /* (Requires armarx::LightweightRemoteGuiComponentPluginUser.) + /// This function should be called once in onConnect() or when you + /// need to re-create the Remote GUI tab. + void createRemoteGuiTab(); + + /// After calling `RemoteGui_startRunningTask`, this function is + /// called periodically in a separate thread. If you update variables, + /// make sure to synchronize access to them. + void RemoteGui_update() override; + */ + + bool createAndStoreCostmap(); + + void run(); + + private: + // Private methods go here. + + // Forward declare `Properties` if you used it before its defined. + // struct Properties; + + /* (Requires the armarx::ArVizComponentPluginUser.) + /// Draw some boxes in ArViz. + void drawBoxes(const Properties& p, viz::Client& arviz); + */ + + + static const std::string defaultName; + + + // Private member variables go here. + + + /// Properties shown in the Scenario GUI. + struct Properties + { + std::string robotName = "Armar6"; + }; + Properties properties; + /* 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; + */ + std::optional<armem::robot::RobotDescription> robotDescription; + armem::client::plugins::ReaderWriterPlugin<armem::robot_state::VirtualRobotReader>* + virtualRobotReaderPlugin = nullptr; + + + armem::client::plugins::ReaderWriterPlugin<memory::client::costmap::Writer>* + costmapWriterPlugin = nullptr; + + + RunningTask<Component>::pointer_type runningTask; + }; + +} // namespace armarx::navigation::components::distance_to_obstacle_costmap_provider diff --git a/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/ComponentInterface.ice b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/ComponentInterface.ice new file mode 100644 index 0000000000000000000000000000000000000000..469a4290af0e9ee1b44b94b2b9d35781ba37c729 --- /dev/null +++ b/source/armarx/navigation/components/distance_to_obstacle_costmap_provider/ComponentInterface.ice @@ -0,0 +1,35 @@ +/* + * 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 navigation::distance_to_obstacle_costmap_provider + * author Fabian Reister ( fabian dot reister at kit dot edu ) + * date 2022 + * copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#pragma once + + +module armarx { module navigation { module components { module distance_to_obstacle_costmap_provider +{ + + interface ComponentInterface + { + // Define your interface here. + }; + +};};};}; diff --git a/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.cpp b/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.cpp index fa926fb76b98f3f617ba928d62f16c072d477713..6b89eb56af7abb5fed5b862ad200ef6e187f3f8d 100644 --- a/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.cpp +++ b/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.cpp @@ -84,6 +84,14 @@ namespace armarx::navigation::components::dynamic_distance_to_obstacle_costmap_p // def->optional( // properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz."); def->optional(properties.updatePeriodMs, "p.updatePeriodMs", ""); + def->optional(properties.staticCostmap.name, "p.staticCostmap.name", ""); + def->required(properties.staticCostmap.providerName, "p.staticCostmap.providerName", ""); + + def->optional(properties.laserScannerFeatures.name, "p.laserScannerFeatures.name", ""); + def->optional(properties.laserScannerFeatures.providerName, "p.laserScannerFeatures.providerName", ""); + + def->optional(properties.robot.name, "p.robot.name", ""); + costmapReader.registerPropertyDefinitions(def); costmapWriter.registerPropertyDefinitions(def); diff --git a/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.h b/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.h index 6094a09eb1b1b84849c7677c029837d43f8c8bba..1837d8ac9cf76718fef5978213a5786235a50a08 100644 --- a/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.h +++ b/source/armarx/navigation/components/dynamic_distance_to_obstacle_costmap_provider/Component.h @@ -124,7 +124,7 @@ namespace armarx::navigation::components::dynamic_distance_to_obstacle_costmap_p // std::string boxLayerName = "boxes"; struct { - std::string providerName = "navigator"; + std::string providerName; std::string name = "distance_to_obstacles"; } staticCostmap; diff --git a/source/armarx/navigation/core/StaticScene.h b/source/armarx/navigation/core/StaticScene.h index de0f008db6a521816bebb17d3534ba1903efc3f3..534b4345577ff49887df8f256e2342511f31a8c4 100644 --- a/source/armarx/navigation/core/StaticScene.h +++ b/source/armarx/navigation/core/StaticScene.h @@ -35,8 +35,7 @@ namespace armarx::navigation::core { VirtualRobot::SceneObjectSetPtr objects; - // TODO(fabian.reister): rename, why unique_ptr - std::unique_ptr<algorithms::Costmap> costmap; + std::optional<algorithms::Costmap> distanceToObstaclesCostmap; }; diff --git a/source/armarx/navigation/global_planning/AStar.cpp b/source/armarx/navigation/global_planning/AStar.cpp index eafc77dae4c3cb6b3e04ec042e75e32e07d77887..67db7790fd16db7198808c8989acc8e28ad5431d 100644 --- a/source/armarx/navigation/global_planning/AStar.cpp +++ b/source/armarx/navigation/global_planning/AStar.cpp @@ -159,7 +159,7 @@ namespace armarx::navigation::global_planning ARMARX_TRACE; // FIXME check if costmap is available - algorithm::astar::AStarPlanner planner(*scene.staticScene->costmap); + algorithm::astar::AStarPlanner planner(*scene.staticScene->distanceToObstaclesCostmap); const Eigen::Vector2f goalPos = conv::to2D(goal.translation()); diff --git a/source/armarx/navigation/global_planning/SPFA.cpp b/source/armarx/navigation/global_planning/SPFA.cpp index ed53c5138b166f4daf0eca037932a4edcf9da1b8..9491705a0db21cd7d53e3ecfc037eed93b9b73d5 100644 --- a/source/armarx/navigation/global_planning/SPFA.cpp +++ b/source/armarx/navigation/global_planning/SPFA.cpp @@ -91,7 +91,7 @@ namespace armarx::navigation::global_planning // FIXME check if costmap is available algorithms::spfa::ShortestPathFasterAlgorithm::Parameters spfaParams; - algorithms::spfa::ShortestPathFasterAlgorithm planner(*scene.staticScene->costmap, + algorithms::spfa::ShortestPathFasterAlgorithm planner(*scene.staticScene->distanceToObstaclesCostmap, spfaParams); const Eigen::Vector2f goalPos = conv::to2D(goal.translation()); @@ -211,14 +211,15 @@ namespace armarx::navigation::global_planning // auto smoothTrajectory = smoothing.smooth(result.trajectory.value()); // smoothTrajectory.setMaxVelocity(params.linearVelocity); - const auto costmap = scene.staticScene->costmap.get(); + ARMARX_CHECK(scene.staticScene->distanceToObstaclesCostmap.has_value()); + const auto& costmap = scene.staticScene->distanceToObstaclesCostmap.value(); for (auto& point : result.trajectory->mutablePoints()) { const float distance = std::min<float>( spfaParams.obstacleMaxDistance, - costmap->value(Eigen::Vector2f{point.waypoint.pose.translation().head<2>()}) + costmap.value(Eigen::Vector2f{point.waypoint.pose.translation().head<2>()}) .value_or(0.F)); if (spfaParams.obstacleDistanceCosts) diff --git a/source/armarx/navigation/memory/client/costmap/Reader.cpp b/source/armarx/navigation/memory/client/costmap/Reader.cpp index 436fd2b9462f5a3132607f7302315443ccb4e5eb..ef078b77da2b9dfa6e1e7425c1fabf15606c98e8 100644 --- a/source/armarx/navigation/memory/client/costmap/Reader.cpp +++ b/source/armarx/navigation/memory/client/costmap/Reader.cpp @@ -96,7 +96,7 @@ namespace armarx::navigation::memory::client::costmap if (not coreSegment.hasProviderSegment(query.providerName)) { - ARMARX_WARNING << "Provider segment `" << query.providerName + ARMARX_VERBOSE << "Provider segment `" << query.providerName << "` does not exist (yet)."; return {.costmap = std::nullopt, .status = Result::Status::NoData}; } @@ -106,7 +106,7 @@ namespace armarx::navigation::memory::client::costmap if (providerSegment.empty()) { - ARMARX_WARNING << "No entities."; + ARMARX_VERBOSE << "No entities."; return {.costmap = std::nullopt, .status = Result::Status::NoData, .errorMessage = "No entities"}; diff --git a/source/armarx/navigation/server/scene_provider/SceneProvider.cpp b/source/armarx/navigation/server/scene_provider/SceneProvider.cpp index b51208e230dd1e15b2215177a0b34e82244b39ad..308cb08898bc2f0687c7fd54a1c189649f5a2c66 100644 --- a/source/armarx/navigation/server/scene_provider/SceneProvider.cpp +++ b/source/armarx/navigation/server/scene_provider/SceneProvider.cpp @@ -3,10 +3,12 @@ #include <VirtualRobot/SceneObjectSet.h> #include "ArmarXCore/core/exceptions/local/ExpressionException.h" +#include "ArmarXCore/core/time/Clock.h" #include "RobotAPI/libraries/armem_robot/types.h" #include "armarx/navigation/core/types.h" +#include "armarx/navigation/memory/client/costmap/Reader.h" #include <armarx/navigation/algorithms/CostmapBuilder.h> #include <armarx/navigation/util/util.h> @@ -33,8 +35,8 @@ namespace armarx::navigation::server::scene_provider config.robotName, timestamp, VirtualRobot::RobotIO::RobotDescription::eCollisionModel); ARMARX_CHECK_NOT_NULL(scn.robot); - scn.staticScene = getStaticScene(timestamp); - scn.dynamicScene = getDynamicScene(timestamp); + scn.staticScene.emplace(getStaticScene(timestamp)); + scn.dynamicScene.emplace(getDynamicScene(timestamp)); scn.graph = getSceneGraph(timestamp); return true; // TODO(fabian.reister): return false if sync fails @@ -77,28 +79,19 @@ namespace armarx::navigation::server::scene_provider ARMARX_CHECK_NOT_NULL(objects); ARMARX_INFO << objects->getSize() << " objects in the scene"; - ARMARX_INFO << "Creating costmap"; - ARMARX_CHECK_NOT_NULL(scn.robot); - - // FIXME: move costmap creation out of this component - // FIXME create costmap writer enum: type of costmaps - algorithms::CostmapBuilder costmapBuilder( - scn.robot, - objects, - algorithms::Costmap::Parameters{.binaryGrid = false, .cellSize = 100}, - "Platform-navigation-colmodel"); - - const auto costmap = costmapBuilder.create(); - - // ARMARX_INFO << "Storing costmap in memory"; - // costmapWriterPlugin->get().store( - // costmap, "distance_to_obstacles", getName(), armarx::Clock::Now()); - - ARMARX_INFO << "Done"; + ARMARX_INFO << "Retrieving costmap in memory"; + const memory::client::costmap::Reader::Query query + { + .providerName = "", + .name = "distance_to_obstacles", + .timestamp = armarx::Clock::Now() + }; ARMARX_TRACE; + const auto costmap = srv.costmapReader->query(query); + ARMARX_INFO << "Done"; - return {.objects = objects, .costmap = std::make_unique<algorithms::Costmap>(costmap)}; + return {.objects = objects, .distanceToObstaclesCostmap = costmap.costmap}; } core::DynamicScene