[Qt]QtLocation移植

在使用香橙派时用到了qtlocation模块,但是开发板没有响应的库,需要自己移植
1.使用命令 *** 查看版本
开发板使用5.15.3版本Qt,需要下载相同版本 https://qt-mirror.dannhauer.de/archive/qt/5.15/
2.下载后解压到主机 ~/tools/下 tar -xvf ***
3.修改头文件,否则报错
src/corelib/global/qglobal.h 里添加limits头文件
# include 一定要加在ifdef __cplusplus和endif之间才行
4.修改conf文件
/home/yue/tools/qt-everywhere-src-5.15.3/qtbase/mkspecs/linux-aarch64-gnu-g++/qmake.conf文件 填入自己的交叉编译链
# modifications to g++.conf
QMAKE_CC = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc
QMAKE_CXX = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++
QMAKE_LINK = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++
QMAKE_LINK_SHLIB = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++

# modifications to linux.conf
QMAKE_AR = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-ar cqs
QMAKE_OBJCOPY = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-objcopy
QMAKE_NM = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-nm -P
QMAKE_STRIP = /home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-strip

5.在qt目录下新建autoconfig.sh文件,并添加可执行属性 sudo chmod +x autoconfig.sh

./configure \
-prefix /opt/qt-5.15.3 \
-release \
-feature-library \
-opensource \
-xplatform linux-aarch64-gnu-g++ \
-make libs \
-optimized-qmake \
-no-opengl \
-pch \
-shared \
-qt-libjpeg \
-qt-zlib \
-qt-libpng

6.先清理下
sudo make distclean -j5
7.执行配置文件
sudo ./autoconfig.sh
8.编译
sudo gmake -j5
9.安装
sudo gmake install -j5

10.将库文件拷贝到开发板, 这里使用了部分正点原子的库,如果自己生成需要修改buildroot

cd /opt/atk-dlrk356x-toolchain/aarch64-buildroot-linux-gnu/sysroot/usr/lib/
scp \
libprotobuf.so.16 \
libopencv_gapi.so.405 \
libjpeg.so.62 \
libmali_hook.so.1 \
libopencv_highgui.so.405 \
libopencv_ml.so.405 \
libopencv_objdetect.so.405 \
libopencv_photo.so.405 \
libopencv_stitching.so.405 \
libopencv_video.so.405 \
libopencv_calib3d.so.405 \
libopencv_features2d.so.405 \
libopencv_dnn.so.405 \
libopencv_flann.so.405 \
libopencv_videoio.so.405 \
libopencv_imgcodecs.so.405 \
libopencv_freetype.so.405 \
libopencv_imgproc.so.405 \
libopencv_core.so.405 \
libQt5MultimediaWidgets.so.5 \
libQt5Multimedia.so.5 \
libQt5SerialPort.so.5 \
libopencv_video.so.405 \
libopencv_calib3d.so.405 \
libopencv_imgproc.so.405 \
libopencv_core.so.405 \
libQt5Test.so.5 \
libopencv_imgproc.so.405 \
libopencv_core.so.405 \
libopencv_core.so.405 \
libopencv_dnn.so.405 \
libopencv_calib3d.so.405 \
libopencv_imgproc.so.405 \
libopencv_core.so.405 \
libopencv_imgproc.so.405 \
libopencv_core.so.405 root@192.168.0.107:/usr/lib/aarch64-linux-gnu

cd /opt/qt-5.15.3/lib
sudo scp libQt5Location.so* libQt5Positioning* libQt5QuickTemplates2.so.5 libQt5QuickControls2.so.5 libQt5Concurrent.so.5 root@192.168.0.101:/usr/lib/aarch64-linux-gnu

cd /opt/qt-5.15.3/qml
sudo scp -r QtLocation root@192.168.0.107:/usr/lib/aarch64-linux-gnu/qt5/qml
sudo scp -r QtPositioning root@192.168.0.107:/usr/lib/aarch64-linux-gnu/qt5/qml
sudo scp -r QtQuick root@192.168.0.107:/usr/lib/aarch64-linux-gnu/qt5/qml

cd /opt/qt-5.15.3/plugins
scp -r ./geoservices root@192.168.0.107:/usr/lib/aarch64-linux-gnu/qt5/plugins/

[FK]天空端和地面端的摄像头发送接收程序-1

———————-.pro—————————–
QT += core gui

QT += core gui widgets # 确保 widgets 模块被包含

CONFIG += link_pkgconfig
PKGCONFIG += opencv4

QT += multimedia multimediawidgets

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# 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 += \
CameraWorker.cpp \
main.cpp \
mainwindow.cpp \
picDecode.c \
tcpsend.cpp \
udpsendthread.cpp

HEADERS += \
CameraWorker.h \
includes.h \
mainwindow.h \
picDecode.h \
tcpsend.h \
udpsendthread.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

————–CameraWorker.h——————————

#ifndef CAMERAWORKER_H
#define CAMERAWORKER_H

#include
#include
#include
#include
#include

