18 #include <condition_variable> 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> 30 namespace std_plugins {
32 using mavlink::common::MAV_CMD;
33 using mavlink::common::MAV_FRAME;
34 using MRES = mavlink::common::MAV_MISSION_RESULT;
45 mavros_msgs::Waypoint ret;
66 ret.is_current = current;
67 ret.autocontinue = autocontinue;
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;
110 ret.mission_type =
enum_value(mavlink::common::MAV_MISSION_TYPE::MISSION);
119 return utils::format(
"#%u%1s F:%u C:%3u p: %f %f %f %f x: %f y: %f z: %f",
121 (current) ?
"*" :
"",
123 param1, param2, param3, param4,
124 x_lat, y_long, z_alt);
138 wp_retries(RETRIES_COUNT),
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)
154 PluginBase::initialize(uas_);
158 wp_nh.param(
"pull_after_gcs", do_pull_after_gcs,
true);
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);
170 schedule_timer.stop();
171 enable_connection_cb();
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;
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)",
277 waypoints.push_back(wpi);
278 if (++wp_cur_id < wp_count) {
279 restart_timeout_timer();
280 mission_request(wp_cur_id);
283 request_mission_done();
290 if (do_pull_after_gcs && reschedule_pull) {
292 schedule_pull(WP_TIMEOUT_DT);
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);
314 restart_timeout_timer();
315 if (mreq.seq < wp_end_id) {
318 wp_cur_id = mreq.seq;
319 send_waypoint(wp_cur_id);
338 if (wp_state == WP::SET_CUR) {
342 wp_cur_active = mcur.seq;
343 set_current_waypoint(wp_cur_active);
346 list_sending.notify_all();
349 else if (wp_state == WP::IDLE && wp_cur_active != mcur.seq) {
352 wp_cur_active = mcur.seq;
353 set_current_waypoint(wp_cur_active);
371 if (wp_state == WP::RXLIST) {
375 wp_count = mcnt.count;
379 waypoints.reserve(wp_count);
383 restart_timeout_timer();
384 mission_request(wp_cur_id);
387 request_mission_done();
395 if (do_pull_after_gcs) {
397 reschedule_pull =
true;
398 schedule_pull(RESCHEDULE_DT);
413 auto wpr = boost::make_shared<mavros_msgs::WaypointReached>();
416 wpr->wp_seq = mitr.seq;
427 void handle_mission_ack(
const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_ACK &mack)
431 auto ack_type =
static_cast<MRES>(mack.type);
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)) {
437 waypoints = send_waypoints;
438 send_waypoints.clear();
441 list_sending.notify_all();
445 else if (wp_state == WP::TXWP && ack_type == MRES::INVALID_SEQUENCE) {
451 else if (wp_state == WP::TXLIST || wp_state == WP::TXPARTIAL || wp_state == WP::TXWP) {
456 list_sending.notify_all();
460 else if (wp_state == WP::CLEAR) {
462 if (ack_type != MRES::ACCEPTED) {
474 list_sending.notify_all();
489 if (wp_retries > 0) {
491 ROS_WARN_NAMED(
"wp",
"WP: timeout, retries left %zu", wp_retries);
495 mission_request_list();
498 mission_request(wp_cur_id);
501 mission_count(wp_count);
504 mission_write_partial_list(wp_start_id, wp_end_id);
507 send_waypoint(wp_cur_id);
513 mission_set_current(wp_set_active);
520 restart_timeout_timer_int();
528 list_receiving.notify_all();
529 list_sending.notify_all();
538 schedule_pull(BOOTUP_TIME_DT);
540 if (wp_nh.
hasParam(
"enable_partial_push")) {
541 wp_nh.
getParam(
"enable_partial_push", enable_partial_push);
544 enable_partial_push = m_uas->is_ardupilotmega();
548 schedule_timer.
stop();
556 if (wp_state != WP::IDLE) {
559 schedule_pull(RESCHEDULE_DT);
564 wp_state = WP::RXLIST;
566 restart_timeout_timer();
567 mission_request_list();
574 mission_ack(MRES::ACCEPTED);
577 list_receiving.notify_all();
583 reschedule_pull =
false;
590 wp_retries = RETRIES_COUNT;
591 restart_timeout_timer_int();
603 schedule_timer.
stop();
605 schedule_timer.
start();
611 if (seq < send_waypoints.size()) {
612 auto wpi = send_waypoints.at(seq);
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
637 std::unique_lock<std::mutex> lock(send_cond_mutex);
639 return list_sending.wait_for(lock, std::chrono::nanoseconds(LIST_TIMEOUT_DT.
toNSec()))
640 == std::cv_status::no_timeout
647 for (
auto &it : waypoints)
648 it.current = (it.seq == seq) ?
true :
false;
654 auto wpl = boost::make_shared<mavros_msgs::WaypointList>();
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());
672 m_uas->msg_set_target(wp);
674 UAS_FCU(m_uas)->send_message_ignore_drop(wp);
681 mavlink::common::msg::MISSION_REQUEST mrq {};
682 m_uas->msg_set_target(mrq);
685 UAS_FCU(m_uas)->send_message_ignore_drop(mrq);
692 mavlink::common::msg::MISSION_SET_CURRENT msc {};
693 m_uas->msg_set_target(msc);
696 UAS_FCU(m_uas)->send_message_ignore_drop(msc);
703 mavlink::common::msg::MISSION_REQUEST_LIST mrl {};
704 m_uas->msg_set_target(mrl);
706 UAS_FCU(m_uas)->send_message_ignore_drop(mrl);
713 mavlink::common::msg::MISSION_COUNT mcnt {};
714 m_uas->msg_set_target(mcnt);
717 UAS_FCU(m_uas)->send_message_ignore_drop(mcnt);
722 ROS_DEBUG_NAMED(
"wp",
"WP:m: write partial list %u - %u", start_index, end_index);
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);
729 UAS_FCU(m_uas)->send_message_ignore_drop(mwpl);
736 mavlink::common::msg::MISSION_CLEAR_ALL mclr {};
737 m_uas->msg_set_target(mclr);
739 UAS_FCU(m_uas)->send_message_ignore_drop(mclr);
745 mavlink::common::msg::MISSION_ACK mack {};
746 m_uas->msg_set_target(mack);
749 UAS_FCU(m_uas)->send_message_ignore_drop(mack);
754 bool pull_cb(mavros_msgs::WaypointPull::Request &req,
755 mavros_msgs::WaypointPull::Response &res)
759 if (wp_state != WP::IDLE)
763 wp_state = WP::RXLIST;
765 restart_timeout_timer();
768 mission_request_list();
769 res.success = wait_fetch_all();
772 res.wp_received = waypoints.size();
777 bool push_cb(mavros_msgs::WaypointPush::Request &req,
778 mavros_msgs::WaypointPush::Response &res)
782 if (wp_state != WP::IDLE)
786 if (req.start_index) {
789 if (!enable_partial_push) {
790 ROS_WARN_NAMED(
"wp",
"WP: Partial Push not enabled. (Only supported on APM)");
792 res.wp_transfered = 0;
796 if (waypoints.size() < req.start_index + req.waypoints.size()) {
799 res.wp_transfered = 0;
803 wp_state = WP::TXPARTIAL;
804 send_waypoints = waypoints;
806 uint16_t seq = req.start_index;
807 for (
auto &it : req.waypoints) {
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();
819 mission_write_partial_list(wp_start_id, wp_end_id);
820 res.success = wait_push_all();
823 res.wp_transfered = wp_cur_id - wp_start_id + 1;
827 wp_state = WP::TXLIST;
829 send_waypoints.clear();
830 send_waypoints.reserve(req.waypoints.size());
832 for (
auto &it : req.waypoints) {
836 wp_count = send_waypoints.size();
837 wp_end_id = wp_count;
839 restart_timeout_timer();
842 mission_count(wp_count);
843 res.success = wait_push_all();
846 res.wp_transfered = wp_cur_id + 1;
853 bool clear_cb(mavros_msgs::WaypointClear::Request &req,
854 mavros_msgs::WaypointClear::Response &res)
858 if (wp_state != WP::IDLE)
861 wp_state = WP::CLEAR;
862 restart_timeout_timer();
866 res.success = wait_push_all();
873 bool set_cur_cb(mavros_msgs::WaypointSetCurrent::Request &req,
874 mavros_msgs::WaypointSetCurrent::Response &res)
878 if (wp_state != WP::IDLE)
881 wp_state = WP::SET_CUR;
882 wp_set_active = req.wp_seq;
883 restart_timeout_timer();
886 mission_set_current(wp_set_active);
887 res.success = wait_push_all();
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
MAVROS Plugin base class.
const ros::Duration LIST_TIMEOUT_DT
void request_mission_done(void)
Send ACK back to FCU after pull.
void timeout_cb(const ros::TimerEvent &event)
Act on a timeout Resend the message that may have been lost.
void initialize(UAS &uas_)
Plugin initializer.
std::vector< WaypointItem > send_waypoints
#define ROS_INFO_NAMED(name,...)
std::mutex recv_cond_mutex
bool set_cur_cb(mavros_msgs::WaypointSetCurrent::Request &req, mavros_msgs::WaypointSetCurrent::Response &res)
void restart_timeout_timer(void)
#define ROS_DEBUG_STREAM_NAMED(name, args)
std::string format(const std::string &fmt, Args...args)
mavlink::common::MAV_MISSION_RESULT MRES
void mission_count(uint16_t cnt)
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)
ros::ServiceServer push_srv
ros::ServiceServer pull_srv
void restart_timeout_timer_int(void)
void setPeriod(const Duration &period, bool reset=true)
std::condition_variable list_sending
#define ROS_INFO_STREAM_NAMED(name, args)
ros::Timer schedule_timer
bool wait_fetch_all()
wait until a waypoint pull is complete. Pull happens asyncronously, this function blocks until it is ...
bool clear_cb(mavros_msgs::WaypointClear::Request &req, mavros_msgs::WaypointClear::Response &res)
const ros::Duration RESCHEDULE_DT
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 ...
static WaypointItem from_msg(mavros_msgs::Waypoint &wp, uint16_t seq)
void send_waypoint(size_t seq)
send a single waypoint to FCU
void publish_waypoints()
publish the updated waypoint list after operation
bool push_cb(mavros_msgs::WaypointPush::Request &req, mavros_msgs::WaypointPush::Response &res)
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
ros::ServiceServer clear_srv
bool wait_push_all()
wait until a waypoint push is complete. Push happens asyncronously, this function blocks until it is ...
#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 ...
const ros::Duration BOOTUP_TIME_DT
std::unique_lock< std::recursive_mutex > unique_lock
bool pull_cb(mavros_msgs::WaypointPull::Request &req, mavros_msgs::WaypointPull::Response &res)
void mission_request(uint16_t seq)
void handle_mission_item_reached(const mavlink::mavlink_message_t *msg, mavlink::common::msg::MISSION_ITEM_REACHED &mitr)
handle MISSION_ITEM_REACHED mavlink msg
const ros::Duration WP_TIMEOUT_DT
ROSLIB_DECL std::string command(const std::string &cmd)
mavros_msgs::Waypoint to_msg()
std::mutex send_cond_mutex
void mission_write_partial_list(uint16_t start_index, uint16_t end_index)
Mission manupulation plugin.
#define UAS_FCU(uasobjptr)
helper accessor to FCU link interface
std::string to_string(timesync_mode e)
Subscriptions get_subscriptions()
Return vector of MAVLink message subscriptions (handlers)
void mission_ack(MRES type)
void schedule_pull(const ros::Duration &dt)
std::lock_guard< std::recursive_mutex > lock_guard
void mission_item(WaypointItem &wp)
std::condition_variable list_receiving
std::recursive_mutex mutex
std::vector< HandlerInfo > Subscriptions
Subscriptions vector.
bool getParam(const std::string &key, std::string &s) const
void connection_cb(bool connected) override
ros::Publisher wp_reached_pub
#define ROS_ERROR_NAMED(name,...)
void mission_request_list()
bool hasParam(const std::string &key) const
ros::Publisher wp_list_pub
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
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
ros::ServiceServer set_cur_srv
void scheduled_pull_cb(const ros::TimerEvent &event)
Callback for scheduled waypoint pull.
std::vector< WaypointItem > waypoints
void set_current_waypoint(size_t seq)
set the FCU current waypoint
constexpr std::underlying_type< _T >::type enum_value(_T e)
std::recursive_mutex mutex