Mavlink地面站编写之一–协议分析_mavlink心跳包编写-程序员宅基地

技术标签: mavlink  Mavlink  地面站  pixhawk  

阿木社区:转载注意出处 http://www.amovauto.com

Pixhawk/APM都是采用MAVLINK协议实现的飞控的数据链路传输。先简单介绍下mavlink协议。Mavlink协议最早由 苏黎世联邦理工学院 计算机视觉与几何实验组 的 Lorenz Meier于2009年发布,并遵循LGPL开源协议。Mavlink协议是在串口通讯基础上的一种更高层的开源通讯协议,主要应用在微型飞行器(micro aerial vehicle)的通讯上。Mavlink是为小型飞行器和地面站(或者其他飞行器)通讯时常常用到的那些数据制定一种发送和接收的规则并加入了校验(checksum)功能。据说亿航四轴的初期版本就是参考的MAVLINK协议或者说参考的APM飞控系统。
下面是mavlink的消息简介和官方指导连接:
https://pixhawk.ethz.ch/mavlink/
http://qgroundcontrol.org/mavlink/start
1.1 mavlink消息结构分析:
MAVLINK的传输基本单位是消息帧,一帧的数据长度8bytes到263bytes不等

mavlink-packet_%e5%89%af%e6%9c%ac1

图1.1

如图所示的消息帧结构,除了灰色外,其他格子都代表一个字节的数据,灰色格子里面的数据长度是不固定的。下面是每个消息帧的详细解释:

6222829

%e6%b6%88%e6%81%af%e5%8c%85%e7%bb%93%e6%9e%84

图1.2

上文中已经提到了在mavlink消息帧里最重要的两个东西,一个是msgid;一个是payload,前者是payload中内容的编号,后者则存放了消息。消息有许多种类型,在官网的网页中中以蓝色的“#”加数字的方式来表示消息的编号如 “#0”(这样的表示方法应该是为了方便在网页中查找相应编号消息的定义)。在官网介绍网页里往下拉,大概拉到二分之一的位置处,开始出现“MAVLink Messages”的介绍,往下看是各种消息的数据组成说明。下面将以几个消息为例,讲解mavlink消息

dmz

我们接上数传在串口调试助手具体分析下MAVLINK消息的解析:

mavlink

前面介绍知道MAVLINK的一包数据由FE开头的,一包数据由FE开头到下一个FE出现为截止。

我们来分析个心跳包:  FE  09  12   01   01   00  (00     00   00   00   02   03   51   03   03)   7B   7A

FE为包开头   09为数据包长度   12消息序号  01硬件系统序号  第五位是消息类型序号  括号里面是有效数据载荷(长度为9)  最后两位是数据校位。我们通过消息类型序号可以看到这是0号消息,0号消息是心跳包消息。

重点分析下这个长度为9的有效载荷,心跳包里面有6个成员变量。00     00   00   00   02   03   51   03   03这是有效消息本身会被当作结构体来做解析,mavlink库解析完了之后,就可以从心跳包里面解析出载具类型,处于什么模式。其他消息包也是类似的。我们一般不关心具体的消息解析,mavlink这个库本身支持很多类型的库,python,C++,C#,C语言的库,我们要用到那个平台,我们做相应的移植就好了,移植完的库就可以解析具体的消息了。

 

Type表示设备类型在MAV_TYPE有定义可以在https://pixhawk.ethz.ch/mavlink/ 的网页中搜索到。在上面网站的文档中可以分析到蓝色(#0,#1,#2)这样的数据就是代表数据包。在文档的1/2处往后都可以看到,一共有254条消息类型。

第二个参数是自驾仪(即通常所说的飞控)类型,比如apm,ppz,Pixhawk等飞控,具体定义查找和之前查找飞行器类型时的方法一样。同样的,对于发送心跳包的飞行器来说代表了自己的飞控类性,对地面站发出的心跳包来说意义不大。