class CameraWorker : public QObject {
Q_OBJECT

public:
CameraWorker(QObject *parent = nullptr);
~CameraWorker();
void startCamera(int deviceIndex);
void stopCamera();

signals:
void frameCompress(const QByteArray &frameCompressData);

private:
cv::VideoCapture capture;
QMutex mutex;
bool isRunning;
void process();
void compressImageToMemory(const QImage &image);

};

#endif // CAMERAWORKER_H
—————————–includes.h——————————
#ifndef INCLUDES_H
#define INCLUDES_H

#define BASEPORT

#ifdef SKYPORT
#define LOCAL_IP “192.168.0.108”
#define LOCAL_PORT 12345
#define TARGET_IP “192.168.0.107”
#define TARGET_PORT 12000
#endif

#ifdef BASEPORT
#define LOCAL_IP “192.168.0.107”
#define LOCAL_PORT 12000
#define TARGET_IP “192.168.0.108”
#define TARGET_PORT 12345
#endif

#endif // INCLUDES_H

———————mainwindow.h—————————————

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include
#include
#include “CameraWorker.h” // 添加这一行以包含 CameraWorker
#include

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
Q_OBJECT

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

private slots:
void updateCameraFrame(const QImage &image);

void debugslot(const QByteArray &data);

private:
Ui::MainWindow *ui;
CameraWorker *cameraWorker; // 确保这个声明是正确的
QThread *cameraThread;
void bindThreadToCPU3(QThread *thread);
};

#endif // MAINWINDOW_H

—————————tcpsend.h————实际没用上—————
#ifndef TCPSEND_H
#define TCPSEND_H

#include
#include
#include
#include

class TcpSend : public QThread
{
Q_OBJECT

public:
explicit TcpSend(QObject *parent = nullptr);
~TcpSend();

void setTargetIp(const QString &ip);
void setTargetPort(quint16 port);

signals:
void dataReceived(const QByteArray &data);

protected:
void run() override;

private:
QTcpSocket *tcpSocket;
QString targetIp;
quint16 targetPort;

public slots:
void sendData(); // 实现发送功能
};

#endif // TCPSEND_H

——————————udpsendthread.h———————-
// udpsendthread.h
#ifndef UDPSENDTHREAD_H
#define UDPSENDTHREAD_H

#include
#include
#include

class UdpSendThread : public QObject
{
Q_OBJECT

public:
unsigned int times_rcv = 0;
int flag_rcv = 0;
int udpbagflag;
unsigned int datasize_max;
int connect_flag =0;
QByteArray picData;
public:
explicit UdpSendThread(QObject *parent = nullptr);
~UdpSendThread();

public slots:
void process(); // 模拟数据接收并触发dataReceived信号
void sendData(const QByteArray &data); // 实现UDP发送功能

void dataReceived(); // 当接收到数据时发出此信号

signals:

void frameCaptured(const QImage &image);

private:
QUdpSocket* udpSocket;
QString targetIP;
quint16 targetPort;
QImage decompressImageFromMemory( QByteArray &compressedData);

signals:
void dataRec(const QByteArray &data);

public slots:
void processData();
};

#endif // UDPSENDTHREAD_H

———————————–CameraWorker.cpp————————-

#include “CameraWorker.h”
#include // 包含 QDebug 以使用 qDebug()
#include
#include
#include
#include
#include “includes.h”

CameraWorker::CameraWorker(QObject *parent) : QObject(parent), isRunning(false) {}

CameraWorker::~CameraWorker() {
stopCamera();
}

