<?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=DriveTask%E8%B0%83%E5%BA%A6%E5%BE%AA%E7%8E%AF</id>
	<title>DriveTask调度循环 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki2.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=DriveTask%E8%B0%83%E5%BA%A6%E5%BE%AA%E7%8E%AF"/>
	<link rel="alternate" type="text/html" href="https://wiki2.lessokaji.com/index.php?title=DriveTask%E8%B0%83%E5%BA%A6%E5%BE%AA%E7%8E%AF&amp;action=history"/>
	<updated>2026-05-16T16:51:30Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki2.lessokaji.com/index.php?title=DriveTask%E8%B0%83%E5%BA%A6%E5%BE%AA%E7%8E%AF&amp;diff=1036&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=DriveTask%E8%B0%83%E5%BA%A6%E5%BE%AA%E7%8E%AF&amp;diff=1036&amp;oldid=prev"/>
		<updated>2026-05-16T14:00:12Z</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;
`DriveTask` 是 Clumsy 内部把 [[Special:MyLanguage/MovementDefinition详解|`MovementDefinition`]] 的 ''迭代器''变成 ''周期控制循环''的工具。每次调用 `DriveTask.WaitDriveTask(IEnumerable&amp;lt;bool&amp;gt;)` ：&lt;br /&gt;
1. 起一条 ''新线程''（`ThreadPriority.AboveNormal`）。&lt;br /&gt;
2. 每隔 `Configuration.conf.DriveTaskInterval`（默认 20 ms）调一次 `enumerator.MoveNext()`。&lt;br /&gt;
3. 阻塞调用方直到迭代器结束（正常完成或异常）。&lt;br /&gt;
&lt;br /&gt;
`DriveTask` is Clumsy's mechanism for turning a [[Special:MyLanguage/MovementDefinition详解|MovementDefinition]]'s iterator into a '''timed control loop'''. Each `DriveTask.WaitDriveTask(IEnumerable&amp;lt;bool&amp;gt;)` call:&lt;br /&gt;
1. Spawns a new thread at `ThreadPriority.AboveNormal`.&lt;br /&gt;
2. Calls `enumerator.MoveNext()` every `Configuration.conf.DriveTaskInterval` (default 20 ms).&lt;br /&gt;
3. Blocks the caller until the iterator ends (success or exception).&lt;br /&gt;
&lt;br /&gt;
实现：`D:\src\Clumsy\ClumsyCore\DriveTask.cs:34-205`。&lt;br /&gt;
Implementation: `D:\src\Clumsy\ClumsyCore\DriveTask.cs:34-205`.&lt;br /&gt;
&lt;br /&gt;
== 标准用法 / Standard usage ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
DriveTask.WaitDriveTask(new SteeringLineFollowing&lt;br /&gt;
{&lt;br /&gt;
    srcX = sx, srcY = sy,&lt;br /&gt;
    dstX = dx, dstY = dy,&lt;br /&gt;
    basespeed = 600&lt;br /&gt;
}.Follow());&lt;br /&gt;
// Returns when the Movement finishes (normal or thrown)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 循环细节 / Loop details ==&lt;br /&gt;
&lt;br /&gt;
  WaitDriveTask(IEnumerable&amp;lt;bool&amp;gt;) 入口:&lt;br /&gt;
       │&lt;br /&gt;
       ▼&lt;br /&gt;
  new DriveTask:&lt;br /&gt;
    enumerator = iterable.GetEnumerator();&lt;br /&gt;
    Thread(prio=AboveNormal) starts:&lt;br /&gt;
       │&lt;br /&gt;
       ▼ 循环 / loop:&lt;br /&gt;
    if (stopToken) break;&lt;br /&gt;
    bool keepGoing = enumerator.MoveNext();&lt;br /&gt;
    if (!keepGoing) { stopped_reason = 0; break; }&lt;br /&gt;
    Thread.Sleep(DriveTaskInterval);   // 20 ms 默认&lt;br /&gt;
       │&lt;br /&gt;
       ▼ 退出 / exit (any cause):&lt;br /&gt;
    Monitor.PulseAll(wait)&lt;br /&gt;
       │&lt;br /&gt;
       ▼&lt;br /&gt;
  WaitDriveTask blocks on Monitor.Wait(wait)&lt;br /&gt;
       └─→ 醒来后检查 exception，重新抛 / wakes, rethrows captured exception if any&lt;br /&gt;
