From 4d9828b0302be8804414a9179bfcbb0d1b4ed290 Mon Sep 17 00:00:00 2001
From: Fabian Peller <fabian.peller-konrad@kit.edu>
Date: Sun, 14 May 2023 13:46:23 +0200
Subject: [PATCH] convenience methods to heartbeat component plugin

---
 .../GamepadControlUnit/CMakeLists.txt         |   2 +-
 .../GamepadControlUnit/GamepadControlUnit.cpp | 229 +++++++++---------
 .../HokuyoLaserUnit/HokuyoLaserUnit.cpp       |  32 +--
 .../drivers/HokuyoLaserUnit/HokuyoLaserUnit.h |  47 ++--
 .../HeartbeatComponentPlugin.cpp              |  94 ++++---
 .../HeartbeatComponentPlugin.h                |  55 ++++-
 6 files changed, 264 insertions(+), 195 deletions(-)

diff --git a/source/RobotAPI/components/GamepadControlUnit/CMakeLists.txt b/source/RobotAPI/components/GamepadControlUnit/CMakeLists.txt
index c3b764a15..8154ff69a 100644
--- a/source/RobotAPI/components/GamepadControlUnit/CMakeLists.txt
+++ b/source/RobotAPI/components/GamepadControlUnit/CMakeLists.txt
@@ -1,6 +1,6 @@
 armarx_component_set_name("GamepadControlUnit")
 
-set(COMPONENT_LIBS ArmarXCoreInterfaces ArmarXCore ArmarXCoreObservers RobotAPIInterfaces )
+set(COMPONENT_LIBS ArmarXCoreInterfaces ArmarXCore ArmarXCoreObservers RobotAPIComponentPlugins RobotAPIInterfaces )
 
 set(SOURCES GamepadControlUnit.cpp)
 set(HEADERS GamepadControlUnit.h)
diff --git a/source/RobotAPI/components/GamepadControlUnit/GamepadControlUnit.cpp b/source/RobotAPI/components/GamepadControlUnit/GamepadControlUnit.cpp
index 55c65ddae..ee2983e5a 100644
--- a/source/RobotAPI/components/GamepadControlUnit/GamepadControlUnit.cpp
+++ b/source/RobotAPI/components/GamepadControlUnit/GamepadControlUnit.cpp
@@ -22,17 +22,15 @@
 
 #include "GamepadControlUnit.h"
 
-#include <ArmarXCore/observers/variant/TimestampVariant.h>
-
 #include <ArmarXCore/core/time/DateTime.h>
 #include <ArmarXCore/core/time/Duration.h>
 #include <ArmarXCore/core/time/ice_conversions.h>
