# Vehicle Agent Windows — Ubuntu 通信协议文档

## 1. 总体架构

```
┌─────────────────────────────────┐        TCP 长连接（每次请求建立/断开）
│  Ubuntu 车间电脑                 │ ──────────────────────────────────────►
│  vehicle_agent_gateway          │
│  ├─ ChassisBridgeNode  :9001    │ ◄──────────────────────────────────────
│  └─ ControlBridgeNode  :9002    │
└─────────────────────────────────┘

┌─────────────────────────────────┐
│  Windows 车端电脑                │
│  vehicle_agent_windows          │
│  ├─ ChassisDomainServer  :9001  │
│  └─ ControlDomainServer  :9002  │
└─────────────────────────────────┘
```

- Ubuntu 侧**主动发起**每次连接，发完请求等响应后关闭 socket。
- Windows 侧持续监听两个 TCP 端口，每次连接处理一条请求后可关闭或保持，均可。
- 两个端口完全独立，可以用同一进程的两个线程分别监听。

---

## 2. 帧格式（Frame Protocol）

所有消息使用统一的二进制帧封装，**与业务域无关**：

```
 ┌──────────────┬──────────────┬──────────────────────────┐
 │ msg_type     │ payload_len  │ payload                  │
 │ 4 bytes LE   │ 4 bytes LE   │ payload_len bytes        │
 └──────────────┴──────────────┴──────────────────────────┘
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `msg_type` | uint32 小端 | 消息类型枚举值（见第3节）|
| `payload_len` | uint32 小端 | payload 字节数，可为 0 |
| `payload` | UTF-8 JSON | 业务数据，格式见第4、5节 |

**注意**：
- 若 `payload_len == 0`，则 payload 段缺省，不发送任何额外字节。
- payload 为 **UTF-8 JSON 字符串**，不含 BOM，不含换行，紧凑格式（不强制，解析时容忍空白）。

Python 读帧示例：
```python
import struct, socket

def read_frame(conn):
    header = recv_exactly(conn, 8)
    msg_type, payload_len = struct.unpack_from('<II', header)
    payload = recv_exactly(conn, payload_len) if payload_len > 0 else b''
    return msg_type, payload.decode('utf-8')

def send_frame(conn, msg_type: int, payload: str):
    data = payload.encode('utf-8')
    conn.sendall(struct.pack('<II', msg_type, len(data)) + data)
