模块 2 练习项目

练习 1:EDS 文件验证器

目标

编写一个程序,验证 EDS 文件的语法正确性和语义一致性。

要求

  1. 解析 EDS 文件(INI 格式)

  2. 验证以下规则:

    • 每个对象必须有 [DeviceInfo] 节
    • 对象索引必须在有效范围内(0x1000-0xFFFF)
    • 数据类型必须是 CiA 301 定义的有效值
    • 访问类型必须是 ro/rw/wo/rwr/rwpre/const 之一
    • ARRAY/RECORD 类型的 sub0 必须表示元素个数
    • 子索引编号必须与节中声明的数量一致
  3. 输出验证报告:

EDS Validator Report
====================
File: sample.eds
Status: PASS (2 warnings)

Objects found: 11
  Mandatory: 5
  Optional: 3
  Manufacturer: 3

Warnings:
  - Object 0x2000: PDOMapping=1 but access type is wo
  - Object 0x1003: SubNumber=9 but only 8 sub-entries found

Errors:
  (none)

测试用例

使用示例 4 中的 sample.eds 进行验证,然后故意修改文件制造错误:

  • 删除 [DeviceInfo] 节
  • 将数据类型改为无效值(如 0xFFFF)
  • 减少子索引数量

提示

  • 可以使用示例 4 的 EDS 解析器作为基础
  • 验证逻辑与解析逻辑分离

练习 2:SDO 批量配置工具

目标

编写一个命令行工具,通过 SDO 批量配置多个节点参数。

要求

  1. 从 JSON 配置文件读取配置:
  1. 对每个节点依次执行配置
  2. 记录每个配置的结果(成功/失败/超时)
  3. 生成配置报告:
SDO Batch Configuration Report
================================
Interface: vcan0
Nodes: 3, 4, 5

Node 3:
  [OK]   0x1017:00 = 1000 (Heartbeat period)
  [OK]   0x1005:00 = 0x80000080 (COB-ID SYNC)

Node 4:
  [OK]   0x1017:00 = 1000 (Heartbeat period)
  [FAIL] 0x1005:00 - Timeout (COB-ID SYNC)

Node 5:
  [OK]   0x1017:00 = 1000 (Heartbeat period)
  [OK]   0x1005:00 = 0x80000080 (COB-ID SYNC)

Summary: 5/6 succeeded, 1 failed

运行方式

./sdo_batch_config config.json

提示

  • 复用示例 5 的 SDO Client 代码
  • 每个配置之间添加 100ms 延时(避免总线拥塞)
  • 使用 select() 实现超时机制

练习 3:SDO 传输性能测试

目标

测量不同数据类型和传输模式下的 SDO 传输延迟。

要求

  1. 测试以下场景:

    • Expedited Upload 1 字节(错误寄存器)
    • Expedited Upload 2 字节(心跳周期)
    • Expedited Upload 4 字节(设备类型)
    • Segmented Upload 16 字节(设备名称)
    • Segmented Upload 256 字节(大数据块)
  2. 每种场景测试 100 次,计算:

    • 平均延迟(毫秒)
    • 最小延迟
    • 最大延迟
    • 成功率
  3. 输出测试报告:

SDO Performance Test Report
============================
Interface: vcan0
Iterations per test: 100

Test                    Avg(ms)  Min(ms)  Max(ms)  Success
─────────────────────────────────────────────────────────
Expedited 1B            0.52     0.48     0.61     100/100
Expedited 2B            0.53     0.49     0.65     100/100
Expedited 4B            0.54     0.50     0.72     100/100
Segmented 16B           1.21     1.10     1.45     100/100
Segmented 256B          18.35    17.80    20.12    100/100

Analysis:
  - Expedited transfers are ~2x faster than Segmented (small data)
  - Segmented 256B requires 37 segments (256/7 bytes per segment)
  - Each segment adds ~0.5ms round-trip latency

实现方式

  • 使用示例 7 的 SDO Demo 作为 Server
  • 编写测试脚本自动发送请求并计时

提示

  • 使用 clock_gettime(CLOCK_MONOTONIC) 获取高精度时间戳
  • 考虑 CAN 总线发送延迟(通常 0.1-0.5ms)
  • 在虚拟 CAN 上测试的延迟比真实 CAN 硬件低

思考题

1. Expedited vs Segmented 的选择

问题:如果数据正好是 4 字节,必须使用 Expedited 传输吗?可以使用 Segmented 吗?

提示:CANOpen 规范允许服务端根据数据类型自主选择传输模式。考虑服务端实现的复杂度。

2. Toggle 位的作用

问题:为什么 Segmented 传输需要 Toggle 位?如果只用序号(0, 1, 2…)而不是翻转位,会有什么优缺点?

提示:考虑丢包场景。如果服务端发送了段 0、1、2,但客户端只收到 0、2,序号方案和 Toggle 方案分别如何检测这个问题?

3. 多节点 SDO 并发

问题:如果主站同时向节点 3 和节点 5 发送 SDO 请求,会发生什么?CAN 总线的仲裁机制如何保证帧不混淆?

提示:考虑 COB-ID 的仲裁优先级。节点 3 的请求(0x603)和节点 5 的请求(0x605)在总线上如何区分?

4. 对象字典的动态性

问题:在机械臂应用中,关节数量可能变化(4-DOF、6-DOF、7-DOF)。如何设计对象字典使其能适应不同配置?

提示:

  • 方案 1:预定义最大数量的条目,未使用的标记为"不可用"
  • 方案 2:运行时动态创建对象字典条目
  • 方案 3:使用 EDS 文件生成工具,为每个配置生成不同的 EDS

分析每种方案的优缺点和实现复杂度。


扩展阅读

  1. CiA 301:CANOpen 应用层规范(SDO 协议详细定义)
  2. CiA 306:EDS 文件格式规范
  3. CANopenNode 源码:https://github.com/CANopenNode/CANopenNode
    • 301/CO_SDOserver.c:服务端实现
    • 301/CO_SDOclient.c:客户端实现
  4. CANFestival 源码:https://forge.canfestival.org/
    • src/sdo.c:SDO 核心逻辑

验收标准

项目完成标准
练习 1能正确解析和验证 sample.eds,并检测故意引入的错误
练习 2能对 3 个节点进行批量配置,并生成报告
练习 3能测量不同传输模式的延迟,数据合理
思考题有清晰的分析和答案
如果这篇文章对你有帮助,欢迎请我喝杯咖啡 ☕
Cygnus Yang 支付宝支付宝
Cygnus Yang 微信微信