base_agent/uas/uas_control/command.py

281 lines
13 KiB
Python
Raw Normal View History

2026-06-18 03:28:14 +00:00
# -*- coding: utf-8 -*-
"""
无人系统控制指令模型
Command 指令基类dataclass
CommandResult 指令执行结果
CommandType 指令类型枚举覆盖无人机/机器狗/通用
CommandStatus 指令状态枚举
"""
from __future__ import annotations
import dataclasses
import time
import uuid
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Dict
# ─────────────────────────────────────────────────────────────────
# 指令类型枚举
# ─────────────────────────────────────────────────────────────────
class CommandType(Enum):
# ── 通用指令 ──────────────────────────────────────────────────
ARM = "arm" # 解锁/上电
DISARM = "disarm" # 加锁/断电
START = "start" # 启动
STOP = "stop" # 停止
PAUSE = "pause" # 暂停
RESUME = "resume" # 恢复
RESET = "reset" # 重置
EMERGENCY_STOP = "emergency_stop" # 紧急停止
SET_MODE = "set_mode" # 设置飞行/运动模式
HEARTBEAT = "heartbeat" # 心跳保活
# ── 运动指令 ──────────────────────────────────────────────────
TAKEOFF = "takeoff" # 起飞(无人机)
LAND = "land" # 降落(无人机)
RTL = "rtl" # 返回起飞点
GOTO = "goto" # 飞往/走往目标点
SET_VELOCITY = "set_velocity" # 设置速度向量
SET_HEADING = "set_heading" # 设置航向
SET_ALTITUDE = "set_altitude" # 设置目标高度
FOLLOW_ROUTE = "follow_route" # 执行预设航线
LOITER = "loiter" # 盘旋/原地待命
# ── 载荷指令 ──────────────────────────────────────────────────
PAYLOAD_ON = "payload_on" # 载荷上电
PAYLOAD_OFF = "payload_off" # 载荷断电
CAMERA_SHOOT = "camera_shoot" # 拍照
CAMERA_RECORD = "camera_record" # 录像开关
GIMBAL_CONTROL = "gimbal_control" # 云台控制
# ── 机器狗专有 ────────────────────────────────────────────────
SIT = "sit" # 坐下
STAND = "stand" # 站立
WALK = "walk" # 行走
TROT = "trot" # 小跑
CLIMB_STAIRS = "climb_stairs" # 爬楼梯
SET_GAIT = "set_gait" # 设置步态
# ── 自定义扩展 ────────────────────────────────────────────────
CUSTOM = "custom" # 自定义指令
# ─────────────────────────────────────────────────────────────────
# 指令状态枚举
# ─────────────────────────────────────────────────────────────────
class CommandStatus(Enum):
PENDING = "pending" # 待发送
SENT = "sent" # 已发送,等待确认
ACCEPTED = "accepted" # 设备已接受
EXECUTING = "executing" # 执行中
COMPLETED = "completed" # 执行完成
FAILED = "failed" # 执行失败
TIMEOUT = "timeout" # 超时未响应
REJECTED = "rejected" # 设备拒绝
# ─────────────────────────────────────────────────────────────────
# 指令基类
# ─────────────────────────────────────────────────────────────────
@dataclass
class Command:
"""
无人系统控制指令
所有指令均继承此类通过 params 字典传递指令参数
子类可新增强类型字段以提升可读性
"""
# ── 标识 ──────────────────────────────────────────────────────
command_id: str = field(
default_factory=lambda: str(uuid.uuid4())[:8]
)
command_type: CommandType = CommandType.CUSTOM
target_id: str = "" # 目标设备 ID
# ── 参数 ──────────────────────────────────────────────────────
params: Dict[str, Any] = field(default_factory=dict)
# ── 时序 ──────────────────────────────────────────────────────
created_at: float = field(default_factory=time.time)
timeout_s: float = 10.0 # 超时时间(秒)
priority: int = 0 # 优先级(越大越高)
# ── 状态 ──────────────────────────────────────────────────────
status: CommandStatus = CommandStatus.PENDING
# ── 序列化 ────────────────────────────────────────────────────
def to_dict(self) -> Dict[str, Any]:
d = dataclasses.asdict(self)
d["command_type"] = self.command_type.value
d["status"] = self.status.value
return d
def __repr__(self) -> str:
return (f"Command({self.command_type.value}"
f"[{self.command_id}]"
f"{self.target_id}"
f" {self.status.value})")
# ─────────────────────────────────────────────────────────────────
# 常用指令工厂方法
# ─────────────────────────────────────────────────────────────────
class Commands:
"""常用指令快速构造工厂"""
@staticmethod
def guide(target_id: str):
return Command(command_type=CommandType.CUSTOM,
target_id=target_id)
@staticmethod
def arm(target_id: str, **kw) -> Command:
return Command(command_type=CommandType.ARM,
target_id=target_id, **kw)
@staticmethod
def disarm(target_id: str, **kw) -> Command:
return Command(command_type=CommandType.DISARM,
target_id=target_id, **kw)
@staticmethod
def takeoff(target_id: str, altitude: float,
speed: float = 3.0, **kw) -> Command:
return Command(command_type=CommandType.TAKEOFF,
target_id=target_id,
params={"altitude": altitude, "speed": speed},
**kw)
@staticmethod
def land(target_id: str, **kw) -> Command:
return Command(command_type=CommandType.LAND,
target_id=target_id, **kw)
@staticmethod
def rtl(target_id: str, **kw) -> Command:
return Command(command_type=CommandType.RTL,
target_id=target_id, **kw)
@staticmethod
def goto(target_id: str, lat: float, lon: float,
alt: float, speed: float = 5.0, **kw) -> Command:
return Command(command_type=CommandType.GOTO,
target_id=target_id,
params={"lat": lat, "lon": lon,
"alt": alt, "speed": speed},
**kw)
@staticmethod
def set_velocity(target_id: str,
vx: float, vy: float, vz: float = 0.0,
**kw) -> Command:
return Command(command_type=CommandType.SET_VELOCITY,
target_id=target_id,
params={"vx": vx, "vy": vy, "vz": vz},
**kw)
@staticmethod
def emergency_stop(target_id: str, **kw) -> Command:
return Command(command_type=CommandType.EMERGENCY_STOP,
target_id=target_id,
priority=999, **kw)
@staticmethod
def set_mode(target_id: str, mode: str, **kw) -> Command:
return Command(command_type=CommandType.SET_MODE,
target_id=target_id,
params={"mode": mode}, **kw)
@staticmethod
def sit(target_id: str, **kw) -> Command:
return Command(command_type=CommandType.SIT,
target_id=target_id, **kw)
@staticmethod
def stand(target_id: str, **kw) -> Command:
return Command(command_type=CommandType.STAND,
target_id=target_id, **kw)
@staticmethod
def walk(target_id: str, speed: float = 1.0,
heading: float = 0.0, **kw) -> Command:
return Command(command_type=CommandType.WALK,
target_id=target_id,
params={"speed": speed, "heading": heading},
**kw)
@staticmethod
def custom(target_id: str, model: int,
**params) -> Command:
return Command(command_type=CommandType.CUSTOM,
target_id=target_id,
params={"model": model, **params})
# ─────────────────────────────────────────────────────────────────
# 指令执行结果
# ─────────────────────────────────────────────────────────────────
@dataclass
class CommandResult:
"""指令执行结果"""
command_id: str = ""
command_type: str = ""
status: CommandStatus = CommandStatus.PENDING
success: bool = False
message: str = ""
data: Dict[str, Any] = field(default_factory=dict)
elapsed_ms: float = 0.0
timestamp: float = field(default_factory=time.time)
@classmethod
def ok(cls, cmd: Command, message: str = "成功",
data: dict = None, elapsed_ms: float = 0.0) -> "CommandResult":
return cls(
command_id = cmd.command_id,
command_type = cmd.command_type.value,
status = CommandStatus.COMPLETED,
success = True,
message = message,
data = data or {},
elapsed_ms = elapsed_ms,
)
@classmethod
def fail(cls, cmd: Command, message: str = "失败",
elapsed_ms: float = 0.0) -> "CommandResult":
return cls(
command_id = cmd.command_id,
command_type = cmd.command_type.value,
status = CommandStatus.FAILED,
success = False,
message = message,
elapsed_ms = elapsed_ms,
)
@classmethod
def timeout(cls, cmd: Command) -> "CommandResult":
return cls(
command_id = cmd.command_id,
command_type = cmd.command_type.value,
status = CommandStatus.TIMEOUT,
success = False,
message = f"指令超时(>{cmd.timeout_s}s",
)
def __repr__(self) -> str:
mark = "" if self.success else ""
return (f"{mark} CommandResult("
f"{self.command_type}[{self.command_id}] "
f"{self.status.value}: {self.message})")