第三个参数是基本模式(base mode),是指飞控现在处在哪个基本模式,对于发心跳包的地面站来说没有意义,对于发送心跳包的飞控来说是有意义的。这个参数要看各个飞控自己的定义方式,mavlink介绍网页并不会给出具体的模式。在Pixhawk中基本模式可以分为使用用户模式(custom mode)还是基本模式(这里有点绕,其实是就是是否使用用户模式)。使用用户模式将在讲下个参数时说明,使用基本模式又会分为自动模式(auto),位置控制模式(posctl)和手动模式(manual)。一般情况下都会使用用户模式,普通用户不用关心这个参数。

第四个参数是用户模式(custom mode),大概说一下Pixhawk的用户模式。以多轴为例。它分为主模式(main mode)和子模式(sub mode),两种模式组合在一起成为最终的模式,主模式分为3种,手动(manual),辅助(assist),自动(auto)。手动模式类似apm的姿态模式。在辅助模式中,又分为高度控制模式(altctl)和位置控制模式(posctl)两个子模式,高度控制模式就类似apm的定高模式,油门对应到飞行器高度控制上。位置模式控制飞行器相对地面的速度,油门和高度控制模式一样,yaw轴控制和手动模式一样。自动模式里又分为3个子模式,任务模式(mission),留待模式(loiter),返航模式(return),任务模式就是执行设定好的航点任务,留待模式就是gps悬停模式,返航模式就是直线返回home点并自动降落。在apm里这个参数貌似是没有用的,注意这个数据占了4个字节,在Pixhawk中,前两个字节(低位)是保留的,没有用,第三个字节是主模式,第四个字节是子模式。

以上是心跳包的分析,还有很多其他的数据包的分析类似,请自行翻阅官方指导文件。

1.2消息包封装过程

以上各区域信息存在关联,当使用MavLink协议提供的方法封装消息包时,会根据所使用的MSG获取到该类别MSG消息的LEN信息,同时软件(地面站或飞行控制软件)会根据自身状态信息填写SYS、COMP。信息填写完毕生成数据包时,封装方法会自动添加STX,并在上一次发送消息包所使用的SEQ上加1作为本次发送的SEQ写入,当SEQ超过255时,会回到0并重新开始计数。CKA、CKB会在PAYLOAD信息写入后、封装完成之前,根据CRC[Fe1] (CyclicRedundancy Check)循环冗余校验码算法计算得出并自动写入包内。

也就是说,设定SYS和COMP并且正确调用MavLink所提供方法后,整个消息包的生成过程中仅有MSG和PAYLOAD两项内容需要用户关心,消息包封装过程如活动图所示。

20150828154136387

 

1.3消息包示例

本文开始提到MavLink使用消息库的形式定义传输规则,用户可以在在源码中查阅消息库的内容,此处使用Java语言下的消息库作为实例,以便更清晰地展示包结构(MavLink源码自带了多语言的生成器,可从源码中的xml文件转换为对应C,C++,Java等语言的MavLink协议包)。以下表格中,SEQ为计算得出,数值不固定,故用X代替,SYS,COMP两项为笔者使用的Mission Planner地面站设定的系统ID和组件ID,MSG项0代表HEARTBEAT消息的ID,PAYLOAD内存储详细信息,最后的CKA CKB为封包后计算得出,以Y代替。

msg_heartbeat:最基本的心跳信号包,周期性发送,用于确认地面站与无人机之间的连接是否有效。

STX LEN SEQ SYS COMP MSG PAYLOAD CKA B
254 9 X 255 190 0 …… Y

msg_request_data_stream:数据流请求包,地面站使用该消息包向飞行控制软件提交数据流申请,飞行控制软件收到该消息后将按照设定的参数周期性返回消息包。

STX LEN SEQ SYS COMP MSG PAYLOAD CKA B
254 6 X 255 190 66 …… Y

大概知道了mavlink协议之后呢,我们就可以用MAVLINK结合APM2.6来实现一个APM的地面站。参考Mission Planner的地面站,Mission Planner是采用C#言语,基于C#的易用性,我们也采用C#语言。不过在编写一个简版的地面站以前。我们可以参考Mission Planner的构架,我们可以安装好VS2013,编译一下Mission Planner源码,如果有能力,可以修改Mission Planner源码。MP地面站的编译方法已经在另一篇文章中详细讲述过,编译完了之后有个SimpleExample的简单代码例程在MP的源码中,我们可以分析下这简单的代码,这个简单的代码是引用了MAVLINK的库,具体位置在MissionPlanner-master\ExtLibs\Mavlink中,如果我们要用只要在新建的工程里面引用即可,知道MAVLINK是怎么解析的。

