ArduPilot 蓝牙风速风向计接入指南:nRF52 + CALYPSO 超声波风速计转 NMEA 0183 完整方案
ArduPilot 蓝牙风速风向计接入指南nRF52 CALYPSO 超声波风速计转 NMEA 0183 完整方案【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot导读本文档详细讲解如何在 ArduPilot 生态中利用一个 Arduino 兼容的 nRF52 蓝牙模块以 Seeed XIAO nRF52840 Sense 为例作为蓝牙中枢Central接收 CALYPSO 超声波便携式迷你风速计Ultrasonic Portable Mini wind meter的蓝牙广播数据并将其转换为 NMEA 0183 报文输出给飞控从而为 ArduPlane / ArduRover / ArduCopter 等载具提供表观风apparent wind方向与速度。阅读本文后你将掌握硬件接线、Arduino 固件烧录、蓝牙地址获取与配置、ArduPilot 侧参数设置WNDVN_TYPE、WNDVN_SPEED_TYPE、SERIALx_PROTOCOL/SERIALx_BAUD以及 ArduPilot 源码中 NMEA 报文解析的底层原理。该方案最大的价值在于CALYPSO 风速计比传统风速风向传感器更小、更轻且通过无线方式传输数据省去了从桅杆顶端到船体/飞控之间的布线——这对于帆船Rover sailboat等需要将传感器安装在桅杆顶部的场景尤其实用。硬件准备与接线所需器件一个 Arduino 兼容的 nRF52 蓝牙开发板本文档以Seeed XIAO nRF52840 Sense为示例编写其他 nRF52 蓝牙板理论上均可工作一台 CALYPSO 超声波便携式迷你风速计作为 BLE 外设Peripheral一台 ArduPilot 飞控作为 NMEA 串口数据的接收方。三线连接飞控与 XIAO 之间只需连接三根线连接关系如下表XIAO 引脚线色飞控连接目标5V红飞控 5V 电源输出GND黑飞控 GND 地TX绿飞控某一串口的 RX 引脚接线完成后XIAO 负责三件事通过 BLE 连接 CALYPSO 风速计、订阅其数据通知Notify、将解析到的风速风向数据以 NMEA 0183 语句从 TX 引脚即飞控串口 RX输出。Arduino 固件搭建与烧录1. 搭建 Arduino 环境并安装依赖按照开发板厂商的说明在 Arduino IDE 中配置好对应 nRF52 板卡的支持Board Support Package即 BSP。随后安装Adafruit nRF52包中提供的Bluefruit52Lib库该库是脚本实现 BLE 客户端Central功能的基础。本文档对应的固件源码位于 libraries/AP_WindVane/Tools/Bluetooth NMEA receiver/Bluetooth NMEA receiver.ino其中明确注释了该代码使用 Adafruit Bluefruit52 库并已在 Seeed XIAO nRF52840 Sense 上完成测试。2. 获取风速计的蓝牙地址CALYPSO 风速计作为 BLE 外设广播自己的地址。使用智能手机上的蓝牙工具扫描并找到风速计对应的设备名与 MAC 地址Android 平台可使用BLE Scanner等工具App 商店中有大量同类应用在扫描结果中定位风速计设备记下其地址例如DD:B7:BE:B4:56:38。3. 修改固件中的目标地址并烧录打开固件源文件将脚本顶部的地址宏替换为风速计的实际地址。替换规则去掉冒号并在前面加上0x前缀表示十六进制数值。例如#define WIND_VANE_ADDRESS 0xDDB7BEB45638在 Bluetooth NMEA receiver.ino 中该宏随后被复制到ble_gap_addr_t结构体中并显式设置地址类型为BLE_GAP_ADDR_TYPE_RANDOM_STATIC随机静态地址这是 CALYPSO 一类消费级 BLE 设备常见的行为uint64_t address WIND_VANE_ADDRESS; memcpy(addr.addr, address, BLE_GAP_ADDR_LEN); addr.addr_type BLE_GAP_ADDR_TYPE_RANDOM_STATIC;保存脚本后将其烧录到 nRF52 开发板。4. LED 状态解读烧录后开发板上的 LED 用于指示连接与电池状态红灯常亮无法建立 BLE 连接绿灯亮起已成功建立连接建立过程可能需要几秒钟绿灯常亮且红灯闪烁已连接但风速计剩余电量不足 25%风速计电量降到 20% 时进入低功耗模式。注意CALYPSO 风速计同一时间只能接受一个 BLE 连接。如果无法连接请先确认没有其他设备例如刚才用于扫描的手机仍占用着与风速计的连接。固件内部机制从 BLE 特征值到 NMEA 报文理解固件的数据通路有助于排查问题。固件在setup()中做了如下关键初始化见 Bluetooth NMEA receiver.ino双串口分工SerialUSB115200输出调试信息Serial157600 波特输出 NMEA 报文给飞控BLE 中央模式Bluefruit.begin(0, 1)初始化Bluefruit.setName(ArduPilot Bluetooth)设置本地名称订阅服务与特征值分别初始化环境感知服务Environmental SensingUUID0x181A与电池服务Battery ServiceUUID0x180F并为各特征值注册 Notify 回调。订阅的 GATT 服务与特征值固件通过标准 Bluetooth SIG 定义的服务与特征值读取风速风向数据GATT 服务UUID特征值UUID含义Environmental Sensing0x181AApparent Wind Speed0x2A72表观风速Environmental Sensing0x181AApparent Wind Direction0x2A73表观风向Battery Service0x180FBattery Level0x2A19电池电量百分比数据解析与 NMEA 编码loop()中的核心逻辑是只有风速与风向同时收到新值时才合成一条 NMEA 报文并输出到Serial1电池电量单独成句。相关处理见 Bluetooth NMEA receiver.ino。风速/风向BLE 特征值以 2 字节无符号整数传输数值需乘以0.01还原为真实物理量value * 0.01即风速单位为 m/s、风向单位为度电池电量单字节整数即百分比。生成的两类 NMEA 语句格式如下$APMWV,direction,R,speed,M,A*checksum $APXDR,G,battery,%,BT*checksumMWV句风向度、R表示相对风relative、风速m/s、M表示单位为米每秒、A表示数据有效XDR句传递风速计电池电量G类型、%单位、名称BT校验和为 NMEA 标准做法对$与*之间的字符逐字节异或XOR结果以两位大写十六进制输出见固件中的NMEA_checksum()函数。同时固件还实现了断线自动重连RECONNECT_TIME_MS1000 ms间隔反复尝试连接已知地址连接建立后会依次 discover 并 enableNotify 上述特征值见connect_callback。ArduPilot 侧配置固件输出的正是 ArduPilot 原生支持的 NMEA 0183 报文MWV因此 ArduPilot 侧只需开启对应的风向/风速类型并配置好串口即可无需额外驱动。1. 启用 NMEA 风向与风速在飞控参数中设置WNDVN_TYPE 4 WNDVN_SPEED_TYPE 4从 AP_WindVane.h 中的枚举定义可以看到WNDVN_TYPE 4对应WINDVANE_NMEANMEA 风向WNDVN_SPEED_TYPE 4对应WINDSPEED_NMEANMEA 风速。两者共用同一个 NMEA 后端驱动当二者都选 NMEA 时固件会复用同一个驱动实例见 AP_WindVane.cpp 中_speed_driver _direction_driver的优化逻辑。2. 配置串口协议与波特率找到 nRF52 模块 TX 线所连接的飞控串口例如SERIAL1、SERIAL2等设置协议为 WindVane、波特率为 57600SERIALx_PROTOCOL 21 SERIALx_BAUD 57这两个值的含义可以从源码得到印证SERIALx_PROTOCOL 21对应AP_SerialManager中的SerialProtocol_WindVane见 AP_SerialManager.h。AP_WindVane_NMEA::init()正是通过serial_manager.find_serial(AP_SerialManager::SerialProtocol_WindVane, 0)查找该协议对应的串口并调用uart-begin()完成初始化见 AP_WindVane_NMEA.cppSERIALx_BAUD 57是编码波特率AP_SerialManager::map_baudrate(57)会将其映射为实际的57600baud见 AP_SerialManager.cpp与固件中#define NMEA_BAUD 57600的Serial1.begin(NMEA_BAUD)完全匹配。由于WNDVN_TYPE与WNDVN_SPEED_TYPE两个参数标注了RebootRequired: True修改后需重启飞控使配置生效。3. 在地面站查看风速风向重启后飞控应持续上报风数据在地面站如 Mission Planner中即可看到AppWndDir/AppWndSpd表观风向与表观风速由飞控以 named float 形式发送见 AP_WindVane.cpp 中的send_named_float(AppWndSpd, ...)与send_named_float(AppWndDir, ...)同时在 Mission Planner 中也可选择MAV_APPWNDDIR与MAV_APPWNDSPD字段进行图形化显示。此外飞控还会通过标准 MAVLinkWIND消息发送真风true wind数据见send_wind()AP_WindVane.cpp并周期性写入WIND日志包含DrRaw、DrApp、DrTru、SpdRaw、SpdApp、SpdTru等字段见 AP_WindVane.cpp便于事后分析。源码级原理ArduPilot 如何解析 MWV 报文AP_WindVane_NMEA后端AP_WindVane_NMEA.cpp按字符流逐字节解析串口数据整体流程与 RangeFinder 的 NMEA 库同源。其解析逻辑值得展开句头识别$标志一句报文的开始同时重置校验和累加器与各项解析状态见decode()第 102-111 行句型匹配报文头的前两个字符是 talker ID任意两个大写字母均可后续字符串必须为MWV才认为句子有效见decode_latest_term()第 140-154 行逐字段校验字段 1风向角度度非法范围负数或大于 360判为无效字段 2必须是R相对风代码注释指出未来可能支持T真风字段 3风速数值字段 4单位标志——Kkm/h乘以KM_PER_HOUR_TO_M_PER_SEC、N节乘以KNOTS_TO_M_PER_SEC统一换算为 m/sMm/s则无需换算风速为负或超过 100 m/s 判为无效字段 5必须是A数据有效。校验和验证*之后的两位十六进制与解析过程中累积的异或校验和比对一致且句子有效才真正采纳数据第 130-137 行。解析成功后风向会加上WNDVN_DIR_OFS偏移并换算为弧度存入_direction_apparent_raw风速存入_speed_apparent_raw见update()第 64-69 行。此后AP_WindVane.cpp 中的update()会以 20 Hz 周期完成滤波表观/真风各方向与速度的低通滤波WNDVN_DIR_FILT、WNDVN_SPEED_FILT、WNDVN_TRUE_FILT控制截止频率-1 表示关闭、真风计算利用AP::ahrs()提供的机体速度与航向依据表观风原理进行矢量合成以及迎风换舷判定tack最终输出给 GCS 与日志。故障排查要点无法连接风速计CALYPSO 只接受单个 BLE 连接确认手机等其他设备未占用连接同时确认WIND_VANE_ADDRESS与风速计实际地址一致含0x前缀、去掉冒号飞控无数据核对SERIALx_PROTOCOL21与SERIALx_BAUD57设置并确认修改后已重启确认接线中 XIAO 的 TX 确实接在飞控对应串口的 RX 上波特率不匹配固件以 57600 输出SERIALx_BAUD 57映射为 57600两者必须一致数据时有时无风速计电量低于 25% 时 LED 红灯闪烁提醒降到 20% 会进入低功耗模式影响数据稳定性应及时更换电池。未来工作当前固件已会将风速计的电池电量以 NMEAXDR报文形式发送给飞控但 ArduPilot 侧尚需相应修改才能解析并展示该值即把电池电量接入 GCS 显示。这是该方案的已知扩展点感兴趣的开发者可在AP_WindVane_NMEA后端中增加对XDR句的解析支持复现MWV句的既有解析框架句头识别、字段校验、校验和验证即可。【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考