2、核心概念与系统连接:System类、Plugin类、回调机制、连接方式
各位同学,欢迎来到第二章。
上一章我们搭好了开发环境,今天要聊的,是MAVSDK里最核心的几个概念。说白了,你搞懂了System类、Plugin类、回调机制和连接方式,后面写航线飞行代码就跟搭积木一样简单。
我个人习惯,学一个新SDK,先看它的对象模型。MAVSDK的设计非常清晰,就两大主角:System 和 Plugin。
2.1 System类:无人机的抽象
System类代表什么?就是你的无人机。它封装了与飞控通信的所有底层细节。
你不需要关心数据包怎么组装的、校验和怎么算的。你只需要拿到一个System对象,然后告诉它:「我要起飞」。就这么简单。
我记得第一次用MAVSDK时,最让我舒服的就是这一点。以前用MAVLink裸协议,光解析心跳包就得写一堆代码。现在呢?
// 伪代码示意
System &system = dc.system(); // 拿到无人机
嗯,拿到system之后,你就可以通过它去调用各种功能了。
核心要点:System对象是单例的,一个连接对应一个System。你不需要自己创建它,MAVSDK内部会帮你管理。
2.2 Plugin类:功能模块化
Plugin类,你可以把它理解成「功能包」。每个Plugin负责一类功能:
- Action:起飞、降落、返航等动作
- Mission:航点任务的上传、下载、执行
- Telemetry:获取姿态、位置、电池等遥测数据
- Offboard:机载计算机直接控制无人机
为什么要拆成这么多Plugin?
你想想看,如果你只需要上传航线,难道还要把整个飞控协议都加载进来吗?没必要。MAVSDK的设计哲学就是「按需加载」。你用哪个功能,就实例化哪个Plugin。
我在项目中遇到过一个问题:有人把所有Plugin都实例化了,结果内存占用多了不少。其实没必要,用哪个new哪个就行。
// 实例化Action插件
Action action(system);
// 实例化Mission插件
Mission mission(system);
小技巧:Plugin对象可以复用。如果你在循环里反复创建销毁,反而浪费性能。建议在初始化阶段一次性创建好。
2.3 回调机制:异步编程的核心
MAVSDK是异步的。什么意思?你调用一个函数,它不会立刻返回结果。比如你发送起飞指令,飞控需要时间响应。这时候就需要回调机制。
回调,说白了就是「你告诉我一声,事情办完了通知我」。
MAVSDK提供了两种回调方式:
- std::function回调:传统方式,传入一个函数指针或lambda
- Future/Promise方式:C++11风格,配合std::future使用
我个人更推荐第二种。为什么?因为代码更清晰,不容易出现回调地狱。
// 回调方式
action.arm_async([](Action::Result result) {
if (result == Action::Result::Success) {
std::cout << "解锁成功!" << std::endl;
}
});
// Future方式(推荐)
auto future = action.arm();
future.wait();
if (future.get() == Action::Result::Success) {
std::cout << "解锁成功!" << std::endl;
}
注意:回调是在MAVSDK内部线程中执行的。不要在回调里做耗时操作,否则会阻塞通信。我曾经见过有人直接在回调里写文件,结果导致丢包。正确的做法是把数据丢到队列里,让主线程去处理。
2.4 连接方式:UDP / TCP / 串口
MAVSDK支持三种连接方式。我按使用频率排序:
| 连接方式 | 适用场景 | 特点 |
|---|---|---|
| UDP | 仿真、局域网通信 | 速度快,不保证可靠 |
| TCP | 远程控制、跨网络 | 可靠,但延迟稍高 |
| 串口 | 实际飞行、机载电脑 | 稳定,波特率需匹配 |
连接代码很简单:
// UDP连接(仿真常用)
Mavsdk dc;
ConnectionResult result = dc.add_udp_connection(14540);
// TCP连接
result = dc.add_tcp_connection("192.168.1.100", 5760);
// 串口连接(实际飞行)
result = dc.add_serial_connection("/dev/ttyUSB0", 921600);
嗯,这里要注意串口的波特率。PX4默认是921600,ArduPilot可能是115200。不匹配的话,连都连不上。我踩过这个坑,当时折腾了半小时才发现是波特率设错了。
2.5 连接状态管理
连接不是一劳永逸的。飞控可能重启、信号可能中断、USB线可能松了。所以,管理连接状态非常重要。
MAVSDK提供了连接状态回调:
dc.register_on_discover([](uint64_t uuid) {
std::cout << "发现无人机,UUID: " << uuid << std::endl;
});
dc.register_on_timeout([](uint64_t uuid) {
std::cout << "无人机超时,UUID: " << uuid << std::endl;
});
我建议你在实际项目中,至少做三件事:
- 连接成功后,启动一个心跳检测线程
- 如果超时,尝试自动重连
- 重连失败后,给出明确的用户提示
避坑指南:我曾经在巡检项目中,无人机飞出去3公里后突然断连。代码里没有重连机制,结果飞机触发了失控保护直接返航。后来我加上了自动重连和状态机管理,再也没出过问题。
2.6 本章知识体系图
下面这张图,帮你理清今天讲的所有概念之间的关系:
这张图展示了MAVSDK的核心架构:Mavsdk对象负责建立连接,连接成功后生成System对象,System对象再派生出各种Plugin。整个通信过程通过回调机制异步完成。
总结一下:
- System = 无人机本体
- Plugin = 功能模块(Action、Mission等)
- 回调 = 异步通知机制
- 连接方式 = UDP/TCP/串口,按场景选
- 状态管理 = 必须做,否则会翻车
好了,这一章的内容就到这里。这些概念是后面所有实战代码的基础。你搞懂了它们,写航线飞行任务就是水到渠成的事。