PX4模块设计之十七:ModuleBase模块

本文详细解读了PX4模块设计中的ModuleBase类,介绍了其核心功能如模块入口、启动、停止、状态查询、任务回调及辅助函数。重点讲解了如何实现基础指令和模块的生命周期管理。

1. ModuleBase模块介绍

ModuleBase模块是一个基础类,主要完成各个模块需要的基础功能,比如:start, stop, status命令,但是目前尚不支持多实例(类似mavlink模块多实例应用)。

当继承自该类的模块:

  • 必须完成以下函数实现:
  1. static int task_spawn(int argc, char *argv[])
  2. static T *instantiate(int argc, char *argv[])
  3. static int custom_command(int argc, char *argv[])
  4. static int print_usage(const char *reason = nullptr)
  • 根据情况重构以下函数实现:
  1. virtual int print_status()
  2. virtual void run()
  3. virtual void request_stop()

2. ModuleBase类介绍

这是一个UML绘图工具绘制的ModuleBase类定义(给出一个整体的picture)。

ModuleBase类 UML图
注:由于PX4的代码已经都完成了实现,从代码上逆向回来的UML图,所以感觉很细(很具体化);设计上的一些内容(注释,考虑,场景分析等)看不太出来。如果自上而下的UML设计,会注意到有非常多的描述。这里只是用了UML画个图,做个整体的了解。知道这个类有哪些函数、参量,以及public/protected/private属性。所以不再去考虑和分析设计这个类的时候设计人员的想法(也无从得知)。

3. ModuleBase类功能介绍

3.1 模块入口

ModuleBase::main
 ├──> <argc <= 1 且 命令参数非 "-h"/"help"/"info"/"usage">
 │   └──> return T::print_usage();                                //【必须实现】的函数
 ├──> <命令参数 "start">
 │   └──> return start_command_base(argc - 1, argv + 1);
 ├──> <命令参数 "status">
 │   └──> return status_command();
 ├──> <命令参数 "stop">
 │   └──> return stop_command();
 ├──> lock_module(); // Lock here, as the method could access _object.
 ├──> int ret = T::custom_command(argc - 1, argv + 1);            //【必须实现】的函数
 └──> unlock_module();

在PX4飞控系统代码中模块入口采用的是_main来作为app应用入口的。这里只是ModuleBase::main,在实际符号链接之前要做转换。我们以logger模块为例:

int logger_main(int argc, char *argv[])
{
	// logger currently assumes little endian
	int num = 1;

	if (*(char *)&num != 1) {
		PX4_ERR("Logger only works on little endian!\n");
		return 1;
	}

	return Logger::main(argc, argv);
}

此时logger_main是logger模块的应用入口,然后【PX4模块设计之十一:Built-In框架】通过CMakelist将logger模块的应用入口编译和链接到系统中。

注:main的写法与【Linux应用程序之Helloworld入门】里面的入口main一致,符合常规习惯。

3.2 模块启动

检查是否已在运行,如果尚未运行,则调用T::task_spawn()。

ModuleBase::start_command_base
 ├──> lock_module();
 ├──> <is_running()>
 │   └──> PX4_ERR("Task already running");
 ├──> <else>
 │   └──> ret = T::task_spawn(argc, argv);                    //【必须实现】的函数
 └──> unlock_module();

3.3 模块停止

检查模块是否正在运行,如果正在运行,则请求模块停止并等待任务完成。

ModuleBase::stop_command
 ├──> lock_module();
 ├──> <is_running()>
 │   ├──> T *object = _object.load();
 │   ├──> <object>
 │   │   ├──> object->request_stop();  // 发布stop应用指令
 │   │   └──> do {} while (_task_id != -1);
 │   │       ├──> unlock_module();
 │   │       ├──> px4_usleep(10000); // 10 ms, 定期循环查询_task_id是否==-1(满足条件表明模块自己已经优雅退出)
 │   │       ├──> lock_module();
 │   │       └──> <++i > 500 && _task_id != -1>  // wait at most 5 sec
 │   │           ├──> PX4_ERR("timeout, forcing stop");
 │   │           ├──> <_task_id != task_id_is_work_queue>  // 如果已经创建task,需要强制删除任务
 │   │           │   └──> px4_task_delete(_task_id);
 │   │           ├──> _task_id = -1;
 │   │           ├──> delete _object.load();
 │   │           ├──> _object.store(nullptr);
 │   │           └──> break
 │   └──> <else>
 │       └──> _task_id = -1;
 └──> unlock_module();

3.4 状态查询

检查是否正在运行,如果正在运行,则调用print_status()。

ModuleBase::status_command
 ├──> lock_module();
 ├──> <is_running() && _object.load()>
 │   ├──> T *object = _object.load();
 │   └──> ret = object->print_status();
 ├──> <else>
 │   └──> PX4_ERR("failed to instantiate object");
 └──> unlock_module();

3.5 任务回调

创建任务以后,ModuleBase通过px4_task_spawn_cmd封装了任务入口函数run_trampoline。

ModuleBase::run_trampoline
 ├──> T *object = T::instantiate(argc, argv);                //【必须实现】的函数
 ├──> _object.store(object);
 ├──> <object>
 │   └──> object->run();
 ├──> <else>
 │   └──> PX4_ERR("failed to instantiate object");
 └──> exit_and_cleanup

