Modulo 5.0.0
Loading...
Searching...
No Matches
BaseControllerInterface.hpp
1#pragma once
2
3#include <any>
4#include <mutex>
5
6#include <controller_interface/controller_interface.hpp>
7#include <controller_interface/helpers.hpp>
8#include <realtime_tools/realtime_buffer.h>
9#include <realtime_tools/realtime_publisher.h>
10
11#include <state_representation/parameters/ParameterMap.hpp>
12
13#include <modulo_core/EncodedState.hpp>
14#include <modulo_core/Predicate.hpp>
15#include <modulo_core/communication/MessagePair.hpp>
16#include <modulo_core/exceptions.hpp>
17#include <modulo_core/translators/message_writers.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
26#include <modulo_core/concepts.hpp>
27
28namespace modulo_controllers {
29
30typedef std::variant<
31 std::shared_ptr<rclcpp::Subscription<modulo_core::EncodedState>>,
32 std::shared_ptr<rclcpp::Subscription<std_msgs::msg::Bool>>,
33 std::shared_ptr<rclcpp::Subscription<std_msgs::msg::Float64>>,
34 std::shared_ptr<rclcpp::Subscription<std_msgs::msg::Float64MultiArray>>,
35 std::shared_ptr<rclcpp::Subscription<std_msgs::msg::Int32>>,
36 std::shared_ptr<rclcpp::Subscription<std_msgs::msg::String>>, std::any>
37 SubscriptionVariant;
38
39typedef std::variant<
40 realtime_tools::RealtimeBuffer<std::shared_ptr<modulo_core::EncodedState>>,
41 realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Bool>>,
42 realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Float64>>,
43 realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Float64MultiArray>>,
44 realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Int32>>,
45 realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::String>>, std::any>
46 BufferVariant;
47
48typedef std::tuple<
49 std::shared_ptr<state_representation::State>, std::shared_ptr<rclcpp::Publisher<modulo_core::EncodedState>>,
50 realtime_tools::RealtimePublisherSharedPtr<modulo_core::EncodedState>>
51 EncodedStatePublishers;
52typedef std::pair<
53 std::shared_ptr<rclcpp::Publisher<std_msgs::msg::Bool>>,
54 realtime_tools::RealtimePublisherSharedPtr<std_msgs::msg::Bool>>
55 BoolPublishers;
56typedef std::pair<
57 std::shared_ptr<rclcpp::Publisher<std_msgs::msg::Float64>>,
58 realtime_tools::RealtimePublisherSharedPtr<std_msgs::msg::Float64>>
59 DoublePublishers;
60typedef std::pair<
61 std::shared_ptr<rclcpp::Publisher<std_msgs::msg::Float64MultiArray>>,
62 realtime_tools::RealtimePublisherSharedPtr<std_msgs::msg::Float64MultiArray>>
63 DoubleVecPublishers;
64typedef std::pair<
65 std::shared_ptr<rclcpp::Publisher<std_msgs::msg::Int32>>,
66 realtime_tools::RealtimePublisherSharedPtr<std_msgs::msg::Int32>>
67 IntPublishers;
68typedef std::pair<
69 std::shared_ptr<rclcpp::Publisher<std_msgs::msg::String>>,
70 realtime_tools::RealtimePublisherSharedPtr<std_msgs::msg::String>>
71 StringPublishers;
72typedef std::pair<std::any, std::any> CustomPublishers;
73
74typedef std::variant<
75 EncodedStatePublishers, BoolPublishers, DoublePublishers, DoubleVecPublishers, IntPublishers, StringPublishers,
76 CustomPublishers>
77 PublisherVariant;
78
84 ControllerInput() = default;
85 ControllerInput(BufferVariant buffer_variant) : buffer(std::move(buffer_variant)) {}
86 BufferVariant buffer;
87 std::chrono::time_point<std::chrono::steady_clock> timestamp;
88};
89
97 bool success;
98 std::string message;
99};
100
105class BaseControllerInterface : public controller_interface::ControllerInterface {
106public:
111
116 CallbackReturn on_init() override;
117
123 CallbackReturn on_configure(const rclcpp_lifecycle::State& previous_state) override;
124
125protected:
135 const std::shared_ptr<state_representation::ParameterInterface>& parameter, const std::string& description,
136 bool read_only = false);
137
148 template<typename T>
149 void add_parameter(const std::string& name, const T& value, const std::string& description, bool read_only = false);
150
161 virtual bool
162 on_validate_parameter_callback(const std::shared_ptr<state_representation::ParameterInterface>& parameter);
163
169 [[nodiscard]] std::shared_ptr<state_representation::ParameterInterface> get_parameter(const std::string& name) const;
170
177 template<typename T>
178 T get_parameter_value(const std::string& name) const;
179
188 template<typename T>
189 void set_parameter_value(const std::string& name, const T& value);
190
196 void add_predicate(const std::string& predicate_name, bool predicate_value);
197
203 void add_predicate(const std::string& predicate_name, const std::function<bool(void)>& predicate_function);
204
211 [[nodiscard]] bool get_predicate(const std::string& predicate_name) const;
212
220 void set_predicate(const std::string& predicate_name, bool predicate_value);
221
229 void set_predicate(const std::string& predicate_name, const std::function<bool(void)>& predicate_function);
230
237 void add_trigger(const std::string& trigger_name);
238
243 void trigger(const std::string& trigger_name);
244
253 template<typename T>
254 void add_input(const std::string& name, const std::string& topic_name = "");
255
264 template<typename T>
265 void add_output(const std::string& name, const std::string& topic_name = "");
266
272
280 template<typename T>
281 std::optional<T> read_input(const std::string& name);
282
291 template<typename T>
292 void write_output(const std::string& name, const T& data);
293
299 void add_service(const std::string& service_name, const std::function<ControllerServiceResponse(void)>& callback);
300
309 void add_service(
310 const std::string& service_name,
311 const std::function<ControllerServiceResponse(const std::string& string)>& callback);
312
317 [[nodiscard]] rclcpp::QoS get_qos() const;
318
323 void set_qos(const rclcpp::QoS& qos);
324
329 bool is_active() const;
330
335 std::timed_mutex& get_command_mutex();
336
337private:
345 bool validate_parameter(const std::shared_ptr<state_representation::ParameterInterface>& parameter);
346
351 void pre_set_parameters_callback(std::vector<rclcpp::Parameter>& parameters);
352
359 rcl_interfaces::msg::SetParametersResult on_set_parameters_callback(const std::vector<rclcpp::Parameter>& parameters);
360
366 modulo_interfaces::msg::Predicate get_predicate_message(const std::string& name, bool value) const;
367
373 void publish_predicate(const std::string& predicate_name, bool value) const;
374
378 void publish_predicates();
379
387 std::string validate_and_declare_signal(
388 const std::string& signal_name, const std::string& type, const std::string& default_topic,
389 bool fixed_topic = false);
390
399 void create_input(const ControllerInput& input, const std::string& name, const std::string& topic_name);
400
409 void create_output(const PublisherVariant& publishers, const std::string& name, const std::string& topic_name);
410
417 template<typename T>
418 std::shared_ptr<rclcpp::Subscription<T>> create_subscription(const std::string& name, const std::string& topic_name);
419
424 bool check_input_valid(const std::string& name) const;
425
429 template<typename PublisherT, typename MsgT, typename T>
430 void write_std_output(const std::string& name, const T& data);
431
435 void add_inputs();
436
440 void add_outputs();
441
448 std::string validate_service_name(const std::string& service_name, const std::string& type) const;
449
450 state_representation::ParameterMap parameter_map_;
451 std::unordered_map<std::string, bool> read_only_parameters_;
452 std::shared_ptr<rclcpp::node_interfaces::PreSetParametersCallbackHandle>
453 pre_set_parameter_cb_handle_;
454 std::shared_ptr<rclcpp::node_interfaces::OnSetParametersCallbackHandle>
455 on_set_parameter_cb_handle_;
456 rcl_interfaces::msg::SetParametersResult set_parameters_result_;
457 bool pre_set_parameter_callback_called_ = false;
458
459 std::vector<SubscriptionVariant> subscriptions_;
460 std::map<std::string, ControllerInput> inputs_;
461 std::map<std::string, std::shared_ptr<modulo_core::communication::MessagePairInterface>>
462 input_message_pairs_;
463 std::map<std::string, PublisherVariant> outputs_;
464 double input_validity_period_;
465 rclcpp::QoS qos_ = rclcpp::QoS(10);
466
467 std::map<std::string, std::shared_ptr<rclcpp::Service<modulo_interfaces::srv::EmptyTrigger>>>
468 empty_services_;
469 std::map<std::string, std::shared_ptr<rclcpp::Service<modulo_interfaces::srv::StringTrigger>>>
470 string_services_;
471
472 std::map<std::string, modulo_core::Predicate> predicates_;
473 std::shared_ptr<rclcpp::Publisher<modulo_interfaces::msg::PredicateCollection>>
474 predicate_publisher_;
475 std::vector<std::string> triggers_;
476 modulo_interfaces::msg::PredicateCollection predicate_message_;
477 std::shared_ptr<rclcpp::TimerBase> predicate_timer_;
478
479 std::timed_mutex command_mutex_;
480
481 std::map<std::string, std::function<void(CustomPublishers&, const std::string&)>>
482 custom_output_configuration_callables_;
483 std::map<std::string, std::function<void(const std::string&, const std::string&)>>
484 custom_input_configuration_callables_;
485};
486
487template<typename T>
489 const std::string& name, const T& value, const std::string& description, bool read_only) {
490 if (name.empty()) {
491 RCLCPP_ERROR(get_node()->get_logger(), "Failed to add parameter: Provide a non empty string as a name.");
492 return;
493 }
494 add_parameter(state_representation::make_shared_parameter(name, value), description, read_only);
495}
496
497template<typename T>
498inline T BaseControllerInterface::get_parameter_value(const std::string& name) const {
499 try {
500 return this->parameter_map_.template get_parameter_value<T>(name);
501 } catch (const state_representation::exceptions::InvalidParameterException& ex) {
503 "Failed to get parameter value of parameter '" + name + "': " + ex.what());
504 }
505}
506
507template<typename T>
508inline void BaseControllerInterface::set_parameter_value(const std::string& name, const T& value) {
509 try {
510 std::vector<rclcpp::Parameter> parameters{
511 modulo_core::translators::write_parameter(state_representation::make_shared_parameter(name, value))};
512 pre_set_parameters_callback(parameters);
513 pre_set_parameter_callback_called_ = true;
514 auto result = get_node()->set_parameters(parameters).at(0);
515 if (!result.successful) {
517 get_node()->get_logger(), *get_node()->get_clock(), 1000,
518 "Failed to set parameter value of parameter '%s': %s", name.c_str(), result.reason.c_str());
519 }
520 } catch (const std::exception& ex) {
522 get_node()->get_logger(), *get_node()->get_clock(), 1000, "Failed to set parameter value of parameter '%s': %s",
523 name.c_str(), ex.what());
524 }
525}
526
527template<typename T>
528inline void BaseControllerInterface::add_input(const std::string& name, const std::string& topic_name) {
529 if constexpr (modulo_core::concepts::CustomT<T>) {
530 auto buffer = std::make_shared<realtime_tools::RealtimeBuffer<std::shared_ptr<T>>>();
531 auto input = ControllerInput(buffer);
532 auto parsed_name = validate_and_declare_signal(name, "input", topic_name);
533 if (!parsed_name.empty()) {
534 inputs_.insert_or_assign(parsed_name, input);
535 custom_input_configuration_callables_.insert_or_assign(
536 name, [this](const std::string& name, const std::string& topic) {
537 auto subscription =
538 get_node()->create_subscription<T>(topic, qos_, [this, name](const std::shared_ptr<T> message) {
539 auto buffer_variant = std::get<std::any>(inputs_.at(name).buffer);
540 auto buffer = std::any_cast<std::shared_ptr<realtime_tools::RealtimeBuffer<std::shared_ptr<T>>>>(
542 buffer->writeFromNonRT(message);
543 inputs_.at(name).timestamp = std::chrono::steady_clock::now();
544 });
545 subscriptions_.push_back(subscription);
546 });
547 }
548 } else {
549 auto buffer = realtime_tools::RealtimeBuffer<std::shared_ptr<modulo_core::EncodedState>>();
550 auto input = ControllerInput(buffer);
551 auto parsed_name = validate_and_declare_signal(name, "input", topic_name);
552 if (!parsed_name.empty()) {
553 inputs_.insert_or_assign(parsed_name, input);
554 input_message_pairs_.insert_or_assign(
556 modulo_core::communication::make_shared_message_pair(std::make_shared<T>(), get_node()->get_clock()));
557 }
558 }
559}
560
561template<>
562inline void BaseControllerInterface::add_input<bool>(const std::string& name, const std::string& topic_name) {
563 auto buffer = realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Bool>>();
564 auto input = ControllerInput(buffer);
565 create_input(input, name, topic_name);
566}
567
568template<>
569inline void BaseControllerInterface::add_input<double>(const std::string& name, const std::string& topic_name) {
570 auto buffer = realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Float64>>();
571 auto input = ControllerInput(buffer);
572 create_input(input, name, topic_name);
573}
574
575template<>
576inline void
577BaseControllerInterface::add_input<std::vector<double>>(const std::string& name, const std::string& topic_name) {
578 auto buffer = realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Float64MultiArray>>();
579 auto input = ControllerInput(buffer);
580 create_input(input, name, topic_name);
581}
582
583template<>
584inline void BaseControllerInterface::add_input<int>(const std::string& name, const std::string& topic_name) {
585 auto buffer = realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Int32>>();
586 auto input = ControllerInput(buffer);
587 create_input(input, name, topic_name);
588}
589
590template<>
591inline void BaseControllerInterface::add_input<std::string>(const std::string& name, const std::string& topic_name) {
592 auto buffer = realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::String>>();
593 auto input = ControllerInput(buffer);
594 create_input(input, name, topic_name);
595}
596
597template<typename T>
598inline std::shared_ptr<rclcpp::Subscription<T>>
599BaseControllerInterface::create_subscription(const std::string& name, const std::string& topic_name) {
600 return get_node()->create_subscription<T>(topic_name, qos_, [this, name](const std::shared_ptr<T> message) {
601 std::get<realtime_tools::RealtimeBuffer<std::shared_ptr<T>>>(inputs_.at(name).buffer).writeFromNonRT(message);
602 inputs_.at(name).timestamp = std::chrono::steady_clock::now();
603 });
604}
605
606template<typename T>
607inline void BaseControllerInterface::add_output(const std::string& name, const std::string& topic_name) {
608 if constexpr (modulo_core::concepts::CustomT<T>) {
609 typedef std::pair<std::shared_ptr<rclcpp::Publisher<T>>, realtime_tools::RealtimePublisherSharedPtr<T>> PublisherT;
610 auto parsed_name = validate_and_declare_signal(name, "output", topic_name);
611 if (!parsed_name.empty()) {
612 outputs_.insert_or_assign(parsed_name, PublisherT());
613 custom_output_configuration_callables_.insert_or_assign(
614 name, [this](CustomPublishers& pub, const std::string& topic) {
615 auto publisher = get_node()->create_publisher<T>(topic, qos_);
616 pub.first = publisher;
617 pub.second = std::make_shared<realtime_tools::RealtimePublisher<T>>(publisher);
618 });
619 }
620 } else {
621 std::shared_ptr<state_representation::State> state_ptr = std::make_shared<T>();
622 create_output(EncodedStatePublishers(state_ptr, {}, {}), name, topic_name);
623 }
624}
625
626template<>
627inline void BaseControllerInterface::add_output<bool>(const std::string& name, const std::string& topic_name) {
628 create_output(BoolPublishers(), name, topic_name);
629}
630
631template<>
632inline void BaseControllerInterface::add_output<double>(const std::string& name, const std::string& topic_name) {
633 create_output(DoublePublishers(), name, topic_name);
634}
635
636template<>
637inline void
638BaseControllerInterface::add_output<std::vector<double>>(const std::string& name, const std::string& topic_name) {
639 create_output(DoubleVecPublishers(), name, topic_name);
640}
641
642template<>
643inline void BaseControllerInterface::add_output<int>(const std::string& name, const std::string& topic_name) {
644 create_output(IntPublishers(), name, topic_name);
645}
646
647template<>
648inline void BaseControllerInterface::add_output<std::string>(const std::string& name, const std::string& topic_name) {
649 create_output(StringPublishers(), name, topic_name);
650}
651
652template<typename T>
653inline std::optional<T> BaseControllerInterface::read_input(const std::string& name) {
654 if (!check_input_valid(name)) {
655 return {};
656 }
657
658 if constexpr (modulo_core::concepts::CustomT<T>) {
659 try {
660 auto buffer_variant = std::get<std::any>(inputs_.at(name).buffer);
661 auto buffer = std::any_cast<std::shared_ptr<realtime_tools::RealtimeBuffer<std::shared_ptr<T>>>>(buffer_variant);
662 return **(buffer->readFromNonRT());
663 } catch (const std::bad_any_cast& ex) {
664 RCLCPP_ERROR(get_node()->get_logger(), "Failed to read custom input: %s", ex.what());
665 }
666 return {};
667 } else {
668 auto message =
669 **std::get<realtime_tools::RealtimeBuffer<std::shared_ptr<modulo_core::EncodedState>>>(inputs_.at(name).buffer)
670 .readFromNonRT();
671 std::shared_ptr<state_representation::State> state;
672 try {
673 auto message_pair = input_message_pairs_.at(name);
674 message_pair->read<modulo_core::EncodedState, state_representation::State>(message);
675 state = message_pair->get_message_pair<modulo_core::EncodedState, state_representation::State>()->get_data();
676 } catch (const std::exception& ex) {
678 get_node()->get_logger(), *get_node()->get_clock(), 1000,
679 "Could not read EncodedState message on input '%s': %s", name.c_str(), ex.what());
680 return {};
681 }
682 if (state->is_empty()) {
683 return {};
684 }
685 auto cast_ptr = std::dynamic_pointer_cast<T>(state);
686 if (cast_ptr != nullptr) {
687 return *cast_ptr;
688 } else {
690 get_node()->get_logger(), *get_node()->get_clock(), 1000,
691 "Dynamic cast of message on input '%s' from type '%s' to type '%s' failed.", name.c_str(),
692 get_state_type_name(state->get_type()).c_str(), get_state_type_name(T().get_type()).c_str());
693 }
694 return {};
695 }
696}
697
698template<>
699inline std::optional<bool> BaseControllerInterface::read_input<bool>(const std::string& name) {
700 if (!check_input_valid(name)) {
701 return {};
702 }
703 // no need to check for emptiness of the pointer: timestamps are default constructed to 0, so an input being valid
704 // means that a message was received
705 return (*std::get<realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Bool>>>(inputs_.at(name).buffer)
706 .readFromNonRT())
707 ->data;
708}
709
710template<>
711inline std::optional<double> BaseControllerInterface::read_input<double>(const std::string& name) {
712 if (!check_input_valid(name)) {
713 return {};
714 }
715 return (*std::get<realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Float64>>>(inputs_.at(name).buffer)
716 .readFromNonRT())
717 ->data;
718}
719
720template<>
721inline std::optional<std::vector<double>>
723 if (!check_input_valid(name)) {
724 return {};
725 }
726 return (*std::get<realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Float64MultiArray>>>(
727 inputs_.at(name).buffer)
728 .readFromNonRT())
729 ->data;
730}
731
732template<>
733inline std::optional<int> BaseControllerInterface::read_input<int>(const std::string& name) {
734 if (!check_input_valid(name)) {
735 return {};
736 }
737 return (*std::get<realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::Int32>>>(inputs_.at(name).buffer)
738 .readFromNonRT())
739 ->data;
740}
741
742template<>
743inline std::optional<std::string> BaseControllerInterface::read_input<std::string>(const std::string& name) {
744 if (!check_input_valid(name)) {
745 return {};
746 }
747 return (*std::get<realtime_tools::RealtimeBuffer<std::shared_ptr<std_msgs::msg::String>>>(inputs_.at(name).buffer)
748 .readFromNonRT())
749 ->data;
750}
751
752template<typename T>
753inline void BaseControllerInterface::write_output(const std::string& name, const T& data) {
754 if (outputs_.find(name) == outputs_.end()) {
756 get_node()->get_logger(), *get_node()->get_clock(), 1000, "Could not find output '%s'", name.c_str());
757 return;
758 }
759
760 if constexpr (modulo_core::concepts::CustomT<T>) {
761 CustomPublishers publishers;
762 try {
763 publishers = std::get<CustomPublishers>(outputs_.at(name));
764 } catch (const std::bad_variant_access&) {
766 get_node()->get_logger(), *get_node()->get_clock(), 1000,
767 "Could not retrieve publisher for output '%s': Invalid output type", name.c_str());
768 return;
769 }
770
771 std::shared_ptr<realtime_tools::RealtimePublisher<T>> rt_pub;
772 try {
773 rt_pub = std::any_cast<std::shared_ptr<realtime_tools::RealtimePublisher<T>>>(publishers.second);
774 } catch (const std::bad_any_cast& ex) {
776 get_node()->get_logger(), *get_node()->get_clock(), 1000,
777 "Skipping publication of output '%s' due to wrong data type: %s", name.c_str(), ex.what());
778 return;
779 }
780 if (rt_pub && rt_pub->trylock()) {
781 rt_pub->msg_ = data;
782 rt_pub->unlockAndPublish();
783 }
784 } else {
785 if (data.is_empty()) {
787 get_node()->get_logger(), *get_node()->get_clock(), 1000,
788 "Skipping publication of output '%s' due to emptiness of state", name.c_str());
789 return;
790 }
791 EncodedStatePublishers publishers;
792 try {
793 publishers = std::get<EncodedStatePublishers>(outputs_.at(name));
794 } catch (const std::bad_variant_access&) {
796 get_node()->get_logger(), *get_node()->get_clock(), 1000,
797 "Could not retrieve publisher for output '%s': Invalid output type", name.c_str());
798 return;
799 }
800 if (const auto output_type = std::get<0>(publishers)->get_type(); output_type != data.get_type()) {
802 get_node()->get_logger(), *get_node()->get_clock(), 1000,
803 "Skipping publication of output '%s' due to wrong data type (expected '%s', got '%s')",
804 state_representation::get_state_type_name(output_type).c_str(),
805 state_representation::get_state_type_name(data.get_type()).c_str(), name.c_str());
806 return;
807 }
808 auto rt_pub = std::get<2>(publishers);
809 if (rt_pub && rt_pub->trylock()) {
810 try {
811 modulo_core::translators::write_message<T>(rt_pub->msg_, data, get_node()->get_clock()->now());
814 get_node()->get_logger(), *get_node()->get_clock(), 1000, "Failed to publish output '%s': %s", name.c_str(),
815 ex.what());
816 }
817 rt_pub->unlockAndPublish();
818 }
819 }
820}
821
822template<typename PublisherT, typename MsgT, typename T>
823void BaseControllerInterface::write_std_output(const std::string& name, const T& data) {
824 if (outputs_.find(name) == outputs_.end()) {
826 get_node()->get_logger(), *get_node()->get_clock(), 1000, "Could not find output '%s'", name.c_str());
827 return;
828 }
830 try {
831 publishers = std::get<PublisherT>(outputs_.at(name));
832 } catch (const std::bad_variant_access&) {
834 get_node()->get_logger(), *get_node()->get_clock(), 1000,
835 "Could not retrieve publisher for output '%s': Invalid output type", name.c_str());
836 return;
837 }
838 auto rt_pub = publishers.second;
839 if (rt_pub && rt_pub->trylock()) {
840 rt_pub->msg_.data = data;
841 rt_pub->unlockAndPublish();
842 }
843}
844
845template<>
846inline void BaseControllerInterface::write_output(const std::string& name, const bool& data) {
848}
849
850template<>
851inline void BaseControllerInterface::write_output(const std::string& name, const double& data) {
853}
854
855template<>
856inline void BaseControllerInterface::write_output(const std::string& name, const std::vector<double>& data) {
858}
859
860template<>
861inline void BaseControllerInterface::write_output(const std::string& name, const int& data) {
863}
864
865template<>
866inline void BaseControllerInterface::write_output(const std::string& name, const std::string& data) {
868}
869
870}// namespace modulo_controllers
Base controller class to combine ros2_control, control libraries and modulo.
std::shared_ptr< state_representation::ParameterInterface > get_parameter(const std::string &name) const
Get a parameter by name.
CallbackReturn on_configure(const rclcpp_lifecycle::State &previous_state) override
Add signals.
rclcpp::QoS get_qos() const
Getter of the Quality of Service attribute.
bool is_active() const
Check if the controller is currently in state active or not.
void set_parameter_value(const std::string &name, const T &value)
Set the value of a parameter.
T get_parameter_value(const std::string &name) const
Get a parameter value by name.
void add_output(const std::string &name, const std::string &topic_name="")
Add an output to the controller.
void set_input_validity_period(double input_validity_period)
Set the input validity period of input signals.
CallbackReturn on_init() override
Declare parameters and register the on_set_parameters callback.
std::optional< T > read_input(const std::string &name)
Read the most recent message of an input.
void add_parameter(const std::shared_ptr< state_representation::ParameterInterface > &parameter, const std::string &description, bool read_only=false)
Add a parameter.
void write_output(const std::string &name, const T &data)
Write an object to an output.
void trigger(const std::string &trigger_name)
Latch the trigger with the provided name.
void set_qos(const rclcpp::QoS &qos)
Set the Quality of Service for ROS publishers and subscribers.
void add_input(const std::string &name, const std::string &topic_name="")
Add an input to the controller.
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...
void add_predicate(const std::string &predicate_name, bool predicate_value)
Add a predicate to the map of predicates.
bool get_predicate(const std::string &predicate_name) const
Get the logical value of a predicate.
virtual bool on_validate_parameter_callback(const std::shared_ptr< state_representation::ParameterInterface > &parameter)
Parameter validation function to be redefined by derived controller classes.
void add_service(const std::string &service_name, const std::function< ControllerServiceResponse(void)> &callback)
Add a service to trigger a callback function with no input arguments.
std::timed_mutex & get_command_mutex()
Get the reference to the command mutex.
void add_trigger(const std::string &trigger_name)
Add a trigger to the controller.
An exception class to notify that the translation of a ROS message failed.
An exception class to notify errors with parameters in modulo classes.
rclcpp::Parameter write_parameter(const std::shared_ptr< state_representation::ParameterInterface > &parameter)
Write a ROS Parameter from a ParameterInterface pointer.
Input structure to save topic data in a realtime buffer and timestamps in one object.
Response structure to be returned by controller services.