【Qt5】多线程串口

2023-05-16

文章目录

  • 原版代码工程
  • 增加QCustomplot实时画图的源码工程
  • 源码

原版代码工程

源码下载链接:
链接:https://pan.baidu.com/s/15pWzadPwOx_OfJGtvL-MjA
提取码:lief
–来自百度网盘超级会员V5的分享

在这里插入图片描述

增加QCustomplot实时画图的源码工程

在这里插入图片描述源码:
链接:https://pan.baidu.com/s/1DJKV7RY3C_1nQ1K2iNP61w
提取码:lief
–来自百度网盘超级会员V5的分享

下位机arduino测试代码:

#include <Arduino.h>

unsigned char data_to_send[100] = {0};

int acc_data[3] = {0};
int gyro_data[3] = {0};

/**********为了匿名四轴上位机的协议定义的变量****************************/
//cup为小端模式存储,也就是在存储的时候,低位被存在0字节,高位在1字节
#define BYTE0(dwTemp)       (*(char *)(&dwTemp))     //取出int型变量的低字节
#define BYTE1(dwTemp)       (*((char *)(&dwTemp) + 1))     //    取存储在此变量下一内存字节的内容,高字节
#define BYTE2(dwTemp)       (*((char *)(&dwTemp) + 2))
#define BYTE3(dwTemp)       (*((char *)(&dwTemp) + 3))

/* 
发送给上位机的数据帧定义 
@桢头--功能字--长度--数据(一个或多个,具体看协议说明)-校验
@前2个字节为帧头0xAAAA 
@第3个字节为帧ID,应设置为0xF1~0xFA中的一个 
@第4个字节为报文数据长度(dlc) 
@第5个字节开始到第5+dlc-1个字节为要传输的数据内容段,每个数据场为高字节在前,地字节在后 
@第5+dlc个字节为CheckSum,为第1个字节到第5+dlc-1个字节所有字节的值相加后,保留结果的低八位作为CheckSum 
*/  
void Data_Send_Senser(unsigned int pst)  //按照协议的要求处理数据,pst为包含多个数据的数组,但这里为一个数据
{
    unsigned char  _cnt=0;
    unsigned char  i=0;
    unsigned int j=0,temp;
    unsigned char sum = 0;
    
    //char 类型为两个字节
    data_to_send[_cnt++]=0xAA;  //桢头
    data_to_send[_cnt++]=0xAA;
    data_to_send[_cnt++]=0x02;  //功能字
    data_to_send[_cnt++]=0;     //需要发送数据的字节数,暂时给0,后面在赋值。
    data_to_send[_cnt++]=pst&0x00ff;  //数据的低8位
    data_to_send[_cnt++]=pst>>8;  //数据的高8位
    
    
    
    data_to_send[3] = _cnt-4;   //长度
    
    for(i=0; i<_cnt; i++)
    {
      sum = sum+ data_to_send[i];  //校验位
    }
    
    data_to_send[_cnt++] =sum; //计算校验位

    Serial.write(data_to_send,_cnt);  
}

