RT-Thread mavlink 甜密相拥教程

背景介绍:
Sugar 玩 ArduPilot 开源飞控,离开顺手的地面站很难玩好飞控。
地面站跟飞机间采用 mavlink 通信,而 mavlink 是个独立的通信协议,并不依赖于飞控。
当华夏骄子 RT-Thread 遇上洋气的 mavlink,中西合璧下能否给让物联网锦上添花,那还得看有多少人愿意并能够让两者协起手来。
相比于 Sugar 写过的一篇《物联网通信,如何应用 mavlink 通信协议》,本篇比较干,直击技术层面的代码对接方法。程序员做媒,就是这么强硬。

先上视频

视频链接

无线通信步骤

当我们想要达到某个目标时,三思而后行,把大目标拆成有序的小目标来实现。这样除了更稳,也会更快,回头再看时也更清晰。

  1. 先实现不带协议的无线通信
    这一步的目标是:确定通信相关硬件会用。
  2. 再用 mavlink 报文进行通信
    这一步的目标是:会用 mavlink 进行通信。

本次使用到的硬件有:RT-Thread IoT 开发板(即:正点原子潘多拉开发板)、小马哥四轴遥控器、nRF24L01 无线通信模块。

nRF24L01 双向通信

RT-Thread 代码质量非常高,使用起来也很方便。下面看一下在 RT-Thread 上使用 nRF24L01 的过程。
nRF24L01 在小马哥四轴遥控器上调试的时候没调通,解决办法见《为了解决 RT-Thread nRF24L01 软件包在 STM32F103C8 上死活调不通的问题,我都干了啥?》

源码只需要改 2 个文件一共 4 个地方:

  1. nrf24l01_init.c 有 1 处
    改使用哪个 spi 以及 spi 的片选引脚
  2. sample.h 有 3 处
    改 nRF24L01 使用的 spi 设备是哪个
    改 nRF24L01 的 CE 引脚
    改 nRF24L01 的 IRQ 引脚

改驱动要看原理图,如下:

小马哥四轴遥控器上的代码见如下 github 链接:
https://github.com/SuWeipeng/xm_rc

项目使用 progen 自动生成目标工程,不会用 progen 的请看 Sugar 写过的《一招通吃MDK5、IAR、GCC》

牵手 mavlink

因为加入了 mavlink,消息的打包、解包都需要更多栈空间;
所以首先“加大栈空间”,把收发双方的栈大小加到 2048

因为 nRF24L01 硬件限制一次通信最多 32 个字节,所以报文设计时要注意包长度。相比于 mavlink 2.0,使用 mavlink 1.0 报文的有效载荷会更多一些,因此 Sugar 采用 mavlink 1.0 协议的通信报文。

一、上哪找 mavlink 生成器
通过 Sugar 改过的 mavlink 三平台(MDK5、IAR 和 GCC)代码生成器生成 C 语言头文件。

生成器的开源地址是:
https://github.com/SuWeipeng/mavlink

二、怎样获得需要的 mavlink 源码
1、选择 xml 模板
2、选择生成代码的储存位置
3、选择目标语言为 C 语言
4、选择协议版本为 1.0
5、不勾选 Validate
6、点击 Generate 按钮进行生成

三、发送端使用 mavlink 的方法
1、配置工程头文件的搜索路径,加入 mavlink 相关文件夹

2、在使用 mavlink 的源文件中加入

#include "mavlink.h"

3、定义一个 mavlink 消息包

mavlink_message_t msg;

4、通过生成的目标 API 打包消息内容

mavlink_msg_simple_pack(0,0,&msg,0);

5、将 msg 内容进行重新排列,送入发送缓冲区 tbuf

mavlink_msg_to_send_buffer(tbuf, &msg);

6、为了方便,将发送长度改为 32 个字节
因为 mavlink 本身有校验机制,所以多发几个字节并不影响什么,按 nRF24L01 最大包长度放心发 32 个就好。

7、解包过程
当收到遥控返回的摇杆速度时,对其进行解包,并从串口打印出来。

(1) 先定义 3 个用于解包的变量

uint8_t i;
mavlink_message_t msg_receive;
mavlink_status_t mav_status;

(2) 解包框架

for(i=0; i<32; i++) {
  if(mavlink_parse_char(0, rbuf[i], &msg_receive, &mav_status)) {
    switch (msg_receive.msgid) {
    case MAVLINK_MSG_ID_VELOCITY: {

      break;
    }
    }
  }
}

(3) 解包

 mavlink_velocity_t packet;
 mavlink_msg_velocity_decode(&msg_receive, &packet);

(4) 从调试口打印解包内容

char get_info[50];
sprintf(get_info, "vel_x:%.3f, vel_y:%.3f, rad_z:%.3f\n", packet.vel_x, packet.vel_y, packet.rad_z);
rt_kputs(get_info);

(5) 因为用到了 sprintf() 函数,所以要加入头文件

#include <stdio.h>

四、接收端使用 mavlink 的方法

出于方便考虑,将接收改为直接取 32 字节,并加大线程栈到 2048。

小马哥四轴遥控器上的代码见如下 github 链接:
https://github.com/SuWeipeng/xm_rc

1、在 progen 的 .yaml 配置文件中加入 mavlink 头文件路径
不了解
.yaml 配置文件的请看 Sugar 写过的《一招通吃MDK5、IAR、GCC》

2、在使用 mavlink 的源文件中加入

#include "mavlink.h"

3、Sugar 使用 rtt_interface.h 文件来统一各个源文件的接口,所以要

#include "rtt_interface.h"

4、当 nRF24L01 接收到消息后,对 rbuf 的内容是否是 mavlink 进行验证
(1) 先定义 3 个用于解包的变量

uint8_t i;
mavlink_message_t msg_receive;
mavlink_status_t mav_status;

(2) 解包框架

for(i=0; i<32; i++) {
  if(mavlink_parse_char(0, rbuf[i], &msg_receive, &mav_status)) {

  }
}

(3) 放入目标消息

switch (msg_receive.msgid) {
case MAVLINK_MSG_ID_SIMPLE: {

  break;
}
}

(4) 回复摇杆值

mavlink_message_t msg_ack;
mavlink_msg_velocity_pack(0, 0, &msg_ack, vel.vel_x, vel.vel_y, vel.rad_z);
mavlink_msg_to_send_buffer((uint8_t *)tbuf, &msg_ack);

因为用到了 vel 变量,但 vel 在其他源文件中定义。所以要在源文件上面加入

extern vel_target vel;

PS

本篇内容按功能对代码进行模块化展开,读者只注重使用思路就行了。就像是给孩子们玩儿的图形化编程一样,清楚使用思路之后“拼”就完了。
如果觉得本篇讲得不够易懂,可以在公众号后台回复 mavlink 获得微课视频链接,Sugar 第一次做付费视频,定价 9.9 元(希望能长长久久地做下去)。
如果看过微课视频还觉得不够,可以在“关于我”页面最下方扫码加 Sugar 为好友,约时间在线一对一讲解(收费会更高一些)。

关注作者

欢迎扫码关注我的公众号MultiMCU EDU

提示:在公众号“关于我”页面可加作者微信好友。

喜欢本文求点赞,有打赏我会更有动力。