4、MAVLink代码生成器:MAVLink Generator工具介绍、Python环境配置、从XML生成C语言/Python库、生成文件结构解析
好,咱们进入第四章。说实话,前面三章我们把MAVLink的协议框架、消息结构、心跳包这些概念都捋了一遍。但有个问题你肯定想过:难道每次写代码,都要手撸一个结构体,然后手动计算CRC校验吗?
当然不是。MAVLink官方早就替我们想好了——MAVLink Generator,也就是代码生成器。这玩意儿能把XML定义文件,直接变成C语言或者Python的库。你只需要定义好消息长什么样,剩下的脏活累活,它全包了。
我个人习惯是,拿到一个新项目,第一件事就是跑一遍Generator。省时省力,还不会出错。
4.1 MAVLink Generator是什么?
说白了,它是一个Python脚本工具。输入是XML文件,输出是C语言头文件或者Python模块。你想想看,MAVLink协议有几百种消息,要是全手写,光是枚举类型就能把人写吐。
Generator的核心逻辑其实不复杂:
- 解析XML中的消息定义
- 生成对应的结构体
- 生成序列化/反序列化函数
- 生成CRC校验表
我在项目中遇到过最头疼的事,就是有人手动改了生成后的代码,结果XML更新后,两边对不上了。嗯,这里要注意:永远不要手动修改生成的文件。要改就改XML,然后重新生成。
4.2 Python环境配置
Generator是用Python写的,所以你得先配好Python环境。别担心,步骤很简单。
4.2.1 安装Python
我建议用Python 3.8以上版本。太老的版本有些依赖库装不上。
# 检查Python版本
python --version
# 如果没有安装,去python.org下载
# 或者用包管理器
sudo apt install python3 python3-pip # Ubuntu
brew install python3 # macOS
4.2.2 安装依赖库
Generator依赖的库不多,主要是lxml和future。我曾经因为忘记装lxml,卡了半天,还以为脚本坏了。
pip install lxml future
pip download把包下载到本地,再离线安装。我踩过这个坑,分享给你。
4.2.3 获取MAVLink源码
Generator脚本在MAVLink的官方仓库里。你需要把整个仓库clone下来。
git clone https://github.com/mavlink/mavlink.git
cd mavlink
仓库结构大致是这样的:
mavlink/
├── pymavlink/ # Python库
├── generator/ # 代码生成器
│ ├── mavgen.py # 主脚本
│ ├── mavparse.py # XML解析器
│ └── mavtemplate.py # 模板引擎
├── message_definitions/ # XML定义文件
│ ├── v1.0/
│ └── v2.0/
└── ...
4.3 从XML生成C语言库
好,环境配好了,咱们来实战。生成C语言库是最常见的需求,因为大部分飞控、地面站都是用C写的。
4.3.1 基本命令
cd generator
python mavgen.py --lang=C --output=../my_mavlink_lib ../message_definitions/v1.0/common.xml
这条命令的意思是:
--lang=C:指定生成C语言代码--output=../my_mavlink_lib:输出目录common.xml:输入的定义文件
运行完后,你会看到my_mavlink_lib目录下多了一堆文件。别慌,我来给你拆解。
3.3.2 生成文件结构解析
生成后的目录大概长这样:
my_mavlink_lib/
├── mavlink.h # 总头文件,包含所有子模块
├── common/
│ ├── mavlink.h # common协议的头文件
│ ├── mavlink_msg.h # 消息定义
│ ├── mavlink_helpers.h # 辅助函数
│ ├── mavlink_types.h # 基础类型定义
│ ├── mavlink_sha256.h # SHA256校验(v2.0用)
│ └── mavlink_versions.h # 版本信息
├── checksum.h # CRC校验表
├── protocol.h # 协议版本定义
└── ...
我来挑几个重点文件说说:
| 文件名 | 作用 | 我的一点经验 |
|---|---|---|
mavlink.h |
总入口,include了所有子模块 | 你只需要在代码里include这一个头文件就行 |
mavlink_msg.h |
所有消息的编解码函数 | 比如mavlink_msg_heartbeat_pack()就在这里 |
checksum.h |
CRC-16-MCRF4XX校验表 | 我曾经手算过一次,算完就决定这辈子都用生成器了 |
mavlink_types.h |
定义了mavlink_message_t等基础结构 |
这个文件一般不用动,但建议看一眼结构体布局 |
4.3.3 在C项目中使用
生成完库之后,怎么用?很简单:
#include "my_mavlink_lib/mavlink.h"
int main() {
mavlink_message_t msg;
uint8_t buf[MAVLINK_MAX_PACKET_LEN];
// 打包心跳包
mavlink_msg_heartbeat_pack(
1, // system_id
1, // component_id
&msg,
MAV_TYPE_QUADROTOR,
MAV_AUTOPILOT_PX4,
MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
0,
MAV_STATE_ACTIVE
);
// 序列化到缓冲区
uint16_t len = mavlink_msg_to_send_buffer(buf, &msg);
// 然后通过串口、UDP等发送出去
// send(buf, len);
return 0;
}
你看,几行代码就搞定了。不用自己算CRC,不用自己拼字节流。这就是Generator的价值。
4.4 生成Python库
Python库的生成更简单,因为MAVLink官方已经提供了pymavlink这个包。但如果你想自定义协议,还是得用Generator。
4.4.1 生成命令
python mavgen.py --lang=Python --output=../my_mavlink_python ../message_definitions/v1.0/common.xml
生成后的文件结构:
my_mavlink_python/
├── __init__.py
├── common.py # 所有消息的Python类
├── mavlink.py # 核心编解码逻辑
└── ...
在Python里用起来更爽:
from my_mavlink_python import MAVLink
# 创建MAVLink实例
mav = MAVLink(None)
# 打包心跳包
msg = mav.heartbeat_encode(
type=MAV_TYPE_QUADROTOR,
autopilot=MAV_AUTOPILOT_PX4,
base_mode=0,
custom_mode=0,
system_status=MAV_STATE_ACTIVE
)
# 序列化
buf = msg.pack()
# 或者直接发送
# mav.send(msg)
4.5 自定义XML定义
有时候官方协议不够用,你得自己加消息。比如我做过一个项目,需要传输摄像头云台的姿态数据,官方没有现成的消息。怎么办?自己写XML。
<?xml version="1.0"?>
<mavlink>
<version>2</version>
<messages>
<message id="150" name="CAMERA_GIMBAL_ATTITUDE">
<description>云台姿态信息</description>
<field type="float" name="roll" units="rad">横滚角</field>
<field type="float" name="pitch" units="rad">俯仰角</field>
<field type="float" name="yaw" units="rad">偏航角</field>
</message>
</messages>
</mavlink>
然后跑Generator:
python mavgen.py --lang=C --output=./my_custom_lib my_custom.xml
搞定。你的自定义消息就有了对应的C结构体和编解码函数。
4.6 生成文件结构总览
为了让你有个整体印象,我画了一张图,展示Generator的工作流程和输出结构。
这张图把整个流程串起来了。你从左边输入XML,中间Generator处理,右边输出C或Python库。下面还列出了C库的关键文件。
4.7 避坑指南
最后,分享几个我踩过的坑:
- 路径问题:Generator对路径大小写敏感。我曾在Windows上因为路径大小写不对,报了一堆莫名其妙的错。
- XML语法:XML里字段顺序很重要。Generator是按顺序解析的,如果你把
<field>顺序写错了,生成的结构体字段顺序也会错。 - 版本匹配:Generator版本要和MAVLink协议版本匹配。v1.0的XML不能直接用v2.0的Generator生成,反之亦然。
- 编码问题:XML文件必须用UTF-8编码。我遇到过用GB2312编码的XML,Generator直接崩溃。
好了,这一章的内容就到这儿。Generator是个好工具,但用好它需要一点经验。希望我的这些分享能帮你少走弯路。
公众号:蓝海资料掘金营,微信deep3321