[Qt]姿态显示仪

——————pro————————
QT += core gui

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

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

———————-AttitudeDisplay.h————————-
#ifndef ATTITUDEDISPLAY_H
#define ATTITUDEDISPLAY_H

#include

class AttitudeDisplay : public QWidget {
Q_OBJECT
public:
explicit AttitudeDisplay(QWidget *parent = nullptr);

void setAttitude(double roll, double pitch, double yaw);

protected:
void paintEvent(QPaintEvent *event) override;

private:
double m_roll; // 滚转角 (Roll)
double m_pitch; // 俯仰角 (Pitch)
double m_yaw; // 偏航角 (Yaw)
};

#endif // ATTITUDEDISPLAY_H

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

#include
#include “AttitudeDisplay.h”

class MainWindow : public QMainWindow {
Q_OBJECT

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

private:
AttitudeDisplay *attitudeDisplay;
};

#endif // MAINWINDOW_H

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

AttitudeDisplay::AttitudeDisplay(QWidget *parent)
: QWidget(parent), m_roll(0), m_pitch(0), m_yaw(0) {
setMinimumSize(300, 300); // 设置最小尺寸
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 允许自动调整大小
}

void AttitudeDisplay::setAttitude(double roll, double pitch, double yaw) {
m_roll = roll;
m_pitch = pitch;
m_yaw = yaw;
update(); // 触发重绘
}

void AttitudeDisplay::paintEvent(QPaintEvent *event) {
Q_UNUSED(event);

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

int centerX = width() / 2;
int centerY = height() / 2;
int radius = qMin(width(), height()) / 2 – 10;

// 绘制圆形背景
painter.setBrush(QColor(30, 30, 30));
painter.setPen(Qt::NoPen);
painter.drawEllipse(centerX – radius, centerY – radius, radius * 2, radius * 2);

// 绘制天空和地面(改为圆形分段显示)
painter.save();
painter.translate(centerX, centerY); // 移动坐标系统到圆心
painter.rotate(-m_roll); // 根据滚转角旋转地平线

// 绘制天空部分(上半圆)
painter.setBrush(QColor(100, 150, 255)); // 天空蓝
painter.setPen(Qt::NoPen);
painter.drawPie(-radius, -radius, radius * 2, radius * 2, 90 * 16, 180 * 16); // 绘制上半圆

// 绘制地面部分(下半圆)
painter.setBrush(QColor(180, 100, 50)); // 地面棕
painter.setPen(Qt::NoPen);
painter.drawPie(-radius, -radius, radius * 2, radius * 2, -90 * 16, 180 * 16); // 绘制下半圆

painter.restore();

// 绘制俯仰线
painter.setPen(QPen(Qt::white, 2));
int pitchOffset = static_cast(m_pitch * radius / 90.0);
painter.drawLine(centerX – radius, centerY + pitchOffset, centerX + radius, centerY + pitchOffset);

// 绘制刻度
for (int i = -90; i <= 90; i += 15) { int offset = static_cast(i * radius / 90.0);
painter.drawLine(centerX – radius / 4, centerY + offset, centerX + radius / 4, centerY + offset);
if (i != 0) {
painter.drawText(QPointF(centerX + radius / 4 + 5, centerY + offset + 5), QString::number(i));
}
}

// 绘制指针
painter.setPen(QPen(Qt::yellow, 2));
painter.drawLine(centerX, centerY – radius, centerX, centerY + radius);

// 绘制中心指针
painter.setBrush(Qt::red);
painter.setPen(Qt::NoPen);
painter.drawEllipse(QPointF(centerX, centerY), 5, 5);

// 绘制仪表盘外圈
painter.setPen(QPen(Qt::white, 2));
painter.setBrush(Qt::NoBrush);
painter.drawEllipse(centerX – radius, centerY – radius, radius * 2, radius * 2);

// 绘制文字信息
painter.setPen(Qt::black);
painter.setFont(QFont(“Arial”, 12, QFont::Bold));
QString text = QString(“Roll: %1°\nPitch: %2°\nYaw: %3°”)
.arg(m_roll, 0, ‘f’, 1)
.arg(m_pitch, 0, ‘f’, 1)
.arg(m_yaw, 0, ‘f’, 1);
painter.drawText(centerX – radius + 15, centerY + radius + 0, text);
}
—————————main.cpp—————————
#include “mainwindow.h”
#include

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

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

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), attitudeDisplay(new AttitudeDisplay(this)) {
setWindowTitle(“圆形姿态仪”);
setMinimumSize(400, 400);

// 设置布局,将仪表盘放在中央
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
QVBoxLayout *layout = new QVBoxLayout(centralWidget);
layout->addWidget(attitudeDisplay);
layout->setAlignment(attitudeDisplay, Qt::AlignCenter);

// 模拟姿态数据更新
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, [this]() {
static double roll = 0, pitch = 0, yaw = 0;
roll += 1.0;
pitch += 0.5;
yaw += 0.3;

if (roll > 180) roll = -180;
if (pitch > 90) pitch = -90;
if (yaw > 360) yaw -= 360;

attitudeDisplay->setAttitude(roll, pitch, yaw);
});
timer->start(50); // 每 50 毫秒更新一次
}

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

[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/