栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

基于Qt平台的UWB LinkTrack模块数据解析(附完整C++代码)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于Qt平台的UWB LinkTrack模块数据解析(附完整C++代码)

        最近要用Nooploop的linkTrack模块做定位,分享数据解析代码。

        linkTrack相关文档的下载地址:资料下载 – Nooploophttps://www.nooploop.com/download/

目录

UWB技术介绍

 用户手册的协议解析

 数据解析

 完整Qt项目

Qt工程文件


UWB技术介绍

        linkTrack用到的是UWB技术。UWB 是一种无载波通信技术,利用纳秒至微秒级的非正弦波窄脉冲传输数据。UWB 具备时间分辨率高、穿透力强、功耗低、抗多径效果好、安全性高等优点,因此常被应用于通信与定位领域,尤其是在GNSS(如GPS、BDS、Glonass、Galileo)信号覆盖不到的场合。

        UWB 定位原理与GPS 相似,其中:ANCHOR(基站)相当于天上的卫星,TAG(标签)相当于用户端的GNSS 接收机,CONSOLE(控制台)相当于地面的监控站。ANCHOR 一般作为参考位置点,一般安装于固定参考点;TAG 一般作为待定位点,一般安装于待定位载体(如无人机、无人车)上;ConSOLE 一般用于监控系统的运行状态并向其他节点(ANCHOR、TAG)下发指令,一般接到Terminal(终端),如计算机、平板电脑等。UWB 属于电磁波,其在真空中的传播速度与光速相同。通过测量TAG 到ANCHOR 的TOF(飞行时间),乘以光速后,TAG 可以获得到ANCHOR 的距离。通过到多个ANCHOR 距离与参考ANCHOR 的坐标,可以列出多组球面方程,进而由数学方法可以求解出标签的坐标。图7为常见的三边定位原理示意图。

 用户手册的协议解析

http://ftp.nooploop.com/software/products/uwb/doc/linkTrack_User_Manual_V2.2_zh.pdf

 数据解析

https://github.com/nooploop-dev/nlink_unpack

        官网给出了帧数据的解析代码,通过此代码可以很好地把串口传来的数据解析成我们想要的数据,从而大大减少开发时间。但是,在接收串口数据时,由于帧数据比较大,分两次才接收完,这对于数据处理很不友好。这个问题我花了一天时间才想出解决办法。在此之前,我们先看下串口通信为什么出现数据分包情况。

关于字节

一个字节多少位 - 一颗蘋果 - 博客园
 

下面是接收linkTrack模块的数据并解析的核心代码

void MainWindow::ReadData()
{
    
    QByteArray arr;
    static QByteArray buffer;

    arr = m_port->readAll();
    static bool flag = false;

    //判断是不是55开头的数据,如果是的话,就存起来,然后设置flag位true,下次就接收另外一组数据
    if(arr.toHex().startsWith("55"))
    {
        buffer.append(arr); //存储第一组数据
        flag = true;
        return;
    }

    if(flag)
    {

        buffer.append(arr); //存储第二组数据
        char *string1 = buffer.toHex().data();

        uint8_t data[1024];
        size_t data_length;
        data_length = Nlink_StringToHex(string1, data);  //将字符串转换为Hex格式,并将数据存储在data中

        if (g_nlt_nodeframe2.UnpackData(data, data_length))
        {
          nlt_nodeframe2_result_t *result = &g_nlt_nodeframe2.result;
          qDebug()<<"linkTrack Nodeframe0 data unpack successfully:n";

    //      和上位机对比,数据是正确的
          qDebug()<< "位置:" <pos_3d[0] <pos_3d[1] <pos_3d[2];
          qDebug()<< "速度:" <vel_3d[0] <vel_3d[1] <vel_3d[2];
          qDebug()<< "加速度:" <imu_acc_3d[0] <imu_acc_3d[1] <imu_acc_3d[2];

         }

        buffer.clear();//因为buffer是静态变量,用完一次后要记得清空,否则会使得内存溢出
        flag=false;
    }

}

        此代码解析的是g_nlt_nodeframe2协议类型,如果需要解析其他协议,只需要修改三处位置即可。

 完整Qt项目

首先配置pro文件,将用到的模块添加进去。

QT       += core gui serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

ConFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += 
    main.cpp 
    mainwindow.cpp 
    nlink_linktrack_anchorframe0.c 
    nlink_linktrack_aoa_nodeframe0.c 
    nlink_linktrack_nodeframe0.c 
    nlink_linktrack_nodeframe1.c 
    nlink_linktrack_nodeframe2.c 
    nlink_linktrack_nodeframe3.c 
    nlink_linktrack_nodeframe5.c 
    nlink_linktrack_nodeframe6.c 
    nlink_linktrack_tagframe0.c 
    nlink_tofsense_frame0.c 
    nlink_utils.c

HEADERS += 
    mainwindow.h 
    nlink_linktrack_anchorframe0.h 
    nlink_linktrack_aoa_nodeframe0.h 
    nlink_linktrack_nodeframe0.h 
    nlink_linktrack_nodeframe1.h 
    nlink_linktrack_nodeframe2.h 
    nlink_linktrack_nodeframe3.h 
    nlink_linktrack_nodeframe5.h 
    nlink_linktrack_nodeframe6.h 
    nlink_linktrack_tagframe0.h 
    nlink_tofsense_frame0.h 
    nlink_utils.h 
    nlink_typedef.h