/* 
发送给上位机的数据帧定义 
@桢头--功能字--长度--数据(一个或多个,具体看协议说明)-校验
@前2个字节为帧头0xAAAA 
@第3个字节为帧ID,应设置为0xF1~0xFA中的一个 
@第4个字节为报文数据长度(dlc) 
@第5个字节开始到第5+dlc-1个字节为要传输的数据内容段,每个数据场为高字节在前,地字节在后 
@第5+dlc个字节为CheckSum,为第1个字节到第5+dlc-1个字节所有字节的值相加后,保留结果的低八位作为CheckSum 
*/  
void data_to_computer(int* acc_data,int* gyro_data)
{
    unsigned char  data_to_send[23] = {0};
    unsigned char i = 0;
    unsigned char cnt = 0;
    unsigned char sum = 0;
    
    data_to_send[cnt++]=0xAA;     //帧头:AAAA
    data_to_send[cnt++]=0xAA;
    data_to_send[cnt++]=0x02;     //功能字:OXF2
    data_to_send[cnt++]=0;         //需要发送数据的字节数,暂时给0,后面在赋值。

    data_to_send[cnt++] = BYTE1(acc_data[0]);//取data[0]数据的高字节,
    data_to_send[cnt++] = BYTE0(acc_data[0]);
    data_to_send[cnt++] = BYTE1(acc_data[1]);
    data_to_send[cnt++] = BYTE0(acc_data[1]);
    data_to_send[cnt++] = BYTE1(acc_data[2]);
    data_to_send[cnt++] = BYTE0(acc_data[2]);

    data_to_send[cnt++] = BYTE1(gyro_data[0]);//取data[0]数据的高字节,
    data_to_send[cnt++] = BYTE0(gyro_data[0]);
    data_to_send[cnt++] = BYTE1(gyro_data[1]);
    data_to_send[cnt++] = BYTE0(gyro_data[1]);
    data_to_send[cnt++] = BYTE1(gyro_data[2]);
    data_to_send[cnt++] = BYTE0(gyro_data[2]);

    data_to_send[cnt++]=0;
    data_to_send[cnt++]=0;
    data_to_send[cnt++]=0;
    data_to_send[cnt++]=0;
    data_to_send[cnt++]=0;
    data_to_send[cnt++]=0;

    data_to_send[3] = cnt-4;//计算总数据的字节数。

    for(i=0;i<cnt;i++) //对于for语句,当不写大括号的时候,只执行到下面第一个分号结束。
    {
        sum+=data_to_send[i];
    }
    data_to_send[cnt++] = sum;    //计算校验位
    Serial.write(data_to_send,cnt);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  randomSeed(analogRead(0));

  pinMode(8,OUTPUT); 
}

void loop() {

  // unsigned char buff[6];
  // unsigned char i;

  // for(i = 0;i<6;i++)
  // {
  //   buff[i] = random(65535);
  // }

  //   acc_data[0] = (buff[0] << 8) | buff[1];//x轴高8位左移8位或上低8位
  //   acc_data[1] = (buff[2] << 8) | buff[3];
  //   acc_data[2] = (buff[4] << 8) | buff[5];

  //   for(i = 0;i<6;i++)
  //   {
  //       buff[i] = random(65535);
  //   }

  //   gyro_data[0] = (buff[0] << 8) | buff[1];//x轴高8位左移8位或上低8位
  //   gyro_data[1] = (buff[2] << 8) | buff[3];
  //   gyro_data[2] = (buff[4] << 8) | buff[5];


 // data_to_computer(acc_data, gyro_data);

  digitalWrite(8,HIGH);


//   unsigned int num = random(100);
//   Data_Send_Senser(num);
  for(int i = 0; i < 255; i++)
  {
    Data_Send_Senser(i);
    delay(2); // ms      
  }
           

  digitalWrite(8,LOW);
  
  //delayMicroseconds(1500); // us
}

源码

mainwindows.cpp

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qDebug() <<"main" <<QThread::currentThread();
    qRegisterMetaType<serialportplus::Settings>("serialportplus::Settings");
    initUI();
    initSerialPort();
}

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

/*
 * 函数功能:完成对串口助手界面的初始化
 */
