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 void setSkipSetpointCheck() // NOLINT we just want to change the methods visibility
171 {
172 ModeBase::setSkipSetpointCheck();
173 }
174
175 private:
176 MissionExecutor& _mission_executor;
177 };
178
180 public:
181 MissionModeExecutor(rclcpp::Node& node, const Settings& settings, ModeBase& owned_mode,
182 const std::string& topic_namespace_prefix,
183 MissionExecutor& mission_executor)
184 : ModeExecutorBase(settings, owned_mode), _mission_executor(mission_executor)
185 {
186 }
187
188 explicit MissionModeExecutor(const ModeExecutorBase& mode_executor_base) = delete;
189
190 ~MissionModeExecutor() override = default;
191 void onActivate() override { _mission_executor.onActivate(); }
192 void onDeactivate(DeactivateReason reason) override { _mission_executor.onDeactivate(reason); }
193 void onFailsafeDeferred() override
194 {
195 if (on_failsafe_deferred) {
196 on_failsafe_deferred();
197 }
198 }
199
200 Result sendCommandSync(uint32_t command, float param1, float param2, float param3, float param4,
201 float param5, float param6, float param7) override
202 {
203 if (command_handler) {
204 return command_handler(command, param1) ? Result::Success : Result::Rejected;
205 }
206 return ModeExecutorBase::sendCommandSync(command, param1, param2, param3, param4, param5,
207 param6, param7);
208 }
209
210 void setRegistration(const std::shared_ptr<Registration>& registration)
211 {
212 setSkipMessageCompatibilityCheck();
213 overrideRegistration(registration);
214 }
215
216 void setSkipMessageCompatibilityCheck()
217 {
218 ModeExecutorBase::setSkipMessageCompatibilityCheck();
219 }
220
221 std::function<bool(uint32_t, float)> command_handler{nullptr};
222 std::function<void()> on_failsafe_deferred{nullptr};
223
224 private:
225 MissionExecutor& _mission_executor;
226 };
227
228 virtual bool doRegisterImpl(MissionMode& mode, MissionModeExecutor& executor_base);
229
230 void setCommandHandler(const std::function<bool(uint32_t, float)>& command_handler)
231 {
232 _mode_executor->command_handler = command_handler;
233 }
234
235 ModeBase::ModeID modeId() const { return _mode->id(); }
236
237 ModeExecutorBase& modeExecutor() { return *_mode_executor; }
238
239 std::shared_ptr<LandDetected> _land_detected;
240
241 private:
242 using ActionID = int;
243 enum class AbortReason {
244 Other,
245 ModeFailure,
246 TrajectoryFailure,
247 NoValidMission,
248 ActionDoesNotExist,
249 };
250 static std::string abortReasonStr(AbortReason reason);
251
252 void checkArmingAndRunConditions(HealthAndArmingCheckReporter& reporter);
253 void checkReadynessAndReport();
254 void updateSetpoint();
255 void onActivate();
256 void onDeactivate(ModeExecutorBase::DeactivateReason reason);
257
258 bool isReady() const { return _has_valid_mission && _actions_ready; }
259
260 void runMode(ModeBase::ModeID mode_id, const std::function<void()>& on_completed,
261 const std::function<void()>& on_failure = nullptr);
270 void runModeTakeoff(float altitude, float heading, const std::function<void()>& on_completed,
271 const std::function<void()>& on_failure = nullptr);
272 void runAction(const std::string& action_name, const ActionArguments& arguments,
273 const std::function<void()>& on_completed);
274 void runTrajectory(const std::shared_ptr<Mission>& trajectory, int start_index, int end_index,
275 const std::function<void(int)>& on_index_reached, bool stop_at_last_item);
276
277 void runNextMissionItem();
278 void runCurrentMissionItem(bool resuming);
279 void resetMissionState();
280 std::pair<int, bool> getNextTrajectorySegment(int start_index) const;
281 bool currentActionSupportsResumeFromLanded() const;
282
283 void setTrajectoryOptions(const TrajectoryOptions& options);
284 void clearTrajectoryOptions();
285
286 void setCurrentMissionIndex(int index);
287
288 void abort(AbortReason reason);
289 void invalidateActionHandler();
290
291 void savePersistentState();
292 void clearPersistentState() const;
293 bool tryLoadPersistentState();
294 nlohmann::json getOnResumeStateAndClear();
295 void runOnResumeStoreState();
296
297 struct ActionState {
298 std::string name;
299 ActionArguments arguments;
300 };
301 std::unique_ptr<ActionStateKeeper> addContinousAction(const ActionState& state);
302 void removeContinousAction(ActionID id);
303 void runStoredActions();
304 void deactivateAllActions();
305
306 struct PersistentState {
307 std::optional<int> current_index;
308 std::string mission_checksum;
309
310 std::map<ActionID, ActionState> continuous_actions;
311
312 void toJson(nlohmann::json& j) const;
313 void fromJson(const nlohmann::json& j);
314 };
315
316 PersistentState _state;
317 int _next_continuous_action_id{0};
318 const std::string _persistence_filename;
319
320 enum class MissionItemState {
321 Trajectory,
322 Other,
323 };
324 MissionItemState _mission_item_state{MissionItemState::Other};
325 ModeBase::ModeID _active_mode{};
326 bool _is_active{false};
327
328 std::optional<rclcpp::Time> _trajectory_update_warn;
329
330 std::shared_ptr<TrajectoryExecutorInterface> _trajectory_executor;
331 std::map<std::string, std::shared_ptr<ActionInterface>> _actions;
332 std::shared_ptr<Mission> _mission;
333 TrajectoryOptions _trajectory_options;
334 bool _has_valid_mission{false};
335 static const std::vector<std::string> kNoMissionErrors;
336 std::vector<std::string> _mission_errors{kNoMissionErrors};
337 bool _actions_ready{false};
338 rclcpp::TimerBase::SharedPtr _readyness_timer;
339 int _abort_recursion_level{
340 0};
341
342 rclcpp::Node& _node;
343 std::unique_ptr<MissionMode> _mode;
344 std::unique_ptr<MissionModeExecutor> _mode_executor;
345 std::shared_ptr<ActionHandler> _action_handler;
346
347 std::unique_ptr<AsyncFunctionCalls> _reporting; // Report asynchronously to avoid potential
348 // recursive calls and state changes in between
349 std::function<void()> _on_activated;
350 std::function<void()> _on_deactivated;
351 std::function<void(int)> _on_progress_update;
352 std::function<void()> _on_completed;
353 std::function<void(const std::optional<std::string>&)> _on_activity_info_change;
354 std::function<void(bool ready, const std::vector<std::string>& errors)> _on_readyness_update;
355
356 friend class ActionHandler;
357 friend class ActionStateKeeper;
358};
359
361 public:
362 ActionStateKeeper(int id, MissionExecutor& mission_executor)
363 : _id(id), _mission_executor(mission_executor)
364 {
365 }
366
367 ~ActionStateKeeper() { _mission_executor.removeContinousAction(_id); }
368
369 private:
370 const int _id;
371 MissionExecutor& _mission_executor;
372};
373
379 public:
380 explicit ActionHandler(MissionExecutor& mission_executor) : _mission_executor(mission_executor) {}
381
382 void runMode(ModeBase::ModeID mode_id, const std::function<void()>& on_completed,
383 const std::function<void()>& on_failure = nullptr)
384 {
385 if (!_valid) {
386 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
387 return;
388 }
389 _mission_executor.runMode(mode_id, on_completed, on_failure);
390 }
399 void runModeTakeoff(float altitude, float heading, const std::function<void()>& on_completed,
400 const std::function<void()>& on_failure = nullptr)
401 {
402 if (!_valid) {
403 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
404 return;
405 }
406 _mission_executor.runModeTakeoff(altitude, heading, on_completed, on_failure);
407 }
408 void runAction(const std::string& action_name, const ActionArguments& arguments,
409 const std::function<void()>& on_completed)
410 {
411 if (!_valid) {
412 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
413 return;
414 }
415 _mission_executor.runAction(action_name, arguments, on_completed);
416 }
417 void runTrajectory(const std::shared_ptr<Mission>& trajectory,
418 const std::function<void()>& on_completed, bool stop_at_last_item = true);
419
423 TrajectoryOptions getTrajectoryOptions() const { return _mission_executor._trajectory_options; }
428 {
429 if (!_valid) {
430 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
431 return;
432 }
433 _mission_executor.clearTrajectoryOptions();
434 }
441 {
442 if (!_valid) {
443 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
444 return;
445 }
446 _mission_executor.setTrajectoryOptions(options);
447 }
448
457 void setActvityInfo(const std::string& activity_info)
458 {
459 if (!_valid) {
460 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
461 return;
462 }
463 _mission_executor.setActivityInfo(activity_info);
464 }
465
472 {
473 if (!_valid) {
474 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
475 return;
476 }
477 _mission_executor.setActivityInfo(std::nullopt);
478 }
479
480 std::optional<int> getCurrentMissionIndex() const;
490 void setCurrentMissionIndex(int index);
491
492 bool currentActionSupportsResumeFromLanded() const;
493
508 std::unique_ptr<ActionStateKeeper> storeState(const std::string& action_name,
509 const ActionArguments& arguments)
510 {
511 if (!_valid) {
512 return nullptr;
513 }
514 return _mission_executor.addContinousAction(
515 MissionExecutor::ActionState{action_name, arguments});
516 }
517
518 const Mission& mission() const { return _mission_executor.mission(); }
519
527 bool deferFailsafes(bool enabled, int timeout_s = 0)
528 {
529 if (!_valid) {
530 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
531 return false;
532 }
533 return _mission_executor.deferFailsafes(enabled, timeout_s);
534 }
535
536 bool controlAutoSetHome(bool enabled)
537 {
538 if (!_valid) {
539 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
540 return false;
541 }
542 return _mission_executor.controlAutoSetHome(enabled);
543 }
544
550 void onFailsafeDeferred(const std::function<void()>& callback)
551 {
552 if (!_valid) {
553 RCLCPP_WARN(_mission_executor._node.get_logger(), "ActionHandler is not valid anymore");
554 return;
555 }
556 _mission_executor.onFailsafeDeferred(callback);
557 }
558
565 bool isValid() const { return _valid; }
566
567 private:
568 friend class MissionExecutor;
569 void setInvalid() { _valid = false; }
570
571 bool _valid{true};
572 MissionExecutor& _mission_executor;
573};
574
576} /* 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:378
void setTrajectoryOptions(const TrajectoryOptions &options)
Override the trajectory config options.
Definition mission_executor.hpp:440
TrajectoryOptions getTrajectoryOptions() const
get the current trajectory config options
Definition mission_executor.hpp:423
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:457
bool isValid() const
Check if the handler is still valid.
Definition mission_executor.hpp:565
void clearActivityInfo()
Clears the activity information. This method sets the activity info of the mission executor to std::n...
Definition mission_executor.hpp:471
bool deferFailsafes(bool enabled, int timeout_s=0)
enable/disable deferral of failsafes
Definition mission_executor.hpp:527
void clearTrajectoryOptions()
Reset the current trajectory config options to the mission defaults.
Definition mission_executor.hpp:427
void onFailsafeDeferred(const std::function< void()> &callback)
register callback for failsafe notification
Definition mission_executor.hpp:550
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:399
std::unique_ptr< ActionStateKeeper > storeState(const std::string &action_name, const ActionArguments &arguments)
store the state of a continuous action
Definition mission_executor.hpp:508
void setCurrentMissionIndex(int index)
Set the current mission index.
Definition mission_executor.hpp:360
Definition health_and_arming_checks.hpp:21
Definition mission_executor.hpp:179
void onActivate() override
Definition mission_executor.hpp:191
Result sendCommandSync(uint32_t command, float param1, float param2, float param3, float param4, float param5, float param6, float param7) override
Definition mission_executor.hpp:200
void onFailsafeDeferred() override
Definition mission_executor.hpp:193
void onDeactivate(DeactivateReason reason) override
Definition mission_executor.hpp:192
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:74
uint8_t ModeID
Mode ID, corresponds to nav_state.
Definition mode.hpp:76
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:30
@ Rejected
The request was rejected.
Definition mission_executor.hpp:30
Definition mode.hpp:90
Definition mode_executor.hpp:33
Definition mission.hpp:114