-
-
+#include <ArmarXCore/observers/variant/TimestampVariant.h>
 
 namespace armarx
 {
-    void GamepadControlUnit::onInitComponent()
+    void
+    GamepadControlUnit::onInitComponent()
     {
         ARMARX_INFO << "oninit GamepadControlUnit";
         usingProxy(getProperty<std::string>("PlatformUnitName").getValue());
@@ -43,78 +41,81 @@ namespace armarx
         scaleY = getProperty<float>("ScaleY").getValue();
         scaleRotation = getProperty<float>("ScaleAngle").getValue();
         ARMARX_INFO << "oninit GamepadControlUnit end";
-
-
-
     }
 
-
-    void GamepadControlUnit::onConnectComponent()
+    void
+    GamepadControlUnit::onConnectComponent()
     {
         ARMARX_INFO << "onConnect GamepadControlUnit";
-        platformUnitPrx = getProxy<PlatformUnitInterfacePrx>(getProperty<std::string>("PlatformUnitName").getValue());
+        platformUnitPrx = getProxy<PlatformUnitInterfacePrx>(
+            getProperty<std::string>("PlatformUnitName").getValue());
         emergencyStop = getProxy<EmergencyStopMasterInterfacePrx>("EmergencyStopMaster");
 
-        RobotHealthHeartbeatArgs args;
-        args.componentName = getDefaultName();
-
-        auto warningTime = armarx::core::time::Duration::MilliSeconds(1000);
 
-        armarx::core::time::toIce(args.maximumCycleTimeWarning, warningTime);
-        args.description = "The GamepadControlUnit";
-        args.requiredByDefault = true;
-        args.aliases = {"Gamepad"};
-        this->heartbeat->signUp(args);
+        if (enableHeartBeat)
+        {
+            this->heartbeat->signUp(armarx::core::time::Duration::MilliSeconds(1000),
+                                    armarx::core::time::Duration::MilliSeconds(1500),
+                                    false,
+                                    {"Gamepad"},
+                                    "The GamepadControlUnit");
+        }
     }
 
-
-    void GamepadControlUnit::onDisconnectComponent()
+    void
+    GamepadControlUnit::onDisconnectComponent()
     {
-
     }
 
-
-    void GamepadControlUnit::onExitComponent()
+    void
+    GamepadControlUnit::onExitComponent()
     {
         ARMARX_INFO << "exit GamepadControlUnit";
     }
 
-    armarx::PropertyDefinitionsPtr GamepadControlUnit::createPropertyDefinitions()
+    armarx::PropertyDefinitionsPtr
+    GamepadControlUnit::createPropertyDefinitions()
     {
-        auto defs = armarx::PropertyDefinitionsPtr(new GamepadControlUnitPropertyDefinitions(
-                getConfigIdentifier()));
-	defs->topic(robotHealthTopic);
-	defs->optional(enableHeartBeat, "EnableHeartBeat", "Flag to enable send a heart beat to the robot healh topic");
-	return defs;
+        auto defs = armarx::PropertyDefinitionsPtr(
+            new GamepadControlUnitPropertyDefinitions(getConfigIdentifier()));
+        defs->optional(enableHeartBeat,
+                       "EnableHeartBeat",
+                       "Flag to enable send a heart beat to the robot healh topic");
+        return defs;
     }
 
-    void GamepadControlUnit::reportGamepadState(const std::string& device, const std::string& name, const GamepadData& data, const TimestampBasePtr& timestamp, const Ice::Current& c)
+    void
+    GamepadControlUnit::reportGamepadState(const std::string& device,
+                                           const std::string& name,
+                                           const GamepadData& data,
+                                           const TimestampBasePtr& timestamp,
+                                           const Ice::Current& c)
     {
 
 
-       // struct GamepadData {
-       //     float leftStickX;
-       //     float leftStickY;
-       //     float rightStickX;
-       //     float rightStickY;
-       //     float dPadX;
-       //     float dPadY;
-       //     float leftTrigger;
-       //     float rightTrigger;
-       //
-       //     bool leftButton;
-       //     bool rightButton;
-       //     bool backButton;
-       //     bool startButton;
-       //     bool xButton;
-       //     bool yButton;
-       //     bool aButton;
-       //     bool bButton;
-       //     bool theMiddleButton;
-       //     bool leftStickButton;
-       //     bool rightStickButton;
-       //
-       // };
+        // struct GamepadData {
+        //     float leftStickX;
+        //     float leftStickY;
+        //     float rightStickX;
+        //     float rightStickY;
+        //     float dPadX;
+        //     float dPadY;
+        //     float leftTrigger;
+        //     float rightTrigger;
+        //
+        //     bool leftButton;
+        //     bool rightButton;
+        //     bool backButton;
+        //     bool startButton;
+        //     bool xButton;
+        //     bool yButton;
+        //     bool aButton;
+        //     bool bButton;
+        //     bool theMiddleButton;
+        //     bool leftStickButton;
+        //     bool rightStickButton;
+        //
+        // };
 
 
         if (data.leftTrigger > 0)
@@ -129,7 +130,9 @@ namespace armarx
         //scales are for the robot axis
         if (data.rightTrigger > 0)
         {
-            platformUnitPrx->move(data.leftStickY  * scaleX, data. leftStickX  * scaleY, data.rightStickX * scaleRotation);
+            platformUnitPrx->move(data.leftStickY * scaleX,
+                                  data.leftStickX * scaleY,
+                                  data.rightStickX * scaleRotation);
         }
         else
         {
@@ -137,63 +140,63 @@ namespace armarx
         }
 
 
-	if (data.leftButton)
-	{
-
-		if(leftHandTime <= 0.0)
-		{
-			leftHandTime = IceUtil::Time::now().toMicroSeconds();
-		}
-		else if ((IceUtil::Time::now().toMicroSeconds() - leftHandTime) > 1000* 1000)
-		{
-
-			HandUnitInterfacePrx handUnit = getProxy<HandUnitInterfacePrx>("LeftHandUnit");
-			if (handUnit)
-			{
-				std::string shapeName = (leftHandOpen) ? "Close" : "Open";
-				handUnit->setShape(shapeName);
-				leftHandOpen = !leftHandOpen;
-				leftHandTime = 0.0;
-			}
-		}
-	}
-	else
-	{
-		leftHandTime = 0.0;
-	}
-
-	if(data.rightButton)
-	{
-	
-		if(rightHandTime <= 0.0)
-		{
-			rightHandTime = IceUtil::Time::now().toMicroSeconds();
-		}
-		else if ((IceUtil::Time::now().toMicroSeconds() - rightHandTime) > 1000* 1000)
-		{
-			HandUnitInterfacePrx handUnit = getProxy<HandUnitInterfacePrx>("RightHandUnit");
-			if (handUnit)
-			{
-				std::string shapeName = (rightHandOpen) ? "Close" : "Open";
-				handUnit->setShape(shapeName);
-				rightHandOpen = !rightHandOpen;
-				rightHandTime = 0.0;
-			}
-		}
-	}
-	else
-	{
-		rightHandTime = 0.0;
-	}
-
-
-	if(enableHeartBeat)
+        if (data.leftButton)
+        {
+
+            if (leftHandTime <= 0.0)
+            {
+                leftHandTime = IceUtil::Time::now().toMicroSeconds();
+            }
+            else if ((IceUtil::Time::now().toMicroSeconds() - leftHandTime) > 1000 * 1000)
+            {
+
+                HandUnitInterfacePrx handUnit = getProxy<HandUnitInterfacePrx>("LeftHandUnit");
+                if (handUnit)
+                {
+                    std::string shapeName = (leftHandOpen) ? "Close" : "Open";
+                    handUnit->setShape(shapeName);
+                    leftHandOpen = !leftHandOpen;
+                    leftHandTime = 0.0;
+                }
+            }
+        }
+        else
+        {
+            leftHandTime = 0.0;
+        }
+
+        if (data.rightButton)
+        {
+
+            if (rightHandTime <= 0.0)
+            {
+                rightHandTime = IceUtil::Time::now().toMicroSeconds();
+            }
+            else if ((IceUtil::Time::now().toMicroSeconds() - rightHandTime) > 1000 * 1000)
+            {
+                HandUnitInterfacePrx handUnit = getProxy<HandUnitInterfacePrx>("RightHandUnit");
+                if (handUnit)
+                {
+                    std::string shapeName = (rightHandOpen) ? "Close" : "Open";
+                    handUnit->setShape(shapeName);
+                    rightHandOpen = !rightHandOpen;
+                    rightHandTime = 0.0;
+                }
+            }
+        }
+        else
+        {
+            rightHandTime = 0.0;
+        }
+
+
+        if (enableHeartBeat)
         {
-          auto now = armarx::core::time::dto::DateTime();
-          armarx::core::time::toIce(now, armarx::core::time::DateTime::Now());
-          robotHealthTopic->heartbeat(getDefaultName(), "", now);
-	}
-                
+            auto now = armarx::core::time::dto::DateTime();
+            armarx::core::time::toIce(now, armarx::core::time::DateTime::Now());
+            heartbeat->heartbeat();
+        }
+
         //ARMARX_INFO << "sending targets" << data.leftStickX* scaleX << " " << data.leftStickY* scaleY << " " << data.rightStickX* scaleRotation;
     }