void MainWindow::initUI()
{
    //增加端口号选择项
    for (int i = 1; i <= 15; i++)
    {
        ui->cboPortName->addItem(QString("COM%1").arg(i));
    }

    //设置端口号波特率
    ui->cboBaudrate->addItem(QString("1200"),QSerialPort::Baud1200);
    ui->cboBaudrate->addItem(QString("2400"),QSerialPort::Baud2400);
    ui->cboBaudrate->addItem(QString("4800"),QSerialPort::Baud4800);
    ui->cboBaudrate->addItem(QString("9600"),QSerialPort::Baud9600);
    ui->cboBaudrate->addItem(QString("19200"),QSerialPort::Baud19200);
    ui->cboBaudrate->addItem(QString("38400"),QSerialPort::Baud38400);
    ui->cboBaudrate->addItem(QString("57600"),QSerialPort::Baud57600);
    ui->cboBaudrate->addItem(QString("115200"),QSerialPort::Baud115200);

    //设置端口数据位数
    ui->cboDataBit->addItem("8",QSerialPort::Data8);
    ui->cboDataBit->addItem("7",QSerialPort::Data7);
    ui->cboDataBit->addItem("6",QSerialPort::Data6);
    ui->cboDataBit->addItem("5",QSerialPort::Data5);

    //设置端口校验方式
    ui->cboParity->addItem("Odd",QSerialPort::OddParity);
    ui->cboParity->addItem("Even",QSerialPort::EvenParity);
    ui->cboParity->addItem("None",QSerialPort::NoParity);

    //设置端口停止位
    ui->cboStopBit->addItem("1",QSerialPort::OneStop);
    ui->cboStopBit->addItem("1.5",QSerialPort::OneAndHalfStop);
    ui->cboStopBit->addItem("2",QSerialPort::TwoStop);

    //设置端口流控制
    ui->cboFlowContral->addItem("None",QSerialPort::NoFlowControl);
    ui->cboFlowContral->addItem("RTS/CTS",QSerialPort::HardwareControl);
    ui->cboFlowContral->addItem("XON/XOFF",QSerialPort::SoftwareControl);

    //设置定时重发时间,单位ms
    ui->lineEdit->setText("1000");
    //定时时间到,则执行timeup函数
    connect(&m_timer, &QTimer::timeout, this,&MainWindow::timeUp);
}

/*
 * 函数功能:完成对串口的初始化,设置串口子线程
 */
void MainWindow::initSerialPort()
{
    //将串口对象的相关操作,放入子线程
    m_serial.moveToThread(&m_thread);
    //子线程启动
    m_thread.start();

    /*分别是界面对串口发出的启动、停止和发送数据的信号*/
    connect(this, &MainWindow::sigStart,&m_serial, &serialportplus::startPort);
    connect(this, &MainWindow::sigStop,&m_serial, &serialportplus::stopPort);
    connect(this, &MainWindow::sigSend,&m_serial, &serialportplus::sendData);

    /*分别是串口对界面发出的启动、停止和接收数据的信号*/
    connect(&m_serial, &serialportplus::sigStarted,this, &MainWindow::started);
    connect(&m_serial, &serialportplus::sigStop,this, &MainWindow::stoped);
    connect(&m_serial, &serialportplus::sigReceived,this, &MainWindow::receiveData);
}

/*
 * 函数功能:当界面关闭时,子线程也要进行关闭
 */
void MainWindow::closeEvent(QCloseEvent *event)
{
    Q_UNUSED(event);
    //打印界面主线程地址
    qDebug() <<"main" <<QThread::currentThread();
    //向发送串口发送串口停止的信号
    emit sigStop();

    //串口子线程关闭
    m_thread.quit();
    //等待串口子线程完全关闭
    m_thread.wait();

}


/*
 * 函数功能:根据串口打开按钮判断是否打开串口,
 *         当串口打开时,对串口参数进行设置,并向串口子线程发出串口打开信号,否则发出关闭信号
 */
void MainWindow::on_btnOpenPort_clicked()
{
    //获取串口打开按钮的文本
    QString text= ui->btnOpenPort->text();
    //当按钮关闭时,打开串口,并设置相关参数,向串口子线程发送串口打开信号
    if(text ==  QString::fromLocal8Bit("打开串口"))
    {
        serialportplus::Settings s;
        s.name= ui->cboPortName->currentText();
        s.baudRate= (QSerialPort::BaudRate)ui->cboBaudrate->currentData().toInt();
        s.dataBits = (QSerialPort::DataBits)ui->cboDataBit->currentData().toInt();
        s.stopBits= (QSerialPort::StopBits)ui->cboStopBit->currentData().toInt();
        s.parity= (QSerialPort::Parity)ui->cboParity->currentData().toInt();
        s.flowControl = (QSerialPort::FlowControl)ui->cboFlowContral->currentData().toInt();
        emit sigStart(s);
    }
     //当按钮打开时,关闭串口,向串口子线程发送串口关闭信号
    else
    {
        emit sigStop();
    }

}

