• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Qt无人机姿态模拟

武飞扬头像
张芮晨
帮助1

这个是我实训做的项目,是模拟对无人机姿态的控制,实现对无人机飞行数据的分析,项目主要分为登录窗口,客户端和服务器端
项目主题界面:
学新通

需求分析:

1、设计本地登录界面及云端平台界面。
2、根据用户登录信息的不同,选择不同的云端用户级别,具体为user和vip。
3、普通用户只能查看实时数据、自动给出实时建议,超级用户可以查看实时数据、历史数据、统计数据判断是否危险飞行、生成事故报告
4、创建数据库,保存两张表,表1判断云端用户级别及用户登录验证,表2记录一定时间内的飞机姿态数据
5、事故报告以文档(word、pdf)形式生成

功能分析:

1、可以根据用户级别的不同授权不同的内容查看。
2、可以使用模拟终端(滑动按钮)来改变机身角度的值。
3、通过计算机网络将数据进行传输。
4、可以实时改变验证平台上图形的状态。
5、可以实时记录机身角度改变的内容并保存到数据库中

总体设计:

学新通
我先从登录界面开始说起吧

登录界面的设计:

学新通
学新通
登录界面主要分为用户登录和管理员登录,运用了Sqlite轻量级数据库,可实现账号的注册,在普通用户界面加了一个验证码的功能,其实是通过随机数来实现验证,主要的代码如下:
创建数据库和表

 //创建数据库
    QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE");
    //QSqlDatabase db1=QSqlDatabase::addDatabase("QSQLITE");
    //设置数据库名
    db.setDatabaseName("pwd.db");
    //db1.setDatabaseName("pwd1.db");
    //打开数据
    if(db.open())
    {
        qDebug()<<"open database success";
    }else
    {
        qDebug()<<"open database fail";
    }
    //创建一个存储用户名密码的数据库表
    QString tableuser="create table userinfo(username varchar(64),password varchar(64))";
    QString tableadmin="create table userinfo1(username1 varchar(64),password1 varchar(64))";
学新通

实现注册:

 QString username=ui->useredit->text();
    QString password=ui->passedit->text();
    QString cmd=QString("insert into userinfo values('%1','%2')")
            .arg(username).arg(password);
    QSqlQuery query;
    if(username==NULL||password==NULL)
    {
        QMessageBox::information(this,"注册提示","用户名或密码不能为空");

    }
    else if(query.exec(cmd))
    {
        QMessageBox::information(this,"注册提示","注册成功");

    }

服务器的实现:

学新通
服务器界面就是一个模拟无人机的圆
学新通
这里运用了Qpainter来绘制三角,圆等形状来实现对无人机的模拟,服务器接收来自客户端的消息,来进行角度的改变,接收来自客户端连接的信号:

if(svr->hasPendingConnections()){
        socket = svr->nextPendingConnection();
        connect(socket,SIGNAL(readyRead()),this,SLOT(slotRecv()));
        qDebug() << "有设备连接";
    }

接收客户端数据:

  QByteArray array = socket->readAll();
    QString str = QString::fromUtf8(array);
    QString tmp;
    int j = 0;
    while(j<str.size()){
        tmp.clear();
        int k = 0;
        for(j;j<str.length();j  )
        {
            if(str[j]>='0'&&str[j]<='9'||str[j]=='-'){
                tmp.append(str[j]);
            }
            if(str[j]==" "){
                k  ;
                if(k == 1){
                    angle_spin = tmp.toInt();
                    tmp.clear();
                }else if(k==2) {
                    angle_dir = tmp.toInt();
                    tmp.clear();
                }
            }
            if(str[j]=="e"){
                j  ;
                angle_pit = tmp.toInt();
                break;
            }
        }
        this->setWindowTitle("偏转角:" QString::number(angle_spin) "°俯仰角:" QString::number(angle_dir) "°方向:" QString::number(angle_pit) "°");
        update();
    }