-}
+} // namespace armarx
diff --git a/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.cpp b/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.cpp
index 7332a8cbe..add212dcb 100644
--- a/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.cpp
+++ b/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.cpp
@@ -84,8 +84,6 @@ HokuyoLaserUnit::onInitComponent()
 void
 HokuyoLaserUnit::onConnectComponent()
 {
-    robotHealthTopic = getTopic<RobotHealthInterfacePrx>(
-        getProperty<std::string>("RobotHealthTopicName").getValue());
     topic = getTopic<LaserScannerUnitListenerPrx>(topicName);
     debugObserver = getTopic<DebugObserverInterfacePrx>(
         getProperty<std::string>("DebugObserverName").getValue());
@@ -107,21 +105,12 @@ HokuyoLaserUnit::onConnectComponent()
             continue;
         }
 
-        RobotHealthHeartbeatArgs args;
-        auto warn = armarx::core::time::Duration::MilliSeconds(500);
-        auto err = armarx::core::time::Duration::MilliSeconds(800);
-        armarx::core::time::toIce(args.maximumCycleTimeWarning, warn);
-        armarx::core::time::toIce(args.maximumCycleTimeError, err);
-        args.componentName = device.componentName + "_" + device.ip;
-
-        if (robotHealthTopic)
-        {
-          robotHealthTopic->signUp(args);
-        }
-        else
-        {
-          ARMARX_WARNING << "No robot health topic available: IP: " << device.ip << ", Port: " << device.port;
-        }
+        heartbeat->signUp(device.componentName + "_" + device.ip,
+                          armarx::core::time::Duration::MilliSeconds(500),
+                          armarx::core::time::Duration::MilliSeconds(800),
+                          true,
+                          {"LaserScanner"},
+                          "HokuyoLaserScanDevice");
 
         LaserScannerInfo info;
         info.device = device.ip;
