diff --git a/.env b/.env index 987b014..af00964 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -# VITE_AGV_DEVICE_ID = 'agv_src2200' +# VITE_AGV_DEVICE_ID = 'src1100' # VITE_ARM_DEVICE_ID = 'aubo_arm' # 机械臂IP 192.168.1.109:50052 diff --git a/server/index.js b/server/index.js index eb0e11d..3d9f736 100644 --- a/server/index.js +++ b/server/index.js @@ -11,8 +11,8 @@ app.use(express.static(path.join(__dirname, '../dist'))); app.use(cors()) app.use(express.json()) -// 获取机器人当前地图名称 -app.post('/api/agv/getCurrentMapName', async (req, res) => { +// 获取agv运行时状态 +app.post('/api/agv/getRuntimeState', async (req, res) => { const request = { header: { device_id: req.body.deviceId || 'agv_src1100' @@ -22,7 +22,7 @@ app.post('/api/agv/getCurrentMapName', async (req, res) => { const grpcClient = createAGVGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { - grpcClient.getMapStatus(request, (err, res) => { + grpcClient.getRuntimeState(request, (err, res) => { if (err) { resolve({ code: 500, @@ -31,7 +31,7 @@ app.post('/api/agv/getCurrentMapName', async (req, res) => { } else { resolve({ code: 200, - data: res.status + data: res.state }); } }); @@ -44,20 +44,18 @@ app.post('/api/agv/getCurrentMapName', async (req, res) => { } }) -// 获取机器人当前地图名称 +// 获取机器人当前地图 app.post('/api/agv/getCurrentMap', async (req, res) => { const grpcClient = createAGVGrpcClient(req.body.ip) const request = { header: { device_id: req.body.deviceId || 'agv_src1100' }, - data: { - map_name: req.body.mapName - } + map_name: req.body.mapName }; const resp = await new Promise((resolve, reject) => { - grpcClient.RobotConfigDownloadMap(request, (err, res) => { + grpcClient.downloadMap(request, (err, res) => { if (err) { resolve({ code: 500, @@ -66,7 +64,7 @@ app.post('/api/agv/getCurrentMap', async (req, res) => { } else { resolve({ code: 200, - data: res.status + data: res.content }); } }); @@ -79,83 +77,22 @@ app.post('/api/agv/getCurrentMap', async (req, res) => { } }) -// 获取机器人状态 -app.post('/api/agv/getRobotState', async (req, res) => { - const request = { - header: { - device_id: req.body.deviceId || 'agv_src1100' - } - }; - - const grpcClient = createAGVGrpcClient(req.body.ip) - - const response = await new Promise((resolve, reject) => { - grpcClient.GetRobotLocation(request, (err, res) => { - if (err) { - resolve({ - code: 500, - data: `grpc服务端错误` - }); - } else { - resolve({ - code: 200, - data: res.status - }); - } - }) - }) - const resp = await new Promise((resolve, reject) => { - grpcClient.GetBatteryStatus(request, (err, res) => { - if (err) { - resolve({ - code: 500, - data: `grpc服务端错误` - }); - } else { - resolve({ - code: 200, - data: res.status - }); - } - }); - }) - - if (response.code === 200 && resp.code ===200) { - res.json({ - code: 200, - data: { - x: response.data.x, - y: response.data.y, - angle: response.data.angle, - confidence: response.data.confidence, - batteryLevel: resp.data.battery_level, - batteryTemp: resp.data.battery_temp, - charging: resp.data.charging, - voltage: resp.data.voltage - } - }) - } else { - res.status(500).json({ error: 'grpc服务端错误' }) - } -}) - // 机器人运动控制 app.post('/api/agv/moveRobot', async (req, res) => { - const grpcClient = createAGVGrpcClient(req.body.ip) + const grpcClient = setVelocity(req.body.ip) const request = { header: { device_id: req.body.deviceId || 'agv_src1100' }, - data: { + velocity: { vx: req.body.vx, vy: req.body.vy, - w: req.body.w, - duration: req.body.duration + vz: req.body.vz } }; const resp = await new Promise((resolve, reject) => { - grpcClient.RobotMotionControl(request, (err, res) => { + grpcClient.setVelocity(request, (err, res) => { if (err) { resolve({ code: 500, @@ -190,7 +127,7 @@ app.post('/api/agv/stopRobot', async (req, res) => { }; const resp = await new Promise((resolve, reject) => { - grpcClient.RobotControlStop(request, (err, res) => { + grpcClient.stopVelocityControl(request, (err, res) => { if (err) { resolve({ code: 500, @@ -215,6 +152,9 @@ app.post('/api/agv/stopRobot', async (req, res) => { } }) + +// ================================================== + // 获取机械臂末端位姿 app.post('/api/arm/getPose', async (req, res) => { const request = { diff --git a/server/proto/cmvr/api/agv_command.proto b/server/proto/cmvr/api/agv_command.proto index cf609cd..267c88f 100644 --- a/server/proto/cmvr/api/agv_command.proto +++ b/server/proto/cmvr/api/agv_command.proto @@ -1,906 +1,212 @@ -/** - * @file agv_command.proto - * @brief AGV 控制相关的 Protobuf 消息定义。 - * 涵盖仙工智能(Seer)SRC 系列控制器的主要 API 命令, - * 包括状态查询、电池、位置、地图管理、控制权、运动控制、导航任务等。 - * @note 所有命令均遵循仙工协议帧格式,通过 gRPC 服务(AgvService)对外暴露。 - */ - syntax = "proto3"; -import "cmvr/api/common.proto"; - package cmvr.api; -// ============================================================================ -// 1. 基本信息查询(命令码 1000, 0x03E8) -// ============================================================================ +import "cmvr/api/common.proto"; +import "cmvr/msgs/agv.proto"; -/** - * @brief AGV 基本信息响应结构。 - * @note 对应仙工 API 1000(0x03E8)的响应体,包含设备标识、软硬件版本、网络状态等。 - */ -message AgvStatusInfo { - optional string id = 1; ///< AGV 设备唯一 ID - optional string vehicle_id = 2; ///< 车辆编号(如 "agv_001") - optional string version = 3; ///< 软件版本号 - optional string model = 4; ///< 车型型号(如 "SRC-1100") - optional string dsp_version = 5; ///< DSP 固件版本 - optional string current_ip = 6; ///< 当前 IP 地址 - optional string mac = 7; ///< MAC 地址 - optional int32 rssi = 8; ///< Wi-Fi 信号强度(0~100) - optional int32 ret_code = 9; ///< 返回码,0 表示成功 - optional string err_msg = 10; ///< 错误信息(失败时填充) -} - -/** - * @brief 获取 AGV 状态命令(请求/反馈)。 - * @note 请求携带设备 ID(header.device_id),反馈返回 AgvStatusInfo。 - */ -message GetAgvStatusInfoCommand { - message Request { - CommandHeader.Request header = 1; ///< 公共请求头,包含 device_id - } - - message Feedback { - CommandHeader.Feedback header = 1; ///< 公共响应头(success/error_message/timestamp) - AgvStatusInfo status = 2; ///< AGV 状态信息 - } -} - - -// ============================================================================ -// 2. 电池状态查询(命令码 1007, 0x03EF) -// ============================================================================ - -/** - * @brief 电池状态响应结构。 - * @note 对应仙工 API 1007(0x03EF),支持简单/全量两种模式。 - */ -message AgvBatteryStatus { - optional double battery_level = 1; ///< 电池电量(0~1,对应 0%~100%) - optional double battery_temp = 2; ///< 电池温度(摄氏度) - optional bool charging = 3; ///< 是否正在充电 - optional double voltage = 4; ///< 当前电压(V) - optional double current = 5; ///< 当前电流(A) - optional double max_charge_voltage = 6; ///< 最大充电电压(-1 表示不支持) - optional double max_charge_current = 7; ///< 最大充电电流(-1 表示不支持) - optional bool manual_charge = 8; ///< 是否连接手动充电器(仅 SRC-2000) - optional bool auto_charge = 9; ///< 是否连接自动充电桩(仅 SRC-2000) - optional int32 battery_cycle = 10; ///< 电池循环次数(从 BMS 读取,可能不准) - optional string battery_user_data = 11; ///< 电池用户自定义数据 - optional string extra = 12; ///< 扩展字段(预留) - optional int32 ret_code = 13; ///< 返回码,0 表示成功 - optional string create_on = 14; ///< 数据创建时间戳(ISO 8601) - optional string err_msg = 15; ///< 错误信息 -} - -/** - * @brief 电池状态请求数据。 - */ -message RobotStatusBatteryRequestData { - optional bool simple = 1; ///< true=仅关键数据,false=全量数据(默认 false) -} - -/** - * @brief 电池状态查询命令。 - */ -message RobotStatusBatteryCommand { - message Request { - CommandHeader.Request header = 1; ///< 公共请求头 - RobotStatusBatteryRequestData data = 2; ///< 请求参数 - } - message Feedback { - CommandHeader.Feedback header = 1; ///< 公共响应头 - AgvBatteryStatus status = 2; ///< 电池状态信息 - } -} - - -// ============================================================================ -// 3. 机器人位置查询(命令码 1004, 0x03EC) -// ============================================================================ - -/** - * @brief 机器人位置响应结构。 - * @note 对应仙工 API 1004(0x03EC),返回世界坐标系下的位姿。 - */ -message AgvRobotLocation { - optional double x = 1; ///< X 坐标(米) - optional double y = 2; ///< Y 坐标(米) - optional double angle = 3; ///< 朝向角(弧度),逆时针为正 - optional double confidence = 4; ///< 定位置信度(0~1) - optional string current_station = 5; ///< 当前所在站点 ID(若在站点上) - optional string last_station = 6; ///< 上一个经过的站点 ID - optional int32 loc_method = 7; ///< 定位方式(0=自然轮廓, 1=反光柱, 2=二维码, 3=里程计...) - optional int32 ret_code = 8; ///< 返回码,0 表示成功 - optional string create_on = 9; ///< 时间戳 - optional string err_msg = 10; ///< 错误信息 -} - -/** - * @brief 位置查询命令(无请求数据)。 - */ -message RobotStatusLocCommand { - message Request { - CommandHeader.Request header = 1; ///< 公共请求头 - } - message Feedback { - CommandHeader.Feedback header = 1; ///< 公共响应头 - AgvRobotLocation status = 2; ///< 位置信息 - } -} - - -// ============================================================================ -// 4. 地图下载(命令码 4011, 0x0FAB) -// ============================================================================ - -/** - * @brief 地图下载请求数据。 - */ -message RobotConfigDownloadMapRequestData { - optional string map_name = 1; ///< 要下载的地图名称(必填) -} - -/** - * @brief 地图下载响应结果。 - */ -message AgvDownloadMapResult { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 - optional string map_content = 4; ///< 地图 JSON 文件内容(成功时填充) -} - -/** - * @brief 地图下载命令。 - */ -message RobotConfigDownloadMapCommand { - message Request { - CommandHeader.Request header = 1; - RobotConfigDownloadMapRequestData data = 2; - } - message Feedback { - CommandHeader.Feedback header = 1; - AgvDownloadMapResult status = 2; - } -} - - -// ============================================================================ -// 5. 地图状态查询(命令码 1300, 0x0514) -// ============================================================================ - -/** - * @brief 单个地图文件信息。 - */ -message MapFileInfo { - optional string name = 1; ///< 文件名 - optional string modified = 2; ///< 最后修改时间 - optional int64 size = 3; ///< 文件大小(字节) -} - -/** - * @brief 地图状态响应结构。 - * @note 对应仙工 API 1300(0x0514),返回当前地图及所有地图列表。 - */ -message AgvMapStatus { - optional string current_map = 1; ///< 当前加载的地图名称 - optional string current_map_md5 = 2; ///< 当前地图的 MD5 校验值 - repeated string maps = 3; ///< 所有地图名称列表 - repeated MapFileInfo map_files_info = 4; ///< 每个地图文件的详细信息 - optional int32 ret_code = 5; ///< 返回码,0 表示成功 - optional string create_on = 6; ///< 时间戳 - optional string err_msg = 7; ///< 错误信息 -} - -/** - * @brief 地图状态查询命令(无请求数据)。 - */ -message RobotStatusMapCommand { +// 查询 AGV 运行状态命令。 +message AgvRuntimeStateCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - AgvMapStatus status = 2; + // AGV 当前运行状态快照。 + cmvr.msgs.AgvRuntimeState state = 2; } } - -// ============================================================================ -// 6. 上传地图(命令码 4010, 0x0FAA) -// ============================================================================ - -/** - * @brief 上传地图请求数据。 - */ -message RobotConfigUploadMapRequestData { - optional string map_content = 1; ///< 完整的地图 JSON 字符串(必填) -} - -/** - * @brief 上传地图响应结果。 - */ -message AgvUploadMapResult { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 -} - -/** - * @brief 上传地图命令。 - */ -message RobotConfigUploadMapCommand { +// 查询 AGV 当前导航任务状态命令。 +message AgvNavigationStatusCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; - RobotConfigUploadMapRequestData data = 2; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - AgvUploadMapResult status = 2; + // 当前导航任务状态。 + cmvr.msgs.AgvNavigationStatus status = 2; } } - -// ============================================================================ -// 7. 抢占控制权(命令码 4005, 0x0FA5) -// ============================================================================ - -/** - * @brief 抢占控制权请求数据。 - */ -message RobotConfigLockRequestData { - optional string nick_name = 1; ///< 抢占者昵称/标识(必填) -} - -/** - * @brief 抢占控制权响应结果。 - */ -message AgvLockResult { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 -} - -/** - * @brief 抢占控制权命令。 - */ -message RobotConfigLockCommand { +// 导航到指定地图位姿命令。 +message AgvNavigateToPoseCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; - RobotConfigLockRequestData data = 2; + // 目标位姿。x/y 单位:米,theta 单位:弧度。 + cmvr.msgs.AgvPose2d pose = 2; + // 通用运动约束和执行选项。 + cmvr.msgs.AgvMotionOptions options = 3; + // AGV 适配器扩展参数,用于传递厂商特有选项。 + cmvr.msgs.AgvAdapterParams adapter_params = 4; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - AgvLockResult status = 2; } } - -// ============================================================================ -// 8. 查询当前控制权所有者(命令码 1060, 0x0424) -// ============================================================================ - -/** - * @brief 当前控制权所有者响应结构。 - * @note 对应仙工 API 1060(0x0424)。 - */ -message AgvCurrentLockStatus { - optional bool locked = 1; ///< 是否被锁定(有持有者) - optional string ip = 2; ///< 持有者 IP 地址 - optional int32 port = 3; ///< 持有者端口 - optional uint32 type = 4; ///< 持有者类型(0=default, 2=roboshop, 0xDD=srd) - optional string nick_name = 5; ///< 持有者昵称 - optional int64 time_t = 6; ///< 锁定时间戳(Unix 秒) - optional string desc = 7; ///< 描述信息 - optional int32 ret_code = 8; ///< 返回码,0 表示成功 - optional string create_on = 9; ///< 时间戳 - optional string err_msg = 10; ///< 错误信息 -} - -/** - * @brief 查询控制权命令(无请求数据)。 - */ -message RobotStatusCurrentLockCommand { +// 导航到指定站点命令。 +message AgvNavigateToStationCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; + // 目标站点 id。 + string station_id = 2; + // 通用运动约束和执行选项。 + cmvr.msgs.AgvMotionOptions options = 3; + // AGV 适配器扩展参数,用于传递厂商特有选项。 + cmvr.msgs.AgvAdapterParams adapter_params = 4; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - AgvCurrentLockStatus status = 2; } } - -// ============================================================================ -// 9. 开环速度运动控制(命令码 2010, 0x07DA) -// ============================================================================ - -/** - * @brief 开环速度运动控制请求数据。 - * @note 命令码 2010(0x07DA)。下发后会强制取消当前自动导航任务。 - * 多舵轮设备仅 vx/vy/w 生效;steer/real_steer 仅单舵轮设备有效。 - * duration = -1 表示持续运行直到下一次指令。 - */ -message RobotMotionControlRequestData { - optional double vx = 1; ///< X 方向线速度(m/s) - optional double vy = 2; ///< Y 方向线速度(m/s) - optional double w = 3; ///< 角速度(rad/s),逆时针为正 - optional double steer = 4; ///< 舵轮转向角(单舵轮,单位 rad) - optional double real_steer = 5; ///< 实际舵轮角度(单舵轮,优先级高于 steer) - optional int64 duration = 6; ///< 持续时间(ms),-1 表示一直运行 -} - -/** - * @brief 开环运动控制响应结果。 - */ -message RobotMotionControlResult { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 -} - -/** - * @brief 开环运动控制命令。 - */ -message RobotMotionControlCommand { +// 按显式站点路径导航命令。 +message AgvFollowPathCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; - RobotMotionControlRequestData data = 2; + // 路径段列表。每段包含起点站点 id 和终点站点 id。 + repeated cmvr.msgs.AgvPathSegment path = 2; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - RobotMotionControlResult status = 2; } } - -// ============================================================================ -// 10. 切换载入地图(命令码 2022, 0x07E6) -// ============================================================================ - -/** - * @brief 切换地图请求数据。 - * @note 命令码 2022(0x07E6)。目标地图必须已存在于机器人中。 - */ -message RobotLoadMapRequestData { - optional string map_name = 1; ///< 目标地图名称(必填,仅字母数字-_) -} - -/** - * @brief 切换地图响应结果。 - */ -message RobotLoadMapResult { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 -} - -/** - * @brief 切换地图命令。 - */ -message RobotLoadMapCommand { +// 下发底盘速度命令。 +message AgvSetVelocityCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; - RobotLoadMapRequestData data = 2; + // 目标车体速度。vx/vy 单位:米/秒,wz 单位:弧度/秒。 + cmvr.msgs.AgvVelocity velocity = 2; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - RobotLoadMapResult status = 2; } } - -// ============================================================================ -// 11. 查询地图载入状态(命令码 1022, 0x03FE) -// ============================================================================ - -/** - * @brief 地图载入状态响应。 - * @note 命令码 1022(0x03FE)。loadmap_status: 0=失败, 1=成功, 2=载入中。 - * 载入中(2)时禁止执行重定位操作。 - */ -message RobotQueryLoadMapStatusResult { - optional int32 loadmap_status = 1; ///< 0=失败, 1=成功, 2=载入中 - optional int32 ret_code = 2; ///< 返回码,0 表示成功 - optional string create_on = 3; ///< 时间戳 - optional string err_msg = 4; ///< 错误信息 -} - -/** - * @brief 查询地图载入状态命令(无请求数据)。 - */ -message RobotQueryLoadMapStatusCommand { +// 查询可用地图列表命令。 +message AgvListMapsCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - RobotQueryLoadMapStatusResult status = 2; + // 地图名称列表。 + repeated string maps = 2; } } - -// ============================================================================ -// 12. 查询站点列表(命令码 1301, 0x0515) -// ============================================================================ - -/** - * @brief 单个站点信息。 - */ -message StationItem { - optional string id = 1; ///< 站点唯一 ID - optional string type = 2; ///< 站点类型(如 "LocationMark", "ChargePoint") - optional double x = 3; ///< X 坐标(米) - optional double y = 4; ///< Y 坐标(米) - optional double r = 5; ///< 朝向角(弧度) - optional string desc = 6; ///< 描述信息 - optional string executor = 7; ///< 执行器信息 - optional string prepoint = 8; ///< 前置点 ID - optional string recfile = 9; ///< 识别文件路径 - optional bool spin = 10; ///< 是否允许自旋 - optional bool use_down_pgv = 11; ///< 是否使用下视 PGV -} - -/** - * @brief 站点列表响应结果。 - */ -message QueryStationListResult { - repeated StationItem stations = 1; ///< 站点列表 - optional int32 ret_code = 2; ///< 返回码,0 表示成功 - optional string create_on = 3; ///< 时间戳 - optional string err_msg = 4; ///< 错误信息 -} - -/** - * @brief 查询站点列表命令(无请求数据)。 - */ -message QueryStationListCommand { +// 查询当前地图站点列表命令。 +message AgvListStationsCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - QueryStationListResult status = 2; + // 当前地图中的站点列表。 + repeated cmvr.msgs.AgvStation stations = 2; } } - -// ============================================================================ -// 13. 指定路径导航(命令码 3066, 0x0BFA) -// ============================================================================ - -/** - * @brief 单段导航任务单元。 - * @note 用于 3066 命令的 move_task_list 数组。 - * source_id 和 id 之间必须有直接路径,不可跳点。 - */ -message MoveTaskItem { - optional string task_id = 1; ///< 任务唯一 ID(必填) - optional string source_id = 2; ///< 起始站点 ID(必填) - optional string id = 3; ///< 目标站点 ID(必填) - optional string operation = 4; ///< 到达后执行的动作(如 "JackLoad") - optional double jack_height = 5; ///< 顶升高度(米) -} - -/** - * @brief 指定路径导航请求数据。 - */ -message RobotGoTargetListRequestData { - repeated MoveTaskItem move_task_list = 1; ///< 导航任务序列(顺序执行) -} - -/** - * @brief 指定路径导航响应结果。 - * @note ret_code=0 仅表示指令被接收,不表示执行完成。 - */ -message RobotGoTargetListResult { - optional int32 ret_code = 1; ///< 返回码,0 表示成功接收 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 -} - -/** - * @brief 指定路径导航命令。 - */ -message RobotGoTargetListCommand { +// 地图上传、下载、切换等通用地图命令。 +message AgvMapCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; - RobotGoTargetListRequestData data = 2; + // 地图名称。切换/下载时表示目标地图,上传时表示写入的地图名称。 + string map_name = 2; + // 地图内容。上传地图时使用;下载或切换地图时可为空。 + string content = 3; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - RobotGoTargetListResult status = 2; + // 地图内容。下载地图时返回;其他命令通常为空。 + string content = 2; } } - -// ============================================================================ -// 14. 查询当前实时导航状态(命令码 1020, 0x03FC) -// ============================================================================ - -/** - * @brief 1020 命令请求数据。 - */ -message RobotStatusTaskReqData { - optional bool simple = 1; ///< true=仅返回 task_status,false=全量 -} - -/** - * @brief 导航任务中的料箱信息。 - */ -message NavContainerItem { - optional string container_name = 1; ///< 料箱名称 - optional string desc = 2; ///< 描述 - optional string goods_id = 3; ///< 绑定的货物 ID - optional bool has_goods = 4; ///< 是否已绑定货物 -} - -/** - * @brief 1020 命令响应数据。 - */ -message RobotStatusTaskResData { - optional int32 task_status = 1; ///< 0=NONE, 1=WAITING, 2=RUNNING, 3=SUSPENDED, 4=COMPLETED, 5=FAILED, 6=CANCELED - optional int32 task_type = 2; ///< 0=无, 1=自由导航到坐标, 2=自由导航到站点, 3=路径导航到站点, 7=平动转动 - optional string target_id = 3; ///< 目标站点 ID(task_type 为 2/3 时) - repeated double target_point = 4; ///< 目标坐标 [x, y, r](task_type 为 1 时) - repeated string finished_path = 5; ///< 已经过的站点列表 - repeated string unfinished_path = 6; ///< 尚未经过的站点列表 - optional string move_status_info = 7; ///< 附加信息(如错误描述) - repeated NavContainerItem containers = 8; ///< 料箱信息 - optional int32 ret_code = 9; ///< 返回码,0 表示成功 - optional string create_on = 10; ///< 时间戳 - optional string err_msg = 11; ///< 错误信息 -} - -/** - * @brief 查询当前导航状态命令。 - */ -message RobotStatusTaskCurrentCommand { +// 开始建图/扫图命令。 +message AgvStartMappingCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; - RobotStatusTaskReqData data = 2; + // 请求建图维度:2D、3D 或二者都要。未指定时由适配器选择最合适模式。 + cmvr.msgs.AgvMapDimension dimension = 2; + // 目标地图名称。为空表示由 AGV 或适配器创建/选择默认地图名。 + string map_name = 3; + // 是否请求实时建图更新。true 表示希望实时推送;false 表示允许离线/批处理。 + bool real_time = 4; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - RobotStatusTaskResData data = 2; + // 建图会话 id。该值由服务端生成,作为调试和日志关联标识。 + string session_id = 2; } } - -// ============================================================================ -// 15. 批量查询任务状态(命令码 1110, 0x0456) -// ============================================================================ - -/** - * @brief 1110 命令请求数据。 - */ -message QueryTaskStatusPackageReqData { - repeated string task_ids = 1; ///< 要查询的任务 ID 列表;为空则查所有未完成 + 最近一条完成 -} - -/** - * @brief 单条任务状态项。 - */ -message SingleTaskStatusItem { - optional string task_id = 1; ///< 任务 ID - optional int32 status = 2; ///< 状态码(同 task_status) - optional int32 type = 3; ///< 任务类型(同 task_type) -} - -/** - * @brief 任务状态包(包含最近完成和所有未完成的任务)。 - */ -message TaskStatusPackage { - optional string closest_target = 1; ///< 最近站点 ID - optional string source_name = 2; ///< 起点站点名称 - optional string target_name = 3; ///< 终点站点名称 - optional double percentage = 4; ///< 任务进度百分比(0~100) - optional double distance = 5; ///< 剩余距离(米) - optional string info = 6; ///< 附加信息 - repeated SingleTaskStatusItem task_status_list = 7; ///< 所有任务状态列表 -} - -/** - * @brief 1110 命令响应数据。 - */ -message QueryTaskStatusPackageResData { - optional TaskStatusPackage task_status_package = 1; ///< 任务状态包 - optional int32 ret_code = 2; ///< 返回码,0 表示成功 - optional string create_on = 3; ///< 时间戳 - optional string err_msg = 4; ///< 错误信息 -} - -/** - * @brief 批量查询任务状态命令。 - */ -message RobotStatusTaskPackageCommand { +// 地图流命令。用于获取当前地图、最近地图、全量快照和后续增量更新。 +message AgvMapStreamCommand { + // 请求体。 message Request { + // 通用请求头。header.device_id 指定目标 AGV 设备。 CommandHeader.Request header = 1; - QueryTaskStatusPackageReqData data = 2; + // 请求地图维度:2D、3D 或二者都要。该字段不是厂商格式选择器。 + cmvr.msgs.AgvMapDimension dimension = 2; + // 地图名称。为空表示当前加载地图;若无当前地图,适配器应尝试使用最近保存/创建的地图。 + string map_name = 3; + // 断点续传令牌。为空表示上位机没有缓存,服务端应先发送全量快照。 + string resume_token = 4; + // 是否请求全量快照。首次请求通常应为 true。 + bool snapshot = 5; + // 是否在快照之后保持流并发送增量更新。若适配器不支持增量,可继续发送全量并标记 update_type。 + bool incremental = 6; + // 单条流消息建议最大载荷大小,单位:字节。小于等于 0 表示使用服务端默认值。 + int32 max_chunk_bytes = 7; } + // 反馈体。 message Feedback { + // 通用反馈头。包含成功标志、错误信息和反馈时间戳。 CommandHeader.Feedback header = 1; - QueryTaskStatusPackageResData data = 2; + // 统一地图更新。payload 只会是 map_2d 或 map_3d,不暴露厂商原始格式。 + cmvr.msgs.AgvUnifiedMapUpdate update = 2; } } - - -// ============================================================================ -// 16. 单点站点自动规划导航(命令码 3051, 0x0BEB) -// ============================================================================ - -/** - * @brief DI(数字输入)点位。 - */ -message DIItem { - int32 id = 1; ///< DI 编号 - bool status = 2; ///< 状态(true=高电平, false=低电平) -} - -/** - * @brief DO(数字输出)点位。 - */ -message DOItem { - int32 id = 1; ///< DO 编号 - bool status = 2; ///< 状态(true=高电平, false=低电平) -} - -/** - * @brief 音频播放参数。 - */ -message SoundArgs { - optional string name = 1; ///< 音频文件名 - optional int32 loop = 2; ///< 循环次数(0=播放一次, 1=循环) - optional int32 stop = 3; ///< 1=停止播放 -} - -/** - * @brief WaitDI 动作参数。 - */ -message WaitDIArgs { - repeated DIItem DI = 1; ///< 需要等待的 DI 条件列表 - optional double timeout = 2; ///< 超时时间(秒),0 表示无限等待 -} - -/** - * @brief SetDO 动作参数。 - */ -message SetDOArgs { - repeated DOItem do_list = 1; ///< 要设置的 DO 列表 -} - -/** - * @brief PGV(二维码)二次定位参数。 - */ -message PgvParam { - optional bool use_pgv = 1; ///< 是否使用上视 PGV - optional bool use_down_pgv = 2; ///< 是否使用下视 PGV - optional double pgv_adjust_dist = 3; ///< 最大调整半径(米) - optional double pgv_adjust_cx = 4; ///< 二维码坐标系 X 偏移(米) - optional double pgv_adjust_cy = 5; ///< 二维码坐标系 Y 偏移(米) - optional double pgv_x_adjust = 6; ///< 仅调整 X 方向误差(米) -} - -/** - * @brief 自由导航目标点(坐标 + 朝向)。 - */ -message FreeGoPoint { - double x = 1; ///< X 坐标(米) - double y = 2; ///< Y 坐标(米) - double theta = 3; ///< 朝向角(弧度) -} - -/** - * @brief 脚本自定义参数。 - */ -message ScriptArgs { - map str_kv = 1; ///< 字符串键值对 - map num_kv = 2; ///< 数字键值对 - repeated DOItem do_list = 3; ///< DO 列表 - repeated DIItem di_list = 4; ///< DI 列表 -} - -/** - * @brief 3051 命令请求数据(单点站点自动规划导航)。 - * @warning 严禁用于多车调度场景,仅限单车测试/验证。 - * 下发此任务会取消当前正在执行的任务(不排队)。 - * 成功下发后会自动清除指定的 warning/error 报错码。 - * 自由导航(freego)仅支持双轮差速底盘。 - */ -message RobotGoTargetReqData { - // -------- 必填字段 -------- - string source_id = 1; ///< 起始站点 ID("SELF_POSITION" 表示当前位置) - string id = 2; ///< 目标站点 ID("SELF_POSITION" 表示原地执行 operation) - optional string task_id = 3; ///< 任务 ID(建议提供) - - // -------- 运动通用参数 -------- - optional double angle = 4; ///< 目标点朝向角(弧度) - optional string method = 5; ///< "forward"(正走)或 "backward"(倒走) - optional double max_speed = 6; ///< 最大线速度(m/s),0 使用默认 - optional double max_wspeed = 7; ///< 最大角速度(rad/s) - optional double max_acc = 8; ///< 最大加速度(m/s²) - optional double max_wacc = 9; ///< 最大角加速度(rad/s²) - optional int64 duration = 10; ///< 到达后等待时间(毫秒) - optional int32 orientation = 11; ///< 全向车保持的角度(暂不使用) - optional bool spin = 12; ///< 是否随动(托盘旋转) - optional int64 delay = 13; ///< 延迟结束导航状态(毫秒),缺省 0 - optional int32 start_rot_dir = 14; ///< 起步旋转方向:-1=顺时针, 0=就近, 1=逆时针 - optional int32 end_rot_dir = 15; ///< 到点旋转方向:-1=顺时针, 0=就近, 1=逆时针 - optional double reach_dist = 16; ///< 到点位置精度(米) - optional double reach_angle = 17; ///< 到点角度精度(弧度) - optional string skill_name = 18; ///< 技能名称:"Action" 或 "GotoSpecifiedPose" - - // -------- PGV -------- - optional PgvParam pgv = 19; ///< 二次定位参数 - - // -------- 设备动作 -------- - optional string operation = 20; ///< 操作类型(JackLoad/ForkUnload/RollerLoad/HookLoad/WaitDI/SetDO/sound/Script 等) - optional double jack_height = 21; ///< 顶升高度(米) - optional double start_height = 22; ///< 货叉起步前举升高度(米) - optional double end_height = 23; ///< 货叉到点后举升高度(米) - optional double fork_mid_height = 24; ///< 货叉行走过程中举升高度(米) - optional double fork_dist = 25; ///< 货叉前移距离(米) - optional string direction = 26; ///< 方向:"left"/"right"/"front"/"back" - optional bool recognize = 27; ///< 是否启用视觉识别 - optional string recfile = 28; ///< 识别文件路径(如 "shelf/s0002.shelf") - - // -------- 音频 -------- - optional SoundArgs sounds_args = 29; ///< 音频参数 - - // -------- WaitDI / SetDO -------- - optional WaitDIArgs wait_di_args = 30; ///< WaitDI 参数 - optional SetDOArgs set_do_args = 31; ///< SetDO 参数 - - // -------- 脚本 -------- - optional string script_name = 32; ///< 脚本文件名 - optional ScriptArgs script_args = 33; ///< 脚本参数 - optional int32 script_stage = 34; ///< 执行阶段:0=导航前, 1=导航中, 2=导航后, 3=脚本控制导航 - - // -------- 原地旋转(GoByOdometer) -------- - optional double move_angle = 35; ///< 旋转角度(弧度) - optional double speed_w = 36; ///< 旋转角速度(rad/s) - optional int32 loc_mode = 37; ///< 定位模式:1=激光定位, 0=里程定位 - - // -------- 自由导航(仅双轮差速) -------- - optional FreeGoPoint freego = 38; ///< 自由导航目标(若提供则忽略 id 字段) -} - -/** - * @brief 3051 命令响应数据。 - */ -message RobotGoTargetResData { - optional int32 ret_code = 1; ///< 返回码,0 表示成功接收 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 -} - -/** - * @brief 单点导航命令。 - */ -message RobotGoTargetCommand { - message Request { - CommandHeader.Request header = 1; - RobotGoTargetReqData data = 2; - } - message Feedback { - CommandHeader.Feedback header = 1; - RobotGoTargetResData data = 2; - } -} - - -// ============================================================================ -// 17. 停止开环运动(命令码 2000, 0x07D0) -// ============================================================================ - -/** - * @brief 停止开环运动请求数据(无业务字段)。 - * @note 命令码 2000(0x07D0)。下发零速度指令,终止当前持续运动。 - */ -message RobotControlStopRequestData -{ -} - -/** - * @brief 停止开环运动响应结果。 - */ -message RobotControlStopResult -{ - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 -} - -/** - * @brief 停止开环运动命令。 - */ -message RobotControlStopCommand -{ - message Request - { - CommandHeader.Request header = 1; - RobotControlStopRequestData data = 2; - } - message Feedback - { - CommandHeader.Feedback header = 1; - RobotControlStopResult status = 2; - } -} - - -// ============================================================================ -// 18. 暂停/继续/取消导航任务(命令码 3001/3002/3003) -// ============================================================================ - -/** - * @brief 暂停当前导航任务(命令码 3001, 0x0BB9)。 - * @note 请求无业务数据。 - */ -message RobotTaskPauseCommand { - message Request { - CommandHeader.Request header = 1; - // 无 data 字段 - } - message Feedback { - CommandHeader.Feedback header = 1; - /** - * @brief 暂停结果。 - */ - message Result { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 - } - Result status = 2; - } -} - -/** - * @brief 继续当前导航任务(命令码 3002, 0x0BBA)。 - * @note 请求无业务数据。 - */ -message RobotTaskResumeCommand { - message Request { - CommandHeader.Request header = 1; - // 无 data 字段 - } - message Feedback { - CommandHeader.Feedback header = 1; - /** - * @brief 继续结果。 - */ - message Result { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 - } - Result status = 2; - } -} - -/** - * @brief 取消当前导航任务(命令码 3003, 0x0BBB)。 - * @note 请求无业务数据。 - */ -message RobotTaskCancelCommand { - message Request { - CommandHeader.Request header = 1; - // 无 data 字段 - } - message Feedback { - CommandHeader.Feedback header = 1; - /** - * @brief 取消结果。 - */ - message Result { - optional int32 ret_code = 1; ///< 返回码,0 表示成功 - optional string create_on = 2; ///< 时间戳 - optional string err_msg = 3; ///< 错误信息 - } - Result status = 2; - } -} \ No newline at end of file diff --git a/server/proto/cmvr/api/agv_service.proto b/server/proto/cmvr/api/agv_service.proto index f914197..f0bdc5b 100644 --- a/server/proto/cmvr/api/agv_service.proto +++ b/server/proto/cmvr/api/agv_service.proto @@ -1,74 +1,72 @@ -/** - * @file agv_service.proto - * @brief 定义AGV服务的gRPC接口,聚合所有AGV相关命令。 - * 服务端实现类为 gRPCAGVServiceImpl。 - */ syntax = "proto3"; -import "cmvr/api/agv_command.proto"; - package cmvr.api; +import "cmvr/api/common.proto"; +import "cmvr/api/agv_command.proto"; + +// AGV 通用服务。该服务只暴露控制器无关的能力, +// 厂商协议、地图文件格式和控制器特有参数由具体 AGV 适配器内部处理。 service AgvService { - // 基本控制 - rpc GetStatusInfo(GetAgvStatusInfoCommand.Request) returns (GetAgvStatusInfoCommand.Feedback); + // 获取 AGV 当前运行状态快照。 + rpc getRuntimeState(AgvRuntimeStateCommand.Request) returns (AgvRuntimeStateCommand.Feedback); - rpc GetBatteryStatus(RobotStatusBatteryCommand.Request) returns (RobotStatusBatteryCommand.Feedback); + // 获取当前导航任务状态。 + rpc getNavigationStatus(AgvNavigationStatusCommand.Request) returns (AgvNavigationStatusCommand.Feedback); - rpc GetRobotLocation(RobotStatusLocCommand.Request) returns (RobotStatusLocCommand.Feedback); + // 执行急停或等效安全停止动作。 + rpc emergencyStop(CommandHeader.Request) returns (CommandHeader.Feedback); - rpc RobotConfigDownloadMap(RobotConfigDownloadMapCommand.Request) returns (RobotConfigDownloadMapCommand.Feedback); + // 清除可恢复故障或告警。 + rpc clearFault(CommandHeader.Request) returns (CommandHeader.Feedback); + // 导航到指定地图位姿。目标位姿 x/y 单位为米,theta 单位为弧度。 + rpc navigateToPose(AgvNavigateToPoseCommand.Request) returns (AgvNavigateToPoseCommand.Feedback); - rpc GetMapStatus(RobotStatusMapCommand.Request) returns (RobotStatusMapCommand.Feedback); + // 导航到指定地图站点。 + rpc navigateToStation(AgvNavigateToStationCommand.Request) returns (AgvNavigateToStationCommand.Feedback); + // 按显式站点路径执行导航。 + rpc followPath(AgvFollowPathCommand.Request) returns (AgvFollowPathCommand.Feedback); - rpc RobotConfigUploadMap(RobotConfigUploadMapCommand.Request) returns (RobotConfigUploadMapCommand.Feedback); + // 暂停当前导航任务。 + rpc pauseNavigation(CommandHeader.Request) returns (CommandHeader.Feedback); - // 抢占机器人控制权 - rpc RobotConfigLock(RobotConfigLockCommand.Request) returns (RobotConfigLockCommand.Feedback); + // 恢复已暂停的导航任务。 + rpc resumeNavigation(CommandHeader.Request) returns (CommandHeader.Feedback); - // 查询当前控制权所有者 - rpc GetCurrentLockStatus(RobotStatusCurrentLockCommand.Request) returns (RobotStatusCurrentLockCommand.Feedback); + // 取消当前导航任务。 + rpc cancelNavigation(CommandHeader.Request) returns (CommandHeader.Feedback); - // 开环速度运动控制 - rpc RobotMotionControl(RobotMotionControlCommand.Request) returns (RobotMotionControlCommand.Feedback); + // 下发底盘速度控制指令。vx/vy 单位为米/秒,wz 单位为弧度/秒。 + rpc setVelocity(AgvSetVelocityCommand.Request) returns (AgvSetVelocityCommand.Feedback); - // 切换载入地图 命令码2022 - rpc RobotLoadMap(RobotLoadMapCommand.Request) returns (RobotLoadMapCommand.Feedback); + // 停止底盘速度控制。该接口不等价于取消导航任务。 + rpc stopVelocityControl(CommandHeader.Request) returns (CommandHeader.Feedback); + // 查询 AGV 控制器可用地图名称列表。 + rpc listMaps(AgvListMapsCommand.Request) returns (AgvListMapsCommand.Feedback); - // 查询地图载入状态 命令码1022 - rpc QueryLoadMapStatus(RobotQueryLoadMapStatusCommand.Request) returns (RobotQueryLoadMapStatusCommand.Feedback); + // 查询当前地图中的站点列表。 + rpc listStations(AgvListStationsCommand.Request) returns (AgvListStationsCommand.Feedback); + // 切换当前使用地图。 + rpc switchMap(AgvMapCommand.Request) returns (AgvMapCommand.Feedback); - // 查询当前地图站点列表 命令码1301 - rpc QueryStationList(QueryStationListCommand.Request) returns (QueryStationListCommand.Feedback); + // 上传地图内容到 AGV 控制器。地图内容字段由适配器解释。 + rpc uploadMap(AgvMapCommand.Request) returns (AgvMapCommand.Feedback); + // 下载指定地图内容。 + rpc downloadMap(AgvMapCommand.Request) returns (AgvMapCommand.Feedback); - // 指定路径导航 命令码3066 - rpc RobotGoTargetList(RobotGoTargetListCommand.Request) returns (RobotGoTargetListCommand.Feedback); + // 开始建图/扫图会话。请求只选择 2D、3D 或二者都要, + // 控制器特有地图格式由 AGV 适配器内部转换。 + rpc startMapping(AgvStartMappingCommand.Request) returns (AgvStartMappingCommand.Feedback); - // 查询当前导航状态 1020 robot_status_task_req - // 1020 查询当前实时导航 robot_status_task_req - rpc RobotStatusTaskCurrent(RobotStatusTaskCurrentCommand.Request) returns (RobotStatusTaskCurrentCommand.Feedback); + // 以服务端流方式发送统一地图。resume_token 为空时应先发送全量快照; + // 后续是否发送增量由 AGV 适配器能力决定,并通过 update_type 标记。 + rpc streamMap(AgvMapStreamCommand.Request) returns (stream AgvMapStreamCommand.Feedback); - // 批量查询任务状态 1110 robot_status_task_status_package_req - rpc RobotStatusTaskPackage(RobotStatusTaskPackageCommand.Request) returns (RobotStatusTaskPackageCommand.Feedback); - - - // 3051 单点站点自动规划导航 robot_task_gotarget_req 0x0BEB - rpc RobotGoTarget(RobotGoTargetCommand.Request) returns (RobotGoTargetCommand.Feedback); - - - - // 0x07D0 停止开环运动 - rpc RobotControlStop(RobotControlStopCommand.Request) returns (RobotControlStopCommand.Feedback); - - // 暂停当前导航任务 命令码 3001 (0x0BB9) - rpc RobotTaskPause(RobotTaskPauseCommand.Request) returns (RobotTaskPauseCommand.Feedback); - // 继续当前导航任务 命令码 3002 (0x0BBA) - rpc RobotTaskResume(RobotTaskResumeCommand.Request) returns (RobotTaskResumeCommand.Feedback); - // 取消当前导航任务 命令码 3003 (0x0BBB) - rpc RobotTaskCancel(RobotTaskCancelCommand.Request) returns (RobotTaskCancelCommand.Feedback); -} \ No newline at end of file + // 停止当前建图/扫图会话。 + rpc stopMapping(CommandHeader.Request) returns (CommandHeader.Feedback); +} diff --git a/server/proto/cmvr/msgs/agv.proto b/server/proto/cmvr/msgs/agv.proto new file mode 100644 index 0000000..54439ee --- /dev/null +++ b/server/proto/cmvr/msgs/agv.proto @@ -0,0 +1,310 @@ +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 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 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; +} diff --git a/src/api/agv.js b/src/api/agv.js index 3b5dd0a..29de072 100644 --- a/src/api/agv.js +++ b/src/api/agv.js @@ -5,8 +5,8 @@ import request from '@/utils/request' * @param {Object} params * @param {string} [params.deviceId] - 设备ID,默认 agv_src1100 */ -export function getCurrentMapName(params) { - return request('/api/agv/getCurrentMapName', params, 'POST') +export function getRuntimeState(params) { + return request('/api/agv/getRuntimeState', params, 'POST') } export function getCurrentMap(params) { diff --git a/src/stores/robot.js b/src/stores/robot.js index dfd3d9c..77def62 100644 --- a/src/stores/robot.js +++ b/src/stores/robot.js @@ -3,12 +3,18 @@ import { defineStore } from 'pinia' // 唯一id:robot export const useRobotStore = defineStore('robot', { state: () => ({ - ip: '192.168.0.109:50052', - agvDeviceId:'agv_src2200', + ip: '192.168.1.110:50052', + agvDeviceId:'src1100', almDeviceId: 'aubo_arm', - position: { x: 0, y: 0, angle: 0 }, - battery: 100, - status: 'idle' + position: { x: 0, y: 0, theta: 0 }, + battery: { + percentage: 0.99, + voltage: -0, + current: -0, + temperature: -0, + charging: false + }, + current_map: '' }), getters: { // 获取机器人坐标 @@ -30,14 +36,15 @@ export const useRobotStore = defineStore('robot', { this.almDeviceId = str }, // 更新机器人位置 - setPosition(x, y, angle) { - this.position.x = x - this.position.y = y - this.position.angle = angle + setPosition(data = {}) { + this.position = data }, // 修改状态 - setStatus(val) { - this.status = val + setBattery(data = {}) { + this.battery = data + }, + setCurrentMap(str = '') { + this.current_map = str }, // 重置仓库 resetRobot() { diff --git a/src/views/Address.vue b/src/views/Address.vue index 008ccf8..5691258 100644 --- a/src/views/Address.vue +++ b/src/views/Address.vue @@ -25,7 +25,7 @@