How to install and use a Flight Mission#
Description#
A flight mission can be in the following states:
UNAVAILABLE: mission is installed but not available. Possible reasons are:
BROKEN: the mission will never be able to load , e.g. because firmware version is not supported.
LOAD_FAILED: the last load failed, e.g. because of an exception in python code.
UNLOADED: mission is not loaded.
IDLE: mission is loaded and can be activated.
ACTIVE: mission is active.

The flight mission is managed from the mission UI that is running on the controller. It can either be a smartphone application using GroundSDK (ex: OpenFlight) or an PC application using Olympe/framework.
The mission UI can list, install and exchange messages with the flight mission.
The mission UI is optional, a flight mission can be installed and setup to replace the default mission.
Listing and installing flight missions from mission UI#
From GroundSDK: MissionUpdater
From Olympe:
Todo
add link when available
Start a flight mission from mission UI#
Once installed, a flight mission shall first be loaded, then activated. Several flight missions can be loaded simultaneously but only one can be active. Activating a new flight mission automatically deactivate the previous one.
From GroundSDK: MissionManager
From Olympe: MissionManager
Exchanging messages between mission and mission UI#
You can define custom messages between your mission UI and your flight mission. Messages are written using Protobuf 3.
You need to comply with the following conditions for your custom protobuf message file: * A package declaration with “<your_company>.missions.” + mission name + “.airsdk.messages”
Two messages called Command and Event, each containing an union of all possible command or event using a oneof tag with the name id.
The following properties need to be set:
java_package: package name in the form “com.your_company.drone.missions.” + mission name + “.airsdk
java_outer_classname: mission name
We also recommend to follow those rules for consistency along all protobuf messages:
Enumerations should be put in their own separate files, use the name Enum and have a package name corresponding to the current service, followed by the enumeration name (ex: MyPackage.MyEnum). If this is not possible, add the enumeration name in the values (ex: enumeration MyEnum with value MY_ENUM_VALUE_ONE)
Message and Package names should be in snake_case
Type name should be in CamelCase
Minimal example:
syntax = "proto3";
package your_company.missions.mymission.airsdk.messages;
option java_package = "com.your_company.drone.missions.mymission.airsdk";
option java_outer_classname = "MyMission";
option (olympe_package) = "your_company.missions.mymission.airsdk";
import 'google/protobuf/empty.proto';
message Command {
oneof id {
google.protobuf.Empty my_empty_command = 1;
}
}
message Event {
oneof id {
uint32 my_event = 1;
}
}
On the drone side: Use the mission_environment given in the Mission constructor.
make_airsdk_service_pair(package): Create a communication channel with the Mission UI given a protobuf package.
From the returned service object, use the following methods to send and receive messages.
send(message): Send the given message to the mission UI.
observe(…): Register a callback for message received from mission UI.
import fsup.services.events as events
import your_company.missions.mymission.airsdk.messages_pb2 as messages_pb
class Mission(object):
def __init__(self, mission_environment):
# Setup service pair with protobuf description
self.ext_ui_msgs = self.env.make_airsdk_service_pair(messages_pb)
# Register for incoming messages (commands)
self.ext_ui_msgs_observer = self.ext_ui_msgs.cmd.observe_messages({
self.ext_ui_msgs.cmd.idx.my_empty_command: self._on_msg_my_empty_command
})
# Send a message (event)
self.ext_ui_msgs.evt.sender.my_event(42)
def _on_msg_my_empty_command(self, msg):
# 'msg' is directly the arguments of 'my_empty_command'
# (google.protobuf.Empty in this case)
pass
On the mobile application side: Use the MissionManager
peripheral from Ground SDK.
Send the given message to the drone:
MissionManager - func send(message: MissionMessage)
message.uid: UID of the destination mission.
message.packageName: Package name of the protobuf message.
message.messageNumber: Number of the message (the value of the id oneof of the message).
message.payload: Message payload serialized from the protobuf message.
Note
mettre à jour le code
let missionUid = "MyMission"
/// Send message to my mission
func sendMessage(drone: Drone) {
/// Get mission manager
let missionManager = drone.getPeripheral(Peripherals.missionManager) { [unowned self] missionManager in
if let missionManager = missionManager {
// Set package name of my mission to mission manager.
// Mission manager will then be able to send messages and received events
missionManager.packageNames = [missionUid]
// Create mission command
var command = Your_Company_Missions_Mymissions_Airsdk_Messages_Command()
// Set command id
command.id = .myEmptyCommand(Google_Protobuf_Empty())
// Create paylaod
if let payload = try? command.serializedData() {
// Create mission message
let message = Message(messageNumber: 1,
payload: payload)
// Send message
missionManager.send(message: message)
}
}
}
}
// Message class
class Message: MissionMessage {
var uid: String = "MyMission"
var messageNumber: UInt
var packageName: String = "your_company.missions.mymission.airsdk.messages"
var payload: Data
init(messageNumber: UInt, payload: Data) {
self.messageNumber = messageNumber
self.payload = payload
}
}
Read the latest message sent by the drone:
MissionManager - var latestMessage: MissionMessage
latestMessage.uid: UID of the destination mission.
latestMessage.packageName: Package name of the protobuf message.
latestMessage.messageNumber: Number of the message (the value of the id oneof of the message).
latestMessage.payload: Message payload serialized from the protobuf message.
Note
mettre à jour le code
var missionManager: Ref<MissionManager>?
/// Observer for my mission
func observeMission(drone: Drone) {
// Get mission manager
missionManager = drone.getPeripheral(Peripherals.missionManager) { [unowned self] missionManager in
// Get missions
if let missions = missionManager?.missions {
// Test if my mission is inside this array.
if missions.keys.contains(missionUid) {
// Get the latest message
if let message = missionManager?.latestMessage {
let uid = message.uid
let messageNumber = message.messageNumber
let packageName = message.packageName
let payload = message.payload
// Print mission parameters
print("uid: \(uid) messageNumber: \(messageNumber) packageName: \(packageName)")
// Decode mission message
do {
let decodeInfo = try Your_Company_Missions_Mymissions_Airsdk_Messages_Event(
serializedData: payload)
DispatchQueue.main.async {
print("Event: \(decodeInfo.myEvent)")
}
} catch {
print("Failed to extract protobuf data from My mission message")
}
}
}
}
}
}
Mission web server REST API#
Instead of using the Ground SDK to manage flight missions, the drone web server REST API can also be used.
Get Missions List#
GET /api/v1/mission/missions
GET /api/v1/mission/missions/
Response:#
Success:
Code |
Return type |
Description |
---|---|---|
200 |
Array of mission object |
Mission list |
Errors:
Code |
Description |
---|---|
405 |
Request error |
500 |
If there is a server internal error |
Mission object:
parameter |
type |
Description |
---|---|---|
uid |
string |
Unique ID of the mission |
name |
string |
Name of the mission |
desc |
string |
Description of the mission |
version |
string |
Version of the mission |
target_model_id |
integer |
Model ID of the drone product |
target_min_version |
string |
Minimum version of drone firmware supported |
target_max_version |
string |
Maximum version of drone firmware supported |
digest |
string |
Digest of the mission (sha256 or sha512) |
Example
{
{
"uid": "com.your_company.missions.mymission1",
"name": "mymission1",
"version": "1.0.0",
"desc": " description of mymission 1",
"target_model_id": 2330,
"target_min_version": "1.0.0",
"target_max_version": "2.0.0"
"digest": "sha512:5862815df39863818738079d4471555710859b13c64427d3a0325bcd987504665c827c91d78a12c276b6fc4846b7568db37e38f659d9ba701393de33c93b408"
},
{
"uid": "com.your_company.missions.mymission5",
"name": "mymission5",
"version": "2.3.0",
"desc": " description of mymission 5",
"target_model_id": 2330,
"target_min_version": "1.0.0",
"target_max_version": "2.0.0"
"digest": "sha512:74655467cc1ac9a9bfb60645748a0d4aa8504f900ebc6e16acd79863ea92f1bd38f87452d3ee8137d8ca0dd4dcf8d436fade2ede445c0e14d6c6f4a47a7b3f71"
}
}
Add / Update a Mission#
PUT /api/v1/mission/missions/
<mission file content in request body>
Parameters:#
allow_overwrite: yes / no (optional, no by default)
is_default: yes / no (optional, no by default)
file: mymission_file.tar.gz
Response:#
Success:
Code |
Description |
---|---|
200 |
Successful |
Errors:
Code |
Description |
---|---|
405 |
Request error |
403 |
if mission with same uid is found (allow_overwrite = no) |
415 |
If there is an installation error |
500 |
If there is a server internal error |
507 |
If there is no more space left in internal storage |
550 |
If the signature is invalid |
551 |
If the targetted drone version is invalid |
552 |
If the targetted drone model is invalid |
553 |
If something is wrong in info file (json) |
554 |
If the mission file is invalid/corrupted |
Delete Mission#
Uid of mission to delete is “com.your_company.mymission5”
DELETE /api/v1/mission/mission/com.your_company.missions.mymission5
Parameters:#
uid: com.your_company.missions.mymission5
Response:#
Success:
Code |
Description |
---|---|
200 |
Successful |
Errors:
Code |
Description |
---|---|
405 |
Request error |
403 |
If mission UID to delete is not found |
415 |
If mission deletion failed |