waypoint.cpp
Go to the documentation of this file.
1 
9 /*
10  * Copyright 2014,2015,2016,2017,2018 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/WaypointList.h>
22 #include <mavros_msgs/WaypointSetCurrent.h>
23 #include <mavros_msgs/WaypointClear.h>
24 #include <mavros_msgs/WaypointPull.h>
25 #include <mavros_msgs/WaypointPush.h>
26 #include <mavros_msgs/WaypointReached.h>
27 
28 
29 namespace mavros {
30 namespace std_plugins {
31 using utils::enum_value;
32 using mavlink::common::MAV_CMD;
33 using mavlink::common::MAV_FRAME;
34 using MRES = mavlink::common::MAV_MISSION_RESULT;
35 
36 
37 class WaypointItem : public mavlink::common::msg::MISSION_ITEM {
38 public:
39  double x_lat;
40  double y_long;
41  double z_alt;
42 
43  mavros_msgs::Waypoint to_msg()
44  {
45  mavros_msgs::Waypoint ret;
46 
47  // [[[cog:
48  // waypoint_item_msg = [(v, v) if isinstance(v, str) else v for v in (
49  // 'frame',
50  // 'command',
51  // ('is_current', 'current'),
52  // 'autocontinue',
53  // 'param1',
54  // 'param2',
55  // 'param3',
56  // 'param4',
57  // 'x_lat',
58  // 'y_long',
59  // 'z_alt',
60  // )]
61  // for a, b in waypoint_item_msg:
62  // cog.outl("ret.%s = %s;" % (a, b))
63  // ]]]
64  ret.frame = frame;
65  ret.command = command;
66  ret.is_current = current;
67  ret.autocontinue = autocontinue;
68  ret.param1 = param1;
69  ret.param2 = param2;
70  ret.param3 = param3;
71  ret.param4 = param4;
72  ret.x_lat = x_lat;
73  ret.y_long = y_long;
74  ret.z_alt = z_alt;
75  // [[[end]]] (checksum: 371710cb8984352c8cc1b93eb8b04a2b)
76 
77  return ret;
78  }
79 
80  static WaypointItem from_msg(mavros_msgs::Waypoint &wp, uint16_t seq)
81  {
82  WaypointItem ret{};
83 
84  // [[[cog:
85  // waypoint_coords = [
86  // ('x_lat', 'x'),
87  // ('y_long', 'y'),
88  // ('z_alt', 'z'),
89  // ]
90  // for a, b in waypoint_item_msg + waypoint_coords:
91  // cog.outl("ret.%s = wp.%s;" % (b, a))
92  // ]]]
93  ret.frame = wp.frame;
94  ret.command = wp.command;
95  ret.current = wp.is_current;
96  ret.autocontinue = wp.autocontinue;
97  ret.param1 = wp.param1;
98  ret.param2 = wp.param2;
99  ret.param3 = wp.param3;
100  ret.param4 = wp.param4;
101  ret.x_lat = wp.x_lat;
102  ret.y_long = wp.y_long;
103  ret.z_alt = wp.z_alt;
104  ret.x = wp.x_lat;
105  ret.y = wp.y_long;
106  ret.z = wp.z_alt;
107  // [[[end]]] (checksum: e277c889ab7a67085562bbd014283a78)
108 
109  ret.seq = seq;
110  ret.mission_type = enum_value(mavlink::common::MAV_MISSION_TYPE::MISSION);
111 
112  return ret;
113  }
114 
115  std::string to_string()
116  {
117  //return to_yaml();
118 
119  return utils::format("#%u%1s F:%u C:%3u p: %f %f %f %f x: %f y: %f z: %f",
120  seq,
121  (current) ? "*" : "",
122  frame, command,
123  param1, param2, param3, param4,
124  x_lat, y_long, z_alt);
125  }
126 };
127 
128 
133 public:
134  WaypointPlugin() : PluginBase(),
135  wp_nh("~mission"),
136  wp_state(WP::IDLE),
137  wp_count(0),
138  wp_retries(RETRIES_COUNT),
139  wp_cur_id(0),
140  wp_cur_active(0),
141  wp_set_active(0),
142  is_timedout(false),
143  do_pull_after_gcs(false),
144  enable_partial_push(false),
145  reschedule_pull(false),
146  BOOTUP_TIME_DT(BOOTUP_TIME_MS / 1000.0),
147  LIST_TIMEOUT_DT(LIST_TIMEOUT_MS / 1000.0),
148  WP_TIMEOUT_DT(WP_TIMEOUT_MS / 1000.0),
149  RESCHEDULE_DT(RESCHEDULE_MS / 1000.0)
150  { }
151 
152  void initialize(UAS &uas_)
153  {
154  PluginBase::initialize(uas_);
155 
156  wp_state = WP::IDLE;
157 
158  wp_nh.param("pull_after_gcs", do_pull_after_gcs, true);
159 
160  wp_list_pub = wp_nh.advertise<mavros_msgs::WaypointList>("waypoints", 2, true);
161  wp_reached_pub = wp_nh.advertise<mavros_msgs::WaypointReached>("reached", 10, true);
162  pull_srv = wp_nh.advertiseService("pull", &WaypointPlugin::pull_cb, this);
163  push_srv = wp_nh.advertiseService("push", &WaypointPlugin::push_cb, this);
164  clear_srv = wp_nh.advertiseService("clear", &WaypointPlugin::clear_cb, this);
165  set_cur_srv = wp_nh.advertiseService("set_current", &WaypointPlugin::set_cur_cb, this);
166 
167  wp_timer = wp_nh.createTimer(WP_TIMEOUT_DT, &WaypointPlugin::timeout_cb, this, true);
168  wp_timer.stop();
169  schedule_timer = wp_nh.createTimer(BOOTUP_TIME_DT, &WaypointPlugin::scheduled_pull_cb, this, true);
170  schedule_timer.stop();
171  enable_connection_cb();
172  }
173 
175  return {
181  make_handler(&WaypointPlugin::handle_mission_ack),
182  };
183  }
184 
185 private:
186  using unique_lock = std::unique_lock<std::recursive_mutex>;
187  using lock_guard = std::lock_guard<std::recursive_mutex>;
188 
189  std::recursive_mutex mutex;
191 
198 
199 
200  std::vector<WaypointItem> waypoints;
201  std::vector<WaypointItem> send_waypoints;
202  enum class WP {
203  IDLE,
204  RXLIST,
205  RXWP,
206  TXLIST,
207  TXPARTIAL,
208  TXWP,
209  CLEAR,
210  SET_CUR
211  };
213 
214  size_t wp_count;
215  size_t wp_start_id;
216  size_t wp_end_id;
217  size_t wp_cur_id;
220  size_t wp_retries;
224  std::condition_variable list_receiving;
225  std::condition_variable list_sending;
226 
231 
233 
234  static constexpr int BOOTUP_TIME_MS = 15000;
235  static constexpr int LIST_TIMEOUT_MS = 30000;
236  static constexpr int WP_TIMEOUT_MS = 1000;
237  static constexpr int RESCHEDULE_MS = 5000;
238  static constexpr int RETRIES_COUNT = 3;
239 
244 
245  /* -*- rx handlers -*- */
246 
253  void handle_mission_item(const mavlink::mavlink_message_t *msg, WaypointItem &wpi)
254  {
255  unique_lock lock(mutex);
256 
257  // WaypointItem has wider fields for Lat/Long/Alt, set it
258  // [[[cog:
259  // for a, b in waypoint_coords:
260  // cog.outl("wpi.%s = wpi.%s;" % (a, b))
261  // ]]]
262  wpi.x_lat = wpi.x;
263  wpi.y_long = wpi.y;
264  wpi.z_alt = wpi.z;
265  // [[[end]]] (checksum: b8f95ce9c7c9dbd4eb493bf1227f273f)
266 
267  /* receive item only in RX state */
268  if (wp_state == WP::RXWP) {
269  if (wpi.seq != wp_cur_id) {
270  ROS_WARN_NAMED("wp", "WP: Seq mismatch, dropping item (%d != %zu)",
271  wpi.seq, wp_cur_id);
272  return;
273  }
274 
275  ROS_INFO_STREAM_NAMED("wp", "WP: item " << wpi.to_string());
276 
277  waypoints.push_back(wpi);
278  if (++wp_cur_id < wp_count) {
279  restart_timeout_timer();
280  mission_request(wp_cur_id);
281  }
282  else {
283  request_mission_done();
284  lock.unlock();
285  publish_waypoints();
286  }
287  }
288  else {
289  ROS_DEBUG_NAMED("wp", "WP: rejecting item, wrong state %d", enum_value(wp_state));
290  if (do_pull_after_gcs && reschedule_pull) {
291  ROS_DEBUG_NAMED("wp", "WP: reschedule pull");
292  schedule_pull(WP_TIMEOUT_DT);
293  }
294  }
295  }
296 
303  void handle_mission_request(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_REQUEST &mreq)
304  {
305  lock_guard lock(mutex);
306 
307  if ((wp_state == WP::TXLIST && mreq.seq == 0) || (wp_state == WP::TXPARTIAL && mreq.seq == wp_start_id) || (wp_state == WP::TXWP)) {
308  if (mreq.seq != wp_cur_id && mreq.seq != wp_cur_id + 1) {
309  ROS_WARN_NAMED("wp", "WP: Seq mismatch, dropping request (%d != %zu)",
310  mreq.seq, wp_cur_id);
311  return;
312  }
313 
314  restart_timeout_timer();
315  if (mreq.seq < wp_end_id) {
316  ROS_DEBUG_NAMED("wp", "WP: FCU requested waypoint %d", mreq.seq);
317  wp_state = WP::TXWP;
318  wp_cur_id = mreq.seq;
319  send_waypoint(wp_cur_id);
320  }
321  else
322  ROS_ERROR_NAMED("wp", "WP: FCU require seq out of range");
323  }
324  else
325  ROS_DEBUG_NAMED("wp", "WP: rejecting request, wrong state %d", enum_value(wp_state));
326  }
327 
334  void handle_mission_current(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_CURRENT &mcur)
335  {
336  unique_lock lock(mutex);
337 
338  if (wp_state == WP::SET_CUR) {
339  /* MISSION_SET_CURRENT ACK */
340  ROS_DEBUG_NAMED("wp", "WP: set current #%d done", mcur.seq);
341  go_idle();
342  wp_cur_active = mcur.seq;
343  set_current_waypoint(wp_cur_active);
344 
345  lock.unlock();
346  list_sending.notify_all();
347  publish_waypoints();
348  }
349  else if (wp_state == WP::IDLE && wp_cur_active != mcur.seq) {
350  /* update active */
351  ROS_DEBUG_NAMED("wp", "WP: update current #%d", mcur.seq);
352  wp_cur_active = mcur.seq;
353  set_current_waypoint(wp_cur_active);
354 
355  lock.unlock();
356  publish_waypoints();
357  }
358  }
359 
367  void handle_mission_count(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_COUNT &mcnt)
368  {
369  unique_lock lock(mutex);
370 
371  if (wp_state == WP::RXLIST) {
372  /* FCU report of MISSION_REQUEST_LIST */
373  ROS_DEBUG_NAMED("wp", "WP: count %d", mcnt.count);
374 
375  wp_count = mcnt.count;
376  wp_cur_id = 0;
377 
378  waypoints.clear();
379  waypoints.reserve(wp_count);
380 
381  if (wp_count > 0) {
382  wp_state = WP::RXWP;
383  restart_timeout_timer();
384  mission_request(wp_cur_id);
385  }
386  else {
387  request_mission_done();
388  lock.unlock();
389  publish_waypoints();
390  }
391  }
392  else {
393  ROS_INFO_NAMED("wp", "WP: seems GCS requesting mission");
394  /* schedule pull after GCS done */
395  if (do_pull_after_gcs) {
396  ROS_INFO_NAMED("wp", "WP: scheduling pull after GCS is done");
397  reschedule_pull = true;
398  schedule_pull(RESCHEDULE_DT);
399  }
400  }
401  }
402 
408  void handle_mission_item_reached(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_ITEM_REACHED &mitr)
409  {
410  /* in QGC used as informational message */
411  ROS_INFO_NAMED("wp", "WP: reached #%d", mitr.seq);
412 
413  auto wpr = boost::make_shared<mavros_msgs::WaypointReached>();
414 
415  wpr->header.stamp = ros::Time::now();
416  wpr->wp_seq = mitr.seq;
417 
418  wp_reached_pub.publish(wpr);
419  }
420 
427  void handle_mission_ack(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_ACK &mack)
428  {
429  unique_lock lock(mutex);
430 
431  auto ack_type = static_cast<MRES>(mack.type);
432 
433  if ((wp_state == WP::TXLIST || wp_state == WP::TXPARTIAL || wp_state == WP::TXWP)
434  && (wp_cur_id == wp_end_id - 1)
435  && (ack_type == MRES::ACCEPTED)) {
436  go_idle();
437  waypoints = send_waypoints;
438  send_waypoints.clear();
439 
440  lock.unlock();
441  list_sending.notify_all();
442  publish_waypoints();
443  ROS_INFO_NAMED("wp", "WP: mission sended");
444  }
445  else if (wp_state == WP::TXWP && ack_type == MRES::INVALID_SEQUENCE) {
446  // Mission Ack: INVALID_SEQUENCE received during TXWP
447  // This happens when waypoint N was received by autopilot, but the request for waypoint N+1 failed.
448  // This causes seq mismatch, ignore and eventually the request for n+1 will get to us and seq will sync up.
449  ROS_DEBUG_NAMED("wp", "WP: Received INVALID_SEQUENCE ack");
450  }
451  else if (wp_state == WP::TXLIST || wp_state == WP::TXPARTIAL || wp_state == WP::TXWP) {
452  go_idle();
453  /* use this flag for failure report */
454  is_timedout = true;
455  lock.unlock();
456  list_sending.notify_all();
457 
458  ROS_ERROR_STREAM_NAMED("wp", "WP: upload failed: " << utils::to_string(ack_type));
459  }
460  else if (wp_state == WP::CLEAR) {
461  go_idle();
462  if (ack_type != MRES::ACCEPTED) {
463  is_timedout = true;
464  lock.unlock();
465  ROS_ERROR_STREAM_NAMED("wp", "WP: clear failed: " << utils::to_string(ack_type));
466  }
467  else {
468  waypoints.clear();
469  lock.unlock();
470  publish_waypoints();
471  ROS_INFO_NAMED("wp", "WP: mission cleared");
472  }
473 
474  list_sending.notify_all();
475  }
476  else
477  ROS_DEBUG_NAMED("wp", "WP: not planned ACK, type: %d", mack.type);
478  }
479 
480  /* -*- mid-level helpers -*- */
481 
486  void timeout_cb(const ros::TimerEvent &event)
487  {
488  unique_lock lock(mutex);
489  if (wp_retries > 0) {
490  wp_retries--;
491  ROS_WARN_NAMED("wp", "WP: timeout, retries left %zu", wp_retries);
492 
493  switch (wp_state) {
494  case WP::RXLIST:
495  mission_request_list();
496  break;
497  case WP::RXWP:
498  mission_request(wp_cur_id);
499  break;
500  case WP::TXLIST:
501  mission_count(wp_count);
502  break;
503  case WP::TXPARTIAL:
504  mission_write_partial_list(wp_start_id, wp_end_id);
505  break;
506  case WP::TXWP:
507  send_waypoint(wp_cur_id);
508  break;
509  case WP::CLEAR:
510  mission_clear_all();
511  break;
512  case WP::SET_CUR:
513  mission_set_current(wp_set_active);
514  break;
515 
516  case WP::IDLE:
517  break;
518  }
519 
520  restart_timeout_timer_int();
521  }
522  else {
523  ROS_ERROR_NAMED("wp", "WP: timed out.");
524  go_idle();
525  is_timedout = true;
526  /* prevent waiting cond var timeout */
527  lock.unlock();
528  list_receiving.notify_all();
529  list_sending.notify_all();
530  }
531  }
532 
533  // Act on first heartbeat from FCU
534  void connection_cb(bool connected) override
535  {
536  lock_guard lock(mutex);
537  if (connected) {
538  schedule_pull(BOOTUP_TIME_DT);
539 
540  if (wp_nh.hasParam("enable_partial_push")) {
541  wp_nh.getParam("enable_partial_push", enable_partial_push);
542  }
543  else {
544  enable_partial_push = m_uas->is_ardupilotmega();
545  }
546  }
547  else {
548  schedule_timer.stop();
549  }
550  }
551 
554  {
555  lock_guard lock(mutex);
556  if (wp_state != WP::IDLE) {
557  /* try later */
558  ROS_DEBUG_NAMED("wp", "WP: busy, reschedule pull");
559  schedule_pull(RESCHEDULE_DT);
560  return;
561  }
562 
563  ROS_DEBUG_NAMED("wp", "WP: start scheduled pull");
564  wp_state = WP::RXLIST;
565  wp_count = 0;
566  restart_timeout_timer();
567  mission_request_list();
568  }
569 
572  {
573  /* possibly not needed if count == 0 (QGC impl) */
574  mission_ack(MRES::ACCEPTED);
575 
576  go_idle();
577  list_receiving.notify_all();
578  ROS_INFO_NAMED("wp", "WP: mission received");
579  }
580 
581  void go_idle(void)
582  {
583  reschedule_pull = false;
584  wp_state = WP::IDLE;
585  wp_timer.stop();
586  }
587 
589  {
590  wp_retries = RETRIES_COUNT;
591  restart_timeout_timer_int();
592  }
593 
595  {
596  is_timedout = false;
597  wp_timer.stop();
598  wp_timer.start();
599  }
600 
601  void schedule_pull(const ros::Duration &dt)
602  {
603  schedule_timer.stop();
604  schedule_timer.setPeriod(dt);
605  schedule_timer.start();
606  }
607 
609  void send_waypoint(size_t seq)
610  {
611  if (seq < send_waypoints.size()) {
612  auto wpi = send_waypoints.at(seq);
613  mission_item(wpi);
614 
615  ROS_DEBUG_STREAM_NAMED("wp", "WP: send item " << wpi.to_string());
616  }
617  }
618 
624  {
625  std::unique_lock<std::mutex> lock(recv_cond_mutex);
626  return list_receiving.wait_for(lock, std::chrono::nanoseconds(LIST_TIMEOUT_DT.toNSec()))
627  == std::cv_status::no_timeout
628  && !is_timedout;
629  }
630 
636  {
637  std::unique_lock<std::mutex> lock(send_cond_mutex);
638 
639  return list_sending.wait_for(lock, std::chrono::nanoseconds(LIST_TIMEOUT_DT.toNSec()))
640  == std::cv_status::no_timeout
641  && !is_timedout;
642  }
643 
645  void set_current_waypoint(size_t seq)
646  {
647  for (auto &it : waypoints)
648  it.current = (it.seq == seq) ? true : false;
649  }
650 
653  {
654  auto wpl = boost::make_shared<mavros_msgs::WaypointList>();
655  unique_lock lock(mutex);
656 
657  wpl->current_seq = wp_cur_active;
658  wpl->waypoints.clear();
659  wpl->waypoints.reserve(waypoints.size());
660  for (auto &it : waypoints) {
661  wpl->waypoints.push_back(it.to_msg());
662  }
663 
664  lock.unlock();
665  wp_list_pub.publish(wpl);
666  }
667 
668  /* -*- low-level send functions -*- */
669 
671  {
672  m_uas->msg_set_target(wp);
673  // WaypointItem may be sent as MISSION_ITEM
674  UAS_FCU(m_uas)->send_message_ignore_drop(wp);
675  }
676 
677  void mission_request(uint16_t seq)
678  {
679  ROS_DEBUG_NAMED("wp", "WP:m: request #%u", seq);
680 
681  mavlink::common::msg::MISSION_REQUEST mrq {};
682  m_uas->msg_set_target(mrq);
683  mrq.seq = seq;
684 
685  UAS_FCU(m_uas)->send_message_ignore_drop(mrq);
686  }
687 
688  void mission_set_current(uint16_t seq)
689  {
690  ROS_DEBUG_NAMED("wp", "WP:m: set current #%u", seq);
691 
692  mavlink::common::msg::MISSION_SET_CURRENT msc {};
693  m_uas->msg_set_target(msc);
694  msc.seq = seq;
695 
696  UAS_FCU(m_uas)->send_message_ignore_drop(msc);
697  }
698 
700  {
701  ROS_DEBUG_NAMED("wp", "WP:m: request list");
702 
703  mavlink::common::msg::MISSION_REQUEST_LIST mrl {};
704  m_uas->msg_set_target(mrl);
705 
706  UAS_FCU(m_uas)->send_message_ignore_drop(mrl);
707  }
708 
709  void mission_count(uint16_t cnt)
710  {
711  ROS_DEBUG_NAMED("wp", "WP:m: count %u", cnt);
712 
713  mavlink::common::msg::MISSION_COUNT mcnt {};
714  m_uas->msg_set_target(mcnt);
715  mcnt.count = cnt;
716 
717  UAS_FCU(m_uas)->send_message_ignore_drop(mcnt);
718  }
719 
720  void mission_write_partial_list(uint16_t start_index, uint16_t end_index)
721  {
722  ROS_DEBUG_NAMED("wp", "WP:m: write partial list %u - %u", start_index, end_index);
723 
724  mavlink::common::msg::MISSION_WRITE_PARTIAL_LIST mwpl {};
725  mwpl.start_index = start_index;
726  mwpl.end_index = end_index;
727  m_uas->msg_set_target(mwpl);
728 
729  UAS_FCU(m_uas)->send_message_ignore_drop(mwpl);
730  }
731 
733  {
734  ROS_DEBUG_NAMED("wp", "WP:m: clear all");
735 
736  mavlink::common::msg::MISSION_CLEAR_ALL mclr {};
737  m_uas->msg_set_target(mclr);
738 
739  UAS_FCU(m_uas)->send_message_ignore_drop(mclr);
740  }
741 
742  void mission_ack(MRES type) {
743  ROS_DEBUG_NAMED("wp", "WP:m: ACK %u", enum_value(type));
744 
745  mavlink::common::msg::MISSION_ACK mack {};
746  m_uas->msg_set_target(mack);
747  mack.type = enum_value(type);
748 
749  UAS_FCU(m_uas)->send_message_ignore_drop(mack);
750  }
751 
752  /* -*- ROS callbacks -*- */
753 
754  bool pull_cb(mavros_msgs::WaypointPull::Request &req,
755  mavros_msgs::WaypointPull::Response &res)
756  {
757  unique_lock lock(mutex);
758 
759  if (wp_state != WP::IDLE)
760  // Wrong initial state, other operation in progress?
761  return false;
762 
763  wp_state = WP::RXLIST;
764  wp_count = 0;
765  restart_timeout_timer();
766 
767  lock.unlock();
768  mission_request_list();
769  res.success = wait_fetch_all();
770  lock.lock();
771 
772  res.wp_received = waypoints.size();
773  go_idle(); // not nessessary, but prevents from blocking
774  return true;
775  }
776 
777  bool push_cb(mavros_msgs::WaypointPush::Request &req,
778  mavros_msgs::WaypointPush::Response &res)
779  {
780  unique_lock lock(mutex);
781 
782  if (wp_state != WP::IDLE)
783  // Wrong initial state, other operation in progress?
784  return false;
785 
786  if (req.start_index) {
787  // Partial Waypoint update
788 
789  if (!enable_partial_push) {
790  ROS_WARN_NAMED("wp", "WP: Partial Push not enabled. (Only supported on APM)");
791  res.success = false;
792  res.wp_transfered = 0;
793  return true;
794  }
795 
796  if (waypoints.size() < req.start_index + req.waypoints.size()) {
797  ROS_WARN_NAMED("wp", "WP: Partial push out of range rejected.");
798  res.success = false;
799  res.wp_transfered = 0;
800  return true;
801  }
802 
803  wp_state = WP::TXPARTIAL;
804  send_waypoints = waypoints;
805 
806  uint16_t seq = req.start_index;
807  for (auto &it : req.waypoints) {
808  send_waypoints[seq] = WaypointItem::from_msg(it, seq);
809  seq++;
810  }
811 
812  wp_count = req.waypoints.size();
813  wp_start_id = req.start_index;
814  wp_end_id = req.start_index + wp_count;
815  wp_cur_id = req.start_index;
816  restart_timeout_timer();
817 
818  lock.unlock();
819  mission_write_partial_list(wp_start_id, wp_end_id);
820  res.success = wait_push_all();
821  lock.lock();
822 
823  res.wp_transfered = wp_cur_id - wp_start_id + 1;
824  }
825  else {
826  // Full waypoint update
827  wp_state = WP::TXLIST;
828 
829  send_waypoints.clear();
830  send_waypoints.reserve(req.waypoints.size());
831  uint16_t seq = 0;
832  for (auto &it : req.waypoints) {
833  send_waypoints.push_back(WaypointItem::from_msg(it, seq++));
834  }
835 
836  wp_count = send_waypoints.size();
837  wp_end_id = wp_count;
838  wp_cur_id = 0;
839  restart_timeout_timer();
840 
841  lock.unlock();
842  mission_count(wp_count);
843  res.success = wait_push_all();
844  lock.lock();
845 
846  res.wp_transfered = wp_cur_id + 1;
847  }
848 
849  go_idle(); // same as in pull_cb
850  return true;
851  }
852 
853  bool clear_cb(mavros_msgs::WaypointClear::Request &req,
854  mavros_msgs::WaypointClear::Response &res)
855  {
856  unique_lock lock(mutex);
857 
858  if (wp_state != WP::IDLE)
859  return false;
860 
861  wp_state = WP::CLEAR;
862  restart_timeout_timer();
863 
864  lock.unlock();
865  mission_clear_all();
866  res.success = wait_push_all();
867 
868  lock.lock();
869  go_idle(); // same as in pull_cb
870  return true;
871  }
872 
873  bool set_cur_cb(mavros_msgs::WaypointSetCurrent::Request &req,
874  mavros_msgs::WaypointSetCurrent::Response &res)
875  {
876  unique_lock lock(mutex);
877 
878  if (wp_state != WP::IDLE)
879  return false;
880 
881  wp_state = WP::SET_CUR;
882  wp_set_active = req.wp_seq;
883  restart_timeout_timer();
884 
885  lock.unlock();
886  mission_set_current(wp_set_active);
887  res.success = wait_push_all();
888 
889  lock.lock();
890  go_idle(); // same as in pull_cb
891  return true;
892  }
893 };
894 } // namespace std_plugins
895 } // namespace mavros
896 
void handle_mission_ack(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_ACK &mack)
handle MISSION_ACK mavlink msg Handles a MISSION_ACK which marks the end of a push, or a failure
Definition: waypoint.cpp:427
MAVROS Plugin base class.
Definition: mavros_plugin.h:37
const ros::Duration LIST_TIMEOUT_DT
Definition: waypoint.cpp:241
void request_mission_done(void)
Send ACK back to FCU after pull.
Definition: waypoint.cpp:571
void timeout_cb(const ros::TimerEvent &event)
Act on a timeout Resend the message that may have been lost.
Definition: waypoint.cpp:486
void initialize(UAS &uas_)
Plugin initializer.
Definition: waypoint.cpp:152
std::vector< WaypointItem > send_waypoints
Definition: waypoint.cpp:201
#define ROS_INFO_NAMED(name,...)
bool set_cur_cb(mavros_msgs::WaypointSetCurrent::Request &req, mavros_msgs::WaypointSetCurrent::Response &res)
Definition: waypoint.cpp:873
#define ROS_DEBUG_STREAM_NAMED(name, args)
std::string format(const std::string &fmt, Args...args)
mavlink::common::MAV_MISSION_RESULT MRES
Definition: waypoint.cpp:34
void mission_count(uint16_t cnt)
Definition: waypoint.cpp:709
void publish(const boost::shared_ptr< M > &message) const
#define ROS_ERROR_STREAM_NAMED(name, args)
#define ROS_WARN_NAMED(name,...)
void mission_set_current(uint16_t seq)
Definition: waypoint.cpp:688
MAVROS Plugin base.
void stop()
void setPeriod(const Duration &period, bool reset=true)
void start()
std::condition_variable list_sending
Definition: waypoint.cpp:225
#define ROS_INFO_STREAM_NAMED(name, args)
bool wait_fetch_all()
wait until a waypoint pull is complete. Pull happens asyncronously, this function blocks until it is ...
Definition: waypoint.cpp:623
bool clear_cb(mavros_msgs::WaypointClear::Request &req, mavros_msgs::WaypointClear::Response &res)
Definition: waypoint.cpp:853
const ros::Duration RESCHEDULE_DT
Definition: waypoint.cpp:243
void handle_mission_count(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_COUNT &mcnt)
handle MISSION_COUNT mavlink msg Handles a mission count from FCU in a Waypoint Pull Triggers a pull ...
Definition: waypoint.cpp:367
static WaypointItem from_msg(mavros_msgs::Waypoint &wp, uint16_t seq)
Definition: waypoint.cpp:80
void send_waypoint(size_t seq)
send a single waypoint to FCU
Definition: waypoint.cpp:609
void publish_waypoints()
publish the updated waypoint list after operation
Definition: waypoint.cpp:652
bool push_cb(mavros_msgs::WaypointPush::Request &req, mavros_msgs::WaypointPush::Response &res)
Definition: waypoint.cpp:777
void handle_mission_current(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_CURRENT &mcur)
handle MISSION_CURRENT mavlink msg This confirms a SET_CUR action
Definition: waypoint.cpp:334
bool wait_push_all()
wait until a waypoint push is complete. Push happens asyncronously, this function blocks until it is ...
Definition: waypoint.cpp:635
#define ROS_DEBUG_NAMED(name,...)
void handle_mission_item(const mavlink::mavlink_message_t *msg, WaypointItem &wpi)
handle MISSION_ITEM mavlink msg handles and stores mission items when pulling waypoints ...
Definition: waypoint.cpp:253
const ros::Duration BOOTUP_TIME_DT
Definition: waypoint.cpp:240
std::unique_lock< std::recursive_mutex > unique_lock
Definition: waypoint.cpp:186
bool pull_cb(mavros_msgs::WaypointPull::Request &req, mavros_msgs::WaypointPull::Response &res)
Definition: waypoint.cpp:754
void mission_request(uint16_t seq)
Definition: waypoint.cpp:677
void handle_mission_item_reached(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_ITEM_REACHED &mitr)
handle MISSION_ITEM_REACHED mavlink msg
Definition: waypoint.cpp:408
const ros::Duration WP_TIMEOUT_DT
Definition: waypoint.cpp:242
UAS for plugins.
Definition: mavros_uas.h:66
ROSLIB_DECL std::string command(const std::string &cmd)
mavros_msgs::Waypoint to_msg()
Definition: waypoint.cpp:43
int64_t toNSec() const
void mission_write_partial_list(uint16_t start_index, uint16_t end_index)
Definition: waypoint.cpp:720
Mission manupulation plugin.
Definition: waypoint.cpp:132
#define UAS_FCU(uasobjptr)
helper accessor to FCU link interface
Definition: mavros_uas.h:41
std::string to_string(timesync_mode e)
Subscriptions get_subscriptions()
Return vector of MAVLink message subscriptions (handlers)
Definition: waypoint.cpp:174
void schedule_pull(const ros::Duration &dt)
Definition: waypoint.cpp:601
std::lock_guard< std::recursive_mutex > lock_guard
Definition: waypoint.cpp:187
void mission_item(WaypointItem &wp)
Definition: waypoint.cpp:670
std::condition_variable list_receiving
Definition: waypoint.cpp:224
std::vector< HandlerInfo > Subscriptions
Subscriptions vector.
Definition: mavros_plugin.h:48
bool getParam(const std::string &key, std::string &s) const
void connection_cb(bool connected) override
Definition: waypoint.cpp:534
#define ROS_ERROR_NAMED(name,...)
static Time now()
bool hasParam(const std::string &key) const
void handle_mission_request(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_REQUEST &mreq)
handle MISSION_REQUEST mavlink msg handles and acts on misison request from FCU
Definition: waypoint.cpp:303
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void scheduled_pull_cb(const ros::TimerEvent &event)
Callback for scheduled waypoint pull.
Definition: waypoint.cpp:553
std::vector< WaypointItem > waypoints
Definition: waypoint.cpp:200
void set_current_waypoint(size_t seq)
set the FCU current waypoint
Definition: waypoint.cpp:645
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:11