|
|
|
|
@ -62,6 +62,13 @@ except ImportError as e:
|
|
|
|
|
_log("ERROR", f"錯誤: {e}")
|
|
|
|
|
AttitudeRaw = None
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
from fc_interfaces.msg import GnssRaw
|
|
|
|
|
except ImportError as e:
|
|
|
|
|
_log("WARN", "無法導入 GnssRaw")
|
|
|
|
|
_log("ERROR", f"錯誤: {e}")
|
|
|
|
|
GnssRaw = None
|
|
|
|
|
|
|
|
|
|
class DroneSignals(QObject):
|
|
|
|
|
update_signal = pyqtSignal(str, str, object) # (msg_type, drone_id, data)
|
|
|
|
|
|
|
|
|
|
@ -792,8 +799,21 @@ class DroneMonitor(Node):
|
|
|
|
|
if not hasattr(self, subs_attr):
|
|
|
|
|
self.setup_drone(sys_id)
|
|
|
|
|
else:
|
|
|
|
|
# 檢查既有訂閱是否包含 position_ned / attitude,如果不包含就添加(兼容舊訂閱)
|
|
|
|
|
# 檢查既有訂閱是否包含 position_gnss / position_ned / attitude,如果不包含就添加(兼容舊訂閱)
|
|
|
|
|
subs = getattr(self, subs_attr, {})
|
|
|
|
|
if isinstance(subs, dict) and 'position_gnss' not in subs and GnssRaw is not None:
|
|
|
|
|
base_topic = f'/fc_network/vehicle/{sys_id}'
|
|
|
|
|
try:
|
|
|
|
|
position_gnss_sub = self.create_subscription(
|
|
|
|
|
GnssRaw,
|
|
|
|
|
f'{base_topic}/position_gnss',
|
|
|
|
|
lambda msg, sid=sys_id: self.gps_callback(sid, msg),
|
|
|
|
|
10
|
|
|
|
|
)
|
|
|
|
|
subs['position_gnss'] = position_gnss_sub
|
|
|
|
|
setattr(self, subs_attr, subs)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
if isinstance(subs, dict) and 'position_ned' not in subs:
|
|
|
|
|
base_topic = f'/fc_network/vehicle/{sys_id}'
|
|
|
|
|
try:
|
|
|
|
|
@ -849,12 +869,6 @@ class DroneMonitor(Node):
|
|
|
|
|
lambda msg, sid=sys_id: self.battery_callback(sid, msg),
|
|
|
|
|
10
|
|
|
|
|
),
|
|
|
|
|
'position': self.create_subscription(
|
|
|
|
|
NavSatFix,
|
|
|
|
|
f'{base_topic}/position',
|
|
|
|
|
lambda msg, sid=sys_id: self.gps_callback(sid, msg),
|
|
|
|
|
10
|
|
|
|
|
),
|
|
|
|
|
'summary': self.create_subscription(
|
|
|
|
|
String,
|
|
|
|
|
f'{base_topic}/summary',
|
|
|
|
|
@ -875,6 +889,21 @@ class DroneMonitor(Node):
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if GnssRaw is not None:
|
|
|
|
|
subs['position_gnss'] = self.create_subscription(
|
|
|
|
|
GnssRaw,
|
|
|
|
|
f'{base_topic}/position_gnss',
|
|
|
|
|
lambda msg, sid=sys_id: self.gps_callback(sid, msg),
|
|
|
|
|
10
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
subs['position'] = self.create_subscription(
|
|
|
|
|
NavSatFix,
|
|
|
|
|
f'{base_topic}/position',
|
|
|
|
|
lambda msg, sid=sys_id: self.gps_callback(sid, msg),
|
|
|
|
|
10
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if AttitudeRaw is not None:
|
|
|
|
|
subs['attitude'] = self.create_subscription(
|
|
|
|
|
AttitudeRaw,
|
|
|
|
|
@ -1177,21 +1206,28 @@ class DroneMonitor(Node):
|
|
|
|
|
# 如果還沒有從 summary 獲取到映射,則不處理
|
|
|
|
|
if actual_drone_id is None:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.latest_data[(actual_drone_id, 'gps')] = {
|
|
|
|
|
|
|
|
|
|
gps_data = {
|
|
|
|
|
'lat': msg.latitude,
|
|
|
|
|
'lon': msg.longitude,
|
|
|
|
|
'alt': msg.altitude
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hasattr(msg, 'fix_type'):
|
|
|
|
|
gps_data['fix_type'] = msg.fix_type
|
|
|
|
|
if hasattr(msg, 'satellites_visible'):
|
|
|
|
|
gps_data['satellites_visible'] = msg.satellites_visible
|
|
|
|
|
if hasattr(msg, 'eph'):
|
|
|
|
|
gps_data['eph'] = msg.eph
|
|
|
|
|
if hasattr(msg, 'epv'):
|
|
|
|
|
gps_data['epv'] = msg.epv
|
|
|
|
|
|
|
|
|
|
self.latest_data[(actual_drone_id, 'gps')] = gps_data
|
|
|
|
|
|
|
|
|
|
# ================================================================================
|
|
|
|
|
# 【新增】儲存 GPS 資料到 drone_gps 字典
|
|
|
|
|
# ================================================================================
|
|
|
|
|
self.drone_gps[actual_drone_id] = {
|
|
|
|
|
'lat': msg.latitude,
|
|
|
|
|
'lon': msg.longitude,
|
|
|
|
|
'alt': msg.altitude
|
|
|
|
|
}
|
|
|
|
|
self.drone_gps[actual_drone_id] = gps_data.copy()
|
|
|
|
|
# ================================================================================
|
|
|
|
|
|
|
|
|
|
def local_vel_callback(self, drone_id, msg):
|
|
|
|
|
|