[orangepi]安装步骤

0.修改密码
sudo passwd root
sudo passwd orangepi

nmcli connection delete uuid XXXX

1.连接无线
sudo nmcli –ask dev wifi connect mini_5G password fsw2021fsw ifname wlan0

sudo nmcli –ask dev wifi connect TP-LINK_7787 password yyxlx18396870603 ifname wlan0

sudo nmcli –ask dev wifi connect mini_5G password fsw2021fsw ifname wlx7822884b2787

sudo nmcli –ask dev wifi connect rtlwap password mqdqxyg1qy ifname wlx7822884b2787
sudo nmcli dev wifi connect password ifname

2.安装ssh
sudo apt-get install openssh-server
3.安装vnc
sudo set_vnc.sh
连接VNC 端口号为5901
4.安装qt
sudo install_qt.sh

5.

[Linux]开机自运行脚本

sudo vi /usr/local/bin/load_module.sh

//skyport的
#!/bin/bash
sleep 1
insmod /home/orangepi/wlanuav.ko rtw_country_code=”CN”
sleep 1
sudo iw dev wlx7822884b2786 set type AP
sleep 2
nmcli dev set wlx7822884b2786 managed no
sleep 2
sudo /usr/sbin/hostapd /usr/sbin/1.config -B
sleep 2
sudo ifconfig wlx7822884b2786 192.168.16.1
sleep 2
sudo openvpn –config /home/orangepi/skyport.ovpn –daemon
sleep 2
echo “autorun init done”

//baseport的

#!/bin/bash
chmod 777 /dev/spidev3.0
sleep 1
insmod /home/orangepi/wlanuav.ko rtw_country_code=”CN”
#sleep 1
#sudo iw dev wlx7822884b2787 set type AP
#sleep 2
#nmcli dev set wlx7822884b2787 managed no
#sleep 2
#sudo /usr/sbin/hostapd /usr/sbin/1.config -B
#sleep 2
#sudo ifconfig wlx7822884b2787 192.168.16.7
sleep 1
sudo openvpn –config /home/orangepi/baseport.ovpn –daemon
sleep 1

sudo chmod +x /usr/local/bin/load_module.sh

sudo vi /etc/rc.local

在 exit 0 之前添加:
——————————–
/usr/local/bin/load_module.sh

while ! ip route | grep -q “default”; do
echo “Waiting for default gateway…”
sleep 1
done

echo “Default gateway is set.”

sudo ip route del default via 192.168.43.1 dev usb0
—————————————–
sudo chmod +x /etc/rc.local

[Qt]地图显示4-显示指向

———————pro——————————
QT += core gui location positioning
QT += quick widgets quickwidgets

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

DISTFILES += \
map.qml

RESOURCES += \
src.qrc \
src.qrc

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

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include
#include

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
Q_OBJECT

public:

bool isQmlView =false;

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

// 更新坐标的接口
void updateCoordinates(double latA, double lonA, double latB, double lonB);
private slots:
void on_zoomInButton_clicked();
void on_zoomOutButton_clicked();
void on_p2m_clicked();
void on_drawButton_clicked();

private:
Ui::MainWindow *ui;

QPointF center; // 圆心
double radius; // 圆半径
QPointF point1; // 经纬度点1对应的坐标
QPointF point2; // 经纬度点2对应的坐标
QPointF pointB; // 点 B 的圆周坐标
bool shouldDraw; // 是否绘制标志

void calculatePoints(double lat1, double lon1, double lat2, double lon2);
void calculatePointB(double latA, double lonA, double latB, double lonB);

private :
void zoomOut();
void zoomIn();

protected:
void paintEvent(QPaintEvent *event) override;

};

#endif // MAINWINDOW_H

—————–main.cpp————————–

#include “mainwindow.h”
#include
#include

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

// 更新坐标到新位置
// w.updateCoordinates(34.0522, -118.2437, 36.7783, -119.4179); // A: Los Angeles, B: Fresno