/*
 * 函数功能:点击发送按钮时,执行串口发送
 */
void MainWindow::on_btnSend_clicked()
{
    //获取所要发送的文本
    QString strSend = ui->SendplainTextEdit->toPlainText();
    //将所要发送的文本存入arr变量
    QByteArray arr = strSend.toUtf8();
    //将arr变量通过信号发给串口子线程
    emit sigSend(arr);
}

/*
 * 函数功能:接收串口子线程发出启动的信号,对串口的按钮和参数设置的界面进行管理
 */
void MainWindow::started()
{
    //串口打开按钮文本切换,切换为“关闭串口”
    ui->btnOpenPort->setText(QString::fromLocal8Bit("关闭串口"));
    //串口参数处于不可更改的状态
    ui->groupBox->setEnabled(false);
}

/*
 * 函数功能:接收串口子线程发出停止的信号,对串口的按钮和参数设置的界面进行管理
 */
void MainWindow::stoped(int status)
{
    Q_UNUSED(status);
    //串口打开按钮文本切换,切换为“打开串口”
    ui->btnOpenPort->setText(QString::fromLocal8Bit("打开串口"));
    //串口参数处于可更改的状态
    ui->groupBox->setEnabled(true);
}

/*
 * 函数功能:接收串口子线程发出数据接收的信号,界面接收串口子线程发送的数据,并将其显示到界面上
 */
void MainWindow::receiveData(QByteArray data)
{
    //将接收的数据进行转换
    QString strText = QString(data);
    //获取当前接收数据的时间
    QDateTime current_date_time = QDateTime::currentDateTime();
    //显示当前接收数据的时间
    QString  t  = current_date_time.toString("yyyy-MM-dd hh:mm:ss.zzz : ");
    //显示当前接收的数据
    ui->RecveeiveplainTextEdit->appendPlainText( t + strText + "\n" );
}

/*
 * 函数功能:定时发送状态改变响应函数
 */
void MainWindow::on_checkBox_stateChanged(int arg1)
{
    //当定时发送被勾选时
    if(arg1)
    {
        //定时器启动
        m_timer.start(ui->lineEdit->text().toInt());
    }
    //当定时发送未被勾选时
    else
    {
        //定时器停止
        m_timer.stop();
    }
}

/*
 * 函数功能:定时时间到时,执行串口发送函数
 */
void MainWindow::timeUp()
{
    qDebug() << "timeup";

    //串口发送函数
    on_btnSend_clicked();
}

mainwindows.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include<QSerialPort>
#include<QDateTime>
#include<QTimer>
#include<QDebug>
#include<QThread>

#include"serialportplus.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    //界面初始化函数
    void initUI();
    //端口初始化函数
    void initSerialPort();
    //界面关闭事件
    void closeEvent(QCloseEvent *event);

private:
    Ui::MainWindow *ui;

    //创建一个自定义的串口类对象
    serialportplus m_serial;
    //创建一个线程对象
    QThread m_thread;
    //创建一个定时器对象
    QTimer m_timer;



signals:

    // 分别是界面对串口发出的启动、停止和发送数据的信号
    void sigStart(serialportplus::Settings s);
    void sigStop();
    void sigSend(QByteArray data);

public slots:

    // 分别是串口对界面发出的启动、停止和接收数据的信号时,所要执行的操作
    void started();
    void stoped(int status);
    void receiveData(QByteArray data);


private slots:
    void timeUp();
    void on_btnOpenPort_clicked();
    void on_btnSend_clicked();
    void on_checkBox_stateChanged(int arg1);
};
#endif // MAINWINDOW_H

