插件开发清单

来自MDCS wiki2
跳到导航 跳到搜索


概述 / Overview

本页是 MDCS 插件开发中 该做与不该做(Do's & Don'ts)的速查表。从生产经验中总结,每一条都对应一个真实踩过的坑。

This page is the MDCS plugin-development Do's & Don'ts. Each rule reflects a real production pitfall.

Do's

命名与契约 / Naming & contract

  • Medulla 插件入口类名必须叫 `MainIOObject` —— 严格大小写。
 Medulla plugin entry class must be exactly `MainIOObject`.
  • 每个插件目录加 README + CHANGELOG,写清适配的硬件型号 + 版本 + 联系人。
  • AssemblyInformationalVersion 含 助记词 如 `1.4.0+kindling`,便于现场区分两个数字相同的二进制。

生命周期 / Lifecycle

  • 构造函数廉价无副作用 —— 硬件连接放在 `Init()`。
 Constructor must be cheap and side-effect-free; hardware contact in `Init()`.
  • `Init()` 内捕获异常,设 `eStop = true` + Hedingben toast —— 不要让 `Init()` 抛出,否则 LadderLogic 部分启动部分不启动,难诊断。
 Catch exceptions in `Init()`; set `eStop = true` rather than throwing.
  • 每次部署前用 `io load` 在 干净控制台测试一次加载 —— 提前发现 Costura 缺失依赖。

LadderLogic

  • 不阻塞 `Operation()` 超 scanInterval —— 起 worker 线程或用 `TriggerOnce` / `WaitSignal` 拆分。
 Don't block `Operation()` for longer than `scanInterval`. Spawn a worker or split with helpers.
  • 共享字段加锁 —— 多个 LadderLogic 并发访问同一字段时用 `lock` 或 `Interlocked`。
  • 发布期间监控 Hedingben —— `resume = true` 默认会静默重启 buggy 循环 ;新插件上线时人在场看 toast。

IO 表 / IO fields

  • 上位字段 `*Cmd` 后缀,下位 `*Est` 后缀 —— 项目约定,避免同名冲突。
  • `[AsInitParam]` 字段加默认值 —— 即使没人设也能初始化。
  • 敏感字段加 `[IOObjectWatch]` —— 电量低 / 温度高 自动告警。

Movement / Clumsy

  • Movement 实现可重入 —— 不要 static 字段保存状态。
  • 在 `Get()` 第一帧读 pose,不要在构造时读 —— 构造与执行间车可能已经移动。
  • Movement 长度 ≤ 50 行 —— 超过就拆成多个 Movement 组合。

Detour / 定位 / TightCoupler

  • 诚实报协方差 —— 谎报会让 TightCoupler 让该源 统治融合 → 全局发散。
  • 外部反馈 `counter` 单调递增 —— 用来检测丢帧 / 乱序。
  • `integrated = true` 配 `startingTick` —— 重置(IMU 重启)时给新 baseline。

