command.cpp
Go to the documentation of this file.
1 
9 /*
10  * Copyright 2014,2016 Vladimir Ermakov.
11  *
12  * This file is part of the mavros package and subject to the license terms
13  * in the top-level LICENSE file of the mavros repository.
14  * https://github.com/mavlink/mavros/tree/master/LICENSE.md
15  */
16 
17 #include <chrono>
18 #include <condition_variable>
19 #include <mavros/mavros_plugin.h>
20 
21 #include <mavros_msgs/CommandAck.h>
22 #include <mavros_msgs/CommandLong.h>
23 #include <mavros_msgs/CommandInt.h>
24 #include <mavros_msgs/CommandBool.h>
25 #include <mavros_msgs/CommandHome.h>
26 #include <mavros_msgs/CommandTOL.h>
27 #include <mavros_msgs/CommandTriggerControl.h>
28 #include <mavros_msgs/CommandTriggerInterval.h>
29 #include <mavros_msgs/CommandVtolTransition.h>
30 
31 namespace mavros {
32 namespace std_plugins {
33 static constexpr double ACK_TIMEOUT_DEFAULT = 5.0;
34 using utils::enum_value;
35 using lock_guard = std::lock_guard<std::mutex>;
36 using unique_lock = std::unique_lock<std::mutex>;
37 
39 public:
41  std::condition_variable ack;
42  uint16_t expected_command;
43  uint8_t result;
44 
45  explicit CommandTransaction(uint16_t command) :
46  ack(),
47  expected_command(command),
48  // Default result if wait ack timeout
49  result(enum_value(mavlink::common::MAV_RESULT::FAILED))
50  { }
51 };
52 
59 public:
60  CommandPlugin() : PluginBase(),
61  cmd_nh("~cmd"),
62  use_comp_id_system_control(false)
63  { }
64 
65  void initialize(UAS &uas_) override
66  {
67  PluginBase::initialize(uas_);
68 
69  double command_ack_timeout;
70 
71  cmd_nh.param("command_ack_timeout", command_ack_timeout, ACK_TIMEOUT_DEFAULT);
72  cmd_nh.param("use_comp_id_system_control", use_comp_id_system_control, false);
73 
74  command_ack_timeout_dt = ros::Duration(command_ack_timeout);
75 
76  command_long_srv = cmd_nh.advertiseService("command", &CommandPlugin::command_long_cb, this);
77  command_ack_srv = cmd_nh.advertiseService("command_ack", &CommandPlugin::command_ack_cb, this);
78  command_int_srv = cmd_nh.advertiseService("command_int", &CommandPlugin::command_int_cb, this);
79  arming_srv = cmd_nh.advertiseService("arming", &CommandPlugin::arming_cb, this);
80  set_home_srv = cmd_nh.advertiseService("set_home", &CommandPlugin::set_home_cb, this);
81  takeoff_srv = cmd_nh.advertiseService("takeoff", &CommandPlugin::takeoff_cb, this);
82  land_srv = cmd_nh.advertiseService("land", &CommandPlugin::land_cb, this);
83  trigger_control_srv = cmd_nh.advertiseService("trigger_control", &CommandPlugin::trigger_control_cb, this);
84  trigger_interval_srv = cmd_nh.advertiseService("trigger_interval", &CommandPlugin::trigger_interval_cb, this);
85  vtol_transition_srv = cmd_nh.advertiseService("vtol_transition", &CommandPlugin::vtol_transition_cb, this);
86  }
87 
89  {
90  return {
92  };
93  }
94 
95 private:
96  using L_CommandTransaction = std::list<CommandTransaction>;
97 
99 
111 
113 
116 
117  /* -*- message handlers -*- */
118 
119  void handle_command_ack(const mavlink::mavlink_message_t *msg, mavlink::common::msg::COMMAND_ACK &ack)
120  {
121  lock_guard lock(mutex);
122 
123  // XXX(vooon): place here source ids check
124 
125  for (auto &tr : ack_waiting_list) {
126  if (tr.expected_command == ack.command) {
127  tr.result = ack.result;
128  tr.ack.notify_all();
129  return;
130  }
131  }
132 
133  ROS_WARN_THROTTLE_NAMED(10, "cmd", "CMD: Unexpected command %u, result %u",
134  ack.command, ack.result);
135  }
136 
137  /* -*- mid-level functions -*- */
138 
140  unique_lock lock(tr.cond_mutex);
141  if (tr.ack.wait_for(lock, std::chrono::nanoseconds(command_ack_timeout_dt.toNSec())) == std::cv_status::timeout) {
142  ROS_WARN_NAMED("cmd", "CMD: Command %u -- wait ack timeout", tr.expected_command);
143  return false;
144  } else {
145  return true;
146  }
147  }
148 
154  bool send_command_long_and_wait(bool broadcast,
155  uint16_t command, uint8_t confirmation,
156  float param1, float param2,
157  float param3, float param4,
158  float param5, float param6,
159  float param7,
160  unsigned char &success, uint8_t &result)
161  {
162  using mavlink::common::MAV_RESULT;
163 
164  unique_lock lock(mutex);
165 
166  L_CommandTransaction::iterator ack_it;
167 
168  /* check transactions */
169  for (const auto &tr : ack_waiting_list) {
170  if (tr.expected_command == command) {
171  ROS_WARN_THROTTLE_NAMED(10, "cmd", "CMD: Command %u already in progress", command);
172  return false;
173  }
174  }
175 
180  bool is_ack_required = (confirmation != 0 || m_uas->is_ardupilotmega() || m_uas->is_px4()) && !broadcast;
181  if (is_ack_required)
182  ack_it = ack_waiting_list.emplace(ack_waiting_list.end(), command);
183 
184  command_long(broadcast,
185  command, confirmation,
186  param1, param2,
187  param3, param4,
188  param5, param6,
189  param7);
190 
191  if (is_ack_required) {
192  lock.unlock();
193  bool is_not_timeout = wait_ack_for(*ack_it);
194  lock.lock();
195 
196  success = is_not_timeout && ack_it->result == enum_value(MAV_RESULT::ACCEPTED);
197  result = ack_it->result;
198 
199  ack_waiting_list.erase(ack_it);
200  }
201  else {
202  success = true;
203  result = enum_value(MAV_RESULT::ACCEPTED);
204  }
205 
206  return true;
207  }
208 
212  bool send_command_int(bool broadcast,
213  uint8_t frame, uint16_t command,
214  uint8_t current, uint8_t autocontinue,
215  float param1, float param2,
216  float param3, float param4,
217  int32_t x, int32_t y,
218  float z,
219  unsigned char &success)
220  {
221  /* Note: seems that COMMAND_INT don't produce COMMAND_ACK
222  * so wait don't needed.
223  */
224  command_int(broadcast,
225  frame, command, current, autocontinue,
226  param1, param2,
227  param3, param4,
228  x, y, z);
229 
230  success = true;
231  return true;
232  }
233 
234  bool send_command_ack( uint16_t command, uint8_t req_result, uint8_t progress, int32_t result_param2,
235  unsigned char &success, uint8_t &res_result)
236  {
237  using mavlink::common::MAV_RESULT;
238 
239  command_ack(command,
240  req_result, progress,
241  result_param2);
242 
243 
244  success = true;
245  res_result = enum_value(MAV_RESULT::ACCEPTED);
246 
247  return true;
248  }
249 
250 
251  /* -*- low-level send -*- */
252 
253  template<typename MsgT>
254  inline void set_target(MsgT &cmd, bool broadcast)
255  {
256  using mavlink::minimal::MAV_COMPONENT;
257 
258  const uint8_t tgt_sys_id = (broadcast) ? 0 : m_uas->get_tgt_system();
259  const uint8_t tgt_comp_id = (broadcast) ? 0 :
260  (use_comp_id_system_control) ?
261  enum_value(MAV_COMPONENT::COMP_ID_SYSTEM_CONTROL) : m_uas->get_tgt_component();
262 
263  cmd.target_system = tgt_sys_id;
264  cmd.target_component = tgt_comp_id;
265  }
266 
267  void command_long(bool broadcast,
268  uint16_t command, uint8_t confirmation,
269  float param1, float param2,
270  float param3, float param4,
271  float param5, float param6,
272  float param7)
273  {
274  const uint8_t confirmation_fixed = (broadcast) ? 0 : confirmation;
275 
276  mavlink::common::msg::COMMAND_LONG cmd {};
277  set_target(cmd, broadcast);
278 
279  cmd.command = command;
280  cmd.confirmation = confirmation_fixed;
281  cmd.param1 = param1;
282  cmd.param2 = param2;
283  cmd.param3 = param3;
284  cmd.param4 = param4;
285  cmd.param5 = param5;
286  cmd.param6 = param6;
287  cmd.param7 = param7;
288 
289  UAS_FCU(m_uas)->send_message_ignore_drop(cmd);
290  }
291 
292  void command_int(bool broadcast,
293  uint8_t frame, uint16_t command,
294  uint8_t current, uint8_t autocontinue,
295  float param1, float param2,
296  float param3, float param4,
297  int32_t x, int32_t y,
298  float z)
299  {
300  mavlink::common::msg::COMMAND_INT cmd {};
301  set_target(cmd, broadcast);
302 
303  cmd.frame = frame;
304  cmd.command = command;
305  cmd.current = current;
306  cmd.autocontinue = autocontinue;
307  cmd.param1 = param1;
308  cmd.param2 = param2;
309  cmd.param3 = param3;
310  cmd.param4 = param4;
311  cmd.x = x;
312  cmd.y = y;
313  cmd.z = z;
314 
315  UAS_FCU(m_uas)->send_message_ignore_drop(cmd);
316  }
317 
318  void command_ack( uint16_t command, uint8_t result,
319  uint8_t progress, int32_t result_param2)
320  {
321  mavlink::common::msg::COMMAND_ACK cmd {};
322  set_target(cmd, false);
323 
324  cmd.command = command;
325  cmd.result = result;
326  cmd.progress = progress;
327  cmd.result_param2 = result_param2;
328 
329  UAS_FCU(m_uas)->send_message_ignore_drop(cmd);
330  }
331 
332 
333  /* -*- callbacks -*- */
334 
335  bool command_long_cb(mavros_msgs::CommandLong::Request &req,
336  mavros_msgs::CommandLong::Response &res)
337  {
338  return send_command_long_and_wait(req.broadcast,
339  req.command, req.confirmation,
340  req.param1, req.param2,
341  req.param3, req.param4,
342  req.param5, req.param6,
343  req.param7,
344  res.success, res.result);
345  }
346 
347  bool command_int_cb(mavros_msgs::CommandInt::Request &req,
348  mavros_msgs::CommandInt::Response &res)
349  {
350  return send_command_int(req.broadcast,
351  req.frame, req.command,
352  req.current, req.autocontinue,
353  req.param1, req.param2,
354  req.param3, req.param4,
355  req.x, req.y, req.z,
356  res.success);
357  }
358 
359  bool command_ack_cb(mavros_msgs::CommandAck::Request &req,
360  mavros_msgs::CommandAck::Response &res)
361  {
362  return send_command_ack(req.command, req.result,
363  req.progress, req.result_param2,
364  res.success, res.result);
365  }
366 
367 
368  bool arming_cb(mavros_msgs::CommandBool::Request &req,
369  mavros_msgs::CommandBool::Response &res)
370  {
371  using mavlink::common::MAV_CMD;
372  return send_command_long_and_wait(false,
373  enum_value(MAV_CMD::COMPONENT_ARM_DISARM), 1,
374  (req.value) ? 1.0 : 0.0,
375  0, 0, 0, 0, 0, 0,
376  res.success, res.result);
377  }
378 
379  bool set_home_cb(mavros_msgs::CommandHome::Request &req,
380  mavros_msgs::CommandHome::Response &res)
381  {
382  using mavlink::common::MAV_CMD;
383  return send_command_long_and_wait(false,
384  enum_value(MAV_CMD::DO_SET_HOME), 1,
385  (req.current_gps) ? 1.0 : 0.0,
386  0, 0, req.yaw, req.latitude, req.longitude, req.altitude,
387  res.success, res.result);
388  }
389 
390  bool takeoff_cb(mavros_msgs::CommandTOL::Request &req,
391  mavros_msgs::CommandTOL::Response &res)
392  {
393  using mavlink::common::MAV_CMD;
394  return send_command_long_and_wait(false,
395  enum_value(MAV_CMD::NAV_TAKEOFF), 1,
396  req.min_pitch,
397  0, 0,
398  req.yaw,
399  req.latitude, req.longitude, req.altitude,
400  res.success, res.result);
401  }
402 
403  bool land_cb(mavros_msgs::CommandTOL::Request &req,
404  mavros_msgs::CommandTOL::Response &res)
405  {
406  using mavlink::common::MAV_CMD;
407  return send_command_long_and_wait(false,
408  enum_value(MAV_CMD::NAV_LAND), 1,
409  0, 0, 0,
410  req.yaw,
411  req.latitude, req.longitude, req.altitude,
412  res.success, res.result);
413  }
414 
415  bool trigger_control_cb(mavros_msgs::CommandTriggerControl::Request &req,
416  mavros_msgs::CommandTriggerControl::Response &res)
417  {
418  using mavlink::common::MAV_CMD;
419  return send_command_long_and_wait(false,
420  enum_value(MAV_CMD::DO_TRIGGER_CONTROL), 1,
421  (req.trigger_enable) ? 1.0 : 0.0,
422  (req.sequence_reset) ? 1.0 : 0.0,
423  (req.trigger_pause) ? 1.0 : 0.0,
424  0, 0, 0, 0,
425  res.success, res.result);
426  }
427 
428  bool trigger_interval_cb(mavros_msgs::CommandTriggerInterval::Request &req,
429  mavros_msgs::CommandTriggerInterval::Response &res)
430  {
431  using mavlink::common::MAV_CMD;
432 
433  // trigger interval can only be set when triggering is disabled
434  return send_command_long_and_wait(false,
435  enum_value(MAV_CMD::DO_SET_CAM_TRIGG_INTERVAL), 1,
436  req.cycle_time,
437  req.integration_time,
438  0, 0, 0, 0, 0,
439  res.success, res.result);
440  }
441 
442  bool vtol_transition_cb(mavros_msgs::CommandVtolTransition::Request &req,
443  mavros_msgs::CommandVtolTransition::Response &res)
444  {
445  using mavlink::common::MAV_CMD;
446  return send_command_long_and_wait(false,
447  enum_value(MAV_CMD::DO_VTOL_TRANSITION), false,
448  req.state,
449  0, 0, 0, 0, 0, 0,
450  res.success, res.result);
451  }
452 };
453 } // namespace std_plugins
454 } // namespace mavros
455 
MAVROS Plugin base class.
Definition: mavros_plugin.h:36
#define ROS_WARN_THROTTLE_NAMED(period, name,...)
#define ROS_WARN_NAMED(name,...)
void set_target(MsgT &cmd, bool broadcast)
Definition: command.cpp:254
void initialize(UAS &uas_) override
Plugin initializer.
Definition: command.cpp:65
MAVROS Plugin base.
string cmd
ros::ServiceServer trigger_interval_srv
Definition: command.cpp:109
bool send_command_ack(uint16_t command, uint8_t req_result, uint8_t progress, int32_t result_param2, unsigned char &success, uint8_t &res_result)
Definition: command.cpp:234
ros::ServiceServer arming_srv
Definition: command.cpp:104
bool command_ack_cb(mavros_msgs::CommandAck::Request &req, mavros_msgs::CommandAck::Response &res)
Definition: command.cpp:359
static constexpr double ACK_TIMEOUT_DEFAULT
Definition: command.cpp:33
std::lock_guard< std::mutex > lock_guard
Definition: command.cpp:35
ros::ServiceServer command_ack_srv
Definition: command.cpp:103
void command_long(bool broadcast, uint16_t command, uint8_t confirmation, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
Definition: command.cpp:267
bool trigger_control_cb(mavros_msgs::CommandTriggerControl::Request &req, mavros_msgs::CommandTriggerControl::Response &res)
Definition: command.cpp:415
std::list< CommandTransaction > L_CommandTransaction
Definition: command.cpp:96
bool command_long_cb(mavros_msgs::CommandLong::Request &req, mavros_msgs::CommandLong::Response &res)
Definition: command.cpp:335
ros::ServiceServer command_long_srv
Definition: command.cpp:101
ros::ServiceServer vtol_transition_srv
Definition: command.cpp:110
void handle_command_ack(const mavlink::mavlink_message_t *msg, mavlink::common::msg::COMMAND_ACK &ack)
Definition: command.cpp:119
ros::ServiceServer trigger_control_srv
Definition: command.cpp:108
UAS for plugins.
Definition: mavros_uas.h:67
bool arming_cb(mavros_msgs::CommandBool::Request &req, mavros_msgs::CommandBool::Response &res)
Definition: command.cpp:368
#define UAS_FCU(uasobjptr)
helper accessor to FCU link interface
Definition: mavros_uas.h:42
Subscriptions get_subscriptions() override
Return vector of MAVLink message subscriptions (handlers)
Definition: command.cpp:88
bool vtol_transition_cb(mavros_msgs::CommandVtolTransition::Request &req, mavros_msgs::CommandVtolTransition::Response &res)
Definition: command.cpp:442
bool send_command_long_and_wait(bool broadcast, uint16_t command, uint8_t confirmation, float param1, float param2, float param3, float param4, float param5, float param6, float param7, unsigned char &success, uint8_t &result)
Definition: command.cpp:154
bool trigger_interval_cb(mavros_msgs::CommandTriggerInterval::Request &req, mavros_msgs::CommandTriggerInterval::Response &res)
Definition: command.cpp:428
bool set_home_cb(mavros_msgs::CommandHome::Request &req, mavros_msgs::CommandHome::Response &res)
Definition: command.cpp:379
bool takeoff_cb(mavros_msgs::CommandTOL::Request &req, mavros_msgs::CommandTOL::Response &res)
Definition: command.cpp:390
std::vector< HandlerInfo > Subscriptions
Subscriptions vector.
Definition: mavros_plugin.h:47
std::condition_variable ack
Definition: command.cpp:41
int64_t toNSec() const
L_CommandTransaction ack_waiting_list
Definition: command.cpp:114
bool send_command_int(bool broadcast, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z, unsigned char &success)
Definition: command.cpp:212
bool command_int_cb(mavros_msgs::CommandInt::Request &req, mavros_msgs::CommandInt::Response &res)
Definition: command.cpp:347
ros::ServiceServer command_int_srv
Definition: command.cpp:102
std::unique_lock< std::mutex > unique_lock
Definition: command.cpp:36
bool land_cb(mavros_msgs::CommandTOL::Request &req, mavros_msgs::CommandTOL::Response &res)
Definition: command.cpp:403
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
ros::ServiceServer takeoff_srv
Definition: command.cpp:106
bool wait_ack_for(CommandTransaction &tr)
Definition: command.cpp:139
void command_int(bool broadcast, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z)
Definition: command.cpp:292
ros::ServiceServer set_home_srv
Definition: command.cpp:105
constexpr std::underlying_type< _T >::type enum_value(_T e)
Definition: utils.h:55
std::recursive_mutex mutex
void command_ack(uint16_t command, uint8_t result, uint8_t progress, int32_t result_param2)
Definition: command.cpp:318


mavros
Author(s): Vladimir Ermakov
autogenerated on Tue Jun 13 2023 02:17:50