serialportplus.cpp

#include "serialportplus.h"

/*
 * 函数功能:对串口接收到数据的信号进行响应,并向界面主线程发送接收到的数据
 */
serialportplus::serialportplus()
{
    //当串口子线程接收到数据时,向界面主线程发出数据接收的信号
    connect(this, &QSerialPort::readyRead, [this]()
    {
        qDebug() << QString::fromLocal8Bit ("接收") << QThread::currentThread();
        //读取串口接收的数据
        QByteArray arr = readAll();
        //将数据通过信号发给界面主线程
        emit sigReceived(arr);
    });
}

/*
 * 函数功能:接收界面主线程发出开始信号,接收串口参数并对设置,
 *         同时根据串口状态发出启动或停止信号。
 */
void serialportplus::startPort(serialportplus::Settings sets)
{
    /*设置串口参数*/
    setPortName(sets.name);
    setParity(sets.parity);
    setBaudRate(sets.baudRate);
    setDataBits(sets.dataBits);
    setStopBits(sets.stopBits);
    setFlowControl(sets.flowControl);

    qDebug() << QString::fromLocal8Bit ("启动") <<QThread::currentThread();

    //判断串口是否处于可读写状态
    if(open(QIODevice::ReadWrite))
    {
        //串口处于可读写状态,发出向界面主线程启动信号
        emit sigStarted();
    }
    else
    {
        //串口不处于可读写状态,发出向界面主线程停止信号
        emit sigStop(1);
    }
}

/*
 * 函数功能:接收界面主线程发送的停止信号,串口关闭
 */
void serialportplus::stopPort()
{
    qDebug() << QString::fromLocal8Bit ("停止") <<QThread::currentThread();
    //判断串口是否关闭
    if(isOpen())
    {
        //关闭串口
        close();
    }
    //向界面主线程发出停止信号
    emit sigStop(0);
}

/*
 * 函数功能:接收界面主线程发出的数据发送信号,串口进行数据发送
 */
void serialportplus::sendData(QByteArray arr)
{
    qDebug() << QString::fromLocal8Bit ("发送") <<QThread::currentThread();
    //判断串口是否关闭


    if(isOpen())
    {
        //发送数据
        write(arr);
    }
}

serialportplus.h

#ifndef SERIALPORTPLUS_H
#define SERIALPORTPLUS_H

#include <QSerialPort>
#include<QThread>
#include<QDebug>

class serialportplus : public QSerialPort
{
    Q_OBJECT
public:

    //串口接收数据的函数
    serialportplus();

    //串口设置
    struct Settings
    {
       QString name;//端口名称COM1、COM2
       BaudRate baudRate;//波特率
       DataBits dataBits;//数据位
       Parity parity;//奇偶校验
       StopBits stopBits;//停止位
       FlowControl flowControl;//流控制
     };

public slots:
    // 分别是界面对串口发出的启动、停止和发送数据的信号时,所要执行的操作
    void startPort(Settings sets);
    void stopPort();
    void sendData(QByteArray arr);

signals:
    // 分别是串口对界面发出的启动、停止和接收数据的信号
    void sigStarted();
    void sigStop(int status);
    void sigReceived(QByteArray data);
};

