Using the drone’s sensors

Parrot calls the AR.Drone sensor data “NavData”, short for navigation data, so we do, too.

Starting with some theory:
NavData is sent in one block including the sensor-measurements and some status information; it consists of bunch of 28 packages, each containing a specific set of values. The packages are named in this API as they are named by Parrot in their SDK.

The available packages are:
"demo", "time", "raw_measures", "phys_measures", "gyros_offsets", "euler_angles", "references", "trims", "rc_references", "pwm", "altitude", "vision_raw", "vision_of", "vision", "vision_perf", "trackers_send", "vision_detect", "watchdog", "adc_data_frame", "video_stream", "games", "pressure_raw", "magneto", "wind_speed", "kalman_pressure", "hdvideo_stream", "wifi", "zimmu_3000" and "chksum".

For some reasons, I am going to speak about “time-units” now. A time-unit (TU) is the time from getting a NavData to getting the next. The drone knows two modes for sending its NavData, a “demo”- and a “full”-mode. Depending on its mode, there are 15 or 200 NavData sent per second which means that a second is divided into 15, respectively 200 time-units.

The AR.Drone 2.0 sends its NavData in a UDP-package. This means that the drone keeps on sending without caring about whether its NavData is being received. So there is a possibility of lost or false information. However, it has become apparent that no false NavData is received, but 3% or more gets lost.

There is also a difference between the available NavData-packages depending on whether the demo-mode is enabled or disabled:
With enabled demo-mode, just the packages "demo", "vision_detect" and "chksum" are (by default) available 15 times a second; however, most of the time, this is enough.
With disabled demo-mode, (by default) all 28 packages are sent 200 times per second.
State-tags are also available. They are, like most packages, not very important right now, but re always sent with the NavDatas header.

The drone's state and its NavData are stored in the variable State or respectively NavData. The variable NavDataCount shows the count of the drone's sent NavData. There are also the variables NavDataTimeStamp and NavDataDecodingTime, representing the time when the last NavData was received by the PS-Drone-API and how long it took to decode it. Make sure that decoding time is less then a time-unit.

##### Suggested clean drone startup sequence #####
import time, sys
import ps_drone                                    # Import PS-Drone-API

drone = ps_drone.Drone()                           # Start using drone
drone.startup()                                    # Connects to drone and starts subprocesses

drone.reset()                                      # Sets drone's status to good
while (drone.getBattery()[0]==-1): time.sleep(0.1) # Wait until drone has done its reset
print "Battery: "+str(drone.getBattery()[0])+"% "+str(drone.getBattery()[1]) # Battery-status
drone.useDemoMode(True)                            # Set 15 basic dataset/sec (default anyway)
drone.getNDpackage(["demo"])                       # Packets, which shall be decoded
time.sleep(0.5)                                    # Give it some time to awake fully after reset

##### Mainprogram begin #####
NDC =   drone.NavDataCount
state = 0
end =   False
while not end:
    while drone.NavDataCount==NDC:  time.sleep(0.001) # Wait for the next NavData
    if drone.getKey():
        state+=1
        if state == 1:  drone.addNDpackage(["demo"])  # Add "demo" to the list of packages
        if state == 2:  drone.getNDpackage(["all"])   # Only get following packages
        if state == 3:  drone.delNDpackage(["all"])   # Delete "all" from list of packages
        if state == 3:  drone.useDemoMode(False)      # switch to full-mode (switches delayed)
        if state == 4:  drone.addNDpackage(["demo"])
        if state == 5:  drone.getNDpackage(["all"])
        if state > 5:   sys.exit()

    print "------------------"
    if state == 0: print "##### Demo Mode: On   , NavData-Packages: None"
    if state == 1: print "##### Demo Mode: On   , NavData-Packages: Demo"
    if state == 2: print "##### Demo Mode: On   , NavData-Packages: All"
    if state == 3: print "##### Demo Mode: Off  , NavData-Packages: None"
    if state == 4: print "##### Demo Mode: Off  , NavData-Packages: Demo"
    if state == 5: print "##### Demo Mode: Off  , NavData-Packages: All"

    if drone.NavDataCount-NDC>1:   print "Lost "+str(drone.NavDataCount-NDC-1)+" NavData"
    print "Number of package : "+str(drone.NavDataCount)
    print "Receifetime :       "+str(drone.NavDataTimeStamp)+" , \t"\
                                +str(time.time()-drone.NavDataTimeStamp)+" sec ago"
    print "Time to decode :    "+str(drone.NavDataDecodingTime)
    print "Included packages : "+str(drone.NavData.keys())
    print "State-data :        "+str(drone.State)
    try:    print "Demo-data :         "+str(drone.NavData["demo"])
    except: pass
    NDC = drone.NavDataCount
Download sample firstNavData.py

While a program-loop using NavData, it is suggested to wait for the next time-unit by using the NavDataCount as shown in the previous example.

getNDpackage() sets the exact list of packages which will be decoded. With the commands addNDpackage() and delNDpackage() a couple of packages can be added to, or deleted from the decoding list.

You start, for example, with getNDpackage(["demo","time"]) and do later addNDpackage(["altitude"]) and delNDpackage(["time"]), the decoding would as if setting getNDpackage(["demo","altitude"]). There is no need to put the entries into a particular order.

