0
0
Pcb-designHow-ToBeginner · 4 min read

How to Write a PX4 Module: Step-by-Step Guide

To write a PX4 module, create a C++ class inheriting from ModuleBase, implement required methods like task_spawn and run, and register the module in the build system. This module runs as a separate task in the PX4 autopilot environment.
📐

Syntax

A PX4 module is a C++ class that inherits from ModuleBase. It must implement static methods like task_spawn to start the module and print_usage to show help. The run method contains the main loop logic.

Key parts:

  • task_spawn: Starts the module task.
  • run: Main execution loop.
  • print_usage: Shows usage info.
  • ModuleBase: Base class for PX4 modules.
c++
#include <px4_platform_common/module.h>

class MyModule : public ModuleBase<MyModule> {
public:
    static int task_spawn(int argc, char *argv[]) {
        MyModule *instance = new MyModule();
        if (instance) {
            _object.store(instance);
            _task_id = task_id_is_work_queue;
            instance->run();
            return 0;
        }
        return -1;
    }

    static int print_usage(const char *reason = nullptr) {
        if (reason) {
            PX4_WARN("%s", reason);
        }
        PX4_INFO("Usage: my_module {start|stop|status}");
        return 0;
    }

    void run() {
        PX4_INFO("MyModule running");
        // Main loop here
    }

private:
    MyModule() = default;
};
💻

Example

This example shows a simple PX4 module that prints a message once and exits. It demonstrates how to define the module class, implement task_spawn, and run the module.

c++
#include <px4_platform_common/module.h>

class HelloModule : public ModuleBase<HelloModule> {
public:
    static int task_spawn(int argc, char *argv[]) {
        HelloModule *instance = new HelloModule();
        if (instance) {
            _object.store(instance);
            _task_id = task_id_is_work_queue;
            instance->run();
            return 0;
        }
        return -1;
    }

    static int print_usage(const char *reason = nullptr) {
        if (reason) {
            PX4_WARN("%s", reason);
        }
        PX4_INFO("Usage: hello_module {start|stop|status}");
        return 0;
    }

    void run() {
        PX4_INFO("Hello from PX4 module!");
    }

private:
    HelloModule() = default;
};

extern "C" __EXPORT int hello_module_main(int argc, char *argv[]) {
    return HelloModule::main(argc, argv);
}
Output
Hello from PX4 module!
⚠️

Common Pitfalls

Common mistakes when writing PX4 modules include:

  • Not properly registering the module with extern "C" __EXPORT function, so PX4 cannot start it.
  • Forgetting to implement task_spawn or run methods, causing the module to not run.
  • Not handling task cleanup or exit conditions, which can cause resource leaks.
  • Using blocking calls inside run without yielding, which can freeze the autopilot.
c++
// Wrong: Missing extern "C" export
class BadModule : public ModuleBase<BadModule> {
public:
    void run() {
        PX4_INFO("BadModule running");
    }
};

// Right: Proper export and main
extern "C" __EXPORT int bad_module_main(int argc, char *argv[]) {
    return BadModule::main(argc, argv);
}
📊

Quick Reference

Summary tips for PX4 module development:

  • Always inherit from ModuleBase template.
  • Implement task_spawn, run, and print_usage.
  • Export the main function with extern "C" __EXPORT.
  • Use PX4 logging macros like PX4_INFO for output.
  • Keep run non-blocking or use sleep/yield properly.

Key Takeaways

PX4 modules are C++ classes inheriting from ModuleBase with specific static methods.
Implement task_spawn to start the module and run for main logic.
Always export the main function with extern "C" __EXPORT for PX4 to recognize the module.
Avoid blocking calls in run to keep the autopilot responsive.
Use PX4 logging macros for clear debug output.