qDebug()<<"11"; return a.exec(); } ----------------mainwindow.cpp----------------------------- #include "mainwindow.h" #include "ui_mainwindow.h" #include
#include
#include
#include
#include
#include
#include

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

// 获取 QQuickWidget
QQuickWidget *quickWidget = ui->quickWidget;

// 设置 QML 文件路径
quickWidget->setSource(QUrl(QStringLiteral(“qrc:/map.qml”)));
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

// 获取 QML 上下文
QQmlContext *context = quickWidget->rootContext();

// 默认坐标
QVariant coordinateA = QVariant::fromValue(QGeoCoordinate(36.01, 37.32)); // San Francisco
QVariant coordinateB = QVariant::fromValue(QGeoCoordinate(36.50, 40.0)); // Oakland

// 传递默认坐标到 QML
context->setContextProperty(“coordinateA”, coordinateA);
context->setContextProperty(“coordinateB”, coordinateB);

// 连接按钮到槽函数
connect(ui->zoomInButton, &QPushButton::clicked, this, &MainWindow::on_zoomInButton_clicked);
connect(ui->zoomOutButton, &QPushButton::clicked, this, &MainWindow::on_zoomOutButton_clicked);

center = QPointF(600, 540);
radius = 50;

}

void MainWindow::updateCoordinates(double latA, double lonA, double latB, double lonB)
{
QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject(); // 修改为 QQuickItem*

if (rootObject) {
// 更新 QML 的属性
rootObject->setProperty(“coordinateA”, QVariant::fromValue(QGeoCoordinate(latA, lonA)));
rootObject->setProperty(“coordinateB”, QVariant::fromValue(QGeoCoordinate(latB, lonB)));
} else {
qWarning() << "Root object is null!"; } } // 放大地图 void MainWindow::zoomIn() { } // 缩小地图 void MainWindow::zoomOut() { } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_zoomInButton_clicked() { QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom + 1.0; // 增加 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
}
}

void MainWindow::on_zoomOutButton_clicked()
{

QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom – 1.0; // 减少 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
qDebug()<update();
}
}

void MainWindow::on_p2m_clicked()
{
isQmlView = !isQmlView;

if (isQmlView) {
ui->quickWidget->show();
ui->label->hide();
} else {
ui->quickWidget->hide();
ui->label->show();
//imageWidget->repaint();
}
}

void MainWindow::paintEvent(QPaintEvent *event) {
QMainWindow::paintEvent(event);

if (!shouldDraw) return; // 如果没有触发绘制,直接返回

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);

// 绘制圆
painter.setPen(Qt::black);
painter.drawEllipse(center, radius, radius);

// 绘制从圆心到点 B 的直线
painter.setPen(Qt::red); // 红色直线表示方向角
painter.drawLine(center, pointB);

