FASS 2.0 / scene.signal

磁条交管逻辑与策略说明

MagCar 管控区排队、兼容组并行与扫车放行

适用对象:现场实施、调度配置、软件维护
配置文件:SimpleLite 工作目录 Config/Signal/mag-control-areas.json
进程名称:磁条交管进程(MagTrafficMission)
文档日期:2026-08-18

1. 文档目的与适用范围

本文说明 FASS 2.0 磁导航场景中,磁条交管进程如何根据管控区配置表对 MagCar(FASS 1.0 磁条车)进行停车等待、排队和放行。读者按本文即可完成十字路口、汇合点、单入口限流的配表,并理解扫车每一拍在做什么。

1.1 适用

1.2 不适用

2. 总体策略

交管策略可以概括为四句话:

  1. 按区绑定:同一「管控区名称」的多行表示同一个物理路口(或汇合区)。
  2. 按线占用:每一行有自己的内部站点列表和容量,占用只统计本行站点,不把整个路口并成一份。
  3. 冲突才互斥:同区里,兼容组相同,或两行内部站点有交集,视为冲突,不能同时放;否则可并行。
  4. 冲突才排队:优先级、到达时刻、等待时长只在冲突线路之间生效。不冲突的线路互不插队、互不占名额。
兼容组留空且同区多行都为空时,视为同一组,整区互斥,与早期「同区容量 1 只放一辆」的行为兼容。旧 JSON 不填兼容组即可沿用。

3. 配置表(交管策略字段)

主键是管控触发站点。同一触发点多条启用记录只保留第一条。未启用(IsUse=false)的行保留在文件中但不参与判定。

字段JSON 键含义与配法
管控触发站点 TriggerSit MagCar 必须停稳在此站点后才进入本行排队。应对齐现场停车点,不要把路口内部行驶点当成触发点。
管控区名称 AreaName 同名多行绑成一个路口,共用等待时长(取最长)。空则该触发点自成一区,相当于单入口限流。
兼容组 CompatGroup 同区里互不干扰的线路填不同组名(如东西 EW、南北 NS)。会交叉、会抢同一段路的填同组。空字符串与其他空组视为同组。
优先级 Priority 整数,越大越先放。干道高、支路低。只在冲突线路之间比较。
等待时长 WaitSeconds 秒。同区多行不一致时取最长。≤0 表示不做插队。用于防止支路被干道一直堵住。
管控区站点列表 ControlArea 本线路穿过路口的内部站点,逗号分隔,如 10,11。不要把各方向排队触发点写进来。空则回退为触发点本身。
区内最多几辆 ControlCapacity 本行容量。小于 1 按 1 处理。统计范围:占用本行内部站点的车 + 与本行冲突、已发启动但未进区的在途车。
放行后启停字节 ControlReleaseStartStop 兼容字段。MagCar 放行发 FASS 1.0 启动指令,不使用该字节。
启用 IsUse false 时本行不生效。

3.1 运行态(不入库)

名称说明
到达时刻 进程第一次扫到该 MagCar 停在该触发点的时间。开走后再回来重新计时。不写入 JSON。
在途占额 已对该车发过启动,但尚未占用本行内部站点。避免「刚放行、车还在触发点」时下一拍又放一辆冲突车。

3.2 进程参数

参数默认说明
TickMs1000扫车周期(毫秒),下限按 200ms 夹紧。
PendingTimeoutSeconds8在途超时(秒)。超时后取消占额,防止启动失败把名额卡死。
AreasPathConfig\Signal\mag-control-areas.json相对路径只解析 SimpleLite 工作目录,不读 plugins 目录。

4. 交管逻辑(扫车每一拍)

进程启动或点「重新加载配置」后,读取启用规则。此后约每秒执行一次 ScanAndRelease

