Medulla软件架构
概述 / Overview
Medulla 是 MDCS 的硬件层:它把异构硬件(电机控制器、PLC、传感器、相机、雷达)抽象成 IOObject 与 字段,并提供跨进程共享内存(DObject)让上层算法订阅数据,无关进程或语言。
Medulla is the hardware-abstraction layer of MDCS: it wraps heterogeneous hardware (motor controllers, PLCs, sensors, cameras, lidars) into IOObject instances exposing typed fields, and exposes them across processes via the DObject shared-memory bus.
关键概念 / Key concepts
| 概念 / Concept | 含义 / Meaning |
|---|---|
| `IOObject` | 一切硬件抽象的基类 / base class for everything: lidars, cameras, carts. File: `D:\src\M2\MedullaCore\Types\IO.cs:47` |
| Sub-classes | `Lidar2DIOObject`, `Lidar3DIOObject`, `CartDefinition`, camera `MainIOObject` |
| `[AsInitParam]` | 启动配置字段 / start-time config field (JSON-serialised) |
| `[AsUpperIO]` / `[AsLowerIO]` | 上 / 下位 IO 字段 / command-down / status-up field |
| `[UseLadderLogic]` | 周期性控制循环(默认 50 ms)/ cyclic control loop (default 50 ms) |
| `[IOObjectMonitor]` | 注册字段到监控面板 / dashboard registration |
| `[IOObjectUtility]` / `WebUtility` | 注册方法为 UI 按钮 / web API / register as UI button / web endpoint |
| `DObject` | 命名共享内存(跨进程)/ named shared memory (cross-process). 详见 DObject |
| `LadderLogic<T>` | 周期性回调宿主 / cyclic-callback host |
体系结构 / Architecture
Plugin DLL (CartDef, Lidar2DIOObject, ...)
│ reflection-loaded by name (no [Plugin] attr)
▼
MedullaCore: IOObject lifecycle, threading, DObject pub/sub
│
▼
DObject (shared memory, cross-process)
▲ ▲
│ │
Detour, Clumsy, SimpleComposer — subscribers
Medulla 既是 加载器 又是 运行时:插件 DLL 通过 `io load plugins/X.dll` 启动命令载入;反射查找入口类(`MainIOObject` 或 `CartDefinition` 派生),实例化,调用 `Init()`,启动配置的 LadderLogic 周期线程。
Medulla is both loader and runtime: plugin DLLs are loaded via the `io load plugins/X.dll` startup command; reflection finds the entry type (named `MainIOObject` or derived from `CartDefinition`), instantiates it, calls `Init()`, and spawns the configured LadderLogic threads.
插件加载示例 / Plugin loading example
# startup.iocmd
lidar = io load plugins/MyLidar.dll
lidar Start 192.168.0.2 2110
cart = io load plugins/MyCart.dll
cart Init
`io load` 把 DLL 反射扫描后实例化入口类;其余命令通过赋值(左侧)保存引用,并把命令转发给该实例。
`io load` reflection-scans the DLL, instantiates the entry type, and the variable assignment keeps a reference. Subsequent commands forward to the instance.
上下位 IO 数据流 / Upper / lower IO data flow
见 车体抽象原理。简而言之:
- 上位 IO(`[AsUpperIO]`)= 调度 / Clumsy 写入命令;Medulla 转发到硬件。
- 下位 IO(`[AsLowerIO]`)= Medulla 读硬件状态;调度 / Clumsy 订阅。
- 初始化参数 IO(`[AsInitParam]`)= 启动时一次性 JSON 注入。
- 监控(`[IOObjectMonitor]`)= 显示在 Medulla 仪表盘 + 暴露给 Web API。
LadderLogic 周期循环 / Ladder cycles
LadderLogic 是 Medulla 提供的 周期性控制循环宿主。一个 `CartDefinition` 可以有多个 LadderLogic 嵌套类,每个 `[UseLadderLogic(IntervalMs = N)]`:
A `CartDefinition` may declare multiple nested LadderLogic classes, each at a configured tick rate:
[UseLadderLogic(IntervalMs = 50)]
public class ControlLoop : LadderLogic<MyCart>
{
public override void Run(MyCart self)
{
// 写 UpperIO → 读硬件 → 更新 LowerIO
}
}
[UseLadderLogic(IntervalMs = 200)]
public class BatteryMonitor : LadderLogic<MyCart>
{
public override void Run(MyCart self)
{
// 较慢的循环,例如电池电压采样
}
}
DObject 共享内存 / DObject IPC
DObject 是 Medulla 提供的 命名共享内存 pub/sub:发布者写一个二进制 blob,订阅者按名字订阅,等到下一帧再读。Detour 用 DObject 读雷达数据;SimpleComposer 用 DObject 读车辆状态。详见 DObject。
DObject is the named binary pub/sub channel. The publisher writes a blob, subscribers wait on the name and consume. Used by Detour for lidar, SimpleComposer for vehicle state. See the dedicated page.
与 Medulla 1(旧版)的区别 / vs legacy Medulla
- `D:\src\M2\` 是 Medulla2(当前在用),`D:\src\Medulla\` 是 legacy。
- Medulla2 引入了:DObject 替代旧 IPC、属性化 IO 表(`[AsUpperIO]` 等)、`LessokajiWeaver` 编译后处理生成代理类。
- 已 不要使用 legacy Medulla 编写新插件。
相关页面 / See also
- Medulla — 主页 / canonical entry
- Medulla-API
- DObject
- 车体抽象原理
- 如何适配新的雷达
- LessokajiWeaver编译后处理工具