1#include "modulo_components/ComponentInterface.hpp"
3#include <console_bridge/console.h>
4#include <tf2_msgs/msg/tf_message.hpp>
6#include <modulo_core/translators/message_readers.hpp>
7#include <modulo_core/translators/message_writers.hpp>
14 const std::shared_ptr<rclcpp::node_interfaces::NodeInterfaces<ALL_RCLCPP_NODE_INTERFACES>>& interfaces)
15 : node_base_(interfaces->get_node_base_interface()),
16 node_clock_(interfaces->get_node_clock_interface()),
17 node_logging_(interfaces->get_node_logging_interface()),
18 node_parameters_(interfaces->get_node_parameters_interface()),
19 node_services_(interfaces->get_node_services_interface()),
20 node_timers_(interfaces->get_node_timers_interface()),
21 node_topics_(interfaces->get_node_topics_interface()) {
23 this->pre_set_parameter_cb_handle_ = this->node_parameters_->add_pre_set_parameters_callback(
24 [
this](std::vector<rclcpp::Parameter>& parameters) {
return this->pre_set_parameters_callback(parameters); });
25 this->on_set_parameter_cb_handle_ = this->node_parameters_->add_on_set_parameters_callback(
26 [
this](
const std::vector<rclcpp::Parameter>& parameters) -> rcl_interfaces::msg::SetParametersResult {
27 return this->on_set_parameters_callback(parameters);
29 this->
add_parameter(
"rate", 10.0,
"The rate in Hertz for all periodic callbacks",
true);
31 this->predicate_publisher_ = rclcpp::create_publisher<modulo_interfaces::msg::PredicateCollection>(
32 this->node_parameters_, this->node_topics_,
"/predicates", this->qos_);
33 this->predicate_message_.node = this->node_base_->get_fully_qualified_name();
34 this->predicate_message_.type = modulo_interfaces::msg::PredicateCollection::COMPONENT;
37 this->period_ = 1.0 / this->rate_;
38 this->step_timer_ = rclcpp::create_wall_timer(
39 std::chrono::nanoseconds(
static_cast<int64_t
>(1e9 * this->period_)),
41 if (this->step_mutex_.try_lock()) {
43 this->step_mutex_.unlock();
46 nullptr, this->node_base_.get(), this->node_timers_.get());
50 this->step_mutex_.lock();
64 return std::chrono::nanoseconds(
static_cast<int64_t
>(1e9 * this->period_));
69 return rclcpp::Duration::from_seconds(this->period_);
77 const std::shared_ptr<state_representation::ParameterInterface>& parameter,
const std::string& description,
79 rclcpp::Parameter ros_param;
85 if (!this->node_parameters_->has_parameter(parameter->get_name())) {
86 RCLCPP_DEBUG_STREAM(this->node_logging_->get_logger(),
"Adding parameter '" << parameter->get_name() <<
"'.");
87 this->parameter_map_.set_parameter(parameter);
88 this->read_only_parameters_.insert_or_assign(parameter->get_name(),
false);
90 rcl_interfaces::msg::ParameterDescriptor descriptor;
91 descriptor.description = description;
92 descriptor.read_only = read_only;
94 this->set_parameters_result_.successful =
true;
95 this->set_parameters_result_.reason =
"";
96 if (parameter->is_empty()) {
97 descriptor.dynamic_typing =
true;
99 this->node_parameters_->declare_parameter(parameter->get_name(), rclcpp::ParameterValue{}, descriptor);
101 this->node_parameters_->declare_parameter(parameter->get_name(), ros_param.get_parameter_value(), descriptor);
103 std::vector<rclcpp::Parameter> ros_parameters{this->node_parameters_->get_parameters({parameter->get_name()})};
104 this->pre_set_parameters_callback(ros_parameters);
105 auto result = this->on_set_parameters_callback(ros_parameters);
106 if (!result.successful) {
107 this->node_parameters_->undeclare_parameter(parameter->get_name());
110 this->read_only_parameters_.at(parameter->get_name()) = read_only;
111 }
catch (
const std::exception& ex) {
112 this->parameter_map_.remove_parameter(parameter->get_name());
113 this->read_only_parameters_.erase(parameter->get_name());
118 this->node_logging_->get_logger(),
"Parameter '" << parameter->get_name() <<
"' already exists.");
122std::shared_ptr<state_representation::ParameterInterface>
125 return this->parameter_map_.get_parameter(name);
126 }
catch (
const state_representation::exceptions::InvalidParameterException& ex) {
131void ComponentInterface::pre_set_parameters_callback(std::vector<rclcpp::Parameter>& parameters) {
132 if (this->pre_set_parameter_callback_called_) {
133 this->pre_set_parameter_callback_called_ =
false;
136 rcl_interfaces::msg::SetParametersResult result;
137 result.successful =
true;
138 for (
auto& ros_parameter : parameters) {
140 auto parameter = parameter_map_.get_parameter(ros_parameter.get_name());
141 if (this->read_only_parameters_.at(ros_parameter.get_name())) {
143 this->node_logging_->get_logger(),
"Parameter '" << ros_parameter.get_name() <<
"' is read only.");
149 if (!this->validate_parameter(new_parameter)) {
150 result.successful =
false;
151 result.reason +=
"Validation of parameter '" + ros_parameter.get_name() +
"' returned false!";
152 }
else if (!new_parameter->is_empty()) {
157 }
catch (
const std::exception& ex) {
158 result.successful =
false;
159 result.reason += ex.what();
162 this->set_parameters_result_ = result;
165rcl_interfaces::msg::SetParametersResult
166ComponentInterface::on_set_parameters_callback(
const std::vector<rclcpp::Parameter>&) {
167 auto result = this->set_parameters_result_;
168 this->set_parameters_result_.successful =
true;
169 this->set_parameters_result_.reason =
"";
173bool ComponentInterface::validate_parameter(
174 const std::shared_ptr<state_representation::ParameterInterface>& parameter) {
175 if (parameter->get_name() ==
"rate") {
176 auto value = parameter->get_parameter_value<
double>();
177 if (value <= 0 || !std::isfinite(value)) {
178 RCLCPP_ERROR(this->node_logging_->get_logger(),
"Value for parameter 'rate' has to be a positive finite number.");
186 const std::shared_ptr<state_representation::ParameterInterface>&) {
191 this->
add_predicate(predicate_name, [predicate_value]() {
return predicate_value; });
195 const std::string& predicate_name,
const std::function<
bool(
void)>& predicate_function) {
196 if (predicate_name.empty()) {
197 RCLCPP_ERROR(this->node_logging_->get_logger(),
"Failed to add predicate: Provide a non empty string as a name.");
200 if (this->predicates_.find(predicate_name) != this->predicates_.end()) {
202 this->node_logging_->get_logger(),
203 "Predicate with name '" << predicate_name <<
"' already exists, overwriting.");
205 RCLCPP_DEBUG_STREAM(this->node_logging_->get_logger(),
"Adding predicate '" << predicate_name <<
"'.");
208 this->predicates_.insert_or_assign(predicate_name,
Predicate(predicate_function));
209 }
catch (
const std::exception& ex) {
210 RCLCPP_ERROR_STREAM_THROTTLE(
211 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
212 "Failed to add predicate '" << predicate_name <<
"': " << ex.what());
217 auto predicate_it = this->predicates_.find(predicate_name);
218 if (predicate_it == this->predicates_.end()) {
219 RCLCPP_ERROR_STREAM_THROTTLE(
220 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
221 "Failed to get predicate '" << predicate_name <<
"': Predicate does not exist, returning false.");
225 return predicate_it->second.get_value();
226 }
catch (
const std::exception& ex) {
228 this->node_logging_->get_logger(),
229 "Failed to evaluate callback of predicate '" << predicate_it->first <<
"', returning false: " << ex.what());
235 this->
set_predicate(predicate_name, [predicate_value]() {
return predicate_value; });
239 const std::string& predicate_name,
const std::function<
bool(
void)>& predicate_function) {
240 auto predicate_it = this->predicates_.find(predicate_name);
241 if (predicate_it == this->predicates_.end()) {
242 RCLCPP_ERROR_STREAM_THROTTLE(
243 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
244 "Failed to set predicate '" << predicate_name <<
"': Predicate does not exist.");
247 predicate_it->second.set_predicate(predicate_function);
248 if (
auto new_predicate = predicate_it->second.query(); new_predicate) {
249 this->publish_predicate(predicate_name, *new_predicate);
254 if (trigger_name.empty()) {
255 RCLCPP_ERROR(this->node_logging_->get_logger(),
"Failed to add trigger: Provide a non empty string as a name.");
258 if (std::find(this->triggers_.cbegin(), this->triggers_.cend(), trigger_name) != this->triggers_.cend()) {
260 this->node_logging_->get_logger(),
261 "Failed to add trigger: there is already a trigger with name '" << trigger_name <<
"'.");
264 if (this->predicates_.find(trigger_name) != this->predicates_.end()) {
266 this->node_logging_->get_logger(),
267 "Failed to add trigger: there is already a predicate with name '" << trigger_name <<
"'.");
270 this->triggers_.push_back(trigger_name);
275 if (std::find(this->triggers_.cbegin(), this->triggers_.cend(), trigger_name) == this->triggers_.cend()) {
277 this->node_logging_->get_logger(),
278 "Failed to trigger: could not find trigger with name '" << trigger_name <<
"'.");
283 this->predicates_.at(trigger_name).set_predicate([]() {
return false; });
287 const std::string& signal_name,
const std::string& default_topic,
bool fixed_topic) {
288 this->declare_signal(signal_name,
"input", default_topic, fixed_topic);
292 const std::string& signal_name,
const std::string& default_topic,
bool fixed_topic) {
293 this->declare_signal(signal_name,
"output", default_topic, fixed_topic);
296void ComponentInterface::declare_signal(
297 const std::string& signal_name,
const std::string& type,
const std::string& default_topic,
bool fixed_topic) {
298 std::string parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
299 if (parsed_signal_name.empty()) {
302 if (signal_name != parsed_signal_name) {
304 this->node_logging_->get_logger(),
305 "The parsed name for " + type +
" '" + signal_name +
"' is '" + parsed_signal_name
306 +
"'. Use the parsed name to refer to this " + type);
308 if (this->
inputs_.find(parsed_signal_name) != this->inputs_.cend()) {
311 if (this->
outputs_.find(parsed_signal_name) != this->outputs_.cend()) {
314 std::string topic_name = default_topic.empty() ?
"~/" + parsed_signal_name : default_topic;
315 auto parameter_name = parsed_signal_name +
"_topic";
316 if (this->node_parameters_->has_parameter(parameter_name) && this->get_parameter(parameter_name)->is_empty()) {
320 parameter_name, topic_name,
"Signal topic name of " + type +
" '" + parsed_signal_name +
"'", fixed_topic);
323 this->node_logging_->get_logger(),
324 "Declared signal '" << parsed_signal_name <<
"' and parameter '" << parameter_name <<
"' with value '"
325 << topic_name <<
"'.");
329 auto parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
330 if (this->
outputs_.find(parsed_signal_name) == this->outputs_.cend()) {
337 this->
outputs_.at(parsed_signal_name)->publish();
339 RCLCPP_ERROR_STREAM_THROTTLE(
340 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
341 "Failed to publish output '" << parsed_signal_name <<
"': " << ex.what());
346 if (!this->remove_signal(signal_name, this->
inputs_)) {
347 auto parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
348 if (!this->remove_signal(parsed_signal_name, this->
inputs_)) {
350 this->node_logging_->get_logger(),
351 "Unknown input '" << signal_name <<
"' (parsed name was '" << parsed_signal_name <<
"').");
357 if (!this->remove_signal(signal_name, this->
outputs_)) {
358 auto parsed_signal_name = modulo_utils::parsing::parse_topic_name(signal_name);
359 if (!this->remove_signal(parsed_signal_name, this->
outputs_)) {
361 this->node_logging_->get_logger(),
362 "Unknown output '" << signal_name <<
"' (parsed name was '" << parsed_signal_name <<
"').");
370 std::string parsed_service_name = this->validate_service_name(service_name,
"empty");
371 RCLCPP_DEBUG_STREAM(this->node_logging_->get_logger(),
"Adding empty service '" << parsed_service_name <<
"'.");
372 auto service = rclcpp::create_service<modulo_interfaces::srv::EmptyTrigger>(
373 this->node_base_, this->node_services_,
"~/" + parsed_service_name,
375 const std::shared_ptr<modulo_interfaces::srv::EmptyTrigger::Request>,
376 std::shared_ptr<modulo_interfaces::srv::EmptyTrigger::Response> response) {
378 auto callback_response = callback();
379 response->success = callback_response.success;
380 response->message = callback_response.message;
381 }
catch (
const std::exception& ex) {
382 response->success =
false;
383 response->message = ex.what();
386 this->qos_,
nullptr);
387 this->empty_services_.insert_or_assign(parsed_service_name, service);
388 }
catch (
const std::exception& ex) {
390 this->node_logging_->get_logger(),
"Failed to add service '" << service_name <<
"': " << ex.what());
395 const std::string& service_name,
398 std::string parsed_service_name = this->validate_service_name(service_name,
"string");
399 RCLCPP_DEBUG_STREAM(this->node_logging_->get_logger(),
"Adding string service '" << parsed_service_name <<
"'.");
400 auto service = rclcpp::create_service<modulo_interfaces::srv::StringTrigger>(
401 this->node_base_, this->node_services_,
"~/" + parsed_service_name,
403 const std::shared_ptr<modulo_interfaces::srv::StringTrigger::Request> request,
404 std::shared_ptr<modulo_interfaces::srv::StringTrigger::Response> response) {
406 auto callback_response = callback(request->payload);
407 response->success = callback_response.success;
408 response->message = callback_response.message;
409 }
catch (
const std::exception& ex) {
410 response->success =
false;
411 response->message = ex.what();
414 this->qos_,
nullptr);
415 this->string_services_.insert_or_assign(parsed_service_name, service);
416 }
catch (
const std::exception& ex) {
418 this->node_logging_->get_logger(),
"Failed to add service '" << service_name <<
"': " << ex.what());
423std::string ComponentInterface::validate_service_name(
const std::string& service_name,
const std::string& type)
const {
424 std::string parsed_service_name = modulo_utils::parsing::parse_topic_name(service_name);
425 if (parsed_service_name.empty()) {
427 modulo_utils::parsing::topic_validation_warning(service_name, type +
" service"));
429 if (service_name != parsed_service_name) {
431 this->node_logging_->get_logger(),
432 "The parsed name for service '" + service_name +
"' is '" + parsed_service_name
433 +
"'. Use the parsed name to refer to this service");
435 if (empty_services_.find(parsed_service_name) != empty_services_.cend()) {
437 "Service with name '" + parsed_service_name +
"' already exists as an empty service.");
439 if (string_services_.find(parsed_service_name) != string_services_.cend()) {
441 "Service with name '" + parsed_service_name +
"' already exists as a string service.");
443 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"Adding %s service '%s'.", type.c_str(), parsed_service_name.c_str());
444 return parsed_service_name;
450 this->node_logging_->get_logger(),
"Failed to add periodic function: Provide a non empty string as a name.");
453 if (this->periodic_callbacks_.find(name) != this->periodic_callbacks_.end()) {
455 this->node_logging_->get_logger(),
"Periodic function '" << name <<
"' already exists, overwriting.");
457 RCLCPP_DEBUG_STREAM(this->node_logging_->get_logger(),
"Adding periodic function '" << name <<
"'.");
459 this->periodic_callbacks_.insert_or_assign(name, callback);
463 if (this->tf_broadcaster_ ==
nullptr) {
464 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"Adding TF broadcaster.");
465 console_bridge::setLogLevel(console_bridge::CONSOLE_BRIDGE_LOG_NONE);
466 this->tf_broadcaster_ = std::make_shared<tf2_ros::TransformBroadcaster>(
467 this->node_parameters_, this->node_topics_, tf2_ros::DynamicBroadcasterQoS());
469 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"TF broadcaster already exists.");
474 if (this->static_tf_broadcaster_ ==
nullptr) {
475 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"Adding static TF broadcaster.");
476 console_bridge::setLogLevel(console_bridge::CONSOLE_BRIDGE_LOG_NONE);
477 tf2_ros::StaticBroadcasterQoS qos;
478 rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> options;
479 this->static_tf_broadcaster_ =
480 std::make_shared<tf2_ros::StaticTransformBroadcaster>(this->node_parameters_, this->node_topics_, qos, options);
482 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"Static TF broadcaster already exists.");
487 if (this->tf_buffer_ ==
nullptr || this->tf_listener_ ==
nullptr) {
488 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"Adding TF buffer and listener.");
489 console_bridge::setLogLevel(console_bridge::CONSOLE_BRIDGE_LOG_NONE);
490 this->tf_buffer_ = std::make_shared<tf2_ros::Buffer>(this->node_clock_->get_clock());
491 this->tf_listener_ = std::make_shared<tf2_ros::TransformListener>(
492 *this->tf_buffer_, this->node_base_, this->node_logging_, this->node_parameters_, this->node_topics_);
494 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"TF buffer and listener already exist.");
499 this->
send_transforms(std::vector<state_representation::CartesianPose>{transform});
503 this->publish_transforms(transforms, this->tf_broadcaster_);
511 this->publish_transforms(transforms, this->static_tf_broadcaster_,
true);
515 const std::string& frame,
const std::string& reference_frame,
const tf2::TimePoint& time_point,
516 const tf2::Duration& duration) {
517 auto transform = this->lookup_ros_transform(frame, reference_frame, time_point, duration);
518 state_representation::CartesianPose result(frame, reference_frame);
524 const std::string& frame,
const std::string& reference_frame,
double validity_period,
525 const tf2::Duration& duration) {
527 this->lookup_ros_transform(frame, reference_frame, tf2::TimePoint(std::chrono::microseconds(0)), duration);
528 if (validity_period > 0.0
529 && (this->node_clock_->get_clock()->now() - transform.header.stamp).seconds() > validity_period) {
532 state_representation::CartesianPose result(frame, reference_frame);
537geometry_msgs::msg::TransformStamped ComponentInterface::lookup_ros_transform(
538 const std::string& frame,
const std::string& reference_frame,
const tf2::TimePoint& time_point,
539 const tf2::Duration& duration) {
540 if (this->tf_buffer_ ==
nullptr || this->tf_listener_ ==
nullptr) {
544 return this->tf_buffer_->lookupTransform(reference_frame, frame, time_point, duration);
545 }
catch (
const tf2::TransformException& ex) {
559 RCLCPP_ERROR(this->node_logging_->get_logger(),
"An error was raised in the component.");
562modulo_interfaces::msg::Predicate ComponentInterface::get_predicate_message(
const std::string& name,
bool value)
const {
563 modulo_interfaces::msg::Predicate message;
564 message.predicate = name;
565 message.value = value;
569void ComponentInterface::publish_predicate(
const std::string& name,
bool value)
const {
570 auto message(this->predicate_message_);
571 message.predicates.push_back(this->get_predicate_message(name, value));
572 this->predicate_publisher_->publish(message);
576 auto message(this->predicate_message_);
577 for (
auto predicate_it = this->predicates_.begin(); predicate_it != this->predicates_.end(); ++predicate_it) {
578 if (
auto new_predicate = predicate_it->second.query(); new_predicate) {
579 message.predicates.push_back(this->get_predicate_message(predicate_it->first, *new_predicate));
582 if (message.predicates.size()) {
583 this->predicate_publisher_->publish(message);
588 for (
const auto& [signal, publisher] : this->
outputs_) {
591 publisher->publish();
594 RCLCPP_ERROR_STREAM_THROTTLE(
595 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
596 "Failed to publish output '" << signal <<
"': " << ex.what());
602 for (
const auto& [name, callback] : this->periodic_callbacks_) {
605 }
catch (
const std::exception& ex) {
606 RCLCPP_ERROR_STREAM_THROTTLE(
607 this->node_logging_->get_logger(), *this->node_clock_->get_clock(), 1000,
608 "Failed to evaluate periodic function callback '" << name <<
"': " << ex.what());
614 RCLCPP_DEBUG(this->node_logging_->get_logger(),
"Finalizing all interfaces.");
617 this->predicate_publisher_.reset();
618 this->empty_services_.clear();
619 this->string_services_.clear();
620 if (this->step_timer_ !=
nullptr) {
621 this->step_timer_->cancel();
623 this->step_timer_.reset();
624 this->tf_buffer_.reset();
625 this->tf_listener_.reset();
626 this->tf_broadcaster_.reset();
627 this->static_tf_broadcaster_.reset();
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 > ¶meter)
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 > ¶meter, 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.
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.
ComponentInterface(const std::shared_ptr< rclcpp::node_interfaces::NodeInterfaces< ALL_RCLCPP_NODE_INTERFACES > > &interfaces)
Constructor with all node interfaces.
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.
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 service.
An exception class to notify errors when adding a signal.
A base class for all core exceptions.
An exception class to notify errors with parameters in modulo classes.
An exception class to notify incompatibility when translating parameters from different sources.
rclcpp::Parameter write_parameter(const std::shared_ptr< state_representation::ParameterInterface > ¶meter)
Write a ROS Parameter from a ParameterInterface pointer.
rclcpp::ParameterType get_ros_parameter_type(const state_representation::ParameterType ¶meter_type)
Given a state representation parameter type, get the corresponding ROS parameter type.
void copy_parameter_value(const std::shared_ptr< const state_representation::ParameterInterface > &source_parameter, const std::shared_ptr< state_representation::ParameterInterface > ¶meter)
Copy the value of one parameter interface into another.
void read_message(state_representation::CartesianState &state, const geometry_msgs::msg::Accel &message)
Convert a ROS geometry_msgs::msg::Accel to a CartesianState.
std::shared_ptr< state_representation::ParameterInterface > read_parameter_const(const rclcpp::Parameter &ros_parameter, const std::shared_ptr< const state_representation::ParameterInterface > ¶meter)
Update the parameter value of a ParameterInterface from a ROS Parameter object only if the two parame...
Response structure to be returned by component services.