Modulo 5.0.0
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
443 void finalize_interfaces();
444
445 std::map<std::string, std::shared_ptr<modulo_core::communication::SubscriptionInterface>> inputs_;
446 std::map<std::string, std::shared_ptr<modulo_core::communication::PublisherInterface>> outputs_;
447 std::map<std::string, bool> periodic_outputs_;
448
449private:
454 void pre_set_parameters_callback(std::vector<rclcpp::Parameter>& parameters);
455
462 rcl_interfaces::msg::SetParametersResult on_set_parameters_callback(const std::vector<rclcpp::Parameter>& parameters);
463
471 bool validate_parameter(const std::shared_ptr<state_representation::ParameterInterface>& parameter);
472
478 modulo_interfaces::msg::Predicate get_predicate_message(const std::string& name, bool value) const;
479
489 void declare_signal(
490 const std::string& signal_name, const std::string& type, const std::string& default_topic, bool fixed_topic);
491
500 template<typename T>
501 bool remove_signal(
502 const std::string& signal_name, std::map<std::string, std::shared_ptr<T>>& signal_map, bool skip_check = false);
503
512 std::string validate_service_name(const std::string& service_name, const std::string& type) const;
513
519 void publish_predicate(const std::string& predicate_name, bool value) const;
520
528 template<typename T>
529 void publish_transforms(
530 const std::vector<state_representation::CartesianPose>& transforms, const std::shared_ptr<T>& tf_broadcaster,
531 bool is_static = false);
532
543 [[nodiscard]] geometry_msgs::msg::TransformStamped lookup_ros_transform(
544 const std::string& frame, const std::string& reference_frame, const tf2::TimePoint& time_point,
545 const tf2::Duration& duration);
546
547 double rate_;
548 double period_;
549 std::mutex step_mutex_;
550
551 std::map<std::string, modulo_core::Predicate> predicates_;
552 std::shared_ptr<rclcpp::Publisher<modulo_interfaces::msg::PredicateCollection>>
553 predicate_publisher_;
554 modulo_interfaces::msg::PredicateCollection predicate_message_;
555 std::vector<std::string> triggers_;
556
557 std::map<std::string, std::shared_ptr<rclcpp::Service<modulo_interfaces::srv::EmptyTrigger>>>
558 empty_services_;
559 std::map<std::string, std::shared_ptr<rclcpp::Service<modulo_interfaces::srv::StringTrigger>>>
560 string_services_;
561
562 std::map<std::string, std::function<void(void)>> periodic_callbacks_;
563
564 state_representation::ParameterMap parameter_map_;
565 std::unordered_map<std::string, bool> read_only_parameters_;
566 std::shared_ptr<rclcpp::node_interfaces::PreSetParametersCallbackHandle>
567 pre_set_parameter_cb_handle_;
568 std::shared_ptr<rclcpp::node_interfaces::OnSetParametersCallbackHandle>
569 on_set_parameter_cb_handle_;
570 rcl_interfaces::msg::SetParametersResult set_parameters_result_;
571 bool pre_set_parameter_callback_called_ = false;
572
573 std::shared_ptr<rclcpp::TimerBase> step_timer_;
574 std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
575 std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
576 std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
577 std::shared_ptr<tf2_ros::StaticTransformBroadcaster> static_tf_broadcaster_;
578
579 std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_;
580 std::shared_ptr<rclcpp::node_interfaces::NodeClockInterface> node_clock_;
581 std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface> node_logging_;
582 std::shared_ptr<rclcpp::node_interfaces::NodeParametersInterface> node_parameters_;
583 std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_;
584 std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface> node_timers_;
585 std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface> node_topics_;
586 rclcpp::QoS qos_ = rclcpp::QoS(10);
587};
588
589template<typename T>
591 const std::string& name, const T& value, const std::string& description, bool read_only) {
592 if (name.empty()) {
593 RCLCPP_ERROR(this->node_logging_->get_logger(), "Failed to add parameter: Provide a non empty string as a name.");
594 return;
595 }
596 this->add_parameter(state_representation::make_shared_parameter(name, value), description, read_only);
597}
598
599template<typename T>
600inline T ComponentInterface::get_parameter_value(const std::string& name) const {
601 try {
602 return this->parameter_map_.template get_parameter_value<T>(name);
603 } catch (const state_representation::exceptions::InvalidParameterException& ex) {
605 "Failed to get parameter value of parameter '" + name + "': " + ex.what());
606 }
607}
608
609template<typename T>
610inline void ComponentInterface::set_parameter_value(const std::string& name, const T& value) {
611 try {
612 std::vector<rclcpp::Parameter> parameters{
613 modulo_core::translators::write_parameter(state_representation::make_shared_parameter(name, value))};
614 this->pre_set_parameters_callback(parameters);
615 this->pre_set_parameter_callback_called_ = true;
616 auto result = this->node_parameters_->set_parameters(parameters).at(0);
617 if (!result.successful) {
619 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
620 "Failed to set parameter value of parameter '" << name << "': " << result.reason);
621 }
622 } catch (const std::exception& ex) {
624 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
625 "Failed to set parameter value of parameter '" << name << "': " << ex.what());
626 }
627}
628
629template<typename DataT>
631 const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::string& default_topic,
632 bool fixed_topic) {
633 this->add_input(signal_name, data, [] {}, default_topic, fixed_topic);
634}
635
636template<typename DataT>
638 const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::function<void()>& user_callback,
639 const std::string& default_topic, bool fixed_topic) {
640 using namespace modulo_core::communication;
641 try {
642 if (data == nullptr) {
643 throw modulo_core::exceptions::NullPointerException("Invalid data pointer for input '" + signal_name + "'.");
644 }
645 this->declare_input(signal_name, default_topic, fixed_topic);
646 std::string parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
647 auto topic_name = this->get_parameter_value<std::string>(parsed_signal_name + "_topic");
649 this->node_logging_->get_logger(),
650 "Adding input '" << parsed_signal_name << "' with topic name '" << topic_name << "'.");
651 auto message_pair = make_shared_message_pair(data, this->node_clock_->get_clock());
652 std::shared_ptr<SubscriptionInterface> subscription_interface;
653 switch (message_pair->get_type()) {
654 case MessageType::BOOL: {
656 std::make_shared<SubscriptionHandler<std_msgs::msg::Bool>>(message_pair, this->node_logging_->get_logger());
657 auto subscription = rclcpp::create_subscription<std_msgs::msg::Bool>(
658 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
659 subscription_handler->get_callback(user_callback));
660 subscription_interface = subscription_handler->create_subscription_interface(subscription);
661 break;
662 }
663 case MessageType::FLOAT64: {
664 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::Float64>>(
665 message_pair, this->node_logging_->get_logger());
666 auto subscription = rclcpp::create_subscription<std_msgs::msg::Float64>(
667 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
668 subscription_handler->get_callback(user_callback));
669 subscription_interface = subscription_handler->create_subscription_interface(subscription);
670 break;
671 }
672 case MessageType::FLOAT64_MULTI_ARRAY: {
673 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::Float64MultiArray>>(
674 message_pair, this->node_logging_->get_logger());
675 auto subscription = rclcpp::create_subscription<std_msgs::msg::Float64MultiArray>(
676 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
677 subscription_handler->get_callback(user_callback));
678 subscription_interface = subscription_handler->create_subscription_interface(subscription);
679 break;
680 }
681 case MessageType::INT32: {
682 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::Int32>>(
683 message_pair, this->node_logging_->get_logger());
684 auto subscription = rclcpp::create_subscription<std_msgs::msg::Int32>(
685 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
686 subscription_handler->get_callback(user_callback));
687 subscription_interface = subscription_handler->create_subscription_interface(subscription);
688 break;
689 }
690 case MessageType::STRING: {
691 auto subscription_handler = std::make_shared<SubscriptionHandler<std_msgs::msg::String>>(
692 message_pair, this->node_logging_->get_logger());
693 auto subscription = rclcpp::create_subscription<std_msgs::msg::String>(
694 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
695 subscription_handler->get_callback(user_callback));
696 subscription_interface = subscription_handler->create_subscription_interface(subscription);
697 break;
698 }
699 case MessageType::ENCODED_STATE: {
700 auto subscription_handler = std::make_shared<SubscriptionHandler<modulo_core::EncodedState>>(
701 message_pair, this->node_logging_->get_logger());
702 auto subscription = rclcpp::create_subscription<modulo_core::EncodedState>(
703 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
704 subscription_handler->get_callback(user_callback));
705 subscription_interface = subscription_handler->create_subscription_interface(subscription);
706 break;
707 }
708 case MessageType::CUSTOM_MESSAGE: {
711 std::make_shared<SubscriptionHandler<DataT>>(message_pair, this->node_logging_->get_logger());
712 auto subscription = rclcpp::create_subscription<DataT>(
713 this->node_parameters_, this->node_topics_, topic_name, this->qos_,
714 subscription_handler->get_callback(user_callback));
715 subscription_interface = subscription_handler->create_subscription_interface(subscription);
716 }
717 break;
718 }
719 }
720 this->inputs_.insert_or_assign(parsed_signal_name, subscription_interface);
721 } catch (const std::exception& ex) {
723 this->node_logging_->get_logger(), "Failed to add input '" << signal_name << "': " << ex.what());
724 }
725}
726
727template<typename MsgT>
729 const std::string& signal_name, const std::function<void(const std::shared_ptr<MsgT>)>& callback,
730 const std::string& default_topic, bool fixed_topic) {
731 using namespace modulo_core::communication;
732 try {
733 std::string parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
734 this->declare_input(parsed_signal_name, default_topic, fixed_topic);
735 auto topic_name = this->get_parameter_value<std::string>(parsed_signal_name + "_topic");
737 this->node_logging_->get_logger(),
738 "Adding input '" << parsed_signal_name << "' with topic name '" << topic_name << "'.");
739 auto subscription =
740 rclcpp::create_subscription<MsgT>(this->node_parameters_, this->node_topics_, topic_name, this->qos_, callback);
742 std::make_shared<SubscriptionHandler<MsgT>>()->create_subscription_interface(subscription);
743 this->inputs_.insert_or_assign(parsed_signal_name, subscription_interface);
744 } catch (const std::exception& ex) {
746 this->node_logging_->get_logger(), "Failed to add input '" << signal_name << "': " << ex.what());
747 }
748}
749
750template<typename DataT>
752 modulo_core::communication::PublisherType publisher_type, const std::string& signal_name,
753 const std::shared_ptr<DataT>& data, const std::string& default_topic, bool fixed_topic, bool publish_on_step) {
754 using namespace modulo_core::communication;
755 try {
756 if (data == nullptr) {
757 throw modulo_core::exceptions::NullPointerException("Invalid data pointer for output '" + signal_name + "'.");
758 }
759 this->declare_output(signal_name, default_topic, fixed_topic);
760 auto parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
762 this->node_logging_->get_logger(),
763 "Creating output '" << parsed_signal_name << "' (provided signal name was '" << signal_name << "').");
764 auto message_pair = make_shared_message_pair(data, this->node_clock_->get_clock());
765 this->outputs_.insert_or_assign(
766 parsed_signal_name, std::make_shared<PublisherInterface>(publisher_type, message_pair));
767 this->periodic_outputs_.insert_or_assign(parsed_signal_name, publish_on_step);
768 return parsed_signal_name;
770 throw;
771 } catch (const std::exception& ex) {
773 }
774}
775
776template<typename T>
777inline bool ComponentInterface::remove_signal(
778 const std::string& signal_name, std::map<std::string, std::shared_ptr<T>>& signal_map, bool skip_check) {
779 if (!skip_check && signal_map.find(signal_name) == signal_map.cend()) {
780 return false;
781 } else {
782 RCLCPP_DEBUG_STREAM(this->node_logging_->get_logger(), "Removing signal '" << signal_name << "'.");
783 signal_map.at(signal_name).reset();
784 return signal_map.erase(signal_name);
785 }
786}
787
788template<typename T>
789inline void ComponentInterface::publish_transforms(
790 const std::vector<state_representation::CartesianPose>& transforms, const std::shared_ptr<T>& tf_broadcaster,
791 bool is_static) {
792 std::string modifier = is_static ? "static " : "";
793 if (tf_broadcaster == nullptr) {
795 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
796 "Failed to send " << modifier << "transform: No " << modifier << "TF broadcaster configured.");
797 return;
798 }
799 try {
800 std::vector<geometry_msgs::msg::TransformStamped> transform_messages;
801 transform_messages.reserve(transforms.size());
802 for (const auto& tf : transforms) {
803 geometry_msgs::msg::TransformStamped transform_message;
804 modulo_core::translators::write_message(transform_message, tf, this->node_clock_->get_clock()->now());
806 }
807 tf_broadcaster->sendTransform(transform_messages);
808 } catch (const std::exception& ex) {
810 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
811 "Failed to send " << modifier << "transform: " << ex.what());
812 }
813}
814}// 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.
void finalize_interfaces()
Finalize all interfaces.
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()
Notify an error in the component.
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.