feat(mission): virtual-leader path following + 固定領隊 + barrier
- mission_planner: Leader-Follower 改用 arc-length 參數化(virtual leader),_build_center_path 以同心圓弧連接直線段,銳角退化成 hover 單點並在該點放 rendezvous barrier,避免暴衝與編隊交叉 - mission_planner: rank 改以輸入順序為準,不再對投影排序,避免浮點噪音 導致 run-to-run leader 漂移 - mission_group / gui: 新增 leader_drone_id 與「領隊」下拉選單,handle_ route_confirmed 把指定領隊重排到 rank 0,整個縱隊順序固定如軍隊行進 - mission_executor: rendezvous barrier 釋放邏輯、fallback LOITER、send retry;加 barrier_timeout 保護 - command_sender / communication / navigation: 配合 setpoint 送達與 Ros2 bridge 更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,7 @@ class MissionGroup:
|
||||
self.planned_waypoints = None # 規劃結果 dict
|
||||
self.executor = None # MissionExecutor 實例(延遲建立)
|
||||
self.center_origin = None # 規劃原點
|
||||
self.leader_drone_id = None # LEADER_FOLLOWER 專用:指定的領隊無人機 ID
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
@@ -415,6 +416,21 @@ class GroupPanel(QWidget):
|
||||
self._param_widgets[key] = (row_w, inp)
|
||||
self._param_rows.append(row_w)
|
||||
|
||||
# LEADER_FOLLOWER 專用:領隊下拉選單
|
||||
self._leader_row = QWidget()
|
||||
leader_layout = QHBoxLayout(self._leader_row)
|
||||
leader_layout.setContentsMargins(0, 0, 0, 0)
|
||||
leader_layout.setSpacing(3)
|
||||
leader_lbl = QLabel("領隊")
|
||||
leader_lbl.setStyleSheet(LBL)
|
||||
self._leader_combo = QComboBox()
|
||||
self._leader_combo.setStyleSheet(COMBO)
|
||||
self._leader_combo.setFixedWidth(70)
|
||||
self._leader_combo.currentTextChanged.connect(self._on_leader_changed)
|
||||
leader_layout.addWidget(leader_lbl, 1)
|
||||
leader_layout.addWidget(self._leader_combo)
|
||||
param_col.addWidget(self._leader_row)
|
||||
|
||||
param_col.addStretch()
|
||||
|
||||
# 初始顯示對應的參數
|
||||
@@ -447,6 +463,27 @@ class GroupPanel(QWidget):
|
||||
self.drone_list_label.setText("、".join(sorted_ids))
|
||||
self.drone_list_label.setStyleSheet(
|
||||
f"color: {self.group.color}; font-size: 11px; font-weight: bold;")
|
||||
self._refresh_leader_options()
|
||||
|
||||
def _refresh_leader_options(self):
|
||||
"""依目前群組成員重新填充領隊下拉選單,保留目前選擇若仍有效"""
|
||||
sorted_ids = sorted(self.group.drone_ids,
|
||||
key=lambda x: (x.split('_')[0], int(x.split('_')[1])))
|
||||
current = self.group.leader_drone_id
|
||||
self._leader_combo.blockSignals(True)
|
||||
self._leader_combo.clear()
|
||||
self._leader_combo.addItems(sorted_ids)
|
||||
if current and current in sorted_ids:
|
||||
self._leader_combo.setCurrentText(current)
|
||||
elif sorted_ids:
|
||||
self._leader_combo.setCurrentText(sorted_ids[0])
|
||||
self.group.leader_drone_id = sorted_ids[0]
|
||||
else:
|
||||
self.group.leader_drone_id = None
|
||||
self._leader_combo.blockSignals(False)
|
||||
|
||||
def _on_leader_changed(self, drone_id):
|
||||
self.group.leader_drone_id = drone_id if drone_id else None
|
||||
|
||||
def update_status(self):
|
||||
"""更新任務狀態顯示"""
|
||||
@@ -485,6 +522,7 @@ class GroupPanel(QWidget):
|
||||
visible_keys = {d[0] for d in self._param_defs.get(mission_type, [])}
|
||||
for key, (row_w, _inp) in self._param_widgets.items():
|
||||
row_w.setVisible(key in visible_keys)
|
||||
self._leader_row.setVisible(mission_type == 'LEADER_FOLLOWER')
|
||||
|
||||
def get_mission_params(self):
|
||||
"""讀取當前顯示的參數值,回傳 dict"""
|
||||
|
||||
Reference in New Issue
Block a user