Compare commits
2 Commits
af67751937
...
edb01463ff
| Author | SHA1 | Date | |
|---|---|---|---|
| edb01463ff | |||
| b54c2936be |
123
README.md
123
README.md
@ -139,119 +139,16 @@ sudo script/ethercat/stop_ethercat.sh eno1
|
|||||||
sudo script/ethercat/stop_ethercat.sh eno1 --restore-network
|
sudo script/ethercat/stop_ethercat.sh eno1 --restore-network
|
||||||
```
|
```
|
||||||
|
|
||||||
## MotorService 与 Modbus TCP PLC
|
## 组件文档
|
||||||
|
|
||||||
工程包含从 gRPC `MotorService`、`MotorManager`、`AbstractMotor` 到
|
具体能力、配置、协议和安全边界由对应代码目录下的 README 维护:
|
||||||
`ModbusTcpMotorBusRuntime` 的 CMVR PLC v1 电机控制链,x86-64 的 libmodbus
|
|
||||||
3.1.11 已放在 `dependency/x86/third_party/modbus/3.1.11`。
|
|
||||||
|
|
||||||
PLC 对接时特别注意:
|
- [MotorService gRPC 接口](cmvr-es/service/README.md#motorservice)
|
||||||
|
- [电机设备模块](cmvr-es/devices/motor/README.md)
|
||||||
|
- [Modbus TCP PLC runtime](cmvr-es/devices/motor/bus_runtime/modbus_tcp/README.md)
|
||||||
|
- [MotorService 与 CMVR PLC v1 完整协议](docs/motor_service_modbus_tcp.md)
|
||||||
|
- [AUBO 控制柜 Standard 数字 IO](cmvr-es/devices/arm/aubo_arm/README.md)
|
||||||
|
- [配置与部署规则](cmvr-es/config/README.md)
|
||||||
|
|
||||||
- `host` 必须配置为 IPv4 字面量,PLC boot ID 必须非零且每次重启变化;
|
Modbus Quick Stop 只是功能性停止,不能替代硬接线急停或驱动器 STO。AUBO
|
||||||
- owner 决策、命令 ACK 都必须回显对应 session,重连不得执行旧 mailbox;
|
JSON 接口只访问控制柜 Standard 数字 IO,不访问安全 IO。
|
||||||
- PLC 在进程启动时可以离线;连接 supervisor 会继续退避重试,离线期间状态
|
|
||||||
返回不可用且运动命令不会写 mailbox;
|
|
||||||
- 状态区按 odd/even seqlock 发布,上位机使用
|
|
||||||
sequence-before → 64-word block → sequence-after 三段读取验证;
|
|
||||||
- 每次 `OpenCyclicPosition/Velocity` 创建新 stream epoch,PLC 必须原子清零
|
|
||||||
`last_applied_cyclic_sequence`、旧样本去重状态和 cyclic watchdog,确认
|
|
||||||
`StreamActive` 与正确 mode 后才 ACK;重开后的首样本序列从 `1` 开始并必须
|
|
||||||
重新应用;
|
|
||||||
- 活动 cyclic 流跨 `connection_epoch` 后不会自动重开;旧流的当前和后续
|
|
||||||
setpoint 均被拒绝并在 Quick Stop 后终止,客户端必须新建 gRPC 流。断链前
|
|
||||||
或断链期间 pending 的 setpoint 不会应用到新 session;
|
|
||||||
- 任何清理 Quick Stop 未确认时,MotorService 都会 fail-closed 锁存,并在
|
|
||||||
成功执行 `setEnabled(true)` 前拒绝新的运动命令;
|
|
||||||
- Modbus Quick Stop 只是功能性停止,不能替代硬接线急停或驱动器 STO。
|
|
||||||
- 当前 Modbus 后端只提供 x86-64 的 libmodbus 3.1.11;`dependency/arm`
|
|
||||||
尚无对应库,因此 ARM 构建暂不支持该后端。
|
|
||||||
|
|
||||||
完整 gRPC 语义、配置样例、寄存器表、TIA Portal 要求、构建测试和安全边界见
|
|
||||||
[`docs/motor_service_modbus_tcp.md`](docs/motor_service_modbus_tcp.md)。
|
|
||||||
|
|
||||||
## AUBO 控制柜 IO
|
|
||||||
|
|
||||||
`AuboArm` 通过通用的 `executeJsonCommand` 接口提供控制柜 Standard 数字 IO
|
|
||||||
读写。第一版支持以下命令:
|
|
||||||
|
|
||||||
| `operation` | 说明 | 必填字段 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `get_di` | 读取控制柜数字输入 | `index` |
|
|
||||||
| `get_do` | 读取控制柜数字输出及其 runstate | `index` |
|
|
||||||
| `set_do` | 设置控制柜数字输出 | `index`、`value` |
|
|
||||||
|
|
||||||
JSON 命令示例:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command":"cabinet_io","operation":"get_di","index":0}
|
|
||||||
{"command":"cabinet_io","operation":"get_do","index":0}
|
|
||||||
{"command":"cabinet_io","operation":"set_do","index":0,"value":true}
|
|
||||||
```
|
|
||||||
|
|
||||||
其中 `index` 从 `0` 开始,运行时会根据控制器返回的 IO 数量检查范围。
|
|
||||||
`set_do.value` 必须是 JSON 布尔值 `true` 或 `false`,不接受 `0/1` 或字符串。
|
|
||||||
`set_do` 成功响应中的 `requested_value` 表示 SDK 已接受的请求值;需要确认控制器
|
|
||||||
当前输出状态时,再调用一次 `get_do` 读取实际值。
|
|
||||||
|
|
||||||
成功响应示例:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"command": "cabinet_io",
|
|
||||||
"operation": "get_di",
|
|
||||||
"index": 0,
|
|
||||||
"count": 16,
|
|
||||||
"value": false
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 通过 gRPC 调用
|
|
||||||
|
|
||||||
该功能复用 `cmvr.api.SystemService/ExecuteJsonCommand`。默认配置中的 gRPC
|
|
||||||
端口是 `50052`,读取 DI0:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
grpcurl -plaintext \
|
|
||||||
-d '{
|
|
||||||
"header":{"deviceId":"aubo_arm"},
|
|
||||||
"requestJson":"{\"command\":\"cabinet_io\",\"operation\":\"get_di\",\"index\":0}"
|
|
||||||
}' \
|
|
||||||
127.0.0.1:50052 \
|
|
||||||
cmvr.api.SystemService/ExecuteJsonCommand
|
|
||||||
```
|
|
||||||
|
|
||||||
设置 DO0 为高电平:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
grpcurl -plaintext \
|
|
||||||
-d '{
|
|
||||||
"header":{"deviceId":"aubo_arm"},
|
|
||||||
"requestJson":"{\"command\":\"cabinet_io\",\"operation\":\"set_do\",\"index\":0,\"value\":true}"
|
|
||||||
}' \
|
|
||||||
127.0.0.1:50052 \
|
|
||||||
cmvr.api.SystemService/ExecuteJsonCommand
|
|
||||||
```
|
|
||||||
|
|
||||||
使用源码树默认配置时,先在 `cmvr-es/config/manager/device_manager.pb.txt` 中把
|
|
||||||
`aubo_arm` 的 `enable` 改为 `true`,并在
|
|
||||||
`cmvr-es/config/devices/arm/aubo_arm.pb.txt` 中配置正确的控制器地址和登录信息,
|
|
||||||
然后重新安装配置并启动安装产物:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cmake --install build
|
|
||||||
./output/bin/cmvr_es
|
|
||||||
```
|
|
||||||
|
|
||||||
`output/bin/cmvr_es` 读取的是 `output/bin/config/`;如果进程使用显式配置路径,
|
|
||||||
应修改该配置根下的对应文件。
|
|
||||||
设备未启用或初始化失败时,gRPC 会返回 `Device not found: aubo_arm`。
|
|
||||||
|
|
||||||
### 安全约束
|
|
||||||
|
|
||||||
- 该接口只访问控制柜 Standard 数字 IO,不操作工具端 IO、可配置 IO 或安全 IO。
|
|
||||||
- `set_do` 不会修改控制器的输出 runstate。只有目标通道的 runstate 为
|
|
||||||
`StandardOutputRunState::None` 时才允许写入,否则返回
|
|
||||||
`output_managed_by_runstate`。
|
|
||||||
- 接口不会调用会重置全部输出配置的 `setDigitalOutputRunstateDefault()`。
|
|
||||||
- 模拟量 IO 涉及 domain、单位和量程,第一版暂不通过该 JSON 接口开放。
|
|
||||||
|
|||||||
@ -18,8 +18,6 @@ cmvr_es.pb.txt
|
|||||||
入口文件:
|
入口文件:
|
||||||
|
|
||||||
- [`cmvr_es.pb.txt`](cmvr_es.pb.txt)
|
- [`cmvr_es.pb.txt`](cmvr_es.pb.txt)
|
||||||
- [`cmvr_es_ume.pb.txt`](cmvr_es_ume.pb.txt):UME 主端样例
|
|
||||||
- [`cmvr_es_robot.pb.txt`](cmvr_es_robot.pb.txt):人形机械臂从端样例
|
|
||||||
- [`manager/device_manager.pb.txt`](manager/device_manager.pb.txt)
|
- [`manager/device_manager.pb.txt`](manager/device_manager.pb.txt)
|
||||||
- [`manager/task_manager.pb.txt`](manager/task_manager.pb.txt)
|
- [`manager/task_manager.pb.txt`](manager/task_manager.pb.txt)
|
||||||
|
|
||||||
@ -111,47 +109,48 @@ output/bin/protoc \
|
|||||||
|
|
||||||
该命令只验证 Proto Text 解析,不验证文件、设备、证书、网络和跨字段语义。最终仍需运行组件测试和进程烟雾测试。
|
该命令只验证 Proto Text 解析,不验证文件、设备、证书、网络和跨字段语义。最终仍需运行组件测试和进程烟雾测试。
|
||||||
|
|
||||||
## 双边遥操部署样例
|
## 双边遥操配置
|
||||||
|
|
||||||
仓库提供两个相互独立的 CMVR-ES 配置入口:
|
源码仓库保持唯一根入口 [`cmvr_es.pb.txt`](cmvr_es.pb.txt)。统一的
|
||||||
|
[`manager/device_manager.pb.txt`](manager/device_manager.pb.txt) 已声明
|
||||||
|
`ume_left`、`ume_right`、`ti5_motors` 和 `right_arm`;统一的
|
||||||
|
[`manager/task_manager.pb.txt`](manager/task_manager.pb.txt) 已声明
|
||||||
|
`ume_teleop` 和 gRPC server。角色差异不通过增加新的源码根配置文件表达,而由
|
||||||
|
两台机器各自的外部部署配置决定。
|
||||||
|
|
||||||
- UME 主端:[`cmvr_es_ume.pb.txt`](cmvr_es_ume.pb.txt),只声明
|
UME 主端部署配置应只启用本机需要的 UME 设备和 `ume_teleop` Task:
|
||||||
`ume_left` 和 `ume_right`。两条机械臂在 DeviceManager 层默认关闭,
|
|
||||||
[`devices/arm/ume_arms.pb.txt`](devices/arm/ume_arms.pb.txt) 内部的
|
- `ume_left`、`ume_right` 在 DeviceManager 层默认关闭;
|
||||||
`hardware_enabled` 也默认关闭;两层开关必须经过标定与安全验收后分别启用。
|
- [`devices/arm/ume_arms.pb.txt`](devices/arm/ume_arms.pb.txt) 内部的
|
||||||
出站 `ume_teleop` Task 默认关闭,样例不包含机器人地址或凭据。当前 Task
|
`hardware_enabled` 也默认关闭;
|
||||||
只实现会话/重连/心跳和 latest-only 指令邮箱,尚无生产算法调用
|
- 两层硬件门必须在完成 CAN 映射、限位标定和安全验收后分别启用;
|
||||||
|
- 当前 Task 只实现会话、重连、心跳和 latest-only 指令邮箱,尚无生产算法调用
|
||||||
`submitSetpoint()`,返回 effort 也尚未接入本地触觉协调器。
|
`submitSetpoint()`,返回 effort 也尚未接入本地触觉协调器。
|
||||||
- 人形机械臂从端:[`cmvr_es_robot.pb.txt`](cmvr_es_robot.pb.txt),通用 gRPC
|
|
||||||
server 可以启动,但 `ti5_motors` 和 `right_arm` 仍默认关闭。生产
|
|
||||||
`ArmTeleop` 已实现真实 `RobotArm` 适配,但服务配置的 `enable` 显式关闭且
|
|
||||||
样例哈希故意留空。`MotorRobotArm.enable_teleop_group_servo` 目前只是预留字段;
|
|
||||||
因为现有 `servoJ` 仍是逐关节顺序写,代码即使看到该字段为 true 也会拒绝能力。
|
|
||||||
必须先实现并验收原子或定时的组下发原语。因此启动 gRPC server 不等于允许遥操
|
|
||||||
执行,也不能绕过设备层硬件门。
|
|
||||||
|
|
||||||
在两台边缘设备各自的源码或安装目录运行:
|
机器人从端部署配置应只启用经过验收的机械臂设备以及所需的 gRPC server:
|
||||||
|
|
||||||
```bash
|
- `ti5_motors`、`right_arm` 默认关闭;
|
||||||
# UME 主端(源码配置)
|
- `ArmTeleop` 服务后端默认关闭,模型哈希必须由部署配置明确给出;
|
||||||
./output/bin/cmvr_es \
|
- 当前 `MotorRobotArm::servoJ()` 仍是逐关节顺序写,不满足遥操作组伺服能力门;
|
||||||
--config ./cmvr-es/config/cmvr_es_ume.pb.txt
|
- 启动 gRPC server 不代表允许遥操作执行,也不能绕过设备层硬件门。
|
||||||
|
|
||||||
# 人形机械臂从端(源码配置)
|
部署时应把完整配置树分别复制到两台机器的外部目录,并继续使用相同的标准文件名:
|
||||||
./output/bin/cmvr_es \
|
|
||||||
--config ./cmvr-es/config/cmvr_es_robot.pb.txt
|
```text
|
||||||
|
/etc/cmvr-es/ume/cmvr_es.pb.txt
|
||||||
|
/etc/cmvr-es/robot/cmvr_es.pb.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
如果使用安装后的配置副本,则相应命令为:
|
两套根配置都继续引用各自目录下同名的
|
||||||
|
`manager/device_manager.pb.txt` 和 `manager/task_manager.pb.txt`。运行命令为:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./output/bin/cmvr_es --config ./output/bin/config/cmvr_es_ume.pb.txt
|
./output/bin/cmvr_es --config /etc/cmvr-es/ume/cmvr_es.pb.txt
|
||||||
./output/bin/cmvr_es --config ./output/bin/config/cmvr_es_robot.pb.txt
|
./output/bin/cmvr_es --config /etc/cmvr-es/robot/cmvr_es.pb.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
上线前应把两套配置分别复制到两台机器的外部配置目录。主端需要填写从端地址、
|
UME 主端需要填写从端地址、会话 manifest 和认证配置;机器人从端需要填写现场
|
||||||
会话 manifest 和认证配置;从端需要换成现场机械臂设备配置,并在真实硬件测试后
|
机械臂配置。不要把生产 IP、token、私钥或设备标定值提交到仓库默认配置。
|
||||||
逐层开启。不要把生产 IP、token、私钥或设备标定值提交到仓库样例。
|
|
||||||
|
|
||||||
## 生产配置
|
## 生产配置
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
# Follower robot-side CMVR-ES profile.
|
|
||||||
#
|
|
||||||
# The RobotArm ArmTeleop backend is implemented but explicitly disabled. The
|
|
||||||
# physical arm and service backend remain closed. Current MotorRobotArm
|
|
||||||
# sequential joint writes are rejected as a teleop group-servo capability until
|
|
||||||
# an atomic/timed group primitive and its safety timing gates are accepted.
|
|
||||||
cmvr_es {
|
|
||||||
logger_config_file: "logger/logger.pb.txt"
|
|
||||||
device_manager_config_file: "manager/device_manager_robot.pb.txt"
|
|
||||||
task_manager_config_file: "manager/task_manager_robot.pb.txt"
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
# UME leader-side CMVR-ES profile.
|
|
||||||
#
|
|
||||||
# All relative paths below are resolved from this file's directory. This
|
|
||||||
# checked-in profile contains no production endpoint, credentials or hardware
|
|
||||||
# enablement.
|
|
||||||
cmvr_es {
|
|
||||||
logger_config_file: "logger/logger.pb.txt"
|
|
||||||
device_manager_config_file: "manager/device_manager_ume.pb.txt"
|
|
||||||
task_manager_config_file: "manager/task_manager_ume.pb.txt"
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
# Follower robot-side devices.
|
|
||||||
device_manager {
|
|
||||||
name: "cmvr_es_robot"
|
|
||||||
version: "0.1"
|
|
||||||
description: "CMVR humanoid follower edge system"
|
|
||||||
init_all_motors_when_no_active_joints: false
|
|
||||||
|
|
||||||
devices {
|
|
||||||
id: "ti5_motors"
|
|
||||||
type: DEVICE_TYPE_MOTOR_SYSTEM
|
|
||||||
config_file: "devices/motor/ti5_motors.pb.txt"
|
|
||||||
# Physical motor communication remains fail-closed in this example.
|
|
||||||
enable: false
|
|
||||||
}
|
|
||||||
|
|
||||||
devices {
|
|
||||||
id: "right_arm"
|
|
||||||
type: DEVICE_TYPE_ROBOT_ARM
|
|
||||||
config_file: "devices/arm/arm.pb.txt"
|
|
||||||
# Do not enable until the motor system, URDF, limits, servoJ timing and
|
|
||||||
# independent emergency-stop path have passed the robot safety checkout.
|
|
||||||
enable: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
# UME leader-side devices only.
|
|
||||||
device_manager {
|
|
||||||
name: "cmvr_es_ume"
|
|
||||||
version: "0.1"
|
|
||||||
description: "UME leader edge system"
|
|
||||||
init_all_motors_when_no_active_joints: false
|
|
||||||
|
|
||||||
devices {
|
|
||||||
id: "ume_right"
|
|
||||||
type: DEVICE_TYPE_ROBOT_ARM
|
|
||||||
config_file: "devices/arm/ume_arms.pb.txt"
|
|
||||||
# Hardware gate 1/2. Gate 2/2 is ume.hardware_enabled in the arm config.
|
|
||||||
# Keep both false until CAN mapping, limits and physical safety are verified.
|
|
||||||
enable: false
|
|
||||||
}
|
|
||||||
|
|
||||||
devices {
|
|
||||||
id: "ume_left"
|
|
||||||
type: DEVICE_TYPE_ROBOT_ARM
|
|
||||||
config_file: "devices/arm/ume_arms.pb.txt"
|
|
||||||
# Hardware gate 1/2. Gate 2/2 is ume.hardware_enabled in the arm config.
|
|
||||||
enable: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
# Follower robot-side tasks.
|
|
||||||
task_manager {
|
|
||||||
tasks {
|
|
||||||
id: "grpc_server"
|
|
||||||
type: TASK_TYPE_GRPC_SERVER
|
|
||||||
run_mode: TASK_RUN_MODE_BLOCKING_SERVICE
|
|
||||||
config_file: "tasks/grpc_server_task/grpc_server_task.pb.txt"
|
|
||||||
# The generic gRPC server may be enabled for integration. This does not
|
|
||||||
# enable a physical arm: device entries and the implemented RobotArm
|
|
||||||
# ArmTeleop adapter are explicitly disabled. Current MotorRobotArm
|
|
||||||
# sequential joint dispatch also fails the group-servo capability gate.
|
|
||||||
enable: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
# UME leader-side tasks.
|
|
||||||
task_manager {
|
|
||||||
tasks {
|
|
||||||
id: "ume_teleop"
|
|
||||||
type: TASK_TYPE_UME_TELEOP
|
|
||||||
run_mode: TASK_RUN_MODE_BLOCKING_SERVICE
|
|
||||||
config_file: "tasks/ume_teleop_task/ume_teleop_task.pb.txt"
|
|
||||||
# Fail-closed: configure the follower endpoint, expected manifest and
|
|
||||||
# transport security before enabling outbound teleoperation.
|
|
||||||
enable: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -37,12 +37,12 @@ config/cmvr_es.pb.txt
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Camera | [`camera/abstract_camera.h`](camera/abstract_camera.h) | [`camera/camera_factory.h`](camera/camera_factory.h) | UVC、RealSense、Hikvision |
|
| Camera | [`camera/abstract_camera.h`](camera/abstract_camera.h) | [`camera/camera_factory.h`](camera/camera_factory.h) | UVC、RealSense、Hikvision |
|
||||||
| AGV | [`agv/abstract_agv.h`](agv/abstract_agv.h) | [`agv/agv_factory.h`](agv/agv_factory.h) | MyAgv、SRC1100 |
|
| AGV | [`agv/abstract_agv.h`](agv/abstract_agv.h) | [`agv/agv_factory.h`](agv/agv_factory.h) | MyAgv、SRC1100 |
|
||||||
| RobotArm | [`arm/robot_arm.h`](arm/robot_arm.h) | [`arm/robot_arm_factory.h`](arm/robot_arm_factory.h) | MotorRobotArm、AUBO、Huayan |
|
| RobotArm | [`arm/robot_arm.h`](arm/robot_arm.h) | [`arm/robot_arm_factory.h`](arm/robot_arm_factory.h) | MotorRobotArm、[AUBO](arm/aubo_arm/README.md)、Huayan、UME |
|
||||||
| DexHand | [`dexhand/abstract_dexhand.h`](dexhand/abstract_dexhand.h) | [`dexhand/dexhand_factory.h`](dexhand/dexhand_factory.h) | RH56DFTP、PX6AXGen3 |
|
| DexHand | [`dexhand/abstract_dexhand.h`](dexhand/abstract_dexhand.h) | [`dexhand/dexhand_factory.h`](dexhand/dexhand_factory.h) | RH56DFTP、PX6AXGen3 |
|
||||||
| Microphone | [`microphone/abstract_microphone.h`](microphone/abstract_microphone.h) | [`microphone/microphone_factory.h`](microphone/microphone_factory.h) | FFmpeg |
|
| Microphone | [`microphone/abstract_microphone.h`](microphone/abstract_microphone.h) | [`microphone/microphone_factory.h`](microphone/microphone_factory.h) | FFmpeg |
|
||||||
| Speaker | [`speaker/abstract_speaker.h`](speaker/abstract_speaker.h) | [`speaker/speaker_factory.h`](speaker/speaker_factory.h) | FFmpeg |
|
| Speaker | [`speaker/abstract_speaker.h`](speaker/abstract_speaker.h) | [`speaker/speaker_factory.h`](speaker/speaker_factory.h) | FFmpeg |
|
||||||
| BioHead | [`biohead/abstract_biohead.h`](biohead/abstract_biohead.h) | DeviceFactory 直接创建 | BioHeadRobot |
|
| BioHead | [`biohead/abstract_biohead.h`](biohead/abstract_biohead.h) | DeviceFactory 直接创建 | BioHeadRobot |
|
||||||
| MotorSystem | `motor/motor_system/` | DeviceFactory 直接创建 | CAN/MuJoCo motor group |
|
| MotorSystem | [`motor/`](motor/README.md) | DeviceFactory 直接创建 | CAN、MuJoCo、EtherCAT、Modbus TCP PLC |
|
||||||
|
|
||||||
代码目录存在不等于已经接入配置创建链:
|
代码目录存在不等于已经接入配置创建链:
|
||||||
|
|
||||||
|
|||||||
124
cmvr-es/devices/arm/aubo_arm/README.md
Normal file
124
cmvr-es/devices/arm/aubo_arm/README.md
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# AUBO RobotArm 与控制柜 IO
|
||||||
|
|
||||||
|
`AuboArm` 是 AUBO SDK v0.27.1 的 `RobotArm` 后端。控制柜 Standard 数字 IO
|
||||||
|
通过设备通用的 `executeJsonCommand` 接口访问,远程调用复用
|
||||||
|
`cmvr.api.SystemService/ExecuteJsonCommand`,不经过 `ArmService` 或
|
||||||
|
`MotorService`。
|
||||||
|
|
||||||
|
返回 [Devices 模块指南](../../README.md) 或 [项目总览](../../../../README.md)。
|
||||||
|
|
||||||
|
## 代码与配置
|
||||||
|
|
||||||
|
- 实现:[`aubo_arm.h`](aubo_arm.h)、[`aubo_arm.cpp`](aubo_arm.cpp)
|
||||||
|
- 测试:[`tests/aubo_arm_json_command_test.cpp`](tests/aubo_arm_json_command_test.cpp)
|
||||||
|
- 设备配置:[`../../../config/devices/arm/aubo_arm.pb.txt`](../../../config/devices/arm/aubo_arm.pb.txt)
|
||||||
|
- DeviceManager 配置:
|
||||||
|
[`../../../config/manager/device_manager.pb.txt`](../../../config/manager/device_manager.pb.txt)
|
||||||
|
- SystemService 实现:
|
||||||
|
[`../../../service/grpc/src/grpc_system_service.cpp`](../../../service/grpc/src/grpc_system_service.cpp)
|
||||||
|
- Proto:[`../../../../protos/cmvr/api/system_service.proto`](../../../../protos/cmvr/api/system_service.proto)
|
||||||
|
|
||||||
|
仓库配置使用 SDK RPC 端口 `30004`。现场部署必须填写真实控制器地址和凭据,
|
||||||
|
不要把生产密码提交到默认配置。
|
||||||
|
|
||||||
|
## 控制柜 Standard 数字 IO
|
||||||
|
|
||||||
|
当前支持:
|
||||||
|
|
||||||
|
| `operation` | 说明 | 必填字段 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `get_di` | 读取控制柜数字输入 | `index` |
|
||||||
|
| `get_do` | 读取控制柜数字输出及其 runstate | `index` |
|
||||||
|
| `set_do` | 设置控制柜数字输出 | `index`、`value` |
|
||||||
|
|
||||||
|
JSON 命令:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"command":"cabinet_io","operation":"get_di","index":0}
|
||||||
|
{"command":"cabinet_io","operation":"get_do","index":0}
|
||||||
|
{"command":"cabinet_io","operation":"set_do","index":0,"value":true}
|
||||||
|
```
|
||||||
|
|
||||||
|
`index` 从 `0` 开始,运行时根据控制器返回的 IO 数量检查范围。
|
||||||
|
`set_do.value` 必须是 JSON 布尔值 `true` 或 `false`,不接受 `0/1` 或字符串。
|
||||||
|
`set_do` 成功响应中的 `requested_value` 只表示 SDK 已接受请求;确认实际输出时
|
||||||
|
必须再调用 `get_do`。
|
||||||
|
|
||||||
|
读取成功响应示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"command": "cabinet_io",
|
||||||
|
"operation": "get_di",
|
||||||
|
"index": 0,
|
||||||
|
"count": 16,
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 通过 gRPC 调用
|
||||||
|
|
||||||
|
默认 gRPC 端口为 `50052`。读取 DI0:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
grpcurl -plaintext \
|
||||||
|
-d '{
|
||||||
|
"header":{"deviceId":"aubo_arm"},
|
||||||
|
"requestJson":"{\"command\":\"cabinet_io\",\"operation\":\"get_di\",\"index\":0}"
|
||||||
|
}' \
|
||||||
|
127.0.0.1:50052 \
|
||||||
|
cmvr.api.SystemService/ExecuteJsonCommand
|
||||||
|
```
|
||||||
|
|
||||||
|
设置 DO0 为高电平:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
grpcurl -plaintext \
|
||||||
|
-d '{
|
||||||
|
"header":{"deviceId":"aubo_arm"},
|
||||||
|
"requestJson":"{\"command\":\"cabinet_io\",\"operation\":\"set_do\",\"index\":0,\"value\":true}"
|
||||||
|
}' \
|
||||||
|
127.0.0.1:50052 \
|
||||||
|
cmvr.api.SystemService/ExecuteJsonCommand
|
||||||
|
```
|
||||||
|
|
||||||
|
使用源码默认配置时:
|
||||||
|
|
||||||
|
1. 在 `cmvr-es/config/devices/arm/aubo_arm.pb.txt` 填写正确地址和登录信息;
|
||||||
|
2. 在 `cmvr-es/config/manager/device_manager.pb.txt` 将 `aubo_arm.enable`
|
||||||
|
改为 `true`;
|
||||||
|
3. 重新安装配置并启动安装产物。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cmake --install build
|
||||||
|
./output/bin/cmvr_es
|
||||||
|
```
|
||||||
|
|
||||||
|
`output/bin/cmvr_es` 默认读取 `output/bin/config/`。使用 `--config` 时,应修改
|
||||||
|
对应外部配置根。设备未启用或初始化失败时,gRPC 返回
|
||||||
|
`Device not found: aubo_arm`。
|
||||||
|
|
||||||
|
## 安全与语义边界
|
||||||
|
|
||||||
|
- 只访问控制柜 Standard 数字 IO,不访问工具端 IO、可配置 IO 或安全 IO;
|
||||||
|
- `set_do` 不修改输出 runstate;
|
||||||
|
- 只有 `StandardOutputRunState::None` 的通道允许写入,否则返回
|
||||||
|
`output_managed_by_runstate`;
|
||||||
|
- 普通访问不会调用会重置全部输出配置的
|
||||||
|
`setDigitalOutputRunstateDefault()`;
|
||||||
|
- 模拟量 IO 涉及 domain、单位和量程,当前 JSON 接口不开放;
|
||||||
|
- gRPC/JSON 返回成功不代表目标 IO 具备功能安全等级;
|
||||||
|
- 真实写测试前应确认通道用途、负载、电气隔离、默认电平和控制器程序所有权。
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build --target aubo_arm_json_command_test -j4
|
||||||
|
ctest --test-dir build \
|
||||||
|
-R '^aubo_arm_json_command_test$' \
|
||||||
|
--output-on-failure
|
||||||
|
```
|
||||||
|
|
||||||
|
该测试覆盖 JSON 校验和无硬件错误路径,不代表已在真实 AUBO 控制柜完成 DI/DO
|
||||||
|
读取、写入或 runstate 拒绝验证。
|
||||||
82
cmvr-es/devices/motor/README.md
Normal file
82
cmvr-es/devices/motor/README.md
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# Motor 设备模块
|
||||||
|
|
||||||
|
`devices/motor/` 提供电机管理、协议适配、总线 runtime 和厂商驱动。Service、
|
||||||
|
RobotArm 和业务 Task 只依赖 `MotorManager`/`AbstractMotor` 的稳定接口,不应
|
||||||
|
直接访问 libmodbus、CAN、EtherCAT 或厂商 SDK。
|
||||||
|
|
||||||
|
返回 [Devices 模块指南](../README.md) 或 [项目总览](../../../README.md)。
|
||||||
|
|
||||||
|
## 目录职责
|
||||||
|
|
||||||
|
| 目录 | 职责 |
|
||||||
|
| --- | --- |
|
||||||
|
| `manager/` | 创建 MotorGroup,按 `motor_id`/`joint_name` 暴露 `AbstractMotor` |
|
||||||
|
| `bus_runtime/` | 连接、收发、重连、watchdog 和总线生命周期 |
|
||||||
|
| `drivers/` | CANopen、EtherCAT、MuJoCo、Modbus PLC 等具体后端 |
|
||||||
|
| `drivers/modbus_plc_motor/` | 关节限位、SI 单位和 CMVR PLC v1 命令映射 |
|
||||||
|
|
||||||
|
PLC 电机链路为:
|
||||||
|
|
||||||
|
```text
|
||||||
|
gRPC MotorService
|
||||||
|
|
|
||||||
|
v
|
||||||
|
MotorManager -> AbstractMotor
|
||||||
|
|
|
||||||
|
v
|
||||||
|
CmvrPlcMotorProtocol
|
||||||
|
|
|
||||||
|
v
|
||||||
|
ModbusTcpMotorBusRuntime
|
||||||
|
|
|
||||||
|
v
|
||||||
|
libmodbus -> PLC -> 驱动器/电机
|
||||||
|
```
|
||||||
|
|
||||||
|
各层边界:
|
||||||
|
|
||||||
|
- `MotorService` 负责 API 校验、单电机控制权、deadline/cancellation 和
|
||||||
|
fail-closed Quick Stop;
|
||||||
|
- `MotorManager` 负责电机查找与统一抽象;
|
||||||
|
- `CmvrPlcMotorProtocol` 负责关节限位、SI 单位和 CMVR PLC v1 命令映射;
|
||||||
|
- `ModbusTcpMotorBusRuntime` 负责 PLC session、mailbox、ACK、状态和重连;
|
||||||
|
- PLC/驱动器必须独立实现通信 watchdog、周期 watchdog 和硬件安全动作。
|
||||||
|
|
||||||
|
## Modbus TCP PLC
|
||||||
|
|
||||||
|
实现、配置、依赖和测试入口见:
|
||||||
|
|
||||||
|
- [Modbus TCP runtime README](bus_runtime/modbus_tcp/README.md)
|
||||||
|
- [完整 MotorService/CMVR PLC v1 协议](../../../docs/motor_service_modbus_tcp.md)
|
||||||
|
- [MotorService 文档](../../service/README.md#motorservice)
|
||||||
|
- [`plc_motors.pb.txt`](../../config/devices/motor/plc_motors.pb.txt)
|
||||||
|
|
||||||
|
当前 Modbus 后端只提供 x86-64 的 libmodbus 3.1.11。ARM 目录没有对应库,
|
||||||
|
不能把 x86 ELF 复制到 ARM 设备使用。
|
||||||
|
|
||||||
|
## 安全边界
|
||||||
|
|
||||||
|
- MotorService 是单轴 API,不提供多轴同扫描周期的原子 commit;
|
||||||
|
- PLC/Modbus 的 Profile 或 cyclic 能力不能直接当成毫秒级机械臂组伺服;
|
||||||
|
- 软件 `emergencyStop`、Quick Stop 和普通 PLC 输出都不是安全急停;
|
||||||
|
- 真实设备必须具有独立的硬接线急停、安全继电器或 F-CPU/F-I/O,以及驱动器
|
||||||
|
STO 等经风险评估确定的安全链;
|
||||||
|
- 新硬件配置保持 `enable: false`,完成方向、限位、watchdog 和故障注入验证后
|
||||||
|
才能启用。
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build --target \
|
||||||
|
modbus_tcp_motor_bus_runtime_test \
|
||||||
|
grpc_motor_service_test \
|
||||||
|
grpc_motor_service_modbus_e2e_test \
|
||||||
|
-j4
|
||||||
|
|
||||||
|
ctest --test-dir build \
|
||||||
|
-R '^(modbus_tcp_motor_bus_runtime_test|grpc_motor_service_test|grpc_motor_service_modbus_e2e_test)$' \
|
||||||
|
--output-on-failure
|
||||||
|
```
|
||||||
|
|
||||||
|
端到端 fake PLC 测试需要本地 TCP bind/listen 权限。软件测试不能代替真实
|
||||||
|
S7-1215C、驱动器、STO 和断网故障台架。
|
||||||
93
cmvr-es/devices/motor/bus_runtime/modbus_tcp/README.md
Normal file
93
cmvr-es/devices/motor/bus_runtime/modbus_tcp/README.md
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# Modbus TCP PLC Runtime
|
||||||
|
|
||||||
|
本目录实现 CMVR PLC v1 的 Modbus TCP 总线 runtime。它负责 PLC 连接、身份
|
||||||
|
握手、session、心跳、重连、命令 mailbox、ACK 轮询和状态快照,不负责 gRPC
|
||||||
|
请求解析,也不提供功能安全急停。
|
||||||
|
|
||||||
|
返回 [Motor 设备模块](../../README.md) 或 [Devices 模块指南](../../../README.md)。
|
||||||
|
|
||||||
|
## 代码与配置
|
||||||
|
|
||||||
|
- [`include/modbus_tcp_client.h`](include/modbus_tcp_client.h):有界超时的
|
||||||
|
libmodbus client
|
||||||
|
- [`include/modbus_tcp_motor_bus_runtime.h`](include/modbus_tcp_motor_bus_runtime.h):
|
||||||
|
连接 supervisor、命令和状态 runtime
|
||||||
|
- [`include/cmvr_plc_register_map.h`](include/cmvr_plc_register_map.h):
|
||||||
|
CMVR PLC v1 寄存器常量
|
||||||
|
- [`src/modbus_tcp_client.cpp`](src/modbus_tcp_client.cpp)
|
||||||
|
- [`src/modbus_tcp_motor_bus_runtime.cpp`](src/modbus_tcp_motor_bus_runtime.cpp)
|
||||||
|
- [`tests/modbus_tcp_motor_bus_runtime_test.cpp`](tests/modbus_tcp_motor_bus_runtime_test.cpp)
|
||||||
|
- [`../../../../config/devices/motor/plc_motors.pb.txt`](../../../../config/devices/motor/plc_motors.pb.txt)
|
||||||
|
|
||||||
|
完整寄存器表、TIA Portal 数据块、gRPC 语义和台架步骤由
|
||||||
|
[MotorService 与 CMVR PLC v1 完整协议](../../../../../docs/motor_service_modbus_tcp.md)
|
||||||
|
统一维护。
|
||||||
|
|
||||||
|
## 连接与协议约束
|
||||||
|
|
||||||
|
- `host` 必须是 IPv4 字面量,避免 DNS 让建连或停止出现无界等待;
|
||||||
|
- PLC boot ID 必须非零且每次 PLC 重启变化;
|
||||||
|
- owner 决策和命令 ACK 必须回显当前 session,旧 session 的 mailbox 不得执行;
|
||||||
|
- runtime `start()` 启动连接 supervisor,PLC 可以在进程启动时离线;
|
||||||
|
- 离线期间状态不可用,运动命令必须在写 mailbox 前失败;
|
||||||
|
- 重连必须重新完成身份、版本、boot ID 和 session 握手,不得重放旧命令;
|
||||||
|
- 状态区按 odd/even seqlock 发布,CMVR 使用
|
||||||
|
sequence-before → 64-word block → sequence-after 三段读取;
|
||||||
|
- payload 必须先完整写入,commit sequence 最后写入,PLC 只原子消费新的
|
||||||
|
commit;
|
||||||
|
- Quick Stop、Disable、故障和通信 watchdog 的状态必须通过当前 session
|
||||||
|
的 ACK/状态确认,不能把本地写成功解释为驱动器已经安全停止。
|
||||||
|
|
||||||
|
## Cyclic stream
|
||||||
|
|
||||||
|
每次 `OpenCyclicPosition/Velocity` 都创建新的轴级 stream epoch。PLC 必须在
|
||||||
|
同一个原子状态事务中:
|
||||||
|
|
||||||
|
1. 清零 `last_applied_cyclic_sequence`;
|
||||||
|
2. 清理旧样本去重状态;
|
||||||
|
3. 重置 cyclic watchdog;
|
||||||
|
4. 设置正确的 CSP/CSV mode;
|
||||||
|
5. 发布 `StreamActive=1` 后再 ACK。
|
||||||
|
|
||||||
|
重开后的首个样本序列从 `1` 开始,必须重新应用。活动 cyclic 流跨
|
||||||
|
`connection_epoch` 后不会自动重开;旧流的当前和后续 setpoint 都被拒绝,
|
||||||
|
Quick Stop 后客户端必须建立新的 gRPC 流。断链前或断链期间 pending 的
|
||||||
|
setpoint 不得进入新 session。
|
||||||
|
|
||||||
|
## 依赖与平台
|
||||||
|
|
||||||
|
x86-64 的 libmodbus 3.1.11 位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dependency/x86/third_party/modbus/3.1.11
|
||||||
|
```
|
||||||
|
|
||||||
|
`dependency/arm/third_party/` 当前没有对应 libmodbus,因此 ARM 构建不支持
|
||||||
|
该后端。支持 ARM 前必须为目标 ABI 单独编译并验证库,不能复用 x86 二进制。
|
||||||
|
|
||||||
|
## 安全边界
|
||||||
|
|
||||||
|
标准 S7-1215C DC/DC/DC 不是 failsafe PLC。Modbus Quick Stop、
|
||||||
|
MotorService `emergencyStop`、普通 OB/FB 和普通数字输出都只是功能性控制,
|
||||||
|
不能替代:
|
||||||
|
|
||||||
|
- 硬接线急停;
|
||||||
|
- 安全继电器或 F-CPU/F-I/O;
|
||||||
|
- 驱动器双通道 STO;
|
||||||
|
- 接触器、抱闸反馈与必要的 EDM。
|
||||||
|
|
||||||
|
PLC 侧通信 watchdog 和 cyclic watchdog 必须在没有 CMVR 进程参与时独立停止
|
||||||
|
危险运动。真实启用前必须在禁能或脱载轴上验证寄存器、方向、限位、断网、PLC
|
||||||
|
重启、交换机故障和 Quick Stop 失败。
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build --target modbus_tcp_motor_bus_runtime_test -j4
|
||||||
|
ctest --test-dir build \
|
||||||
|
-R '^modbus_tcp_motor_bus_runtime_test$' \
|
||||||
|
--output-on-failure
|
||||||
|
```
|
||||||
|
|
||||||
|
fake PLC 测试需要本地 TCP bind/listen 权限。测试通过只证明软件协议和故障注入
|
||||||
|
路径,不代表真实 PLC、驱动器或硬件安全链已经验收。
|
||||||
@ -21,6 +21,42 @@ gRPC 和 QUIC 的职责边界:
|
|||||||
- 实时音视频使用 QUIC DATAGRAM;
|
- 实时音视频使用 QUIC DATAGRAM;
|
||||||
- `quic_edge/` 不是平台 Gateway,也不是浏览器服务器。
|
- `quic_edge/` 不是平台 Gateway,也不是浏览器服务器。
|
||||||
|
|
||||||
|
## MotorService
|
||||||
|
|
||||||
|
`MotorService` 将 gRPC 电机命令适配到已经由 `DeviceManager` 创建的
|
||||||
|
`MotorManager` 和 `AbstractMotor`,不直接持有 PLC、现场总线或厂商驱动。
|
||||||
|
|
||||||
|
关键文件:
|
||||||
|
|
||||||
|
- Proto:[`../../protos/cmvr/api/motor_service.proto`](../../protos/cmvr/api/motor_service.proto)
|
||||||
|
和 [`../../protos/cmvr/api/motor_command.proto`](../../protos/cmvr/api/motor_command.proto)
|
||||||
|
- 实现:[`grpc/include/grpc_motor_service.h`](grpc/include/grpc_motor_service.h)
|
||||||
|
和 [`grpc/src/grpc_motor_service.cpp`](grpc/src/grpc_motor_service.cpp)
|
||||||
|
- 注册:[`../task/grpc_server_task/src/grpc_server_task.cpp`](../task/grpc_server_task/src/grpc_server_task.cpp)
|
||||||
|
- 单元测试:[`grpc/tests/grpc_motor_service_test.cpp`](grpc/tests/grpc_motor_service_test.cpp)
|
||||||
|
- gRPC–Modbus 端到端测试:
|
||||||
|
[`grpc/tests/grpc_motor_service_modbus_e2e_test.cpp`](grpc/tests/grpc_motor_service_modbus_e2e_test.cpp)
|
||||||
|
|
||||||
|
服务按单电机仲裁。同步 Profile 命令、Cyclic Position/Velocity 双向流、
|
||||||
|
`setEnabled`、状态读取和软件 `emergencyStop` 共用同一控制权状态:
|
||||||
|
|
||||||
|
- 同一电机已有 owner 时拒绝新的控制调用;
|
||||||
|
- cyclic 流首帧必须是 `open`,后续 setpoint sequence 必须严格递增;
|
||||||
|
- reader 使用 latest-wins 邮箱,客户端必须持续并发读取反馈;
|
||||||
|
- 取消、deadline、watchdog、非法帧、后端拒绝或写失败都会触发 Quick Stop;
|
||||||
|
- 任何清理 Quick Stop 未确认时,服务进入 fail-closed 锁存;
|
||||||
|
- 只有成功执行 `setEnabled(true)` 才解除服务内软件急停锁存;
|
||||||
|
- 服务层 Quick Stop 和 `emergencyStop` 都不具备功能安全等级。
|
||||||
|
|
||||||
|
PLC 后端的连接 epoch、stream epoch、寄存器、ACK 和 TIA Portal 要求见:
|
||||||
|
|
||||||
|
- [Modbus TCP PLC runtime](../devices/motor/bus_runtime/modbus_tcp/README.md)
|
||||||
|
- [MotorService 与 CMVR PLC v1 完整协议](../../docs/motor_service_modbus_tcp.md)
|
||||||
|
|
||||||
|
AUBO 控制柜 IO 不经过 `MotorService` 或 `ArmService`,而是复用
|
||||||
|
`SystemService/ExecuteJsonCommand`。厂商命令和安全约束见
|
||||||
|
[AUBO 控制柜 IO](../devices/arm/aubo_arm/README.md)。
|
||||||
|
|
||||||
## 新增 gRPC Service
|
## 新增 gRPC Service
|
||||||
|
|
||||||
当前没有动态 service registry,必须完成以下全部步骤。
|
当前没有动态 service registry,必须完成以下全部步骤。
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user