基于UWB的室内定位MiniFly无人机编队

先展示一下效果: 在这里插入图片描述

三机定位

编队飞行

UWB定位技术

超宽带无线通信技术(UWB) 是一种无载波通信技术,UWB不使用载波,而是使用短的能量脉冲序列,并通过正交频分调制或直接排序将脉冲扩展到一个频率范围内。IR-UWB信号,仅需要产生一个时间短至nS级以下的脉冲,便可通过天线进行发送。需要传送信息可以通过改变脉冲的幅度,时间,相位进行加载,进而实现信息传输。(参考于:https://zhuanlan.zhihu.com/p/138505840)
在这里插入图片描述

测距原理

单向双向测距(SS-TWR)

涉及单个消息从一个节点到另一个节点的往返延迟的简单测量,以及将响应发送回原始节点。
在这里插入图片描述
但这种测距方式的误差会随着时钟偏移增加,飞行时间估计中的误差增加到误
差使得估计非常不准确的程度。

双向双向测距(DS-TWR)

是基本的单向双向测距的延伸,其中使用了两个往返时间测量,并将其组合在一起,从而得到飞行时间结果 。
在这里插入图片描述
在三个和四个消息情况下的所得飞行时间估计 Tprop 可以使用以下表达式来计算:
在这里插入图片描述
使用 DS 测距方式时钟引入的误差为:在这里插入图片描述
假设设备 A 和设备 B 的时钟精度是 20ppm(很差),1ppm 为百万分之一,那么 Ka 和 Kb分别是 0.99998 或者 1.00002,ka 和 kb 分别是设备 A、B 时钟的实际频率和预期频率的比值。设备 A、B 相距 100m,电磁波的飞行时间是 333ns。则因为时钟引入的误差为 2033310-9 秒,导致测距误差为 2.2mm,可以忽略不计了。因此双边测距是最常采用的测距方式

三基站一标签通讯图解

在这里插入图片描述
在这里插入图片描述
以主动扫描标签方式构建,所有行为集中在主基站(A 基站)上发送命令并处理,并且由非常大的可操控性,所有的执行行为只需要操控配置主基站即可。

定位算法

假设基站 A 的坐标为(x1,y1,z1),基站 B 的坐标为(x2,y2,z2),基站 C 的坐标为(x3,y3,z3), 基站 D 的坐标为(x4,y4,z4),需要求解的标签坐标为(x,y,z),则有:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
把这些式子转换为矩阵相乘的形式
在这里插入图片描述

模块选择

我使用的是广州联网科技有限公司的定位系统,基于该系统,自行设计适合MiniFly的定位标签。该系统的标签是基于 DW1000 定位模块的。在这里插入图片描述
并改造一下MiniFly,将716改为720,桨叶改大一点,并倒置电机,提高升力,并同时将电池换为850mah,通过这些改进,MiniFly在搭载了UWB模块之后还能有接近10分钟的续航时间。在这里插入图片描述

无人机接收控制指令

要实现室内定位无人机编队,除了获取到无人机的准确位置外,还需要对无人机进行控制,最简单的控制方式就是无人机只是搭载UWB定位标签,实现定位功能,然后再电脑上位机通过串口控制遥控器进而实现无人机的定点飞行,另一种方式就是直接使用搭载在MiniFly上的UWB标签模块与无人机直接通信,从而控制无人机。在这里插入图片描述
第一种方式的优点是简单快捷,而且之前也有串口上位机控制遥控从而控制无人机的基础,缺点是流程过于繁杂,会造成定位数据的延迟,在多台无人机的情况下,定位效果不佳。
第二种方式的优点是流程直接,控制数据能快速的发送到无人机上,而且无人机在获取了自己的位置之后可以采用自主飞行的方式,可以实现多台无人机的定位编队控制。缺点是代码比较复杂,定点飞行算法也需要优化。
在这里插入图片描述
为了实现多台无人机编队,因此我选择了第二种方式。使UWB标签模块模仿MiniFly的WiFi模块发送数据,发送的数据有多种格式,如下:在这里插入图片描述
1.当收到基站发来的数据透传指令时,直接转发给MiniFly
2.在空闲时段,UWB将持续发送当前位置信息给MiniFly
3.在收到灯光控制信息时,由UWB控制WS2812的LED模块在这里插入图片描述在这里插入图片描述
到了MiniFly这边就接收到搭载在机身上的UWB标签模块的信息。在这里插入图片描述
在这里插入图片描述
并在成功接收到数据后调用UWBDataHandle函数处理,这部分函数就涉及接下来的无人机定点飞行。

无人机定点飞行控制

该部分代码涉及了无人机的定点飞行,以及上位机控制无人机飞行,由于只是一个demo,只是简单的引入了误差量,还没实现PID控制。
下面展示一些 内联代码片

static void UWBDataHandle(u8 *data)
{
    static u8 Fly_Speed = 20;       //飞行速度(148-128)*0.25
    static u8 Error = 5;            //UWB目标点与实时坐标之间的误差
    static u8 Deviation = 10;       //重新执行定点飞行的偏移量
    
    static bool re_arrival_fly = false;//重新执行目标点飞行标志
    static u8 count = 1;            //计算偏离目标点的次数(消除抖动)
    static u8 countfly = 1;         //用于指令控制无人机飞行的延迟
    
    //2022/06/27
    static bool Low_Speed_Flag = false;//用于降低飞行的速度标志
    u16 DiffX = 0,DiffY = 0;        //用于记录当前位置与目标点的距离
    static u8 Radius = 40;          //圆域半径
    static u8 Low_Speed = 10 , High_Speed = 20;
    
    //------------------------------------------------------------
    //2022/6/3接收到20条指令,或者在执行目标点飞行,就把飞行控制数据重置
    if(++countfly > 20 || !Arrival_Flag){
        UWBCtrl.pitch   = 0;
        UWBCtrl.roll    = 0;
        UWBCtrl.yaw     = 0;//航向控制数据
        UWBCtrl.thrust  = 32768;//油门控制数据,居中
        countfly = 1;
    }
  
    if(data[1] == 0x01) { //目标点数据
        if(data[2]*256+data[3] != DestX || data[4]*256+data[5] != DestY) {
            //如果获取到的目标点数据与当前设置的目标点数据不一致
            DestX = data[2]*256+data[3];//赋值
            DestY = data[4]*256+data[5];
            FirstOrder = true;
            Arrival_Flag = false;//修改标志位,继续飞行
            ArrivalX = false;
            ArrivalY = false;
            re_arrival_fly = false;
            Low_Speed_Flag = false;//重新发送目标点恢复速度
        }
    }

    else if(data[1] == 0x02) { //实时坐标数据
        //默认机头方向与Y轴平行
        LocatX = data[2]*256+data[3];
        LocatY = data[4]*256+data[5];
        
        //2022/06/27计算目标点与实时坐标的距离
        DiffX = Diff(LocatX,DestX);
        DiffY = Diff(LocatY,DestY);
        
        //2022/06/27到达以目标点为圆心,50为半径的圆域内,降速为10 DiffX <= Radius && DiffY <= Radius
        if((DiffX * DiffX + DiffY * DiffY) <= Radius * Radius){
            Low_Speed_Flag = true;
        }
        else{
            Low_Speed_Flag = false;
        }
        
        //2022/06/27添加
        if(Low_Speed_Flag && Fly_Speed == High_Speed){//到达圆域内且飞行速度是20,防止多次调用赋值
            Fly_Speed = Low_Speed;
        }
        else if(Fly_Speed == Low_Speed && !Low_Speed_Flag){
            Fly_Speed = High_Speed;
        }
        
        Type = Fly_Speed;//将数据类型回传
    
        //FlagData = Low_Speed_Flag;
        
        if(!Arrival_Flag && FirstOrder) { //如果还没到达目标点
            //横滚飞行控制数据
            if(!ArrivalX) {
                //目标点 + 误差 > 当前坐标 && 目标点 - 误差 < 当前坐标
                //if((DestX + Error) > LocatX && (DestX - Error) < LocatX) {
                if(DiffX < Error){
                    ArrivalX = true;//X到达指定位置
                    UWBCtrl.roll = 0;
                }
                else if(DestX < LocatX ) {
                    UWBCtrl.roll = -((float)Fly_Speed) * 0.25f;//-Fly_Speed
                }
                else if(DestX > LocatX ) {
                    UWBCtrl.roll = ((float)Fly_Speed) * 0.25f;//Fly_Speed
                }
            }

            //俯仰飞行控制数据
            if(!ArrivalY) {
                //if((DestY + Error) > LocatY && (DestY - Error) < LocatY) {
                if(DiffY < Error){
                    ArrivalY = true;//Y到达指定位置
                    UWBCtrl.pitch = 0;
                }
                else if(DestY < LocatY ) {
                    UWBCtrl.pitch = -((float)Fly_Speed) * 0.25f;//-Fly_Speed;
                }
                else if(DestY > LocatY ) {
                    UWBCtrl.pitch = ((float)Fly_Speed) * 0.25f;//Fly_Speed
                }
            }

            //XY到到达指定位置
            if(ArrivalX && ArrivalY) {
                Arrival_Flag = true;//到达目标位置
                //复位准备下次定点飞行
            }
        }
        //---------------------------------------------2022/5/22
        //只要有一个方向出现了偏移
        else if(DiffX > Deviation || DiffY > Deviation){
            if(++count > 10)//连续10次获取到的当前位置偏离目标点才重新执行自主飞行代码
                re_arrival_fly = true;
        }
        else{
            count = 1;//不连续重新置位1
        }
        
        //继续执行自主飞行
        if(re_arrival_fly){
            count = 1;
            Arrival_Flag = false;
            ArrivalX = false;
            ArrivalY = false;
            re_arrival_fly = false;
        }
    }
    
    else if(data[1] == 0x03) { //控制数据
        if(DestX != 0 && DestY != 0){
            //使无人机在有目标点的情况下可以使用键盘控制而不回到目标点
            FirstOrder = false;
            DestX = 0;
            DestY = 0;
        }
        UWBCtrl.thrust = (u16)data[2] << 8;					    //thrust :0~63356
        UWBCtrl.pitch  = ((float)data[3]-(float)0x80)*0.25f;	//pitch:±9.5 ±19.2 ±31.7
        UWBCtrl.roll   = ((float)data[4]-(float)0x80)*0.25f;	//roll: ±9.5 ±19.2 ±31.7
        UWBCtrl.yaw    = ((float)data[5]-(float)0x80)*1.6f;	    //yaw : ±203.2
        countfly = 1;//重新开始计数
        //(在接收到下一个指令前一直保持控制数,当不再接收到控制数据,就在一定时间后恢复定点)
    }

    else if(data[1] == 0x04) { //RGB,标志位数据
        UWBCmdProcess(data[2]);//位标志命令解析
        FlagData = data[2];
        Color_R = data[3];
        Color_G = data[4];
        Color_B = data[5];
    }
    
    UWBCtrl.trimPitch = 0;
    UWBCtrl.trimRoll = 0;
    setCommanderCtrlMode(3);//定点模式
	setCommanderFlightmode(0);//有头模式
    flightCtrldataCache(WIFI, UWBCtrl);//飞机控制数据发送到执行函数
}

上位机开发

最后一部分就是上位机的开发了,该部分涉及了UWB定位开启,UWB参数配置,还有灯光控制,目标点发送等等功能。
第一部分就是基于广州联网科技有限公司的UWB参数配置功能,基本没什么改动。
在这里插入图片描述
第二部分就开发出了
控制架次的选择:可以选择控制所有无人机或者控制单台无人机;
目标点设置:用于控制无人机的定点飞行;
键盘控制无人机:可以通过键盘的方向键发送控制指令从而控制无人机的俯仰和横滚;
编队路径设置:通过录入多组目标点,可以设置出一条航线,让无人机按照航线飞行;
编队队形:还有四个基础的控制队形,用于无人机集群的编队展示(视频中就实现了三台无人机的三角队形和直线队形);
灯光控制:为了无人机编队表演的效果,我们在无人机上搭载了全彩LED,通过发送控制指令控制无人机的灯光颜色;
在这里插入图片描述
这部分是我同学开发的,为保护其知识产权,我就不擅自分享代码了。

至此,无人机的室内编队表演系统雏形就基本形成,当然还有许多值得优化的方面,比如UWB定位算法的优化,提高其定位速率、比如定点飞行算法的优化,添加PID控制算法,让无人机的定点飞行更加丝滑、以及无人机的防碰撞机制等等。。。

  • 8
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值