void CameraWorker::startCamera(int deviceIndex) {
if (capture.isOpened()) return;

capture.open(deviceIndex);
if (!capture.isOpened()) {
qDebug() << "无法打开摄像头"; // 这里可以正常使用 qDebug() return; } capture.set(cv::CAP_PROP_FRAME_WIDTH, 640); // 设置宽度 capture.set(cv::CAP_PROP_FRAME_HEIGHT, 480); // 设置高度 capture.set(cv::CAP_PROP_FPS, 25); // 设置帧率 capture.set(cv::CAP_PROP_EXPOSURE, -4); // 设置曝光(根据需要调整) capture.set(cv::CAP_PROP_GAIN, 0); // 设置增益(根据需要调整) QThread::msleep(100); // 暂停以让设置生效 isRunning = true; QThread *thread = QThread::create([this]() { process(); }); connect(thread, &QThread::finished, this, &CameraWorker::deleteLater); thread->start();
}

void CameraWorker::stopCamera() {
QMutexLocker locker(&mutex);
isRunning = false;
capture.release();
}

void CameraWorker::process() {

#ifdef SKYPORT
while (true) {
{
QMutexLocker locker(&mutex);
if (!isRunning) break;
}

cv::Mat frame;
capture >> frame;
if (frame.empty()) continue;

cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage image(frame.data, frame.cols, frame.rows, frame.step[0], QImage::Format_RGB888);

size_t memory_usage_qimage = image.width() * image.height() * image.depth() / 8;
// qDebug() << "QImage memory usage: " << memory_usage_qimage / 1024.0 / 1024.0 << " MB"; compressImageToMemory(image); //emit frameCaptured(image); QThread::msleep(50); // 限制帧率 } #endif } void CameraWorker::compressImageToMemory(const QImage &image) { // 创建一个 QBuffer 对象,它将充当内存缓冲区 QBuffer buffer; buffer.open(QIODevice::WriteOnly); // 创建 QImageWriter 对象,用于将图像压缩并写入内存缓存 QImageWriter writer(&buffer, "JPEG"); // 使用 JPEG 格式进行压缩,可以选择其他格式 // 设置压缩质量(如果适用) writer.setQuality(80); // 设定压缩质量,范围是 0-100 // 将 QImage 压缩并写入缓存 if (writer.write(image)) { // 压缩成功后,获取压缩后的数据大小 size_t compressedSize = buffer.size(); //qDebug() << "Compressed image size: " << compressedSize / 1024.0 / 1024.0 << " MB"; // 你可以从缓存中获取压缩后的数据 QByteArray compressedData = buffer.data(); // 例如,可以将数据保存到文件,或者发送到网络 emit frameCompress(compressedData); } else { qDebug() << "Image compression failed!"; } } ----------------------------------main.cpp------------------------ #include "mainwindow.h" #include
#include

int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();

int cpu = sched_getcpu();
qDebug() << "Running on CPU: " << cpu ; return a.exec(); } --------------------------------CameraWorker.cpp------------------- #include "CameraWorker.h" #include // 包含 QDebug 以使用 qDebug()
#include
#include
#include
#include
#include “includes.h”

CameraWorker::CameraWorker(QObject *parent) : QObject(parent), isRunning(false) {}

CameraWorker::~CameraWorker() {
stopCamera();
}

void CameraWorker::startCamera(int deviceIndex) {
if (capture.isOpened()) return;

capture.open(deviceIndex);
if (!capture.isOpened()) {
qDebug() << "无法打开摄像头"; // 这里可以正常使用 qDebug() return; } capture.set(cv::CAP_PROP_FRAME_WIDTH, 640); // 设置宽度 capture.set(cv::CAP_PROP_FRAME_HEIGHT, 480); // 设置高度 capture.set(cv::CAP_PROP_FPS, 25); // 设置帧率 capture.set(cv::CAP_PROP_EXPOSURE, -4); // 设置曝光(根据需要调整) capture.set(cv::CAP_PROP_GAIN, 0); // 设置增益(根据需要调整) QThread::msleep(100); // 暂停以让设置生效 isRunning = true; QThread *thread = QThread::create([this]() { process(); }); connect(thread, &QThread::finished, this, &CameraWorker::deleteLater); thread->start();
}

void CameraWorker::stopCamera() {
QMutexLocker locker(&mutex);
isRunning = false;
capture.release();
}

void CameraWorker::process() {

#ifdef SKYPORT
while (true) {
{
QMutexLocker locker(&mutex);
if (!isRunning) break;
}

cv::Mat frame;
capture >> frame;
if (frame.empty()) continue;

cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage image(frame.data, frame.cols, frame.rows, frame.step[0], QImage::Format_RGB888);

size_t memory_usage_qimage = image.width() * image.height() * image.depth() / 8;
// qDebug() << "QImage memory usage: " << memory_usage_qimage / 1024.0 / 1024.0 << " MB"; compressImageToMemory(image); //emit frameCaptured(image); QThread::msleep(50); // 限制帧率 } #endif } void CameraWorker::compressImageToMemory(const QImage &image) { // 创建一个 QBuffer 对象,它将充当内存缓冲区 QBuffer buffer; buffer.open(QIODevice::WriteOnly); // 创建 QImageWriter 对象,用于将图像压缩并写入内存缓存 QImageWriter writer(&buffer, "JPEG"); // 使用 JPEG 格式进行压缩,可以选择其他格式 // 设置压缩质量(如果适用) writer.setQuality(80); // 设定压缩质量,范围是 0-100 // 将 QImage 压缩并写入缓存 if (writer.write(image)) { // 压缩成功后,获取压缩后的数据大小 size_t compressedSize = buffer.size(); //qDebug() << "Compressed image size: " << compressedSize / 1024.0 / 1024.0 << " MB"; // 你可以从缓存中获取压缩后的数据 QByteArray compressedData = buffer.data(); // 例如,可以将数据保存到文件,或者发送到网络 emit frameCompress(compressedData); } else { qDebug() << "Image compression failed!"; } } -------------------mainwindow.cpp-------------------------------- #include "mainwindow.h" #include "ui_mainwindow.h" #include // 包含 QDebug 以使用 qDebug()
#include “udpsendthread.h”
#include “tcpsend.h”
#include
#include “UdpReceiver.h”
#include “includes.h”

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

#ifdef SKYPORT
// 创建线程
cameraThread = new QThread;
cameraWorker->moveToThread(cameraThread);

connect(cameraThread, &QThread::started, [this]() {
cameraWorker->startCamera(0); // 打开默认摄像头
});
connect(cameraThread, &QThread::finished, cameraWorker, &CameraWorker::deleteLater);

bindThreadToCPU3(cameraThread);

cameraThread->start();
#endif
// 创建线程和数据发送对象
QThread* udpthread = new QThread();
UdpSendThread* udpSendThread = new UdpSendThread();

// 将 udpSendThread 移动到新线程
udpSendThread->moveToThread(udpthread);

// 使用lambda函数启动信号槽
QObject::connect(udpthread, &QThread::started, udpSendThread, &UdpSendThread::process);

// 绑定信号槽,当udpSendThread接收到数据后发送数据
//QObject::connect(udpSendThread, &UdpSendThread::dataReceived, udpSendThread, &UdpSendThread::sendData);

QObject::connect(udpSendThread, &UdpSendThread::frameCaptured, this, &MainWindow::updateCameraFrame);

QObject::connect(udpSendThread, &UdpSendThread::dataRec, [](const QByteArray &data) {
qDebug() << "Received data:" << data; }); bindThreadToCPU3(udpthread); // 启动线程 udpthread->start();

connect(cameraWorker, &CameraWorker::frameCompress, udpSendThread, &UdpSendThread::sendData);

}

MainWindow::~MainWindow() {
cameraThread->quit();
cameraThread->wait();
delete ui;
}

void MainWindow::updateCameraFrame(const QImage &image) {
ui->cameraLabel->setPixmap(QPixmap::fromImage(image)); // 假设你在 UI 中有一个 QLabel 名为 cameraLabel
}

void MainWindow::bindThreadToCPU3(QThread *thread) {
// 获取当前线程的原生线程句柄
pthread_t nativeThread = pthread_self(); // 使用 pthread_self() 获取当前线程的句柄

// 创建 CPU 亲和性掩码
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(3, &cpuset); // 绑定到 CPU3

// 设置线程 CPU 亲和性
if (pthread_setaffinity_np(nativeThread, sizeof(cpu_set_t), &cpuset) != 0) {
qDebug() << "无法设置线程的 CPU 亲和性"; } else { qDebug() << "线程成功绑定到 CPU3"; } } void MainWindow::debugslot(const QByteArray &data) { qDebug()<<"hello"; } --------------------------------tcpsend.cpp------------------------------------ #include "tcpsend.h" #include
#include
#include

TcpSend::TcpSend(QObject *parent) : QThread(parent), targetPort(0), tcpSocket(nullptr) {
tcpSocket = new QTcpSocket(this);
}

TcpSend::~TcpSend() {
if (tcpSocket->isOpen()) {
tcpSocket->close();
}
}

void TcpSend::setTargetIp(const QString &ip) {
targetIp = ip;
}

void TcpSend::setTargetPort(quint16 port) {
targetPort = port;
}

void TcpSend::run() {
// Bind thread to CPU3 (core 3)
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(3, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);

// Connect to TCP server
tcpSocket->connectToHost(QHostAddress(targetIp), targetPort);
if (!tcpSocket->waitForConnected(3000)) {
qDebug() << "Error: Unable to connect to server!"; return; } /* connect(this, &TcpSend::dataReceived, [this](const QByteArray &data) { if (tcpSocket->isOpen()) {
tcpSocket->write(data);
tcpSocket->flush();
qDebug() << "Data sent: " << data; } }); */ exec(); // Start the event loop for the thread } void TcpSend::sendData() { QByteArray data = "Hello from tcpsend"; // 要发送的数据 if (tcpSocket->isOpen()) {
tcpSocket->write(data);
tcpSocket->flush();
qDebug() << "tcp Data sent: " << data; } int cpu = sched_getcpu(); qDebug() << "Running on CPU: " << cpu ; } --------------------------------udpsendthread.cpp------------------------ // udpsendthread.cpp #include "udpsendthread.h" #include
#include
#include
#include
#include
#include “includes.h”
#include
#include
#include
#include

UdpSendThread::UdpSendThread(QObject *parent) : QObject(parent),
udpSocket(new QUdpSocket(this))
{
if (!udpSocket->bind(QHostAddress(LOCAL_IP), LOCAL_PORT))
{
qDebug() << "Bind failed!"; } else { qDebug() << "Bind successful!"; } qDebug()<<"start startReceiving"; connect(udpSocket, &QUdpSocket::readyRead, this, &UdpSendThread::processData); } UdpSendThread::~UdpSendThread() { udpSocket->close();
delete udpSocket;
}

void UdpSendThread::process()
{
#ifdef BASEPORT
// 模拟数据接收,可以使用 QTimer 定时发出 dataReceived 信号
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &UdpSendThread::dataReceived);
timer->start(2); // 每5ms触发一次 dataReceived 信号
#endif
}

void UdpSendThread::sendData(const QByteArray & data)
{
//QByteArray datas = “Hello from udpsend”; // 要发送的数据
//udpSocket->writeDatagram(data, QHostAddress(targetIP), targetPort);
//qDebug() << "Data sent to" << targetIP << ":" << targetPort; //int cpu = sched_getcpu(); //qDebug() << "Running on CPU: " << cpu ; const int maxPacketSize = 65500; // UDP 单个数据包的最大数据量 int dataSize = data.size(); int offset = 0; if (datasize_max < dataSize) { datasize_max = dataSize; qDebug()<< "mx = " <writeDatagram(packet.mid(bytesSent), QHostAddress(TARGET_IP), TARGET_PORT);
if (result == -1) {
qDebug() << "Failed to send data:" << udpSocket->errorString();
QThread::msleep(10); // 短暂等待后再重试,避免过多的 CPU 占用
continue;
}
bytesSent += result;
}

offset += packetSize; // 更新偏移量
QThread::msleep(10); // 短暂等待后再重试,避免过多的 CPU 占用
/*
int packetSize = qMin(maxPacketSize, dataSize – offset); // 每次发送的字节数
QByteArray packet = data.mid(offset, packetSize); // 获取分包数据

qint64 bytesSent = udpSocket->writeDatagram(packet, QHostAddress(TARGET_IP), TARGET_PORT);
offset += packetSize;

if (udpSocket->waitForBytesWritten(3000)) {
;
} else {
qDebug() << "Timeout or error while writing data."; } //QThread::msleep(2); // 限制帧率 */ } auto end = std::chrono::high_resolution_clock::now(); // 计算时间差 auto duration = std::chrono::duration_cast(end – start).count();

//qDebug()<< "发送耗时: " << duration << "us" ; } void UdpSendThread::processData() { QImage rcvimage ; QNetworkDatagram datagram ; while (udpSocket->hasPendingDatagrams())
{
times_rcv = 0;
flag_rcv = 1;
datagram = udpSocket->receiveDatagram();
picData.append(datagram.data());
}

/*
QByteArray lastTwoBytes ;
if (datagram.data().size()>=2)
{
lastTwoBytes = datagram.data().right(2);
if ((lastTwoBytes[0]==0xFF)&&(lastTwoBytes[1]==0xD9))
{
udpbagflag = 1;
}
}

if (udpbagflag!=0)
{
rcvimage = decompressImageFromMemory(picData);
emit frameCaptured(rcvimage);
picData.clear();
udpbagflag = 0;

}
*/
//int cpu = sched_getcpu();
//qDebug() << "Running on CPU: " << cpu ; } QImage UdpSendThread::decompressImageFromMemory(QByteArray &compressedData) { int i = 0; QBuffer buffer(&compressedData); buffer.open(QIODevice::ReadOnly); // 打开为只读模式 // 使用 QImageReader 从 QBuffer 中读取压缩的图像 QImageReader reader(&buffer); QImage image = reader.read(); if (image.isNull()) { qDebug() << "Failed to decompress the image."; } return image; } void UdpSendThread::dataReceived() { QImage rcvimage ; if (times_rcv < 60000) { times_rcv++; } if (times_rcv < 10) { return; } if (flag_rcv ==0) { return; } flag_rcv = 0; rcvimage = decompressImageFromMemory(picData); emit frameCaptured(rcvimage); picData.clear(); }

[Orangepi]配置wlan为AP模式

1.加载ko模块
sudo insmod wlanrtl.ko rtw_country_code=”CN” 或者 insmod wlanrtl.ko 并且 echo 0x3E > /proc/net/rtl88x2eu/wlx7822884b2786/chan_plan

2.确保hostapd文件夹是否存在,如不存在新建文件
sudo mkdir -p /var/run/hostapd

3.进入cd /usr/sbin

4.在/usr/sbin文件夹下新建1.config文件
————-1.config————–
interface=wlx7822884b2786
ctrl_interface=/var/run/hostapd
ssid=rtlwap
channel=36
wpa=2
wpa_passphrase=12345678
driver=nl80211
beacon_int=100
hw_mode=a
ieee80211n=1
wme_enabled=1
ht_capab=[SHORT-GI-20][SHORT-GI-40][HT40+]
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP

4.执行sudo ./hostapd 1.config -B

5.如无IP地址,sudo ifconfig wlx7822884b2786 192.168.16.1

[orangepi]移植8812EU驱动

内核中执行
sudo make mrproper # 清理源码树
sudo make menuconfig ARCH=arm64 CROSS_COMPILE=/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-
sudo make prepare ARCH=arm64 CROSS_COMPILE=/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu- # 准备编译环境,包括生成头文件
sudo make scripts ARCH=arm64 CROSS_COMPILE=/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu- # 生成 scripts,包括 genheaders 等工具
sudo make modules_prepare ARCH=arm64 CROSS_COMPILE=/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu- modules_prepare

驱动中执行
make ARCH=arm64 CROSS_COMPILE=/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-

————————–makefile添加————————————–

CONFIG_PLATFORM_RK3566 = y

ifeq ($(CONFIG_PLATFORM_RK3566), y)
EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -DCONFIG_RTW_TX_NPATH_EN

ARCH := arm64
CROSS_COMPILE :=/home/yue/sdk/orangepi-build/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
KSRC := /home/yue/sdk/orangepi-build/kernel/orange-pi-5.10-rk35xx
MODULE_NAME := wlanuav
endif

[Linux]创建server服务器并将数据存入log文件并只保留最后10000行

————————–baseport.c————————————-
#include
#include
#include
#include
#include
#include

#define PORT 8080 // 服务器端口
#define MAX_CLIENTS 5 // 最大连接数
#define BUFFER_SIZE 1024 // 数据缓冲区大小

int client_sockets[MAX_CLIENTS]; // 存储客户端套接字

// 结构体用于传递客户端套接字和地址信息
typedef struct {
int socket;
struct sockaddr_in address;
} client_info;

void *handle_client(void *arg) {
client_info *c_info = (client_info *)arg;
int client_socket = c_info->socket;
struct sockaddr_in client_address = c_info->address;
char buffer[BUFFER_SIZE];

// 获取并打印客户端IP地址
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_address.sin_addr, client_ip, sizeof(client_ip));
printf(“Client connected: %s\n”, client_ip);

while (1) {
memset(buffer, 0, BUFFER_SIZE);

int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
if (bytes_received <= 0) { printf("Client disconnected or error occurred.\n"); break; // 连接关闭 } printf("Received from %s: %s\n", client_ip, buffer); send(client_socket, buffer, bytes_received, 0); } close(client_socket); printf("Closed connection for socket %d (%s)\n", client_socket, client_ip); free(c_info); // 释放分配的内存 return NULL; } void manage_connections(int new_socket, struct sockaddr_in client_address) { int i; // 将变量声明移至循环外 // 关闭最早的连接 for (i = 0; i < MAX_CLIENTS; i++) { if (client_sockets[i] == 0) { // 找到空闲位置 client_sockets[i] = new_socket; return; } } // 如果达到最大连接数,关闭最早的连接 close(client_sockets[0]); // 将新的连接插入到数组中 for (i = 0; i < MAX_CLIENTS - 1; i++) { client_sockets[i] = client_sockets[i + 1]; } client_sockets[MAX_CLIENTS - 1] = new_socket; } int main() { int server_fd, new_socket; struct sockaddr_in address, client_address; int opt = 1; socklen_t addrlen = sizeof(client_address); // 初始化客户端套接字数组 memset(client_sockets, 0, sizeof(client_sockets)); // 创建套接字 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("Socket failed"); exit(EXIT_FAILURE); } // 绑定套接字 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror("Setsockopt failed"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); exit(EXIT_FAILURE); } // 开始监听 if (listen(server_fd, 3) < 0) { perror("Listen failed"); exit(EXIT_FAILURE); } printf("Server listening on port %d\n", PORT); while (1) { // 等待客户端连接 if ((new_socket = accept(server_fd, (struct sockaddr *)&client_address, &addrlen)) < 0) { perror("Accept failed"); exit(EXIT_FAILURE); } printf("New connection: socket fd is %d\n", new_socket); // 管理连接 manage_connections(new_socket, client_address); // 创建线程处理客户端 client_info *c_info = malloc(sizeof(client_info)); // 分配内存以存储客户端信息 c_info->socket = new_socket;
c_info->address = client_address;
pthread_t thread_id;
pthread_create(&thread_id, NULL, handle_client, (void *)c_info);
}

// 关闭服务器套接字
close(server_fd);
return 0;
}

—————————————–编译——————————————-
gcc -pthread -o baseport.o server.c

—————————在阿里云服务器运行、将结果打印到server.out文件,禁止缓存 执行—-
nohup stdbuf -oL ./baseport.o> baseport.log 2>&1 &

———————在/root/baseport/ 新建 baseport_last_10000_lines.sh —–并添加可执行属性—-

#!/bin/bash

# 设置日志文件路径
LOG_FILE=” /root/baseport/baseport.log”

# 仅保留最后 1000 行
tail -n 1000 “$LOG_FILE” > “$LOG_FILE.tmp” && mv “$LOG_FILE.tmp” “$LOG_FILE”

————————-执行—————————–
crontab -e

[Qt]串口通信 ,不使用movetothread

—————————.pro—————————-
QT += core gui serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# 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

HEADERS += \
mainwindow.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—————————–
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #include
#include

class SerialReceiver : public QObject {
Q_OBJECT

public:
SerialReceiver(QTextEdit *textEdit) : m_serialPort(new QSerialPort), m_textEdit(textEdit) {
// 设置串口设备 ttyUSB0
m_serialPort->setPortName(“/dev/ttyUSB0”);
m_serialPort->setBaudRate(QSerialPort::Baud115200);
m_serialPort->setDataBits(QSerialPort::Data8);
m_serialPort->setParity(QSerialPort::NoParity);
m_serialPort->setStopBits(QSerialPort::OneStop);
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);

connect(m_serialPort, &QSerialPort::readyRead, this, &SerialReceiver::readData);

if (m_serialPort->open(QIODevice::ReadWrite)) {
qDebug() << "Serial port opened."; } else { qDebug() << "Failed to open serial port."; } // 启动定时器,每隔 1 秒发送一次数据 m_timer = new QTimer(this); connect(m_timer, &QTimer::timeout, this, &SerialReceiver::sendData); m_timer->start(1000); // 1 秒间隔
}

public slots:
void readData() {
QByteArray data = m_serialPort->readAll();
// 将接收的数据展示到文本框中
m_textEdit->append(data);
}

void sendData() {
QByteArray dataToSend = “Hello, this is a periodic message!\n”;
qDebug() << "Sending data:" << dataToSend; m_serialPort->write(dataToSend);
}

private:
QSerialPort *m_serialPort;
QTextEdit *m_textEdit;
QTimer *m_timer; // 定时器
};