@@ -137,7 +126,7 @@ HokuyoLaserUnit::onConnectComponent()
         device.lengthData.resize(lengthDataSize);
 
         device.scanTopic = topic;
-        device.robotHealthTopic = robotHealthTopic;
+        device.robotHealthPlugin = heartbeat;
         device.debugObserver = debugObserver;
 
         connectedDevices.push_back(info);
@@ -284,12 +273,9 @@ HokuyoLaserScanDevice::run()
             }
             IceUtil::Time time_topicSensor = TimeUtil::GetTime();
 
-            RobotHealthHeartbeatArgs args;
-            args.maximumCycleTimeWarningMS = 500;
-            args.maximumCycleTimeErrorMS = 800;
-            if (robotHealthTopic)
+            if (robotHealthPlugin)
             {
-                robotHealthTopic->heartbeat(componentName + "_" + ip, args);
+                robotHealthPlugin->heartbeatOnChannel(componentName + "_" + ip);
             }
             else
             {
diff --git a/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.h b/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.h
index 57595aff8..560a5dd12 100644
--- a/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.h
+++ b/source/RobotAPI/drivers/HokuyoLaserUnit/HokuyoLaserUnit.h
@@ -22,14 +22,17 @@
 
 #pragma once
 
+#include <vector>
+
 #include <ArmarXCore/core/Component.h>
 #include <ArmarXCore/core/services/tasks/RunningTask.h>
+
 #include <RobotAPI/components/units/SensorActorUnit.h>
-#include <RobotAPI/interface/units/LaserScannerUnit.h>
 #include <RobotAPI/interface/components/RobotHealthInterface.h>
+#include <RobotAPI/interface/units/LaserScannerUnit.h>
+#include <RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h>
 
 #include <HokuyoLaserScannerDriver/urg_sensor.h>
-#include <vector>
 
 namespace armarx
 {
@@ -37,21 +40,30 @@ namespace armarx
      * @class HokuyoLaserUnitPropertyDefinitions
      * @brief
      */
-    class HokuyoLaserUnitPropertyDefinitions:
-        public armarx::ComponentPropertyDefinitions
+    class HokuyoLaserUnitPropertyDefinitions : public armarx::ComponentPropertyDefinitions
     {
     public:
-        HokuyoLaserUnitPropertyDefinitions(std::string prefix):
+        HokuyoLaserUnitPropertyDefinitions(std::string prefix) :
             armarx::ComponentPropertyDefinitions(prefix)
         {
-            defineOptionalProperty<std::string>("LaserScannerTopicName", "LaserScans", "Name of the laser scan topic.");
+            defineOptionalProperty<std::string>(
+                "LaserScannerTopicName", "LaserScans", "Name of the laser scan topic.");
             defineOptionalProperty<int>("UpdatePeriod", 25, "Update period for laser scans");
-            defineOptionalProperty<float>("AngleOffset", -2.3561944902, "Offset is applied the raw angles before reporting them");
-            defineOptionalProperty<std::string>("Devices", "", "List of devices in form of 'IP1,port1,frame1;IP2,port2,frame2;...'");
-
-            defineOptionalProperty<std::string>("RobotHealthComponentName", "RobotHealth", "Name of the RobotHealth component");
-            defineOptionalProperty<std::string>("RobotHealthTopicName", "RobotHealthTopic", "Name of the RobotHealth topic");
-            defineOptionalProperty<std::string>("DebugObserverName", "DebugObserver", "Name of the topic the DebugObserver listens on");
+            defineOptionalProperty<float>("AngleOffset",
+                                          -2.3561944902,
+                                          "Offset is applied the raw angles before reporting them");
+            defineOptionalProperty<std::string>(
+                "Devices",
+                "",
+                "List of devices in form of 'IP1,port1,frame1;IP2,port2,frame2;...'");
+
+            defineOptionalProperty<std::string>(
+                "RobotHealthComponentName", "RobotHealth", "Name of the RobotHealth component");
+            defineOptionalProperty<std::string>(
+                "RobotHealthTopicName", "RobotHealthTopic", "Name of the RobotHealth topic");
+            defineOptionalProperty<std::string>("DebugObserverName",
+                                                "DebugObserver",
+                                                "Name of the topic the DebugObserver listens on");
         }
     };
 
@@ -76,8 +88,7 @@ namespace armarx
 
         std::string componentName;
         LaserScannerUnitListenerPrx scanTopic;
-        RobotHealthPrx
-        RobotHealthInterfacePrx robotHealthTopic;
+        armarx::plugins::HeartbeatComponentPlugin* robotHealthPlugin;
         DebugObserverInterfacePrx debugObserver;
     };
 
@@ -94,13 +105,15 @@ namespace armarx
      */
     class HokuyoLaserUnit :
         virtual public armarx::LaserScannerUnitInterface,
+        virtual public armarx::HeartbeatComponentPluginUser,
         virtual public armarx::SensorActorUnit
     {
     public:
         /**
          * @see armarx::ManagedIceObject::getDefaultName()
          */
-        std::string getDefaultName() const override
+        std::string
+        getDefaultName() const override
         {
             return "HokuyoLaserUnit";
         }
@@ -142,8 +155,6 @@ namespace armarx
         float angleOffset = 0.0f;
         std::vector<HokuyoLaserScanDevice> devices;
         LaserScannerInfoSeq connectedDevices;
-        RobotHealthInterfacePrx robotHealthTopic;
         DebugObserverInterfacePrx debugObserver;
     };
-}
-
+} // namespace armarx
diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.cpp b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.cpp
index 6411af0bb..7daa93200 100644
--- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.cpp
@@ -10,46 +10,83 @@
 namespace armarx::plugins
 {
     void
-    HeartbeatComponentPlugin::configureHeartbeatChannel(const std::string& channel,
-                                                        const RobotHealthHeartbeatArgs& args)
+    HeartbeatComponentPlugin::signUp(bool required,
+                                     const std::vector<std::string> aliases,
+                                     const std::string& description)
     {
-        channelHeartbeatConfig.emplace(channel, args);
+        RobotHealthHeartbeatArgs argsCopy = defaultHeartbeatArgs;
+        argsCopy.description = description;
+        argsCopy.aliases = aliases;
+        argsCopy.requiredByDefault = required;
+        signUp(argsCopy);
     }
 
     void
-    HeartbeatComponentPlugin::configureHeartbeatChannel(const std::string& channel,
-                                                        const std::string& description)
+    HeartbeatComponentPlugin::signUp(const std::string& name,
+                                     bool required,
+                                     const std::vector<std::string> aliases,
+                                     const std::string& description)
     {
-        auto args = defaultHeartbeatArgs;
-        args.description = description;
-        configureHeartbeatChannel(channel, args);
+        RobotHealthHeartbeatArgs argsCopy = defaultHeartbeatArgs;
+        argsCopy.description = description;
+        argsCopy.componentName = name;
+        argsCopy.aliases = aliases;
+        argsCopy.requiredByDefault = required;
+        signUp(argsCopy);
     }
 
     void
-    HeartbeatComponentPlugin::signUp()
+    HeartbeatComponentPlugin::signUp(const std::string componentName,
+                                     const armarx::core::time::Duration& warning,
+                                     const armarx::core::time::Duration& error,
+                                     bool required,
+                                     const std::vector<std::string> aliases,
+                                     const std::string& description)
     {
-          RobotHealthHeartbeatArgs args = defaultHeartbeatArgs;
-          args.componentName = componentName;
-          p.rhprx->signUp(args);
+        RobotHealthHeartbeatArgs argsCopy = defaultHeartbeatArgs;
+        argsCopy.description = description;
+        argsCopy.aliases = aliases;
+        argsCopy.componentName = componentName;
+        armarx::core::time::toIce(argsCopy.maximumCycleTimeWarning, warning);
+        armarx::core::time::toIce(argsCopy.maximumCycleTimeError, error);
+        argsCopy.requiredByDefault = required;
+        signUp(argsCopy);
     }
 
     void
-    HeartbeatComponentPlugin::signUp(const std::string& channelName)
+    HeartbeatComponentPlugin::signUp(const armarx::core::time::Duration& warning,
+                                     const armarx::core::time::Duration& error,
+                                     bool required,
+                                     const std::vector<std::string> aliases,
+                                     const std::string& description)
     {
-          const auto argsIt = channelHeartbeatConfig.find(channelName);
-          ARMARX_CHECK(argsIt != channelHeartbeatConfig.end())
-              << "signUp(channel) called for unknown channel '" << channelName << "'."
-              << "You must register the config using configureHeartbeatChannel(channel) first!";
-
-          RobotHealthHeartbeatArgs args = channelHeartbeatConfig[channelName];
-          args.componentName = componentName + "_" + channelName;
-          p.rhprx->signUp(args);
+        RobotHealthHeartbeatArgs argsCopy = defaultHeartbeatArgs;
+        argsCopy.description = description;
+        argsCopy.aliases = aliases;
+        armarx::core::time::toIce(argsCopy.maximumCycleTimeWarning, warning);
+        armarx::core::time::toIce(argsCopy.maximumCycleTimeError, error);
+        argsCopy.requiredByDefault = required;
+        signUp(argsCopy);
     }
 
     void
-    HeartbeatComponentPlugin::heartbeat(const std::string& message)
+    HeartbeatComponentPlugin::signUp(const RobotHealthHeartbeatArgs& args)
     {
+        if (args.componentName.empty())
+        {
+            RobotHealthHeartbeatArgs argsCopy = args;
+            argsCopy.componentName = componentName;
+            p.rhprx->signUp(argsCopy);
+        }
+        else
+        {
+            p.rhprx->signUp(args);
+        }
+    }
 
+    void
+    HeartbeatComponentPlugin::heartbeat(const std::string& message)
+    {
         if (robotHealthTopic)
         {
             armarx::core::time::dto::DateTime now;
@@ -63,7 +100,8 @@ namespace armarx::plugins
     }
 
     void
-    HeartbeatComponentPlugin::heartbeat(const std::string& channelName, const std::string& message)
+    HeartbeatComponentPlugin::heartbeatOnChannel(const std::string& channelName,
+                                                 const std::string& message)
     {
         if (robotHealthTopic)
         {
@@ -102,8 +140,8 @@ namespace armarx::plugins
     void
     HeartbeatComponentPlugin::preOnConnectComponent()
     {
-      topicName = p.rhprx->getTopicName();
-      robotHealthTopic = parent<Component>().getTopic<RobotHealthInterfacePrx>(topicName);
+        topicName = p.rhprx->getTopicName();
+        robotHealthTopic = parent<Component>().getTopic<RobotHealthInterfacePrx>(topicName);
     }
 
     void
@@ -111,10 +149,8 @@ namespace armarx::plugins
     {
         if (!properties->hasDefinition(makePropertyName(healthPropertyName)))
         {
-            properties->component(p.rhprx,
-                                "RobotHealth",
-                              healthPropertyName,
-                              "Name of the robot health component.");
+            properties->component(
+                p.rhprx, "RobotHealth", healthPropertyName, "Name of the robot health component.");
         }
 
         if (not properties->hasDefinition(makePropertyName(maximumCycleTimeWarningMSPropertyName)))
diff --git a/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h
index 4f4e9564f..c237e9085 100644
--- a/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h
+++ b/source/RobotAPI/libraries/RobotAPIComponentPlugins/HeartbeatComponentPlugin.h
@@ -23,6 +23,7 @@
 
 #include <ArmarXCore/core/ComponentPlugin.h>
 #include <ArmarXCore/core/ManagedIceObject.h>
+#include <ArmarXCore/core/time/Duration.h>
 
 #include <RobotAPI/interface/components/RobotHealthInterface.h>
 
@@ -34,15 +35,44 @@ namespace armarx::plugins
     public:
         using ComponentPlugin::ComponentPlugin;
 
+        /**
+       * @brief register component to heartbeat
+       */
+        void signUp(bool requiredByDefault = true,
+                    const std::vector<std::string> aliases = {},
+                    const std::string& description = "");
+
         /**
          * @brief register component to heartbeat
          */
-        void signUp(const RobotHealthHeartbeatArgs& args);
+        void signUp(const std::string& name,
+                    bool requiredByDefault = true,
+                    const std::vector<std::string> aliases = {},
+                    const std::string& description = "");
+
+        /**
+         * @brief register component to heartbeat
+         */
+        void signUp(const armarx::core::time::Duration& warning,
+                    const armarx::core::time::Duration& error,
+                    bool requiredByDefault = true,
+                    const std::vector<std::string> aliases = {},
+                    const std::string& description = "");
+
+        /**
+         * @brief register component to heartbeat
+         */
+        void signUp(const std::string componentName,
+                    const armarx::core::time::Duration& warning,
+                    const armarx::core::time::Duration& error,
+                    bool requiredByDefault = true,
+                    const std::vector<std::string> aliases = {},
+                    const std::string& description = "");
 
         /**
-         * @brief register component with a specific name to heartbeat
+         * @brief register component to heartbeat, possibly with different component name
          */
-        void signUp(const std::string& channelName, const RobotHealthHeartbeatArgs& args);
+        void signUp(const RobotHealthHeartbeatArgs& args);
 
         /**
          * @brief Sends out a heartbeat using the default config
@@ -57,7 +87,7 @@ namespace armarx::plugins
          *
          * @param channel Identifier of the heartbeat channel
          */
-        void heartbeat(const std::string& channelName, const std::string& message = "");
+        void heartbeatOnChannel(const std::string& channelName, const std::string& message = "");
 
     protected:
         void preOnInitComponent() override;
@@ -66,6 +96,10 @@ namespace armarx::plugins
 
         void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override;
 
+    public:
+        RobotHealthInterfacePrx robotHealthTopic;
+        std::string topicName{"RobotHealthTopic"};
+
     private:
         //! heartbeat topic name (outgoing)
 
@@ -79,10 +113,6 @@ namespace armarx::plugins
         static constexpr auto maximumCycleTimeErrorMSPropertyName =
             "heartbeat.maximumCycleTimeErrorMS";
 
-
-        RobotHealthInterfacePrx robotHealthTopic;
-        std::string topicName{"RobotHealthTopic"};
-
         struct Properties
         {
             RobotHealthComponentInterfacePrx rhprx;
@@ -92,9 +122,6 @@ namespace armarx::plugins
 
         //! default config used in heartbeat(), set via properties
         RobotHealthHeartbeatArgs defaultHeartbeatArgs;
-
-        //! configs used in heartbeat(channel), set by user via configureHeartbeatChannel(...)
-        std::unordered_map<std::string, RobotHealthHeartbeatArgs> channelHeartbeatConfig;
     };
 } // namespace armarx::plugins
 
@@ -108,6 +135,12 @@ namespace armarx
     public:
         HeartbeatComponentPluginUser();
 
+        RobotHealthInterfacePrx
+        getHeartbeatTopic()
+        {
+            return heartbeat->robotHealthTopic;
+        }
+
     protected:
         armarx::plugins::HeartbeatComponentPlugin* heartbeat = nullptr;
     };
-- 
GitLab