cmvr-es/README.md
xtkuang 28f1dd1bf8 feat: add gRPC motor control over Modbus TCP
Add synchronous and streaming MotorService APIs backed by the PLC Modbus TCP runtime and protocol driver. Extend AUBO JSON commands and isolate vendor libstdc++ paths while keeping build-tree tests runnable.
2026-07-30 15:09:07 +08:00

258 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CMVR-ES
## 简介
CMVR-ES 工程。
## 安装
### 1. 拉取 Git 子模块
```
git submodule update --init --recursive
```
### 2. 安装系统依赖
```shell
# 基础工具
sudo apt-get update
sudo apt install -y build-essential cmake git pkg-config patchelf libboost-all-dev libssl-dev
# OpenCV
sudo apt install -y \
libjpeg-dev libpng-dev libtiff-dev \
libavcodec-dev libavformat-dev libswscale-dev \
libv4l-dev libxvidcore-dev libx264-dev \
libgtk-3-dev
# PulseAudio
sudo apt-get install libpulse-dev
# OpenGL
sudo apt-get install libgl1-mesa-dev
# GLFW
sudo apt-get install libglfw3-dev
# Assimp
sudo apt-get install libassimp-dev
# visp
sudo apt-get install -y libx11-dev liblapack-dev libzbar-dev libpthread-stubs0-dev libdc1394-dev nlohmann-json3-dev
# RealSense
sudo apt-get install -y \
libusb-1.0-0-dev libudev-dev \
libglu1-mesa-dev
# Matplot++
sudo apt install gnuplot-qt
```
### 3. 配置 IgH EtherCAT
工程已内置 IgH EtherCAT 1.7.0 的 userspace 文件:
```text
dependency/x86/third_party/ethercat/v1.7.0
```
先设置本机路径:
```shell
export CMVR_ES_ROOT=/path/to/cmvr-es
export IGH_ETHERCAT_ROOT=$CMVR_ES_ROOT/dependency/x86/third_party/ethercat/v1.7.0
```
安装当前内核的 header
```shell
sudo apt-get update
sudo apt-get install -y linux-headers-$(uname -r)
```
如果内置目录里已经有当前内核版本的 EtherCAT 内核模块,直接安装到系统:
```shell
sudo mkdir -p /lib/modules/$(uname -r)/ethercat
sudo cp -r $IGH_ETHERCAT_ROOT/lib/modules/$(uname -r)/ethercat/* /lib/modules/$(uname -r)/ethercat/
sudo depmod
```
内置内核模块只适用于相同内核版本。如果 `$IGH_ETHERCAT_ROOT/lib/modules/$(uname -r)` 不存在,说明这台机器的内核版本不匹配,需要在这台机器上重新编译安装 IgH EtherCAT
```shell
sudo apt-get update
sudo apt-get install -y \
build-essential autoconf automake libtool pkg-config git \
linux-headers-$(uname -r)
cd /tmp
git clone --branch stable-1.7 --depth 1 https://gitlab.com/etherlab.org/ethercat.git ethercat-stable-1.7
cd ethercat-stable-1.7
./bootstrap
./configure \
--prefix=$IGH_ETHERCAT_ROOT \
--libdir=$IGH_ETHERCAT_ROOT/lib \
--includedir=$IGH_ETHERCAT_ROOT/include \
--sysconfdir=$IGH_ETHERCAT_ROOT/etc \
--with-systemdsystemunitdir=$IGH_ETHERCAT_ROOT/lib/systemd/system \
--enable-generic \
--with-linux-dir=/lib/modules/$(uname -r)/build
make -j$(nproc) all modules
make install
sudo make modules_install
sudo depmod
```
启动 EtherCAT。`eno1` 换成实际连接 EtherCAT 从站的网卡:
```shell
sudo script/ethercat/start_ethercat.sh eno1
```
脚本会写入内置 IgH 配置文件:
```text
$IGH_ETHERCAT_ROOT/etc/ethercat.conf
```
脚本会把该网卡的 MAC 写到 `MASTER0_DEVICE`,使用 `DEVICE_MODULES="generic"`,把网卡从 NetworkManager 断开,并通过 `ethercatctl -c` 启动 IgH master。
查看状态:
```shell
script/ethercat/status_ethercat.sh
$IGH_ETHERCAT_ROOT/bin/ethercat master
$IGH_ETHERCAT_ROOT/bin/ethercat slaves
$IGH_ETHERCAT_ROOT/bin/ethercat pdos
```
停止 EtherCAT
```shell
sudo script/ethercat/stop_ethercat.sh eno1
sudo script/ethercat/stop_ethercat.sh eno1 --restore-network
```
## MotorService 与 Modbus TCP PLC
工程包含从 gRPC `MotorService`、`MotorManager`、`AbstractMotor` 到
`ModbusTcpMotorBusRuntime` 的 CMVR PLC v1 电机控制链x86-64 的 libmodbus
3.1.11 已放在 `dependency/x86/third_party/modbus/3.1.11`
PLC 对接时特别注意:
- `host` 必须配置为 IPv4 字面量PLC boot ID 必须非零且每次重启变化;
- owner 决策、命令 ACK 都必须回显对应 session重连不得执行旧 mailbox
- PLC 在进程启动时可以离线;连接 supervisor 会继续退避重试,离线期间状态
返回不可用且运动命令不会写 mailbox
- 状态区按 odd/even seqlock 发布,上位机使用
sequence-before → 64-word block → sequence-after 三段读取验证;
- 每次 `OpenCyclicPosition/Velocity` 创建新 stream epochPLC 必须原子清零
`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 接口开放。