学新通

客户端的实现:

学新通
客户端主要通过三个Slider来实现对角度的控制,在tableView控件里来显示历史数据,tableView里还有一个事故,我这里设置的是三个角度大于60度就会报警,一般报警就是事故变为1.0并且图标发生改变:
学新通
学新通
学新通
然后就是散点图的绘制:


    chart = new QChart();

    chart->setTitle("无人机飞行角度"); //设置表格标题

    QScatterSeries *scatterSeries1 = new QScatterSeries(chart);
    QScatterSeries *scatterSeries2 = new QScatterSeries(chart);
    QScatterSeries *scatterSeries3 = new QScatterSeries(chart);


    scatterSeries1->setName("偏航角度");
    scatterSeries1->setPointLabelsFormat("@yPoint");
    scatterSeries1->setPointLabelsVisible();
    scatterSeries1->setMarkerSize(16); // 设置节点大小

    scatterSeries2->setName("横滚角度");
    scatterSeries2->setPointLabelsFormat("@yPoint");
    scatterSeries2->setPointLabelsVisible();
    scatterSeries2->setMarkerSize(16);

    scatterSeries3->setName("俯视角度");
    scatterSeries3->setPointLabelsFormat("@yPoint");
    scatterSeries3->setPointLabelsVisible();
    scatterSeries3->setMarkerSize(16);


    QSqlQuery sql_query;
    QString select_sql = "select * from info3";// order by 字段名  asc 递增方式
    if(!sql_query.exec(select_sql))
    {
        qDebug()<<"错误";
    }
    else
    {
        while(sql_query.next())//判断下个查询数据是否可用
        {
            static int i=1,j=1,k=1;
            int a = sql_query.value(0).toDouble();//打印某行第一列
            int b = sql_query.value(1).toDouble();
            int c=sql_query.value(2).toDouble();


            scatterSeries1->append(i,a);

            scatterSeries2->append(j,b);
            scatterSeries3->append(k,c);
            i  ;
            j  ;
            k  ;
            if(i==90){
                i=-90;
            }
            if(j==90){
                j=-90;
            }
            if(k==0){
                k=-90;
            }


        }
    }


    // 添加节点
    //    scatterSeries1->append(0,6);
    //    scatterSeries1->append(1,10);
    //    scatterSeries1->append(4,12);
    //    scatterSeries1->append(6,5);
    //    scatterSeries2->append(0,18);
    //    scatterSeries2->append(3,13);
    //    scatterSeries2->append(5,7);
    //    scatterSeries2->append(6,2);
    chart->addSeries(scatterSeries1);
    chart->addSeries(scatterSeries2);
    chart->addSeries(scatterSeries3);
    //设置动画效果
    chart->setAnimationOptions(QChart::AllAnimations);

    chart->createDefaultAxes();//设置网格线
    chart->axes(Qt::Horizontal).first()->setRange(-90,90);// x轴范围
    chart->axes(Qt::Vertical).first()->setRange(-90,90);// y轴范围
    // Add space to label to add space between labels and axis在标签和轴之间加空格
    QValueAxis *axisY = qobject_cast<QValueAxis*>(chart->axes(Qt::Vertical).first());
    Q_ASSERT(axisY);
    axisY->setLabelFormat("%.1f  ");


    chart->setTheme(QChart::ChartThemeDark);

    QChartView *chartView;

    chartView = new QChartView(chart);

    zt  ;
    ui->widget1->insertWidget(0,chartView,0,Qt::Alignment());
    if(zt==1){
        ui->widget1->removeWidget(chartView);
        zt=0;
    }
学新通

可以实现数据的清空,一旦清空所有数据都会删除,散点图也会清除:
学新通
全部重置是对Slider的重置,导出数据是保存历史数据到csv文件:
学新通
导出pdf是保存历史数据到pdf中:
学新通