// 线程函数
void setThreadToCPU3() {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(3, &cpuset); // 将线程绑定到CPU3
pthread_t currentThread = pthread_self();
int result = pthread_setaffinity_np(currentThread, sizeof(cpu_set_t), &cpuset);
if (result != 0) {
qDebug() << "Error setting CPU affinity for thread:" << strerror(result); } else { qDebug() << "Thread is now running on CPU3."; } } class SerialThread : public QThread { public: SerialThread(QTextEdit *textEdit) : m_textEdit(textEdit) {} protected: void run() override { setThreadToCPU3(); // 设置线程在CPU3上运行 SerialReceiver receiver(m_textEdit); // 创建串口接收器 exec(); // 开始事件循环 } private: QTextEdit *m_textEdit; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; QVBoxLayout layout; QLabel label("Serial Data:"); QTextEdit textEdit; textEdit.setReadOnly(true); layout.addWidget(&label); layout.addWidget(&textEdit); window.setLayout(&layout); // 创建一个线程来接收串口数据 SerialThread serialThread(&textEdit); serialThread.start(); window.show(); // 在程序退出前确保线程安全结束 QObject::connect(&app, &QApplication::aboutToQuit, [&serialThread]() { serialThread.quit(); // 结束线程事件循环 serialThread.wait(); // 等待线程完全结束 }); return app.exec(); } #include "main.moc" ----------------------------mainwindow.cpp-------------------------- #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this);
}

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

————————–mainwindow.h——————————
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
Q_OBJECT

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

private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

[OrangePi]bootargs相关

1.修改bootargs
①修改u-boot
②修改dts文件的
chosen: chosen {
bootargs = “earlycon=uart8250,mmio32,0xfe660000 console=ttyFIQ0 isolcpus=3”;
};

2.隔离cpu,不让程序运行在CPU3上 isolcpus=3

3.查看bootargs cat /proc/cmdline

[Qt]显示摄像头-4 使用线程

————————.pro——————————-
QT += core gui
QT += core gui widgets # 确保 widgets 模块被包含

CONFIG += link_pkgconfig
PKGCONFIG += opencv4

QT += multimedia multimediawidgets

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# 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 += \
CameraWorker.cpp \
main.cpp \
mainwindow.cpp

HEADERS += \
CameraWorker.h \
mainwindow.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

——————————–CameraWorker.h—————————
#ifndef CAMERAWORKER_H
#define CAMERAWORKER_H

#include
#include
#include
#include
#include

class CameraWorker : public QObject {
Q_OBJECT

public:
CameraWorker(QObject *parent = nullptr);
~CameraWorker();
void startCamera(int deviceIndex);
void stopCamera();

signals:
void frameCaptured(const QImage &image);

private:
cv::VideoCapture capture;
QMutex mutex;
bool isRunning;
void process();
};

#endif // CAMERAWORKER_H

————————-CameraWorker.cpp———————————
#include “CameraWorker.h”
#include // 包含 QDebug 以使用 qDebug()
#include

CameraWorker::CameraWorker(QObject *parent) : QObject(parent), isRunning(false) {}

CameraWorker::~CameraWorker() {
stopCamera();
}

void CameraWorker::startCamera(int deviceIndex) {
if (capture.isOpened()) return;

capture.open(deviceIndex);
if (!capture.isOpened()) {
qDebug() << "无法打开摄像头"; // 这里可以正常使用 qDebug() return; } capture.set(cv::CAP_PROP_FRAME_WIDTH, 640); // 设置宽度 capture.set(cv::CAP_PROP_FRAME_HEIGHT, 480); // 设置高度 capture.set(cv::CAP_PROP_FPS, 15); // 设置帧率 capture.set(cv::CAP_PROP_EXPOSURE, -4); // 设置曝光(根据需要调整) capture.set(cv::CAP_PROP_GAIN, 0); // 设置增益(根据需要调整) QThread::msleep(100); // 暂停以让设置生效 isRunning = true; QThread *thread = QThread::create([this]() { process(); }); connect(thread, &QThread::finished, this, &CameraWorker::deleteLater); thread->start();
}

void CameraWorker::stopCamera() {
QMutexLocker locker(&mutex);
isRunning = false;
capture.release();
}

void CameraWorker::process() {
while (true) {
{
QMutexLocker locker(&mutex);
if (!isRunning) break;
}

cv::Mat frame;
capture >> frame;
if (frame.empty()) continue;

cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage image(frame.data, frame.cols, frame.rows, frame.step[0], QImage::Format_RGB888);
emit frameCaptured(image);
QThread::msleep(33); // 限制帧率
}
}

———————-mainwindow.h—————————————–
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include
#include
#include “CameraWorker.h” // 添加这一行以包含 CameraWorker
#include

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
Q_OBJECT

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

private slots:
void updateCameraFrame(const QImage &image);

private:
Ui::MainWindow *ui;
CameraWorker *cameraWorker; // 确保这个声明是正确的
QThread *cameraThread;
};

#endif // MAINWINDOW_H

——————————mainwindow.cpp————————-
#include “mainwindow.h”
#include “ui_mainwindow.h”

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

// 创建线程
cameraThread = new QThread;
cameraWorker->moveToThread(cameraThread);

connect(cameraThread, &QThread::started, [this]() {
cameraWorker->startCamera(0); // 打开默认摄像头
});
connect(cameraThread, &QThread::finished, cameraWorker, &CameraWorker::deleteLater);
connect(cameraWorker, &CameraWorker::frameCaptured, this, &MainWindow::updateCameraFrame);

cameraThread->start();
}