单拍流程
  1. 快照全场车辆:站点(siteID / GetLastSite)、占用站点(siteID + holdingLocks)、是否 MagCar、是否停稳。
  2. 启用规则按管控区名称分组(空名称则按「#sit:触发点」自成一区)。同区等待时长取各行之最长。
  3. 清理到达时刻:已离开原触发点的车重新计时。
  4. 清理在途:车消失、超时、或已经踩到本行内部站点 → 去掉在途标记(进区后改由占用统计)。
  5. 收集本区停在各触发点上的停稳 MagCar,记为等待队列;已在途的不再重复发启动。
  6. 按第 6 节规则排序,然后从队头到队尾贪心:本行有空位则发启动并登记在途;无空位则跳过,继续看后面不冲突的车。
  7. 放行动作:先尝试停充,再 StartMagCar(FASS 1.0 启动)。

4.1 何谓停稳

状态不是「运行中 / Running」。下列视为可排队:停止中、充电中、WaitPass,以及没有 pendingLocks、没有 occupied 标签的非运行状态。充电中的车放行前会尝试 StopCharge。

4.2 占用怎么数

对某一等待车辆,只统计占用该行 ControlArea 的他车。排队触发点上尚未放行的 MagCar 不计入占用(它们还在区外等候)。本车不计。

占用站点来源:车辆当前 siteID,以及 status.holdingLocks。任一命中列表即算 1 辆。

4.3 可放行数(空位)

空位 = 本行容量 − 占用本行站点的车 − 与本行冲突的在途车

空位 ≥ 1 才对该车发启动。容量 1 表示:本线路内部(含冲突在途)最多一辆。

在途车若已经进入本行内部站点,只算「占用」,不再重复算「在途」,避免一名额扣两次。

5. 冲突判定(能否并行)

只比较同一管控区名称下的两行(或一行与一条在途记录)。不同区互不影响。

满足下面任一条件即冲突(互斥):

  1. 兼容组相同(不区分大小写,去首尾空格)。两边都为空也算相同 → 整区互斥。
  2. 两行的管控区站点列表有交集。

两组都不同、且站点列表不相交 → 不冲突,可同时放行

场景兼容组内部站点结果
旧表、未填兼容组都空任意同区全部互斥
东西对向直行都填 EW可不相交同组,互斥(对向若也要并行,应拆成不同组且站点不相交)
东西 / 南北互不交叉EW 与 NS10,11 与 20,21不冲突,可并行
组名不同但抢同一段EW 与 NS都含 15站点相交,仍互斥
左转与对向直行交叉建议同组,或站点列出交叉段有交集或同组互斥
若四个方向都复制同一份内部站点(例如都写 10,11,12,13),则即使兼容组不同也会因站点相交而全部互斥。要对向并行,必须按方向拆开内部点,且不要把触发点写进列表。

6. 排队规则(仅冲突线路)

同一管控区内,先按下列比较函数排序,再贪心放行。不冲突的车排序先后不影响能否同时过,只影响扫描顺序。

6.1 插队(等待时长)

当同区等待时长 W > 0,且两车优先级不同:

高优先级到达时刻 − 低优先级到达时刻 > W,则低优先级先走。

含义:低优先级更早到达,且已经比高优先级早到超过 W 秒,避免支路饿死。差值未超过 W 时,仍让优先级高的先走。

使用「>」而不是「≥」。例如 W=10,恰好早到 10 秒时仍按优先级。

6.2 默认顺序

  1. 未触发插队时:优先级数值大的在前。
  2. 优先级相同:到达时刻早的在前。
  3. 仍相同:车号小的在前(稳定次序)。

6.3 贪心,而不是只放队头

排序后从前往后看。队头因本线已满或冲突在途没有空位时,跳过队头,继续检查后面的车。这样南北已占用时,队头若是南北,不会挡住后面可以走的东西向车辆。

7. 放行与在途生命周期

  1. 判定可放 → StopCharge(若有)→ StartMagCar。
  2. 登记在途:记录区名、触发点、兼容组、本行内部站点、放行时刻。
  3. 下一拍该车仍停在触发点:不再重复启动,但作为冲突在途占额。
  4. 车进入本行内部站点:清除在途,改为占用统计。
  5. 超过 PendingTimeoutSeconds(默认 8 秒)仍未进区:清除在途,避免卡死。车若仍停在触发点,下一拍可再次进入排队。
  6. 车离线或从系统消失:清除在途与到达时刻。

重新加载配置会清空到达时刻和在途表,请避免在路口有车等待时频繁重载。

8. 配置示例

8.1 十字路口:东西与南北并行

区名均为「十字路口A」。东西兼容组 EW,南北 NS。内部站点按方向拆开,容量均为 1。东西对向若现场确实会在同一段交汇,应把对向也拆站点或改为同组。

[
  { "TriggerSit": 8,  "AreaName": "十字路口A", "CompatGroup": "EW", "Priority": 10, "WaitSeconds": 15, "ControlArea": "10,11", "ControlCapacity": 1, "IsUse": true },
  { "TriggerSit": 18, "AreaName": "十字路口A", "CompatGroup": "EW", "Priority": 10, "WaitSeconds": 15, "ControlArea": "12,13", "ControlCapacity": 1, "IsUse": true },
  { "TriggerSit": 9,  "AreaName": "十字路口A", "CompatGroup": "NS", "Priority": 5,  "WaitSeconds": 15, "ControlArea": "20,21", "ControlCapacity": 1, "IsUse": true },
  { "TriggerSit": 19, "AreaName": "十字路口A", "CompatGroup": "NS", "Priority": 5,  "WaitSeconds": 15, "ControlArea": "22,23", "ControlCapacity": 1, "IsUse": true }
]

效果:东西一辆与南北一辆可同时过;同一兼容组内容量 1,同向或同组第二辆要等;南北优先级较低,但若已等待超过 15 秒且比干道更早到达,可以插队。

8.2 单入口限流(旧用法)

只配一行:触发点 8,区名为空,兼容组空,ControlArea 写内部点,容量 1。该点自成一区,他车占用内部点时不放行。

8.3 支路防饿死

干道 Priority=10,支路 Priority=1,同区 WaitSeconds=20。支路先到、干道后到且时间差大于 20 秒时放支路;否则放干道。

9. 现场操作

  1. 确认已加载信号插件 StandardScene.Signal.dll,进程栏中有「磁条交管进程」。
  2. 将 JSON 放到 SimpleLite 工作目录 Config\Signal\mag-control-areas.json。可用迷毂数据中心「磁条管控区」编辑(含兼容组列,需较新的 MiGu.Server)。
  3. 添加并启动磁条交管进程。改表后点「重新加载配置」,或进程内打开列表保存后重载。
  4. 状态栏可见:规则条数、触发点等待数、在途数、扫车拍数。
  5. 诊断通道 MagTraffic 会记录放行:区名、兼容组、触发点、本线占用/容量、冲突在途。
交管不会替任务系统停车。请保证 MagCar 到达触发点时处于停止,否则不会进入排队,也不会发启动。

10. 与 Mag2 / 其他交管的边界

机制对象关系
本进程 mag-control-areas.jsonMagCar触发点停稳后发 StartMagCar
地图 Fass2_ControlArea 等Mag2CarStartStop=12 等待,放行改本车报文,本进程不介入
TrafficControl 点锁MagCar / Mag2 路径执行锁站点资源,与本表并行存在
交通管制 traffic.json区域互斥钩子需单独启动「交通管制」进程

11. 常见问题

十字路口空着,四个方向却一起冲出去?

兼容组未区分,或内部站点写成同一串。请按方向拆兼容组并拆开 ControlArea。

四个方向谁也不走?

把四个停车触发点写进了 ControlArea,容量又为 1,等待车被当成区内占用。触发点不要写入内部列表。

改了 JSON 不生效?

必须点「重新加载配置」或重启进程。路径必须是工作目录 Config/Signal,不是插件目录。

Mag2 在同一路口不停不等?

本策略不管 Mag2。Mag2 需在地图配置 Fass2_StartStop=12 及管控区字段。

容量填 0?

当前实现小于 1 按 1 处理,不会变成不限流。

对向也要并行,但写成了同一兼容组?

同组即互斥。对向要并行:不同组名,且内部站点不相交。

12. 逻辑对照(维护用)

内容位置
表字段StandardScene.Signal / MagControlAreaModel
冲突、占用、容量MagControlAreaGate
扫车、排队、在途、贪心放行MagControlRuntime.ScanAndRelease
进程与重载MagTrafficMission
迷毂列定义MiGu.Server / SignalDataStore(表 id: mag-control)