syntax = "proto3";

package cmvr.msgs;

// AGV 在地图平面坐标系中的二维位姿。
message AgvPose2d {
  // X 坐标，单位：米。
  double x = 1;
  // Y 坐标，单位：米。
  double y = 2;
  // 航向角，单位：弧度，逆时针为正。
  double theta = 3;
}

// AGV 车体坐标系下的平面速度。
message AgvVelocity {
  // 车体 X 方向线速度，单位：米/秒。
  double vx = 1;
  // 车体 Y 方向线速度，单位：米/秒。
  double vy = 2;
  // 绕 Z 轴角速度，单位：弧度/秒。
  double wz = 3;
}

// AGV 电池状态。
message AgvBatteryState {
  // 电量比例，范围：[0, 1]，例如 0.8 表示 80%。
  double percentage = 1;
  // 电池电压，单位：伏特。
  double voltage = 2;
  // 电池电流，单位：安培；正负号含义由具体 AGV 适配器保持一致。
  double current = 3;
  // 电池温度，单位：摄氏度。
  double temperature = 4;
  // 是否正在充电。
  bool charging = 5;
}

// 导航任务的通用运动约束和执行选项。
message AgvMotionOptions {
  // 最大线速度，单位：米/秒；0 表示使用 AGV 默认值。
  double max_speed = 1;
  // 最大角速度，单位：弧度/秒；0 表示使用 AGV 默认值。
  double max_angular_speed = 2;
  // 最大线加速度，单位：米/秒^2；0 表示使用 AGV 默认值。
  double max_acceleration = 3;
  // 最大角加速度，单位：弧度/秒^2；0 表示使用 AGV 默认值。
  double max_angular_acceleration = 4;
  // 到达目标点的距离容差，单位：米；0 表示使用 AGV 默认值。
  double reach_distance = 5;
  // 到达目标角度的角度容差，单位：弧度；0 表示使用 AGV 默认值。
  double reach_angle = 6;
  // 速度比例，范围通常为 [0, 1]；1 表示不降速。
  double speed_ratio = 7;
  // 是否异步执行；true 表示下发任务后立即返回。
  bool asynchronous = 8;
}

// AGV 适配器扩展参数。用于传递厂商或控制器特有的参数。
message AgvAdapterParams {
  // 参数键值表。键和值都使用字符串，具体含义由 AGV 适配器解释。
  map<string, string> values = 1;
}

// AGV 当前运行状态快照。
message AgvRuntimeState {
  // 状态采样时间，Unix 时间戳，单位：秒。
  double timestamp = 1;
  // 运行模式，取值对应服务端内部 AgvMode 枚举的整数值。
  int32 mode = 2;
  // 是否已连接 AGV 控制器。
  bool connected = 3;
  // 是否已定位成功。
  bool localized = 4;
  // AGV 是否处于运动状态。
  bool moving = 5;
  // AGV 是否处于故障状态。
  bool fault = 6;
  // AGV 是否处于急停状态。
  bool emergency_stopped = 7;
  // 当前地图坐标系下的二维位姿。
  AgvPose2d pose = 8;
  // 当前车体速度。
  AgvVelocity velocity = 9;
  // 当前电池状态。
  AgvBatteryState battery = 10;
  // 当前加载地图名称；为空表示未知或控制器未返回。
  string current_map = 11;
  // 当前或最近站点 id；为空表示未知或当前不在站点附近。
  string current_station = 12;
  // 最近一次错误信息；为空表示无错误或未知。
  string last_error = 13;
}

// 地图中的站点信息。
message AgvStation {
  // 站点唯一 id。
  string id = 1;
  // 站点类型；具体枚举由地图或控制器定义。
  string type = 2;
  // 站点在地图坐标系下的二维位姿。
  AgvPose2d pose = 3;
  // 站点描述或备注。
  string description = 4;
}

// 显式站点路径中的一段路径。
message AgvPathSegment {
  // 起点站点 id。
  string source_station = 1;
  // 目标站点 id。
  string target_station = 2;
}