Possible entries are the names of the packages, but also "all" for the complete set of packages:
"demo", "time", "raw_measures", "phys_measures", "gyros_offsets", "euler_angles", "references", "trims", "rc_references", "pwm", "altitude", "vision_raw", "vision_of", "vision", "vision_perf", "trackers_send", "vision_detect", "watchdog", "adc_data_frame", "video_stream", "games", "pressure_raw", "magneto", "wind_speed", "kalman_pressure", "hdvideo_stream", "wifi", "zimmu_3000" "chksum" and "all".

Most of the packages and their included values are not very well documented; this tutorial will focus on the most important packages. For further and more comprehensive information, please take a look at the documentary and at the sourcecode of “ps_prone.py”.

Note: Some measurements are not available when the drone is not in flight-mode. If it is on the ground, some values will stay “0”.

This tutorial will show the most important values for the packages, like State, "demo", "magneto", "pressure_raw", "altitude", "kalman_pressure", "wind_speed", "pwm" and "vision_detect".

State:
Pos
Name
0:
1:
[10]
[12]
[15]
[18]
[20]
[21]
[31]
NavData demo
Motors status
Batterystatus
Magnetometer calib
Wind mask
Ultrasonic sensor
Emergency landing
All NavData
OK
OK
No calibration needed
OK
OK
No emergency
NavData demo
Problem
Too low
Calibration needed
Too much wind
Deaf
Emergency

"demo"-package:
Shows the most important values at all, like some status-tags and information about slope, acceleration and battery charge.
Pos
Note
[0][2]
[0][3]
[0][4]
[1]
[2][0]
[2][1]
[2][2]
[3]
[4][0]
[4][1]
[4][2]
Status-tag for "landed"-Drone is on the ground or not fully flying
Status-tag for "flying"-Drone is flying
Status-tag for "hovering"-Name should be:"landing", the drone is landing
Battery-status in percent
Pitch in degree (front/back)
Roll in degree (left/right)
Yaw in degree (turn)
Altitude in cm (only when flying)
Estimated speed in X in mm/s (forward/backward, only when flying)
Estimated speed in Y in mm/s (left/right, only when flying)
Estimated speed in Z in mm/s (up/down, only when flying)


Status-tags while taking off and landing of an AR.Drone 2.0


"magneto"-package:
Pos
Note
[1]
[3]
Magnetometer values for X, Y and Z
Raw magnetometer values for X, Y and Z

"pressure_raw"-package:
Pos
Note
[1]
A raw value, the height is calculable, the higher the drone flies the lower the value (about 80cm per count)

"altitude"-package:
Pos
Note
[3]Altitude in mm

"kalman_pressure"-package:
Pos
Note
[1]
Estimated height (only when flying)

"wind_speed"-package:
Pos
Note
[0]
[1]
Windspeed (only when flying)
Angle of wind (only when flying)

"pwm"-package:
Pos
Note
[0][0]
[0][1]
[0][2]
[0][3]
Shows the actual pwm-value for the motor onthe front left
Shows the actual pwm-value for the motor on the front right
Shows the actual pwm-value for the motor on the back right
Shows the actual pwm-value for the motor on the back left

"vision_detect"-package:
Pos
Note
[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[9]
Number of detected marker (max 4)
List of the types of detected markers
List of the X-positions of detected markers
List of the Y-positions of detected markers
List of the dimensional width of detected markers
List of the dimensional depth of detected markers
List of the distances of detected markers
List of the orientation angles of detected markers
List of the rotations of detected markers

"chksum"-package:
Pos
Note
[0]
[1]
Checksum
Quality: incorrect/correct

##### Suggested clean drone startup sequence #####
import time, sys
import ps_drone                                    # Import PS-Drone-API

drone = ps_drone.Drone()                           # Start using drone
drone.startup()                                    # Connects to drone and starts subprocesses

drone.reset()                                      # Sets drone's status to good
while (drone.getBattery()[0]==-1): time.sleep(0.1) # Wait until drone has done its reset
print "Battery: "+str(drone.getBattery()[0])+"% "+str(drone.getBattery()[1]) # Battery-status
drone.useDemoMode(False)                           # Give me everything...fast
drone.getNDpackage(["demo","pressure_raw","altitude","magneto","wifi"]) # Packets to decoded
time.sleep(0.5)                                    # Give it some time to awake fully after reset

##### Mainprogram begin #####
NDC = drone.NavDataCount
end = False
while not end:
    while drone.NavDataCount==NDC:  time.sleep(0.001) # Wait until next time-unit
    if drone.getKey():              end = True        # Stop if any key is pressed
    NDC=drone.NavDataCount
    print "-----------"
    print "Aptitude [X,Y,Z] :            "+str(drone.NavData["demo"][2])
    print "Altitude / sensor / pressure: "+str(drone.NavData["altitude"][3])+" / "\
          +str(drone.State[21])+" / "+str(drone.NavData["pressure_raw"][0])
    print "Megnetometer [X,Y,Z]:         "+str(drone.NavData["magneto"][0])
    print "Wifi link quality:            "+str(drone.NavData["wifi"])
Download sample getNavData.py