尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ArduPilot DroneCAN 总线嗅探器实战:用 AP_DroneCAN 例程抓取 UAVCAN 报文并解析 1Hz 统计输出

ArduPilot DroneCAN 总线嗅探器实战:用 AP_DroneCAN 例程抓取 UAVCAN 报文并解析 1Hz 统计输出 ArduPilot DroneCAN 总线嗅探器实战用 AP_DroneCAN 例程抓取 UAVCAN 报文并解析 1Hz 统计输出【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot本文基于 ArduPilot 仓库中的官方示例 DroneCAN_sniffer 展开介绍如何在 ArduPilot 板卡上构建、烧录一个 UAVCAN/DroneCAN 总线嗅探器固件实时观察总线上各类报文的收发情况并通过每秒一次的统计输出诊断节点流量与报文周期。读完本文你将掌握该示例的编译上传流程、输出格式的完整含义、其底层实现机制以及如何通过MSG_CB()与START_CB()宏扩展想要监听的报文类型。DroneCAN Sniffer 是什么DroneCAN即 UAVCAN 的无人机应用分支是 ArduPilot 生态中用于连接 GNSS、电调、空速计、罗盘等外设的 CAN 总线协议。排障时最直接的诉求就是看总线上到底在传什么。官方在 libraries/AP_DroneCAN/examples/DroneCAN_sniffer/ 目录下提供了一个专门的嗅探器示例程序其定位在 README 中写得很清楚这是一个设计运行在 ArduPilot 板卡上的 UAVCAN 嗅探器可用于观察 UAVCAN 总线上的流量精确展示另一个节点实际会收到的内容。换句话说把该固件烧录到一块 ArduPilot 板卡上并将板卡的 CAN 接口接入目标总线这块板就变成了一台只听不干扰的监听设备它订阅若干常见 DroneCAN 报文统计每种报文的出现次数与发送周期再通过 USB 串口控制台周期性打印出来。构建与烧录一条命令链完成编译上传README 给出了针对 Pixhawk 风格板卡以fmuv3为例的标准构建方式./waf configure --board fmuv3 ./waf --target examples/UAVCAN_sniffer --upload注意两点第一步configure只需要执行一次或在你切换板型后重新执行第二步中目标名称写作examples/UAVCAN_sniffer尽管源码目录名为DroneCAN_sniffer——这是 waf 构建系统对示例程序注册的目标名。示例的构建规则定义在 wscript 中它通过bld.ap_stlib()汇总通用库并额外链接AP_OSD、AP_Avoidance再通过bld.ap_program()以program_groups[tool]的方式把示例编译为独立固件因此最终生成的是一个可单独烧录的完整程序而非普通机架固件。上传完成后通过 USB 连接板卡的控制台console即可看到类似下面的每秒统计输出。读懂 1Hz 统计输出README 给出了真实运行时的输出示例这是本文的核心素材完整保留如下uavcan.equipment.air_data.StaticPressure: 29 uavcan.equipment.air_data.StaticTemperature: 29 uavcan.equipment.ahrs.MagneticFieldStrength: 20 uavcan.protocol.NodeStatus: 6 uavcan.equipment.gnss.Fix: 10 uavcan.equipment.gnss.Auxiliary: 1 uavcan.equipment.actuator.ArrayCommand: 45 uavcan.equipment.esc.RawCommand: 368每行格式为消息类型全名: 计数每 1 秒刷新一次。从中可以直接读出总线负载特征例如uavcan.equipment.esc.RawCommand: 368——电调原始指令帧频率极高368 帧/秒说明飞控正在以约 1 kHz 级速率向电调发送指令uavcan.equipment.actuator.ArrayCommand: 45——舵机/执行器阵列指令uavcan.equipment.gnss.Fix与Auxiliary——GNSS 定位解与辅助数据uavcan.equipment.air_data.StaticPressure/StaticTemperature——空速/气压计的静压与静温uavcan.equipment.ahrs.MagneticFieldStrength——磁力计磁场强度uavcan.protocol.NodeStatus——各节点的健康/模式心跳报文。需要特别说明的是README 示例输出中uavcan.equipment.gnss.Fix对应源码中的uavcan_equipment_gnss_Fix2见下文源码分析名称差异源于示例固件内部订阅的是Fix2消息类型。输出比 README 更丰富周期统计字段实际源码的打印内容不止类型: 计数两列。在 DroneCAN_sniffer.cpp 的print_stats()中每行输出为%s: %lu AVG_US: %lu MAX_US: %lu MIN_US: %lu即在计数之外还会给出该报文两次到达之间的平均周期AVG_US、最大周期MAX_US、最小周期MIN_US单位均为微秒。每次打印后计数器与周期统计会被清零count、avg_period_us、max_period_us、min_period_us全部归零因此这是严格的每秒窗口统计。周期数据对判断节点是否丢帧、是否按预期节律发送如 50Hz 的 GNSS Fix 应表现为约 20000 µs 的平均周期非常有价值。源码级实现剖析整体结构示例固件由 DroneCAN_sniffer.cpp 一个文件实现入口为AP_HAL_MAIN()第 260 行遵循 ArduPilot 示例的标准setup()/loop()模式setup()延时 2 秒等待总线稳定后调用sniffer.init()loop()调用sniffer.loop()处理收发并在每满 1 秒时调用sniffer.print_stats()打印统计附加逻辑当控制台输入缓冲超过 50 字节时自动重启固件rebooting这是为了配合--upload的自动烧录流程。计数器的数据结构统计核心是一个最多 100 项的静态结构体数组DroneCAN_sniffer.cppstatic struct { const char *msg_name; uint32_t count; uint64_t last_time_us; uint32_t avg_period_us; uint32_t max_period_us; uint32_t min_period_us; } counters[100];count_msg()DroneCAN_sniffer.cpp负责在数组中找到或新建对应消息类型的表项更新计数并增量维护平均/最大/最小到达周期平均周期采用递推均值avg (avg * (count-1) period) / count最大/最小周期与历史值比较更新首次到达时avg_period_us直接取当前周期。MSG_CB 与 START_CB 宏扩展监听类型的两个关键点README 末尾专门提示代码要求你自行添加想要观察的新消息类型请在代码中寻找MSG_CB()和START_CB()宏。这正是扩展该嗅探器的核心方法。MSG_CB()宏DroneCAN_sniffer.cpp为每种消息生成一个回调函数函数体内只做一件事——调用count_msg()对该消息类型计数#define MSG_CB(mtype, cbname) \ static void cb_ ## cbname(const CanardRxTransfer transfer, const mtype msg) { count_msg(#mtype); }示例固件内置了 12 种消息回调覆盖了 DroneCAN 最常见的传感器与执行器流量MSG_CB(uavcan_protocol_NodeStatus, NodeStatus) MSG_CB(uavcan_equipment_gnss_Fix2, Fix2) MSG_CB(uavcan_equipment_gnss_Auxiliary, Auxiliary) MSG_CB(uavcan_equipment_ahrs_MagneticFieldStrength, MagneticFieldStrength) MSG_CB(uavcan_equipment_ahrs_MagneticFieldStrength2, MagneticFieldStrength2); MSG_CB(uavcan_equipment_air_data_StaticPressure, StaticPressure) MSG_CB(uavcan_equipment_air_data_StaticTemperature, StaticTemperature) MSG_CB(uavcan_equipment_power_BatteryInfo, BatteryInfo); MSG_CB(uavcan_equipment_actuator_ArrayCommand, ArrayCommand) MSG_CB(uavcan_equipment_esc_RawCommand, RawCommand) MSG_CB(uavcan_equipment_indication_LightsCommand, LightsCommand); MSG_CB(com_hex_equipment_flow_Measurement, Measurement);START_CB()宏DroneCAN_sniffer.cpp则把上述回调注册为对应 driver index 的静态订阅者消息真正进入嗅探器的接收路径#define START_CB(mtype, cbname) Canard::allocate_sub_static_callback(cb_ ## cbname, driver_index) START_CB(uavcan_protocol_NodeStatus, NodeStatus); START_CB(uavcan_equipment_gnss_Fix2, Fix2); // ... 其余消息类型一一对应因此添加新消息类型的标准动作是两步先用MSG_CB(新类型, 名字)生成计数回调再用START_CB(新类型, 名字)注册订阅。二者必须成对出现且名字一致否则回调不会被触发统计中也不会出现该类型。可订阅的消息类型如uavcan_equipment_esc_Status、uavcan_protocol_debug_LogMessage等可以参考 AP_DroneCAN.h 中AP_DroneCAN类已有的订阅者列表。底层协议栈CanardInterface 与内存池嗅探器并非自己实现 CAN 收发而是复用了与正式固件相同的 DroneCAN 协议栈。其初始化流程DroneCAN_sniffer.cpp展示了关键细节创建 CAN 接口通过NEW_NOTHROW HAL_CANIface(driver_index)实例化 CAN 硬件接口并以1000000 bps1 MbpsDroneCAN 标准速率初始化若初始化失败控制台打印 Can not initialised。创建协议接口CanardInterface{driver_index}是 ArduPilot 对 Canard 协议栈的封装见 AP_Canard_iface.h随后add_interface()把 CAN 硬件挂接上去。分配内存池并设定节点 ID_uavcan_iface_mgr-init(node_memory_pool, sizeof(node_memory_pool), 9)使用静态数组uint8_t node_memory_pool[DRONECAN_NODE_POOL_SIZE]8192 字节见 DroneCAN_sniffer.cpp作为 Canard 的传输内存嗅探器节点 ID 固定为9。作为普通节点参与总线固件创建了uavcan_protocol_NodeStatus发布器与uavcan_protocol_GetNodeInfoRequest服务端。在loop()中send_node_status()每 1 秒广播一次节点状态心跳模式为 OPERATIONAL、健康状态 OK节点名字为org.ardupilot:%u%u为 driver index软件/硬件版本号取 AP_DroneCAN.h 中定义的AP_DRONECAN_SW_VERS_MAJOR/MINOR与AP_DRONECAN_HW_VERS_MAJOR/MINOR。这意味着嗅探器本身对总线是透明但合规的它不向其他节点发指令、不改动总线行为只以合法节点身份接收订阅的广播报文——这正是 README 所说精确展示另一个节点实际会收到的内容的原因。主循环与消息分发loop()的核心只有一行_uavcan_iface_mgr-process(1)DroneCAN_sniffer.cpp。该调用驱动 Canard 协议栈完成一次接收与发送处理触发各订阅回调随后loop()中另外以 1 秒为周期调用print_stats()输出统计同时保持每秒一次的 NodeStatus 心跳广播。整体形成了一个接收—计数—每秒汇报的闭环。平台与硬件前提示例通过条件编译适配了三种 HAL 平台DroneCAN_sniffer.cppChibiOSPixhawk 系列等飞控板使用AP_HAL_ChibiOS/CANIface.h这是 README 中fmuv3构建命令对应的目标平台Linux使用AP_HAL_Linux/CANSocketIface.hSITL软件在环仿真使用AP_HAL_SITL/CANSocketIface.h可在仿真环境中验证嗅探逻辑。整个示例包在#if HAL_ENABLE_DRONECAN_DRIVERS条件编译内若目标板未启用 DroneCAN 驱动则会编译到末尾的降级分支控制台仅打印 Board not currently supportedDroneCAN_sniffer.cpp。因此使用时需确认目标板具备 CAN 外设且构建配置启用了 DroneCAN。实战建议定位丢帧/周期异常关注AVG_US/MAX_US/MIN_US三列。若某消息MAX_US远大于平均周期或计数在 1 秒窗口内明显波动说明对应节点存在偶发丢帧或调度抖动评估总线负载统计各消息每秒帧数之和乘以平均帧长即可粗略估算总线占用率RawCommand这类高频消息通常是负载大头扩展新消息按上文MSG_CB START_CB 成对添加的方式把需要诊断的消息类型例如 ESC 状态回传、CAN 统计、调试日志等加入订阅列表重新编译即可无需改动其余逻辑观测后自动重启上传新版固件时控制台缓冲超过 50 字节会触发自动 reboot便于--upload流程连续迭代。小结DroneCAN Sniffer 示例是 ArduPilot 生态中一个轻量而实用的总线诊断工具它复用正式的AP_DroneCAN/Canard 协议栈以独立节点身份接入总线通过MSG_CB()/START_CB()宏按需订阅报文并在控制台以 1Hz 频率输出每类消息的帧数与周期统计。无论是排查 GNSS/电调/空速计通信异常还是评估 DroneCAN 总线负载本文介绍的构建命令、输出解读与扩展方法都可以直接落地使用。【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表