qDebug() << "Drawn line from center to" << pointB; } void MainWindow::calculatePointB(double latA, double lonA, double latB, double lonB) { // 经纬度转弧度 double phi1 = qDegreesToRadians(latA); // 点 A 的纬度 double phi2 = qDegreesToRadians(latB); // 点 B 的纬度 double deltaLambda = qDegreesToRadians(lonB - lonA); // 经度差 // 计算方位角 (以弧度为单位) double theta = qAtan2( qSin(deltaLambda) * qCos(phi2), qCos(phi1) * qSin(phi2) - qSin(phi1) * qCos(phi2) * qCos(deltaLambda) ); // 转换为 [0, 2π] 范围 if (theta < 0) theta += 2 * M_PI; qDebug() << "Calculated angle (radians):" << theta; // 计算点 B 的圆周坐标 pointB.setX(center.x() + radius * qCos(theta)); pointB.setY(center.y() - radius * qSin(theta)); qDebug() << "Point B (on circle):" << pointB; } void MainWindow::on_drawButton_clicked() { // 示例经纬度 double latA = 30.0, lonA = 120.0; // 点 A 经纬度 double latB = 35.0, lonB = 125.0; // 点 B 经纬度 calculatePointB(latA, lonA, latB, lonB); shouldDraw = true; update(); // 触发重绘 } -----------------------------map.qml------------------------------- import QtQuick 2.15 import QtQuick.Controls 2.15 import QtLocation 5.15 import QtPositioning 5.15 Item { width: 800 height: 600 Plugin { id: mapPlugin name: "osm" // 使用 OpenStreetMap 插件 } // 坐标属性,可通过 C++ 更新 property var coordinateA: QtPositioning.coordinate(36.01, 116.11) property var coordinateB: QtPositioning.coordinate(37.0, 117.0) property real zoomLevelVal: 10 Map { anchors.fill: parent plugin: mapPlugin center: coordinateA // 默认以 A 为中心 zoomLevel: zoomLevelVal // 使用绑定的 zoomLevel 属性 // 显示从 A 到 B 的路径 MapPolyline { line.width: 1 line.color: "red" path: [coordinateA, coordinateB] } } }

[Qt]显示地图-3 切换地图和图片

——pro————————–
QT += core gui location positioning
QT += quick widgets quickwidgets

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

HEADERS += \
imagewidget.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

DISTFILES += \
map.qml

RESOURCES += \
src.qrc

———————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:

bool isQmlView =false;

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

// 更新坐标的接口
void updateCoordinates(double latA, double lonA, double latB, double lonB);
private slots:
void on_zoomInButton_clicked();
void on_zoomOutButton_clicked();
void on_p2m_clicked();
private:
Ui::MainWindow *ui;
private :
void zoomOut();
void zoomIn();
};

#endif // MAINWINDOW_H

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

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

// 更新坐标到新位置
// w.updateCoordinates(34.0522, -118.2437, 36.7783, -119.4179); // A: Los Angeles, B: Fresno

qDebug()<<"11"; return a.exec(); } ---------------------mainwindow.cpp------------------------------------- #include "mainwindow.h" #include "ui_mainwindow.h" #include "imagewidget.h" #include
#include
#include
#include
#include
#include

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

// 获取 QQuickWidget
QQuickWidget *quickWidget = ui->quickWidget;

// 设置 QML 文件路径
quickWidget->setSource(QUrl(QStringLiteral(“qrc:/map.qml”)));
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

// 获取 QML 上下文
QQmlContext *context = quickWidget->rootContext();

// 默认坐标
QVariant coordinateA = QVariant::fromValue(QGeoCoordinate(37.7749, -122.4194)); // San Francisco
QVariant coordinateB = QVariant::fromValue(QGeoCoordinate(37.8044, -122.2711)); // Oakland

// 传递默认坐标到 QML
context->setContextProperty(“coordinateA”, coordinateA);
context->setContextProperty(“coordinateB”, coordinateB);

// 连接按钮到槽函数
connect(ui->zoomInButton, &QPushButton::clicked, this, &MainWindow::on_zoomInButton_clicked);
connect(ui->zoomOutButton, &QPushButton::clicked, this, &MainWindow::on_zoomOutButton_clicked);

}

void MainWindow::updateCoordinates(double latA, double lonA, double latB, double lonB)
{
QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject(); // 修改为 QQuickItem*

if (rootObject) {
// 更新 QML 的属性
rootObject->setProperty(“coordinateA”, QVariant::fromValue(QGeoCoordinate(latA, lonA)));
rootObject->setProperty(“coordinateB”, QVariant::fromValue(QGeoCoordinate(latB, lonB)));
} else {
qWarning() << "Root object is null!"; } } // 放大地图 void MainWindow::zoomIn() { } // 缩小地图 void MainWindow::zoomOut() { } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_zoomInButton_clicked() { QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom + 1.0; // 增加 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
}
}

void MainWindow::on_zoomOutButton_clicked()
{

QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom – 1.0; // 减少 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
qDebug()<update();
}
}

void MainWindow::on_p2m_clicked()
{
isQmlView = !isQmlView;

if (isQmlView) {
ui->quickWidget->show();
ui->label->hide();
} else {
ui->quickWidget->hide();
ui->label->show();
//imageWidget->repaint();
}
}

———————-map.qml——————————
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15