// 地图维度请求。这里只描述上位机想要 2D、3D 还是二者都要，
// 不用于指定厂商文件格式；厂商格式必须在 AGV 适配器内部转换。
enum AgvMapDimension {
  // 未指定。服务端应选择最有用的默认地图，通常是当前加载地图。
  AGV_MAP_DIMENSION_UNSPECIFIED = 0;
  // 只请求统一 2D 地图。
  AGV_MAP_2D = 1;
  // 只请求统一 3D 地图。
  AGV_MAP_3D = 2;
  // 在同一个流中请求统一 2D 和统一 3D 地图。
  AGV_MAP_2D_AND_3D = 3;
}

// 地图流更新类型。上位机应根据该字段判断是全量、增量还是缓存重置。
enum AgvMapUpdateType {
  // 未指定。
  AGV_MAP_UPDATE_UNSPECIFIED = 0;
  // 全量地图快照。首次请求或无法增量续传时应发送该类型。
  AGV_MAP_UPDATE_SNAPSHOT = 1;
  // 全量快照之后的增量更新。仅当适配器能够可靠生成差异时发送。
  AGV_MAP_UPDATE_INCREMENTAL = 2;
  // 上位机本地缓存已失效，应丢弃缓存并等待后续全量快照。
  AGV_MAP_UPDATE_RESET = 3;
}

// 2D/3D 地图共用的语义对象类型。
enum AgvMapObjectType {
  // 未指定。
  AGV_MAP_OBJECT_UNSPECIFIED = 0;
  // 导航站点或路径点。
  AGV_MAP_OBJECT_STATION = 1;
  // 路径线、禁行线、引导线等线对象。
  AGV_MAP_OBJECT_LINE = 2;
  // 多边形区域，例如禁行区、限速区、作业区。
  AGV_MAP_OBJECT_AREA = 3;
  // 二维码、天码或其他标签地标。
  AGV_MAP_OBJECT_QR_TAG = 4;
  // 反光板或反光柱地标。
  AGV_MAP_OBJECT_REFLECTOR = 5;
  // 库位、货位或储位。
  AGV_MAP_OBJECT_BIN_LOCATION = 6;
  // 门、电梯、充电桩等外部设备。
  AGV_MAP_OBJECT_EXTERNAL_DEVICE = 7;
}

// 地图坐标系下的三维点。单位：米。
message AgvMapPoint3D {
  // X 坐标，单位：米。
  double x = 1;
  // Y 坐标，单位：米。
  double y = 2;
  // Z 坐标，单位：米；纯 2D 几何可置为 0。
  double z = 3;
}

// 统一 2D 地图。栅格数据按行优先排列：index = y * width + x。
message AgvUnifiedMap2D {
  // 坐标系名称，例如 "map"。
  string frame_id = 1;
  // 地图采样或更新时间，Unix 时间戳，单位：秒。
  double timestamp = 2;
  // 栅格分辨率，单位：米/格。
  double resolution = 3;
  // 栅格宽度，单位：格。
  uint32 width = 4;
  // 栅格高度，单位：格。
  uint32 height = 5;
  // 栅格 (0, 0) 在世界/地图坐标系下的位姿；x/y 单位：米，theta 单位：弧度。
  AgvPose2d origin = 6;
  // 占据值：-1 表示未知，0 表示空闲，100 表示占据。
  repeated int32 data = 7;
  // 地图中的统一语义对象，例如站点、线、区域、标签、反光板等。
  repeated AgvMapObject objects = 8;
}

// 统一 3D 点样本。坐标单位：米。
message AgvMapPointSample3D {
  // X 坐标，单位：米。
  double x = 1;
  // Y 坐标，单位：米。
  double y = 2;
  // Z 坐标，单位：米。
  double z = 3;
  // 激光强度；无强度信息时置为 0。
  float intensity = 4;
  // 激光雷达线束/通道编号；无该信息时置为 0。
  uint32 ring = 5;
  // 相对地图时间戳的时间偏移，单位：秒；无该信息时置为 0。
  double time_offset = 6;
}