MainWindow::~MainWindow() {
cameraThread->quit();
cameraThread->wait();
delete ui;
}

void MainWindow::updateCameraFrame(const QImage &image) {
ui->cameraLabel->setPixmap(QPixmap::fromImage(image)); // 假设你在 UI 中有一个 QLabel 名为 cameraLabel
}

————————–main.cpp——————————
#include “mainwindow.h”
#include

int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

————————-.ui————————————-
添加名为 cameraLabel 的 QLabel 的控件

[Qt]显示USB摄像头3

————————.pro————————————-
QT += core gui
QT += core gui widgets # 确保 widgets 模块被包含

CONFIG += link_pkgconfig
PKGCONFIG += opencv4

QT += multimedia multimediawidgets

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# 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 += \
CameraWidget.cpp \
main.cpp \
mainwindow.cpp

HEADERS += \
CameraWidget.h \
mainwindow.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

———————-CameraWidget.h—————————-
#ifndef CAMERAWIDGET_H
#define CAMERAWIDGET_H

#include
#include
#include
#include

class CameraWidget : public QWidget {
Q_OBJECT

public:
explicit CameraWidget(QWidget *parent = nullptr);
~CameraWidget();

private slots:
void updateFrame();

private:
QLabel *label; // 用于显示摄像头画面
cv::VideoCapture capture; // OpenCV 摄像头捕获对象
};

