docs(ethercat): add EYOU setup guide and scripts

This commit is contained in:
lgv 2026-07-09 14:22:35 +08:00
parent 5b94d5c85a
commit d84f84b5ee
10 changed files with 11532 additions and 137 deletions

View File

@ -18,7 +18,9 @@ set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/output" CACHE PATH "" FORCE)
set(CMAKE_BUILD_RPATH "\$ORIGIN:\$ORIGIN/../lib")
set(CMAKE_INSTALL_RPATH "\$ORIGIN:\$ORIGIN/../lib")
# Use RUNPATH (new dtags) generally preferable
# Use transitive RPATH so CLion can run build-tree test executables without
# manually setting LD_LIBRARY_PATH for indirect third-party dependencies.
add_link_options(-Wl,--disable-new-dtags)
set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

103
README.md
View File

@ -1,23 +1,25 @@
# CMVR-ES
## Overview
## 简介
## Installation
CMVR-ES 工程。
### 1. Git submodules install
## 安装
### 1. 拉取 Git 子模块
```
git submodule update --init --recursive
```
### 2. Dependency install
### 2. 安装系统依赖
```shell
# basic
# 基础工具
sudo apt-get update
sudo apt install -y build-essential cmake git pkg-config patchelf libboost-all-dev libssl-dev
# opencv
# OpenCV
sudo apt install -y \
libjpeg-dev libpng-dev libtiff-dev \
libavcodec-dev libavformat-dev libswscale-dev \
@ -39,7 +41,7 @@ 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
# RealSense
sudo apt-get install -y \
libusb-1.0-0-dev libudev-dev \
libglu1-mesa-dev
@ -48,4 +50,91 @@ sudo apt-get install -y \
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
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,51 @@
# EtherCAT 电机接入教程
这份文档只说明新增一种 EtherCAT 电机需要改哪里、怎么写
当前已接入意优 `EYOU_ServoModule_ECAT_V145`,协议为 EtherCAT CoE + CiA402PDO 使用 `docs/EYOU_ServoModule_ECAT_V145_no_slot.xml` 中的 `0x1600/0x1A00` 映射
## 1. 增加 vendor
ESI XML 作为厂商通信说明和对照资料保存,运行时不直接解析 XML。实际 PDO 映射写在:
修改 `protos/cmvr/config/motor_config/motor_config.proto`
```proto
enum MotorVendor {
MOTOR_VENDOR_UNKNOWN = 0;
MOTOR_VENDOR_TI5 = 1;
MOTOR_VENDOR_MUJOCO = 2;
MOTOR_VENDOR_XXX = 3;
}
```text
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_cia402_pdo_mapping.h
```
`MOTOR_VENDOR_XXX` 改成真实厂商名,例如 `MOTOR_VENDOR_FOO`。不要复用 `TI5`
## 1. 系统依赖
## 2. 写电机配置
IgH EtherCAT userspace 已安装在:
新增配置文件:
```text
dependency/x86/third_party/ethercat/v1.7.0
```
真机运行前,系统里还需要安装/加载 IgH master 内核模块。使用仓库脚本启动 EtherCAT master
```bash
sudo script/ethercat/start_ethercat.sh eno1
script/ethercat/status_ethercat.sh
```
其中 `eno1` 是连接 EtherCAT 从站的网卡。脚本会读取该网卡 MAC写入
```text
dependency/x86/third_party/ethercat/v1.7.0/etc/ethercat.conf
```
并通过 bundled IgH 的 `ethercatctl -c` 启动 master。能看到 EYOU slave 后再启动程序。
停止 EtherCAT
```bash
sudo script/ethercat/stop_ethercat.sh eno1
```
如果这张网卡要恢复给普通网络使用:
```bash
sudo script/ethercat/stop_ethercat.sh eno1 --restore-network
```
## 2. 电机配置
新增或修改:
```text
cmvr-es/config/devices/motor/ethercat_motors.pb.txt
@ -34,20 +60,28 @@ motor {
motor_groups {
id: "right_arm_ethercat"
bus_type: MOTOR_BUS_ETHERCAT
vendor: MOTOR_VENDOR_XXX
vendor: MOTOR_VENDOR_EYOU
protocol: MOTOR_PROTOCOL_ETHERCAT_CIA402
tool_frame: "R_FINGER_TIP"
ethercat {
master_id: "eth0"
master_index: 0
cycle_us: 1000
slaves { motor_id: 1 slave_index: 0 vendor_id: 0x00000000 product_code: 0x00000000 }
slaves { motor_id: 2 slave_index: 1 vendor_id: 0x00000000 product_code: 0x00000000 }
slaves { motor_id: 3 slave_index: 2 vendor_id: 0x00000000 product_code: 0x00000000 }
slaves { motor_id: 4 slave_index: 3 vendor_id: 0x00000000 product_code: 0x00000000 }
slaves { motor_id: 5 slave_index: 4 vendor_id: 0x00000000 product_code: 0x00000000 }
slaves { motor_id: 6 slave_index: 5 vendor_id: 0x00000000 product_code: 0x00000000 }
slaves { motor_id: 7 slave_index: 6 vendor_id: 0x00000000 product_code: 0x00000000 }
cia402 {
profile_position_trigger_delay_ms: 2
state_transition_timeout_ms: 1200
velocity_stop_timeout_ms: 2000
status_poll_period_ms: 10
stopped_velocity_tolerance_rad_s: 0.001
}
slaves { motor_id: 1 alias: 0 position: 0 }
slaves { motor_id: 2 alias: 0 position: 1 }
slaves { motor_id: 3 alias: 0 position: 2 }
slaves { motor_id: 4 alias: 0 position: 3 }
slaves { motor_id: 5 alias: 0 position: 4 }
slaves { motor_id: 6 alias: 0 position: 5 }
slaves { motor_id: 7 alias: 0 position: 6 }
}
joint_limits {
@ -63,21 +97,26 @@ motor {
}
motors {
motors { id: 1 joint_name: "R_SHOULDER_P" }
motors { id: 2 joint_name: "R_SHOULDER_R" }
motors { id: 3 joint_name: "R_SHOULDER_Y" }
motors { id: 4 joint_name: "R_ELBOW_R" }
motors { id: 5 joint_name: "R_WRIST_P" }
motors { id: 6 joint_name: "R_WRIST_Y" }
motors { id: 7 joint_name: "R_WRIST_R" }
motors { id: 1 joint_name: "R_SHOULDER_P" encoder_counts_per_rev: 65536 gear_ratio: 101.0 }
motors { id: 2 joint_name: "R_SHOULDER_R" encoder_counts_per_rev: 65536 gear_ratio: 101.0 }
motors { id: 3 joint_name: "R_SHOULDER_Y" encoder_counts_per_rev: 65536 gear_ratio: 101.0 }
motors { id: 4 joint_name: "R_ELBOW_R" encoder_counts_per_rev: 65536 gear_ratio: 101.0 }
motors { id: 5 joint_name: "R_WRIST_P" encoder_counts_per_rev: 65536 gear_ratio: 101.0 }
motors { id: 6 joint_name: "R_WRIST_Y" encoder_counts_per_rev: 65536 gear_ratio: 101.0 }
motors { id: 7 joint_name: "R_WRIST_R" encoder_counts_per_rev: 65536 gear_ratio: 101.0 }
}
}
}
```
`motors.motors.id` 是系统内的电机逻辑 id。`ethercat.slaves.motor_id` 必须和它对应。
字段说明:
`joint_limits``joint_name` 读取,和 CAN、MuJoCo 电机保持同一个风格。
- `master_index`IgH master 编号,第一张 EtherCAT master 是 `0`
- `alias`EtherCAT alias一般为 `0`
- `position`slave 在 EtherCAT 链路上的顺序,从 `0` 开始。
- `motor_id`:系统内电机 id必须和 `motors.motors.id` 对应。
- `encoder_counts_per_rev`:电机编码器每转 count 数,用于 `rad <-> count` 换算。
- `gear_ratio`:电机轴到关节输出轴的减速比,用于接口层 `rad/rad/s` 和驱动器 raw count/counts/s 换算。
## 3. 注册设备
@ -98,15 +137,9 @@ devices {
}
```
## 4. 机械臂使用 EtherCAT group
## 4. 机械臂使用 EtherCAT 电机
修改机械臂配置,例如:
```text
cmvr-es/config/devices/arm/arm.pb.txt
```
把 motor backend 改成:
修改机械臂配置中的 motor backend
```proto
motor {
@ -122,116 +155,66 @@ motor {
}
```
## 5. 实现 bus runtime
## 5. 代码结构
EtherCAT 总线资源放在
EtherCAT 总线运行时
```text
cmvr-es/devices/motor/bus_runtime/ethercat/include/ethercat_motor_bus_runtime.h
cmvr-es/devices/motor/bus_runtime/ethercat/src/ethercat_motor_bus_runtime.cpp
```
`EthercatMotorBusRuntime` 负责:
它负责:
- 打开 IgH master
- 创建 domain
- 使用 `vendor + protocol` 选择 PDO mapping
- 按 mapping 配置 `0x1600/0x1A00` PDO
- 注册每个非 padding PDO entry 的 offset
- 启动 cyclic loop
- 按 `motor_id + index + subindex` 提供通用 PDO 读写接口
CiA402 EtherCAT 电机驱动:
```text
读取 ethercat 配置
初始化 EtherCAT master
扫描/校验 slave_index、vendor_id、product_code
启动 cyclic loop
保存 command/feedback buffer
停止 cyclic loop
cmvr-es/devices/motor/drivers/ethercat_motor/include/cia402/cia402_protocol.h
cmvr-es/devices/motor/drivers/ethercat_motor/include/cia402/cia402_objects.h
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/motor_vendor_adapter.h
cmvr-es/devices/motor/drivers/ethercat_motor/src/cia402/cia402_protocol.cpp
```
bus runtime 不创建具体电机,也不关心厂商;它只保存总线连接、线程和数据缓存。
## 6. 增加具体电机 driver
新增目录:
EYOU 私有适配:
```text
cmvr-es/devices/motor/drivers/xxx_ethercat/
CMakeLists.txt
include/xxx_ethercat_motor.h
include/xxx_ethercat_motor_protocol.h
src/xxx_ethercat_motor.cpp
src/xxx_ethercat_motor_protocol.cpp
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_motor.h
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_motor_adapter.h
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_cia402_pdo_mapping.h
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_objects.h
cmvr-es/devices/motor/drivers/ethercat_motor/src/vendor/eyou/eyou_motor.cpp
cmvr-es/devices/motor/drivers/ethercat_motor/src/vendor/eyou/eyou_motor_adapter.cpp
```
`XxxEthercatMotor` 继承 `AbstractMotor`
它负责:
`XxxEthercatMotorProtocol` 继承 `MotorProtocolInterface`,把 `setTarget`、`setQd`、`getQ` 等接口转换成 EtherCAT command/feedback。
- CiA402 `6040/6041` 状态机
- 设置 `6060` 运行模式
- 写 `607A/60FF/6071`
- 读 `6064/606C/6077/603F`
- `rad` 和 encoder count 的换算
## 7. 在 MotorManager 里创建 EtherCAT 电机
修改:
```text
cmvr-es/devices/motor/manager/src/motor_manager.cpp
```
`MotorManager::createEthercatMotors_()` 里按 `vendor + protocol` 创建具体电机:
```cpp
auto ethercat_bus_runtime =
std::dynamic_pointer_cast<EthercatMotorBusRuntime>(bus_runtime);
if (group_cfg.vendor() == config::MOTOR_VENDOR_XXX &&
group_cfg.protocol() == config::MOTOR_PROTOCOL_ETHERCAT_CIA402) {
auto protocol = std::make_shared<XxxEthercatMotorProtocol>(ethercat_bus_runtime);
std::vector<std::shared_ptr<AbstractMotor>> motors;
motors.reserve(motor_cfgs.size());
for (const auto& cfg : motor_cfgs) {
auto motor = std::make_shared<XxxEthercatMotor>(cfg);
motor->setProtocol(protocol);
if (!motor->init()) {
return {};
}
motors.push_back(std::move(motor));
}
return motors;
}
```
## 8. 加入 CMake
修改:
```text
cmvr-es/devices/motor/manager/CMakeLists.txt
```
`motor_manager` 链接新增的具体 EtherCAT 电机 target。
修改:
```text
cmvr-es/devices/motor/CMakeLists.txt
```
加入:
```cmake
add_subdirectory(drivers/xxx_ethercat)
```
## 9. 验证配置
先验证 proto
## 6. 编译验证
```bash
./output/bin/protoc \
--encode=cmvr.config.MotorRootConfig \
-I protos \
protos/cmvr/config/motor_config/motor_config.proto \
< cmvr-es/config/devices/motor/ethercat_motors.pb.txt \
> /tmp/ethercat_motors.pb.bin
cmake -S . -B cmake-build-debug
cmake --build cmake-build-debug --target motor_manager
```
再编译
真机验证顺序:
```bash
cmake --build cmake-build-debug --target mujoco_manual_ui_test
sudo script/ethercat/start_ethercat.sh eno1
script/ethercat/status_ethercat.sh
cmake --build cmake-build-debug --target cmvr_es
```
真机联调时先只验证初始化日志master 打开、slave 数量、vendor/product 校验、cyclic loop 启动、每个 motor 注册成功。然后再下发运动命令
第一次联调先不要大幅度运动。先看 master 是否打开、slave 是否进入 OP、状态字是否更新再给单个电机小角度目标。

Binary file not shown.

View File

@ -33,5 +33,6 @@ third_party/modbus/3.1.11
third_party/visp/3.7.0
third_party/mainif/0.0.5
third_party/matplotplusplus/1.2.0
third_party/ethercat/v1.7.0

133
script/ethercat/start_ethercat.sh Executable file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage:
sudo script/ethercat/start_ethercat.sh [iface] [ethercat_dev] [start_wait_sec]
Any pure numeric argument is treated as start_wait_sec.
Example:
sudo script/ethercat/start_ethercat.sh eno1
sudo script/ethercat/start_ethercat.sh 10
sudo script/ethercat/start_ethercat.sh eno1 10
sudo script/ethercat/start_ethercat.sh eno1 /dev/EtherCAT1
sudo script/ethercat/start_ethercat.sh eno1 /dev/EtherCAT0 10
sudo script/ethercat/start_ethercat.sh eno1 10 /dev/EtherCAT0
Environment:
DEVICE_MODULES=generic IgH device module list.
IGH_ROOT=... Override bundled IgH install path.
ETHERCAT_CONF=... Override ethercatctl config path.
ETHERCAT_DEV=/dev/EtherCAT0 Override EtherCAT character device node.
START_WAIT_SEC=5 Seconds to wait for link/slave discovery.
USAGE
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
if [[ "$(id -u)" -ne 0 ]]; then
echo "error: please run with sudo." >&2
exit 1
fi
IFACE="${IFACE:-eno1}"
ETHERCAT_DEV="${ETHERCAT_DEV:-/dev/EtherCAT0}"
START_WAIT_SEC="${START_WAIT_SEC:-5}"
NON_NUMERIC_ARG_COUNT=0
for arg in "$@"; do
if [[ "${arg}" =~ ^[0-9]+$ ]]; then
START_WAIT_SEC="${arg}"
continue
fi
case "${NON_NUMERIC_ARG_COUNT}" in
0)
IFACE="${arg}"
;;
1)
ETHERCAT_DEV="${arg}"
;;
*)
echo "error: unexpected argument: ${arg}" >&2
usage >&2
exit 1
;;
esac
NON_NUMERIC_ARG_COUNT=$((NON_NUMERIC_ARG_COUNT + 1))
done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
IGH_ROOT="${IGH_ROOT:-${REPO_ROOT}/dependency/x86/third_party/ethercat/v1.7.0}"
DEVICE_MODULES="${DEVICE_MODULES:-generic}"
ETHERCAT_CONF="${ETHERCAT_CONF:-${IGH_ROOT}/etc/ethercat.conf}"
ETHERCATCTL="${IGH_ROOT}/sbin/ethercatctl"
ETHERCAT="${IGH_ROOT}/bin/ethercat"
if [[ ! -d "/sys/class/net/${IFACE}" ]]; then
echo "error: network interface '${IFACE}' does not exist." >&2
exit 1
fi
if [[ ! -x "${ETHERCATCTL}" ]]; then
echo "error: ethercatctl not found: ${ETHERCATCTL}" >&2
exit 1
fi
if [[ ! -x "${ETHERCAT}" ]]; then
echo "error: ethercat command not found: ${ETHERCAT}" >&2
exit 1
fi
MAC="$(cat "/sys/class/net/${IFACE}/address")"
echo "EtherCAT interface: ${IFACE}"
echo "EtherCAT MAC: ${MAC}"
echo "EtherCAT device: ${ETHERCAT_DEV}"
echo "IgH root: ${IGH_ROOT}"
echo "IgH config: ${ETHERCAT_CONF}"
echo "Device modules: ${DEVICE_MODULES}"
echo "Start wait: ${START_WAIT_SEC}s"
mkdir -p "$(dirname "${ETHERCAT_CONF}")"
if [[ -f "${ETHERCAT_CONF}" ]]; then
echo "Stopping existing EtherCAT master with current config..."
"${ETHERCATCTL}" -c "${ETHERCAT_CONF}" stop >/dev/null 2>&1 || true
sleep 1
fi
cat >"${ETHERCAT_CONF}" <<EOF
MASTER0_DEVICE="${MAC}"
DEVICE_MODULES="${DEVICE_MODULES}"
UPDOWN_INTERFACES="${IFACE}"
EOF
if command -v nmcli >/dev/null 2>&1; then
nmcli device disconnect "${IFACE}" >/dev/null 2>&1 || true
fi
ip addr flush dev "${IFACE}"
ip link set "${IFACE}" up
"${ETHERCATCTL}" -c "${ETHERCAT_CONF}" start
if [[ -e "${ETHERCAT_DEV}" ]]; then
chmod 666 "${ETHERCAT_DEV}"
else
echo "warning: ${ETHERCAT_DEV} not found; skip chmod. Check with: ls -l /dev/EtherCAT*" >&2
fi
for ((i = 0; i < START_WAIT_SEC; ++i)); do
if "${ETHERCAT}" slaves 2>/dev/null | grep -qE '^[0-9]+[[:space:]]'; then
break
fi
sleep 1
done
"${ETHERCAT}" master
"${ETHERCAT}" slaves || true

View File

@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage:
script/ethercat/status_ethercat.sh
Environment:
IGH_ROOT=... Override bundled IgH install path.
ETHERCAT_CONF=... Override ethercatctl config path.
USAGE
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
IGH_ROOT="${IGH_ROOT:-${REPO_ROOT}/dependency/x86/third_party/ethercat/v1.7.0}"
ETHERCAT_CONF="${ETHERCAT_CONF:-${IGH_ROOT}/etc/ethercat.conf}"
ETHERCATCTL="${IGH_ROOT}/sbin/ethercatctl"
ETHERCAT="${IGH_ROOT}/bin/ethercat"
if [[ ! -x "${ETHERCATCTL}" ]]; then
echo "error: ethercatctl not found: ${ETHERCATCTL}" >&2
exit 1
fi
if [[ ! -x "${ETHERCAT}" ]]; then
echo "error: ethercat command not found: ${ETHERCAT}" >&2
exit 1
fi
echo "== ${ETHERCAT_CONF} =="
if [[ -f "${ETHERCAT_CONF}" ]]; then
sed -n '1,80p' "${ETHERCAT_CONF}"
else
echo "missing"
fi
echo
echo "== kernel modules =="
lsmod | grep -E '(^ec_master|^ec_generic|^ec_)' || true
echo
echo "== ethercatctl =="
"${ETHERCATCTL}" -c "${ETHERCAT_CONF}" status || true
echo
echo "== master =="
"${ETHERCAT}" master || true
echo
echo "== slaves =="
"${ETHERCAT}" slaves || true
echo
echo "== pdos =="
"${ETHERCAT}" pdos || true

View File

@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage:
sudo script/ethercat/stop_ethercat.sh [iface] [--restore-network]
Examples:
sudo script/ethercat/stop_ethercat.sh eno1
sudo script/ethercat/stop_ethercat.sh eno1 --restore-network
Environment:
IGH_ROOT=... Override bundled IgH install path.
ETHERCAT_CONF=... Override ethercatctl config path.
USAGE
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
if [[ "$(id -u)" -ne 0 ]]; then
echo "error: please run with sudo." >&2
exit 1
fi
IFACE="eno1"
RESTORE_NETWORK="false"
for arg in "$@"; do
case "${arg}" in
--restore-network)
RESTORE_NETWORK="true"
;;
-*)
echo "error: unknown option: ${arg}" >&2
usage >&2
exit 1
;;
*)
IFACE="${arg}"
;;
esac
done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
IGH_ROOT="${IGH_ROOT:-${REPO_ROOT}/dependency/x86/third_party/ethercat/v1.7.0}"
ETHERCAT_CONF="${ETHERCAT_CONF:-${IGH_ROOT}/etc/ethercat.conf}"
ETHERCATCTL="${IGH_ROOT}/sbin/ethercatctl"
if [[ ! -x "${ETHERCATCTL}" ]]; then
echo "error: ethercatctl not found: ${ETHERCATCTL}" >&2
exit 1
fi
"${ETHERCATCTL}" -c "${ETHERCAT_CONF}" stop
if [[ "${RESTORE_NETWORK}" == "true" ]]; then
ip link set "${IFACE}" up
if command -v nmcli >/dev/null 2>&1; then
nmcli device connect "${IFACE}" || true
fi
echo "Stopped EtherCAT and requested normal network restore on ${IFACE}."
else
echo "Stopped EtherCAT. Normal network restore skipped."
echo "Use '--restore-network' if this interface should return to NetworkManager."
fi