&lt;br /&gt;
== `DoUntil` 并行检查 / Parallel termination check ==&lt;br /&gt;
`DoUntil(IEnumerable&amp;lt;bool&amp;gt; condition)` 起一条 ''并行''任务，独立轮询 `condition`；若 `condition.MoveNext()` 返回 true，停止主 Movement 并设置 `stopped_reason = stop_condition_id`：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
var driveTask = DriveTask.WaitDriveTaskBegin(new SteeringLineFollowing { ... }.Follow());&lt;br /&gt;
driveTask.DoUntil(new ObstacleCloseCheck { distThres = 200 }.Get());&lt;br /&gt;
driveTask.Wait();  // blocks; returns when either main Movement done OR DoUntil fires&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`stopped_reason` 区分了正常完成 (0)、`DoUntil` 触发（其条件 id）、异常 (-1)。&lt;br /&gt;
`stopped_reason` differentiates normal (0), `DoUntil` triggered (the cond ID), and exception (-1).&lt;br /&gt;
&lt;br /&gt;
== 与 SecurityCheck 的关系 / Relation to SecurityCheck ==&lt;br /&gt;
`PilotBase.SecurityCheck()`（`D:\src\Clumsy\ClumsyCore\Pilot\PilotDefinition.cs:64-75`）是 ''独立''的看门狗，每个 Movement 都不感知它。SecurityCheck 监测 ：&lt;br /&gt;
* 当前 DriveTask 是否在 `Configuration.conf.DriveTaskTimeout`（默认 300 ms）内有控制信号产生。&lt;br /&gt;
* 若没有 → 调 `DriveStop()` 强制车停 → 主 DriveTask 的 `stopToken = true` → 下一 tick 退出循环。&lt;br /&gt;
&lt;br /&gt;
【发现】 SecurityCheck 不杀 Movement 的 enumerator；它只是让 DriveTask 在下一 tick 退出循环。所以 ''Movement 作者需自己确保 `Get()` 在迭代器内可被中断''（不要 sleep 长时间）。&amp;lt;br&amp;gt;&lt;br /&gt;
SecurityCheck doesn't kill the enumerator; it just lets the loop bail next tick. Movement authors must keep `Get()` interruptible (no long sleeps).&lt;br /&gt;
&lt;br /&gt;
== 异常传播 / Exception propagation ==&lt;br /&gt;
* `MoveNext()` 抛异常 → 捕获到 `_exception` 字段 → `stopped_reason = -1` → 触发 `Monitor.PulseAll`。&lt;br /&gt;
* `WaitDriveTask` 调用方 ''醒来后''重新抛该异常。&lt;br /&gt;
* 上游 `SimpleAgvInterface.Queue` 的 action 内异常 → 记到 `queueInfo[i].exception`，跳过本行剩余 action。&lt;br /&gt;
&lt;br /&gt;
【注意】 不要把异常 ''吞''在 Movement 内。让它传出，让上层决定恢复策略。&amp;lt;br&amp;gt;&lt;br /&gt;
Don't swallow exceptions inside Movements; let them propagate so the upper layer decides.&lt;br /&gt;
&lt;br /&gt;
== Thread Priority 与延迟 / Thread priority &amp;amp; latency ==&lt;br /&gt;
* DriveTask 线程是 `AboveNormal`，比 LadderLogic 略高。&lt;br /&gt;
* tick 抖动主要来自 `Thread.Sleep` 精度（Windows ~1–15 ms 量级）。&lt;br /&gt;
* 高速 / 高精度场景（如 [[Special:MyLanguage/汽车面差检测|汽车面差检测]]）可能需要在 PLC 层做关键回路，DriveTask 仅做高层规划。&lt;br /&gt;
&lt;br /&gt;
== 在 SimpleAgvInterface 中的使用 / Usage in SimpleAgvInterface ==&lt;br /&gt;
`SimpleAgvInterface.Queue` 的每个 action 内通常一次 `DriveTask.WaitDriveTask(...)`。详见 [[Special:MyLanguage/SimpleAgvInterface Queue机制|SimpleAgvInterface Queue机制]]。&lt;br /&gt;
&lt;br /&gt;
Each action inside `SimpleAgvInterface.Queue` typically calls `DriveTask.WaitDriveTask` once.&lt;br /&gt;
&lt;br /&gt;
== 配置 / Configuration ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! 字段 / Field !! 默认 / Default !! 文件 / File&lt;br /&gt;
|-&lt;br /&gt;
| `DriveTaskInterval` || 20 ms || `D:\src\Clumsy\ClumsyCore\Configuration.cs`&lt;br /&gt;
|-&lt;br /&gt;
| `DriveTaskTimeout` || 300 ms || same&lt;br /&gt;
|-&lt;br /&gt;
| `basicSpeed` || 项目相关 || same&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
从嵌入资源 `ClumsyCore.res.defaultconf.json` 加载，或用 `Configuration.FromFile(fn)` 覆盖。&lt;br /&gt;
Loaded from embedded `ClumsyCore.res.defaultconf.json` or overridden via `Configuration.FromFile`.&lt;br /&gt;
&lt;br /&gt;
== 常见错误 / Common mistakes ==&lt;br /&gt;
* '''忘了 `WaitDriveTask` 是阻塞的''' → 在 UI 线程调会冻 UI。包到 `SimpleAgvInterface.Queue` 的 async action 里。&lt;br /&gt;
* '''Movement Get() 不 yield''' → 立即耗尽，DriveTask 立即返回，看起来&amp;quot;完成了 0 ms&amp;quot;。Always `yield return` at least once per control cycle.&lt;br /&gt;
* '''DriveStop 中无 vCmd = 0''' → 即使 enumerator 停了，最后一帧的 vCmd 还在 DObject 里，车继续动。在 `DriveStop()` 里显式清零所有 IDriveWriter 状态。&lt;br /&gt;
&lt;br /&gt;
* `WaitDriveTask` is blocking; calling it on the UI thread freezes UI. Wrap in `SimpleAgvInterface.Queue`'s async action.&lt;br /&gt;
* If `Get()` never yields, DriveTask exits immediately.&lt;br /&gt;
* `DriveStop()` must explicitly zero all IDriveWriter outputs; otherwise the last frame's `vCmd` stays in DObject.&lt;br /&gt;
&lt;br /&gt;
== 相关页面 / See also ==&lt;br /&gt;
* [[Special:MyLanguage/MovementDefinition详解|MovementDefinition详解]]&lt;br /&gt;
* [[Special:MyLanguage/SimpleAgvInterface Queue机制|SimpleAgvInterface Queue机制]]&lt;br /&gt;
* [[Special:MyLanguage/巡线行走|巡线行走]]&lt;br /&gt;
* [[Special:MyLanguage/绕障行走|绕障行走]]&lt;br /&gt;
* [[Special:MyLanguage/车体抽象原理|车体抽象原理]]&lt;br /&gt;
* [[Special:MyLanguage/Clumsy-API|Clumsy-API]]&lt;br /&gt;
&lt;br /&gt;
[[Category:二次开发相关说明]]&lt;br /&gt;
[[Category:运动控制使用手册]]&lt;/div&gt;</summary>
		<author><name>Artheru</name></author>
	</entry>
</feed>