-
Notifications
You must be signed in to change notification settings - Fork 19.7k
Add support for multi-GCS operation #29252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
18151cc
08258ac
b5d1c91
40ce68c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -317,10 +317,22 @@ uint8_t GCS_MAVLINK_Copter::sysid_my_gcs() const | |
| { | ||
| return copter.g.sysid_my_gcs; | ||
| } | ||
| void GCS_MAVLINK_Copter::set_sysid_my_gcs(uint8_t sysid) const | ||
| { | ||
| copter.g.sysid_my_gcs.set_and_save(sysid); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do not do this - definitely not "save" and not "set". We've learnt over time that changing the vehicle parameters based on random other mavlink messages leads to a lot of pain. The most obvious of these were the "set-speed" mavlink messages! Alternative here would probably make SYSID_MYGCS a reboot-required parameter and initialise a little object at boot-time. |
||
| } | ||
| bool GCS_MAVLINK_Copter::sysid_enforce() const | ||
| { | ||
| return copter.g2.sysid_enforce; | ||
| } | ||
| bool GCS_MAVLINK_Copter::control_takeover_allowed() const | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation might benefit from a little sub-object, in the same way we have for Params and MissionitemProtocol |
||
| { | ||
| return copter.g2.control_takeover_allowed; | ||
| } | ||
| void GCS_MAVLINK_Copter::set_control_takeover_allowed(bool takeoverAllowed) const | ||
| { | ||
| return copter.g2.control_takeover_allowed.set_and_save(takeoverAllowed); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's your reasoning for persisting things? |
||
| } | ||
|
|
||
| uint32_t GCS_MAVLINK_Copter::telem_delay() const | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1151,6 +1151,7 @@ ap_message GCS_MAVLINK::mavlink_id_to_ap_message_id(const uint32_t mavlink_id) c | |||||||||||||||
| #endif | ||||||||||||||||
| { MAVLINK_MSG_ID_AVAILABLE_MODES, MSG_AVAILABLE_MODES}, | ||||||||||||||||
| { MAVLINK_MSG_ID_AVAILABLE_MODES_MONITOR, MSG_AVAILABLE_MODES_MONITOR}, | ||||||||||||||||
| { MAVLINK_MSG_ID_CONTROL_STATUS, MSG_CONTROL_STATUS}, | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| for (uint8_t i=0; i<ARRAY_SIZE(map); i++) { | ||||||||||||||||
|
|
@@ -1515,6 +1516,12 @@ void GCS_MAVLINK::update_send() | |||||||||||||||
| #if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED | ||||||||||||||||
| initialise_message_intervals_from_config_files(); | ||||||||||||||||
| #endif | ||||||||||||||||
| // We evaluate SYSID_ENFORCE parameter to send or not CONTROL_STATUS. This message is what | ||||||||||||||||
| // populates GCS UI for multi GCS control | ||||||||||||||||
| if (sysid_enforce()) { | ||||||||||||||||
| set_mavlink_message_id_interval(MAVLINK_MSG_ID_CONTROL_STATUS, 5000); | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definite no-no. Should be in the streams.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did this one to not send this message unless really required. I thought it would be pointless to share it with other streams, as for the case of single GCS operations it would be a small but nonetheless waste of bandwidth, as it would not be used at all. |
||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| deferred_messages_initialised = true; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -3204,6 +3211,79 @@ MAV_RESULT GCS_MAVLINK::handle_command_request_message(const mavlink_command_int | |||||||||||||||
| return MAV_RESULT_ACCEPTED; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| MAV_RESULT GCS_MAVLINK::handle_request_operator_control(const mavlink_command_int_t &packet, const mavlink_message_t &msg) | ||||||||||||||||
| { | ||||||||||||||||
| // Param2 is 0: Release control, 1: Request control. | ||||||||||||||||
| bool isRequestControl; | ||||||||||||||||
| if (is_equal(packet.param2, 1.0f)) { | ||||||||||||||||
| isRequestControl = true; | ||||||||||||||||
| } else if (is_zero(packet.param2)) { | ||||||||||||||||
| isRequestControl = false; | ||||||||||||||||
| } else { | ||||||||||||||||
| // Malformed packet, return denied | ||||||||||||||||
| return MAV_RESULT_DENIED; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Param3 is 0: Do not allow takeover, 1: Allow takeover. | ||||||||||||||||
| bool setTakeoverAllowed; | ||||||||||||||||
| if (is_equal(packet.param3, 1.0f)) { | ||||||||||||||||
| setTakeoverAllowed = true; | ||||||||||||||||
| } else if (is_zero(packet.param3)) { | ||||||||||||||||
| setTakeoverAllowed = false; | ||||||||||||||||
| } else { | ||||||||||||||||
| // Malformed packet, return denied | ||||||||||||||||
| return MAV_RESULT_DENIED; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (isRequestControl) { | ||||||||||||||||
| // This part would proceed the same if takeover is allowed, or if this is coming from the current GCS in control, | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Break this out into a method |
||||||||||||||||
| // for example to modify takover allowed | ||||||||||||||||
| if (control_takeover_allowed() || msg.sysid == sysid_my_gcs()) { | ||||||||||||||||
| // Set takeover allowed, so other GCS can get control automatically or they need to ask first to current GCS in control | ||||||||||||||||
| set_control_takeover_allowed(setTakeoverAllowed); | ||||||||||||||||
| // Set current GCS in control if this is coming from a different GCS | ||||||||||||||||
| if (msg.sysid != sysid_my_gcs()) { | ||||||||||||||||
| set_sysid_my_gcs(msg.sysid); | ||||||||||||||||
| } | ||||||||||||||||
| // And send control status inmediatly to notify all GCS | ||||||||||||||||
| send_control_status(); | ||||||||||||||||
| return MAV_RESULT_ACCEPTED; | ||||||||||||||||
| // Else send a command to the current GCS in control, so current active operator can be prompted to allow takeover for the GCS asking | ||||||||||||||||
| } else { | ||||||||||||||||
| mavlink_msg_command_long_send( | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pointless else
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer command_int, not command_long |
||||||||||||||||
| chan, | ||||||||||||||||
| sysid_my_gcs(), | ||||||||||||||||
| 0, // Should we retrieve here GCS compid and use it instead? | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No way to tell without a parameter. I think
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that would be good to have! |
||||||||||||||||
| MAV_CMD_REQUEST_OPERATOR_CONTROL, | ||||||||||||||||
| 0, | ||||||||||||||||
| msg.sysid, // Param1: Sysid of the GCS requesting control | ||||||||||||||||
| 1, // Param2: Release/request control. If we are here this should always be 1 (request). 0 would not make sense anyway | ||||||||||||||||
| packet.param3, // Param3: Allow takeover, this way the GCS in control can prompt the operator with the specific type of control request | ||||||||||||||||
| packet.param4, // Param4: Timeout in seconds before a request to a GCS to allow takeover is assumed to be rejected. This is used to display the timeout graphically on requestor and GCS in control. | ||||||||||||||||
| 0, 0, 0); | ||||||||||||||||
| // We should answer result failed, see MAV_CMD_REQUEST_OPERATOR_CONTROL documentation for more information | ||||||||||||||||
| return MAV_RESULT_FAILED; | ||||||||||||||||
| } | ||||||||||||||||
| // Release control | ||||||||||||||||
| } else { | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pointless else |
||||||||||||||||
| // Sanity check, double check that this is the GCS in control | ||||||||||||||||
| if (msg.sysid == sysid_my_gcs()) { | ||||||||||||||||
| // Set takeover allowed, so other GCS can get control automatically or they need to ask first to current GCS in control | ||||||||||||||||
| set_control_takeover_allowed(true); | ||||||||||||||||
| // As per Mavlink protocol, see MAV_CMD_REQUEST_OPERATOR_CONTROL, we should set sysid_my_gcs to 0, so CONTROL_STATUS emits 0 | ||||||||||||||||
| // (nobody in control), so other GCS can display properly lthe current control status of the vehicle. Should we be compliant here | ||||||||||||||||
| // and set sysid_my_gcs to 0? | ||||||||||||||||
| // set_sysid_my_gcs(0) | ||||||||||||||||
| // Finally send a CONTROL_STATUS inmediately to notify the GCSs on the system | ||||||||||||||||
| send_control_status(); | ||||||||||||||||
| return MAV_RESULT_ACCEPTED; | ||||||||||||||||
| // A release control command should always be sent from the GCS in control. Return failed otherwise | ||||||||||||||||
| } else { | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pointless else, and sysid check should be inverted |
||||||||||||||||
| return MAV_RESULT_FAILED; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| bool GCS_MAVLINK::get_ap_message_interval(ap_message id, uint16_t &interval_ms) const | ||||||||||||||||
| { | ||||||||||||||||
| // check if it's a specially-handled message: | ||||||||||||||||
|
|
@@ -5610,6 +5690,8 @@ MAV_RESULT GCS_MAVLINK::handle_command_int_packet(const mavlink_command_int_t &p | |||||||||||||||
| case MAV_CMD_REQUEST_MESSAGE: | ||||||||||||||||
| return handle_command_request_message(packet); | ||||||||||||||||
|
|
||||||||||||||||
| case MAV_CMD_REQUEST_OPERATOR_CONTROL: | ||||||||||||||||
| return handle_request_operator_control(packet, msg); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return MAV_RESULT_UNSUPPORTED; | ||||||||||||||||
|
|
@@ -5961,6 +6043,18 @@ bool GCS_MAVLINK::send_relay_status() const | |||||||||||||||
| } | ||||||||||||||||
| #endif // AP_MAVLINK_MSG_RELAY_STATUS_ENABLED | ||||||||||||||||
|
|
||||||||||||||||
| void GCS_MAVLINK::send_control_status() const | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Everything needs to be behind a feature define
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted. would MAVLINK_MULTIGCS_PROTOCOL_ENABLED work? |
||||||||||||||||
| { | ||||||||||||||||
| uint8_t flags = GCS_CONTROL_STATUS_FLAGS_SYSTEM_MANAGER; | ||||||||||||||||
| flags |= control_takeover_allowed() ? GCS_CONTROL_STATUS_FLAGS_TAKEOVER_ALLOWED : 0; | ||||||||||||||||
| mavlink_msg_control_status_send( | ||||||||||||||||
| chan, | ||||||||||||||||
| // System ID of the system currently in control of this MAV | ||||||||||||||||
| sysid_my_gcs(), | ||||||||||||||||
| // Flags: Automatic takeover allowed and this system controlling the rest of components of this system ID ( always true for an autopilot ) | ||||||||||||||||
| flags); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| void GCS_MAVLINK::send_autopilot_state_for_gimbal_device() const | ||||||||||||||||
| { | ||||||||||||||||
| #if AP_AHRS_ENABLED | ||||||||||||||||
|
|
@@ -6490,6 +6584,9 @@ bool GCS_MAVLINK::try_send_message(const enum ap_message id) | |||||||||||||||
| ret = send_relay_status(); | ||||||||||||||||
| break; | ||||||||||||||||
| #endif | ||||||||||||||||
| case MSG_CONTROL_STATUS: | ||||||||||||||||
| send_control_status(); | ||||||||||||||||
| break; | ||||||||||||||||
|
|
||||||||||||||||
| case MSG_AVAILABLE_MODES: | ||||||||||||||||
| ret = send_available_modes(); | ||||||||||||||||
|
|
@@ -6823,9 +6920,35 @@ bool GCS_MAVLINK::accept_packet(const mavlink_status_t &status, | |||||||||||||||
| return true; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Allow REQUEST_OPERATOR_CONTROL packets. This is needed for a GCS not in control | ||||||||||||||||
| // to communicate with the vehicle, so it can forward the request to GCS in control. | ||||||||||||||||
| if (is_control_request_packet(msg)) { | ||||||||||||||||
|
Comment on lines
+6923
to
+6925
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does the vehicle need to be in the middle of this negotiation? I'm not saying it's wrong.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we thought about this protocol we thought about this paradigm, and some reasons I remember:
|
||||||||||||||||
| return true; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return false; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| bool GCS_MAVLINK::is_control_request_packet(const mavlink_message_t &msg) const | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an awfully expensive function to be doing on every incoming packet!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it isn't ideal but:
|
||||||||||||||||
| { | ||||||||||||||||
| bool result = false; | ||||||||||||||||
| if (msg.msgid == MAVLINK_MSG_ID_COMMAND_LONG) { | ||||||||||||||||
| mavlink_command_long_t command; | ||||||||||||||||
| mavlink_msg_command_long_decode(&msg, &command); | ||||||||||||||||
| if (command.command == MAV_CMD_REQUEST_OPERATOR_CONTROL) { | ||||||||||||||||
| result = true; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+6935
to
+6941
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
| if (msg.msgid == MAVLINK_MSG_ID_COMMAND_INT) { | ||||||||||||||||
| mavlink_command_int_t command; | ||||||||||||||||
| mavlink_msg_command_int_decode(&msg, &command); | ||||||||||||||||
| if (command.command == MAV_CMD_REQUEST_OPERATOR_CONTROL) { | ||||||||||||||||
| result = true; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| return result; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /* | ||||||||||||||||
| update UART pass-thru, if enabled | ||||||||||||||||
| */ | ||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This absolutely doesn't belong in Copter. If you're finding it convenient to work only in the Copter directory, fine - but itreally should be up in
libvraries/GCS_MAVLink