Item {
width: 800
height: 600

Plugin {
id: mapPlugin
name: “osm” // 使用 OpenStreetMap 插件
}

// 坐标属性,可通过 C++ 更新
property var coordinateA: QtPositioning.coordinate(37.7749, -122.4194)
property var coordinateB: QtPositioning.coordinate(37.8044, -122.2711)
property real zoomLevelVal: 10

Map {
anchors.fill: parent
plugin: mapPlugin
center: coordinateA // 默认以 A 为中心
zoomLevel: zoomLevelVal // 使用绑定的 zoomLevel 属性

// 显示从 A 到 B 的路径
MapPolyline {
line.width: 1
line.color: “red”
path: [coordinateA, coordinateB]
}
}
}

[Qt]显示地图-2 将地图嵌入主窗口,可放大缩小

———————pro—————————–
QT += core gui location positioning
QT += quick widgets quickwidgets

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

DISTFILES += \
map.qml

RESOURCES += \
src.qrc

————————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();

// 更新坐标的接口
void updateCoordinates(double latA, double lonA, double latB, double lonB);

private slots:
void on_zoomInButton_clicked();

void on_zoomOutButton_clicked();

private:
Ui::MainWindow *ui;
private :
void zoomOut();
void zoomIn();
};

#endif // MAINWINDOW_H

——————————–main.cpp———————————

#include “mainwindow.h”
#include
#include

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

// 更新坐标到新位置
// w.updateCoordinates(34.0522, -118.2437, 36.7783, -119.4179); // A: Los Angeles, B: Fresno

qDebug()<<"11"; return a.exec(); } ---------------------------mainwindow.cpp--------------------------------------- #include "mainwindow.h" #include "ui_mainwindow.h" #include
#include
#include
#include
#include

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

// 获取 QQuickWidget
QQuickWidget *quickWidget = ui->quickWidget;

// 设置 QML 文件路径
quickWidget->setSource(QUrl(QStringLiteral(“qrc:/map.qml”)));
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

// 获取 QML 上下文
QQmlContext *context = quickWidget->rootContext();

// 默认坐标
QVariant coordinateA = QVariant::fromValue(QGeoCoordinate(37.7749, -122.4194)); // San Francisco
QVariant coordinateB = QVariant::fromValue(QGeoCoordinate(37.8044, -122.2711)); // Oakland

// 传递默认坐标到 QML
context->setContextProperty(“coordinateA”, coordinateA);
context->setContextProperty(“coordinateB”, coordinateB);

// 连接按钮到槽函数
connect(ui->zoomInButton, &QPushButton::clicked, this, &MainWindow::on_zoomInButton_clicked);
connect(ui->zoomOutButton, &QPushButton::clicked, this, &MainWindow::on_zoomOutButton_clicked);
}

void MainWindow::updateCoordinates(double latA, double lonA, double latB, double lonB)
{
QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject(); // 修改为 QQuickItem*

if (rootObject) {
// 更新 QML 的属性
rootObject->setProperty(“coordinateA”, QVariant::fromValue(QGeoCoordinate(latA, lonA)));
rootObject->setProperty(“coordinateB”, QVariant::fromValue(QGeoCoordinate(latB, lonB)));
} else {
qWarning() << "Root object is null!"; } } // 放大地图 void MainWindow::zoomIn() { } // 缩小地图 void MainWindow::zoomOut() { } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_zoomInButton_clicked() { qDebug()<<"2"; QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom + 1.0; // 增加 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
}
}

void MainWindow::on_zoomOutButton_clicked()
{

QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom – 1.0; // 减少 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
qDebug()<update();
}
}

———————————main.qml———————————-
#include “mainwindow.h”
#include “ui_mainwindow.h”
#include
#include
#include
#include
#include

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

// 获取 QQuickWidget
QQuickWidget *quickWidget = ui->quickWidget;

// 设置 QML 文件路径
quickWidget->setSource(QUrl(QStringLiteral(“qrc:/map.qml”)));
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

