# WTR-Mavlink-Library
**Repository Path**: I_Robot/WTR-Mavlink-Library
## Basic Information
- **Project Name**: WTR-Mavlink-Library
- **Description**: 移植到 stm32 平台的 mavlink
- **Primary Language**: Python
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2025-04-20
- **Last Updated**: 2025-04-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# WTR Mavlink Library
WTRobot, HITsz
## 介绍
移植到 stm32 平台的 mavlink
MAVLink 是一套消息传输协议。可以使用它方便地在单片机之间传输信息(变量、结构体等),并且有校验机制,可以检测并丢弃传输错误的包。
本库支持 MavLink V1 和 V2 版本的协议。
MAVLink 官网:
## 安装 mavlink
### 获取 mavlink
方法一:克隆或下载本仓库,里面的 `mavlink_1.0.12` 文件夹就是 1.0.12 版本的 mavlink 生成器和 2.4.36 版本的 pymavlink
方法二:从官方库中下载:
1. clone 官方库
```
git clone https://github.com/mavlink/mavlink.git --recursive
```
2. 切换到 release 版本
```sh
cd mavlink
# 查看有哪些版本的 mavlink 库
git tag
# 切换到你希望的版本,例如:
git checkout 1.0.12
cd pymavlink
# 查看有哪些版本的 pymavlink 库
git tag
# 切换到你希望的版本。例如:
git checkout 2.4.36
```
### 安装环境
使用 mavlink 生成消息前,需要安装 python 和一些模块
> 安装参考
> 上面的链接中,Windows 下只需要装好 python 和 future 模块就行了,Linux 下可能还要安装 TkInter
## 开始上手
### 生成自定义消息
消息就是你要发送或接收的一组变量。
消息在 xml 文件中定义。mavlink 会根据 xml 文件生成对应的结构体以及收发函数。
如果想在两个系统之间传输消息,那么这个消息必须在这两个系统中都定义(而且这个消息的id和内容要相同)
#### 编写 `.xml` 文件
可以仿照以下文件编写 `.xml`:
[wtr_mavlink_demo.xml](examples/stm32f103cbt6/UserCode/mavlink/wtr_mavlink_demo.xml)
[test.xml](mavlink_1.0.12/message_definitions/v1.0/test.xml)
> 建议将你写的 xml 文件也放在你的工程目录中,以免以后修改时找不到之前写的文件
以下是 MavLink 官方关于如何选取消息 id 的建议:
> 对于 MAVLink 1:
> - 有效数字介于 0 到 255。
> - ID 0-149 和 230-255 为common.xml保留。 语支可以使用180-229 用于自定义消息 (除非这些信息没有被其他包括语支使用)。
>
> 对于 MAVLink 2 :
> - 有效数字介于0-1677215。
> - 255以下所有值都被认为是保留的,除非报文也打算用于 MAVLink 1。 **注意** ID 在 MAVLink 1 中很宝贵!
> mavlink 官方有一些预定义好的消息(放在这里 [mavlink_1.0.12/message_definitions/v1.0](mavlink_1.0.12/message_definitions/v1.0))。这些消息是官方预设的无人机通信消息,如果不玩无人机就基本上用不到。
详细语法见官方文档:
#### 根据 xml 文件生成库文件
1. 打开 `mavlink/mavgenerate.py`
- XML 选择你刚刚编写的 XML 文件
- Out 选择你想要存放库文件的目录
- Language 选择 C
- Protocol 选择 1.0 或 2.0(看你需求,版本区别官网上有说明)
2. Generate
### 移植到 stm32
1. 将生成的库文件添加到你的 stm32 工程中
2. 将 `src/wtr_mavlink.c` 和 `src/wtr_mavlink.h` 添加到你的 stm32 工程中
3. 对于 MDK,可能要开启 GNU 拓展
4. 根据实际需要,修改 `wtr_mavlink.h` 中的以下内容
```
// 系统 ID 和 组件 ID
static mavlink_system_t mavlink_system = {
1, // System ID (1-255)
1 // Component ID (1-255)
};
// MavLink 能使用的最大通道数
#define MAVLINK_COMM_NUM_BUFFERS 4
```
MAVLink 支持多个系统互相通信。系统可以是上位机、机器人、遥控器、无人机等。一般建议为每个系统分配唯一的 `System ID`。如果一个系统上有多个单片机,建议为每个单片机分配唯一的 `Component ID`。
> 这两个 ID 只是为了让接收方知道消息是谁发过来的。
> MAVLink 原本设想的是为系统上的每个组件(比如说各种传感器)分配一个 `Component ID`,但这里的 mavlink_system 是全局变量,一个单片机不方便设置多个 `Component ID`,所以只能每个单片机分配一个 `Component ID` 了。
> `MAVLINK_COMM_NUM_BUFFERS` 是 MAVLink 最大可用的通道数。通常一个通道对应一个串口。请根据需要分配。设置得越大会占用越多内存。MAVLink 默认为单片机分配 4 个通道。
## 使用 WTR Mavlink Library
使用 mavlink 相关函数前,需要 `#include "wtr_mavlink.h"`
> 只需要包含 `wtr_mavlink.h` 这一个文件就行了,不用包含 mavlink 的其他头文件
### 绑定通道和串口
> mavlink 支持多通道收发,使用 mavlink 的通道前需要先绑定串口,之后对这个通道的发送和接收操作就相当于对绑定的串口的操作(串口要在 CubeMX 里先配置好)
> 一般一个通道对应一个串口,一个通道可以同时收发,通道的数量取决于你在`wtr_mavlink.h`中定义的 `MAVLINK_COMM_NUM_BUFFERS`
使用 `wtrMavlink_BindChannel()` 函数绑定
examples:
```c
wtrMavlink_BindChannel(&huart1, MAVLINK_COMM_0);
wtrMavlink_BindChannel(&huart2, MAVLINK_COMM_1);
```
### 发送消息
mavlink 将你自定义的消息都封装在了结构体里,一个消息对应一个结构体
如名字为 `speed` 的消息在 `mavlink_speed_t` 中
本库采用阻塞式发送,使用如下函数发送结构体(记得绑定通道和串口):
```c
// 向通道X发送结构体,(X要改为对应的数字)
mavlink_msg_xxx_send_struct(MAVLINK_COMM_X, &StructToBeSend);
```
> xxx 为要发送的消息名称
### 接收消息
本库采用中断接收模式,因此如果需要接收消息,必须在 CubeMX 里使能串口全局中断
接收消息需要如下操作:
1. 确保已经绑定通道和串口
2. 在代码中调用:
```c
// 启动通道X对应串口的中断接收
wtrMavlink_StartReceiveIT(MAVLINK_COMM_X);
```
3. 在中断回调函数中调用`wtrMavlink_UARTRxCpltCallback()`
例如:
```c
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// 接收通道X的消息
wtrMavlink_UARTRxCpltCallback(huart, MAVLINK_COMM_X);
}
```
4. 在你喜欢的位置(如 main.c)定义如下函数:
```c
/**
* @brief 接收到完整消息且校验通过后会调用这个函数。在这个函数里调用解码函数就可以向结构体写入收到的消息
*
* @param msg 接收到的消息
* @return
*/
void wtrMavlink_MsgRxCpltCallback(mavlink_message_t *msg)
{
switch (msg->msgid) {
case 1:
// id = 1 的消息对应的解码函数(mavlink_msg_xxx_decode)
mavlink_msg_xxx_decode(msg, &StructReceived);
break;
case 2:
// id = 2 的消息对应的解码函数(mavlink_msg_xxx_decode)
break;
// ......
default:
break;
}
}
```
> 以上代码通过 `msg->msgid` 判断是哪个消息,还可以通过 `msg->sysid` 和 `msg->compid` 判断消息是从哪里来的
## 更多 example
更多 example 可以参考 [examples](examples/) 下的工程
## 性能测试
stm32f103 在 arm-none-eabi-gcc-10.3.1 编译器下:
开启 O3 优化:2M 波特率成功收发,2.5M 波特率接收失败
不开优化:1M 波特率接收失败,115200 (0.1M) 波特率接收成功
## 作者
X. Y.
- github: [MirTITH (github.com)](https://github.com/MirTITH)
- gitee: [TITHChan (tithchan) - Gitee.com](https://gitee.com/tithchan)
## 版本日志
### 1.2
- 增加数组下标溢出判断
- 修改文件注释
### 1.1.1
- 更新 readme
- 添加 .gitignore
- 更新 pymavlink 脚本到 2.4.36 版本
- 发现这个库直接支持 V2 协议(原本是在 V1 协议 mavlink 库上设计的)(😀)
### 1.1
- 修复同时收发时可能的卡串口问题
### 1.0
- 优化性能
- 重构 API
- 使用外部 mavlink_get_channel_status 和 mavlink_get_channel_buffer
- 完善注释
### 0.2
上古代码,赶时间写出来的,有许多问题,和之后的版本差别巨大,不建议使用