PX4 ROS 2 Interface Library
Library to interface with PX4 from a companion computer using ROS 2
Loading...
Searching...
No Matches
mission_executor.hpp
1/****************************************************************************
2 * Copyright (c) 2024 PX4 Development Team.
3 * SPDX-License-Identifier: BSD-3-Clause
4 ****************************************************************************/
5
6#pragma once
7#include <memory>
8#include <px4_ros2/components/mode.hpp>
9#include <px4_ros2/components/mode_executor.hpp>
10#include <px4_ros2/mission/actions/action.hpp>
11#include <px4_ros2/mission/mission.hpp>
12#include <px4_ros2/mission/trajectory/trajectory_executor.hpp>
13#include <px4_ros2/vehicle_state/land_detected.hpp>
14#include <vector>
15
16namespace px4_ros2 {
21class AsyncFunctionCalls;
22class ActionStateKeeper;
23
29 public:
31 std::vector<std::function<std::shared_ptr<ActionInterface>(ModeBase& mode)>>
32 custom_actions_factory;
33 std::set<std::string> default_actions{
34 "changeSettings", "onResume", "onFailure", "takeoff", "rtl", "land", "hold"};
35 std::function<std::shared_ptr<TrajectoryExecutorInterface>(ModeBase& mode)>
36 trajectory_executor_factory;
37 std::string persistence_filename;
38
39 template <class ActionType, typename... Args>
40 Configuration& addCustomAction(Args&&... args)
41 {
42 custom_actions_factory.push_back(
43 [args = std::tie(std::forward<Args>(args)...)](ModeBase& mode) mutable {
44 return std::apply(
45 [&mode](auto&&... args) {
46 return std::make_shared<ActionType>(mode, std::forward<Args>(args)...);
47 },
48 std::move(args));
49 });
50 return *this;
51 }
52 template <typename TrajectoryExecutorType, typename... Args>
53 Configuration& withTrajectoryExecutor(Args&&... args)
54 {
55 trajectory_executor_factory = [args = std::tie(std::forward<Args>(args)...)](
56 ModeBase& mode) mutable {
57 return std::apply(
58 [&mode](auto&&... args) {
59 return std::make_shared<TrajectoryExecutorType>(mode, std::forward<Args>(args)...);
60 },
61 std::move(args));
62 };
63 return *this;
64 }
65 Configuration& withPersistenceFile(const std::string& filename)
66 {
67 persistence_filename = filename;
68 return *this;
69 }
70 };
71
72 MissionExecutor(const std::string& mode_name, const Configuration& configuration,
73 rclcpp::Node& node, const std::string& topic_namespace_prefix = "");
74
75 virtual ~MissionExecutor();
76
77 bool doRegister();
78
79 void setMission(const Mission& mission);
80 void resetMission();
81
82 const Mission& mission() const { return *_mission; }
83
84 void onActivated(const std::function<void()>& callback) { _on_activated = callback; }
85 void onDeactivated(const std::function<void()>& callback) { _on_deactivated = callback; }
90 void onProgressUpdate(const std::function<void(int)>& callback)
91 {
92 _on_progress_update = callback;
93 }
94 void onCompleted(const std::function<void()>& callback) { _on_completed = callback; }
95 void onFailsafeDeferred(const std::function<void()>& callback);
96 void onReadynessUpdate(
97 const std::function<void(bool ready, const std::vector<std::string>& errors)>& callback);
98
105 void onActivityInfoChange(const std::function<void(const std::optional<std::string>&)>& callback)
106 {
107 _on_activity_info_change = callback;
108 }
109
120 void setActivityInfo(const std::optional<std::string>& activity_info);
131 bool deferFailsafes(bool enabled, int timeout_s = 0);
132
133 bool controlAutoSetHome(bool enabled);
134
139 void abort();
140
145 void setSkipMessageCompatibilityCheck() { _mode_executor->setSkipMessageCompatibilityCheck(); }
146
147 protected:
148 class MissionMode : public ModeBase {
149 public:
150 MissionMode(rclcpp::Node& node, const Settings& settings,
151 const std::string& topic_namespace_prefix, MissionExecutor& mission_executor)
152 : ModeBase(node, settings, topic_namespace_prefix), _mission_executor(mission_executor)
153 {
154 }
155
156 explicit MissionMode(const ModeBase& mode_base) = delete;
157
158 ~MissionMode() override = default;
160 {
161 _mission_executor.checkArmingAndRunConditions(reporter);
162 }
163 void updateSetpoint(float dt_s) override { _mission_executor.updateSetpoint(); }
164
165 void disableWatchdogTimer() // NOLINT we just want to change the methods visibility
166 {
167 ModeBase::disableWatchdogTimer();
168 }
169
170 private:
171 MissionExecutor& _mission_executor;
172 };
173
175 public:
176 MissionModeExecutor(rclcpp::Node& node, const Settings& settings, ModeBase& owned_mode,
177 const std::string& topic_namespace_prefix,
178 MissionExecutor& mission_executor)
179 : ModeExecutorBase(settings, owned_mode), _mission_executor(mission_executor)
180 {
181 }
182
183 explicit MissionModeExecutor(const ModeExecutorBase& mode_executor_base) = delete;
184
185 ~MissionModeExecutor() override = default;
186 void onActivate() override { _mission_executor.onActivate(); }
187 void onDeactivate(DeactivateReason reason) override { _mission_executor.onDeactivate(reason); }
188 void onFailsafeDeferred() override
189 {
190 if (on_failsafe_deferred) {
191 on_failsafe_deferred();
192 }
193 }
194
195 Result sendCommandSync(uint32_t command, float param1, float param2, float param3, float param4,
196 float param5, float param6, float param7) override
197 {
198 if (command_handler) {
199 return command_handler(command, param1) ? Result::Success : Result::Rejected;
200 }
201 return ModeExecutorBase::sendCommandSync(command, param1, param2, param3, param4, param5,
202 param6, param7);
203 }
204
205 void setRegistration(const std::shared_ptr<Registration>& registration)
206 {
207 setSkipMessageCompatibilityCheck();
208 overrideRegistration(registration);
209 }
210
211 void setSkipMessageCompatibilityCheck()
212 {
213 ModeExecutorBase::setSkipMessageCompatibilityCheck();
214 }
215
216 std::function<bool(uint32_t, float)> command_handler{nullptr};
217 std::function<void()> on_failsafe_deferred{nullptr};
218
219 private:
220 MissionExecutor& _mission_executor;
221 };
222
223 virtual bool doRegisterImpl(MissionMode& mode, MissionModeExecutor& executor_base);
224
225 void setCommandHandler(const std::function<bool(uint32_t, float)>& command_handler)
226 {
227 _mode_executor->command_handler = command_handler;
228 }
229
230 ModeBase::ModeID modeId() const { return _mode->id(); }
231
232 ModeExecutorBase& modeExecutor() { return *_mode_executor; }
233
234 std::shared_ptr<LandDetected> _land_detected;
235
236 private:
237 using ActionID = int;
238 enum class AbortReason {
239 Other,
240 ModeFailure,
241 TrajectoryFailure,
242 NoValidMission,
243 ActionDoesNotExist,
244 };
245 static std::string abortReasonStr(AbortReason reason);
246
247 void checkArmingAndRunConditions(HealthAndArmingCheckReporter& reporter);
248 void checkReadynessAndReport();
249 void updateSetpoint();
250 void onActivate();
251 void onDeactivate(ModeExecutorBase::DeactivateReason reason);
252
253 bool isReady() const { return _has_valid_mission && _actions_ready; }
254
255 void runMode(ModeBase::ModeID mode_id, const std::function<void()>& on_completed,
256 const std::function<void()>& on_failure = nullptr);
265 void runModeTakeoff(float altitude, float heading, const std::function<void()>& on_completed,
266 const std::function<void()>& on_failure = nullptr);
267 void runAction(const std::string& action_name, const ActionArguments& arguments,
268 const std::function<void()>& on_completed);
269 void runTrajectory(const std::shared_ptr<Mission>& trajectory, int start_index, int end_index,
270 const std::function<void(int)>& on_index_reached, bool stop_at_last_item);
271
272 void runNextMissionItem();
273 void runCurrentMissionItem(bool resuming);
274 void resetMissionState();
275 std::pair<int, bool> getNextTrajectorySegment(int start_index) const;
276 bool currentActionSupportsResumeFromLanded() const;
277
278 void setTrajectoryOptions(const TrajectoryOptions& options);
279 void clearTrajectoryOptions();
280
281 void setCurrentMissionIndex(int index);
282
283 void abort(AbortReason reason);
284 void invalidateActionHandler();
285
286 void savePersistentState();
287 void clearPersistentState() const;
288 bool tryLoadPersistentState();
289 nlohmann::json getOnResumeStateAndClear();
290 void runOnResumeStoreState();
291
292 struct ActionState {
293 std::string name;
294 ActionArguments arguments;
295 };
296 std::unique_ptr<ActionStateKeeper> addContinousAction(const ActionState& state);
297 void removeContinousAction(ActionID id);
298 void runStoredActions();
299 void deactivateAllActions();
300
301 struct PersistentState {
302 std::optional<int> current_index;
303 std::string mission_checksum;
304
305 std::map<ActionID, ActionState> continuous_actions;
306
307 void toJson(nlohmann::json& j) const;
308 void fromJson(const nlohmann::json& j);
309 };
310
311 PersistentState _state;
312 int _next_continuous_action_id{0};
313 const std::string _persistence_filename;
314
315 enum class MissionItemState {
316 Trajectory,
317 Other,
318 };
319 MissionItemState _mission_item_state{MissionItemState::Other};
320 ModeBase::ModeID _active_mode{};
321 bool _is_active{false};
322
323 std::optional<rclcpp::Time> _trajectory_update_warn;
324
325 std::shared_ptr<TrajectoryExecutorInterface> _trajectory_executor;
326 std::map<std::string, std::shared_ptr<ActionInterface>> _actions;
327 std::shared_ptr<Mission> _mission;
328 TrajectoryOptions _trajectory_options;
329 bool _has_valid_mission{false};
330 static const std::vector<std::string> kNoMissionErrors;
331 std::vector<std::string> _mission_errors{kNoMissionErrors};
332 bool _actions_ready{false};
333 rclcpp::TimerBase::SharedPtr _readyness_timer;
334 int _abort_recursion_level{
335 0};
336
337 rclcpp::Node& _node;
338 std::unique_ptr<MissionMode> _mode;
339 std::unique_ptr<MissionModeExecutor> _mode_executor;
340 std::shared_ptr<ActionHandler> _action_handler;
341
342 std::unique_ptr<AsyncFunctionCalls> _reporting; // Report asynchronously to avoid potential
343 // recursive calls and state changes in between
344 std::function<void()> _on_activated;
345 std::function<void()> _on_deactivated;
346 std::function<void(int)> _on_progress_update;
347 std::function<void()> _on_completed;
348 std::function<void(const std::optional<std::string>&)> _on_activity_info_change;
349 std::function<void(bool ready, const std::vector<std::string>& errors)> _on_readyness_update;
350
351 friend class ActionHandler;
352 friend class ActionStateKeeper;
353};
354
356 public:
357 ActionStateKeeper(int id, MissionExecutor& mission_executor)
358 : _id(id), _mission_executor(mission_executor)
359 {
360 }
361
362 ~ActionStateKeeper() { _mission_executor.removeContinousAction(_id); }
363
364 private:
365 const int _id;
366 MissionExecutor& _mission_executor;
367};
368
374 public:
375 explicit ActionHandler(MissionExecutor& mission_executor) : _mission_executor(mission_executor) {}
376
377 void runMode(ModeBase::ModeID mode_id, const std::function<void()>& on_completed,
378 const std::function<void()>& on_failure = nullptr)
379 {
380 if (!_valid) {
381 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
382 return;
383 }
384 _mission_executor.runMode(mode_id, on_completed, on_failure);
385 }
394 void runModeTakeoff(float altitude, float heading, const std::function<void()>& on_completed,
395 const std::function<void()>& on_failure = nullptr)
396 {
397 if (!_valid) {
398 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
399 return;
400 }
401 _mission_executor.runModeTakeoff(altitude, heading, on_completed, on_failure);
402 }
403 void runAction(const std::string& action_name, const ActionArguments& arguments,
404 const std::function<void()>& on_completed)
405 {
406 if (!_valid) {
407 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
408 return;
409 }
410 _mission_executor.runAction(action_name, arguments, on_completed);
411 }
412 void runTrajectory(const std::shared_ptr<Mission>& trajectory,
413 const std::function<void()>& on_completed, bool stop_at_last_item = true);
414
418 TrajectoryOptions getTrajectoryOptions() const { return _mission_executor._trajectory_options; }
423 {
424 if (!_valid) {
425 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
426 return;
427 }
428 _mission_executor.clearTrajectoryOptions();
429 }
436 {
437 if (!_valid) {
438 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
439 return;
440 }
441 _mission_executor.setTrajectoryOptions(options);
442 }
443
452 void setActvityInfo(const std::string& activity_info)
453 {
454 if (!_valid) {
455 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
456 return;
457 }
458 _mission_executor.setActivityInfo(activity_info);
459 }
460
467 {
468 if (!_valid) {
469 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
470 return;
471 }
472 _mission_executor.setActivityInfo(std::nullopt);
473 }
474
475 std::optional<int> getCurrentMissionIndex() const;
485 void setCurrentMissionIndex(int index);
486
487 bool currentActionSupportsResumeFromLanded() const;
488
503 std::unique_ptr<ActionStateKeeper> storeState(const std::string& action_name,
504 const ActionArguments& arguments)
505 {
506 if (!_valid) {
507 return nullptr;
508 }
509 return _mission_executor.addContinousAction(
510 MissionExecutor::ActionState{action_name, arguments});
511 }
512
513 const Mission& mission() const { return _mission_executor.mission(); }
514
522 bool deferFailsafes(bool enabled, int timeout_s = 0)
523 {
524 if (!_valid) {
525 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
526 return false;
527 }
528 return _mission_executor.deferFailsafes(enabled, timeout_s);
529 }
530
531 bool controlAutoSetHome(bool enabled)
532 {
533 if (!_valid) {
534 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
535 return false;
536 }
537 return _mission_executor.controlAutoSetHome(enabled);
538 }
539
545 void onFailsafeDeferred(const std::function<void()>& callback)
546 {
547 if (!_valid) {
548 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
549 return;
550 }
551 _mission_executor.onFailsafeDeferred(callback);
552 }
553
560 bool isValid() const { return _valid; }
561
562 private:
563 friend class MissionExecutor;
564 void setInvalid() { _valid = false; }
565
566 bool _valid{true};
567 MissionExecutor& _mission_executor;
568};
569
571} /* namespace px4_ros2 */
Arguments passed to an action from the mission JSON definition.
Definition mission.hpp:25
Handler passed to custom actions to run modes, actions and trajectories.
Definition mission_executor.hpp:373
void setTrajectoryOptions(const TrajectoryOptions &options)
Override the trajectory config options.
Definition mission_executor.hpp:435
TrajectoryOptions getTrajectoryOptions() const
get the current trajectory config options
Definition mission_executor.hpp:418
void setActvityInfo(const std::string &activity_info)
Sets the activity info for the mission executor. This method forwards the provided activity string to...
Definition mission_executor.hpp:452
bool isValid() const
Check if the handler is still valid.
Definition mission_executor.hpp:560
void clearActivityInfo()
Clears the activity information. This method sets the activity info of the mission executor to std::n...
Definition mission_executor.hpp:466
bool deferFailsafes(bool enabled, int timeout_s=0)
enable/disable deferral of failsafes
Definition mission_executor.hpp:522
void clearTrajectoryOptions()
Reset the current trajectory config options to the mission defaults.
Definition mission_executor.hpp:422
void onFailsafeDeferred(const std::function< void()> &callback)
register callback for failsafe notification
Definition mission_executor.hpp:545
void runModeTakeoff(float altitude, float heading, const std::function< void()> &on_completed, const std::function< void()> &on_failure=nullptr)
Trigger a takeoff.
Definition mission_executor.hpp:394
std::unique_ptr< ActionStateKeeper > storeState(const std::string &action_name, const ActionArguments &arguments)
store the state of a continuous action
Definition mission_executor.hpp:503
void setCurrentMissionIndex(int index)
Set the current mission index.
Definition mission_executor.hpp:355
Definition health_and_arming_checks.hpp:21
Definition mission_executor.hpp:174
void onActivate() override
Definition mission_executor.hpp:186
Result sendCommandSync(uint32_t command, float param1, float param2, float param3, float param4, float param5, float param6, float param7) override
Definition mission_executor.hpp:195
void onFailsafeDeferred() override
Definition mission_executor.hpp:188
void onDeactivate(DeactivateReason reason) override
Definition mission_executor.hpp:187
Definition mission_executor.hpp:148
void checkArmingAndRunConditions(HealthAndArmingCheckReporter &reporter) override
Definition mission_executor.hpp:159
Mission execution state machine.
Definition mission_executor.hpp:28
void onActivityInfoChange(const std::function< void(const std::optional< std::string > &)> &callback)
Registers a callback to be invoked when the activity information changes. This callback provides a wa...
Definition mission_executor.hpp:105
bool deferFailsafes(bool enabled, int timeout_s=0)
void onProgressUpdate(const std::function< void(int)> &callback)
Definition mission_executor.hpp:90
void setActivityInfo(const std::optional< std::string > &activity_info)
Sets a string with extra information about the current activity. This provides more specific context ...
void setSkipMessageCompatibilityCheck()
Definition mission_executor.hpp:145
Mission definition.
Definition mission.hpp:149
Base class for a mode.
Definition mode.hpp:73
uint8_t ModeID
Mode ID, corresponds to nav_state.
Definition mode.hpp:75
Base class for a mode executor.
Definition mode_executor.hpp:29
virtual Result sendCommandSync(uint32_t command, float param1=NAN, float param2=NAN, float param3=NAN, float param4=NAN, float param5=NAN, float param6=NAN, float param7=NAN)
Result
Definition mode.hpp:29
@ Rejected
The request was rejected.
Definition mission_executor.hpp:30
Definition mode.hpp:89
Definition mode_executor.hpp:33
Definition mission.hpp:114