```

---

## 3. 消息类型枚举（MsgType）

### 3.1 底盘域（端口 9001）

| 值 | 名称 | 方向 | 说明 |
|----|------|------|------|
| 1 | `CHASSIS_GET_READINESS_REQ` | Ubuntu → Windows | 查询底盘是否就绪 |
| 2 | `CHASSIS_GET_READINESS_RSP` | Windows → Ubuntu | 底盘就绪响应 |
| 3 | `CHASSIS_MOTION_PRIMITIVE_REQ` | Ubuntu → Windows | 执行动作原语 |
| 4 | `CHASSIS_MOTION_PRIMITIVE_RSP` | Windows → Ubuntu | 动作原语执行结果 |
| 5 | `CHASSIS_EMERGENCY_BRAKE_REQ` | Ubuntu → Windows | 紧急制动 |
| 6 | `CHASSIS_EMERGENCY_BRAKE_RSP` | Windows → Ubuntu | 紧急制动响应 |

### 3.2 运控域（端口 9002）

| 值 | 名称 | 方向 | 说明 |
|----|------|------|------|
| 11 | `CONTROL_GET_READINESS_REQ` | Ubuntu → Windows | 查询运控是否就绪 |
| 12 | `CONTROL_GET_READINESS_RSP` | Windows → Ubuntu | 运控就绪响应 |
| 13 | `CONTROL_EVALUATION_REQ` | Ubuntu → Windows | 执行控制评估任务 |
| 14 | `CONTROL_EVALUATION_RSP` | Windows → Ubuntu | 控制评估结果 |

---

## 4. 底盘域 payload 格式（端口 9001）

### 4.1 CHASSIS_GET_READINESS_REQ（type=1）

Ubuntu 发送，询问底盘当前是否具备执行标定动作的条件。

```json
{
  "agent_name": "chassis",
  "include_details": true,
  "target_resource_ids": []
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `agent_name` | string | 固定为 `"chassis"` |
| `include_details` | bool | 是否返回详细问题列表 |
| `target_resource_ids` | string[] | 指定资源 ID，通常为空 |

### 4.2 CHASSIS_GET_READINESS_RSP（type=2）

Windows 返回，描述底盘当前状态。**所有布尔字段均须填写**。

```json
{
  "success": true,
  "error_code": {"code": 0},
  "message": "底盘就绪。",
  "agent_ready": true,
  "chassis_driver_online": true,
  "motion_control_ready": true,
  "estop_released": true,
  "vehicle_safe_to_move": true,
  "telemetry_available": true,
  "checked_timestamp_us": 1711234567000000
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 查询本身是否成功 |
| `error_code.code` | uint32 | 错误码（0=OK，见附录 A）|
| `message` | string | 人读说明 |
| `agent_ready` | bool | 底盘代理服务是否就绪 |
| `chassis_driver_online` | bool | 底盘驱动是否在线 |
| `motion_control_ready` | bool | 运控链路是否可执行动作 |
| `estop_released` | bool | 急停是否已释放（**必须为 true 才会执行标定动作**）|
| `vehicle_safe_to_move` | bool | 当前车辆是否允许移动（**必须为 true**）|
| `telemetry_available` | bool | 是否可回传遥测 |
| `checked_timestamp_us` | int64 | 检查时刻（Unix 微秒）|

### 4.3 CHASSIS_MOTION_PRIMITIVE_REQ（type=3）

Ubuntu 发送，让车辆执行一个标定动作原语。`selected_primitive` 决定哪个子对象有效。

```json
{
  "header": {
    "session_id": "workshop_v2_1711234567000000_1",
    "task_id": "stage_chassis_straight_001",
    "vehicle_id": "AGV-001",
    "request_id": "chassis_req_1711234567100000",
    "client_send_timestamp_us": 1711234567100000,
    "operator_id": "op_001",
    "workshop_host": "ubuntu-workshop-pc"
  },
  "test_case_id": "straight_line_v1",
  "task_purpose": 1,
  "selected_primitive": 1,
  "brake_when_finished": true,
  "timeout_sec": 30.0,
  "source_iteration_id": "iter_001",
  "straight_line": {
    "target_speed_ms": 0.3,
    "target_distance_m": 5.0,
    "reverse": false
  }
}
```

#### `selected_primitive` 枚举值

| 值 | 名称 | 有效子对象 |
|----|------|----------|
| 0 | UNSPECIFIED | — |
| 1 | STRAIGHT_LINE | `straight_line` |
| 2 | ARC | `arc` |
| 3 | IN_PLACE_ROTATION | `in_place_rotation` |
| 4 | STEERING_SWEEP | `steering_sweep` |
| 5 | LATERAL_TRANSLATION | `lateral_translation` |
| 6 | DIAGONAL_MOTION | `diagonal_motion` |
| 7 | MODULE_ALIGNMENT | `module_alignment` |
| 8 | COORDINATED_STEERING | `coordinated_steering` |

#### 各动作原语子对象格式

**straight_line**（直线行驶）
```json
{
  "target_speed_ms": 0.3,
  "target_distance_m": 5.0,
  "reverse": false
}
```

**arc**（圆弧行驶）
```json
{
  "target_speed_ms": 0.2,
  "radius_m": 2.0,
  "sweep_angle_deg": 90.0,
  "clockwise": true
}
```

**in_place_rotation**（原地旋转）
```json
{
  "target_yaw_deg": 90.0,
  "target_angular_vel_deg_s": 10.0
}
```

**steering_sweep**（舵角扫动）
```json
{
  "target_angle_deg": 0.0,
  "sweep_amplitude_deg": 15.0,
  "sweep_frequency_hz": 0.5,
  "duration_sec": 10.0
}
```

**lateral_translation**（横移，多舵轮专用）
```json
{
  "target_speed_ms": 0.2,
  "target_distance_m": 1.0,
  "move_left": true
}
```

**diagonal_motion**（斜移，多舵轮专用）
```json
{
  "target_speed_ms": 0.2,
  "target_distance_m": 2.0,
  "heading_deg": 45.0
}
```

**module_alignment**（模块零位检查）
```json
{
  "module_ids": ["module_0", "module_1", "module_2", "module_3"],
  "target_zero_deg": 0.0,
  "tolerance_deg": 0.5
}
```

**coordinated_steering**（模块协同转向）
```json
{
  "module_ids": ["module_0", "module_1"],
  "target_angle_deg": 30.0,
  "hold_time_sec": 3.0
}
```

### 4.4 CHASSIS_MOTION_PRIMITIVE_RSP（type=4）

Windows 在动作完成后返回，包含质量评估结果供编排器做自动验收。

```json
{
  "success": true,
  "error_code": {"code": 0},
  "message": "直线行驶完成。",
  "job_id": "chassis_req_1711234567100000",
  "data_quality_passed": true,
  "suitable_for_commit": true,
  "recommended_parameter_version": "chassis_v1_iter001",
  "estimated_straight_line_bias": 0.003,
  "validation_summary": {
    "max_lateral_error_m": 0.012,
    "max_yaw_error_rad": 0.008,
    "rms_lateral_error_m": 0.006,
    "rms_yaw_error_rad": 0.004,
    "repeatability_error_m": 0.002,
    "curvature_error": 0.001,
    "module_consistency_error": 0.0,
    "auto_acceptance_passed": true
  },
  "artifacts": [
    {
      "file_name": "chassis_run_001.bag",
      "file_uri": "C:/calib_data/chassis_run_001.bag",
      "size_bytes": 1048576,
      "description": "底盘标定采集数据包"
    }
  ]
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 动作是否成功执行 |
| `data_quality_passed` | bool | 采集数据质量是否达标（影响自动验收）|
| `suitable_for_commit` | bool | 估计参数是否适合写入（影响自动验收）|
| `recommended_parameter_version` | string | 本次估计的参数版本号 |
| `estimated_straight_line_bias` | float64 | 估计的直线跑偏量（m）|
| `validation_summary` | object | 验收关键指标（见上）|
| `artifacts` | array | 关联数据文件列表 |

**自动验收规则**：编排器要求 `data_quality_passed == true && suitable_for_commit == true`

---

## 5. 运控域 payload 格式（端口 9002）

### 5.1 CONTROL_GET_READINESS_REQ（type=11）

```json
{
  "agent_name": "control",
  "include_details": true,
  "target_resource_ids": []
}
```

### 5.2 CONTROL_GET_READINESS_RSP（type=12）

```json
{
  "success": true,
  "error_code": {"code": 0},
  "message": "运控就绪。",
  "agent_ready": true,
  "trajectory_executor_ready": true,
  "vehicle_feedback_ready": true,
  "control_output_ready": true,
  "estop_released": true,
  "vehicle_safe_to_move": true,
  "checked_timestamp_us": 1711234567000000
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `trajectory_executor_ready` | bool | 轨迹执行器是否就绪 |
| `vehicle_feedback_ready` | bool | 车辆反馈链路是否就绪 |
| `control_output_ready` | bool | 控制输出链路是否就绪 |
| `estop_released` | bool | 急停是否释放（**必须为 true**）|
| `vehicle_safe_to_move` | bool | 是否允许移动（**必须为 true**）|

### 5.3 CONTROL_EVALUATION_REQ（type=13）

Ubuntu 发送，让车端按当前控制参数执行一次评估任务。`selected_task` 决定哪个子对象有效。

```json
{
  "header": {
    "session_id": "workshop_v2_1711234567000000_1",
    "task_id": "stage_control_lateral_001",
    "vehicle_id": "AGV-001",
    "request_id": "chassis_req_1711234568000000",
    "client_send_timestamp_us": 1711234568000000,
    "operator_id": "op_001",
    "workshop_host": "ubuntu-workshop-pc"
  },
  "test_case_id": "lateral_tracking_v1",
  "task_purpose": 1,
  "selected_task": 1,
  "source_iteration_id": "iter_001",
  "trajectory_tracking": {
    "path": [
      {"x_m": 0.0, "y_m": 0.0, "yaw_rad": 0.0, "target_speed_ms": 0.5},
      {"x_m": 5.0, "y_m": 0.0, "yaw_rad": 0.0, "target_speed_ms": 0.5},
      {"x_m": 10.0, "y_m": 0.0, "yaw_rad": 0.0, "target_speed_ms": 0.0}
    ],
    "stop_at_end": true,
    "timeout_sec": 60.0,
    "required_external_pose_source_id": "workshop_external_truth",
    "max_external_pose_age_ms": 100.0,
    "min_external_pose_quality_score": 0.8,
    "trajectory_id": "traj_001",
    "segment_index": 0,
    "total_segments": 1,
    "is_final_segment": true
  }
}
```

#### `selected_task` 枚举值

| 值 | 名称 | 有效子对象 | 说明 |
|----|------|----------|------|
| 0 | UNSPECIFIED | — | — |
| 1 | TRAJECTORY_TRACKING | `trajectory_tracking` | 跟踪给定轨迹，评估横向/航向误差 |
| 2 | VELOCITY_STEP | `velocity_step` | 速度阶跃，评估纵向动态响应 |
| 3 | ACCELERATION_DECELERATION | `accel_decel` | 加减速，评估纵向平顺性与 jerk |
| 4 | STOP_ACCURACY | `stop_accuracy` | 评估停车位置精度 |

#### 各任务子对象格式

**trajectory_tracking**
```json
{
  "path": [
    {"x_m": 0.0, "y_m": 0.0, "yaw_rad": 0.0, "target_speed_ms": 0.5}
  ],
  "stop_at_end": true,
  "timeout_sec": 60.0,
  "required_external_pose_source_id": "workshop_external_truth",
  "max_external_pose_age_ms": 100.0,
  "min_external_pose_quality_score": 0.8,
  "trajectory_id": "traj_001",
  "segment_index": 0,
  "total_segments": 1,
  "is_final_segment": true
}
```

**velocity_step**
```json
{
  "target_velocity_ms": 1.0,
  "hold_time_sec": 5.0,
  "settle_before_step_sec": 2.0
}
```

**accel_decel**
```json
{
  "start_velocity_ms": 0.0,
  "target_velocity_ms": 1.5,
  "target_accel_ms2": 0.5,
  "hold_time_sec": 3.0
}
```

**stop_accuracy**
```json
{
  "target_stop_x_m": 10.0,
  "target_stop_y_m": 0.0,
  "target_stop_yaw_rad": 0.0,
  "timeout_sec": 30.0
}
```

### 5.4 CONTROL_EVALUATION_RSP（type=14）

```json
{
  "success": true,
  "error_code": {"code": 0},
  "message": "轨迹跟踪评估完成。",
  "job_id": "chassis_req_1711234568000000",
  "data_quality_passed": true,
  "suitable_for_commit": true,
  "recommended_parameter_version": "control_lateral_pid_v2",
  "validation_summary": {
    "rms_lateral_error_m": 0.015,
    "rms_heading_error_rad": 0.010,
    "rms_speed_error_ms": 0.05,
    "overshoot_ratio": 0.08,
    "settle_time_sec": 1.2,
    "stop_position_error_m": 0.02,
    "max_jerk": 0.3,
    "saturation_ratio": 0.05,
    "auto_acceptance_passed": true
  },
  "artifacts": [
    {
      "file_name": "control_eval_001.csv",
      "file_uri": "C:/calib_data/control_eval_001.csv",
      "size_bytes": 204800,
      "description": "控制评估误差时序数据"
    }
  ]
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `data_quality_passed` | bool | 数据质量是否达标 |
| `suitable_for_commit` | bool | 参数是否适合写入 |
| `validation_summary` | object | 验收关键指标 |
| `validation_summary.rms_lateral_error_m` | float64 | 横向误差 RMS（m）|
| `validation_summary.rms_heading_error_rad` | float64 | 航向误差 RMS（rad）|
| `validation_summary.rms_speed_error_ms` | float64 | 速度误差 RMS（m/s）|
| `validation_summary.overshoot_ratio` | float64 | 超调比例（0~1）|
| `validation_summary.settle_time_sec` | float64 | 收敛时间（s）|
| `validation_summary.stop_position_error_m` | float64 | 停车位置误差（m）|
| `validation_summary.max_jerk` | float64 | 最大 jerk（m/s³）|
| `validation_summary.saturation_ratio` | float64 | 控制饱和占比（0~1）|
| `validation_summary.auto_acceptance_passed` | bool | 综合自动验收是否通过 |

---

## 6. 交互时序

### 6.1 底盘标定完整流程

```
Ubuntu (orchestrator)          Ubuntu (gateway)           Windows (vehicle_agent)
        │                            │                            │
        │── execute_goal ───────────►│                            │
        │                            │── TCP connect :9001 ──────►│
        │                            │── CHASSIS_GET_READINESS_REQ│
        │                            │◄─ CHASSIS_GET_READINESS_RSP│
        │                            │── TCP close ───────────────│
        │                            │                            │
        │  (readiness check passed)  │                            │
        │                            │── TCP connect :9001 ──────►│
        │                            │── CHASSIS_MOTION_PRIM_REQ ─│ (车辆开始运动)
        │                            │        ... 等待车辆完成 ... │
        │                            │◄─ CHASSIS_MOTION_PRIM_RSP ─│ (含验收指标)
        │                            │── TCP close ───────────────│
        │◄── action result ─────────│                            │
```

### 6.2 注意事项

1. **每次请求建立新 TCP 连接**：Ubuntu 侧 `TcpClient` 每次 `send_recv` 都会新建、使用、关闭连接。Windows 侧不需要维护长连接状态。
2. **超时控制**：Ubuntu 侧默认等待 5000ms（可通过 ROS2 参数 `chassis_timeout_ms` / `control_timeout_ms` 调整）。动作原语执行时间可能远超此值，Windows 侧应在动作完成后才回复 RSP 帧，不要提前响应。
3. **急停处理**：Ubuntu 侧 orchestrator 在收到取消请求时会关闭 socket 连接。Windows 侧检测到连接断开即应停止当前动作并触发安全停车。
4. **并发**：底盘域和运控域在不同端口，理论上可并发，但编排器保证同一时刻只有一个域的任务在执行。

---

## 7. Windows 侧实现最小要求

### 7.1 必须实现的接口

| 端口 | REQ type | 行为 |
|------|----------|------|
| 9001 | type=1 READINESS | 检查底盘状态，返回 type=2 |
| 9001 | type=3 MOTION_PRIMITIVE | 执行指定动作，完成后返回 type=4（含验收指标）|
| 9002 | type=11 READINESS | 检查运控状态，返回 type=12 |
| 9002 | type=13 EVALUATION | 执行控制评估，完成后返回 type=14（含验收指标）|

### 7.2 错误响应格式

执行失败时，`success` 设为 `false`，`error_code.code` 填对应错误码，`message` 填人读错误说明：

```json
{
  "success": false,
  "error_code": {"code": 5},
  "message": "底盘驱动离线，无法执行动作。",
  "job_id": "chassis_req_1711234567100000",
  "data_quality_passed": false,
  "suitable_for_commit": false
}
```

### 7.3 联调工具

Ubuntu 侧提供了 Python stub 服务器用于 Windows 侧联调前的自测：

```bash
# 在 Ubuntu 上运行，模拟 Windows 车端（返回空 payload 的成功响应）
python3 src/communication/win_ubuntu_bridge/vehicle_agent_gateway/scripts/windows_stub_server.py
```

---

## 附录 A：ErrorCode 值

| 值 | 名称 | 含义 |
|----|------|------|
| 0  | UNSPECIFIED               | 未指定 |
| 1  | OK                        | 成功 |
| 2  | INVALID_ARGUMENT          | 参数非法 |
| 3  | INVALID_STATE             | 当前状态不允许此操作 |
| 4  | VEHICLE_BUSY              | 车辆当前忙 |
| 5  | NOT_READY                 | 未准备好 |
| 6  | TIMEOUT                   | 超时 |
| 7  | NETWORK_LOSS              | 网络断开 |
| 8  | SAFETY_TRIGGERED          | 安全保护触发 |
| 9  | HARDWARE_FAULT            | 硬件故障 |
| 10 | FILE_NOT_FOUND            | 文件不存在 |
| 11 | CHECKSUM_MISMATCH         | 校验失败 |
| 12 | INTERNAL_ERROR            | 内部错误 |
| 13 | UNSUPPORTED_CAPABILITY    | 当前车辆不支持该能力 |
| 14 | RESOURCE_LOCKED           | 资源已被其他会话占用 |
| 15 | MANUAL_CONFIRM_REQUIRED   | 需要人工确认 |
| 16 | APPROVAL_REQUIRED         | 需要审批 |
| 17 | VALIDATION_FAILED         | 验证失败 |
| 18 | ROLLBACK_REQUIRED         | 需要回滚 |
| 19 | DATA_QUALITY_INSUFFICIENT | 数据质量不足 |

---

## 附录 B：快速验证清单

Windows 侧自测时依次验证：

- [ ] 监听 9001 端口，收到 type=1 帧，回复 type=2 帧（`success=true`, `estop_released=true`, `vehicle_safe_to_move=true`）
- [ ] 收到 type=3 帧（`selected_primitive=1` 直线），车辆执行，完成后回复 type=4（`success=true`, `data_quality_passed=true`, `suitable_for_commit=true`）
- [ ] 监听 9002 端口，收到 type=11 帧，回复 type=12 帧
- [ ] 收到 type=13 帧（`selected_task=1` 轨迹跟踪），执行，回复 type=14
- [ ] 模拟急停：收到 type=3 帧后主动关闭连接，验证车辆停车