// 获取 QML 上下文
QQmlContext *context = quickWidget->rootContext();

// 默认坐标
QVariant coordinateA = QVariant::fromValue(QGeoCoordinate(37.7749, -122.4194)); // San Francisco
QVariant coordinateB = QVariant::fromValue(QGeoCoordinate(37.8044, -122.2711)); // Oakland

// 传递默认坐标到 QML
context->setContextProperty(“coordinateA”, coordinateA);
context->setContextProperty(“coordinateB”, coordinateB);

// 连接按钮到槽函数
connect(ui->zoomInButton, &QPushButton::clicked, this, &MainWindow::on_zoomInButton_clicked);
connect(ui->zoomOutButton, &QPushButton::clicked, this, &MainWindow::on_zoomOutButton_clicked);
}

void MainWindow::updateCoordinates(double latA, double lonA, double latB, double lonB)
{
QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject(); // 修改为 QQuickItem*

if (rootObject) {
// 更新 QML 的属性
rootObject->setProperty(“coordinateA”, QVariant::fromValue(QGeoCoordinate(latA, lonA)));
rootObject->setProperty(“coordinateB”, QVariant::fromValue(QGeoCoordinate(latB, lonB)));
} else {
qWarning() << "Root object is null!"; } } // 放大地图 void MainWindow::zoomIn() { } // 缩小地图 void MainWindow::zoomOut() { } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_zoomInButton_clicked() { qDebug()<<"2"; QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom + 1.0; // 增加 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
}
}

void MainWindow::on_zoomOutButton_clicked()
{

QQuickWidget *quickWidget = ui->quickWidget;
QQuickItem *rootObject = quickWidget->rootObject();

if (rootObject) {
double currentZoom = rootObject->property(“zoomLevelVal”).toDouble();
double newZoom = currentZoom – 1.0; // 减少 zoomLevel
rootObject->setProperty(“zoomLevelVal”, newZoom);
qDebug()<update();
}
}

[Qt]显示地图-1

—————–pro————————-
QT += core gui location positioning
QT += quick widgets quickwidgets

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

HEADERS += \
CoordinateUpdater.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

DISTFILES += \
main.qml

RESOURCES += \
res.qrc
————-CoordinateUpdater.h—————————-
#ifndef COORDINATEUPDATER_H
#define COORDINATEUPDATER_H

#include
#include

class CoordinateUpdater : public QObject {
Q_OBJECT
Q_PROPERTY(QGeoCoordinate coordinateA READ coordinateA WRITE setCoordinateA NOTIFY coordinateAChanged)
Q_PROPERTY(QGeoCoordinate coordinateB READ coordinateB WRITE setCoordinateB NOTIFY coordinateBChanged)

public:
explicit CoordinateUpdater(QObject *parent = nullptr);

QGeoCoordinate coordinateA() const;
QGeoCoordinate coordinateB() const;

void setCoordinateA(const QGeoCoordinate &coord);
void setCoordinateB(const QGeoCoordinate &coord);

signals:
void coordinateAChanged();
void coordinateBChanged();

private:
QGeoCoordinate m_coordinateA;
QGeoCoordinate m_coordinateB;
};

#endif // COORDINATEUPDATER_H

———————————-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

————————————CoordinateUpdater.cpp—————————-
#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
——————————————main.cpp————————————–
#include
#include
#include
#include
#include
#include
#include “CoordinateUpdater.h”

int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);

// 创建 C++ 坐标更新器
CoordinateUpdater coordinateUpdater;
coordinateUpdater.setCoordinateA(QGeoCoordinate(37.7749, -122.4194)); // 初始值 (旧金山)
coordinateUpdater.setCoordinateB(QGeoCoordinate(37.8044, -122.2711)); // 初始值 (奥克兰)

QQmlApplicationEngine engine;

// 将 C++ 对象暴露给 QML
engine.rootContext()->setContextProperty(“coordinateUpdater”, &coordinateUpdater);

// 加载 QML 文件
const QUrl url(QStringLiteral(“qrc:/main.qml”));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app,
[url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
},
Qt::QueuedConnection);
engine.load(url);