工程 / Project

  • 每个 csproj 用 `..\tools\` HintPath —— 仓库一致约定。
  • FodyWeavers.xml 含 Costura + LessokajiWeaver
  • Release 模式发布 —— Debug 会保留更多 PDB / 符号;体积大。
  • 测试 .NET 4.8 ↔ .NET 6/8 兼容 —— 部分老 driver 还在 .NET Framework。

DObject

  • 名 ≤ 32 字符 —— 超长会被静默截断。
  • 读者用 `Wait()` 阻塞 —— 比轮询省 CPU。
  • 每次 Post 含 frame counter —— 读者能检测丢帧。

文档 / Documentation

  • README 写清 硬件型号 + 协议版本
  • CHANGELOG 含具体行为变化 —— 不是 "fix bug"。
  • startup.iocmd 示例放在 INSTALL.txt —— 客户照抄。

Don'ts

命名

  • 不要把入口类改名(如 `MyLidar : Lidar2DIOObject`) —— 加载器找不到。
  • 不要给 IOObject 加 `[Plugin]` 属性 —— MDCS 不用 manifest,加了也无效。

加载

  • 不要热替换 DLL —— Costura 缓存导致未定义行为。停 → 替换 → 启动。
  • 不要在 `static` 构造函数里碰硬件 —— 加载时立刻触发。
  • 不要假设 `Init()` 立刻被调 —— 它要 startup.iocmd 里的 `<inst> Init` 显式触发。

IO 表

  • `[AsUpperIO]` 不要标在 `readonly` 字段上 —— 编译过,运行时 `MissingMethodException`。
  • 不要从外部直接写 `MedullaCartUpperIO<tag>` DObject —— 总走 `SetUpperIO`,否则失同步。
  • 不要把高速字段都 `[IOObjectMonitor]` 加 `VerboseLog` —— 日志爆炸。

LadderLogic

  • 不要在 `Operation()` 里 `Thread.Sleep` —— 阻塞整个 loop 线程。
  • 不要假设 LadderLogic 是实时 —— Windows 上 1–15 ms 抖动;真实时需要 PLC。
  • 不要在多 LadderLogic 之间共享 可变字段而不加锁

Movement

  • 不要在 Movement 里 `Thread.Sleep` —— 用 `yield return` 多次。
  • 不要在 `Get()` 抛异常但不写 `eStop = true` —— 车继续按上一帧 `vCmd` 走。
  • 不要从 UI 线程调 `DriveTask.WaitDriveTask` —— 它阻塞。

Queue

  • 不要假设 Queue 的不同行真的并行 —— 当前实现是串行(行 i 等行 i-1)。详见 Queue 机制 的"超标量实际行为"段。
  • 不要在 action 内 忽略异常 —— 让它传出,让上层决定恢复。

Detour

  • 不要在雷达插件里调 `TightCoupler.PostExternalFeed` —— 雷达走 DObject `output()` 路径;TightCoupler 是 非雷达来源的入口。
  • 不要谎报协方差 —— 永远不要 "我超准请相信我"。
  • 不要在 SLAM 输出帧间 内部重新加载地图 —— 用 Detour 的 reload API。

SimpleComposer / Fleet

  • 不要在 `BusinessLogic.Plan` 里阻塞超过 100 ms —— UI 假死。
  • `[CarType]` 标 class,不要标实例字段 —— 反射查找按 Type。
  • 不要在 SimpleComposer 进程内调阻塞 HTTP —— 用 async/await。

Costura / 构建

  • 不要给 核心 DLL 加 Costura.Fody —— `MedullaCore.dll` / `ClumsyCore.dll` 等保持 loose DLL,让插件共载。
  • 不要直接引用 impl DLL —— 引用 `Ref<Name>.dll`;否则带入 Costura 内嵌的整套依赖。

DObject

  • 不要在 Linux 上假设 `io_shared` MMF —— Linux 上是文件后备。
  • 不要 cache 多个 `new DObject("name")` 实例 —— 一个 name 一个,跨进程共享。

性能反模式 / Performance anti-patterns

  • 每帧 `new` 大数组 —— 用 buffer 池或预分配。
  • 每帧 `Console.WriteLine` —— 日志走 DLog,主题化、可关闭。
  • 每帧序列化大对象到 DObject —— 用紧凑二进制,避免 JSON。
  • Movement 内每帧 `LINQ` 链 —— `foreach` + 索引循环。

安全 / Safety

  • e-stop 必须 独立于 Movement 逻辑 —— 硬件 e-stop 线 + 软件 watchdog 双层。
  • 激光雷达 < 300 mm 范围内任何点 → 触发硬 stop —— 不能等 Movement 层减速。
  • 功能安全设备(SIL-2 / PL-d)独立于 MDCS —— MDCS 是控制层,不是安全层。

相关页面 / See also