diff --git a/.clang-tidy b/.clang-tidy
index fc2f7fe90f6696c438dbc6090d06f2c74ce8d02e..6e80b9026b3eb65a5417ca390eac4ccc1903e85e 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -67,7 +67,7 @@ CheckOptions:
   - key:    readability-identifier-naming.ConstantMemberPrefix
     value:  ''
   - key:    readability-identifier-naming.ConstantMemberCase
-    value:  UPPER_CASE
+    value:  camelBack
   - key:    readability-identifier-naming.ConstantParameterPrefix
     value:  ''
   - key:    readability-identifier-naming.ConstantParameterCase
diff --git a/source/armarx/navigation/algorithms/astar/AStarPlanner.cpp b/source/armarx/navigation/algorithms/astar/AStarPlanner.cpp
index 0386c314dea9df3f0b609fe0eb022a7cf380432b..0213bd3197be6c17e3ea23a5eb0666a76f3a2558 100644
--- a/source/armarx/navigation/algorithms/astar/AStarPlanner.cpp
+++ b/source/armarx/navigation/algorithms/astar/AStarPlanner.cpp
@@ -124,8 +124,8 @@ namespace armarx::navigation::algorithm::astar
         ARMARX_CHECK_NOT_NULL(VirtualRobot::CollisionChecker::getGlobalCollisionChecker());
         ARMARX_CHECK_NOT_NULL(obstacles);
 
-        const core::Pose globalPose = Eigen::Translation3f(conv::to3D(n->position)) *
-                                      Eigen::AngleAxisf(M_PI_2f32, Eigen::Vector3f::UnitX());
+        const core::Pose globalPose(Eigen::Translation3f(conv::to3D(n->position))); //*
+                                      //Eigen::AngleAxisf(M_PI_2f32, Eigen::Vector3f::UnitX());
 
         robotCollisionModel->setGlobalPose(globalPose.matrix());
 
@@ -186,6 +186,7 @@ namespace armarx::navigation::algorithm::astar
         // << "No collision model for robot node " << robotColModelName;
 
         // robotCollisionModel = robot->getRobotNode(robotColModelName)->getCollisionModel()->clone();
+        ARMARX_CHECK_NOT_NULL(robotCollisionModel);
         robotCollisionModel->setGlobalPose(robot->getGlobalPose());
 
         // static auto cylinder = VirtualRobot::ObjectIO::loadObstacle("/home/fabi/cylinder.xml");
@@ -194,7 +195,6 @@ namespace armarx::navigation::algorithm::astar
 
         // robotCollisionModel = cylinder->getCollisionModel();
 
-        ARMARX_CHECK_NOT_NULL(robotCollisionModel);
 
         createUniformGrid();
         ARMARX_DEBUG << "Setting start node for position " << start;
diff --git a/source/armarx/navigation/client/ComponentPlugin.cpp b/source/armarx/navigation/client/ComponentPlugin.cpp
index 3578b69541b521fad45360ffa78e794a5c7dc180..6266c680f8fb74e54b51735bb07310fb09b1a94c 100644
--- a/source/armarx/navigation/client/ComponentPlugin.cpp
+++ b/source/armarx/navigation/client/ComponentPlugin.cpp
@@ -1,10 +1,19 @@
-#include "ArmarXCore/core/exceptions/local/ExpressionException.h"
+#include <memory>
+
 #include <ArmarXCore/core/Component.h>
 #include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h>
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/util/CPPUtility/trace.h>
 
+#include <RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.h>
+#include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
+#include <RobotAPI/libraries/armem/client/plugins/ListeningPluginUser.h>
+#include <RobotAPI/libraries/armem/client/plugins/PluginUser.h>
+
 #include <armarx/navigation/client/ComponentPlugin.h>
 #include <armarx/navigation/client/Navigator.h>
+#include <armarx/navigation/client/services/MemorySubscriber.h>
+#include <armarx/navigation/client/services/SimpleEventHandler.h>
 
 // ComponentPlugin
 
@@ -36,16 +45,62 @@ armarx::navigation::client::ComponentPlugin::preOnConnectComponent()
 
     ARMARX_TRACE;
     const std::string componentName = parent().getName();
-    IceNavigator& srv = parent<armarx::navigation::client::ComponentPluginUser>().iceNavigator;
 
     ARMARX_CHECK_NOT_NULL(navigatorPrx) << "Navigator proxy is null!";
-    srv.setNavigatorComponent(navigatorPrx);
+    iceNavigator.setNavigatorComponent(navigatorPrx);
+}
+
+void
+armarx::navigation::client::ComponentPlugin::configureNavigator(
+    const client::NavigationStackConfig& stackConfig,
+    const std::string& configId)
+{
+    ARMARX_TRACE;
+
+    ARMARX_CHECK_NULL(eventHandler) << "`configureNavigator()` can only be called once!";
+
+    eventHandler = [&]() -> std::unique_ptr<SimpleEventHandler>
+    {
+        if (parentDerives<armarx::armem::client::plugins::ListeningPluginUser>())
+        {
+            ARMARX_INFO << "Using memory event callbacks.";
+            auto memoryNameSystem =
+                parent<armarx::armem::client::plugins::ListeningPluginUser>().memoryNameSystem();
+            return std::make_unique<MemorySubscriber>(configId, memoryNameSystem);
+        }
+
+        ARMARX_INFO << "Cannot use memory event callbacks as this component is not derived from "
+                       "`armarx::armem::client::plugins::ListeningPluginUser`";
+
+        return std::make_unique<SimpleEventHandler>();
+    }();
+
+    iceNavigator.createConfig(stackConfig, configId);
+
+    navigator = std::make_unique<Navigator>(
+        Navigator::InjectedServices{.navigator = &iceNavigator, .subscriber = eventHandler.get()});
+}
+void
+armarx::navigation::client::ComponentPlugin::configureNavigator(
+    const armarx::navigation::client::NavigationStackConfig& stackConfig,
+    const std::string& configId,
+    armarx::armem::client::MemoryNameSystem& memoryNameSystem)
+{
+    ARMARX_TRACE;
+
+    ARMARX_CHECK_NULL(eventHandler) << "`configureNavigator()` can only be called once!";
+
+    eventHandler = std::make_unique<MemorySubscriber>(configId, memoryNameSystem);
+
+    iceNavigator.createConfig(stackConfig, configId);
+
+    navigator = std::make_unique<Navigator>(
+        Navigator::InjectedServices{.navigator = &iceNavigator, .subscriber = eventHandler.get()});
 }
 
 // ComponentPluginUser
 