3.6 辅助函数

static bool is_running()                                       //判断模块是否已经启动
bool should_exit()                                             //判断模块是否需要退出
static void exit_and_cleanup()                                 //清除当前模块对象(清空指针)
static int wait_until_running(int timeout_ms = 1000)           //等待实例初始化完成,可以在task_spawn最初阶段
static T *get_instance()                                       // 获取当前模块实例

4. 总结

ModuleBase类总体上看类似一个简单封装,将模块设计的基本框架搭建好了,完成最为基本的start/stop/status功能。关于具体是否创建任务(线程),还是使用工作队列,ModuleBase类都没有具体给出。

关于模块是否采用任务(T::task_spawn内部实现),还是采用WorkQueue(继承WorkItem实现),在后续章节中再做深入。

5. 参考资料

【1】PX4开源软件框架简明简介
【2】Linux应用程序之Helloworld入门
【3】PX4模块设计之十一:Built-In框架
【4】PX4模块设计之十三:WorkQueue设计

<think> 嗯,用户询问PX4中自定义飞行模式与自定义模块的区别。需要结合之前的引用内容来分析这个问题。 根据引用[1],PX4-ROS2接口库允许开发者创建自定义飞行模式,比如手动模式和目标点飞行模式。引用[2][3]进一步说明了PX4飞行模式相关的模块设计,特别是FlightModeManager模块的作用。引用[4]则提到了添加自定义模块的方法,比如编辑Kconfig文件。 自定义飞行模式应该是在FlightModeManager框架内实现的特定飞行行为,比如悬停或巡航。而自定义模块可能是更底层的功能组件,比如导航算法或传感器驱动,它们可以独立于飞行模式存在。 从架构角度看,飞行模式依赖于FlightModeManager模块,而自定义模块可以注册到NuttX应用列表。开发流程上,飞行模式需要继承FlightTask基类,而自定义模块有独立的编译配置方式。 用户可能是PX4开发者,想了解如何扩展飞控功能。需要区分这两个概念的应用场景:飞行模式针对具体飞行行为,自定义模块用于系统功能扩展。可以准备一些相关问题帮助用户深化理解。 回答时会采用表格对比形式,清晰展示两者在定义、位置、开发方式等方面的差异。同时设计相关问题,覆盖开发实践和应用场景。 </think>在PX4飞控系统中,**自定义飞行模式**和**自定义模块**是两种不同层级的扩展方式,主要区别如下: ### 一、核心区别对比 | **特性** | **自定义飞行模式** | **自定义模块** | |------------------|---------------------------------------------|------------------------------------------| | **定义** | 特定飞行行为的逻辑封装(如悬停、巡航) | 独立功能单元(如传感器处理、控制算法) | | **架构位置** | 位于`FlightModeManager`框架内 | 可独立注册到PX4模块系统 | | **开发方式** | 继承`FlightTask`基类并实现接口 | 通过`ModuleBase`创建独立线程/周期任务 | | **依赖关系** | 强依赖飞行模式管理器 | 可独立运行或与其他模块低耦合交互 | | **典型应用** | 实现手动模式、目标点飞行等特定行为 | 添加新传感器驱动、自定义控制器等 | --- ### 二、技术实现差异 1. **自定义飞行模式** - 通过创建`FlightTask`子类实现(如`FlightTaskManual`) - 必须注册到`FlightModeManager`的任务池: ```cpp // 在FlightModeManager初始化中注册 _flight_tasks.registerTaskFactory(FlightTaskIndex::MyCustomMode, FlightTaskFactory::create<FlightTaskMyMode>); ``` - 需响应模式切换命令(如MAVLink指令),并接管控制权[^3] 2. **自定义模块** - 继承`ModuleBase`并实现`run()`方法: ```cpp class MyModule : public ModuleBase<MyModule> { public: static int task_spawn(int argc, char *argv[]); int run() override; // 主逻辑 }; ``` - 独立编译配置(需修改`CMakeLists.txt`和`Kconfig`)[^4] - 可发布自定义uORB消息(如`sensor_mycustom`) --- ### 三、典型应用场景 - **选择飞行模式当**: 需要定义**完整的飞行行为链**(如:起飞→路径跟踪→降落) - **选择自定义模块当**: 需添加**基础功能组件**(如:新避障算法、地面站通信协议) > 例如目标点飞行模式(`FlightTaskAutoLine`)内部会调用`PositionControl`模块进行轨迹跟踪,这种分层设计体现了飞行模式作为**高层行为**与模块作为**底层能力**的协作关系[^2][^3]。 --- ### 四、开发流程对比 | **步骤** | 自定义飞行模式 | 自定义模块 | |------------------|----------------------------------------|-------------------------------------| | 1. 创建文件 | `FlightTaskMyMode.hpp/cpp` | `MyModule.hpp/cpp` | | 2. 继承基类 | `FlightTask` | `ModuleBase` | | 3. 注册到系统 | 在`FlightModeManager`注册工厂 | 使用`MODULE_REGISTER`宏 | | 4. 编译配置 | 修改`flight_mode_manager/CMakeLists.txt` | 修改顶层`Kconfig`和`CMakeLists.txt` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值