# Payloads and Cameras

PX4 supports a wide range of payloads and cameras.

Payloads are connected to Fight Controller outputs, and can generally be triggered automatically in missions, or manually using RC passthrough, mapping to a joystick, or MAVLink/MAVSDK commands.


Payloads (actuators) can be tested in the pre-arm state, which disables motors but allows actuators to move. This may be safer than testing when the vehicle is armed.

# Mapping Drones

Mapping drones use cameras to capture images at time or distance intervals during surveys.

MAVLink cameras that support the MAVLink Camera Protocol (opens new window) provide the best integration with PX4 and QGroundControl. The MAVSDK provides simple APIs to use this protocol for both standalone camera operations (opens new window) and in missions (opens new window).

Cameras can also be connected directly to a flight controller using PWM or GPI outputs. PX4 supports the following set of MAVLink commands/mission items for cameras that are connected to the flight controller:

The following topics show how to connect and configure a camera:

# Cargo Drones (Package Delivery)

Cargo drones commonly use grippers, winches, and mechanisms to release packages at their destinations.

PX4 supports package delivery in missions using a gripper (support for winches and other release mechanism is also intended). PX4 also supports generic actuator triggering using both RC Control and MAVLink commands.


Prefer using a gripper (or other integrated hardware) to generic actuator triggering when possible. This makes missions easier to write, more predictable, and more reusable. The main reason to use generic actuator triggering is when RC triggering is required, or you need to use release hardware that is not integrated.

# Package Delivery in Missions

PX4 supports package delivery in missions using a Gripper (support for winches and other release mechanism is also intended).

This is recommended because with properly configured hardware, it is much easier to create missions that are predictable, reusable, and safe.

Grippers can also be triggering using the MAV_CMD_DO_GRIPPER (opens new window) MAVLink command, or manually via a Joystick button.

For setup and usage information see:

# Generic Actuator Control with RC

Up to 6 autopilot PWM or CAN outputs can be controlled using RC channels. The outputs that are to be controlled are specified in the Actuators configuration screen by assigning the functions RC AUX 1 to RC AUX 6 to the desired actuator outputs.

To map a particular RC channel to an output function RC AUX n (and hence it's assigned output) you use the RC_MAP_AUXn parameter that has the same n number.

For example, to control an actuator attached to AUX pin 3 (say) you would assign the output function RC AUX 5 to the output AUX3. You could then use set the RC channel to control the AUX3 output using RC_MAP_AUX5.

MAV_CMD_DO_SET_ACTUATOR (opens new window) can be used in a mission or as a command to set the value of up to 6 actuators (at a time). This command can be used in missions or as a stand alone command.

The outputs that are to be controlled are specified in the Actuators configuration screen by assigning the functions Offboard Actuator Set 1 to Offboard Actuator Set 6 to the desired actuator outputs.

Generic actuator output setting in QGC

MAV_CMD_DO_SET_ACTUATOR param1 to param6 control the outputs mapped by Offboard Actuator Set 1 to Offboard Actuator Set 6 respectively.

For example, in the image above, the AUX5 output is assigned the function Offboard Actuator Set 1 function. To control the actuator attached to AUX5 you would set the value of MAV_CMD_DO_SET_ACTUATOR.param1.

# MAVSDK (Example script)

The following MAVSDK (opens new window) example code (opens new window) shows how to trigger payload release using the MAVSDK Action plugin's set_actuator() (opens new window) method.

The set_actuator() index values map to the MAVLink payload outputs defined for your airframe.


sends the MAV_CMD_DO_SET_ACTUATOR (opens new window) MAVLink command under the hood.

#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/action/action.h>
#include <chrono>
#include <cstdint>
#include <iostream>
#include <future>

using namespace mavsdk;

void usage(const std::string& bin_name)
    std::cerr << "Usage :" << bin_name << " <connection_url> <actuator_index> <actuator_value>\n"
              << "Connection URL format should be :\n"
              << " For TCP : tcp://[server_host][:server_port]\n"
              << " For UDP : udp://[bind_host][:bind_port]\n"
              << " For Serial : serial:///path/to/serial/dev[:baudrate]\n"
              << "For example, to connect to the simulator use URL: udp://:14540\n";

int main(int argc, char** argv)
    if (argc != 4) {
        return 1;

    const std::string connection_url = argv[1];
    const int index = std::stod(argv[2]);
    const float value = std::stof(argv[3]);

    Mavsdk mavsdk;
    const ConnectionResult connection_result = mavsdk.add_any_connection(connection_url);

    if (connection_result != ConnectionResult::Success) {
        std::cerr << "Connection failed: " << connection_result << '\n';
        return 1;

    std::cout << "Waiting to discover system...\n";
    auto prom = std::promise<std::shared_ptr<System>>{};
    auto fut = prom.get_future();

    // We wait for new systems to be discovered, once we find one that has an
    // autopilot, we decide to use it.
    mavsdk.subscribe_on_new_system([&mavsdk, &prom]() {
        auto system = mavsdk.systems().back();

        if (system->has_autopilot()) {
            std::cout << "Discovered autopilot\n";

            // Unsubscribe again as we only want to find one system.

    // We usually receive heartbeats at 1Hz, therefore we should find a
    // system after around 3 seconds max, surely.
    if (fut.wait_for(std::chrono::seconds(3)) == std::future_status::timeout) {
        std::cerr << "No autopilot found, exiting.\n";
        return 1;

    // Get discovered system now.
    auto system = fut.get();

    // Instantiate plugins.
    auto action = Action{system};

    std::cout << "Setting actuator...\n";
    const Action::Result set_actuator_result = action.set_actuator(index, value);

    if (set_actuator_result != Action::Result::Success) {
        std::cerr << "Setting actuator failed:" << set_actuator_result << '\n';
        return 1;

    return 0;

# Surveillance, Search & Rescue

Surveillance and Search & Rescue drones have similar requirements to mapping drones. The main differences are that, in addition to flying a planned survey area, they typically need good standalone control over the camera for image and video capture, and they may need to be able to work during both day and night

Use a camera that supports the MAVLink Camera Protocol (opens new window) as this supports image and video capture, zooming, storage management, multiple cameras on the same vehicle and switching between them, etc. These cameras can be controlled either manually from QGroundControl or via MAVSDK (for both standalone camera operations (opens new window) and in missions (opens new window)). See Camera triggering for information on how to configure your camera to work with MAVLink.


Cameras connected directly to the flight control only support camera triggering, and are unlikely to be suitable for most surveillance/search work.

A search and rescue drone may also need to carry cargo, for example, emergency supplies for a stranded hiker. See Cargo Drones above for information about payload delivery.