#endif // CAMERAWIDGET_H

—————CameraWidget.cpp—————————————-
#include “CameraWidget.h”
#include
#include
#include
#include

CameraWidget::CameraWidget(QWidget *parent) : QWidget(parent) {
QVBoxLayout *layout = new QVBoxLayout(this);
label = new QLabel(this);
layout->addWidget(label);
setLayout(layout);

// 打开摄像头
if (!capture.open(0)) { // 0 为默认摄像头
label->setText(“无法打开摄像头”);
return;
}

// 设置摄像头分辨率和其他属性
capture.set(cv::CAP_PROP_FRAME_WIDTH, 640); // 设置宽度
capture.set(cv::CAP_PROP_FRAME_HEIGHT, 480); // 设置高度
capture.set(cv::CAP_PROP_FPS, 15); // 设置帧率
capture.set(cv::CAP_PROP_EXPOSURE, -4); // 设置曝光(根据需要调整)
capture.set(cv::CAP_PROP_GAIN, 0); // 设置增益(根据需要调整)
QThread::msleep(100); // 暂停以让设置生效

// 设置定时器定时更新摄像头画面
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &CameraWidget::updateFrame);
timer->start(33); // 每 33 毫秒更新一次(约 30 FPS)
}

CameraWidget::~CameraWidget() {
capture.release(); // 释放摄像头资源
}

