Modulo 4.2.2
Loading...
Searching...
No Matches
ComponentInterface.hpp
1#pragma once
2
3#include <rclcpp/node_interfaces/node_interfaces.hpp>
4
5#include <tf2_ros/buffer.h>
6#include <tf2_ros/static_transform_broadcaster.h>
7#include <tf2_ros/transform_broadcaster.h>
8#include <tf2_ros/transform_listener.h>
9
10#include <state_representation/parameters/ParameterMap.hpp>
11
12#include <modulo_core/Predicate.hpp>
13#include <modulo_core/communication/PublisherHandler.hpp>
14#include <modulo_core/communication/PublisherType.hpp>
15#include <modulo_core/communication/SubscriptionHandler.hpp>
16#include <modulo_core/concepts.hpp>
17#include <modulo_core/exceptions.hpp>
18#include <modulo_core/translators/parameter_translators.hpp>
19
20#include <modulo_interfaces/msg/predicate_collection.hpp>
21#include <modulo_interfaces/srv/empty_trigger.hpp>
22#include <modulo_interfaces/srv/string_trigger.hpp>
23
24#include <modulo_utils/parsing.hpp>
25
30namespace modulo_components {
31
39 bool success;
40 std::string message;
41};
42
48
57public:
59
63 virtual ~ComponentInterface();
64
65protected:
70 explicit ComponentInterface(
71 const std::shared_ptr<rclcpp::node_interfaces::NodeInterfaces<ALL_RCLCPP_NODE_INTERFACES>>& interfaces);
72
77 double get_rate() const;
78
83 template<typename T>
84 T get_period() const;
85
89 virtual void step();
90
94 virtual void on_step_callback();
95
105 void add_parameter(
106 const std::shared_ptr<state_representation::ParameterInterface>& parameter, const std::string& description,
107 bool read_only = false);
108
120 template<typename T>
121 void add_parameter(const std::string& name, const T& value, const std::string& description, bool read_only = false);
122
129 [[nodiscard]] std::shared_ptr<state_representation::ParameterInterface> get_parameter(const std::string& name) const;
130
138 template<typename T>
139 [[nodiscard]] T get_parameter_value(const std::string& name) const;
140
149 template<typename T>
150 void set_parameter_value(const std::string& name, const T& value);
151
162 virtual bool
163 on_validate_parameter_callback(const std::shared_ptr<state_representation::ParameterInterface>& parameter);
164
170 void add_predicate(const std::string& predicate_name, bool predicate_value);
171
177 void add_predicate(const std::string& predicate_name, const std::function<bool(void)>& predicate_function);
178
185 [[nodiscard]] bool get_predicate(const std::string& predicate_name) const;
186
194 void set_predicate(const std::string& predicate_name, bool predicate_value);
195
203 void set_predicate(const std::string& predicate_name, const std::function<bool(void)>& predicate_function);
204
210 void add_trigger(const std::string& trigger_name);
211
216 void trigger(const std::string& trigger_name);
217
226 void declare_input(const std::string& signal_name, const std::string& default_topic = "", bool fixed_topic = false);
227
236 void declare_output(const std::string& signal_name, const std::string& default_topic = "", bool fixed_topic = false);
237
246 template<typename DataT>
247 void add_input(
248 const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::string& default_topic = "",
249 bool fixed_topic = false);
250
260 template<typename DataT>
261 void add_input(
262 const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::function<void()>& callback,
263 const std::string& default_topic = "", bool fixed_topic = false);
264
273 template<typename MsgT>
274 void add_input(
275 const std::string& signal_name, const std::function<void(const std::shared_ptr<MsgT>)>& callback,
276 const std::string& default_topic = "", bool fixed_topic = false);
277
290 template<typename DataT>
291 std::string create_output(
293 const std::shared_ptr<DataT>& data, const std::string& default_topic, bool fixed_topic, bool publish_on_step);
294
300 void publish_output(const std::string& signal_name);
301
306 void remove_input(const std::string& signal_name);
307
312 void remove_output(const std::string& signal_name);
313
319 void add_service(const std::string& service_name, const std::function<ComponentServiceResponse(void)>& callback);
320
329 void add_service(
330 const std::string& service_name,
331 const std::function<ComponentServiceResponse(const std::string& string)>& callback);
332
339 void add_periodic_callback(const std::string& name, const std::function<void(void)>& callback);
340
344 void add_tf_broadcaster();
345
350
354 void add_tf_listener();
355
360 void send_transform(const state_representation::CartesianPose& transform);
361
366 void send_transforms(const std::vector<state_representation::CartesianPose>& transforms);
367
372 void send_static_transform(const state_representation::CartesianPose& transform);
373
378 void send_static_transforms(const std::vector<state_representation::CartesianPose>& transforms);
379
390 [[nodiscard]] state_representation::CartesianPose lookup_transform(
391 const std::string& frame, const std::string& reference_frame, const tf2::TimePoint& time_point,
392 const tf2::Duration& duration);
393
404 [[nodiscard]] state_representation::CartesianPose lookup_transform(
405 const std::string& frame, const std::string& reference_frame = "world", double validity_period = -1.0,
406 const tf2::Duration& duration = tf2::Duration(std::chrono::microseconds(10)));
407
412 [[nodiscard]] rclcpp::QoS get_qos() const;
413
418 void set_qos(const rclcpp::QoS& qos);
419
423 virtual void raise_error();
424
428 void publish_predicates();
429
433 void publish_outputs();
434
439
440 std::map<std::string, std::shared_ptr<modulo_core::communication::SubscriptionInterface>> inputs_;
441 std::map<std::string, std::shared_ptr<modulo_core::communication::PublisherInterface>> outputs_;
442 std::map<std::string, bool> periodic_outputs_;
443
444private:
449 void pre_set_parameters_callback(std::vector<rclcpp::Parameter>& parameters);
450
457 rcl_interfaces::msg::SetParametersResult on_set_parameters_callback(const std::vector<rclcpp::Parameter>& parameters);
458
466 bool validate_parameter(const std::shared_ptr<state_representation::ParameterInterface>& parameter);
467
473 modulo_interfaces::msg::Predicate get_predicate_message(const std::string& name, bool value) const;
474
484 void declare_signal(
485 const std::string& signal_name, const std::string& type, const std::string& default_topic, bool fixed_topic);
486
495 template<typename T>
496 bool remove_signal(
497 const std::string& signal_name, std::map<std::string, std::shared_ptr<T>>& signal_map, bool skip_check = false);
498
507 std::string validate_service_name(const std::string& service_name, const std::string& type) const;
508
514 void publish_predicate(const std::string& predicate_name, bool value) const;
515
523 template<typename T>
524 void publish_transforms(
525 const std::vector<state_representation::CartesianPose>& transforms, const std::shared_ptr<T>& tf_broadcaster,
526 bool is_static = false);
527
538 [[nodiscard]] geometry_msgs::msg::TransformStamped lookup_ros_transform(
539 const std::string& frame, const std::string& reference_frame, const tf2::TimePoint& time_point,
540 const tf2::Duration& duration);
541
542 double rate_;
543 double period_;
544 std::mutex step_mutex_;
545
546 std::map<std::string, modulo_core::Predicate> predicates_;
547 std::shared_ptr<rclcpp::Publisher<modulo_interfaces::msg::PredicateCollection>>
548 predicate_publisher_;
549 modulo_interfaces::msg::PredicateCollection predicate_message_;
550 std::vector<std::string> triggers_;
551
552 std::map<std::string, std::shared_ptr<rclcpp::Service<modulo_interfaces::srv::EmptyTrigger>>>
553 empty_services_;
554 std::map<std::string, std::shared_ptr<rclcpp::Service<modulo_interfaces::srv::StringTrigger>>>
555 string_services_;
556
557 std::map<std::string, std::function<void(void)>> periodic_callbacks_;
558
559 state_representation::ParameterMap parameter_map_;
560 std::unordered_map<std::string, bool> read_only_parameters_;
561 std::shared_ptr<rclcpp::node_interfaces::PreSetParametersCallbackHandle>
562 pre_set_parameter_cb_handle_;
563 std::shared_ptr<rclcpp::node_interfaces::OnSetParametersCallbackHandle>
564 on_set_parameter_cb_handle_;
565 rcl_interfaces::msg::SetParametersResult set_parameters_result_;
566 bool pre_set_parameter_callback_called_ = false;
567
568 std::shared_ptr<rclcpp::TimerBase> step_timer_;
569 std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
570 std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
571 std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
572 std::shared_ptr<tf2_ros::StaticTransformBroadcaster> static_tf_broadcaster_;
573
574 std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_;
575 std::shared_ptr<rclcpp::node_interfaces::NodeClockInterface> node_clock_;
576 std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface> node_logging_;
577 std::shared_ptr<rclcpp::node_interfaces::NodeParametersInterface> node_parameters_;
578 std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_;
579 std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface> node_timers_;
580 std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface> node_topics_;
581 rclcpp::QoS qos_ = rclcpp::QoS(10);
582};
583
584template<typename T>
586 const std::string& name, const T& value, const std::string& description, bool read_only) {
587 if (name.empty()) {
588 RCLCPP_ERROR(this->node_logging_->get_logger(), "Failed to add parameter: Provide a non empty string as a name.");
589 return;
590 }
591 this->add_parameter(state_representation::make_shared_parameter(name, value), description, read_only);
592}
593
594template<typename T>
595inline T ComponentInterface::get_parameter_value(const std::string& name) const {
596 try {
597 return this->parameter_map_.template get_parameter_value<T>(name);
598 } catch (const state_representation::exceptions::InvalidParameterException& ex) {
600 "Failed to get parameter value of parameter '" + name + "': " + ex.what());
601 }
602}
603
604template<typename T>
605inline void ComponentInterface::set_parameter_value(const std::string& name, const T& value) {
606 try {
607 std::vector<rclcpp::Parameter> parameters{
608 modulo_core::translators::write_parameter(state_representation::make_shared_parameter(name, value))};
609 this->pre_set_parameters_callback(parameters);
610 this->pre_set_parameter_callback_called_ = true;
611 auto result = this->node_parameters_->set_parameters(parameters).at(0);
612 if (!result.successful) {
614 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
615 "Failed to set parameter value of parameter '" << name << "': " << result.reason);
616 }
617 } catch (const std::exception& ex) {
619 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
620 "Failed to set parameter value of parameter '" << name << "': " << ex.what());
621 }
622}
623
624template<typename DataT>
626 const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::string& default_topic,
627 bool fixed_topic) {
628 this->add_input(signal_name, data, [] {}, default_topic, fixed_topic);
629}
630
631template<typename DataT>
633 const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::function<void()>& user_callback,
634 const std::string& default_topic, bool fixed_topic) {
635 using namespace modulo_core::communication;
636 try {
637 if (data == nullptr) {
638 throw modulo_core::exceptions::NullPointerException("Invalid data pointer for input '" + signal_name + "'.");
639 }
640 this->declare_input(signal_name, default_topic, fixed_topic);
641 std::string parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
642 auto topic_name = this->get_parameter_value<std::string>(parsed_signal_name + "_topic");
644 this->node_logging_->get_logger(),
645 "Adding input '" << parsed_signal_name << "' with topic name '" << topic_name << "'.");
646 auto message_pair = make_shared_message_pair(data, this->node_clock_->get_clock());
647 std::shared_ptr<SubscriptionInterface> subscription_interface;
648 switch (message_pair->get_type()) {
649 case MessageType::BOOL: {
651 std::make_shared<SubscriptionHandler<std_msgs::msg::Bool>>(message_pair, this->node_logging_->get_logger());
652 auto subscription = rclcpp::create_subscription<std_msgs::msg::Bool>(
653 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
654 subscription_handler->get_callback(user_callback));
655 subscription_interface = subscription_handler->create_subscription_interface(subscription);
656 break;
657 }
658 case MessageType::FLOAT64: {
659 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::Float64>>(
660 message_pair, this->node_logging_->get_logger());
661 auto subscription = rclcpp::create_subscription<std_msgs::msg::Float64>(
662 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
663 subscription_handler->get_callback(user_callback));
664 subscription_interface = subscription_handler->create_subscription_interface(subscription);
665 break;
666 }
667 case MessageType::FLOAT64_MULTI_ARRAY: {
668 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::Float64MultiArray>>(
669 message_pair, this->node_logging_->get_logger());
670 auto subscription = rclcpp::create_subscription<std_msgs::msg::Float64MultiArray>(
671 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
672 subscription_handler->get_callback(user_callback));
673 subscription_interface = subscription_handler->create_subscription_interface(subscription);
674 break;
675 }
676 case MessageType::INT32: {
677 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::Int32>>(
678 message_pair, this->node_logging_->get_logger());
679 auto subscription = rclcpp::create_subscription<std_msgs::msg::Int32>(
680 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
681 subscription_handler->get_callback(user_callback));
682 subscription_interface = subscription_handler->create_subscription_interface(subscription);
683 break;
684 }
685 case MessageType::STRING: {
686 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::String>>(
687 message_pair, this->node_logging_->get_logger());
688 auto subscription = rclcpp::create_subscription<std_msgs::msg::String>(
689 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
690 subscription_handler->get_callback(user_callback));
691 subscription_interface = subscription_handler->create_subscription_interface(subscription);
692 break;
693 }
694 case MessageType::ENCODED_STATE: {
695 auto subscription_handler = std::make_shared<SubscriptionHandler<modulo_core::EncodedState>>(
696 message_pair, this->node_logging_->get_logger());
697 auto subscription = rclcpp::create_subscription<modulo_core::EncodedState>(
698 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
699 subscription_handler->get_callback(user_callback));
700 subscription_interface = subscription_handler->create_subscription_interface(subscription);
701 break;
702 }
703 case MessageType::CUSTOM_MESSAGE: {
706 std::make_shared<SubscriptionHandler<DataT>>(message_pair, this->node_logging_->get_logger());
707 auto subscription = rclcpp::create_subscription<DataT>(
708 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
709 subscription_handler->get_callback(user_callback));
710 subscription_interface = subscription_handler->create_subscription_interface(subscription);
711 }
712 break;
713 }
714 }
715 this->inputs_.insert_or_assign(parsed_signal_name, subscription_interface);
716 } catch (const std::exception& ex) {
718 this->node_logging_->get_logger(), "Failed to add input '" << signal_name << "': " << ex.what());
719 }
720}
721
722template<typename MsgT>
724 const std::string& signal_name, const std::function<void(const std::shared_ptr<MsgT>)>& callback,
725 const std::string& default_topic, bool fixed_topic) {
726 using namespace modulo_core::communication;
727 try {
728 std::string parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
729 this->declare_input(parsed_signal_name, default_topic, fixed_topic);
730 auto topic_name = this->get_parameter_value<std::string>(parsed_signal_name + "_topic");
732 this->node_logging_->get_logger(),
733 "Adding input '" << parsed_signal_name << "' with topic name '" << topic_name << "'.");
734 auto subscription =
735 rclcpp::create_subscription<MsgT>(this->node_parameters_, this->node_topics_, topic_name, this->qos_, callback);
737 std::make_shared<SubscriptionHandler<MsgT>>()->create_subscription_interface(subscription);
738 this->inputs_.insert_or_assign(parsed_signal_name, subscription_interface);
739 } catch (const std::exception& ex) {
741 this->node_logging_->get_logger(), "Failed to add input '" << signal_name << "': " << ex.what());
742 }
743}
744
745template<typename DataT>
747 modulo_core::communication::PublisherType publisher_type, const std::string& signal_name,
748 const std::shared_ptr<DataT>& data, const std::string& default_topic, bool fixed_topic, bool publish_on_step) {
749 using namespace modulo_core::communication;
750 try {
751 if (data == nullptr) {
752 throw modulo_core::exceptions::NullPointerException("Invalid data pointer for output '" + signal_name + "'.");
753 }
754 this->declare_output(signal_name, default_topic, fixed_topic);
755 auto parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
757 this->node_logging_->get_logger(),
758 "Creating output '" << parsed_signal_name << "' (provided signal name was '" << signal_name << "').");
759 auto message_pair = make_shared_message_pair(data, this->node_clock_->get_clock());
760 this->outputs_.insert_or_assign(
761 parsed_signal_name, std::make_shared<PublisherInterface>(publisher_type, message_pair));
762 this->periodic_outputs_.insert_or_assign(parsed_signal_name, publish_on_step);
763 return parsed_signal_name;
765 throw;
766 } catch (const std::exception& ex) {
768 }
769}
770
771template<typename T>
772inline bool ComponentInterface::remove_signal(
773 const std::string& signal_name, std::map<std::string, std::shared_ptr<T>>& signal_map, bool skip_check) {
774 if (!skip_check && signal_map.find(signal_name) == signal_map.cend()) {
775 return false;
776 } else {
777 RCLCPP_DEBUG_STREAM(this->node_logging_->get_logger(), "Removing signal '" << signal_name << "'.");
778 signal_map.at(signal_name).reset();
779 return signal_map.erase(signal_name);
780 }
781}
782
783template<typename T>
784inline void ComponentInterface::publish_transforms(
785 const std::vector<state_representation::CartesianPose>& transforms, const std::shared_ptr<T>& tf_broadcaster,
786 bool is_static) {
787 std::string modifier = is_static ? "static " : "";
788 if (tf_broadcaster == nullptr) {
790 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
791 "Failed to send " << modifier << "transform: No " << modifier << "TF broadcaster configured.");
792 return;
793 }
794 try {
795 std::vector<geometry_msgs::msg::TransformStamped> transform_messages;
796 transform_messages.reserve(transforms.size());
797 for (const auto& tf : transforms) {
798 geometry_msgs::msg::TransformStamped transform_message;
799 modulo_core::translators::write_message(transform_message, tf, this->node_clock_->get_clock()->now());
801 }
802 tf_broadcaster->sendTransform(transform_messages);
803 } catch (const std::exception& ex) {
805 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
806 "Failed to send " << modifier << "transform: " << ex.what());
807 }
808}
809}// namespace modulo_components
Friend class to the ComponentInterface to allow test fixtures to access protected and private members...
Base interface class for modulo components to wrap a ROS Node with custom behaviour.
double get_rate() const
Get the component rate in Hertz.
void send_transforms(const std::vector< state_representation::CartesianPose > &transforms)
Send a vector of transforms to TF.
virtual bool on_validate_parameter_callback(const std::shared_ptr< state_representation::ParameterInterface > &parameter)
Parameter validation function to be redefined by derived Component classes.
void publish_outputs()
Helper function to publish all output signals.
void remove_input(const std::string &signal_name)
Remove an input from the map of inputs.
void declare_input(const std::string &signal_name, const std::string &default_topic="", bool fixed_topic=false)
Declare an input to create the topic parameter without adding it to the map of inputs yet.
void declare_output(const std::string &signal_name, const std::string &default_topic="", bool fixed_topic=false)
Declare an output to create the topic parameter without adding it to the map of outputs yet.
T get_period() const
Get the component period.
void set_parameter_value(const std::string &name, const T &value)
Set the value of a parameter.
void send_static_transforms(const std::vector< state_representation::CartesianPose > &transforms)
Send a vector of static transforms to TF.
std::map< std::string, std::shared_ptr< modulo_core::communication::PublisherInterface > > outputs_
Map of outputs.
std::shared_ptr< state_representation::ParameterInterface > get_parameter(const std::string &name) const
Get a parameter by name.
T get_parameter_value(const std::string &name) const
Get a parameter value by name.
virtual ~ComponentInterface()
Virtual destructor.
void add_static_tf_broadcaster()
Configure a static transform broadcaster.
void add_parameter(const std::shared_ptr< state_representation::ParameterInterface > &parameter, const std::string &description, bool read_only=false)
Add a parameter.
void trigger(const std::string &trigger_name)
Latch the trigger with the provided name.
void add_input(const std::string &signal_name, const std::shared_ptr< DataT > &data, const std::string &default_topic="", bool fixed_topic=false)
Add and configure an input signal of the component.
state_representation::CartesianPose lookup_transform(const std::string &frame, const std::string &reference_frame, const tf2::TimePoint &time_point, const tf2::Duration &duration)
Look up a transform from TF.
virtual void on_step_callback()
Steps to execute periodically. To be redefined by derived Component classes.
void set_predicate(const std::string &predicate_name, bool predicate_value)
Set the value of the predicate given as parameter, if the predicate is not found does not do anything...
virtual void raise_error()
Put the component in error state by setting the 'in_error_state' predicate to true.
void remove_output(const std::string &signal_name)
Remove an output from the map of outputs.
void publish_output(const std::string &signal_name)
Trigger the publishing of an output.
virtual void step()
Step function that is called periodically.
void publish_predicates()
Helper function to publish all predicates.
void set_qos(const rclcpp::QoS &qos)
Set the Quality of Service for ROS publishers and subscribers.
std::string create_output(modulo_core::communication::PublisherType publisher_type, const std::string &signal_name, const std::shared_ptr< DataT > &data, const std::string &default_topic, bool fixed_topic, bool publish_on_step)
Helper function to parse the signal name and add an unconfigured PublisherInterface to the map of out...
rclcpp::QoS get_qos() const
Getter of the Quality of Service attribute.
void add_predicate(const std::string &predicate_name, bool predicate_value)
Add a predicate to the map of predicates.
void send_transform(const state_representation::CartesianPose &transform)
Send a transform to TF.
void add_trigger(const std::string &trigger_name)
Add a trigger to the component. Triggers are predicates that are always false except when it's trigge...
void add_periodic_callback(const std::string &name, const std::function< void(void)> &callback)
Add a periodic callback function.
std::map< std::string, std::shared_ptr< modulo_core::communication::SubscriptionInterface > > inputs_
Map of inputs.
void add_tf_listener()
Configure a transform buffer and listener.
void evaluate_periodic_callbacks()
Helper function to evaluate all periodic function callbacks.
void add_tf_broadcaster()
Configure a transform broadcaster.
void send_static_transform(const state_representation::CartesianPose &transform)
Send a static transform to TF.
bool get_predicate(const std::string &predicate_name) const
Get the logical value of a predicate.
std::map< std::string, bool > periodic_outputs_
Map of outputs with periodic publishing flag.
void add_service(const std::string &service_name, const std::function< ComponentServiceResponse(void)> &callback)
Add a service to trigger a callback function with no input arguments.
An exception class to notify errors when adding a signal.
An exception class to notify that a certain pointer is null.
An exception class to notify errors with parameters in modulo classes.
Modulo components.
Definition Component.hpp:9
Modulo Core communication module for handling messages on publication and subscription interfaces.
PublisherType
Enum of supported ROS publisher types for the PublisherInterface.
void write_message(geometry_msgs::msg::Accel &message, const state_representation::CartesianState &state, const rclcpp::Time &time)
Convert a CartesianState to a ROS geometry_msgs::msg::Accel.
rclcpp::Parameter write_parameter(const std::shared_ptr< state_representation::ParameterInterface > &parameter)
Write a ROS Parameter from a ParameterInterface pointer.
Response structure to be returned by component services.