Changing a drone setting - Understand the “expectation” mechanism#

In this example, we will change the “maximum tilt” drone setting. This setting indirectly controls the maximum drone acceleration and speed. The more the drone can tilt, the more the drone gain speed.

The maximum tilt setting itself must be within a minimum and maximum range. A drone with a max tilt value of 0° is not particularly useful while a maximum tilt over 180° might only be useful for a racer drone. For ANAFI the maximum tilt setting must be within 1° and 40°.

You might be wondering:

  • What is happening when you send an invalid setting value (ex: 180°)?

  • How does the drone respond to that?

  • How do we catch this kind of error with Olympe?

Let’s see how this is done in the following example. Some important explanations will follow.

First, reset the simulation (sphinx-cli action -m world fwman world_reset_all in a terminal).

Create the following Python maxtilt.py script somewhere in your home directory:

 1import olympe
 2import os
 3from olympe.messages.ardrone3.PilotingSettings import MaxTilt
 4
 5DRONE_IP = os.environ.get("DRONE_IP", "10.202.0.1")
 6
 7
 8def test_maxtilt():
 9    drone = olympe.Drone(DRONE_IP)
10    drone.connect()
11    maxTiltAction = drone(MaxTilt(10)).wait()
12    if maxTiltAction.success():
13        print("MaxTilt(10) success")
14    elif maxTiltAction.timedout():
15        print("MaxTilt(10) timedout")
16    else:
17        # If ".wait()" is called on the ``maxTiltAction`` this shouldn't happen
18        print("MaxTilt(10) is still in progress")
19    maxTiltAction = drone(MaxTilt(0)).wait()
20    if maxTiltAction.success():
21        print("MaxTilt(0) success")
22    elif maxTiltAction.timedout():
23        print("MaxTilt(0) timedout")
24    else:
25        # If ".wait()" is called on the ``maxTiltAction`` this shouldn't happen
26        print("MaxTilt(0) is still in progress")
27    drone.disconnect()
28
29
30if __name__ == "__main__":
31    test_maxtilt()

This time, the script starts by importing the MaxTilt() command from the ardrone3 feature. Then, it connects to the drone and sends two MaxTilt commands. The first one with a 10° tilt value, the second with a 0° tilt value.

Note that this time, we are assigning into the maxTiltAction variable the object returned by the .wait() method. For now, all you have to know is that you can call .success() -> bool on an “action” object (the more general term is “expectation” object) if you want to know if your command succeeded or not. The success() function just returns True in case of success and False otherwise.

You can also call .timedout() -> bool on an “action” object to know if your command message timed out. This .timedout() method is not particularly useful in this example because we always call .wait() on the action object, so the action is either successful or has timed out.

To execute this script, from the same shell/terminal you have source’d the shell script in:

$ python ./maxtilt.py

If all goes well, you should see the following output in your terminal:

MaxTilt(10) success
MaxTilt(0) timedout

Obviously, the 10° maximum tilt value is correct, so the first command succeeded while the second command failed to set an incorrect 0° maximum tilt value.

It is important to understand how Olympe knows if a particular command succeeded or not. When Olympe sends a command message, it usually implicitly expects an event message in return.

Up until now, we have only explicitly used command messages. Command messages and event messages are somewhat similar. They are both associated with an internal unique ID and eventually with some arguments (ex: the maximum tilt value) and they both travel from one source to a destination.

A command message travel from the controller (Olympe) to the drone while an event message travel the other way around.

Here, when Olympe sends the MaxTilt(10) command message it implicitly expects a MaxTiltChanged(10) event message in return. If the event is received in time, everything is fine: maxTiltAction.success() is True and maxTiltAction.timedout() is False. Otherwise, the maxTiltAction times out (maxTiltAction.success() is False and maxTiltAction.timedout() is True).

The following sequence diagram illustrates what is happening here. For the second maximum tilt command, when Olympe sends the MaxTilt(0) command message it receives a MaxTiltChanged(1) event message because 0° is an invalid setting value, so the drone just informs the controller that it has set the minimum setting value instead (1°). Olympe does not assume that this response means “No, I won’t do what you are asking”. Instead, it still waits for a MaxTiltChanged(0) event that will never come and the command message times out: (maxTiltAction.success() is False and maxTiltAction.timedout() is True). This behavior is identical for every command message: when Olympe sends a command message to a drone, it either result in a success or a timeout.

Setting the drone MaxTilt#

The arsdk protocol defined in arsdk-xml does not provide a way to report errors uniformly. This is why Olympe cannot detect errors like this one and just time out instead. Olympe associates to each command a default timeout that can be overridden with the _timeout message parameter. For example:

maxTiltAction = drone(MaxTilt(10, _timeout=1)).wait()