void CameraWidget::updateFrame() {
cv::Mat frame;
capture >> frame; // 从摄像头获取一帧图像
if (frame.empty()) return;

// 转换为 RGB 格式并显示
cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage image(frame.data, frame.cols, frame.rows, frame.step[0], QImage::Format_RGB888);
label->setPixmap(QPixmap::fromImage(image));
}

—————————-mainwindow.h—————————–
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include
#include “CameraWidget.h”

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
Q_OBJECT

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

private:
Ui::MainWindow *ui;
CameraWidget *cameraWidget; // 摄像头小部件
};

#endif // MAINWINDOW_H

—————————-mainwindow.cpp—————————
#include “mainwindow.h”
#include “ui_mainwindow.h”
#include

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

// 创建并设置摄像头小部件
cameraWidget = new CameraWidget(this);

// 将摄像头小部件添加到布局
QWidget *cameraContainer = ui->cameraContainer; // 确保在 .ui 文件中设置了 cameraContainer
QVBoxLayout *layout = new QVBoxLayout(cameraContainer);
layout->addWidget(cameraWidget);
}

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

———————-main.cpp—————————————-
#include
#include “mainwindow.h”

int main(int argc, char *argv[]) {
QApplication app(argc, argv); // 创建 QApplication 对象

MainWindow mainWindow; // 创建主窗口对象
mainWindow.show(); // 显示主窗口

return app.exec(); // 进入应用程序主事件循环
}

————————-ui————————————
新建个名字为 cameraContainer 的QWidget控件