Moving around - Waiting for a ‘hovering’ flying state#

In this example, we will move our drone around using the moveBy() command message.

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

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

 1import olympe
 2import os
 3from olympe.messages.ardrone3.Piloting import TakeOff, moveBy, Landing
 4
 5DRONE_IP = os.environ.get("DRONE_IP", "10.202.0.1")
 6
 7
 8def test_moveby():
 9    drone = olympe.Drone(DRONE_IP)
10    drone.connect()
11    assert drone(TakeOff()).wait().success()
12    drone(moveBy(10, 0, 0, 0)).wait()
13    assert drone(Landing()).wait().success()
14    drone.disconnect()
15
16
17if __name__ == "__main__":
18    test_moveby()

This script starts by importing the olympe package and then the TakeOff(), moveBy() and Landing() command messages from the ardrone3.Piloting feature module. It then connects to the drone and send the TakeOff(), moveBy() and Landing() commands.

This script should work as-is, right? Let’s see.

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

$ python ./moveby.py

The output of this script should be:

moveBy timedout

Wait! The drone takes off and then eventually lands without performing the moveBy?! What happened?

When olympe sends a command message to the drone it expects an acknowledgment event message from the drone in return. In this script, drone(TakeOff()).wait() sends the TakeOff() command to the drone and then waits for the drone taking off event message as an acknowledgment from the drone. Olympe knows that after a TakeOff() command it should expect a FlyingStateChanged(state='takingoff') and automatically waits for that event for you.

The problem with the moveBy() command is that it is rejected by the drone as long as the drone is not in the “hovering” flying state. In this case it is rejected because after the TakeOff() command the drone is in takingoff flying state. So, to fix this script we will have to wait for the hovering state before sending the moveBy() command. The following sequence diagram illustrates what is happening with this first attempt to use the moveBy() command.

blockdiag Olympe Drone takeOffAction pending takeOffAction successful takeOffAction successful moveByAction pending silently rejected, moveBy is unavailable moveBy available moveByAction timedout connect connected TakeOff() FlyingStateChanged(state='motor_ramping') FlyingStateChanged(state='takingoff') moveBy() FlyingStateChanged(state='hovering') disconnect disconnected

Attempt to use the moveBy command#

Edit moveby.py with the following corrected script:

 1import olympe
 2import os
 3from olympe.messages.ardrone3.Piloting import TakeOff, moveBy, Landing
 4from olympe.messages.ardrone3.PilotingState import FlyingStateChanged
 5
 6DRONE_IP = os.environ.get("DRONE_IP", "10.202.0.1")
 7
 8
 9def test_moveby2():
10    drone = olympe.Drone(DRONE_IP)
11    drone.connect()
12    assert drone(
13        TakeOff()
14        >> FlyingStateChanged(state="hovering", _timeout=5)
15    ).wait().success()
16    assert drone(
17        moveBy(10, 0, 0, 0)
18        >> FlyingStateChanged(state="hovering", _timeout=5)
19    ).wait().success()
20    assert drone(Landing()).wait().success()
21    drone.disconnect()
22
23
24if __name__ == "__main__":
25    test_moveby2()

This new script will wait for the hovering state after each command sent to the drone. To do that, it imports the FlyingStateChanged() event message from the same ardrone3.PilotingState module feature.

Note: The expectations for each command message are defined in the arsdk-xml source repo along with the command and event messages themselves.

 9def test_moveby2():
10    drone = olympe.Drone(DRONE_IP)
11    drone.connect()
12    assert drone(

In this new example after the drone connection, the above code tells Olympe to:

  1. Send the TakeOff() command

  2. Then, to implicitly wait for the expectations of the TakeOff() command: FlyingStateChanged(state='takingoff')

  3. Then, to explicitly wait for the drone hovering flying state event: FlyingStateChanged(state='hovering')

Here, the drone() functor accepts more than just a command message. The drone() takes an expression that may be a combination of command and event messages to process. The “>>” operator is used to combine two expressions with an “and then” semantic. This example could be read as “Take off and then wait a maximum of 5 seconds for the ‘hovering’ flying state”).

The rest of the example should be easy to understand now. After the drone has taken off, this script waits for the drone “hovering” state and then sends the moveBy command, waits for the “hovering” state again and then sends the landing command. The following sequence diagram illustrates this second (successful) attempt to use the moveBy() command.

blockdiag Olympe Drone takeOffAction pending takeOffAction pending takeOffAction successful waiting for FlyingStateChanged(state='hovering') moveBy available moveByAction pending moveByAction successful connect connected TakeOff() FlyingStateChanged(state='motor_ramping') FlyingStateChanged(state='takingoff') FlyingStateChanged(state='hovering') moveBy() moveByEnd() disconnect disconnected

Using the moveBy command#

Let’s check everything works! Reset the simulation (sphinx-cli action -m world fwman world_reset_all in a terminal) and execute this script, from the same shell/terminal you have source’d the shell script:

$ python ./moveby.py

And it should work now! The drone should take off, perform a forward move by 10 meters and then land.