#endif // SERIALPORTPLUS_H

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Qt5】多线程串口 的相关文章

  • linux应用编程--思维导图

    思维导图软件是xmind 下载源文件点击打开链接
  • 深度学习中Batch、Iteration、Epoch的概念与区别

    在神经网络训练中 xff0c 一般采用小批量梯度下降的方式 Batch Epoch Iteration 就是其中的重要的概念 我们要理解懂得它们都是什么以及它们之间的区别 1 Batch 每次迭代时使用的一批样本就叫做一个Batch xff
  • STM32使用CubeMAX配置的串口中断接收方法

    STM32使用CubeMAX配置的串口中断接收方法 目录 1 定位串口中断发生的地方 2 处理串口中断接收的流程是 xff1a xff08 1 xff09 初始化串口 xff08 2 xff09 在main中第一次调用接收中断函数 xff0
  • SAP 寻找增强点的方法

    SAP中寻找增强的实现方法 SAP 增强已经发展过几代了 xff0c 可参考 SAP 标准教材 BC425 和 BC427 简单的说SAP的用户出口总共有四 代 1 第一代 基于源代码的增强 SAP提供一个空代码的子过程 xff0c 在这个
  • SNMPV3的实现原理

    在snmp发展到V3版本后 xff0c 把snmp的安全性提升到一个新高度 xff0c 这同时也带来了实现上的复杂性 在02年 xff0c 03年我都曾经想进一步的了解它的实现 xff0c 但都没什么进展 这次在实现Csnmp的过程中 xf
  • ubuntu更新错误:dists/artful/main/binary-arm64/Packages 404 Not Found

    Failed to fetch http archive ubuntu com ubuntu dists artful main binary arm64 Packages 404 Not Found IP 91 189 88 162 80
  • 个人公众号开通啦!!!!

    已经开通了个人微信公众号 xff1a 编程时光机 以后会在公众号里和大家分享知识和生吞活 xff0c 欢迎大家关注 xff01 xff01
  • 小白学AI系列(一)-- AI简史

    经过一段时间的酝酿 xff0c 小白学AI系列也正是开始了 xff01 小编将从三个阶段和大家一起入门人工智能 xff0c 掌握常用机器学习算法和数据分析技巧 小编专业为数据融合方向 xff0c 也曾接触过机器学习 xff0c 但由于人工智
  • 小白学AI系列(二) -- Python模块和函数

    原文地址 xff1a 小白学AI系列 xff08 二 xff09 Python模块和函数 今天的内容是带大家学习解释性语言 Python 小编有学过一段时间的C 43 43 和Matlab 相对于二者而言 xff0c Python是作为学习
  • PX4固定翼调试校准流程及实验相关问题记录分析

    pixhawk固定翼调试流程 对于px4固件 xff0c 其对应选择的一般是qgroundcontrol地面站 xff08 APM一般使用Mission Planner xff09 本次调试的固件版本是1 6 5dev xff08 最新的固
  • Ubuntu16.04下PX4环境快速搭建及uORB通信机制

    Ubuntu16 04下的环境搭建 之前搭建PX4环境常常编译不通 xff0c cmake gcc 以及交叉编译器gcc arm none eabi的版本问题导致make固件报错 xff0c 好不容易编译通过了 xff0c 在进行安装jMA
  • PX4固件通过UART连接串口读取超声波,和树莓派3通信

    添加串口读取程序 首先在Firmware msg文件夹下添加rw uart msg span class hljs keyword char span span class hljs number 5 span datastr span c
  • PX4自主飞行相关问题

    调试入坑 赶在回去之前把10月1日新校区试飞相关问题记录一下 首先是调试相关问题 调试具体流程 在校准遥控器时经常出现校准一半就停止的问题 xff0c 期初认为是固件问题 xff0c 换了1 6 5 1 6 3 xff0c 1 5 5三个固
  • PID控制器及其C++实现

    PID控制器原理 PID控制器实际上是对偏差的控制 其原理图如下 其数学的表达如下 u x 61 K p e r r t 43 1 T e r r t d t 43 T D d e r r t d t u x
  • Oracle Systimestamp 函数

    在Oracle PLSQL中 xff0c Systimestamp 函数返回本机数据库上当前系统日期和时间 包括微秒和时区 Systimestamp 函数的语法是 xff1a systimestamp 应用于 xff1a Oracle 9i
  • px4源码解读之fw_att_control

    目录 程序和控制流程源码解读总结 程序和控制流程 个人简单的总结了一下整个程序的流程如下 整个的控制流程图可以在官网中找到 源码解读 在解读源码之前 需要提几个公式 第一个就是协调转弯中的偏航控制 也就是流程图中为什么输入是空速 p 61
  • 安装Mavlink generator出现UnicodeEncodeError错误

    最近在看mavlink 在执行官网的操作时出现了问题 问题如下 span class hljs constant Exception span span class hljs keyword in span span class hljs
  • mc_att_control基础知识:向量运算和罗德里格斯旋转

    向量的叉乘和点乘 在我们的mc att control中有我们的向量的点乘和叉乘 一般遇到的都是三维的运算 S O 3 S O 3 李群 向量点乘 假设向量 a 61 a 1 a 2 a 3
  • 低通滤波器和高通滤波器的程序实现原理推导

    傅立叶变换 拉普拉斯变换和Z变换 对于信号分析而言 傅立叶变换是必不可少的 我们都知道傅立叶变换是把系统从时域变换到频域进行分析 那么拉普拉斯变换和Z变换是干什么的 简单的来说 由于傅里叶变换的收敛有一个狄利克雷条件 xff0c 要求信号绝
  • PX4源码解读之fw_pos_control_l1

    固定翼的位置控制是一个很重要问题 它不同于旋翼的控制 需要对速度和高度进行解耦控制 并且其不能像旋翼那样进行悬停 其转弯的时候有一个转弯半径 本博客不会对源码进行详细的解读 主要是分享一些自己读源码时的资料 自己读的过程中也有注释 想要的同

