PX4 ROS 2 Interface Library
Library to interface with PX4 from a companion computer using ROS 2
node_with_mode.hpp
1 /****************************************************************************
2  * Copyright (c) 2024 PX4 Development Team.
3  * SPDX-License-Identifier: BSD-3-Clause
4  ****************************************************************************/
5 
6 #pragma once
7 
8 #include <tuple>
9 #include <utility>
10 #include <rclcpp/rclcpp.hpp>
11 #include <px4_ros2/components/mode.hpp>
12 #include <px4_ros2/components/wait_for_fmu.hpp>
13 
14 namespace px4_ros2
15 {
33 template<typename ModeT>
34 class NodeWithMode : public rclcpp::Node
35 {
36  static_assert(
37  std::is_base_of<ModeBase, ModeT>::value,
38  "Template type ModeT must be derived from px4_ros2::ModeBase");
39 
40 public:
41  explicit NodeWithMode(std::string node_name, bool enable_debug_output = false)
42  : Node(node_name)
43  {
44  if (enable_debug_output) {
45  auto ret =
46  rcutils_logging_set_logger_level(get_logger().get_name(), RCUTILS_LOG_SEVERITY_DEBUG);
47 
48  if (ret != RCUTILS_RET_OK) {
49  RCLCPP_ERROR(get_logger(), "Error setting severity: %s", rcutils_get_error_string().str);
50  rcutils_reset_error();
51  }
52  }
53 
54  _mode = std::make_unique<ModeT>(*this);
55 
56  if (!_mode->doRegister()) {
57  throw std::runtime_error("Registration failed");
58  }
59  }
60 
61  ModeT & getMode() const
62  {
63  return *_mode;
64  }
65 
66 private:
67  std::unique_ptr<ModeT> _mode;
68 };
69 
89 template<typename ModeExecutorT, typename OwnedModeT, typename ... OtherModesT>
90 class NodeWithModeExecutor : public rclcpp::Node
91 {
92  static_assert(
93  std::is_base_of_v<ModeExecutorBase, ModeExecutorT>,
94  "Template type ModeExecutorT must be derived from px4_ros2::ModeExecutorBase");
95  static_assert(
96  (std::is_base_of_v<ModeBase, OwnedModeT>&& ... && std::is_base_of_v<ModeBase, OtherModesT>),
97  "Template types OwnedModeT and OtherModesT must be derived from px4_ros2::ModeBase");
98 
99 public:
100  explicit NodeWithModeExecutor(std::string node_name, bool enable_debug_output = false)
101  : Node(node_name)
102  {
103  if (enable_debug_output) {
104  auto ret =
105  rcutils_logging_set_logger_level(get_logger().get_name(), RCUTILS_LOG_SEVERITY_DEBUG);
106 
107  if (ret != RCUTILS_RET_OK) {
108  RCLCPP_ERROR(get_logger(), "Error setting severity: %s", rcutils_get_error_string().str);
109  rcutils_reset_error();
110  }
111  }
112 
113  _owned_mode = std::make_unique<OwnedModeT>(*this);
114  _other_modes = std::make_tuple(std::make_unique<OtherModesT>(*this)...);
115  _mode_executor = createModeExecutor(std::index_sequence_for<OtherModesT...>{});
116 
117  if (!_mode_executor->doRegister() || !std::apply(
118  [](const auto &... mode) {
119  // *INDENT-OFF*
120  return (mode->doRegister() && ...);
121  // *INDENT-ON*
122  }, _other_modes))
123  {
124  throw std::runtime_error("Registration failed");
125  }
126  }
127 
128  template<typename ModeT = OwnedModeT>
129  ModeT & getMode() const
130  {
131  if constexpr (std::is_same_v<ModeT, OwnedModeT>) {
132  return *_owned_mode;
133  } else {
134  return *std::get<ModeT>(_other_modes);
135  }
136  }
137 
138 private:
139  template<std::size_t... Idx>
140  auto createModeExecutor(std::index_sequence<Idx...>)
141  {
142  if constexpr (sizeof...(Idx) == 0) {
143  return std::make_unique<ModeExecutorT>(*this, *_owned_mode);
144  } else {
145  return std::make_unique<ModeExecutorT>(*this, *_owned_mode, *std::get<Idx>(_other_modes)...);
146  }
147  }
148 
149  std::unique_ptr<ModeExecutorT> _mode_executor;
150  std::unique_ptr<OwnedModeT> _owned_mode;
151  std::tuple<std::unique_ptr<OtherModesT>...> _other_modes;
152 };
153 
155 } // namespace px4_ros2
A ROS2 node which instantiates a mode executor and its owned mode, and handles their registration wit...
Definition: node_with_mode.hpp:91
A ROS2 node which instantiates a control mode and handles its registration with PX4.
Definition: node_with_mode.hpp:35