MAVLINK解析示例

主代码如下:

namespace SimpleExample

{
public partial class simpleexample : Form
{
MAVLink.MavlinkParse mavlink = new MAVLink.MavlinkParse();//MAVLINK解析包函数,通过这个函数从串口得到一帧的数据
bool armed = false;
public simpleexample()
{
InitializeComponent();
}
private void but_connect_Click(object sender, EventArgs e)
{
// if the port is open close it
if (serialPort1.IsOpen)
{
serialPort1.Close();
return;
}
// set the comport options
serialPort1.PortName = CMB_comport.Text;//打开串口
serialPort1.BaudRate = int.Parse(cmb_baudrate.Text);
// open the comport
serialPort1.Open();
// set timeout to 2 seconds
serialPort1.ReadTimeout = 2000;
// request streams - asume target is at 1,1
mavlink.GenerateMAVLinkPacket(MAVLink.MAVLINK_MSG_ID.REQUEST_DATA_STREAM,
new MAVLink.mavlink_request_data_stream_t()
{
req_message_rate = 2,
req_stream_id = (byte)MAVLink.MAV_DATA_STREAM.ALL
start_stop = 1,
target_component = 1,
target_system = 1
});//设置mavlink数据缓冲区格式
while (serialPort1.IsOpen)
{
try
{
// try read a hb packet from the compo
var hb = readsomedata<MAVLink.mavlink_heartbeat_t>();//读取一帧心跳数据包
var att = readsomedata<MAVLink.mavlink_attitude_t>();//读取一帧姿态包
Console.WriteLine(att.pitch*57.2958 + " " + att.roll*57.2958);//写入命令行
}
catch{
}
System.Threading.Thread.Sleep(1);
Application.DoEvents();
}
}
T readsomedata<T>(int timeout = 2000)//读取数据函数
{
DateTime deadline = DateTime.Now.AddMilliseconds(timeout);
// read the current buffered bytes
while (DateTime.Now < deadline)
{
var packet = mavlink.ReadPacketObj(serialPort1.BaseStream);//读出一帧数据
if (packet == null)
continue;
Console.WriteLine(packet);//打印在控制台
if (packet.GetType() == typeof(T))
{
return (T)packet;//从一帧MAVLINK数据中返回T类型的数据,T类型是在调用处指定的可以是心跳包,或者姿态包等等。
}
}
throw new Exception("No packet match found");
}
MAVLink.MavlinkParse mavlink 最重要的是这个类,这个类是解析一帧数据包用的,我们来分析下
public partial class MAVLink
{
public static void ReadWithTimeout
public byte[] ReadPacket
public object ReadPacketObj//读取一包数据
public byte[] GenerateMAVLinkPacket//生成一个MAVLINK包,可以同个这个函数来生成读取数据包或者写命令数据包,在解析数据和读取MAVLINK数据之前都要先调用这个函数,生成一个空包,以便放入数据或者写入数据,相当于开辟一个MAVLINK数据缓冲区。
}
以上的程序运行如下:
apmcom_%e5%89%af%e6%9c%ac
图1.4 读取MAVLINK数据包

可以看到在
var hb = readsomedata<MAVLink.mavlink_heartbeat_t>();
var att = readsomedata<MAVLink.mavlink_attitude_t>();
在mavlink_heartbeat_t这个类中有心跳包的成员变量六个。
在MAVLink.mavlink_attitude_t这类中有姿态成员变量。我们可以在VS里面清楚的看到。所以如果我们想读取心跳包和姿态包,就可以使用上面的方法来获取心跳和姿态,很方便。通过上面的代码,我们就可以从APM的串口MAVLINK数据流中解析出想要的数据。我们想读取其他数据,在readsomedata中写入不同的形参即可,具体还有其他什么形参可以在VS里面查看。如果我们要更复杂的界面,做出专业的地面站,就去布局控件即可,不过还是比较复杂的,可以参考MP地面站。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Gen_Ye/article/details/53886482

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线

推荐文章

热门文章

相关标签