从 SDK 继续
上一步你已经在配置工具中完成了测试, 并导出了代码。现在, 将导出的代码集成到你自己的项目中。
功能概览
| 项目 | 内容 |
|---|---|
| 导出的项目 | 完整可编译, 包含代码、配置、运行脚本 |
| SDK 文件夹 | 工具自动维护, 含六语言 SDK 文件 |
| 六种语言 | C# / C / C++ / Python / Java / Rust |
| 协议覆盖 | CoE / FoE / FSoE / EoE / SoE / AoE / VoE / MDP |
导出的项目结构
选择 C# 导出后, 工具会生成一个完整的可编译项目:
EtherCATRestore/
├── EtherCATRestore.csproj # 项目文件 (已配置本地引用)
├── Program.cs # C# 调用示例 (含初始化、PDO 循环、选配的协议代码)
├── config.deni # 主站配置文件
├── run.bat # 一键编译运行脚本
└── lib/
├── DarraEtherCAT.dll # C# 类库
├── DarraEtherCAT.xml # IntelliSense 文档
└── Darra.Core.dll # 核心运行库
导出的项目已包含 .csproj 和本地引用, 无需安装 NuGet 包。双击 run.bat 或用 dotnet run 即可编译运行。
SDK 文件夹
配置工具启动后会在 exe 目录下自动创建 SDK/ 文件夹, 你也可以直接从这里获取最新版本:
Darra_EtherCAT_Master.exe
SDK/
├── CSharp/
├── C/
├── CPP/
├── Python/
├── Java/
└── Rust/
各语言详细文档: C# SDK · C SDK · C++ SDK · Python SDK · Java SDK · Rust SDK
快速开始
按你使用的语言, 选择对应方式引入 SDK:
- C#
- C++
- C
- Python
- Java
- Rust
方式 A: NuGet 包 (推荐)
dotnet new console -n MyEtherCATApp
cd MyEtherCATApp
dotnet add package DarraEtherCAT
或在 Visual Studio 的 NuGet 包管理器 中搜索 DarraEtherCAT, 然后将导出的 Program.cs 和 config.deni 复制到项目目录。
方式 B: 本地引用
从导出的 lib/ 目录或配置工具的 SDK/CSharp/ 复制 DarraEtherCAT.dll、DarraEtherCAT.xml、Darra.Core.dll 到项目 lib/ 目录, 然后:
<Reference Include="DarraEtherCAT">
<HintPath>lib\DarraEtherCAT.dll</HintPath>
</Reference>
DarraEtherCAT.xml 与同目录文件即可获得完整 IntelliSense。
C++ SDK 是 header-only 封装, 无需额外编译:
- 从
SDK/CPP/复制:ethercat.hpp、ethercat.h、Darra.Core.dll(Linux 下libDarra.Core.so) - 头文件放入项目
include/, 运行库放在可执行文件运行目录 - 编译示例:
# MSVC
cl /std:c++17 /Fe:my_app.exe main.cpp /I include
# GCC / MinGW
g++ -std=c++17 main.cpp -I include -o my_app
源码内只需:
#define DYNAMIC_LOAD
#include "ethercat.hpp"
- 从
SDK/C/复制:ethercat.h、Darra.Core.dll(Linux:libDarra.Core.so) - 编译:
# 推荐
gcc main.c -I include -DDARRA_DYNAMIC_LOAD -o my_app
# MSVC
cl /Fe:my_app.exe main.c /I include /DDARRA_DYNAMIC_LOAD
- 运行时通过
LOAD_DLL()加载, 所有函数走dll_t结构体。
pip install darra-ethercat
安装后第一次 import ethercat 会自动定位运行库; 如安装位置不标准, 可显式传入路径:
from ethercat import EtherCATMaster
master = EtherCATMaster(dll_path=r"C:\path\to\Darra.Core.dll")
将导出的 config.deni 放在脚本同目录即可。
Maven:
<dependency>
<groupId>com.darra</groupId>
<artifactId>darra-ethercat</artifactId>
<version>1.0.0</version>
</dependency>
Gradle:
implementation 'com.darra:darra-ethercat:1.0.0'
或直接将 SDK/Java/ 中的 darra-ethercat.jar 加入 classpath, 同时确保 Darra.Core.dll 在 JVM 的 java.library.path 或可执行目录中。
Cargo.toml:
[dependencies]
darra-ethercat = "1.0"
或本地路径引用:
[dependencies]
darra-ethercat = { path = "../SDK/Rust" }
确保 Darra.Core.dll (Windows) / libDarra.Core.so (Linux) 在可执行文件搜索路径中。
完整示例
下面展示完全等价的 Hello-World — 枚举网卡 → 加载 DENI 配置 → 构建主站 → 进入 OP → 读取从站身份对象 0x1018:01 (VendorID)。 六种 SDK 步骤一致, 仅语法差异。
- C#
- C++
- C
- Python
- Java
- Rust
using System;
using System.Linq;
using DarraEtherCAT_Master;
class Program
{
static void Main()
{
// 1. 枚举网卡, 挑选挂有从站的接口
var nic = DarraEtherCAT.GetNetworkInfo(needSlavesNum: true)
.FirstOrDefault(n => n.SlaveNum > 0);
if (nic == null) { Console.WriteLine("未发现从站"); return; }
// 2. 通过 DENI 配置 + 网卡构建主站
var result = new DarraEtherCAT()
.SetENI(@"config.deni")
.SetNetwork(nic)
.EnableAutoStartup()
.Build();
if (!result.Success) { Console.WriteLine(result.Message); return; }
DarraEtherCAT master = result;
Console.WriteLine($"发现 {master.SlaveCount} 个从站");
// 3. 进入 OP (OP = 完全启动)
var (ok, msg) = master.SetState(EcState.OP);
if (!ok) { Console.WriteLine(msg); master.Dispose(); return; }
// 4. 读取从站 1 的 VendorID (0x1018:01)
byte[] data = master.Slaves[0].CoE.SDORead(0x1018, 0x01);
uint vendorId = BitConverter.ToUInt32(data, 0);
Console.WriteLine($"VendorID = 0x{vendorId:X8}");
master.Close();
master.Dispose();
}
}
#define DYNAMIC_LOAD
#include "ethercat.hpp"
#include <iostream>
int main() {
dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");
{
// 1. 创建主站实例 (RAII 自动释放)
darra::EtherCATMaster master(dll);
// 2. 通过 DENI 配置 + 网卡构建主站
master.SetENI("config.deni")
.SetNetwork("\\Device\\NPF_{your-nic-guid}")
.EnableAutoStartup();
if (!master.Build()) {
std::cerr << "主站构建失败" << std::endl;
return 1;
}
// 3. 进入 OP
master.SetState(darra::EcState::OP);
master.Start();
std::cout << "从站数量: " << master.SlaveCount() << std::endl;
// 4. 读取 VendorID (0x1018:01)
auto vid = master.GetSlave(1).GetCoE().SDOReadU32(0x1018, 0x01);
if (vid) std::cout << "VendorID = 0x" << std::hex << *vid << std::endl;
} // 离开作用域, 自动 Stop + Dispose
UNLOAD_DLL(&dll);
return 0;
}
#define DYNAMIC_LOAD
#include "ethercat.h"
#include "ethercat_advanced.h"
#include <stdio.h>
int main(void) {
dll_t dll;
if (!LOAD_DLL(&dll, "Darra.Core.dll")) return 1;
/* 1. 初始化主站 */
uint16_t master = dll.Initialize();
if (master == 0) { UNLOAD_DLL(&dll); return 1; }
/* 2. 加载 DENI 配置 + 选网卡 */
dll.LoadConfigJson(master, "config.deni");
dll.SetNetwork(master, "\\Device\\NPF_{your-nic-guid}", "");
/* 3. 状态机一步进入 OP, 启动 PDO 循环 */
dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
dll.Start(master);
/* 4. 读取从站 1 的 VendorID (0x1018:01) */
uint32_t vendor_id = 0;
if (sdo_read_u32(&dll, master, 1, 0x1018, 0x01, &vendor_id) == 0) {
printf("VendorID = 0x%08X\n", vendor_id);
}
dll.Stop(master);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}
from ethercat import EtherCATMaster, EcState
# 1. 通过 DENI 配置一步初始化主站
with EtherCATMaster.from_json_file("config.deni") as master:
# 2. 进入 OP
master.set_state_sequence(EcState.OP, 10000)
master.start()
print(f"发现 {master.slave_count} 个从站")
# 3. 读取从站 1 的 VendorID (0x1018:01)
vendor_id = master.slaves[0].coe.sdo_read_value(0x1018, 0x01, dtype='u32')
print(f"VendorID = 0x{vendor_id:08X}")
# 退出 with: 自动 close
import com.darra.ethercat.master.EtherCATMaster;
import com.darra.ethercat.master.EcState;
public class HelloEtherCAT {
public static void main(String[] args) throws Exception {
// 1. 通过 DENI 配置一步初始化主站
try (EtherCATMaster master = EtherCATMaster.createFromJsonFile("config.deni")) {
// 2. 进入 OP
master.setStateSequence(EcState.OP, 10000);
master.Start();
System.out.println("从站数量: " + master.SlaveCount());
// 3. 读取从站 1 的 VendorID (0x1018:01)
byte[] data = master.Slaves().get(0).getCoE()
.SDORead((short) 0x1018, (byte) 0x01);
int vendorId = java.nio.ByteBuffer.wrap(data)
.order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
System.out.printf("VendorID = 0x%08X%n", vendorId);
} // try-with-resources: 自动 close
}
}
use ethercat::{EcState, EtherCATMaster};
fn main() -> anyhow::Result<()> {
// 1. 通过 DENI 配置一步初始化主站
let master = EtherCATMaster::from_json_file("config.deni")?;
// 2. 一步进入 OP
master.set_state_sequence(EcState::Operational, 10000)?;
master.start();
println!("从站数量: {}", master.slave_count());
// 3. 读取从站 1 的 VendorID (0x1018:01)
let vendor_id: u32 = master.slave(1).sdo_read_value(0x1018, 0x01)?;
println!("VendorID = 0x{:08X}", vendor_id);
Ok(()) // master 在此 drop, 自动停止并释放
}
- 枚举网卡 → 找到挂有从站的接口
- 加载 DENI 配置 → 由配置工具导出
- 构建/启动主站 → 自动完成 INIT → PRE_OP → SAFE_OP → OP
- 读取对象字典 →
0x1018:01 (VendorID)是任何从站都必有的标准对象
任何一种语言跑通后, 扩展到 PDO 循环、协议读写都是同一套模型。
定义 PDO 结构体
如果没有使用工具导出的代码, 需要手动定义 PDO 结构体。三条共通规则:
- 顺序紧凑 — 字段按 PDO 映射顺序声明, 禁止编译器插入填充字节
- 小端字节序 — EtherCAT 协议规定 PDO 数据为 little-endian
- 大小匹配 — 结构体总字节数必须等于从站的
IBytes/OBytes
各语言对应的"紧凑布局"声明方式:
- C# —
[StructLayout(LayoutKind.Sequential, Pack = 1)] struct ... - C++ —
#pragma pack(push, 1) struct ... #pragma pack(pop) - C —
__attribute__((packed))(GCC/Clang) 或#pragma pack(1)(MSVC) - Python —
class X(ctypes.Structure): _pack_ = 1; _fields_ = [...] - Java —
class X extends Structure { ... } - Rust —
#[repr(C, packed)] struct ...
类型对照表 (C# 为参照):
- 1 bit — bool
- 8 bit — sbyte / byte / int8 / uint8 / i8 / u8
- 16 bit — short / ushort / int16 / uint16 / i16 / u16
- 32 bit — int / uint / float / int32 / uint32 / i32 / u32 / f32
- 64 bit — long / ulong / double / int64 / uint64 / i64 / u64 / f64
务必在运行前比对结构体大小与从站汇报的 IBytes / OBytes, 不一致就别启动 PDO。
关闭资源
各语言的关闭方式 (与 作用域结束 / with / try-with-resources / RAII 机制配合最佳):
- C# —
master.Close(); master.Dispose(); - C++ — 离开作用域自动析构 (RAII)
- C —
dll.Stop(master); dll.Dispose(master); UNLOAD_DLL(&dll); - Python —
with EtherCATMaster() as master: ...(退出 with 自动释放) - Java —
try (var master = ...) { ... }(try-with-resources) - Rust —
master离开作用域自动 drop
下一步
- 拓展协议
- SDK 文档
- 应用案例
| 协议 | 用途 | 文档 |
|---|---|---|
| FSoE | 功能安全通信 | FSoE 用法 |
| CoE | CANopen over EtherCAT, SDO 读写对象字典 | CoE 用法 |
| FoE | 文件传输 (固件升级) | FoE 用法 |
| EoE | 以太网透传 | EoE 用法 |
| SoE | 伺服参数访问 | SoE 用法 |
| AoE | ADS over EtherCAT | AoE 用法 |
| DC | 分布式时钟同步 | DC 用法 |