关于 UWB 的使用
Author: CGC
使用 Nooploop 的 LinkTrack 定位系统为 Acfly飞控提供定位
我们使用的是4基站+1标签+1控制台的方案
参考的是官方用户手册中第13-14页的内容
- 按顺序0-3的id分别配置4个anchor
- 配置tag标签(飞控端) 通信协议选择tag_frame0
- 配置console控制台
摆放及上电方向
Section titled “摆放及上电方向”由于飞控的数据适配性,基站摆放位置和飞机上电位置需要受到限制
(可能之后随着设备的更新会减轻这方面带来的影响,但是按我们目前的测试结果来看,还是非常建议按照已经测试好的方向进行初始化)
如下

飞控通信协议设置
Section titled “飞控通信协议设置”tag端通信协议
Section titled “tag端通信协议”具体通信协议可以参考官方参考通信协议
在此处对飞控段使用的协议即 Tag 端作说明 即
tag端通信协议(接收)如下
可知飞控可接收到数据有位置、姿态、精度等一系列数据
官方驱动代码
Section titled “官方驱动代码”以下给出acfly官方发布的驱动代码
#include "drv_UWB_LinkTrack.hpp"#include "Commulink.hpp"#include "Basic.hpp"#include "FreeRTOS.h"#include "task.h"#include "SensorsBackend.hpp"#include "MeasurementSystem.hpp"
struct DriverInfo{ uint32_t param; Port port; uint32_t sensor_key;};
typedef struct{ uint8_t id; uint8_t role; int pos_x:24; int pos_y:24; int pos_z:24; int vel_x:24; int vel_y:24; int vel_z:24; int dis_0:24; int dis_1:24; int dis_2:24; int dis_3:24; int dis_4:24; int dis_5:24; int dis_6:24; int dis_7:24; float imuGyro[3]; float imuAcc[3]; uint8_t reserved1[12]; int16_t angle[3]; float q[4]; uint8_t reserved2[4]; uint32_t localTime; uint32_t systemTime; uint8_t reserved3[1]; uint8_t eop[3]; // 估计位置的精度 uint16_t voltage; uint8_t reserved4[5];}__PACKED _Uwb;static const unsigned char packet_ID[2] = { 0x55 , 0x01 };
static void OpticalFlow_Server(void* pvParameters){ DriverInfo driver_info = *(DriverInfo*)pvParameters; delete (DriverInfo*)pvParameters;
/*状态机*/ _Uwb Uwb; unsigned char rc_counter = 0; signed char sum = 0; /*状态机*/
//等待初始化完成 while( get_Altitude_MSStatus() != MS_Ready ) os_delay(1);
//注册传感器 double angleOffset = 0; if( driver_info.param>360 ) { //记录初始偏航 Quaternion quat; get_Attitude_quat(&quat); angleOffset = quat.getYaw(); } else angleOffset = degree2rad((double)driver_info.param);
uint32_t sensor_key = PositionSlamSensorRegister( default_uwb_sensor_index , \ "UWB_LinkTrack" ,\ Position_Sensor_Type_RelativePositioning , \ Position_Sensor_DataType_s_xy , \ Position_Sensor_frame_SLAM , \ 0.1, angleOffset, 100 );
int lastP = 0; uint8_t pUCCounter = 0; while(1) { uint8_t rdata; if( driver_info.port.read( &rdata, 1, 2, 0.5 ) ) { if( rc_counter < sizeof(packet_ID) ) { //接收包头 if( rdata != packet_ID[ rc_counter ] ) { rc_counter = 0; sum = 0; } else { ++rc_counter; sum += rdata; } } else if( rc_counter < sizeof(packet_ID) + sizeof(_Uwb) ) { //接收数据 ( (unsigned char*)&Uwb )[ rc_counter - sizeof(packet_ID) ] = rdata; sum += rdata; ++rc_counter; } else { //校验 if( sum == rdata ) { if( Uwb.eop[0]>200 || Uwb.eop[1]>200 ) // x y 精度大于2cm就失能 PositionSensorSetInavailable(default_uwb_sensor_index,driver_info.sensor_key); else { vector3<double> pos, vel; pos.x = Uwb.pos_x*0.1; pos.y = Uwb.pos_y*0.1; pos.z = Uwb.pos_z * 0.1; vel.x = Uwb.vel_x*0.01; vel.y = Uwb.vel_y*0.01; vel.z = Uwb.vel_z * 0.01; if( Uwb.eop[2] > 200 ) PositionSensorChangeDataType( default_uwb_sensor_index,sensor_key, Position_Sensor_DataType_s_xy ); else PositionSensorChangeDataType( default_uwb_sensor_index,sensor_key, Position_Sensor_DataType_s_xyz ); double eop_xy = sqrtf( Uwb.eop[0]*Uwb.eop[0] + Uwb.eop[1]*Uwb.eop[1] );
if( Uwb.dis_0 != lastP ) { lastP = Uwb.dis_0; pUCCounter = 0; } else { if( pUCCounter < 255 ) ++pUCCounter; }
if( pUCCounter>100 ) PositionSensorSetInavailable( default_uwb_sensor_index,sensor_key ); else PositionSensorUpdatePosition( default_uwb_sensor_index,sensor_key, pos, true, -1, eop_xy<100?100:eop_xy, Uwb.eop[2] ); } } rc_counter = 0; sum = 0; } } }}
static bool UWB_LinkTrack_DriverInit( Port port, uint32_t param ){ //波特率115200 port.SetBaudRate( 460800, 2, 2 ); //注册传感器 DriverInfo* driver_info = new DriverInfo; driver_info->param = param; driver_info->port = port;
xTaskCreate( OpticalFlow_Server, "OptFlowGL9306", 1024, (void*)driver_info, SysPriority_ExtSensor, NULL); return true;}
void init_drv_UWB_LinkTrack(){ PortFunc_Register( 41, UWB_LinkTrack_DriverInit );}在以上驱动代码中,值得一提的是
// z 精度大于2cm就不使用z轴数据if( Uwb.eop[2] > 200 ) PositionSensorChangeDataType( default_uwb_sensor_index,sensor_key, Position_Sensor_DataType_s_xy );else PositionSensorChangeDataType( default_uwb_sensor_index,sensor_key, Position_Sensor_DataType_s_xyz );及
if( Uwb.eop[0]>200 || Uwb.eop[1]>200 ) // x y 精度大于2cm就失能 PositionSensorSetInavailable(default_uwb_sensor_index,driver_info.sensor_key);else{ // ...}驱动内容为 超出2cm的精度许可范围,就将传感器失能
UWB官方给出的数据是,x y 的精度在 10cm 之内 z 精度在 30cm 以内
- 关于z轴数据
这样一来其实可以反应我们看到的现象,首先是在只使用uwb作为外接传感器时,飞机完全定不住高(因为z精度完全无法满足2cm的要求),但是可能由于飞控中气压计等设备的存在,飞控有高度数据,室内定位可用,所以能够允许起飞,但在天上的高度数据,完全由飞控而来,所以现象是,没有定高可言。。。
注意事项及传感器使用建议
Section titled “注意事项及传感器使用建议”- 使用时发起自动标定的设备需要在线,比如我们使用控制台发起一键标定,则在使用时控制台必须要在线,否则数据会不可用
- 由于uwb的z轴精度较低,建议加上tfmini等作为定高传感器,通过测试,有uwb加上tfmini,定位效果较好
- 通过这段时间的测试,我们发现至少在电赛赛制的背景下,用uwb可能会出现某些限制,比如场地不一定能够容纳摆放下基站,并且无法在换场地后进行标定,可能受到干扰等
- 对于电赛(赛场不允许携带笔记本及pc,上位机只支持x86,我们手上已有的板载电脑皆为arm,无法在现场进行标定)无法在换场地后进行标定的情况,可能考虑自行写接口,使用单片机或板载电脑进行标定,能够很大程度减少对位置场地的限制,我们尝试按照通信协议写了一份一键自动标定的程序,但还未在实际场地中进行测试。