<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki2.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=LadderLogic%E6%A1%86%E6%9E%B6</id>
	<title>LadderLogic框架 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki2.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=LadderLogic%E6%A1%86%E6%9E%B6"/>
	<link rel="alternate" type="text/html" href="https://wiki2.lessokaji.com/index.php?title=LadderLogic%E6%A1%86%E6%9E%B6&amp;action=history"/>
	<updated>2026-05-16T16:51:38Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki2.lessokaji.com/index.php?title=LadderLogic%E6%A1%86%E6%9E%B6&amp;diff=1038&amp;oldid=prev</id>
		<title>Artheru：​Initial bilingual draft (auto-published)</title>
		<link rel="alternate" type="text/html" href="https://wiki2.lessokaji.com/index.php?title=LadderLogic%E6%A1%86%E6%9E%B6&amp;diff=1038&amp;oldid=prev"/>
		<updated>2026-05-16T14:00:15Z</updated>

		<summary type="html">&lt;p&gt;Initial bilingual draft (auto-published)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;languages/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 概述 / Overview ==&lt;br /&gt;
'''LadderLogic''' 是 Medulla 提供的 ''周期循环宿主''。CartDefinition 插件用嵌套类 `: LadderLogic&amp;lt;MyCart&amp;gt;` + `[UseLadderLogic(IntervalMs = N)]` 声明一个定时执行的控制循环；框架按 N 毫秒间隔调用 `Operation(int iteration)`。多个循环可在同一 Cart 上共存，各自在独立线程。&lt;br /&gt;
&lt;br /&gt;
'''LadderLogic''' is Medulla's ''cyclic-loop host''. A CartDefinition plugin declares a timed loop via a nested class `: LadderLogic&amp;lt;MyCart&amp;gt;` plus `[UseLadderLogic(IntervalMs = N)]`; the framework calls `Operation(int iteration)` every N ms. Multiple loops can coexist on one cart, each on its own thread.&lt;br /&gt;
&lt;br /&gt;
实现：`D:\src\M2\OfficialPlugins\CartActivator\LadderLogic.cs:7-272`，属性定义 `D:\src\M2\OfficialPlugins\CartActivator\Attrs.cs:26-36`。&lt;br /&gt;
Implementation: `D:\src\M2\OfficialPlugins\CartActivator\LadderLogic.cs:7-272`; attribute at `Attrs.cs:26-36`.&lt;br /&gt;
&lt;br /&gt;
== 最小骨架 / Minimal skeleton ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
public class MyCart : CartDefinition&lt;br /&gt;
{&lt;br /&gt;
    [AsUpperIO] public float vCmd;&lt;br /&gt;
    [AsLowerIO] public float vEst;&lt;br /&gt;
&lt;br /&gt;
    public override void Init()&lt;br /&gt;
    {&lt;br /&gt;
        // connect to hardware here&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    [UseLadderLogic(IntervalMs = 50)]&lt;br /&gt;
    public class Loop : LadderLogic&amp;lt;MyCart&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        public override void Operation(int iteration)&lt;br /&gt;
        {&lt;br /&gt;
            // iteration == 0 on first tick after Init/restart&lt;br /&gt;
            self.WriteToHw(self.vCmd);&lt;br /&gt;
            self.vEst = self.ReadFromHw();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 属性参数 / Attribute parameters ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! 字段 / Field !! 默认 / Default !! 含义 / Meaning&lt;br /&gt;
|-&lt;br /&gt;
| `logic: Type` || (自动)|| LadderLogic 子类（嵌套类自动绑定）&lt;br /&gt;
|-&lt;br /&gt;
| `scanInterval: int` (or `IntervalMs`)|| 50 || tick 周期（ms）&lt;br /&gt;
|-&lt;br /&gt;
| `realTime: bool` || false || 保留，暂未使用 / reserved&lt;br /&gt;
|-&lt;br /&gt;
| `resume: bool` || true || 异常后自动重启循环 / auto-restart on exception&lt;br /&gt;
|-&lt;br /&gt;
| `resumeRetryDelay: int` || 1000 || 重启前等多久（ms）&lt;br /&gt;
|-&lt;br /&gt;
| `timeoutInterval: double` || 10000 || 保留 / reserved&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 生命周期 / Lifecycle ==&lt;br /&gt;
&lt;br /&gt;
  CartDefinition.Init()                  ← 你的初始化&lt;br /&gt;
       │&lt;br /&gt;
       ▼&lt;br /&gt;
  CartDefinition.createLadders()         ← 反射扫 [UseLadderLogic]&lt;br /&gt;
       │&lt;br /&gt;
       ▼ 对每个属性 / for each attribute&lt;br /&gt;
  实例化 LadderLogic&amp;lt;T&amp;gt;, 注入 self = this&lt;br /&gt;
       │&lt;br /&gt;
       ▼&lt;br /&gt;
  创建 MultimediaTimer + 工作线程&lt;br /&gt;
       │&lt;br /&gt;
       ▼ 周期触发 / every scanInterval ms&lt;br /&gt;
  Operation(iteration: 0)   ← 第一次 / first tick&lt;br /&gt;
  Operation(iteration: 1)&lt;br /&gt;
  Operation(iteration: 2)&lt;br /&gt;
  ...&lt;br /&gt;
       │&lt;br /&gt;
       ▼ 异常时 / on exception&lt;br /&gt;
  Hedingben.ToastText(...)&lt;br /&gt;
  如果 resume=true 等 resumeRetryDelay 后重启 / resume after delay&lt;br /&gt;
&lt;br /&gt;
== Tick 精度 / Tick precision ==&lt;br /&gt;
基于 MultimediaTimer（OS 决定，Windows 约 1–15 ms 分辨率）。&lt;br /&gt;
Based on MultimediaTimer; OS-dependent (~1–15 ms on Windows).&lt;br /&gt;
&lt;br /&gt;
'''超时行为''' / Overrun: 若 `Operation()` 耗时 &amp;gt; scanInterval，下一 tick 排队执行（不丢 tick）。长期超时会累积延迟。&lt;br /&gt;
If `Operation()` exceeds scanInterval, the next tick queues behind (no tick skipping). Sustained overrun accrues latency.&lt;br /&gt;
&lt;br /&gt;
【注意】 不要在 `Operation()` 里阻塞 / sleep / 等 IO 超过 scanInterval。&amp;lt;br&amp;gt;&lt;br /&gt;
Don't block / sleep / wait IO longer than scanInterval inside `Operation()`.&lt;br /&gt;
&lt;br /&gt;
== 多 LadderLogic 共存 / Multiple loops ==&lt;br /&gt;
一个 CartDefinition 可以有多个 `[UseLadderLogic]` 属性，每个一对独立的线程 + Timer：&lt;br /&gt;
&lt;br /&gt;
A CartDefinition can declare multiple loops, each on its own thread:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[UseLadderLogic(IntervalMs = 50)]&lt;br /&gt;
public class CtrlLoop : LadderLogic&amp;lt;MyCart&amp;gt; { ... }   // motion control 50 Hz&lt;br /&gt;
&lt;br /&gt;
[UseLadderLogic(IntervalMs = 200)]&lt;br /&gt;
public class BatteryLoop : LadderLogic&amp;lt;MyCart&amp;gt; { ... }  // battery / telemetry 5 Hz&lt;br /&gt;
&lt;br /&gt;
[UseLadderLogic(IntervalMs = 1000)]&lt;br /&gt;
public class DiagLoop : LadderLogic&amp;lt;MyCart&amp;gt; { ... }     // health 1 Hz&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
线程之间共享 cart 字段；如果同一字段同时被多个 loop 读写，自己处理同步（lock / Interlocked）。&lt;br /&gt;
Threads share cart fields; if multiple loops touch the same field, synchronise (lock / Interlocked).&lt;br /&gt;
&lt;br /&gt;
== 内置工具方法 / Built-in helpers ==&lt;br /&gt;
`LadderLogic&amp;lt;T&amp;gt;` 基类提供以下状态机助手（`LadderLogic.cs:50-272`）：&lt;br /&gt;
The `LadderLogic&amp;lt;T&amp;gt;` base class offers these state-machine helpers (`LadderLogic.cs:50-272`):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! 方法 / Method !! 用途 / Use&lt;br /&gt;
|-&lt;br /&gt;
| `TriggerOnce(bool active, int millis, Action a)` || 信号持续 `millis` ms 后触发 `a()` 一次 / fire once after signal held `millis` ms&lt;br /&gt;
|-&lt;br /&gt;
| `WaitSignal(bool sig, int timeout)` || 等信号上升或超时 / wait for signal rising or timeout&lt;br /&gt;
|-&lt;br /&gt;
| `TriggerIfChanged&amp;lt;T&amp;gt;(Func&amp;lt;T&amp;gt; g, Action&amp;lt;T&amp;gt; h)` || 值变化触发 / fire when value changes&lt;br /&gt;
|-&lt;br /&gt;
| `FlipFlop&amp;lt;T&amp;gt;(ref T field, int millis, T[] vals)` || 周期切换值 / cycle values periodically (e.g. blinking LED)&lt;br /&gt;
|-&lt;br /&gt;
| `SwitcherTrigger(bool, Action, bool)` || 边沿触发一次 / edge-trigger one-shot&lt;br /&gt;
|-&lt;br /&gt;
| `ModSignal(Func&amp;lt;bool&amp;gt;, int delay, int span)` || 时间窗内信号检测 / time-window detection&lt;br /&gt;
|-&lt;br /&gt;
| `IsochronousFork(Action)` || &amp;quot;同步分叉&amp;quot;，一次只跑一个 / one-at-a-time async fork&lt;br /&gt;
|-&lt;br /&gt;
| `PriorityActions` || 高优先级动作执行器 / priority action runner&lt;br /&gt;
|-&lt;br /&gt;
| `DaemonVal(float send, float read, float r, int t, Action&amp;lt;bool&amp;gt;)` || 多变量一致性看门狗 / multi-var consistency watcher&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
用这些替代裸 `if (Math.Abs(now - lastEvent) &amp;gt; T) ...` 的散乱时间状态机。&lt;br /&gt;
&lt;br /&gt;
Use these helpers to replace ad-hoc `if (Math.Abs(now - lastEvent) &amp;gt; T) ...` time state-machines scattered through the loop.&lt;br /&gt;
&lt;br /&gt;
== 错误传播 / Error propagation ==&lt;br /&gt;
* `Operation()` 抛异常 → 框架捕获 → log 到 DLog + Hedingben toast `&amp;quot;Ladder broken: &amp;lt;msg&amp;gt;&amp;quot;` 在 UI 显示。&lt;br /&gt;
* 若 `resume = true`：等 `resumeRetryDelay` 后重新调用 `Operation(iteration: 0)`（iteration 重置）。&lt;br /&gt;
* 若 `resume = false`：循环退出，cart 进入&amp;quot;半工作&amp;quot;状态 —— 其它 loop 还在跑。&lt;br /&gt;
&lt;br /&gt;
【发现】 `resume = true` 是默认值。一个 buggy 插件不会让整个进程崩，但会 ''无限重试'' —— 务必在开发期密切看 Hedingben。&amp;lt;br&amp;gt;&lt;br /&gt;
`resume = true` is the default. A buggy plugin won't crash the process but will silently retry forever — watch Hedingben during development.&lt;br /&gt;
&lt;br /&gt;
== iteration 参数 / iteration parameter ==&lt;br /&gt;
* `iteration == 0`：首次 tick 或异常重启后的首次 tick；框架自动清空内部跟踪状态（如 `TriggerOnce` 的计时器）。&lt;br /&gt;
* `iteration &amp;gt; 0`：递增；可用来做 &amp;quot;每 N tick 做一次&amp;quot;。&lt;br /&gt;
&lt;br /&gt;
== 调试 / Debugging ==&lt;br /&gt;
* `Hedingben` toast 是最直接的报错通道 —— 总打开。&lt;br /&gt;
* DLog 有详细 stack trace 用 `$ladder` 主题。&lt;br /&gt;
* 用 `[IOObjectMonitor]` 暴露 `iteration` 或自定义计数器到 Medulla dashboard 看跳速。&lt;br /&gt;
&lt;br /&gt;
== 相关页面 / See also ==&lt;br /&gt;
* [[Special:MyLanguage/CartDefinition属性参考|CartDefinition属性参考]]&lt;br /&gt;
* [[Special:MyLanguage/MDCS引擎适配机器人入门教学|MDCS引擎适配机器人入门教学]]&lt;br /&gt;
* [[Special:MyLanguage/Medulla软件架构|Medulla软件架构]]&lt;br /&gt;
* [[Special:MyLanguage/看门狗Wawa使用说明|看门狗Wawa使用说明]]&lt;br /&gt;
&lt;br /&gt;
[[Category:开发手册]]&lt;br /&gt;
[[Category:二次开发相关说明]]&lt;/div&gt;</summary>
		<author><name>Artheru</name></author>
	</entry>
</feed>