// 模拟外部更新坐标
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&coordinateUpdater]() {
double newLatA = (qrand() % 180) – 90.0; // 随机纬度
double newLonA = (qrand() % 360) – 180.0; // 随机经度
double newLatB = (qrand() % 180) – 90.0;
double newLonB = (qrand() % 360) – 180.0;

coordinateUpdater.setCoordinateA(QGeoCoordinate(newLatA, newLonA));
coordinateUpdater.setCoordinateB(QGeoCoordinate(newLatB, newLonB));
});
timer.start(2000); // 每 2 秒更新坐标

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;
}

——————————–main.qml————————————
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtLocation 5.15
import QtPositioning 5.15

ApplicationWindow {
visible: true
width: 640
height: 480

// QML 中的动态坐标绑定到 C++ 的属性
property var coordinateA: coordinateUpdater.coordinateA
property var coordinateB: coordinateUpdater.coordinateB

// 定义地图
Map {
anchors.fill: parent
plugin: Plugin {
name: “osm” // 使用 OpenStreetMap 插件
}
center: coordinateA // 设置地图中心为 A 坐标
zoomLevel: 12

// 绘制指向 B 坐标的箭头
MapQuickItem {
coordinate: coordinateA // A 坐标点
sourceItem: Image {
width: 30
height: 30
source: “qrc:/monkey.png” // 替换为您的箭头图片
rotation: Math.atan2(coordinateB.latitude – coordinateA.latitude,
coordinateB.longitude – coordinateA.longitude) * 180 / Math.PI
}
}

MapQuickItem {
coordinate: coordinateA // A 坐标点
sourceItem: Image {
width: 30
height: 30
source: “qrc:/monkey.png” // 替换为您的箭头图片
rotation: Math.atan2(-coordinateB.latitude + coordinateA.latitude,
-coordinateB.longitude + coordinateA.longitude) * 180 / Math.PI
}
}
}
/*
// 坐标更新时打印调试信息
Connections {
target: coordinateUpdater
onCoordinateAChanged: console.log(“Updated A:”, coordinateUpdater.coordinateA)
onCoordinateBChanged: console.log(“Updated B:”, coordinateUpdater.coordinateB)
}
*/
}

[阿里云]搭建openvpn服务器

1.安装openvpn
sudo yum install epel-release -y
sudo yum install openvpn easy-rsa -y

cd ~
git clone https://github.com/OpenVPN/easy-rsa.git

