精华内容
下载资源
问答
  • <link rel="stylesheet" href=... <div class="htmledit_views" id="content_views"> XBee模块是Digi公司的一款采用ZigBee技术的无线模块,通过串口与单片机等设备间进行通信,能够...

    XBee模块是Digi公司的一款采用ZigBee技术的无线模块,通过串口与单片机等设备间进行通信,能够非常快速地实现将设备接入到ZigBee网络的目的,我最近做的一个项目使用了该模块,感觉非常的好用,开发基于ZigBee的无线通信来说是很easy了。此模块采用802.15.4协议栈,通过配置可以用作ZigBee网络中的Coordinator、Router或者End Device节点。XBee按照性能分为XBee和XBee pro两种,XBee pro相对于XBee具有更高的功耗和更远的传输距离,它们对外的接口基本相同,可以根据实际项目的要求来选择。

    XBee的引脚如下图所示:

     

    最简单的使用方式下只需要将单片机的串口与XBee模块的串口(Pin2、Pin3、Pin10)相连即可,另外也可通过RTS(Pin16)、CTS(Pin12)进行流控,单片机与XBee模块串口的连接如下图所示:

    XBee模块与单片机的串口通信有transparent和API两种操作模式:

    (1)transparent操作模式:

    单片机直接通过串口将要传输的数据发送给XBee模块,XBee模块按照ZigBee协议将数据通过无线发送给远端的XBee模块,再通过串口发送给远程的单片机,就好像两个单片机之间通过XBee模块建立了一条透明传输通道。如果要通过串口配置本地XBee模块的参数,则可以向XBee模块输入+++,等待XBee模块返回OK后即可通过AT指令集对XBee模块进行参数的配置。这里使用Digi公司的XCTU软件进行演示(XCTU的具体使用以后再进行详细的介绍,其实就是通过串口与XBee模块交互的软件),如下图所示:

    (2)API操作模式:

    在API操作模式下,所有发送给XBee模块的数据或是从XBee模块接收的数据都会封装成特殊的API帧的格式,包括ZigBee无线发送和接收的数据帧、XBee模块配置的命令帧(等同于transparent操作模式里面的AT指令)、命令响应帧、事件消息帧等。相比于transparent操作模式,API操作模式虽然相对复杂一点,但是提供很多transparent操作模式下无法完成的功能:

    API操作模式下,只需要改变API帧里面的目的地址,就可以将数据传输给多个不同的远程节点,而transparent操作模式下要改变远程目的地址只能先进入AT命令下配置目的地址,在进行数据传输。而且API可以接收数据是否发送成功的状态;

    接收到的远程节点的数据可以获取远程节点的地址以确认是哪个节点发送的;

    获取远程节点的IO采样数据;

    通过API帧还可以配置远程XBee模块的参数。

    API模式的使用将在以后的文章中进行详细介绍。

     

    XBee模块还具有以下的一些比较实用的功能,简要介绍一下:

    (1)支持IO的输入输出,AD采样

    上面引脚图中的Name列含有DIOx字样的引脚表示可以进行数字IO的采样输入或者输出高低电平,通过AT指令配置引脚复用的参数即可;

    含有ADx字样的引脚表示可以进行模拟电压的AD采样输入,采样电压范围为0~1200mV,采样值范围0~0x3FF,此外还可以对Vcc电压进行采样。

    XBee可以将采样数据直接通过ZigBee网络发送给远程节点。这样,在API操作模式下,可以使用远程配置命令控制远程XBee节点开启采样,采样后的数据直接传给本节点,还可以控制远程节点IO输出来控制远程XBee接的外围设备。

    (2)ZigBee网络安全
    XBee支持多个等级安全模式,加密方式采用128位的AES加密,如下图:

     

    (3)可通过串口Xmodem升级XBee的固件

    将DTR(Pin9)、DIN(Pin3)置为低电平,RTS(Pin16)置为高电平后复位XBee模块即可进入XBee的bootloader,串口通信波特率变为115200,输入回车后可获得菜单,选择相应的选项后可以通过Xmodem将XBee固件传送给模块进行升级。

     

    最新的XBee支持SPI的通信方式,还有集成处理器芯片的XBee模块等,那些功能我还没有研究使用过,所以就暂时不做介绍了,接下去的文章我将详细介绍XBee模块使用的具体操作方式与细节。

    欢迎大家来吐槽~

    展开全文
  • 本文主要介绍ZigBee网络的基本结构,三种组成ZigBee网络的基本节点:协调器(coordinator)、路由器(router)、终端(end device),如何使用XCTU对XBee进行基本参数的配置,使XBee成为ZigBee网络中的一个节点。

    本文主要介绍ZigBee网络的基本结构,三种组成ZigBee网络的基本节点:协调器(coordinator)、路由器(router)、终端(end device),如何使用XCTU对XBee进行基本参数的配置,使XBee成为ZigBee网络中的一个节点。

    ZigBee网络中定义了三种不同类型的设备:

    协调器(coordinator)

    每个ZigBee网络中只允许有一个协调器,它是整个网络的开始,协调器首先选择一个信道(channel)和网络标识(PAN ID)来启动一个ZigBee网络,然后允许路由器和终端加入这个网络。协调器在建立ZigBee网络之后,其功能相当于路由器,可以进行数据的路由转发,可以为它的终端子设备缓存数据包,协调器本身不能休眠。

    路由器(router)

    路由器首先必须加入到一个ZigBee网络中,然后路由器也是允许其他路由器和终端加入这个网络,进行数据的路由转发,为它的终端子设备缓存数据包,同样路由器也不能休眠。

     终端(end device)

    终端也必须加入到一个ZIgBee网络中才能工作,但它不支持其他设备加入ZigBee网络,也不能进行数据的路由转发,终端数据的收发必须通过其父设备进行转发。终端可以休眠进入低功耗的模式,一般可以采用电池进行供电。

    ZigBee网络的基本拓扑结构如下图所示:

     

    一个XBee模块只能选择成为以上三种设备类型的其中一种,对于老的硬件XBee S2或Xbee S2B来说,需要给XBee模块升级不同的固件来改变设备类型和操作方式(API或Transparent),固件版本对应类型如下:

    20xx - Coordinator - AT/Transparent Operation
    21xx - Coordinator - API Operation
    22xx - Router - AT/Transparent Operation
    23xx - Router - API Operation
    28xx - End Device - AT/Transparent Operation
    29xx - End Device - API Operation

    而对于新的XBee S2C(固件版本为40xx)来说,只需要通过配置XBee参数就可以改变设备类型或操作方式,下面仅以XBee S2C模块为例进行说明。

    在默认参数的情况下,XBee模块为路由器transparent模式,通过AT指令设置CE为1可以将XBee设置为协调器,设置SM为一个非零值可以将XBee设置为终端。注意:作为协调器时SM必须设置为0,作为终端时CE必须设置为0,CE和SM同时为0则为路由器。此外,设置AP为0为transparent模式,设置AP为1或2则为API模式。

    将XBee模块通过串口与PC相连,使用XCTU对模块进行测试、修改参数,首先搜索与PC连接的XBee模块,默认波特率为9600,如下图:

     成功添加XBee模块后选中XBee模块可以获取到该模块对应的配置参数并进行修改,如下图:

    通过修改CE、SM和AP的值可以改变XBee模块的ZigBee设备类型和操作方式。当然,也可以手动向XBee模块的串口发送AT指令来修改参数,如下图:

     

    在配置完XBee模块的参数后,我们进行XBee模块的组网通信,以两个XBee模块为例,一个设置为协调器,一个设置为路由器,都为transparent操作模式,设置DH和DL的值为目的地址(接收数据的XBee模块的MAC地址,即SH和SL的值),如果发送的目的地址为协调器,也可以设置DH和DL为0。上电后XBee模块会按照配置的参数自动完成ZigBee的组网。使用XCTU分别打开协调器和路由器的串口连接,向路由器串口发送数据,可以在协调器的串口观察到路由器发送过来的数据,说明组网通信成功,如下图所示:

    当然,可以使用更多的XBee模块,组成一个多跳的ZigBee网络,网络中的XBee节点只要配置目的地址为任何一个在ZigBee网络中存在节点的64位MAC地址,就可以将数据通过ZigBee网络送达,组网和多跳路由的功能将由XBee模块自动完成。需要注意的是,如果一个XBee路由器节点之前已经接入过其他的ZigBee网络,那么他的PAN ID将始终保存,这样就无法再加入其他ZigBee网络,即使断电重启也不会改变,需要使用ATNR0命令来退出之前ZigBee网络,之后就可以自动搜索加入新的ZigBee网络了。

    我们可以看到,在采用transparent操作方式下,如果需要将数据发送给网络中的多个节点,需要首先进入AT命令模式修改DH和DL的值,再发送数据,非常繁琐。而采用API操作方式可以指定发送的目的地址,非常方便,API操作方式将在以后进行介绍。

    展开全文
  • xbee中文教程

    2013-12-01 22:42:02
    xbee中文文件,简单实用,搬运过来的东东,看过了确实是好东西,值得大家分享
  • 介绍XTCU-Xbee参数配置及调试软件,可用于配置xbee模块的波特率、网络ID、组网方式,设置模块类型,以及对模块进行初始的调试等。
  • XBee Pro 900HP的基本配置

    为使无人机编队个体间实现组网通信,需要选用合适的通信模块构建通信网络。前期曾试用ZIGBEE模块(DRF1605),但其传输速度不能令人满意——每秒最快只能接收10个数据包,320个字节,将近2.4Kbps。近来经过调研发现,XBee系列的模块或许可以更好的解决机间组网通信问题。本篇博客即结合XBee PRO 900HP 模块来记录其基本配置和使用情况。

    一、编队通信需求及XBee PRO 900HP 模块的基本性能参数

    XBee PRO 900HP 模块的资料可参考已上传 资源文档。在考虑选用编队通信模块时,我们实际上期望其能到达以下几点要求:

    1. 尽量可以兼容发送PX4飞控大部分的mavlink数据包;
    2. 一个数据包至少能发送X,Y,Z三方向位置、速度数据;
    3. 可以实现多机分布式的组网;
    4. 邻近节点间的通信距离最远不小于100米。

    对于第一点,PX4飞控中的mavlink通信数据包比较重要有:心跳包-9个字节;姿态数据-28个字节;经纬度-28个字节,传感器数据-64个字节等,因此,所选通信模块容许的数据包负载字节数至少是64个字节;再考虑下通信频率,综合通信频率应不低于50Hz,那么1秒钟最低需传输字节数为3200,即传输速率最低不小于为25.6Kbps。

    对于第二点,X,Y,Z三方向位置、速度数据以float32类型计算,单个数据包负载字节数应不小于8*6=48个字节;

    对于第三点,需要通信模块可自由设置集群系统中任意两个节点的通信情况,即通信网络拓扑可自由配置;

    对于第四点,主要是为了进行室外编队飞行实验。

    通过查阅相关技术手册,XBee PRO 900HP 模块的部分性能如下图所示:

    XBeePRO900HP相关性能参数

    图1 XBeePRO900HP相关性能参数

    上图表明XBee模块在室内305米内或室外6.5km内的通信速率都能达到200Kbps。此外,在数据手册的58页,我们看到其数据负载长度需要用2~3个字节来存储其数目,也就是说每个数据包至少可传输数据 2 16 = 1024 2^{16}=1024 216=1024字节:
    XBeePRO900HP数据包字节长度

    图2 XBeePRO900HP数据包字节长度

    因此可以满足我们编队开发需要的1、2、4点要求。对于组网模式,XBee PRO 900HP 模块可实现的组网有集中式的组网和分布式的组网,如下图所示:
    在这里插入图片描述

    图3 XBeePRO900HP组网模式

    因此XBee PRO 900HP 模块完全满足我们编队组网的的需要。对了,该模块外形如图4所示:
    XBeePro900HP模块

    图4 XBeePro900HP模块

    二、利用软件XTCU配置XBee PRO 900HP 模块

    配置Xbee模块需要用到XTCU软件,该软件界面如下图所示:

    XTCU软件

    图5 XTCU软件

    利用软件XTCU对XBee进行参数配置主要参考其用户手册。一般需要配置的参数有:

    1. 网络ID:相当于标识当前Xbee模块属于哪个通信网络中;
    2. 波特率:每个模块必须配置相同的波特率(可以理解为通信速率),且该波特率还要与飞控的波特率一致,这样才能确保正常通信;
    3. 组网模式:XBee模块间的通信有透传模式和API模式两种。透传模式下,XBeee模块只有主机和从机之分,就和蓝牙一样只有一对模块间通信,不是我们需要的;另一种API通信模式就可以多点之间组网通信,也就是我们需要通信方式。

    与ZigBee模块类似,XBee模块组网时,也需要网络中有且仅有一个节点模块作为协调器(),其余节点作为路由器(router)。我们可以先配置好网络中的一个协调器节点和路由节点,然后依次添加新的路由节点到网络中。下面给出具体步骤:

    1. 首先按照图4的方式连好两个XBee PRO 900HP 模块(一个协调器和一个路由器)。需要注意的是,在购买该模块时,要同时采购具有USB接口的底板,这样才能方便的连接到电脑上,此外电脑需要安装CH340的驱动,这样连接上模块(可以利用360驱动自动搜索安装)。
    2. 打开XTCU软件,添加XBee设备。如图6所示,点击搜索按钮:
      打开XTCU软件搜索端口
    图6 打开XTCU软件搜索端口

    选中端口,点击Next:
     选中端口

    图7 选中端口

    点击finish:

    点击finish

    图8 点击finish

    等待检测:

    等待检测

    图9 等待检测

    添加设备:
     添加设备

    图10 添加设备
    1. 配置参数。点击第一个设备,然后点击参数配置窗口:

     选择配置窗口

    图11 选择配置窗口

    修改网络ID:
    修改网络ID

    图12 修改网络ID
    图中的红色标记的第2步是写入修改的参数。此外网络ID可以自己随便设置,不一定是图中的1234,但应当是两个字节的16进制数。

    利用同样的方法修改网络类型为协调器:

    修改模块类型

    图13 修改模块类型

    修改波特率:

    修改波特率

    图14 修改波特率

    将网络改成API模式(即分布式组网模式):
    选择API组网模式

    图15 选择API组网模式
    1. 以上就将模块配置成协调器了。我们可以保存参数,然后用于配置路由器时,只需修改图13步骤的模块类型就行了。保存参数方法如下图所示:
      保存参数
    图16 保存参数
    1. 配置路由器时点击左栏第二个模块,然后点击右栏那个Profile人像按钮,选择第一个Apply configuration profile,找到之前保存的参数配置文件就能和协调器配置一样的参数,但注意需要按图13的方式将模块类型改为路由器。
      改路由端口
    图17 改路由端口

    下面测试数据传输功能:

    1. 选择控制台,连接模块(协调器和路由器都要通过此操作进行连接):

    选中控制台

    图18 选中控制台

    点击“+”号按钮,创建适合API格式的数据包
    添加待发送的数据包

    图19 添加待发送的数据包

    生成符合格式要求的的数据包:
    生成符合格式要求的的数据包

    图20 生成符合格式要求的的数据包

    注意:图中第二个红色箭头指示的"FFFF"是表示广播该数据包,如果要指定某个节点发送,需要该对方节点的mac地址,mac地址可以从左栏模块信息中看到:

    模块mac地址

    图21 模块mac地址

    图20所述步骤点击OK,然后就生成了发送字符串Hellow的数据包,之后就可以点击发送:
    发送数据包

    图22 发送数据包

    接收端可查看数据:
    接收端查看数据

    图23 接收端查看数据

    三、数据通信协议分析

    从图20可以看出,模块间的通信协议发送包格式为:

    数据包头(0x7E)+字长(2个字节)+发送协议类型(0x10)+发送协议ID(0x01)目标64位地址(8个字节,即mac地址)+目标16位地址(FFFE)+广播半径(00)+选项(00)+数据(N个字节)+校验码(1个字节)

    对于字长,实际上计数的是排在它之后所有数据字节之和(校验码除外),也就是从协议类型(0x10)到校验码之前的长度,假设实际负载的数据是N个字节的话,那么字长计数值就为:1+1+8+2+1+1+N=N+14;

    接收协议与发送协议基本相同,只是目标地址变成了发送源地址。即:
    数据包头(0x7E)+字长(2个字节)+接收协议类型(0x90)+来源64位地址(8个字节,即mac地址)+来源16位地址(FFFE)+选项(0xC1)+数据(N个字节)+校验码(1个字节)

    注意,接收的字长和发送的字长并不一致,前者比后者少2个字节(少了发送协议ID和广播半径),为N+12。比如某次发送信息要求从A发给B,二者mac地址分别为:

    A的mac地址为:00 13 A2 00 41 08 01 0B
    B的mac地址为:00 13 A2 00 41 08 01 12
    

    要发送的数据包内容为:

    hellpw
    

    其ascll码转化为16进制为:

    68 65 6C 6C 70 77
    

    则发送字长为6+14=20=0x14,发送数据包为:
    7E 00 14 10 01 00 13 A2 00 41 08 01 12 FF FE 00 00 68 65 6C 6C 70 77 54

    接收字长为6+12=18,其数据包为:
    7E 00 12 90 00 13 A2 00 41 08 01 0B FF FE C1 68 65 6C 6C 70 77 1B

    校验码的计算方式如下:

    • 添加数据包的所有字节,但数据包头0x7E和长度(第二个和第三个字节)除外。
    • 根据结果​​,仅保留最低的8位。
    • 0xFF减去该数量

    对于上述接收包计算过程即为:

    1. 数据累加:90 + 00 + 13 + A2 + 00 + 41 + 08 + 01 + 0B + FF + FE + C1 + 68 + 65 + 6C + 6C + 70 + 77 =6E4
    2. 保留后八位,即:E4
    3. 校验码=FF-E4=1B

    最后,需要指出,发送端的Xbee模块若成功发送数据还会收到一个反馈,其格式为

    数据包头(0x7E)+字长(2个字节)+协议类型(0x88)+16位地址(FFFE)+ 失效重发次数(1个字节)+传输状态(1个字节,成功为00)+ discovery status(1个字节,暂时不清楚用法)+ 校验码(1个字节)

    如一次成功的发送得到的反馈可能如下:

    7E 00 07 8B 01 FF FE 00 00 00 76

    展开全文
  • XBee PRO 900HP 模块的数据手册,主要可用于查阅该模块的基本性能参数,如通信速率、通信距离、功耗以及组网模式等。
  • 本篇博客介绍如何利用XBee模块实现QGC地面站与飞控的通信

    本篇博客介绍如何利用XBee模块实现QGC地面站与飞控的通信

    一、问题的提出

    正如 上一篇博客 指出,PX4飞控原装数传模块(3DR Radio)只能一对一通信,并不能实现多机组网通信,而XBee模块可以弥补以上不足,因此,为实现后续多机编队分布式控制,用XBee模块来替代原装数传进行无线通信势在必行。鉴于地面站具备友好的显示功能,此项任务的核心工作就是实现基于XBee模块的QGC地面站与飞控之间的通信,这样就能为后续多机组网通信的调试奠定基础。

    二、基本思路

    上篇博客 中可以看出XBee模块有自己的通信协议,与PX4飞控原装的mavlink协议有较大的差异,因而可以想到修改与mavlink通信相关代码是实现XBee模块通信的关键。另外模块之间的通信,除去中间传输过程,两端节点要处理的其实就是根据通信协议对信息进行解码和编码 。因此,添加XBee模块的基本思路如下:

    1. 找到QGC地面站中涉及到mavlink通信解码和编码部分程序,修改使之兼容XBee模块的通信协议;
    2. 同样地,找到PX4飞控源码中涉及到mavlink通信解码和编码部分程序,修改使之兼容XBee模块的通信协议;
    3. 通信测试和功能完善。

    三、开发过程

    如下:

    3-1 QGC地面站部分修改

    QGC地面站部分源码的学习主要参考B站UP主 胡萝卜科技上传的教学视频。根据视频中的相关介绍,与mavlink通信协议的编/解码相关的程序代码主要位于以下三个文件中(位于文件夹:../qgroundcontrol/libs/mavlink/include/mavlink/v2.0/):

    • mavlink_helpers.h
    • mavlink_types.h
    • checksum.h

    其中, mavlink_helpers.h文件中有解码和编码的函数,mavlink_types.h给出了与通信协议相关的变量定义(如数据包帧头,编/解码序列格式), checksum.h文件则定义了校验码生成函数(源码中使用的是哈希校验,与XBee的求和校验并不相同)。

    (1) mavlink_helpers.h

    该文件中编/解码的函数分别为

    • mavlink_msg_to_send_buffer(uint8_t *buf, const mavlink_message_t *msg)//编码函数
    • mavlink_finalize_message_buffer(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, mavlink_status_t* status, uint8_t min_length, uint8_t length uint8_t crc_extra)

    通过这两个函数,我们可以知道mavlink通信协议有两个版本,数据包帧头分别为:

    • MAVLINK_STX_MAVLINK1:0xFE
    • MAVLINK_STX: 0xFD

    当前用的是2.0的版本,协议格式如下

    【数据包字节序号】字节含义
    1帧头:开始标志0xFD
    2有效载荷长度0-255
    3incompat_flags暂时不了解,似乎常取0
    4compat_flags暂时不了解,似乎常取0
    5消息序列(SEQ)0-255,传输计数,用于计算丢包率
    6系统ID1-255,区分不同的飞控
    7组件ID0-255, 区分同一飞控里不同的组件,如相机
    8~10消息ID三个字节,0~ 2 24 2^{24} 224,标记本数据包类型
    11~N+10消息内容数据最多253字节 , N ≥ 1 N\geq1 N1
    N+11~N+12校验码2字节

    注意,mavlink的发送协议和接收协议是一致的,但是XBee的不同, 根据上一篇博客 所述,其发送协议为:

    【数据包字节序号】字节含义
    1帧头:开始标志0x7E
    2~3有效载荷长度2个字节
    4发送协议类型0x10
    5发送协议ID0x01
    6-1364位目标地址8个字节
    14~1516位目标地址2个字节,0xFFFE
    16广播半径0x00
    17选项0x00
    18~N+17消息内容数据N个字节
    N+18校验码1个字节

    接收协议为:

    【数据包字节序号】字节含义
    1帧头:开始标志0x7E
    2~3有效载荷长度2个字节
    4接收协议0x90
    5-1264位来源地址8个字节
    13~1416位来源地址2个字节,0xFFFE
    15选项0xC1/0xC2
    16~N+15消息内容数据N个字节
    N+16校验码1个字节

    为了尽可能与mavlink统一,我们可以对XBee通信协议中的消息内容数据进行进一步结构化处理,以发送协议为例,可划分如下:

    【18~N+17 】消息内容数据共N个字节
    18消息序列(SEQ)0-255,传输计数,用于计算丢包率
    19系统ID1-255,区分不同的飞控
    20组件ID0-255, 区分同一飞控里不同的组件,如相机
    21~23消息ID三个字节,0~ 2 24 2^{24} 224,标记本数据包类型
    24~N+10消息内容数据N-6个字节

    相应的,mavlink_helpers.h中的编码函数(发送对应编码)可添加XBee发送协议编码内容:

        if(status->flags==MAVLINK_STATUS_FLAG_IN_XBEE){
            msg->magic = MAVLINK_STX_XBEE;
            header_len = MAVLINK_XBEE_HEADER_LEN+1;
            msg->len = _mav_trim_payload(_MAV_PAYLOAD(msg), length);
            msg->transfer_type=MAVLINK_SENDTYPE_XBEE;
            msg->transfer_ID=MAVLINK_SENDID_XBEE;
            if(msg->addr64==0)
            {
                msg->addr64=0x000000000000FFFF;
            }
            if(msg->addr16==0)
            {
                msg->addr16=0xFFFE;
            }
            msg->opt_xbee=OPT_SEND_BYTE;
            msg->brdcst_r=BRDCST_R;
        }
        ...
        if(status->flags==MAVLINK_STATUS_FLAG_IN_XBEE)
        {
            signature_len=0;
            signing=false;
            buf[0] = msg->magic;
            buf[1] = 0;
            buf[2] = length+14+6;
            buf[3] = msg->transfer_type;
            buf[4] = msg->transfer_ID;
            buf[12] = msg->addr64 & 0xFF;
            buf[11] = (msg->addr64>>8)&0xFF;
            buf[10] = (msg->addr64>>16)&0xFF;
            buf[9] = (msg->addr64>>24)&0xFF;
            buf[8] = (msg->addr64>>32)&0xFF;
            buf[7] = (msg->addr64>>40)&0xFF;
            buf[6] = (msg->addr64>>48)&0xFF;
            buf[5] = (msg->addr64>>56)&0xFF;
    
            buf[14] = msg->addr16&0xFF;
            buf[13] = (msg->addr16>>8)&0xFF;
            buf[15] = msg->brdcst_r;
            buf[16] = msg->opt_xbee;
    
            buf[17] = msg->seq;
            buf[18] = msg->sysid;
            buf[19] = msg->compid;
    
            buf[20] = msg->msgid & 0xFF;
            buf[21] = (msg->msgid >> 8) & 0xFF;
            buf[22] = (msg->msgid >> 16) & 0xFF;
    
            msg->checksum = crc_calculate2(&buf[3], header_len-3);
            crc_accumulate_buffer2(&msg->checksum, _MAV_PAYLOAD(msg), msg->len);
            msg->checksum=msg->checksum & 0xFF;
            msg->checksum=0xFF-msg->checksum;
            checksum_len=1;
    
        }
    

    接收协议也可做类似的处理。修改后的 mavlink_helpers.h参考 资源文件

    (2) mavlink_types.h

    该文件中定义了与通信协议相关的变量,主要有:

    • mavlink_parse_state_t:解码次序标记
    • mavlink_framing_t解码结果反馈
    • 协议类型宏定义:
    #define MAVLINK_STATUS_FLAG_IN_MAVLINK1  1 // last incoming packet was MAVLink1
    #define MAVLINK_STATUS_FLAG_OUT_MAVLINK1 2 // generate MAVLink1 by default
    #define MAVLINK_STATUS_FLAG_IN_SIGNED    4 // last incoming packet was signed and validated
    #define MAVLINK_STATUS_FLAG_IN_BADSIG    8 // last incoming packet had a bad signature
    
    • mavlink_status_t:协议状态结构体变量
    • mavlink_message_tmavlink消息结构体

    为使之兼容XBee,可增加如下内容:

    //mavlink_parse_state_t
    typedef enum {
        MAVLINK_PARSE_STATE_UNINIT=0,
        ...
        MAVLINK_PARSE_STATE_GOT_RCVTYPE,//7
        MAVLINK_PARSE_STATE_GOT_SRCADDR64,//8
        MAVLINK_PARSE_STATE_GOT_SRCADDR16,//9
        MAVLINK_PARSE_STATE_GOT_OPTTYPE,//10
       ...
        MAVLINK_PARSE_STATE_SIGNATURE_WAIT
    } mavlink_parse_state_t; ///< The state machine for the comm parser
    
    //mavlink_message_t
    MAVPACKED(
    typedef struct __mavlink_message {
    	uint16_t checksum;      ///< sent at end of packet
    ...
        uint8_t transfer_type; ///< for XBEE
        uint8_t transfer_ID; ///<  for XBEE
        uint8_t brdcst_r; ///<  for XBEE
        uint8_t opt_xbee; ///<  for XBEE
    ...
        uint64_t addr64;
        uint16_t addr16;
    ...
    }) mavlink_message_t;
    
    //新增宏定义
    //XBEE protocol
    #define MAVLINK_STX_XBEE 0x7E          // 1. marker for XBEE protocol
    //2.LENGTH 2 BYTES
    #define MAVLINK_SENDTYPE_XBEE 0x10          // 3. Send type
    #define MAVLINK_RECEIVETYPE_XBEE 0x90          // 3. receive type
    #define MAVLINK_SENDID_XBEE 0x01          // 4. Send ID
    // 5. Destination/Source Adress  8bytes
        /* 主机与从机地址 */
    
        #define Addr_Coordinate 0x0013A20041080112
    
        #define Addr_QuadRotor1 0x0013A2004108010B
    
        #define Addr_QuadRotor2 0x0013A20041080102
    
        #define Addr_ALL 0x000000000000FFFF
    //6. 16bit address
    #define Addr_16BIT 0xFFFE
    //7.Broadcast radius 1BYTE
    #define BRDCST_R 0x00
    //8.Option byte
    #define OPT_SEND_BYTE 0x00
    #define OPT_RECEIVE_BYTE 0xC2
    

    修改完的文件可参见已上传资源文件 mavlink_types.h.

    (3) checksum.h

    由于XBee校验方式不同,因此在该文件中仿照mavlink校验函数增加了适合XBee协议的校验函数,主要有:

    • 仿照函数crc_accumulate(uint8_t data, uint16_t *crcAccum)构造了适用于XBee数据校验的累和函数:
    static inline void crc_accumulate2(uint8_t data, uint16_t *crcAccum)
    {
            /*Accumulate one byte of data into the CRC*/
            *crcAccum = *crcAccum+data;
    }
    
    • 适用于XBee的初始化函数
    static inline void crc_init2(uint16_t* crcAccum)
    {
            *crcAccum = 0x0000;
    }
    
    • 适用于XBee的计算函数
    static inline uint16_t crc_calculate2(const uint8_t* pBuffer, uint16_t length)
    {
            uint16_t crcTmp=0x00;
            crc_init2(&crcTmp);
            while (length--) {
                    crc_accumulate2(*pBuffer++, &crcTmp);
            }
            return crcTmp;
    }
    

    修改完的文件可参考已上传资源文件 checksum.h.

    3-2 PX4飞控部分的修改

    和QGC部分类似,只要将上面修改的 mavlink_helpers.h、 mavlink_types.h、 checksum.h这三个文件复制到文件夹./Firmware/mavlink/include/mavlink/v2.0/中即可。

    此外,还需要注意的是,我们应当配置一个串口给XBee模块使用,主要是飞控板的 TELEM 1 端口(注册路径为:/dev/ttyS1)和 TELEM2 端口(注册路径为:/dev/ttyS2),我们可以选用TELEM2 端口,在rcS文件中默认开启为:

    mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 57600 -m xbee -r 1000
    

    然后在mavlink_main.cpp文件中添加端口参数设置程序:

    		case 'm':
    			if (strcmp(myoptarg, "custom") == 0) {
    				_mode = MAVLINK_MODE_CUSTOM;
    ...
    			}else if (strcmp(myoptarg, "xbee") == 0) {
    				_mode = MAVLINK_MODE_XBEE;
    				_rstatus.type = telemetry_status_s::TELEMETRY_STATUS_RADIO_TYPE_XBEE;
    				int32_t proto =MAVLINK_STATUS_FLAG_IN_XBEE;
    				if (_protocol_version_switch != proto) {
    					_protocol_version_switch = proto;//默认是0
    					set_proto_version(proto);//转化为zigebee协议
    				}
    			}
    			break;
    

    以及设置需要的发送消息:

    switch (_mode) {
    	case MAVLINK_MODE_XBEE:
    		configure_stream("HEARTBEAT", 0.75f);
    			/* STATUSTEXT stream is like normal stream but gets messages from logbuffer instead of uORB */
    		configure_stream("STATUSTEXT", 3.0f);
    
    		/* COMMAND_LONG stream: use unlimited rate to send all commands  */
    		configure_stream("COMMAND_LONG");
    
    		configure_stream("ALTITUDE", 1.0f);
    		configure_stream("ATTITUDE", 5.0f);
    		configure_stream("ATTITUDE_TARGET", 2.0f);
    		configure_stream("DEBUG", 1.0f);
    		configure_stream("DEBUG_VECT", 1.0f);
    		configure_stream("DISTANCE_SENSOR", 0.5f);
    		configure_stream("ESTIMATOR_STATUS", 0.5f);
    		configure_stream("EXTENDED_SYS_STATE", 1.0f);
    		configure_stream("GLOBAL_POSITION_INT", 5.0f);
    		configure_stream("GPS_RAW_INT", 1.0f);
    		//configure_stream("HIGHRES_IMU", 1.5f);
    		configure_stream("HOME_POSITION", 0.5f);
    		configure_stream("LOCAL_POSITION_NED", 1.0f);		
    		configure_stream("NAMED_VALUE_FLOAT", 1.0f);
    		configure_stream("RC_CHANNELS", 0.5f);
    		configure_stream("SYS_STATUS", 0.1f);
    		configure_stream("VFR_HUD", 1.0f);
    	break;
    

    3-3 通信测试及功能完善

    通信测试主要通过以下两步完成:

    • 给飞控和电脑端连接好各自的XBee模块,打开地面站并给飞控上电,观察地面站有无收到飞控发送的消息数据;
    • 给地面站配置一个指令发送按钮,并在飞控源码中编写针对该指令的应答程序,然后测试地面站在点击按钮时,有没有收到飞控反馈的应答信号。

    其中,第一步主要测试地面站的接收解码和飞控的发送编码功能是否正常;第二步主要测试地面站的发送编码和飞控端的接收解码。

    第一步基本无需新增代码,地面站收到飞控端发送的心跳包configure_stream("HEARTBEAT", 0.75f);即可显示连接;下面重点考虑第二步的实现流程,依次为:

    1. 在 Analyze 页面 左栏的console选项下新增一个MyTest项;
    2. MyTest项右栏空页中添加一个按钮,名称记为My Flight Command
    3. My Flight Command右边增加一个选项下拉列表(即combobox类型的控件),用于选择不同的指令;
    4. 在该combobox控件右侧再添加一个label标签,用于显示接收到的应答信号。

    正如下图所示:
    在这里插入图片描述

    图1 MyTestPage

    如图1所示,需要实现的功能为:通过选项下拉列表控件(图1中的3)选择指定的命令,点击按钮My Flight Command,地面站即发送该指令给飞控,飞控收到指令后反馈回一个应答信号到地面站,通过标签(图中的4)显示该应答信号。

    具体实现方法为:

    1. 仿照Analyze页面下的Mavlink Console子页面对应的qml文件来构造一个MyTestPage页面,并在该新页面中从左至右加入QGC的按钮、选项下拉列表、标签
    2. 定义对应于按钮的触发函数;
    3. 定义对应于下拉列表选项的变量;
    4. 定义对应于标签内容的变量;
    5. 编写C++文件代码,建立页面中的控件与相关命令发送及接收之间的关系。

    (1)创建MyTestPage页面

    Mavlink Console子页面对应的qml文件为MavlinkConsolePage.qml,仿照其写法,创建的MavlinkConsolePage.qml文件为:

    /****************************************************************************
     *  myTestPage
     ****************************************************************************/
    
    import QtQuick          2.3
    import QtQuick.Controls 1.2
    import QtQuick.Dialogs  1.2
    ...
    import QGroundControl.Vehicle       1.0
    
    AnalyzePage {
        id:        myTestPage
        pageComponent:      pageComponent
        pageName:           qsTr("MyTestPage")
        pageDescription:    qsTr("MyTestPage  is used to test some function write by myself.")
    
        property real _margin: ScreenTools.defaultFontPixelWidth * 2
    
        Component {
            id:                 pageComponent
    
            Column {
                id:         mainColumn
                width:      availableWidth
                spacing:    _margin
    
                Row {
                    spacing: _margin
    
                    QGCButton {
                        text:       qsTr("My Flight Command")
                        width:      ScreenTools.defaultFontPixelWidth * 30
                        anchors.verticalCenter:   parent.verticalCenter
                    }
    
                    QGCComboBox {
                        id:             modeChannelCombo
                        width:          ScreenTools.defaultFontPixelWidth * 20
                        model:          [ qsTr("Not assigned"), qsTr("Takeoff"), qsTr("Land"),qsTr("Fly a circle"), qsTr("Fly a rectangle"), qsTr("swarm")]
                    }    
    
                    QGCLabel {
                        text: "Waiting for an ACK from PX4!"
                        anchors.verticalCenter:   parent.verticalCenter
                    }
                }
            } // Column
        } // Component
    } // AnalyzePage
    

    创建好后,需要添加到qgroundcontrol.qrc文件和 AnalyzeView.qml文件中,依次如下:

    # qgroundcontrol.qrc
    ...
            <file alias="GeoTagPage.qml">src/AnalyzeView/GeoTagPage.qml</file>
            <file alias="MyTestPage.qml">src/AnalyzeView/ MyTestPage.qml</file>
            <file alias="HealthPageWidget.qml">src/FlightMap/Widgets/HealthPageWidget.qml</file>
     ...
     #  AnalyzeView.qml
     ...
                         ListElement {
                            buttonImage:        "/qmlimages/MavlinkConsoleIcon"
                            buttonText:         qsTr("Mavlink Console")
                            pageSource:         "MavlinkConsolePage.qml"
                        }
                        ListElement {
                            buttonImage:        "/qmlimages/MavlinkConsoleIcon"
                            buttonText:         qsTr("MyTestPage")
                            pageSource:         "MyTestPage.qml"
                        }
    ...
    

    (2)定义对应于按钮控件的触发函数

    c++中的函数都是某个类的方法,若要定义一个能被qml调用的类的方法,还需要该类声明为qml可以访问的类型,具体有两种方式:

    1. qmlRegisterUncreatableType进行声明,如:
       qmlRegisterUncreatableType<MultiVehicleManager>("QGroundControl.MultiVehicleManager", 1, 0, "MultiVehicleManager", "Reference only");
    

    然后在头文件中声明类的属性:

    Q_PROPERTY(MultiVehicleManager* multiVehicleManager READ multiVehicleManager CONSTANT)
    

    最后qml文件可以通过QGroundControl.multiVehicleManager 来访问其中的属性和方法。

    1. qmlRegisterType对类进行声明,在qml中通过id来访问属性和方法:
    // --QGCApplication.cc
    qmlRegisterType<PlanMasterController>("QGroundControl.Controllers", 1, 0, "PlanMasterController");
    ///PlanView.qml
        PlanMasterController {
            id:                     masterController
            Component.onCompleted:  start(true /* flyView */)
        }
    

    解决类的问题后,对于类中需要被qml使用的方法,则在函数前加上Q_INVOKABLE即可,如:

    Q_INVOKABLE void emergencyStop(void);
    

    可以看出按钮My Flight Command的触发函数在c++文件中被定义,然后在qml文件中被按钮控件调用,函数可在头文件中通过Q_INVOKABLE关键字来声明:

    Q_INVOKABLE void MyFlightCMD(void);
    

    那么究竟选用那个类的头文件呢?由于我们是要发送指令给飞控,所以头文件对应的c++文件必须能发送mavlink消息给飞控。这里先简单对QGC地面站的工作流程进行简要分析,QGC地面站的启动包含两条流程线,如下图所示:

    在这里插入图片描述

    图2 QGC地面站启动流程图

    左边是显示的页面,也就是软件的前端,右边是由c++运行计算的数据流,也就是软件后台。地面站启动后,后台会通过LinkManager.cc文件相关函数找到计算机当前存在的端口,然后MultiVehicleManager.cc的相关函数会不断发心跳包给这个端口,MAVLinkProtocol.cc负责检查是否收到PX4的发送回的心跳包,若收到,则告诉MultiVehicleManager.cc,然后MultiVehicleManager.cc为该收到心跳包的端口建立一个Vehicle的类对象,标记为activeVehicle

    因此,最终与PX4建立通信连接的是该Vehicle类对象,所以前面的按钮触发函数应在Vehicle.h里进行声明,然后在Vehicle.cc里进行定义。
    qml中的调用如下:

     QGCButton {
                        text:       qsTr("My Flight Command")
                        width:      ScreenTools.defaultFontPixelWidth * 30
    
                        onClicked:  QGroundControl.multiVehicleManager.activeVehicle.MyFlightCMD()//触发函数
    
                        anchors.verticalCenter:   parent.verticalCenter
                    }
    

    (3)定义对应于下拉列表选项的变量

    下拉列表的选项一般都是整数型的,为了定义一个可同时被qml文件和cpp类修改的整数变量,可按以下步骤实现:

    • 在vehicle.h里声明该整数型变量(public):
    Q_PROPERTY(int  Flight_Command   READ Flight_Command  WRITE setFlight_Command  NOTIFY Flight_CommandChanged)
    

    此外,对于仅在cpp文件中需要修改的变量,可以按以下方式声明:

     Q_PROPERTY(int      firmwareMajorVersion        READ firmwareMajorVersion       NOTIFY firmwareVersionChanged)
    

    若变量为仅初始赋值一次,后续不再允许改动的常量,则声明格式为:

    Q_PROPERTY(int id READ id CONSTANT)
    
    • 定义一个对应的全局变量(private):
      int  _Flight_Command;
    
    • 定义一个取值函数(public):
    int Flight_Command(void){ return _Flight_Command; }
    
    • 声明及定义写值函数(public):
    void setFlight_Command(int Flight_Command)...
    
    void Vehicle::setFlight_Command(int Flight_Command)
    {
       ...
       _Flight_Command=Flight_Command;
       qDebug("Flight_Command=%d",Flight_Command);
    }
    
    • 声明信号传递函数(传递到qml文件中,无需定义内容,signals:)
    void Flight_CommandChanged(int Flight_Command);
    

    使用时,在C++中采用如下方式修改变量值:

    ...
            _Flight_Command = 1;
            emit Flight_CommandChanged(_Flight_Command);
    ...        
    

    qml文件中,则通过调用类对象方法修改:

    ...
           property var    _activeVehicle:         QGroundControl.multiVehicleManager.activeVehicle
    ...        
            QGCComboBox {
                id:             modeFlightCmdCombo
                width:          ScreenTools.defaultFontPixelWidth * 20
                model:          [ qsTr("Not assigned"), qsTr("Takeoff"), qsTr("Land"),qsTr("Fly a circle"), qsTr("Fly a rectangle"), qsTr("swarm")]
                
                currentIndex:  _activeVehicle.Flight_Command
                onActivated: {
                               _activeVehicle.Flight_Command=index//相当于调用了函数setFlight_Command(index)
                             }                    
            }    
    ...     
    

    (4)定义对应于标签内容的变量

    标签中的内容只需要显示,不需要从界面中去更改它,因此我们可以声明一个字符串变量,属性如下:

    Q_PROPERTY(int  ackString   READ ackString  NOTIFY ackStringChanged)
    

    然后声明和定义函数:

    QString         ackString        ();
    ...
    QString Vehicle::ackString()
    {
        QString messages;
        switch(_CommandACK)
        {
            case 0:
               messages="Waiting for an ACK from PX4!";
            break;
            case 1:
               messages="ACK:Success!";
            break;
            case 2:
               messages="ACK:Failed!";
            break;
            default:
               messages="ACK:Waiting!";
            break;
        }
        return messages;
    }
    

    声明信号传递函数:

     void ackStringChanged    ();
    

    qml文件中调用:

    QGCLabel {
        text:  qsTr(_activeVehicle.ackString)
        anchors.verticalCenter:   parent.verticalCenter
    }
    

    (5)建立页面中的控件与指令发送/消息接收之间的关系

    我们首先需要通过mavlink-generator 的 mavlink 消息生成器:mavgenerate.py生成一个新的mavlink消息:mavlink_msg_set_my_command用于我们发送/接收我们的指令:

    #define MAVLINK_MSG_ID_SET_MY_COMMAND 197
    
    MAVPACKED(
    typedef struct __mavlink_set_my_command_t {
     int16_t data1; /*<  not specific defined*/
     int16_t data2; /*<  not specific defined*/
     int16_t data3; /*<  not specific defined*/
     int16_t data4; /*<  not specific defined*/
     int16_t data5; /*<  not specific defined*/
     int16_t data6; /*<  not specific defined*/
     int16_t data7; /*<  not specific defined*/
     int16_t data8; /*<  not specific defined*/
    }) mavlink_set_my_command_t;
    

    在QGC地面站的common.h文件(libs/mavlink/include/mavlink/v2.0/common/common.h)中添加该消息头文件:

    ...
    #include "./mavlink_msg_obstacle_distance.h"
    #include "./mavlink_msg_set_my_command.h"
    ...
    

    同时在该文件下的 MAVLINK_MESSAGE_INFO 和 MAVLINK_MESSAGE_NAMES 宏定义中添加:

    #define MAVLINK_MESSAGE_INFO{... ,MAVLINK_MESSAGE_INFO_SET_MY_COMMAND,...}
    #define MAVLINK_MESSAGE_NAMES {{ "ACTUATOR_CONTROL_TARGET", 140 }, ...,{ "SET_MY_COMMAND", 197 }, ...}
    

    在 ardupilotmega.h 需要添加消息的校验数组 {197, 9, 16, 0, 0, 0},:

    #define MAVLINK_MESSAGE_CRCS {...{195, 120, 37, 0, 0, 0}, {197, 9, 16, 0, 0, 0}, {200, 134, 42, 3, 40, 41}...
    

    数组的第一个数197就是消息ID,注意这个ID的大小也决定了数组在 MAVLINK_MESSAGE_CRCS中所放的位置,因为没有196号消息,所以放在195号消息之后。数组其它元素,可从mavgenerate.py生成的其它文件(set_my_command.h)中找到,原本为:

    #define MAVLINK_MESSAGE_CRCS {{197, 9, 16, 16,0, 0, 0}}
    

    我们去掉中间多余的一个16即可,然后在按钮触发函数中添加打包发送函数:

    void Vehicle::MyFlightCMD()
    {
        qDebug("_Flight_Command=%d",_Flight_Command);
        mavlink_message_t msg={};
        mavlink_msg_set_my_command_pack_chan(_mavlink->getSystemId(),
                                      _mavlink->getComponentId(),
                                       priorityLink()->mavlinkChannel(),
                                       &msg,
                                       _Flight_Command,
                                       0,0,0,0,0,0,0);
    
        sendMessageOnLink(priorityLink(), msg);
    }
    

    同时在PX4飞控源码中也要按以上步骤添加新的mavlink消息:mavlink_msg_set_my_command,然后在消息处理函数中添加对该消息的处理:

    void MavlinkReceiver::handle_message(mavlink_message_t *msg)
    {
           ...
           switch(msg->msgid)
           {
                ...
                case MAVLINK_MSG_ID_SET_MY_COMMAND:
                handle_message_set_my_command(msg);
                break;
                ...
           }
    }
    ...
    void MavlinkReceiver::handle_message_set_my_command(mavlink_message_t *msg)
    {
        mavlink_set_my_command_t cmd_mavlink
        mavlink_set_my_command_decode(msg, &cmd_mavlink);
        acknowledge(msg->sysid,msg->compid,cmd_mavlink.data1,cmd_mavlink.data1);
    }
    
    

    也就是说,我们利用PX4飞控中acknowledge应答函数反馈接收到的消息给QGC地面站,所以需要在地面站处理应答消息的函数里添加对反馈的处理:

    void Vehicle::_handleCommandAck(mavlink_message_t& message)
    {
        bool showError = false;
    
        mavlink_command_ack_t ack;
        mavlink_msg_command_ack_decode(&message, &ack);
    
        _CommandACK=ack.result;
        emit ackStringChanged();
        ...
    }
    

    最后分别连接XBee模块到飞控和QGC地面站,开机测试,得到我们想要的结果。

    在这里插入图片描述

    图3 XBee通信测试
    展开全文
  • XBee无线模块的通信方式和结合Arduino的具体实施过程 原理简介: XBee模块是Digi公司的一款采用ZigBee技术的无线模块,通过串口与单片机等设备间进行通信,能够非常快速地实现将设备接入到ZigBee网络的目的。 XBee...
  • XBee3系列模块完整生态链介绍 一、XBee3模块封装形式 1. XBee3微封装模块 2. 直插模块及兼容适配板 3. 贴片模块及兼容适配板 二、XBee3模块评估板 1. USB评估板 2. 多功能评估板 三、XBee3模块评估软件 1. X-CTU综合...
  • XBee/XBee-Pro@ SX模块快速入门

    千次阅读 2018-07-21 13:07:15
    本文将指导您使用XBee SX开发套件和XCTU软件进行通信测试。您需要首先安装XCTU 6.3以上的版本。如果您还没有安装,请先下载:http://www.digi.com/xctu-windows XBee开发底板的驱动,如果您还没有安装,可以...
  • 一般3-5个XBEE S2C模块 点对多点的通信,使用XCTU软件进行如下设置: 1、所有模块都设置相同的 ID、ZS、SC,可以都未默认值 2、核心模块为协调器 AT (CE=1),其余模块为默认不修改; 3、核心模块的DH设置为0000, DL...

空空如也

空空如也

1 2 3 4 5 6
收藏数 103
精华内容 41
关键字:

xbee组网