docs(ethercat): add EYOU setup guide and scripts
This commit is contained in:
parent
5b94d5c85a
commit
d84f84b5ee
@ -18,7 +18,9 @@ set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/output" CACHE PATH "" FORCE)
|
|||||||
set(CMAKE_BUILD_RPATH "\$ORIGIN:\$ORIGIN/../lib")
|
set(CMAKE_BUILD_RPATH "\$ORIGIN:\$ORIGIN/../lib")
|
||||||
set(CMAKE_INSTALL_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_BUILD_WITH_INSTALL_RPATH OFF)
|
||||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||||
|
|
||||||
|
|||||||
103
README.md
103
README.md
@ -1,23 +1,25 @@
|
|||||||
# CMVR-ES
|
# CMVR-ES
|
||||||
|
|
||||||
## Overview
|
## 简介
|
||||||
|
|
||||||
## Installation
|
CMVR-ES 工程。
|
||||||
|
|
||||||
### 1. Git submodules install
|
## 安装
|
||||||
|
|
||||||
|
### 1. 拉取 Git 子模块
|
||||||
|
|
||||||
```
|
```
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Dependency install
|
### 2. 安装系统依赖
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# basic
|
# 基础工具
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt install -y build-essential cmake git pkg-config patchelf libboost-all-dev libssl-dev
|
sudo apt install -y build-essential cmake git pkg-config patchelf libboost-all-dev libssl-dev
|
||||||
|
|
||||||
# opencv
|
# OpenCV
|
||||||
sudo apt install -y \
|
sudo apt install -y \
|
||||||
libjpeg-dev libpng-dev libtiff-dev \
|
libjpeg-dev libpng-dev libtiff-dev \
|
||||||
libavcodec-dev libavformat-dev libswscale-dev \
|
libavcodec-dev libavformat-dev libswscale-dev \
|
||||||
@ -39,7 +41,7 @@ sudo apt-get install libassimp-dev
|
|||||||
# visp
|
# visp
|
||||||
sudo apt-get install -y libx11-dev liblapack-dev libzbar-dev libpthread-stubs0-dev libdc1394-dev nlohmann-json3-dev
|
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 \
|
sudo apt-get install -y \
|
||||||
libusb-1.0-0-dev libudev-dev \
|
libusb-1.0-0-dev libudev-dev \
|
||||||
libglu1-mesa-dev
|
libglu1-mesa-dev
|
||||||
@ -48,4 +50,91 @@ sudo apt-get install -y \
|
|||||||
sudo apt install gnuplot-qt
|
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
|
||||||
|
```
|
||||||
|
|||||||
5560
docs/EYOU_ServoModule_ECAT_V145.xml
Normal file
5560
docs/EYOU_ServoModule_ECAT_V145.xml
Normal file
File diff suppressed because it is too large
Load Diff
5495
docs/EYOU_ServoModule_ECAT_V145_no_slot.xml
Normal file
5495
docs/EYOU_ServoModule_ECAT_V145_no_slot.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,25 +1,51 @@
|
|||||||
# EtherCAT 电机接入教程
|
# EtherCAT 电机接入教程
|
||||||
|
|
||||||
这份文档只说明新增一种 EtherCAT 电机需要改哪里、怎么写。
|
当前已接入意优 `EYOU_ServoModule_ECAT_V145`,协议为 EtherCAT CoE + CiA402,PDO 使用 `docs/EYOU_ServoModule_ECAT_V145_no_slot.xml` 中的 `0x1600/0x1A00` 映射。
|
||||||
|
|
||||||
## 1. 增加 vendor
|
ESI XML 作为厂商通信说明和对照资料保存,运行时不直接解析 XML。实际 PDO 映射写在:
|
||||||
|
|
||||||
修改 `protos/cmvr/config/motor_config/motor_config.proto`:
|
```text
|
||||||
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_cia402_pdo_mapping.h
|
||||||
```proto
|
|
||||||
enum MotorVendor {
|
|
||||||
MOTOR_VENDOR_UNKNOWN = 0;
|
|
||||||
MOTOR_VENDOR_TI5 = 1;
|
|
||||||
MOTOR_VENDOR_MUJOCO = 2;
|
|
||||||
MOTOR_VENDOR_XXX = 3;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`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
|
```text
|
||||||
cmvr-es/config/devices/motor/ethercat_motors.pb.txt
|
cmvr-es/config/devices/motor/ethercat_motors.pb.txt
|
||||||
@ -34,20 +60,28 @@ motor {
|
|||||||
motor_groups {
|
motor_groups {
|
||||||
id: "right_arm_ethercat"
|
id: "right_arm_ethercat"
|
||||||
bus_type: MOTOR_BUS_ETHERCAT
|
bus_type: MOTOR_BUS_ETHERCAT
|
||||||
vendor: MOTOR_VENDOR_XXX
|
vendor: MOTOR_VENDOR_EYOU
|
||||||
protocol: MOTOR_PROTOCOL_ETHERCAT_CIA402
|
protocol: MOTOR_PROTOCOL_ETHERCAT_CIA402
|
||||||
tool_frame: "R_FINGER_TIP"
|
|
||||||
|
|
||||||
ethercat {
|
ethercat {
|
||||||
master_id: "eth0"
|
master_index: 0
|
||||||
cycle_us: 1000
|
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 }
|
cia402 {
|
||||||
slaves { motor_id: 3 slave_index: 2 vendor_id: 0x00000000 product_code: 0x00000000 }
|
profile_position_trigger_delay_ms: 2
|
||||||
slaves { motor_id: 4 slave_index: 3 vendor_id: 0x00000000 product_code: 0x00000000 }
|
state_transition_timeout_ms: 1200
|
||||||
slaves { motor_id: 5 slave_index: 4 vendor_id: 0x00000000 product_code: 0x00000000 }
|
velocity_stop_timeout_ms: 2000
|
||||||
slaves { motor_id: 6 slave_index: 5 vendor_id: 0x00000000 product_code: 0x00000000 }
|
status_poll_period_ms: 10
|
||||||
slaves { motor_id: 7 slave_index: 6 vendor_id: 0x00000000 product_code: 0x00000000 }
|
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 {
|
joint_limits {
|
||||||
@ -63,21 +97,26 @@ motor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
motors {
|
motors {
|
||||||
motors { id: 1 joint_name: "R_SHOULDER_P" }
|
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" }
|
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" }
|
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" }
|
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" }
|
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" }
|
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" }
|
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. 注册设备
|
## 3. 注册设备
|
||||||
|
|
||||||
@ -98,15 +137,9 @@ devices {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4. 机械臂使用 EtherCAT group
|
## 4. 机械臂使用 EtherCAT 电机
|
||||||
|
|
||||||
修改机械臂配置,例如:
|
修改机械臂配置中的 motor backend:
|
||||||
|
|
||||||
```text
|
|
||||||
cmvr-es/config/devices/arm/arm.pb.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
把 motor backend 改成:
|
|
||||||
|
|
||||||
```proto
|
```proto
|
||||||
motor {
|
motor {
|
||||||
@ -122,116 +155,66 @@ motor {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5. 实现 bus runtime
|
## 5. 代码结构
|
||||||
|
|
||||||
EtherCAT 总线资源放在:
|
EtherCAT 总线运行时:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
cmvr-es/devices/motor/bus_runtime/ethercat/include/ethercat_motor_bus_runtime.h
|
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
|
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
|
```text
|
||||||
读取 ethercat 配置
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/cia402/cia402_protocol.h
|
||||||
初始化 EtherCAT master
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/cia402/cia402_objects.h
|
||||||
扫描/校验 slave_index、vendor_id、product_code
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/motor_vendor_adapter.h
|
||||||
启动 cyclic loop
|
cmvr-es/devices/motor/drivers/ethercat_motor/src/cia402/cia402_protocol.cpp
|
||||||
保存 command/feedback buffer
|
|
||||||
停止 cyclic loop
|
|
||||||
```
|
```
|
||||||
|
|
||||||
bus runtime 不创建具体电机,也不关心厂商;它只保存总线连接、线程和数据缓存。
|
EYOU 私有适配:
|
||||||
|
|
||||||
## 6. 增加具体电机 driver
|
|
||||||
|
|
||||||
新增目录:
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
cmvr-es/devices/motor/drivers/xxx_ethercat/
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_motor.h
|
||||||
CMakeLists.txt
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_motor_adapter.h
|
||||||
include/xxx_ethercat_motor.h
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_cia402_pdo_mapping.h
|
||||||
include/xxx_ethercat_motor_protocol.h
|
cmvr-es/devices/motor/drivers/ethercat_motor/include/vendor/eyou/eyou_objects.h
|
||||||
src/xxx_ethercat_motor.cpp
|
cmvr-es/devices/motor/drivers/ethercat_motor/src/vendor/eyou/eyou_motor.cpp
|
||||||
src/xxx_ethercat_motor_protocol.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 电机
|
## 6. 编译验证
|
||||||
|
|
||||||
修改:
|
|
||||||
|
|
||||||
```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:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./output/bin/protoc \
|
cmake -S . -B cmake-build-debug
|
||||||
--encode=cmvr.config.MotorRootConfig \
|
cmake --build cmake-build-debug --target motor_manager
|
||||||
-I protos \
|
|
||||||
protos/cmvr/config/motor_config/motor_config.proto \
|
|
||||||
< cmvr-es/config/devices/motor/ethercat_motors.pb.txt \
|
|
||||||
> /tmp/ethercat_motors.pb.bin
|
|
||||||
```
|
```
|
||||||
|
|
||||||
再编译:
|
真机验证顺序:
|
||||||
|
|
||||||
```bash
|
```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、状态字是否更新,再给单个电机小角度目标。
|
||||||
|
|||||||
BIN
docs/意优CANopen&EtherCAT应用手册V2.2.pdf
Normal file
BIN
docs/意优CANopen&EtherCAT应用手册V2.2.pdf
Normal file
Binary file not shown.
@ -33,5 +33,6 @@ third_party/modbus/3.1.11
|
|||||||
third_party/visp/3.7.0
|
third_party/visp/3.7.0
|
||||||
third_party/mainif/0.0.5
|
third_party/mainif/0.0.5
|
||||||
third_party/matplotplusplus/1.2.0
|
third_party/matplotplusplus/1.2.0
|
||||||
|
third_party/ethercat/v1.7.0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
133
script/ethercat/start_ethercat.sh
Executable file
133
script/ethercat/start_ethercat.sh
Executable 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
|
||||||
62
script/ethercat/status_ethercat.sh
Executable file
62
script/ethercat/status_ethercat.sh
Executable 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
|
||||||
70
script/ethercat/stop_ethercat.sh
Executable file
70
script/ethercat/stop_ethercat.sh
Executable 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
|
||||||
Loading…
Reference in New Issue
Block a user