克隆完成后,检查 easy-rsa 文件夹是否已包含 easyrsa3 目录:
2.
mkdir -p ~/openvpn-ca
cp -r ~/easy-rsa/easyrsa3/* ~/openvpn-ca/

cd ~/openvpn-ca
./easyrsa init-pki

拷贝vars.example为vars

——————
set_var EASYRSA_REQ_COUNTRY “CN”
set_var EASYRSA_REQ_PROVINCE “ShanDong”
set_var EASYRSA_REQ_CITY “JiNan”
set_var EASYRSA_REQ_ORG “MyOrganization”
set_var EASYRSA_REQ_EMAIL “yue37152633@163.com”
set_var EASYRSA_REQ_OU “MyOrganizationalUnit”
————————-

./easyrsa init-pki
./easyrsa build-ca

输入密码(新)
输入用户名(新)

3.生成服务器密钥和证书。
./easyrsa gen-req server nopass
输入服务器名称(新)
./easyrsa sign-req server server
输入上次设置的密码(旧)
./easyrsa gen-dh

4.生成客户端密钥和证书。 该客户端的名称为client1
./easyrsa gen-req client1 nopass
./easyrsa sign-req client client1

5.生成 HMAC 密钥(用于增强服务器安全)。
openvpn –genkey –secret ta.key

6.将证书、密钥文件复制到 OpenVPN 目录。
sudo cp pki/ca.crt pki/issued/server.crt pki/private/server.key pki/dh.pem ta.key /etc/openvpn/

7.配置 OpenVPN 服务器
复制 OpenVPN 的示例配置文件。
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/

如果没有sample-config-files/server.conf文件
———-更改为—————
git clone https://github.com/OpenVPN/openvpn.git

cd openvpn/sample-config-files
sudo cp server.conf /etc/openvpn/

sudo cp ~/openvpn-ca/pki/ca.crt /etc/openvpn/
sudo cp ~/openvpn-ca/pki/issued/server.crt /etc/openvpn/
sudo cp ~/openvpn-ca/pki/private/server.key /etc/openvpn/
sudo cp ~/openvpn-ca/pki/dh.pem /etc/openvpn/
sudo cp ~/openvpn-ca/ta.key /etc/openvpn/

8.编辑 /etc/openvpn/server.conf 文件,根据需求调整配置。
sudo nano /etc/openvpn/server.conf
将以下几行修改为生成的证书、密钥路径:
ca /etc/openvpn/ca.crt
cert /etc/openvpn/server.crt
key /etc/openvpn/server.key
dh /etc/openvpn/dh.pem
tls-auth /etc/openvpn/ta.key 0
//
设置 VPN 子网地址(默认为 10.8.0.0/24,可以按需求更改):
server 10.8.0.0 255.255.255.0
//
启用客户端与服务端的互通及客户端之间的通信:
push “redirect-gateway def1 bypass-dhcp”
push “dhcp-option DNS 8.8.8.8”
保存并退出编辑器。

9. 重启 OpenVPN 服务器以应用更改

完成配置后,重启 OpenVPN 服务以确保更改生效:
sudo systemctl restart openvpn@server

10.验证配置

使用以下命令查看 OpenVPN 是否正常运行
sudo systemctl status openvpn@server

11.启用 IP 转发
编辑 /etc/sysctl.conf 文件,找到或添加以下行,启用 IP 转发:
net.ipv4.ip_forward = 1

应用该更改:
sudo sysctl -p

12.配置防火墙

在阿里云控制台 安全组 中允许 UDP 1194 端口流量。您还可以使用以下命令设置防火墙规则:
CentOS (firewalld)

sudo firewall-cmd –permanent –add-port=1194/udp
sudo firewall-cmd –permanent –add-masquerade
sudo firewall-cmd –reload

并且在阿里云安全组添加1194 UDP接口

13.启动 OpenVPN 服务器
sudo systemctl start openvpn@server
sudo systemctl enable openvpn@server

14.创建客户端文件

client1.ovpn

————————
client
dev tun
proto udp
remote IP地址 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
#使用enx020c29a39b6d进行转发,不影响别的网卡
#route 10.8.0.0 255.255.255.0 enx020c29a39b6d
route-nopull
tls-auth ta.key 1
# OpenVPN 加密配置
#data-ciphers AES-256-GCM:AES-128-GCM
#data-ciphers-fallback AES-256-CBC
#data-ciphers-fallback BF-CBC
#comp-lzo no
#auth SHA256
verb 4


—–BEGIN CERTIFICATE—–
#写入CA文件
—–END CERTIFICATE—–


—–BEGIN CERTIFICATE—–
#写入CERT文件
—–END CERTIFICATE—–


—–BEGIN PRIVATE KEY—–
#写入KEY文件
—–END PRIVATE KEY—–


—–BEGIN OpenVPN Static key V1—–
#写入TLS文件
—–END OpenVPN Static key V1—–

//再次创建客户端
cd ~/openvpn-ca
./easyrsa gen-req pc nopass
./easyrsa sign-req client pc

//sh文件破解密码,在~/openvpn-ca创建sh文件,+x权限

#!/bin/bash

PASSWORDS=(“” “1234” “password”)

for pass in “${PASSWORDS[@]}”; do

echo “尝试密码: ‘$pass'”

openssl rsa -in pki/private/ca.key -out /dev/null -passin pass:”$pass” 2>/dev/null

if [ $? -eq 0 ]; then

echo “✅ 找到密码: ‘$pass'”
exit 0

fi

done

echo “❌ 未找到正确密码”

[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(); }