随机推荐

  • 四元数表示旋转的理解

    哈密尔顿 为了纪念四元数的发明者哈密尔顿 爱尔兰于1943年11月15日发行了下面这张邮票 哈密尔顿简直是个天才 哈密尔顿从小到进入大学之前没有进过学校读书 xff0c 他的教育是靠叔父传授以及自学 他找到了法国数学家克莱罗 xff08 C
  • mc_att_control源码解析

    目录 源码分析内环控制外环控制 之前写了博客分析了一下旋翼姿态控制的基础知识 mc att control基础知识 这次就对照代码将整个旋翼姿态控制过程呈现一遍 先看一下整个程序的框图 从图中可以看到 实际上整个控制分成内外两个环进行控制
  • PX4下载指定版本代码和刷固件的三种方式

    由于之前下载的是1 7版本的代码 现在v5版本的px4需要最新的代码固件 因此这里记录一下 查看自己代码版本 查看自己仓库代码版本的命令如下 git describe always tags 输出 v1 7 0 rc3 9 g0e1c7eb
  • Python怎么调用matlab的

    文章目录 环境的安装安装合适的python环境安装用于 Python 的 MATLAB 引擎 API 环境的安装 安装合适的python环境 研究这个也是在知乎上突然看到的 xff0c 以前python写的多 xff0c 现在由于工作需要
  • insert语句中sequence的使用方法

    我们常常在表中需要插入一些自动增长的值 一方面 我们可以手动添加这些值 xff0c 另一方面 oracle提供的sequence可以帮助我们实现插入的值自动增长 而不需要我们手动的提供值 我们需要做的就是设置好sequence的初值和增长值
  • Ubuntu 安装 vnc server

    查看Ubuntu系统版本 xff1a sudo lsb release a 安装Xfce桌面环境 xff1a sudo apt install xfce4 xfce4 goodies 配置gnome桌面环境 xff0c 参考 xff1a h
  • 嵌入式Linux(4):应用层和内核层数据传输

    文章目录 简介1 如果在应用层使用系统IO对设备节点进行打开 xff0c 关闭 xff0c 读写等操作会发生什么呢 xff1f 写个例子2 假如驱动层的file operations里面没有实现read之类的操作函数 xff0c 会发生什么
  • 嵌入式Linux(5):物理地址到虚拟地址映射

    文章目录 理论知识1 使能了MMU以后有什么好处呢 xff1f 2 MMU非常复杂 xff0c 那么我们如何完成物理地址到虚拟地址的转换呢 xff1f 3 如何查看哪些物理地址被映射过了呢 xff1f 实例 RK3568 理论知识 在Lin
  • 嵌入式Linux(6):驱动模块传参

    文章目录 1 什么是驱动传参 xff1f 2 驱动传参有什么作用 xff1f 3 怎么给我们的驱动传参数 xff1f 传递普通参数传递数组 1 什么是驱动传参 xff1f 驱动传参就是在安装驱动模块 xff08 ko文件 xff09 的时候
  • 嵌入式Linux(7):字符设备驱动--申请设备号

    文章目录 1 字符设备和杂项设备的区别2 注册字符类设备号的两个办法第一种 xff1a 静态分配一个设备号第二种 xff1a 动态分配注销设备号 写代码不带参数测试 xff08 动态分配 xff09 xff1a 带参数测试 xff08 静态
  • 嵌入式Linux(8):字符设备驱动--注册字符类设备

    文章目录 前言上代码 前言 杂项设备 注册杂项设备 xff1a span class token function misc register span span class token punctuation span span clas
  • 嵌入式Linux(9):字符设备驱动--自动创建设备节点

    文章目录 前言1 怎么自动创建一个设备节点 xff1f 2 什么是mdev3 什么是udev 4 怎么自动创建设备节点 xff1f 5 创建和删除类函数 自动生成类代码 6 创建设备函数 自动生成节点代码 前言 在上一节中 xff0c 使用
  • 嵌入式Linux(10):杂项设备和字符设备驱动总结

    文章目录 杂项设备驱动框架图 xff1a 字符设备驱动框架图 xff1a 相对来说 xff0c 如果是操作几个GPIO的操作 xff0c 其实使用简单的杂项设备驱动就可以了 xff0c 字符驱动相对会复杂一点
  • 嵌入式Linux:FrameBuffer 和 DRM/KMS(一)

    文章目录 前言 Linux 的两种显示方案FrameBufferDRM1 GEM2 KMS 参考 xff1a RK3399 探索之旅 Display 子系统 基础概念 参考 xff1a DRM架构介绍 xff08 一 xff09 前言 Li
  • 【RP-RV1126】Ubuntu上配置Buildroot Qt 开发板远程开发调试环境(SSH)

    文章目录 一 前提二 基础设置建设Buildroot编译Qt5配置SSHBuildroot文件系统添加账号密码开发板联网Buildroot文件系统构建时打开rsync功能 三 QtCreator配置3 1 配置Qt交叉编译套件 Kits 配
  • oracle create view语法

    视图实际上是一个或多个表上的预定义查询 xff0c 这些表称为基表 视图并不存储数据 xff0c 只是在查询视图时才访问基表 视图的优点 xff1a 限制用户只能通过视图检索数据 xff0c 对用户屏蔽基表 可以将复杂的查询编写为视图 xf
  • springsecurity oauth2实现前后端分离项目的SSO技术点总结

    参考 xff1a https www jianshu com p b549220e7b34 ivk sa 61 1024320u 一 基于cookie 43 session的SSO基本实现 1 认证中心的授权服务器配置 配置类继承Autho
  • 【Buildroot】基础知识:目录、根文件系统目录覆盖、编译性能分析(编译时间、目标尺寸、包依赖图)

    文章目录 一 Buildroot目录介绍二 Finalizing target2 1 fs overlay2 2 post build2 3 post image 三 编译性能3 1 编译耗时3 2 编译依赖关系3 3 编译结果尺寸分析3
  • 【RV1126】移植kaldi实时语音识别

    文章目录 算法一 环境1 1 硬件环境 RV1126开发板1 2 交叉编译器1 3 需要Cmake版本大于3 1以上 二 交叉编译sherpa2 1 下载sherpa2 2 编译sherpa2 3 运行测试 三 下载模型四 语音测试4 1
  • 【Qt5】多线程串口

    文章目录 原版代码工程增加QCustomplot实时画图的源码工程源码 原版代码工程 源码下载链接 xff1a 链接 xff1a https pan baidu com s 15pWzadPwOx OfJGtvL MjA 提取码 xff1a