-armarx::navigation::client::ComponentPluginUser::ComponentPluginUser() :
-    navigator{navigatorServices}
+armarx::navigation::client::ComponentPluginUser::ComponentPluginUser()
 {
     ARMARX_TRACE;
     addPlugin(plugin);
@@ -55,15 +110,16 @@ void
 armarx::navigation::client::ComponentPluginUser::configureNavigator(
     const client::NavigationStackConfig& stackConfig)
 {
-    configureNavigator(stackConfig, getName());
+    ARMARX_TRACE;
+    plugin->configureNavigator(stackConfig, getName());
 }
 
-void
-armarx::navigation::client::ComponentPluginUser::configureNavigator(
-    const client::NavigationStackConfig& stackConfig,
-    const std::string& configId)
+armarx::navigation::client::Navigator&
+armarx::navigation::client::ComponentPluginUser::getNavigator()
 {
-    iceNavigator.createConfig(stackConfig, configId);
+    ARMARX_CHECK_NOT_NULL(plugin->navigator)
+        << "You need to call `configureNavigator()` before you can access the navigator!";
+    return *plugin->navigator;
 }
 
 armarx::navigation::client::ComponentPluginUser::~ComponentPluginUser() = default;
diff --git a/source/armarx/navigation/client/ComponentPlugin.h b/source/armarx/navigation/client/ComponentPlugin.h
index f64ce55b7a22545d49dcd99e2d992c589d6449c8..38ab565fb95c1bea71ee78e4838dbb6f050771ed 100644
--- a/source/armarx/navigation/client/ComponentPlugin.h
+++ b/source/armarx/navigation/client/ComponentPlugin.h
@@ -4,21 +4,27 @@
 #include <ArmarXCore/core/ComponentPlugin.h>
 #include <ArmarXCore/core/ManagedIceObject.h>
 
+#include <armarx/navigation/client/ComponentPlugin.h>
 #include <armarx/navigation/client/Navigator.h>
 #include <armarx/navigation/client/ice/NavigatorInterface.h>
 #include <armarx/navigation/client/services/IceNavigator.h>
-#include <armarx/navigation/client/services/MemorySubscriber.h>
 #include <armarx/navigation/client/services/SimpleEventHandler.h>
 
+namespace armarx::armem::client
+{
+    class MemoryNameSystem;
+}
 
 namespace armarx::navigation::client
 {
 
-    class ComponentPlugin : virtual public armarx::ComponentPlugin
-    {
+    class Navigator;
 
+    class ComponentPlugin : public armarx::ComponentPlugin
+    {
     public:
-        using armarx::ComponentPlugin::ComponentPlugin;
+        ComponentPlugin(ManagedIceObject& parent, const std::string& prefix) :
+            armarx::ComponentPlugin(parent, prefix){};
 
         ~ComponentPlugin() override;
 
@@ -28,10 +34,22 @@ namespace armarx::navigation::client
 
         void preOnConnectComponent() override;
 
+        void configureNavigator(const client::NavigationStackConfig& stackConfig,
+                                const std::string& configId);
+
+        void configureNavigator(const client::NavigationStackConfig& stackConfig,
+                                const std::string& configId, armarx::armem::client::MemoryNameSystem& memoryNameSystem);
+
     private:
         static constexpr const char* PROPERTY_NAME = "nav.NavigatorName";
 
         client::NavigatorInterfacePrx navigatorPrx;
+        IceNavigator iceNavigator;
+
+        std::unique_ptr<SimpleEventHandler> eventHandler;
+
+    public:
+        std::unique_ptr<Navigator> navigator;
     };
 
 
@@ -43,30 +61,14 @@ namespace armarx::navigation::client
 
         void configureNavigator(const client::NavigationStackConfig& stackConfig);
 
-        void configureNavigator(const client::NavigationStackConfig& stackConfig,
-                                const std::string& configId);
-
-
+        Navigator& getNavigator();
+        
         // Non-API
-
-    public:
         ~ComponentPluginUser() override;
 
-        friend class ComponentPlugin;
-
     private:
-        IceNavigator iceNavigator;
-        // MemorySubscriber memorySubscriber;
-        SimpleEventHandler memorySubscriber; // FIXME
-        Navigator::InjectedServices navigatorServices{.navigator = &iceNavigator,
-                                                      .subscriber = &memorySubscriber};
-
-
         ComponentPlugin* plugin = nullptr;
 
-
-    public:
-        Navigator navigator;
     };
 
 } // namespace armarx::navigation::client
diff --git a/source/armarx/navigation/client/Navigator.cpp b/source/armarx/navigation/client/Navigator.cpp
index 8e8ac4ce358d4ca405dd2e68f771415a8b33be79..9780c8c009164d4a5ea1753ac9089a48f632ecab 100644
--- a/source/armarx/navigation/client/Navigator.cpp
+++ b/source/armarx/navigation/client/Navigator.cpp
@@ -3,6 +3,7 @@
 #include <algorithm>
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/util/CPPUtility/trace.h>
 
 #include <armarx/navigation/client/PathBuilder.h>
 #include <armarx/navigation/client/ice_conversions.h>
@@ -12,6 +13,7 @@ namespace armarx::navigation::client
 
     Navigator::Navigator(const InjectedServices& services) : srv{services}
     {
+        ARMARX_TRACE;
         // these checks cannot be used when component is started in property-readout mode
         ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
         ARMARX_CHECK_NOT_NULL(srv.subscriber) << "Subscriber service must not be null!";
@@ -28,6 +30,7 @@ namespace armarx::navigation::client
     void
     Navigator::moveTo(const core::Pose& pose, core::NavigationFrame frame)
     {
+        ARMARX_TRACE;
         moveTo(std::vector<core::Pose>{pose}, frame);
     }
 
@@ -35,6 +38,7 @@ namespace armarx::navigation::client
     void
     Navigator::moveTo(const std::vector<core::Pose>& waypoints, core::NavigationFrame frame)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
         srv.navigator->moveTo(waypoints, frame);
     }
@@ -43,6 +47,7 @@ namespace armarx::navigation::client
     void
     Navigator::moveTo(const PathBuilder& builder, core::NavigationFrame frame)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
 
         const std::vector<WaypointTarget>& path = builder.path();
@@ -55,6 +60,7 @@ namespace armarx::navigation::client
     void
     Navigator::moveTowards(const core::Direction& direction, core::NavigationFrame frame)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
         srv.navigator->moveTowards(direction, frame);
     }
@@ -63,6 +69,7 @@ namespace armarx::navigation::client
     void
     Navigator::pause()
     {
+        ARMARX_TRACE;
         ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
         srv.navigator->pause();
     }
@@ -71,6 +78,7 @@ namespace armarx::navigation::client
     void
     Navigator::resume()
     {
+        ARMARX_TRACE;
         ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
         srv.navigator->resume();
     }
@@ -79,6 +87,7 @@ namespace armarx::navigation::client
     void
     Navigator::stop()
     {
+        ARMARX_TRACE;
         ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
         srv.navigator->stop();
     }
@@ -87,6 +96,7 @@ namespace armarx::navigation::client
     void
     Navigator::onGoalReached(const std::function<void(void)>& callback)
     {
+        ARMARX_TRACE;
         onGoalReached([&callback](const core::GoalReachedEvent&) { callback(); });
     }
 
