ArduPilot SITL 模拟外设:sitl_periph 板级定义与 AP_Periph 仿真构建全解析
【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot
导读
本文围绕 libraries/AP_HAL_SITL/hwdef/sitl_periph/README.md 展开,深入解析 ArduPilot 中用于构建 AP_Periph 仿真固件的板级定义(hwdef)——sitl_periph。它是连接 "仿真(SITL)" 与 "真实外设(AP_Periph)" 两套世界的桥接配置文件:当你需要在 PC 上以纯软件方式模拟一个通过 CAN 总线对外提供 GPS、电量监控等数据的传感器节点时,所有特性默认值都由此处统一控制。读完本文,你将掌握 sitl_periph 内部各宏开关的含义与取舍逻辑、它与 ChibiOS 硬件板上的defaults_periph.h之间的替代关系,以及如何借助 sim_vehicle.py 一键编译并启动这类仿真外设。
一、sitl_periph 是什么:一个"特性默认值集合"而非完整固件
原文档对 sitl_periph 的定位非常直白,全文如下:
This is an include file which sets defaults for a lot of features. To be (mostly?) replaced by re-use of defaults_periph.h.
即:sitl_periph 是一个被其他 hwdef 以 include 方式引用的公共片段文件,本身并不构成一个独立可构建的板卡。它的全部职责是"为一大堆特性设置默认开关",并(大部分)计划由 ChibiOS 侧已有的 libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_periph.h 复用替代,以消除两套平台(真实硬件 vs 仿真)在外设默认配置上的重复维护。
仓库中的实际证据清楚地印证了这一点。目录下除 README 外只有一个文件 libraries/AP_HAL_SITL/hwdef/sitl_periph/hwdef.inc,而具体板卡则通过include指令引用它,例如 libraries/AP_HAL_SITL/hwdef/sitl_periph_gps/hwdef.dat 的第一行:
include ../sitl_periph/hwdef.inc当前仓库中共有 5 个这样的具体板卡(均位于 libraries/AP_HAL_SITL/hwdef/ 下):
| 板卡目录 | 用途(依据各目录 README) |
|---|---|
sitl_periph_gps | 模拟一个通过 CAN 输出 GPS 数据的外设 |
sitl_periph_battmon | 模拟一个通过 CAN 提供数据的电池监控外设 |
sitl_periph_universal | 包含 AP_Periph 大部分功能的通用模拟外设 |
sitl_periph_PPP | 启用了 PPP 网络后端的 SITL AP_Periph,用于测试 Plane 与外设间的 PPP 链路 |
sitl_periph_battery_tag、sitl_periph_can_to_serial | 电池标签、CAN 转串口等专项仿真外设 |
这些板卡共同说明:sitl_periph 扮演的是"公共配置底座"角色,真正的功能差异由各板卡的hwdef.dat通过undef/define覆盖宏实现(见下文第三节的 GPS 板卡示例)。
二、逐段拆解 hwdef.inc:构建身份的建立
hwdef.inc 是整个配置体系的核心,其内容可以清晰地分为四个层次:构建身份、协议栈、特性裁剪、AP_Periph 专项开关。
2.1 声明"我是 AP_Periph"
env AP_PERIPH 1 define HAL_BUILD_AP_PERIPH 1 define PERIPH_FW 1 define HAL_RAM_RESERVE_START 0这三行决定了编译出的固件是什么物种:
env AP_PERIPH 1在环境变量层面标记该构建为 AP_Periph;HAL_BUILD_AP_PERIPH与PERIPH_FW是贯穿全工程的宏标志,Tools/AP_Periph/AP_Periph.cpp 等外设源码正是依靠它们决定自身是否被编译进固件;HAL_RAM_RESERVE_START 0表示仿真场景下不预留特殊 RAM 区域。
2.2 CAN 协议栈配置
define CANARD_ENABLE_CANFD 1 define CANARD_ENABLE_TAO_OPTION 1 define CANARD_MULTI_IFACE 1这三行启用 Libcanard(DroneCAN 协议实现,见 modules/DroneCAN 子模块)的三大能力:
CANARD_ENABLE_CANFD:启用 CAN FD(可变数据率)帧支持;CANARD_ENABLE_TAO_OPTION:启用 TAO(Tail Array Optimization)特性,允许数组类型消息在序列化时省去长度前缀,降低总线负载;CANARD_MULTI_IFACE:启用多 CAN 接口支持,允许外设同时挂在多条 CAN 总线上。
由于 AP_Periph 的通信主通道就是 DroneCAN/CAN,这几项开关直接决定外设能否以更高效的方式工作。
2.3 AHRS 的必要保留
# FIXME: SITL library should not be using AP_AHRS: define AP_AHRS_ENABLED 1 define AP_AHRS_BACKEND_DEFAULT_ENABLED 0 define AP_AHRS_DCM_ENABLED 1 # need a default backend define AP_EXTERNAL_AHRS_ENABLED 0这是 hwdef.inc 中唯一带着 FIXME 注释的片段,也是理解 SITL 实现约束的关键点。严格来说,一个 AP_Periph 外设节点并不需要完整的姿态解算(真实外设上AP_AHRS_ENABLED默认为 0,见defaults_periph.h);但 SITL 仿真环境中的 AHRS 库被 HAL_SITL 内部依赖(例如 libraries/AP_HAL_SITL/HAL_SITL_Class.cpp 中 AP_PERIPH 相关代码路径),因此这里必须:
- 保留
AP_AHRS_ENABLED 1; - 关闭默认后端
AP_AHRS_BACKEND_DEFAULT_ENABLED 0,同时手动开启 DCM 后端AP_AHRS_DCM_ENABLED 1(注释明确说明"需要一个默认后端"),以保证仿真固件能正常链接与运行; - 关闭外部 AHRS 支持
AP_EXTERNAL_AHRS_ENABLED 0。
从代码结构看,这一取舍属于仿真平台的"无奈之举":为了在 PC 上编译通过,仿真 AP_Periph 比真实 AP_Periph 多保留了一个 DCM 姿态后端。
2.4 串口协议绑定
define HAL_MAVLINK_BINDINGS_ENABLED 1AP_Periph 不维护传统飞控的 SERIAL 参数树,而是为每个串口设备类型单独设置端口参数。这里将 MAVLink 绑定保持启用,与 Tools/AP_Periph 的 GCS_MAVLink 相关实现配套。
三、特性裁剪:从"全功能"到"最小外设"的宏清单
以下宏全部被显式关闭(值为 0),这是 sitl_periph 与普通飞控固件差异最显著的部分。每一个开关都对应 ArduPilot 中的一个独立功能模块:
| 宏 | 含义 | 关闭原因(推断) |
|---|---|---|
AP_AIRSPEED_AUTOCAL_ENABLE | 空速自动校准 | 外设不负责导航控制 |
AP_CAN_SLCAN_ENABLED | SLCAN(串口 CAN 网关) | 仿真外设不需要调试网关 |
AP_ICENGINE_ENABLED | 内燃机控制 | 外设无发动机管理 |
AP_MISSION_ENABLED | 任务(Mission)库 | 外设不执行任务 |
AP_RCPROTOCOL_ENABLED | RC 协议解析 | 见第四节,由 RCIN 外设开关联动 |
AP_RTC_ENABLED | 实时时钟 | 见第四节,由电池标签联动 |
AP_SCHEDULER_ENABLED | 调度器 | 外设使用自身主循环(见第四节说明) |
AP_SCRIPTING_ENABLED | Lua 脚本 | 外设默认不跑脚本 |
AP_STATS_ENABLED | 统计信息 | 减少开销 |
COMPASS_CAL_ENABLED/COMPASS_LEARN_ENABLED/COMPASS_MOT_ENABLED | 罗盘校准/学习/电机补偿 | 外设罗盘校准交由自驾仪完成(defaults_periph.h 有同款注释) |
HAL_CAN_DEFAULT_NODE_ID 0 | CAN 默认节点 ID | 默认节点 0,由用户配置 |
HAL_CANMANAGER_ENABLED | CAN 管理器 | AP_Periph 不依赖 CANManager |
HAL_GCS_ENABLED | 地面站协议栈 | 外设通过 DroneCAN 通信,不走 GCS |
HAL_GENERATOR_ENABLED | 发电机 | 外设无发电管理 |
HAL_LOGGING_ENABLED/HAL_LOGGING_MAVLINK_ENABLED | 数据日志 / MAVLink 日志 | 外设默认不记录飞行日志 |
HAL_PROXIMITY_ENABLED | 避障距离传感器 | 由外设距离传感器开关联动 |
HAL_RALLY_ENABLED | 集结点(Rally) | 外设无航线需求 |
HAL_SUPPORT_RCOUT_SERIAL | 串行舵机输出 | 见第四节 |
AP_TERRAIN_AVAILABLE | 地形数据 | 外设不查询地形 |
AP_CUSTOMROTATIONS_ENABLED | 自定义旋转 | 外设磁罗盘假设 ROTATION_NONE |
值得注意的一个例外是AP_UART_MONITOR_ENABLED 1:在绝大多数功能都被裁剪的同时,UART 监视器被显式打开,因为串口是仿真外设调试与数据观测的重要通道。
四、AP_Periph 专项开关矩阵:模块级使能体系
从第 43 行开始,hwdef.inc 进入 AP_Periph 自己的"子功能开关"体系。这些AP_PERIPH_*_ENABLED宏是理解整个 AP_Periph 可裁剪性的钥匙——它们不是直接控制 ArduPilot 大库,而是控制 Tools/AP_Periph 内部各外设驱动模块的编译,再在构建期把这些开关"翻译"成对应的大库开关。对照 ChibiOS 侧 defaults_periph.h 的对应规则(第 390-420 行),翻译逻辑一目了然:
| AP_Periph 开关 | 翻译后的大库开关 |
|---|---|
AP_PERIPH_BATTERY_ENABLED | AP_BATTERY_ENABLED |
AP_PERIPH_GPS_ENABLED | AP_GPS_ENABLED,且联动 GPS 各后端 |
AP_PERIPH_MAG_ENABLED | AP_COMPASS_ENABLED |
AP_PERIPH_BARO_ENABLED | AP_BARO_ENABLED |
AP_PERIPH_RANGEFINDER_ENABLED | AP_RANGEFINDER_ENABLED |
AP_PERIPH_IMU_ENABLED | AP_INERTIALSENSOR_ENABLED与AP_INERTIALSENSOR_ALLOW_NO_SENSORS |
AP_PERIPH_RCIN_ENABLED | AP_RCPROTOCOL_ENABLED |
AP_PERIPH_RPM_ENABLED | AP_RPM_ENABLED |
AP_PERIPH_DEVICE_TEMPERATURE_ENABLED | AP_TEMPERATURE_SENSOR_ENABLED |
AP_PERIPH_MSP_ENABLED | HAL_MSP_ENABLED |
AP_PERIPH_RELAY_ENABLED | AP_RELAY_ENABLED |
AP_PERIPH_PROXIMITY_ENABLED | HAL_PROXIMITY_ENABLED |
AP_PERIPH_EFI_ENABLED | HAL_EFI_ENABLED |
hwdef.inc 中第 43–76 行给出的默认值全部为 0(共 30 余个),意味着一个"裸"的仿真 AP_Periph 默认不具备任何传感器/输出能力,各具体板卡需要像 GPS 板卡那样自行打开所需项。
defaults_periph.h中还有两条非常关键的联动规则,可以帮助读者理解 hwdef.inc 里部分"冗余"关闭项的由来:
#ifndef AP_PERIPH_RTC_ENABLED #define AP_PERIPH_RTC_ENABLED AP_PERIPH_BATTERY_TAG_ENABLED #endif #ifndef AP_PERIPH_RPM_STREAM_ENABLED #define AP_PERIPH_RPM_STREAM_ENABLED AP_PERIPH_RPM_ENABLED #endif即:RTC 随电池标签(BatteryTag)功能自动开启,RPM 数据流随 RPM 功能自动开启。同理,hwdef.inc 中AP_RTC_ENABLED 0、AP_SCHEDULER_ENABLED 0等看似"关闭调度器"的写法,在真实 AP_Periph 体系中的语义是:外设不依赖飞控式调度循环,而是由 Tools/AP_Periph/AP_Periph.cpp 自己的loop()主循环驱动各模块轮询。
另外,defaults_periph.h的尾部还提供了一组"命名规范自检"(#error提示),强制要求把旧的HAL_PERIPH_ENABLE_*命名迁移到新的AP_PERIPH_*_ENABLED命名——这正是 hwdef.inc 中采用新命名的规范来源。
五、真实硬件与 SITL 的配置统一:defaults_periph.h 对照
defaults_periph.h由 ChibiOS 构建脚本chibios_hwdef.py在配置 AP_Periph 构建时插入到生成的hwdef.h中(见该文件头注释)。它和 sitl_periph/hwdef.inc 的关系是:
- 定位相似:都是"AP_Periph 特性默认值集合";
- 实现方式不同:hwdef.inc 是 hwdef 语法(
define/undef),defaults_periph.h 是 C 预处理器头文件(大量使用#ifndef包裹,允许板卡用自身的define覆盖); - 覆盖范围不同:hwdef.inc 目前覆盖约 30 余个开关并固定在 0,defaults_periph.h 覆盖 100+ 个开关,且包含 GPS 后端选择性开关(如
AP_GPS_UBLOX_ENABLED、AP_GPS_GSOF_ENABLED、AP_GPS_NOVA_ENABLED联动AP_PERIPH_GPS_ENABLED,而 ERB/SBP/SIRF 等默认关闭)、空速/测距仪后端裁剪、电池监控器实例数限制(AP_BATT_MONITOR_MAX_INSTANCES 1)、AP_BOOTLOADER_ALWAYS_ERASE 1等更完整的规则。
README 中"To be (mostly?) replaced by re-use of defaults_periph.h"的规划,正是期望未来 SITL 与 ChibiOS 共享同一份默认值,消除双份维护。从当前代码看,hwdef.inc 的许多值仍与 defaults_periph.h 高度一致(如COMPASS_CAL_ENABLED 0、HAL_GCS_ENABLED 0、HAL_CAN_DEFAULT_NODE_ID 0、AP_AIRSPEED_AUTOCAL_ENABLE 0),可以推断两个文件正在逐步趋同。
六、板卡实例:如何基于 sitl_periph 定制一个 GPS 外设
以 libraries/AP_HAL_SITL/hwdef/sitl_periph_gps/hwdef.dat 为完整示例,看一个具体外设如何在公共底座之上做"最小增量配置":
include ../sitl_periph/hwdef.inc define CAN_APP_NODE_NAME "org.ardupilot.ap_periph_gps" define APJ_BOARD_ID 101 undef AP_PERIPH_GPS_ENABLED define AP_PERIPH_GPS_ENABLED 1配置要点:
include ../sitl_periph/hwdef.inc:先继承全部公共默认值;CAN_APP_NODE_NAME:声明本节点在 DroneCAN 网络中的应用名,供总线枚举识别;APJ_BOARD_ID 101:声明板卡 ID,SITL 构建系统据此生成对应固件目标;undef+define AP_PERIPH_GPS_ENABLED 1:由于 hwdef.inc 已将该开关固定为 0,这里必须先undef再重新define为 1,从而打开 GPS 外设功能。配合 defaults_periph.h 的联动规则,AP_GPS_ENABLED以及 UBLOX/GSOF/NOVA 等 GPS 后端也会随之启用。
同样的模式也适用于 sitl_periph_battmon(电池监控)、sitl_periph_universal(通用外设,保留大部分功能)等其余板卡,差异仅在于打开哪些AP_PERIPH_*_ENABLED开关。
七、如何编译与启动:sim_vehicle.py 的 periph 支持
仿真 AP_Periph 的构建与启动由自动测试框架 Tools/autotest/sim_vehicle.py 统一封装。其内部定义了一个专用函数,注释为 "Compile and run the sitl_periph"(约第 880 行),默认板卡取sitl_periph_universal:
periph_board = frame_info.get('periph_board', 'sitl_periph_universal')板卡映射关系维护在 Tools/autotest/pysim/vehicleinfo.json 中,其中第 718–730 行明确登记了sitl_periph_universal与sitl_periph_PPP两个仿真外设目标:
"sitl_periph_universal": { ... "configure_target": "sitl_periph_universal", ... }, "sitl_periph_PPP": { ... "configure_target": "sitl_periph_PPP", ... }典型使用场景(以 PPP 外设为例,源自 sitl_periph_PPP/README.md):该板卡启用AP_NETWORKING_BACKEND_PPP,用于测试 ArduPlane SITL 与 AP_Periph SITL 之间通过回环 TCP 承载 PPP 帧的链路。配对飞行框架为quadplane-PPP,启动命令为:
sim_vehicle.py -v Plane -f quadplane-PPP其中quadplane-PPP框架在 vehicleinfo.json 的configure_args中会自动附加--enable-PPP与--enable-networking-tests到 waf 配置步骤(对应 PPP 与网络测试的 waf 选项),而外设侧已由板卡 hwdef 直接定义了AP_NETWORKING_BACKEND_PPP=1。sitl_periph_PPP的使用也体现在自动测试中,如 Tools/autotest/arduplane.py 与 Tools/autotest/arducopter.py 中对 PPP 外设的调用。
编译仿真 AP_Periph 固件本质上与其他 SITL 目标一致,只是 configure 阶段指定板卡名:
./waf configure --board sitl_periph_universal ./waf build构建产物即为一个可运行的 SITL 外设进程,可与飞行器 SITL 通过虚拟 CAN 互联,用于在纯软件环境下验证外设通信与整机集成。
八、总结与演进方向
归纳 sitl_periph 的设计要点:
- 它是 include 型公共配置:本身不构成板卡,由各具体仿真外设板卡的
hwdef.dat通过include引入(证据:sitl_periph_gps/hwdef.dat); - 它定义了 AP_Periph 的仿真形态:声明
PERIPH_FW/HAL_BUILD_AP_PERIPH,启用 CAN FD、TAO、多接口等 DroneCAN 高级能力; - 它默认裁剪掉几乎所有飞控功能:GCS、日志、任务、脚本、罗盘校准等 30 余项开关默认关闭,仅保留 SITL 运行必需的 AHRS(DCM) 与 UART 监视器;
- 它通过
AP_PERIPH_*_ENABLED开关体系实现外设功能的模块化装配,具体功能由各板卡按需打开; - 它正被规划与 defaults_periph.h 合并,README 中的"to be (mostly?) replaced"揭示了这一演进方向,当前两份文件中大量默认值的一致性也佐证了这一趋势。
对于需要在开发机上验证 CAN 外设协议、调试 PPP 链路或进行 AP_Periph 功能开发的工程师而言,sitl_periph 这套配置是进入仿真外设世界的第一道入口——理解它,就等于理解了 ArduPilot 如何用一套可裁剪的宏体系,在 PC 上重构出一个接近真实硬件行为的外设节点。
【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考