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/CommandLong.h>
22 #include <mavros_msgs/CommandInt.h>
23 #include <mavros_msgs/CommandBool.h>
24 #include <mavros_msgs/CommandHome.h>
25 #include <mavros_msgs/CommandTOL.h>
26 #include <mavros_msgs/CommandTriggerControl.h>
27 #include <mavros_msgs/CommandTriggerInterval.h>
28 
29 namespace mavros {
30 namespace std_plugins {
31 using utils::enum_value;
32 using lock_guard = std::lock_guard<std::mutex>;
33 using unique_lock = std::unique_lock<std::mutex>;
34 
36 public:
38  std::condition_variable ack;
39  uint16_t expected_command;
40  uint8_t result;
41 
42  explicit CommandTransaction(uint16_t command) :
43  ack(),
44  expected_command(command),
45  // Default result if wait ack timeout
46  result(enum_value(mavlink::common::MAV_RESULT::FAILED))
47  { }
48 };
49 
56 public:
57  CommandPlugin() : PluginBase(),
58  cmd_nh("~cmd"),
59  use_comp_id_system_control(false),
60  ACK_TIMEOUT_DT(ACK_TIMEOUT_MS / 1000.0)
61  { }
62 
63  void initialize(UAS &uas_)
64  {
65  PluginBase::initialize(uas_);
66 
67  cmd_nh.param("use_comp_id_system_control", use_comp_id_system_control, false);
68 
69  command_long_srv = cmd_nh.advertiseService("command", &CommandPlugin::command_long_cb, this);
70  command_int_srv = cmd_nh.advertiseService("command_int", &CommandPlugin::command_int_cb, this);
71  arming_srv = cmd_nh.advertiseService("arming", &CommandPlugin::arming_cb, this);
72  set_home_srv = cmd_nh.advertiseService("set_home", &CommandPlugin::set_home_cb, this);
73  takeoff_srv = cmd_nh.advertiseService("takeoff", &CommandPlugin::takeoff_cb, this);
74  land_srv = cmd_nh.advertiseService("land", &CommandPlugin::land_cb, this);
75  trigger_control_srv = cmd_nh.advertiseService("trigger_control", &CommandPlugin::trigger_control_cb, this);
76  trigger_interval_srv = cmd_nh.advertiseService("trigger_interval", &CommandPlugin::trigger_interval_cb, this);
77  }
78 
80  {
81  return {
83  };
84  }
85 
86 private:
87  using L_CommandTransaction = std::list<CommandTransaction>;
88 
90 
100 
102 
104  static constexpr int ACK_TIMEOUT_MS = 5000;
105 
107 
108  /* -*- message handlers -*- */
109 
110  void handle_command_ack(const mavlink::mavlink_message_t *msg, mavlink::common::msg::COMMAND_ACK &ack)
111  {
112  lock_guard lock(mutex);
113 
114  // XXX(vooon): place here source ids check
115 
116  for (auto &tr : ack_waiting_list) {
117  if (tr.expected_command == ack.command) {
118  tr.result = ack.result;
119  tr.ack.notify_all();
120  return;
121  }
122  }
123 
124  ROS_WARN_THROTTLE_NAMED(10, "cmd", "CMD: Unexpected command %u, result %u",
125  ack.command, ack.result);
126  }
127 
128  /* -*- mid-level functions -*- */
129 
131  unique_lock lock(tr.cond_mutex);
132  if (tr.ack.wait_for(lock, std::chrono::nanoseconds(ACK_TIMEOUT_DT.toNSec())) == std::cv_status::timeout) {
133  ROS_WARN_NAMED("cmd", "CMD: Command %u -- wait ack timeout", tr.expected_command);
134  return false;
135  } else {
136  return true;
137  }
138  }
139 
145  bool send_command_long_and_wait(bool broadcast,
146  uint16_t command, uint8_t confirmation,
147  float param1, float param2,
148  float param3, float param4,
149  float param5, float param6,
150  float param7,
151  unsigned char &success, uint8_t &result)
152  {
153  using mavlink::common::MAV_RESULT;
154 
155  unique_lock lock(mutex);
156 
157  L_CommandTransaction::iterator ack_it;
158 
159  /* check transactions */
160  for (const auto &tr : ack_waiting_list) {
161  if (tr.expected_command == command) {
162  ROS_WARN_THROTTLE_NAMED(10, "cmd", "CMD: Command %u already in progress", command);
163  return false;
164  }
165  }
166 
171  bool is_ack_required = (confirmation != 0 || m_uas->is_ardupilotmega() || m_uas->is_px4()) && !broadcast;
172  if (is_ack_required)
173  ack_it = ack_waiting_list.emplace(ack_waiting_list.end(), command);
174 
175  command_long(broadcast,
176  command, confirmation,
177  param1, param2,
178  param3, param4,
179  param5, param6,
180  param7);
181 
182  if (is_ack_required) {
183  lock.unlock();
184  bool is_not_timeout = wait_ack_for(*ack_it);
185  lock.lock();
186 
187  success = is_not_timeout && ack_it->result == enum_value(MAV_RESULT::ACCEPTED);
188  result = ack_it->result;
189 
190  ack_waiting_list.erase(ack_it);
191  }
192  else {
193  success = true;
194  result = enum_value(MAV_RESULT::ACCEPTED);
195  }
196 
197  return true;
198  }
199 
203  bool send_command_int(bool broadcast,
204  uint8_t frame, uint16_t command,
205  uint8_t current, uint8_t autocontinue,
206  float param1, float param2,
207  float param3, float param4,
208  int32_t x, int32_t y,
209  float z,
210  unsigned char &success)
211  {
212  /* Note: seems that COMMAND_INT don't produce COMMAND_ACK
213  * so wait don't needed.
214  */
215  command_int(broadcast,
216  frame, command, current, autocontinue,
217  param1, param2,
218  param3, param4,
219  x, y, z);
220 
221  success = true;
222  return true;
223  }
224 
225  /* -*- low-level send -*- */
226 
227  template<typename MsgT>
228  inline void set_target(MsgT &cmd, bool broadcast)
229  {
230  using mavlink::common::MAV_COMPONENT;
231 
232  const uint8_t tgt_sys_id = (broadcast) ? 0 : m_uas->get_tgt_system();
233  const uint8_t tgt_comp_id = (broadcast) ? 0 :
234  (use_comp_id_system_control) ?
235  enum_value(MAV_COMPONENT::COMP_ID_SYSTEM_CONTROL) : m_uas->get_tgt_component();
236 
237  cmd.target_system = tgt_sys_id;
238  cmd.target_component = tgt_comp_id;
239  }
240 
241  void command_long(bool broadcast,
242  uint16_t command, uint8_t confirmation,
243  float param1, float param2,
244  float param3, float param4,
245  float param5, float param6,
246  float param7)
247  {
248  const uint8_t confirmation_fixed = (broadcast) ? 0 : confirmation;
249 
250  mavlink::common::msg::COMMAND_LONG cmd {};
251  set_target(cmd, broadcast);
252 
253  cmd.command = command;
254  cmd.confirmation = confirmation_fixed;
255  cmd.param1 = param1;
256  cmd.param2 = param2;
257  cmd.param3 = param3;
258  cmd.param4 = param4;
259  cmd.param5 = param5;
260  cmd.param6 = param6;
261  cmd.param7 = param7;
262 
263  UAS_FCU(m_uas)->send_message_ignore_drop(cmd);
264  }
265 
266  void command_int(bool broadcast,
267  uint8_t frame, uint16_t command,
268  uint8_t current, uint8_t autocontinue,
269  float param1, float param2,
270  float param3, float param4,
271  int32_t x, int32_t y,
272  float z)
273  {
274  mavlink::common::msg::COMMAND_INT cmd {};
275  set_target(cmd, broadcast);
276 
277  cmd.frame = frame;
278  cmd.command = command;
279  cmd.current = current;
280  cmd.autocontinue = autocontinue;
281  cmd.param1 = param1;
282  cmd.param2 = param2;
283  cmd.param3 = param3;
284  cmd.param4 = param4;
285  cmd.x = x;
286  cmd.y = y;
287  cmd.z = z;
288 
289  UAS_FCU(m_uas)->send_message_ignore_drop(cmd);
290  }
291 
292  /* -*- callbacks -*- */
293 
294  bool command_long_cb(mavros_msgs::CommandLong::Request &req,
295  mavros_msgs::CommandLong::Response &res)
296  {
297  return send_command_long_and_wait(req.broadcast,
298  req.command, req.confirmation,
299  req.param1, req.param2,
300  req.param3, req.param4,
301  req.param5, req.param6,
302  req.param7,
303  res.success, res.result);
304  }
305 
306  bool command_int_cb(mavros_msgs::CommandInt::Request &req,
307  mavros_msgs::CommandInt::Response &res)
308  {
309  return send_command_int(req.broadcast,
310  req.frame, req.command,
311  req.current, req.autocontinue,
312  req.param1, req.param2,
313  req.param3, req.param4,
314  req.x, req.y, req.z,
315  res.success);
316  }
317 
318  bool arming_cb(mavros_msgs::CommandBool::Request &req,
319  mavros_msgs::CommandBool::Response &res)
320  {
321  using mavlink::common::MAV_CMD;
322  return send_command_long_and_wait(false,
323  enum_value(MAV_CMD::COMPONENT_ARM_DISARM), 1,
324  (req.value) ? 1.0 : 0.0,
325  0, 0, 0, 0, 0, 0,
326  res.success, res.result);
327  }
328 
329  bool set_home_cb(mavros_msgs::CommandHome::Request &req,
330  mavros_msgs::CommandHome::Response &res)
331  {
332  using mavlink::common::MAV_CMD;
333  return send_command_long_and_wait(false,
334  enum_value(MAV_CMD::DO_SET_HOME), 1,
335  (req.current_gps) ? 1.0 : 0.0,
336  0, 0, 0, req.latitude, req.longitude, req.altitude,
337  res.success, res.result);
338  }
339 
340  bool takeoff_cb(mavros_msgs::CommandTOL::Request &req,
341  mavros_msgs::CommandTOL::Response &res)
342  {
343  using mavlink::common::MAV_CMD;
344  return send_command_long_and_wait(false,
345  enum_value(MAV_CMD::NAV_TAKEOFF), 1,
346  req.min_pitch,
347  0, 0,
348  req.yaw,
349  req.latitude, req.longitude, req.altitude,
350  res.success, res.result);
351  }
352 
353  bool land_cb(mavros_msgs::CommandTOL::Request &req,
354  mavros_msgs::CommandTOL::Response &res)
355  {
356  using mavlink::common::MAV_CMD;
357  return send_command_long_and_wait(false,
358  enum_value(MAV_CMD::NAV_LAND), 1,
359  0, 0, 0,
360  req.yaw,
361  req.latitude, req.longitude, req.altitude,
362  res.success, res.result);
363  }
364 
365  bool trigger_control_cb(mavros_msgs::CommandTriggerControl::Request &req,
366  mavros_msgs::CommandTriggerControl::Response &res)
367  {
368  using mavlink::common::MAV_CMD;
369  return send_command_long_and_wait(false,
370  enum_value(MAV_CMD::DO_TRIGGER_CONTROL), 1,
371  (req.trigger_enable)? 1.0 : 0.0,
372  (req.sequence_reset)? 1.0 : 0.0,
373  (req.trigger_pause)? 1.0: 0.0,
374  0, 0, 0, 0,
375  res.success, res.result);
376  }
377 
378  bool trigger_interval_cb(mavros_msgs::CommandTriggerInterval::Request &req,
379  mavros_msgs::CommandTriggerInterval::Response &res)
380  {
381  using mavlink::common::MAV_CMD;
382 
383  // trigger interval can only be set when triggering is disabled
384  return send_command_long_and_wait(false,
385  enum_value(MAV_CMD::DO_SET_CAM_TRIGG_INTERVAL), 1,
386  req.cycle_time,
387  req.integration_time,
388  0, 0, 0, 0, 0,
389  res.success, res.result);
390  }
391 };
392 } // namespace std_plugins
393 } // namespace mavros
394 
MAVROS Plugin base class.
Definition: mavros_plugin.h:37
#define ROS_WARN_THROTTLE_NAMED(period, name,...)
#define ROS_WARN_NAMED(name,...)
void set_target(MsgT &cmd, bool broadcast)
Definition: command.cpp:228
MAVROS Plugin base.
string cmd
ros::ServiceServer trigger_interval_srv
Definition: command.cpp:99
ros::ServiceServer arming_srv
Definition: command.cpp:94
std::lock_guard< std::mutex > lock_guard
Definition: command.cpp:32
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:241
bool trigger_control_cb(mavros_msgs::CommandTriggerControl::Request &req, mavros_msgs::CommandTriggerControl::Response &res)
Definition: command.cpp:365
void initialize(UAS &uas_)
Plugin initializer.
Definition: command.cpp:63
std::list< CommandTransaction > L_CommandTransaction
Definition: command.cpp:87
const ros::Duration ACK_TIMEOUT_DT
Definition: command.cpp:106
bool command_long_cb(mavros_msgs::CommandLong::Request &req, mavros_msgs::CommandLong::Response &res)
Definition: command.cpp:294
ros::ServiceServer command_long_srv
Definition: command.cpp:92
void handle_command_ack(const mavlink::mavlink_message_t *msg, mavlink::common::msg::COMMAND_ACK &ack)
Definition: command.cpp:110
ros::ServiceServer trigger_control_srv
Definition: command.cpp:98
UAS for plugins.
Definition: mavros_uas.h:66
int64_t toNSec() const
bool arming_cb(mavros_msgs::CommandBool::Request &req, mavros_msgs::CommandBool::Response &res)
Definition: command.cpp:318
#define UAS_FCU(uasobjptr)
helper accessor to FCU link interface
Definition: mavros_uas.h:41
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:145
bool trigger_interval_cb(mavros_msgs::CommandTriggerInterval::Request &req, mavros_msgs::CommandTriggerInterval::Response &res)
Definition: command.cpp:378
bool set_home_cb(mavros_msgs::CommandHome::Request &req, mavros_msgs::CommandHome::Response &res)
Definition: command.cpp:329
bool takeoff_cb(mavros_msgs::CommandTOL::Request &req, mavros_msgs::CommandTOL::Response &res)
Definition: command.cpp:340
std::vector< HandlerInfo > Subscriptions
Subscriptions vector.
Definition: mavros_plugin.h:48
std::condition_variable ack
Definition: command.cpp:38
Subscriptions get_subscriptions()
Return vector of MAVLink message subscriptions (handlers)
Definition: command.cpp:79
L_CommandTransaction ack_waiting_list
Definition: command.cpp:103
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:203
bool command_int_cb(mavros_msgs::CommandInt::Request &req, mavros_msgs::CommandInt::Response &res)
Definition: command.cpp:306
ros::ServiceServer command_int_srv
Definition: command.cpp:93
std::unique_lock< std::mutex > unique_lock
Definition: command.cpp:33
bool land_cb(mavros_msgs::CommandTOL::Request &req, mavros_msgs::CommandTOL::Response &res)
Definition: command.cpp:353
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
ros::ServiceServer takeoff_srv
Definition: command.cpp:96
bool wait_ack_for(CommandTransaction &tr)
Definition: command.cpp:130
ros::ServiceServer land_srv
Definition: command.cpp:97
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:266
ros::ServiceServer set_home_srv
Definition: command.cpp:95
constexpr std::underlying_type< _T >::type enum_value(_T e)
Definition: utils.h:55
std::recursive_mutex mutex


mavros
Author(s): Vladimir Ermakov
autogenerated on Mon Jul 8 2019 03:20:10