// 统一 3D 体素。体素索引基于 AgvUnifiedMap3D.voxel_resolution。
message AgvMapVoxel3D {
  // 体素 X 索引。
  int32 x = 1;
  // 体素 Y 索引。
  int32 y = 2;
  // 体素 Z 索引。
  int32 z = 3;
  // 占据概率，范围：[0, 1]；未知时置为 -1。
  float probability = 4;
}

// 统一 3D 平面特征。平面方程：
// normal.x * x + normal.y * y + normal.z * z + d = 0。
message AgvMapPlane3D {
  // 平面中心点，单位：米。
  AgvMapPoint3D center = 1;
  // 平面单位法向量。
  AgvMapPoint3D normal = 2;
  // 平面方程偏移量，单位：米。
  double d = 3;
  // 平面特征近似半径，单位：米。
  double radius = 4;
}

// 统一语义对象。几何点均使用地图坐标系，单位：米。
message AgvMapObject {
  // 对象稳定 id 或名称。
  string id = 1;
  // 对象类型。
  AgvMapObjectType type = 2;
  // 对象几何点。点对象使用 1 个点，线对象使用多个点，区域对象使用多边形顶点。
  repeated AgvMapPoint3D points = 3;
  // 朝向角，单位：弧度；不适用时置为 0。
  double heading = 4;
  // 额外归一化属性。为兼容不同 AGV，属性值统一使用字符串。
  map<string, string> properties = 5;
}

// 统一 3D 地图。虽然内部包含点、体素、平面和语义对象，
// 但对上位机来说它仍然是唯一的 3D 地图格式。
message AgvUnifiedMap3D {
  // 坐标系名称，例如 "map"。
  string frame_id = 1;
  // 地图采样或更新时间，Unix 时间戳，单位：秒。
  double timestamp = 2;
  // 体素分辨率，单位：米/体素；没有体素数据时置为 0。
  double voxel_resolution = 3;
  // 统一点云点样本。
  repeated AgvMapPointSample3D points = 4;
  // 统一占据体素。
  repeated AgvMapVoxel3D voxels = 5;
  // 统一平面特征。
  repeated AgvMapPlane3D planes = 6;
  // 统一 3D 语义对象，例如站点、区域、标签、地标等。
  repeated AgvMapObject objects = 7;
}

// 地图流中的单条更新。AGV 适配器必须先把厂商地图转换成 map_2d 或 map_3d，
// 再通过该消息发送给上位机。
message AgvUnifiedMapUpdate {
  // 实际发送的地图 id 或名称。请求 map_name 为空时，AGV 可选择当前或最近地图。
  string map_id = 1;
  // 建图或地图流会话 id。
  string session_id = 2;
  // 会话内单调递增序号，从 0 或 1 开始均可，但同一会话内必须保持递增。
  uint64 sequence = 3;
  // 用于断点续传或增量订阅的不透明令牌。
  string resume_token = 4;
  // 本条更新的数据维度。
  AgvMapDimension dimension = 5;
  // 本条更新是全量、增量还是缓存重置。
  AgvMapUpdateType update_type = 6;
  // 坐标系名称，例如 "map"。
  string frame_id = 7;
  // 本条更新产生时间，Unix 时间戳，单位：秒。
  double timestamp = 8;
  // 是否为全量快照的第一条消息。
  bool snapshot_begin = 9;
  // 是否为全量快照的最后一条消息。
  bool snapshot_end = 10;
  // 大地图分片发送时的分片序号，从 0 开始。
  uint32 chunk_index = 11;
  // 大地图分片总数；0 表示未知或连续流。
  uint32 chunk_count = 12;

  oneof payload {
    // 统一 2D 地图或 2D 地图增量。
    AgvUnifiedMap2D map_2d = 20;
    // 统一 3D 地图或 3D 地图增量。
    AgvUnifiedMap3D map_3d = 21;
  }
}

// 当前导航任务状态。
message AgvNavigationStatus {
  // 导航状态，取值对应服务端内部 AgvTaskState 枚举的整数值。
  int32 state = 1;
  // 导航任务类型，取值对应服务端内部 AgvTaskType 枚举的整数值。
  int32 type = 2;
  // 当前任务进度，范围：[0, 1]；未知时置为 0。
  double progress = 3;
  // 状态描述或错误信息。
  string message = 4;
}