保存pdf代码:

 QFile pdfFile("D:\\test1.pdf");//输出文件名
    if(!pdfFile.open(QIODevice::WriteOnly))
    {
        QMessageBox::warning(this,tr("write File"),tr("Cannot open file:\n%1").arg("d:\\test.pdf"));
        return;
    }
    QPdfWriter *pdfWriter = new QPdfWriter(&pdfFile);               //实例化QPdfWriter 可以设置PDF文件的一些参数
    pdfWriter->setPageSize(QPagedPaintDevice::A4);                  //设置纸张为A4纸
    pdfWriter->setResolution(QPrinter::ScreenResolution);           //设置分辨率 屏幕分辨率 打印机分辨率 高分辨率
    pdfWriter->setPageMargins(QMarginsF(40, 40, 40, 40));           //设置页边距 顺序是:左上右下

    QPainter *pdfPainter = new QPainter(pdfWriter);                //qt绘制工具

    //设置标题
    QTextOption option(Qt::AlignCenter);                           //标题居中显示
    option.setWrapMode(QTextOption::WordWrap);                     //标题自动换行

    // 设置标题字体 需要使用QT的QFont
    QFont font;
    font.setFamily("Microsoft YaHei");                            //设置字体 微软雅黑、宋体之类的
    font.setPointSize(22);                                        //设置字体大小
    //font.setItalic(true);//斜体
    //font.setUnderline(true);//设置下划线
    //    font.setBold(true);                                           //加粗
    pdfPainter->setFont(font);
    pdfPainter->drawText(QRect(3000, 0, 2100, 450), QString::QString::fromUtf8("历史数据"), option);//距离左边3000,上面0,标题字宽度2100,标题字高450(如果字显示不全,可以适当调整)

    //设置内容
    option.setAlignment(Qt::AlignLeft);
    font.setPointSize(14);                                       //字体大小14
    pdfPainter->setFont(font);

    pdfPainter->drawRect(200, 250, 2000, 1);
    pdfPainter->drawRect(200, 700, 2000, 4);

    pdfPainter->setFont(QFont("NSimSun", 12, QFont::Normal));


    pdfPainter->setFont(QFont("NSimSun", 14, QFont::Normal));
    option.setAlignment(Qt::AlignLeft);
    font.setPointSize(10);                                       //字体大小14
    pdfPainter->setFont(font);

    pdfPainter->drawText(200, 2000, QString::fromUtf8("偏移角度"));
    pdfPainter->drawText(1200, 2000, QString::fromUtf8("横滚角度"));
    pdfPainter->drawText(2200, 2000, QString::fromUtf8("俯视角度"));
    pdfPainter->drawText(3200, 2000, QString::fromUtf8("事故"));

    QString str = "select * from info3";
    QSqlQuery query;
    query.exec(str);

    int i=0;
    while(query.next())//依次取出下一行数据
    {
        i  ;
        QString x1 = query.value(0).toString();
        QString x = query.value(1).toString();
        QString y = query.value(2).toString();
        QString z = query.value(3).toString();

        pdfPainter->drawText(200, 2000 i*200, x1);
        pdfPainter->drawText(1200, 2000 i*200, y);
        pdfPainter->drawText(2200, 2000 i*200, x);
        pdfPainter->drawText(3200, 2000 i*200, z);

        if(2000 i*200>12000)
        {
            i=i-50;
            pdfWriter->newPage();
            pdfPainter->drawText(200, 2000 i*200, x1);
            pdfPainter->drawText(1200, 2000 i*200, y);
            pdfPainter->drawText(2200, 2000 i*200, x);
            pdfPainter->drawText(3200, 2000 i*200, z);


        }
    }
    delete pdfPainter;
    delete pdfWriter;
    QDesktopServices::openUrl(QUrl::fromLocalFile("D:\\test1.pdf"));

学新通

整体的项目就是这样,最后由衷地感谢我的小组团队,以及实训的所有老师

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgehhef
系列文章
更多 icon
同类精品
更多 icon
继续加载