FORMS += 
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target


main.cpp代码不变,就不展示了

 mainwindow.h代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 

#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void _Init();//初始化函数声明

private slots:
    void on_open_clicked();

    void on_send_clicked();

    void ReadData();//数据读取

    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    //声明串口
    QSerialPort *m_port;

};
#endif // MAINWINDOW_H

mainwindow.cpp代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 
#include 


#include "nlink_linktrack_nodeframe0.h"
#include "nlink_linktrack_nodeframe1.h"
#include "nlink_tofsense_frame0.h"
#include "nlink_utils.h"
#include "nlink_linktrack_nodeframe2.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::_Init()
{
    //查找可用的串口
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        QSerialPort port;
        port.setPort(info);
        if(port.open(QIODevice::ReadWrite))
        {
            ui->comboBox_port->addItem(port.portName());
            port.close();
        }
    }
    //设置波特率下拉菜单默认显示第0项
    ui->comboBox_baud->setCurrentIndex(0);

    //连接信号槽,用于接收信息
    m_port = new QSerialPort();
    connect(m_port, SIGNAL(readyRead()), this, SLOT(ReadData()));
}

void MainWindow::on_open_clicked()
{
    if(ui->open->text() == tr("打开串口"))
    {
        //设置串口名
        m_port->setPortName(ui->comboBox_port->currentText());
        //打开串口
        m_port->open(QIODevice::ReadWrite);
//        设置波特率
        m_port->setBaudRate(ui->comboBox_baud->currentText().toInt());
//        设置数据位
        switch(ui->comboBox_bit->currentText().toInt())
        {
            case 8:
                m_port->setDataBits(QSerialPort::Data8);
                break;
            case 7:
                m_port->setDataBits(QSerialPort::Data7);
                break;
            case 6:
                m_port->setDataBits(QSerialPort::Data6);
                break;
            case 5:
                m_port->setDataBits(QSerialPort::Data5);
                break;
            default:
                break;
        }

//        设置控制流
        m_port->setFlowControl(QSerialPort::NoFlowControl);

//        关闭菜单使能
        ui->comboBox_port->setEnabled(false);
        ui->comboBox_baud->setEnabled(false);
        ui->comboBox_bit->setEnabled(false);
        ui->comboBox_parity->setEnabled(false);
        ui->comboBox_stop->setEnabled(false);

        ui->open->setText(tr("关闭串口"));

    }
    else
    {
//        关闭串口
        m_port->clear();
        m_port->close();
//        m_port->deleteLater(); //这句是删除串口

//        恢复菜单使能
        ui->comboBox_port->setEnabled(true);
        ui->comboBox_baud->setEnabled(true);
        ui->comboBox_bit->setEnabled(true);
        ui->comboBox_parity->setEnabled(true);
        ui->comboBox_stop->setEnabled(true);

        ui->open->setText(tr("打开串口"));

    }
}


void MainWindow::on_send_clicked()
{
    m_port->write(ui->lineEdit_send->text().toUtf8());
}

void MainWindow::ReadData()
{
    
    QByteArray arr;
    static QByteArray buffer;

    arr = m_port->readAll();
    static bool flag = false;

    //判断是不是55开头的数据,如果是的话,就存起来,然后设置flag位true,下次就接收另外一组数据
    if(arr.toHex().startsWith("55"))
    {
        buffer.append(arr); //存储第一组数据
        flag = true;
        return;
    }

    if(flag)
    {

        buffer.append(arr); //存储第二组数据
        char *string1 = buffer.toHex().data();

        uint8_t data[1024];
        size_t data_length;
        data_length = Nlink_StringToHex(string1, data);  //将字符串转换为Hex格式,并将数据存储在data中

        if (g_nlt_nodeframe2.UnpackData(data, data_length))
        {
          nlt_nodeframe2_result_t *result = &g_nlt_nodeframe2.result;
          qDebug()<<"linkTrack Nodeframe0 data unpack successfully:n";

    //      和上位机对比,数据是正确的
          qDebug()<< "位置:" <pos_3d[0] <pos_3d[1] <pos_3d[2];
          qDebug()<< "速度:" <vel_3d[0] <vel_3d[1] <vel_3d[2];
          qDebug()<< "加速度:" <imu_acc_3d[0] <imu_acc_3d[1] <imu_acc_3d[2];

          ui->textEdit_get->clear();
          QString str1, str2, str3;

          str1 ="位置:" + QString::number(result->pos_3d[0]) + " " + QString::number(result->pos_3d[1]) + " " + QString::number(result->pos_3d[2]);
          str2 ="速度:" + QString::number(result->vel_3d[0]) + " " + QString::number(result->vel_3d[1]) + " " + QString::number(result->vel_3d[2]);
          str3 ="加速度:" + QString::number(result->imu_acc_3d[0]) + " " + QString::number(result->imu_acc_3d[1]) + " " + QString::number(result->imu_acc_3d[2]);

          ui->textEdit_get->append(str1);
          ui->textEdit_get->append(str2);
          ui->textEdit_get->append(str3);

         }

        buffer.clear();//因为buffer是静态变量,用完一次后要记得清空,否则会使得内存溢出
        flag=false;
    }

}


void MainWindow::on_check_clicked()
{

    ui->comboBox_port->clear();

    _Init();
}

Qt工程文件

在我的博客里面找一下,0积分下载

https://download.csdn.net/download/laoxue123456/36761662

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/429983.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号