The Telemetry class provides simple methods for getting vehicle telemetry, including state and flight mode information.

All the methods have both synchronous and asynchronous versions, and users can set the rate at which the vehicle provides updates for each type of information.

All the methods of a particular type (synchronous, asynchronous, and set_rate methods) are used in the same way.

API Overview

The Telemetry API provides methods to return the following types of information:

  • Position - latitude and longitude in degrees, and altitude relative to sea level and to the takeoff altitude.
  • Battery - voltage and percentage power remaining.
  • GroundSpeedNED - velocity components in NED coordinates.
  • Vehicle attitude/orientation - as a Quaternion or EulerAngle
  • GPSInfo - type of fix, if any, and number of satellites.
  • Health - calibration status of various sensors and confirmation that position estimates are good enough for position control.
  • RCStatus - connection status, signal strength, and whether RC has ever been connected.

In addition there are a number of methods that return vehicle "state":

  • Current flight mode (FlightModes).
  • Whether the vehicle is "all healthy" (aggregates the vehicle Health information). This is used to check if the vehicle is ready to arm.
  • Whether the vehicle is armed/disarmed.
  • Whether the vehicle is flying/in air.

Setting the Update Rate

The telemetry update rate determines the frequency at which callbacks will be invoked with new information, and also the probable "freshness" of data obtained when using synchronous telemetry APIs. The default update rate depends on the autopilot and may also be limited by the characteristics of the communications channel. You can set the rate for each type of telemetry, and both synchronous or asynchronous rate-setting methods are provided.

For PX4 running on hardware the default rates are set on a per-mode basis in mavlink_main.cpp (search on configure_stream). For PX4 running on SITL, the default rates are defined in the init file.

The rate-setting methods are all used in the same way, so we just show one example for both the asynchronous and synchronous methods below. In both cases we set the rate for position updates.

To set the position update rate synchronously (in this case using set_rate_position()):

// Set position update rate to 1 Hz.
const Telemetry::Result set_rate_result = dc.device().telemetry().set_rate_position(1.0);
if (set_rate_result != Telemetry::Result::SUCCESS) {
    // handle rate-setting failure (in this case print error)
    std::cout << "Setting rate failed:" << Telemetry::result_str(set_rate_result) << std::endl;

To set the position update rate asynchronously with set_rate_position_async() (here we use a promise to block until we have a result):

    std::cout << "Setting rate updates..." << std::endl;

    auto prom = std::make_shared<std::promise<Telemetry::Result>>();
    auto future_result = prom->get_future();
    // Set position update rate to 1 Hz.
    device.telemetry().set_rate_position_async(1.0, [prom](Telemetry::Result result) {
        prom->set_value(result); //fulfill promise

    //Block until promise is fulfilled (in callback function)
    const Telemetry::Result result = future_result.get();
    if (result != Telemetry::Result::SUCCESS) {
        // handle rate-setting failure (in this case print error)
        std::cout << "Setting telemetry rate failed (" << Telemetry::result_str(result) << ")." << std::endl;

Getting Regular Updates

The best way to get telemetry updates is to use the asynchronous methods. These methods are non-blocking - they take a callback function argument and return immediately. The callback will be invoked with a populated struct of the associated type as soon as an update message arrives from the vehicle. The rate at which this occurs can be set through the API as discussed above.

For example, the Telemetry::position_async() has the following prototype, where position_callback_t is called with a populated Position:

void dronecore::Telemetry::position_async(position_callback_t callback)

The code fragment below shows this method being use with a lambda function for the callback, which simply prints out the current position and altitude).

device.telemetry().position_async([](Telemetry::Position position) {
    std::cout << "Altitude: " << position.relative_altitude_m << " m" << std::endl
              << "Latitude: " << position.latitude_deg << std::endl
              << "Longitude: " << position.longitude_deg << std::endl;

Detecting Changes (only)

The asynchronous callbacks are updated every time new information is provided by the vehicle. For some types of telemetry you may only wish to report only when the value changes.

The example below shows how to use flight_mode_async() to report only when the current flight mode changes. The example uses a lambda function callback that captures a variable for the last mode. This variable is compared to the current flight mode to determine whether the value has changed and needs to be reported.

// Set up callback to monitor flight mode 'changes' 
Telemetry::FlightMode oldFlightMode=Telemetry::FlightMode::UNKNOWN;
device.telemetry().flight_mode_async([&oldFlightMode](Telemetry::FlightMode flightMode) {
    if (oldFlightMode != flightMode) {
        //Flight mode changed. Print!
        std::cout << "FlightMode: " << Telemetry::flight_mode_str(flightMode) << std::endl;
        oldFlightMode=flightMode; //Save updated mode.

This same approach can be used to report only messages that meet some condition.

In future we may add a mechanism in the API to support just reporting changes: Issue #63.

Blocking Telemetry Requests (State Management)

Some commands/vehicle operations must be performed in a certain sequence, or can only be called when the vehicle reaches a certain state. For example, in order to takeoff the vehicle must first be armed, and in order to arm, the vehicle must have a home position/GPS lock. For these cases you will want to monitor for the vehicle being in a certain state and block other commands until it is ready to proceed.

Often the easiest approach is to use synchronous methods and poll for the result. For example, the following code shows how you might poll for whether the vehicle is ready to arm (health_all_ok()).

// Check if vehicle is ready to arm
while (!device.telemetry().health_all_ok()) {
    std::cout << "Vehicle not ready to arm" << std::endl;
// now ready to arm ...

Similarly, you can use the asynchronous method and block

    std::cout << "Waiting for device to be ready" << std::endl;
    auto prom = std::make_shared<std::promise<void>>();
    auto future_result = prom->get_future();
    [prom](bool result) {
        //fulfill promise if health is OK
        if (result) {// health OK

    future_result.get(); //Block until promise is fulfilled.
    // Now ready to arm

Depending on the architecture of your application, you may even wish to arm the vehicle in your callback function. Usually though it is easier to understand program flow using the approach above.

Further Information

Additional information/examples for the Telemetry API are linked below:

© Dronecode 2017. License: CC BY 4.0            Updated: 2018-02-01 00:34:22

results matching ""

    No results matching ""