@@ -106,6 +116,7 @@ namespace armarx::navigation::client
     StopEvent
     Navigator::waitForStop()
     {
+        ARMARX_TRACE;
         std::unique_lock l{stoppedInfo.m};
         stoppedInfo.cv.wait(l, [&i = stoppedInfo] { return i.event.has_value(); });
 
@@ -118,6 +129,7 @@ namespace armarx::navigation::client
     void
     Navigator::stopped(const StopEvent& e)
     {
+        ARMARX_TRACE;
         {
             std::scoped_lock l{stoppedInfo.m};
             stoppedInfo.event = e;
diff --git a/source/armarx/navigation/client/services/IceNavigator.cpp b/source/armarx/navigation/client/services/IceNavigator.cpp
index 6df5101d2623fb475878bc137341601e1ac583ec..a28e70467d5f3932638d1b90e248dcd36051ad89 100644
--- a/source/armarx/navigation/client/services/IceNavigator.cpp
+++ b/source/armarx/navigation/client/services/IceNavigator.cpp
@@ -43,6 +43,7 @@ namespace armarx::navigation::client
     IceNavigator::createConfig(const client::NavigationStackConfig& config,
                                const std::string& configId)
     {
+        ARMARX_TRACE;
         this->configId = configId;
         navigator->createConfig(config.toAron(), configId);
     }
diff --git a/source/armarx/navigation/components/Navigator/Navigator.cpp b/source/armarx/navigation/components/Navigator/Navigator.cpp
index 95f9410c394472dfd196b8dd692c99ad41756ca1..6532665f5ec93209e1066526118f68142ec3a830 100644
--- a/source/armarx/navigation/components/Navigator/Navigator.cpp
+++ b/source/armarx/navigation/components/Navigator/Navigator.cpp
@@ -322,7 +322,7 @@ namespace armarx::navigation::components
                                        const Ice::Current&)
     {
         // TODO: Error handling.
-
+        ARMARX_TRACE;
         ARMARX_INFO << "MoveTowards requested by caller '" << callerId << "'";
 
         ARMARX_CHECK(navigators.count(callerId) > 0)
@@ -344,6 +344,7 @@ namespace armarx::navigation::components
     void
     components::Navigator::resume(const std::string& configId, const Ice::Current&)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK(navigators.count(configId) > 0)
             << "Navigator config for caller `" << configId << "` not registered!";
         navigators.at(configId).resume();
@@ -352,6 +353,7 @@ namespace armarx::navigation::components
     void
     components::Navigator::stop(const std::string& configId, const Ice::Current&)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK(navigators.count(configId) > 0)
             << "Navigator config for caller `" << configId << "` not registered!";
         navigators.at(configId).stop();
@@ -360,6 +362,7 @@ namespace armarx::navigation::components
     void
     components::Navigator::stopAll(const Ice::Current&)
     {
+        ARMARX_TRACE;
         for (auto& [_, navigator] : navigators)
         {
             navigator.stop();
@@ -369,6 +372,7 @@ namespace armarx::navigation::components
     bool
     components::Navigator::isPaused(const std::string& configId, const Ice::Current&)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK(navigators.count(configId) > 0)
             << "Navigator config for caller `" << configId << "` not registered!";
         return navigators.at(configId).isPaused();
@@ -377,6 +381,7 @@ namespace armarx::navigation::components
     bool
     components::Navigator::isStopped(const std::string& configId, const Ice::Current&)
     {
+        ARMARX_TRACE;
         ARMARX_CHECK(navigators.count(configId) > 0)
             << "Navigator config for caller `" << configId << "` not registered!";
         return navigators.at(configId).isStopped();
@@ -511,6 +516,7 @@ namespace armarx::navigation::components
     void
     components::Navigator::updateRobot()
     {
+        ARMARX_TRACE;
         synchronizeLocalClone(scene.robot);
 
         auto robotDescription = virtualRobotReader.queryDescription("Armar6", armem::Time::now());
@@ -540,6 +546,7 @@ namespace armarx::navigation::components
     server::Navigator*
     components::Navigator::activeNavigator()
     {
+        ARMARX_TRACE;
         // We define the active navigator to be the one whose movement is enabled.
         const auto isActive = [](auto& nameNavPair) -> bool
         {
diff --git a/source/armarx/navigation/components/example_client/Component.cpp b/source/armarx/navigation/components/example_client/Component.cpp
index 1a8b1fdda8526184bd7052d3b0a061556ad179d6..5b702a537dfc0b489e0ef23bf363a923e1b0bceb 100644
--- a/source/armarx/navigation/components/example_client/Component.cpp
+++ b/source/armarx/navigation/components/example_client/Component.cpp
@@ -103,10 +103,10 @@ namespace armarx::navigation::components::example_client
                 .trajectoryController(traj_ctrl::TrajectoryFollowingControllerParams()));
 
         // Example of registering a lambda as callback.
-        navigator.onGoalReached([&]() { ARMARX_IMPORTANT << "Goal reached! (lambda-style)"; });
+        getNavigator().onGoalReached([&]() { ARMARX_IMPORTANT << "Goal reached! (lambda-style)"; });
 
         // Example of registering a method as callback.
-        navigator.onGoalReached([this] { goalReached(); });
+        getNavigator().onGoalReached([this] { goalReached(); });
 
         std::this_thread::sleep_for(1s);
 
@@ -115,12 +115,12 @@ namespace armarx::navigation::components::example_client
         core::Pose goal = core::Pose::Identity();
         goal.translation() << 2000, 1000, 0;
 
-        navigator.moveTo(goal, core::NavigationFrame::Absolute);
+        getNavigator().moveTo(goal, core::NavigationFrame::Absolute);
 
         std::this_thread::sleep_for(15s);
 
         // Wait until goal is reached
-        armarx::navigation::client::StopEvent se = navigator.waitForStop();
+        armarx::navigation::client::StopEvent se = getNavigator().waitForStop();
         if (se)
         {
             ARMARX_INFO << "Goal 1 reached.";
@@ -143,12 +143,12 @@ namespace armarx::navigation::components::example_client
         }
 
         goal.translation() << -1500, 1000, 0;
-        navigator.moveTo(goal, core::NavigationFrame::Absolute);
+        getNavigator().moveTo(goal, core::NavigationFrame::Absolute);
 
         std::this_thread::sleep_for(15s);
 
         // Wait until goal is reached
-        se = navigator.waitForStop();
+        se = getNavigator().waitForStop();
         if (se)
         {
             ARMARX_INFO << "Goal 2 reached.";
@@ -159,10 +159,10 @@ namespace armarx::navigation::components::example_client
         }
 
         goal.translation() << 4500, 4500, 0;
-        navigator.moveTo(goal, core::NavigationFrame::Absolute);
+        getNavigator().moveTo(goal, core::NavigationFrame::Absolute);
 
         // Wait until goal is reached
-        se = navigator.waitForStop();
+        se = getNavigator().waitForStop();
         if (se)
         {
             ARMARX_INFO << "Goal 3 reached.";
@@ -178,12 +178,12 @@ namespace armarx::navigation::components::example_client
 
         ARMARX_INFO << "Moving into certain direction.";
         // Start moving towards a direction
-        navigator.moveTowards(core::Direction(100, 100, 0), core::NavigationFrame::Relative);
+        getNavigator().moveTowards(core::Direction(100, 100, 0), core::NavigationFrame::Relative);
 
         std::this_thread::sleep_for(3s);
 
         ARMARX_INFO << "Pausing movement.";
-        navigator.pause();
+        getNavigator().pause();
     }
 
     void
@@ -206,10 +206,10 @@ namespace armarx::navigation::components::example_client
                 .trajectoryController(traj_ctrl::TrajectoryFollowingControllerParams()));
 
         // Example of registering a lambda as callback.
-        navigator.onGoalReached([&]() { ARMARX_IMPORTANT << "Goal reached! (lambda-style)"; });
+        getNavigator().onGoalReached([&]() { ARMARX_IMPORTANT << "Goal reached! (lambda-style)"; });
 
         // Example of registering a method as callback.
-        navigator.onGoalReached([this] { goalReached(); });
+        getNavigator().onGoalReached([this] { goalReached(); });
 
         std::this_thread::sleep_for(1s);
 
@@ -232,12 +232,12 @@ namespace armarx::navigation::components::example_client
         // clang-format on
 
         ARMARX_INFO << "Starting execution";
-        navigator.moveTo(pathBuilder, core::NavigationFrame::Absolute);
+        getNavigator().moveTo(pathBuilder, core::NavigationFrame::Absolute);
 
         std::this_thread::sleep_for(25s); // TODO(fabian.reister): remove in the future
 
         // Wait until goal is reached
-        armarx::navigation::client::StopEvent se = navigator.waitForStop();
+        armarx::navigation::client::StopEvent se = getNavigator().waitForStop();
         if (se)
         {
             ARMARX_INFO << "Goal 1 reached.";
@@ -260,7 +260,7 @@ namespace armarx::navigation::components::example_client
         }
 
         ARMARX_INFO << "Pausing movement.";
-        navigator.pause();
+        getNavigator().pause();
     }
 
 
diff --git a/source/armarx/navigation/core/Graph.cpp b/source/armarx/navigation/core/Graph.cpp
index f1bc378109fa48f6ed104e728467866474426dec..ac2fc21e9c497d0bff55e7baf354042625afcee4 100644
--- a/source/armarx/navigation/core/Graph.cpp
+++ b/source/armarx/navigation/core/Graph.cpp
@@ -81,7 +81,8 @@ namespace armarx::navigation::core
 
         ss << " cost " << edge.attrib().cost()
            << ", type: " << static_cast<int>(edge.attrib().strategy) << " , has traj "
-           << edge.attrib().trajectory.has_value() << ", aron: " << nlohmann::json(edge.attrib().aron);
+           << edge.attrib().trajectory.has_value();
+        //    << ", aron: " << nlohmann::json(edge.attrib().aron);
 
         return ss.str();
     }
diff --git a/source/armarx/navigation/global_planning/AStar.cpp b/source/armarx/navigation/global_planning/AStar.cpp
index 8cc0acb31627e0a5ac566a528f5394358bab32e1..9d6f0033ad042ea2c447632179b13c78bfc865ac 100644
--- a/source/armarx/navigation/global_planning/AStar.cpp
+++ b/source/armarx/navigation/global_planning/AStar.cpp
@@ -6,6 +6,7 @@
 
 #include <Eigen/Geometry>
 
+#include <VirtualRobot/RobotNodeSet.h>
 #include <VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.h>
 
 #include <ArmarXCore/core/exceptions/LocalException.h>
@@ -73,58 +74,60 @@ namespace armarx::navigation::glob_plan
     {
     }
 
-    auto
-    robotCollisionModel()
-    {
+    // auto
+    // robotCollisionModel()
+    // {
 
-        constexpr float platformHeight = 600;
-        constexpr float bodyHeight = 1400;
-        constexpr float fullHeight = platformHeight + bodyHeight;
+    //     constexpr float platformHeight = 600;
+    //     constexpr float bodyHeight = 1400;
+    //     constexpr float fullHeight = platformHeight + bodyHeight;
 
-        constexpr float platformRadius = 500.F;
-        constexpr float bodyRadius = 300.F;
-        constexpr float simpleRadius = std::max(platformRadius, bodyRadius);
+    //     constexpr float platformRadius = 600.F;
+    //     constexpr float bodyRadius = 300.F;
+    //     constexpr float simpleRadius = std::max(platformRadius, bodyRadius);
 
-        // combined model made out of two stacked cylinders.
-        [[maybe_unused]]
-        const auto createCombinedVisuModel = []()
-        {
-            VirtualRobot::CoinVisualizationFactory factory;
+    //     // combined model made out of two stacked cylinders.
+    //     [[maybe_unused]] const auto createCombinedVisuModel = []()
+    //     {
+    //         VirtualRobot::CoinVisualizationFactory factory;
 
-            auto cylinderPlatform = factory.createCylinder(platformRadius, platformHeight);
-            factory.applyDisplacement(
-                cylinderPlatform,
-                core::Pose(Eigen::Translation3f{Eigen::Vector3f{0, 0, platformHeight / 2}})
-                    .matrix());
+    //         auto cylinderPlatform = factory.createCylinder(platformRadius, platformHeight);
+    //         factory.applyDisplacement(
+    //             cylinderPlatform,
+    //             core::Pose(Eigen::Translation3f{platformHeight / 2 * Eigen::Vector3f::UnitY()})
+    //                 .matrix());
 
-            auto cylinderBody = factory.createCylinder(bodyRadius, bodyHeight);
-            factory.applyDisplacement(cylinderPlatform,
-                                      core::Pose(Eigen::Translation3f{Eigen::Vector3f{
-                                                     0, 0, bodyHeight / 2 + platformHeight}})
-                                          .matrix());
+    //         auto cylinderBody = factory.createCylinder(bodyRadius, bodyHeight);
+    //         factory.applyDisplacement(
+    //             cylinderPlatform,
+    //             core::Pose(Eigen::Translation3f{(bodyHeight / 2 + platformHeight) *
+    //                                             Eigen::Vector3f::UnitY()})
+    //                 .matrix());
 
-            return factory.createUnitedVisualization({cylinderPlatform, cylinderBody});
-        };
 
-        // simple model made of one cylinder only
-        const auto createSimpleVisuModel = []()
-        {
-            VirtualRobot::CoinVisualizationFactory factory;
+    //         return factory.createUnitedVisualization({cylinderPlatform, cylinderBody});
+    //     };
 
-            auto cylinderPlatform = factory.createCylinder(simpleRadius, fullHeight);
-            factory.applyDisplacement(
-                cylinderPlatform,
-                core::Pose(Eigen::Translation3f{Eigen::Vector3f{0, 0, fullHeight / 2}}).matrix());
+    //     // simple model made of one cylinder only
+    //     const auto createSimpleVisuModel = []()
+    //     {
+    //         VirtualRobot::CoinVisualizationFactory factory;
 
-            return cylinderPlatform;
-        };
+    //         auto cylinderPlatform = factory.createCylinder(simpleRadius, fullHeight);
+    //         factory.applyDisplacement(
+    //             cylinderPlatform,
+    //             core::Pose(Eigen::Translation3f{fullHeight / 2 * Eigen::Vector3f::UnitY()})
+    //                 .matrix());
 
-        const auto visuModel = createSimpleVisuModel();
+    //         return cylinderPlatform;
+    //     };
 
-        VirtualRobot::CollisionModelPtr collisionModel(new VirtualRobot::CollisionModel(visuModel));
+    //     const auto visuModel = createSimpleVisuModel();
 
-        return collisionModel;
-    }
+    //     VirtualRobot::CollisionModelPtr collisionModel(new VirtualRobot::CollisionModel(visuModel));
+
+    //     return collisionModel;
+    // }
 
     std::vector<Eigen::Vector2f>
     AStar::postProcessPath(const std::vector<Eigen::Vector2f>& path)
@@ -160,7 +163,8 @@ namespace armarx::navigation::glob_plan
         // planner.setRobotColModel("Platform-colmodel");
 
         // planner.setRobotColModel("Platform-colmodel");
-        planner.setRobotCollisionModel(robotCollisionModel());
+        //planner.setRobotCollisionModel(robotCollisionModel());
+        planner.setRobotCollisionModel(scene.robot->getRobotNode("Platform-navigation-colmodel")->getCollisionModel());
 
         const Eigen::Vector2f goalPos = conv::to2D(goal.translation());
 
diff --git a/source/armarx/navigation/global_planning/CMakeLists.txt b/source/armarx/navigation/global_planning/CMakeLists.txt
index 87d9bd68ab130f67d2dda3b4bbc027bde922dd50..4de838c4800f93ee893ef7ec22398800902063a6 100644
--- a/source/armarx/navigation/global_planning/CMakeLists.txt
+++ b/source/armarx/navigation/global_planning/CMakeLists.txt
@@ -30,3 +30,11 @@ armarx_add_library(global_planning
         ./aron_conversions.h
         ./optimization/OrientationOptimizer.h
 )
+
+
+armarx_add_test(orientation_optimization_test
+    TEST_FILES
+        test/orientation_optimization_test.cpp
+    DEPENDENCIES
+        armarx_navigation::global_planning
+)
diff --git a/source/armarx/navigation/global_planning/optimization/OrientationOptimizer.cpp b/source/armarx/navigation/global_planning/optimization/OrientationOptimizer.cpp
index 8cc3ec811b9a06e00e0c49e5c34704d683f9b311..eb6aeee7fd233d3eaa3f40a1dee42c2625273bb2 100644
--- a/source/armarx/navigation/global_planning/optimization/OrientationOptimizer.cpp
+++ b/source/armarx/navigation/global_planning/optimization/OrientationOptimizer.cpp
@@ -1,5 +1,7 @@
 #include "OrientationOptimizer.h"
 
+#include <cmath>
+
 #include <range/v3/range/conversion.hpp>
 #include <range/v3/view/drop.hpp>
 #include <range/v3/view/drop_last.hpp>
@@ -8,9 +10,11 @@
 
 #include <ceres/ceres.h>
 #include <ceres/cost_function.h>
+#include <ceres/jet.h>
 
 #include <SimoxUtility/math/convert/mat4f_to_xyyaw.h>
 #include <SimoxUtility/math/convert/rpy_to_mat3f.h>
+#include <SimoxUtility/math/periodic/periodic_diff.h>
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/core/logging/Logging.h>
@@ -29,16 +33,24 @@ namespace armarx::navigation::glob_plan
     //   problem.AddResidualBlock(new MyBinaryCostFunction(...), nullptr, x2, x1);
 
 
-    struct CostFunctor
+    inline auto
+    periodicDiff(auto a, auto b)
     {
-        template <typename T>
-        bool
-        operator()(const T* const x, T* residual) const
-        {
-            residual[0] = 10.0 - x[0];
-            return true;
-        }
-    };
+        // angle to corresponding vector
+        const auto a1 = ceres::cos(a);
+        const auto a2 = ceres::sin(a);
+
+        // angle to corresponding vector
+        const auto b1 = ceres::cos(b);
+        const auto b2 = ceres::sin(b);
+
+        // cosine similarity
+        const auto cosSim = a1 * b1 + a2 * b2;
+
+        const auto angleDiff = ceres::acos(cosSim);
+
+        return angleDiff;
+    }
 
     struct SmoothOrientationCostFunctor
     {
@@ -54,9 +66,8 @@ namespace armarx::navigation::glob_plan
                    const T* const yawNext,
                    T* residual) const
         {
-            // TODO periodic
-            residual[0] = weight * (yawPrev[0] - yaw[0]);
-            residual[1] = weight * (yawNext[0] - yaw[0]);
+            residual[0] = weight * periodicDiff(yawPrev[0], yaw[0]);
+            residual[1] = weight * periodicDiff(yawNext[0], yaw[0]);
             return true;
         }
 
@@ -76,9 +87,8 @@ namespace armarx::navigation::glob_plan
         bool
         operator()(const T* const yaw, const T* const yawNext, T* residual) const
         {
-            // TODO periodic
-            residual[0] = weight * (yawPre - yaw[0]);
-            residual[1] = weight * (yawNext[0] - yaw[0]);
+            residual[0] = weight * periodicDiff(yawPre, yaw[0]);
+            residual[1] = weight * periodicDiff(yawNext[0], yaw[0]);
             return true;
         }
 
@@ -99,9 +109,8 @@ namespace armarx::navigation::glob_plan
         bool
         operator()(const T* const yawPre, const T* const yaw, T* residual) const
         {
-            // TODO periodic
-            residual[0] = weight * (yawPre[0] - yaw[0]);
-            residual[1] = weight * (yawNext - yaw[0]);
+            residual[0] = weight * periodicDiff(yawPre[0], yaw[0]);
+            residual[1] = weight * periodicDiff(yawNext, yaw[0]);
             return true;
         }
 
@@ -122,8 +131,7 @@ namespace armarx::navigation::glob_plan
         bool
         operator()(const T* const x, T* residual) const
         {
-            // TODO periodic
-            residual[0] = weight * (prior - x[0]);
+            residual[0] = weight * periodicDiff(prior, x[0]);
             return true;
         }
 
@@ -163,31 +171,43 @@ namespace armarx::navigation::glob_plan
         //   ceres::AngleLocalParameterization::Create();
 
         // prior for all waypoints
-        for (size_t i = 1; i < (orientations.size() - 1); i++)
+        if (params.priorWeight > 0.F)
         {
-            ceres::CostFunction* priorCostFunction =
-                new ceres::AutoDiffCostFunction<OrientationPriorCostFunctor, 1, 1>(
-                    new OrientationPriorCostFunctor(orientations.at(i), params.priorWeight));
-
-            problem.AddResidualBlock(priorCostFunction, nullptr, &orientations.at(i));
+            for (size_t i = 1; i < (orientations.size() - 1); i++)
+            {
+                ceres::CostFunction* priorCostFunction =
+                    new ceres::AutoDiffCostFunction<OrientationPriorCostFunctor, 1, 1>(
+                        new OrientationPriorCostFunctor(orientations.at(i), params.priorWeight));
+
+                problem.AddResidualBlock(priorCostFunction, nullptr, &orientations.at(i));
+            }
         }
 
+
         // smooth waypoint orientation, no start and goal nodes involved!
-        for (size_t i = 2; i < (orientations.size() - 2); i++)
+        if (params.smoothnessWeight > 0.F)
         {
-            ceres::CostFunction* smoothCostFunction =
-                new ceres::AutoDiffCostFunction<SmoothOrientationCostFunctor, 2, 1, 1, 1>(
-                    new SmoothOrientationCostFunctor(params.smoothnessWeight));
-
-            problem.AddResidualBlock(smoothCostFunction,
-                                     nullptr,
-                                     &orientations.at(i - 1),
-                                     &orientations.at(i),
-                                     &orientations.at(i + 1));
+            ARMARX_VERBOSE << "Enabled SmoothOrientationCost";
+            for (size_t i = 2; i < (orientations.size() - 2); i++)
+            {
+                ceres::CostFunction* smoothCostFunction =
+                    new ceres::AutoDiffCostFunction<SmoothOrientationCostFunctor, 2, 1, 1, 1>(
+                        new SmoothOrientationCostFunctor(params.smoothnessWeight));
+
+                problem.AddResidualBlock(smoothCostFunction,
+                                         nullptr,
+                                         &orientations.at(i - 1),
+                                         &orientations.at(i),
+                                         &orientations.at(i + 1));
+            }
         }
 
+
         // smooth waypoint orientation, involving start
+        if (params.smoothnessWeightStartGoal > 0.F)
         {
+            ARMARX_VERBOSE << "Enabled SmoothOrientationFixedPreCost";
+
             ceres::CostFunction* smoothCostFunction =
                 new ceres::AutoDiffCostFunction<SmoothOrientationFixedPreCostFunctor, 2, 1, 1>(
                     new SmoothOrientationFixedPreCostFunctor(orientations.front(),
@@ -198,7 +218,10 @@ namespace armarx::navigation::glob_plan
         }
 
         // smooth waypoint orientation, involving goal
+        if (params.smoothnessWeightStartGoal > 0.F)
         {
+            ARMARX_VERBOSE << "Enabled SmoothOrientationFixedNextCost";
+
             ceres::CostFunction* smoothCostFunction =
                 new ceres::AutoDiffCostFunction<SmoothOrientationFixedNextCostFunctor, 2, 1, 1>(
                     new SmoothOrientationFixedNextCostFunctor(orientations.back(),
@@ -215,12 +238,23 @@ namespace armarx::navigation::glob_plan
         ceres::Solver::Options options;
         options.linear_solver_type = ceres::DENSE_QR;
         options.minimizer_progress_to_stdout = true;
+        options.max_num_iterations = 100;
+        options.function_tolerance = 0.01;
+
         ceres::Solver::Summary summary;
         Solve(options, &problem, &summary);
 
-        std::cout << summary.BriefReport() << "\n";
+        std::cout << summary.FullReport() << "\n";
+        // std::cout << summary.BriefReport() << "\n";
 
         ARMARX_INFO << "orientations after: " << orientations;
+        ARMARX_INFO << "Optimization: " << summary.iterations.size() << " iterations";
+
+        if(not summary.IsSolutionUsable())
+        {
+            ARMARX_ERROR << "Orientation optimization failed!";
+            // TODO write to file
+        }
 
         const auto applyOrientation = [](const auto& p) -> core::TrajectoryPoint
         {
diff --git a/source/armarx/navigation/global_planning/test/global_planningTest.cpp b/source/armarx/navigation/global_planning/test/global_planningTest.cpp
deleted file mode 100644
index 2518dcfda0e01e336fae50adbaf3db98756010f4..0000000000000000000000000000000000000000
--- a/source/armarx/navigation/global_planning/test/global_planningTest.cpp
+++ /dev/null
@@ -1,38 +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/>.
- *
- * @package    Navigation::ArmarXObjects::global_planning
- * @author     Fabian Reister ( fabian dot reister at kit dot edu )
- * @author     Christian R. G. Dreher ( c dot dreher at kit dot edu )
- * @date       2021
- * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
- *             GNU General Public License
- */
-
-#define BOOST_TEST_MODULE Navigation::ArmarXLibraries::global_planning
-
-#define ARMARX_BOOST_TEST
-
-#include "../global_planning.h"
-
-#include <iostream>
-
-#include <armarx/navigation/Test.h>
-
-BOOST_AUTO_TEST_CASE(testExample)
-{
-
-    BOOST_CHECK_EQUAL(true, true);
-}
diff --git a/source/armarx/navigation/global_planning/test/orientation_optimization_test.cpp b/source/armarx/navigation/global_planning/test/orientation_optimization_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c584146cbd704f87e1a7317a27cd7f513298024b
--- /dev/null
+++ b/source/armarx/navigation/global_planning/test/orientation_optimization_test.cpp
@@ -0,0 +1,128 @@
+/**
+ * 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::global_planning
+ * @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
+ */
+
+#include <cstddef>
+
+#include <boost/test/tools/old/interface.hpp>
+
+#include <SimoxUtility/math/convert/mat3f_to_rpy.h>
+#define BOOST_TEST_MODULE Navigation::ArmarXLibraries::global_planning
+
+#define ARMARX_BOOST_TEST
+
+#include <cmath>
+#include <iostream>
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include "armarx/navigation/core/basic_types.h"
+#include <armarx/navigation/Test.h>
+#include <armarx/navigation/global_planning/optimization/OrientationOptimizer.h>
+
+BOOST_AUTO_TEST_CASE(testOrientationOptimizationRotatedGoal)
+{
+    namespace nav = armarx::navigation;
+    namespace gp = armarx::navigation::glob_plan;
+
+    nav::core::Path path;
+    path.emplace_back(nav::core::Pose::Identity());
+    path.emplace_back(Eigen::Translation3f{Eigen::Vector3f::UnitX() * 500});
+    path.emplace_back(Eigen::Translation3f{Eigen::Vector3f::UnitX() * 1000});
+    path.emplace_back(Eigen::Translation3f{Eigen::Vector3f::UnitX() * 1500});
+    path.emplace_back(Eigen::Translation3f{Eigen::Vector3f::UnitX() * 2000} *
+                      Eigen::AngleAxis(M_PI_2f32, Eigen::Vector3f::UnitZ()));
+
+    const auto trajectory = nav::core::Trajectory::FromPath(path, 100);
+
+    gp::OrientationOptimizer::Params params{};
+
+
+    gp::OrientationOptimizer optimizer(trajectory, params);
+
+    const gp::OrientationOptimizer::OptimizationResult result = optimizer.optimize();
+
+    // # of points should be unchanged
+    BOOST_REQUIRE_EQUAL(result.trajectory.poses().size(), trajectory.poses().size());
+
+    // avoid an underflow in the for loop below
+    BOOST_REQUIRE_GE(trajectory.poses().size(), 2);
+
+    // loop over intermediate points
+    for (std::size_t i = 0; i < (result.trajectory.poses().size() - 2); i++)
+    {
+        const auto rpy = simox::math::mat3f_to_rpy(result.trajectory.poses().at(i).linear());
+        const auto yaw = rpy.z();
+
+        // The orientation should be changed compared to the unoptimized version.
+        // As the last pose is rotated by 90°, the intermediate poses should at least be
+        // changed gentlty into this direction.
+        BOOST_CHECK_GT(yaw, 0.1);
+    }
+}
+
+
+BOOST_AUTO_TEST_CASE(testOrientationOptimizationCircular)
+{
+    namespace nav = armarx::navigation;
+    namespace gp = armarx::navigation::glob_plan;
+
+    nav::core::Path path;
+    path.emplace_back(nav::core::Pose::Identity());
+    for (int i = 0; i < 20; i++)
+    {
+        path.emplace_back(Eigen::Translation3f{Eigen::Vector3f::UnitX() * 500 * i} *
+                          Eigen::AngleAxis(M_PI_2f32 * i, Eigen::Vector3f::UnitZ()));
+    }
+
+    path.emplace_back(Eigen::Translation3f{Eigen::Vector3f::UnitX() * 500 * 20});
+
+
+    const auto trajectory = nav::core::Trajectory::FromPath(path, 100);
+
+    // Here we don't care about the orientatation prior.
+    // The orientation of the intermediate points should converge to 0 (same direction as start and goal)
+    gp::OrientationOptimizer::Params params{.priorWeight = 0.F};
+
+
+    gp::OrientationOptimizer optimizer(trajectory, params);
+
+    const gp::OrientationOptimizer::OptimizationResult result = optimizer.optimize();
+
+    // # of points should be unchanged
+    BOOST_REQUIRE_EQUAL(result.trajectory.poses().size(), trajectory.poses().size());
+
+    // avoid an underflow in the for loop below
+    BOOST_REQUIRE_GE(trajectory.poses().size(), 2);
+
+    // loop over intermediate points
+    for (std::size_t i = 0; i < (result.trajectory.poses().size() - 2); i++)
+    {
+        const auto rpy = simox::math::mat3f_to_rpy(result.trajectory.poses().at(i).linear());
+        const auto yaw = rpy.z();
+
+        // The orientation should be changed compared to the unoptimized version.
+        // As the last pose is oriented the same way as the start, the intermediate poses should 
+        // have the same orientation. => yaw ~= 0
+        BOOST_CHECK_LT(std::abs(yaw), 0.01);
+    }
+}
diff --git a/source/armarx/navigation/server/Navigator.cpp b/source/armarx/navigation/server/Navigator.cpp
index bb1a6296e68d705e9806c163b2a9a895c461811c..5653dd7cb84ad375b35287853205f9f1e2d0dcff 100644
--- a/source/armarx/navigation/server/Navigator.cpp
+++ b/source/armarx/navigation/server/Navigator.cpp
@@ -88,7 +88,7 @@ namespace armarx::navigation::server
                 case armarx::navigation::client::GlobalPlanningStrategy::Free:
                 {
                     ARMARX_VERBOSE << "Global planning from " << start.translation() << " to "
-                                 << goal.translation();
+                                   << goal.translation();
                     ARMARX_CHECK_NOT_NULL(config.stack.globalPlanner);
 
                     try
@@ -97,7 +97,8 @@ namespace armarx::navigation::server
                         if (globalPlan.has_value())
                         {
                             edge.attrib().trajectory = globalPlan->trajectory;
-                            ARMARX_VERBOSE << "Free path length: " << globalPlan->trajectory.length();
+                            ARMARX_VERBOSE << "Free path length: "
+                                           << globalPlan->trajectory.length();
                             edge.attrib().cost() = globalPlan->trajectory.length();
                         }
                         else
@@ -109,7 +110,7 @@ namespace armarx::navigation::server
                     catch (...)
                     {
                         ARMARX_VERBOSE << "Global planning failed due to exception "
-                                     << GetHandledExceptionString();
+                                       << GetHandledExceptionString();
                         edge.attrib().cost() = std::numeric_limits<float>::max();
                     }
 
@@ -162,7 +163,7 @@ namespace armarx::navigation::server
                      const core::Graph::ConstVertex& goalVertex)
     {
         ARMARX_VERBOSE << "Graph consists of " << graph.numVertices() << " vertices and "
-                     << graph.numEdges() << " edges.";
+                       << graph.numEdges() << " edges.";
 
         std::vector<core::Graph::VertexDescriptor> predecessors(graph.numVertices());
         std::vector<int> d(num_vertices(graph));
@@ -189,7 +190,7 @@ namespace armarx::navigation::server
         for (const auto& edge : graph.edges())
         {
             ARMARX_VERBOSE << edge.sourceObjectID() << " -> " << edge.targetObjectID() << ": "
-                         << edge.attrib().m_value;
+                           << edge.attrib().m_value;
         }
 
         std::vector<core::Graph::EdgeDescriptor> edgesToBeRemoved;
@@ -210,15 +211,15 @@ namespace armarx::navigation::server
         for (const auto& edge : graph.edges())
         {
             ARMARX_VERBOSE << edge.sourceObjectID() << " -> " << edge.targetObjectID() << ": "
-                         << edge.attrib().m_value;
+                           << edge.attrib().m_value;
             ARMARX_VERBOSE << "Edge: " << edge << "cost: " << edge.attrib().cost()
-                         << ", type: " << static_cast<int>(edge.attrib().strategy) << " , has traj "
-                         << edge.attrib().trajectory.has_value();
+                           << ", type: " << static_cast<int>(edge.attrib().strategy)
+                           << " , has traj " << edge.attrib().trajectory.has_value();
         }
 
         ARMARX_VERBOSE << "Searching shortest path from vertex with id `"
-                     << graph.vertex(start).objectID() << "` to vertex `"
-                     << graph.vertex(goalVertex.descriptor()).objectID() << "`";
+                       << graph.vertex(start).objectID() << "` to vertex `"
+                       << graph.vertex(goalVertex.descriptor()).objectID() << "`";
 
         boost::dijkstra_shortest_paths(graph, start, params);
 
@@ -243,8 +244,9 @@ namespace armarx::navigation::server
             // find edge between parent and currentVertex
             auto outEdges = graph.vertex(parent).outEdges();
             ARMARX_VERBOSE << "Parent has " << std::distance(outEdges.begin(), outEdges.end())
-                         << " out edges";
-            ARMARX_CHECK(std::distance(outEdges.begin(), outEdges.end()) > 0); // not empty
+                           << " out edges";
+
+            ARMARX_CHECK_GREATER(std::distance(outEdges.begin(), outEdges.end()), 0) << "Cannot reach another vertex from vertex `" << graph.vertex(parent).objectID(); // not empty
 
             auto edgeIt = std::find_if(outEdges.begin(),
                                        outEdges.end(),
@@ -361,18 +363,25 @@ namespace armarx::navigation::server
                     // resample event straight lines
                     ARMARX_CHECK_NOT_EMPTY(trajectoryPoints);
 
-                    const core::Trajectory segmentTraj({trajectoryPoints.back(), nextTrajPt});
-                    ARMARX_INFO << "Segment trajectory length: " << segmentTraj.length();
+                    // const core::Trajectory segmentTraj({trajectoryPoints.back(), nextTrajPt});
+                    // ARMARX_INFO << "Segment trajectory length: " << segmentTraj.length();
+
+                    // const auto resampledTrajectory = segmentTraj.resample(500); // FIXME param
 
-                    const auto resampledTrajectory = segmentTraj.resample(500); // FIXME param
+                    // ARMARX_INFO << "Resampled trajectory contains "
+                    //           << resampledTrajectory.points().size() << " points";
 
-                    ARMARX_INFO << "Resampled trajectory contains "
-                                << resampledTrajectory.points().size() << " points";
+                    // this is the same pose as the goal of the previous segment but with a different velocity
+                    // FIXME MUST set velocity here.
+                    // trajectoryPoints.push_back(
+                        // core::TrajectoryPoint{.waypoint = trajectoryPoints.back().waypoint,
+                                            //   .velocity = std::numeric_limits<float>::max()});
 
                     ARMARX_TRACE;
-                    trajectoryPoints.insert(trajectoryPoints.end(),
-                                            resampledTrajectory.points().begin(),
-                                            resampledTrajectory.points().end());
+                    // trajectoryPoints.insert(trajectoryPoints.end(),
+                    //                         resampledTrajectory.points().begin(),
+                    //                         resampledTrajectory.points().end());
+                    trajectoryPoints.push_back(nextTrajPt);
 
                     break;
                 }
@@ -533,6 +542,8 @@ namespace armarx::navigation::server
 
         ARMARX_VERBOSE << graph;
 
+        srv.introspector->onGlobalGraph(graph);
+
         ARMARX_TRACE;
         const auto shortestPath = findShortestPath(graph, startVertex.value(), goalVertex);
 
@@ -858,8 +869,9 @@ namespace armarx::navigation::server
 
         const core::Rotation robot_R_world(config.scene->robot->getGlobalOrientation().inverse());
 
-        ARMARX_VERBOSE << deactivateSpam(100) << "Robot orientation "
-                     << simox::math::mat3f_to_rpy(config.scene->robot->getGlobalOrientation()).z();
+        ARMARX_VERBOSE
+            << deactivateSpam(100) << "Robot orientation "
+            << simox::math::mat3f_to_rpy(config.scene->robot->getGlobalOrientation()).z();
 
         core::Twist robotFrameVelocity;
 
@@ -868,7 +880,7 @@ namespace armarx::navigation::server
         robotFrameVelocity.angular = twist.angular;
 
         ARMARX_VERBOSE << deactivateSpam(1) << "velocity in robot frame "
-                     << robotFrameVelocity.linear;
+                       << robotFrameVelocity.linear;
 
         srv.executor->move(robotFrameVelocity);
     }
diff --git a/source/armarx/navigation/server/introspection/ArvizIntrospector.cpp b/source/armarx/navigation/server/introspection/ArvizIntrospector.cpp
index 21e2638773cf1b36fb2b3684a48a2bf81ed090df..5607b29e86c11db028cce98f317cee24dbb1bfbf 100644
--- a/source/armarx/navigation/server/introspection/ArvizIntrospector.cpp
+++ b/source/armarx/navigation/server/introspection/ArvizIntrospector.cpp
@@ -175,4 +175,38 @@ namespace armarx::navigation::server
         return *this;
     }
 
+    void
+    ArvizIntrospector::onGlobalGraph(const core::Graph& graph)
+    {
+        auto layer = arviz.layer("global_planning_graph");
+
+
+        for (const auto& edge : graph.edges())
+        {
+
+            const auto sourcePose = graph.vertex(edge.sourceDescriptor()).attrib().getPose();
+            const auto targetPose = graph.vertex(edge.targetDescriptor()).attrib().getPose();
+
+
+            const viz::Color color = [&]()
+            {
+                if (edge.attrib().cost() > 100'000) // "NaN check"
+                {
+                    return viz::Color::red();
+                }
+
+                return viz::Color::green();
+            }();
+
+
+            layer.add(viz::Arrow(std::to_string(edge.sourceObjectID().t) + " -> " +
+                                                std::to_string(edge.targetObjectID().t))
+                          .fromTo(sourcePose.translation(), targetPose.translation())
+                          .color(color));
+        }
+
+        arviz.commit(layer);
+    }
+
+
 } // namespace armarx::navigation::server
diff --git a/source/armarx/navigation/server/introspection/ArvizIntrospector.h b/source/armarx/navigation/server/introspection/ArvizIntrospector.h
index cc67dccd67355215c411f7cdf8a6d8df8b25b660..8d20cd8cccc608f04d10dcf76888821817e968d2 100644
--- a/source/armarx/navigation/server/introspection/ArvizIntrospector.h
+++ b/source/armarx/navigation/server/introspection/ArvizIntrospector.h
@@ -61,6 +61,9 @@ namespace armarx::navigation::server
 
         void onGlobalShortestPath(const std::vector<core::Pose>& path) override;
 
+        void onGlobalGraph(const core::Graph& graph) override;
+
+
 
         // // Non-API
         ArvizIntrospector(ArvizIntrospector&& other) noexcept;
diff --git a/source/armarx/navigation/server/introspection/IntrospectorInterface.h b/source/armarx/navigation/server/introspection/IntrospectorInterface.h
index 50b6ca851beeb9380cea632da87601450143e469..316cb9baa11690e2d1bfcc0a72cecb9ba8973264 100644
--- a/source/armarx/navigation/server/introspection/IntrospectorInterface.h
+++ b/source/armarx/navigation/server/introspection/IntrospectorInterface.h
@@ -47,6 +47,8 @@ namespace armarx::navigation::server
 
         virtual void onGlobalShortestPath(const std::vector<core::Pose>& path) = 0;
 
+        virtual void onGlobalGraph(const core::Graph& graph) = 0;
+
     protected:
     private:
     };
diff --git a/source/armarx/navigation/server/introspection/MemoryIntrospector.h b/source/armarx/navigation/server/introspection/MemoryIntrospector.h
index 0e4a53549ea40ce726fcc3d44721fc3648662296..2efb102a0e5467a6ae659be7e29c59319f702dc1 100644
--- a/source/armarx/navigation/server/introspection/MemoryIntrospector.h
+++ b/source/armarx/navigation/server/introspection/MemoryIntrospector.h
@@ -51,6 +51,11 @@ namespace armarx::navigation::server
         {
         }
 
+        void
+        onGlobalGraph(const core::Graph& graph) override
+        {
+        }
+
 
     protected:
     private: