Upload files to 'src/unitdev01/unitdev01'

ken910606 1 year ago
parent 72a59b1a3a
commit 945d79a6fa

@ -3,11 +3,14 @@ import rclpy
from rclpy.node import Node
from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
QWidget, QLabel, QSplitter, QScrollArea,
QSizePolicy)
from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSignal
QSizePolicy, QApplication)
from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSignal, QUrl
from PyQt6.QtGui import QColor
from PyQt6.QtWebEngineWidgets import QWebEngineView
import math
import re
import os
import sys
from threading import Lock
from geometry_msgs.msg import Point, Vector3
from sensor_msgs.msg import BatteryState, NavSatFix, Imu
@ -138,8 +141,8 @@ class DroneMonitor(Node):
def gps_callback(self, drone_id, msg):
self.signals.update_signal.emit('gps', drone_id, {
'lat': msg.latitude,
'lon': msg.longitude,
'alt': msg.altitude
'lon': msg.longitude
,'alt': msg.altitude
})
def local_vel_callback(self, drone_id, msg):
@ -150,7 +153,9 @@ class DroneMonitor(Node):
})
def altitude_callback(self, drone_id, msg):
self.signals.update_signal.emit('altitude', drone_id, msg.data)
self.signals.update_signal.emit('altitude', drone_id, {
'altitude': msg.data
})
def local_pose_callback(self, drone_id, msg):
self.signals.update_signal.emit('local_pose', drone_id, {
@ -212,26 +217,43 @@ class ControlStationUI(QMainWindow):
left_layout.addWidget(scroll_area)
# 右侧地图区域
self.map_widget = QLabel()
self.map_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.map_widget.setStyleSheet("""
QLabel {
background-color: #1A1A1A;
color: #AAAAAA;
font-size: 18px;
border: 2px solid #333;
border-radius: 10px;
padding: 20px;
self.map_view = QWebEngineView()
inline_html = '''
<!DOCTYPE html>
<html><head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<style>html,body,#map{height:100%;margin:0}</style>
</head><body>
<div id="map"></div>
<script>
var map = L.map('map').setView([0,0],2);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{maxZoom:19}).addTo(map);
var markers = {};
function updateDrone(lat,lon,id){
if(markers[id]) markers[id].setLatLng([lat,lon]);
else markers[id]=L.marker([lat,lon]).addTo(map).bindPopup(id);
}
""")
self.update_map_display("等待GPS數據...")
</script>
</body></html>
'''
self.map_view.setHtml(inline_html)
self.map_view.loadFinished.connect(self.on_map_loaded)
main_splitter.addWidget(left_panel)
main_splitter.addWidget(self.map_widget)
main_splitter.addWidget(self.map_view)
main_splitter.setSizes([400, 1000])
self.setCentralWidget(main_splitter)
def on_map_loaded(self, ok: bool):
if ok:
self.map_loaded = True
else:
print("⚠️ 地图页加载失败")
def create_drone_panel(self, drone_id):
panel = QWidget()
panel.setObjectName(f"panel_{drone_id}")
@ -280,11 +302,11 @@ class ControlStationUI(QMainWindow):
# 数据字段(带标签)
self.create_data_row(layout, "模式:", f"{drone_id}_mode", "--")
self.create_data_row(layout, "電壓:", f"{drone_id}_battery", "-- V")
self.create_data_row(layout, "GPS:", f"{drone_id}_gps", "等待定位...")
self.create_data_row(layout, "Local:", f"{drone_id}_local", "X: -- Y: -- Z: --")
self.create_data_row(layout, "速度:", f"{drone_id}_velocity", "VX: -- VY: -- VZ: --")
self.create_data_row(layout, "姿態:", f"{drone_id}_attitude", "Roll: -- Pitch: -- Yaw: --")
self.create_data_row(layout, "電壓:", f"{drone_id}_battery", "--")
self.create_data_row(layout, "GPS:", f"{drone_id}_gps", "--")
self.create_data_row(layout, "高度:", f"{drone_id}_altitude", "--")
self.create_data_row(layout, "Local:", f"{drone_id}_local", "--")
self.create_data_row(layout, "HUD:", f"{drone_id}_hud", "--")
return panel
@ -317,7 +339,7 @@ class ControlStationUI(QMainWindow):
return
if msg_type == 'mode':
self.update_field(panel, drone_id, 'mode', f"模式: {data}",
self.update_field(panel, drone_id, 'mode', f"{data}",
'#FF5555' if '返航' in data else '#55FF55')
elif msg_type == 'battery':
@ -327,18 +349,26 @@ class ControlStationUI(QMainWindow):
'#FF6464' if voltage < 12 else '#FFFFFF')
elif msg_type == 'gps':
text = (f"緯度: {data['lat']:.6f}\n"
f"經度: {data['lon']:.6f}\n"
f"高度: {data['alt']:.1f} m")
text = (f"緯度: {data['lat']:.6f}°\n"
f"經度: {data['lon']:.6f}°")
self.update_field(panel, drone_id, 'gps', text)
self.update_map_display(f"Drone {drone_id}\n{text}")
if self.on_map_loaded:
js = f"updateDrone({data['lat']}, {data['lon']:.6f}, {drone_id})"
self.map_view.page().runJavaScript(js)
elif msg_type == 'altitude':
text = (f"{data['altitude']:.1f} m")
self.update_field(panel, drone_id, 'altitude', text)
elif msg_type == 'local_pose':
text = (f"X: {data['x']:.1f} m\n"
f"Y: {data['y']:.1f} m\n"
f"Z: {data['z']:.1f} m")
text = (f"({data['x']:.1f}, {data['y']:.1f}, {data['z']:.1f})")
self.update_field(panel, drone_id, 'local', text)
elif msg_type == 'hud':
text = (f"地速: {data['groundspeed']:.1f} m/s\n"
f"航向: {data['heading']:.1f}°")
self.update_field(panel, drone_id, 'hud', text)
'''
elif msg_type == 'velocity':
text = (f"VX: {data['vx']:.1f} m/s\n"
f"VY: {data['vy']:.1f} m/s\n"
@ -350,13 +380,7 @@ class ControlStationUI(QMainWindow):
f"Pitch: {data['pitch']:.1f}°\n"
f"Yaw: {data['yaw']:.1f}°")
self.update_field(panel, drone_id, 'attitude', text)
elif msg_type == 'hud':
text = (f"空速: {data['airspeed']:.1f} m/s\n"
f"地速: {data['groundspeed']:.1f} m/s\n"
f"航向: {data['heading']:.1f}°")
self.update_field(panel, drone_id, 'hud', text)
'''
def update_field(self, panel, drone_id, field, text, color=None):
if label := panel.findChild(QLabel, f"{drone_id}_{field}"):
label.setText(text)
@ -369,10 +393,6 @@ class ControlStationUI(QMainWindow):
self.info_layout.addWidget(panel)
self.drones[drone_id] = panel
def update_map_display(self, text):
self.map_widget.setText(text)
self.map_widget.repaint()
def spin_ros(self):
try:
self.executor.spin_once(timeout_sec=0)
@ -386,7 +406,7 @@ class ControlStationUI(QMainWindow):
event.accept()
if __name__ == '__main__':
app = QApplication([])
app = QApplication(sys.argv)
station = ControlStationUI()
station.show()
app.exec()
app.exec(app.exec())
Loading…
Cancel
Save