A: 不是必须的,但强烈推荐使用。
EDS (Electronic Data Sheet) 是CANopen设备的电子数据表,是一个文本文件(类似INI格式),包含:
设备基本信息
对象字典定义
通信参数
制造商特定信息
[DeviceInfo]
VendorName=MyCompany
ProductName=ServoDrive
VendorNumber=0x00000133
ProductNumber=0x00000001
[DummyUsage]
Dummy0001=1
[Comments]
Lines=0
[MandatoryObjects]
SupportedObjects=3
1=0x1000
2=0x1001
3=0x1018
[1000]
ParameterName=Device type
ObjectType=0x07
DataType=0x0007
AccessType=ro
DefaultValue=0x00000190
[1018]
ParameterName=Identity
ObjectType=0x09
SubNumber=5
[1018sub0]
ParameterName=Number of entries
ObjectType=0x07
DataType=0x0005
AccessType=ro
DefaultValue=4
[1018sub1]
ParameterName=Vendor ID
ObjectType=0x07
DataType=0x0007
AccessType=ro
DefaultValue=0x00000133
[OptionalObjects]
SupportedObjects=2
1=0x1600
2=0x1A00
[1600]
ParameterName=RPDO 1 mapping
ObjectType=0x09
SubNumber=3
[1600sub0]
ParameterName=Number of mapped objects
ObjectType=0x07
DataType=0x0005
AccessType=rw
DefaultValue=2
[1600sub1]
ParameterName=1st mapped object
ObjectType=0x07
DataType=0x000F
AccessType=rw
DefaultValue=0x60000108
[1600sub2]
ParameterName=2nd mapped object
ObjectType=0x07
DataType=0x000F
AccessType=rw
DefaultValue=0x60000208
[1A00]
ParameterName=TPDO 1 mapping
ObjectType=0x09
SubNumber=3
[1A00sub0]
ParameterName=Number of mapped objects
ObjectType=0x07
DataType=0x0005
AccessType=rw
DefaultValue=2
[1A00sub1]
ParameterName=1st mapped object
ObjectType=0x07
DataType=0x000F
AccessType=rw
DefaultValue=0x64000110
[1A00sub2]
ParameterName=2nd mapped object
ObjectType=0x07
DataType=0x000F
AccessType=rw
DefaultValue=0x64000210
✅ 简单直接 - 不需要额外的文件
✅ 快速开发 - 适合已知设备的场景
✅ 代码可控 - 所有配置都在代码中
❌ 需要手动查阅手册 - 必须知道每个对象的索引和数据类型
❌ 容易出错 - 索引或数据类型错误难以发现
❌ 维护困难 - 更换设备需要修改代码
❌ 缺乏灵活性 - 无法自动适配不同型号的设备
using (CanOpenMaster master = new CanOpenMaster(4, 0, 0))
{
master.Initialize(CanBaudRate.BaudRate_500K);
// 添加节点(不提供EDS)
master.AddNode(1, "IO_Module");
// 必须手动指定索引和数据类型
// 假设我们知道0x6000:01是数字输入,8位,只读
var response = master.SdoReadAndWait(1, 0x6000, 0x01);
if (response != null && response.Length >= 5)
{
byte di1 = response[4]; // 需要自己知道这是byte类型
Console.WriteLine($"DI1 = {di1}");
}
// 假设我们知道0x6200:01是数字输出,8位,可读写
master.SdoWriteAndWait(1, 0x6200, 0x01, 0x000000FF);
// PDO也需要手动配置
master.ConfigureTpdoTransmissionType(1, 1, 0xFF); // 事件驱动
}
适用场景:
✅ 自动化配置 - 自动解析对象字典和PDO映射
✅ 减少错误 - 避免手动输入索引和数据类型
✅ 易于维护 - 更换设备只需替换EDS文件
✅ 通用性强 - 同一套代码可适配多种设备
✅ 便于调试 - 可以看到完整的设备信息
❌ 需要EDS文件 - 必须从设备厂商获取
❌ 解析开销 - 需要解析EDS文件(一次性)
❌ 文件管理 - 需要管理多个EDS文件
using (CanOpenMaster master = new CanOpenMaster(4, 0, 0))
{
master.Initialize(CanBaudRate.BaudRate_500K);
// 添加节点并提供EDS文件
string edsPath = @"D:\EDS\ServoDrive.eds";
master.AddNode(1, "Servo_X", edsPath);
// 查看EDS信息
var edsInfo = master.GetEdsInfo(1);
if (edsInfo != null)
{
Console.WriteLine($"厂商: {edsInfo.VendorName}");
Console.WriteLine($"产品: {edsInfo.ProductName}");
Console.WriteLine($"对象数量: {edsInfo.ObjectDictionary.Count}");
}
// 自动配置PDO映射
master.AutoConfigurePdoFromEds(1);
// 通过EDS信息查询对象
var entry = edsInfo.ObjectDictionary[0x6040]; // 控制字
Console.WriteLine($"对象名称: {entry.Name}");
Console.WriteLine($"数据类型: {entry.DataType}");
Console.WriteLine($"访问权限: {entry.AccessType}");
// 更安全的数据读写
if (entry.DataType == "UNSIGNED16")
{
var response = master.SdoReadAndWait(1, 0x6040, 0x00);
if (response != null)
{
ushort controlWord = BitConverter.ToUInt16(response, 4);
Console.WriteLine($"Control Word = 0x{controlWord:X4}");
}
}
}
适用场景:
基础主站功能(无需EDS)
可选的EDS支持
LoadEdsFile() - 加载EDS文件GetEdsInfo() - 获取EDS信息AutoConfigurePdoFromEds() - 自动配置PDO简化的EDS解析
完整的EDS解析器
EdsFileGenerator 进行反向解析对象字典查询接口
// 期望的功能
var value = master.ReadObject<byte>(1, 0x6000, 0x01);
master.WriteObject<ushort>(1, 0x6040, 0x00, 0x0006);
EDS验证
在线EDS更新
// 对于自研设备 - 不使用EDS(硬编码)
master.AddNode(1, "Custom_IO"); // 完全控制的设备
// 对于第三方设备 - 使用EDS
master.AddNode(2, "Servo_Drive", @"D:\EDS\Servo.eds");
master.AddNode(3, "VFD", @"D:\EDS\VFD.eds");
// 对于测试阶段 - 先用EDS,稳定后可以去掉
#if DEBUG
master.AddNode(4, "Test_Device", @"D:\EDS\Test.eds");
#else
master.AddNode(4, "Test_Device"); // 生产环境去掉EDS依赖
#endif
✅ 使用EDS文件
✅ 充分利用EDS信息进行调试
✅ 验证所有对象索引和数据类型
✅ 保留EDS文件用于配置
✅ 记录常用的对象索引
✅ 建立对象字典文档
选项A: 保留EDS(推荐)
- 便于维护和升级
- 支持设备替换
选项B: 移除EDS
- 减少文件依赖
- 提高启动速度
- 需要硬编码关键配置
// 简单IO模块,不使用EDS
master.AddNode(1, "DI_Module");
master.AddNode(2, "DO_Module");
// 定期轮询
while (true)
{
var di = master.SdoReadAndWait(1, 0x6000, 0x01);
ProcessDigitalInput(di);
Thread.Sleep(100);
}
// 多个伺服驱动器,使用EDS
string[] edsFiles = {
@"D:\EDS\Servo_X.eds",
@"D:\EDS\Servo_Y.eds",
@"D:\EDS\Servo_Z.eds"
};
for (int i = 0; i < 3; i++)
{
master.AddNode((byte)(i + 1), $"Axis_{i}", edsFiles[i]);
master.AutoConfigurePdoFromEds((byte)(i + 1));
}
// 通过PDO实时控制
master.EnableSync(1); // 1ms周期
// 自研IO板(无EDS)
master.AddNode(1, "Custom_IO");
// 第三方伺服(有EDS)
master.AddNode(2, "Delta_Servo", @"D:\EDS\Delta.eds");
// 第三方变频器(有EDS)
master.AddNode(3, "ABB_VFD", @"D:\EDS\ABB.eds");
// 统一监控
foreach (var nodeId in master.NodeIds)
{
var edsInfo = master.GetEdsInfo(nodeId);
if (edsInfo != null)
{
Console.WriteLine($"{nodeId}: {edsInfo.ProductName}");
}
else
{
Console.WriteLine($"{nodeId}: Custom Device");
}
}
// 可以通过SDO读取设备信息,生成简易EDS
uint deviceType = master.ReadDeviceType(1);
uint vendorId = master.ReadVendorId(1);
uint productCode = master.ReadProductCode(1);
Console.WriteLine($"Device Type: 0x{deviceType:X8}");
Console.WriteLine($"Vendor ID: 0x{vendorId:X8}");
Console.WriteLine($"Product Code: 0x{productCode:X8}");
// 本项目已有EdsFileGenerator可以生成EDS
// 可以用于为从站生成EDS,也可以参考其格式
| 特性 | 不使用EDS | 使用EDS |
|---|---|---|
| 开发难度 | ⭐⭐ 简单 | ⭐⭐⭐ 中等 |
| 维护成本 | ⭐⭐⭐ 高 | ⭐⭐ 低 |
| 灵活性 | ⭐⭐ 低 | ⭐⭐⭐⭐⭐ 高 |
| 可靠性 | ⭐⭐⭐ 中等 | ⭐⭐⭐⭐ 高 |
| 适用场景 | 自研/简单设备 | 第三方/复杂系统 |
记住: EDS文件是可选但推荐的,根据你的项目需求选择合适的方案! 🎯