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