Files
StandardSence/StandardScene.Core/Docs/DoorMission使用手册.md
T
2026-06-14 11:19:15 +08:00

20 KiB
Raw Blame History

DoorMission 使用手册

目录


概述

DoorMission 是一个门控进程类,用于管理多个门控制器及其关联的门。它提供了以下核心功能:

  • 多门控制器管理(支持不同类型)
  • 自动门控逻辑(根据小车位置自动开关门)
  • 手动控制功能(支持临时手动控制,优先级高于自动控制)
  • 车辆占用管理(跟踪和清空门区域的车辆占用)
  • 配置文件动态监控(支持热更新)
  • 线程安全的门状态读写
  • 可视化的配置和监控界面

架构特点

  • 抽象化设计:门控制器通过抽象基类 BasicDoorController 实现,支持扩展不同类型的控制器
  • 线程安全:门状态读取和控制写入分离,所有通信操作在门控制器内部线程完成
  • 事件驱动:与交通控制系统集成,响应小车进入/离开站点事件
  • 热更新支持:配置文件每10秒自动检查更新,无需重启任务
  • 控制仲裁机制:手动控制优先级高于自动控制,手动控制过期后自动恢复自动模式

基本功能

1. 门控制器管理

1.1 门控制器类型

门控制器通过 DoorTypeAttribute 标记类型,系统会自动识别并创建实例。当前支持:

  • ModbusDoorController:基于 Modbus TCP 的门控制器

1.2 门控制器配置

每个门控制器包含以下配置:

  • Index:控制器索引(唯一标识)
  • IpIP地址
  • Port:端口号(默认502
  • Type:控制器类型(通过 DoorTypeAttribute.Name 指定)
  • Doors:门列表

1.3 门配置

每个门包含以下配置:

  • Index:门索引(在控制器内唯一)
  • ControlAddress:开关控制信号地址(Modbus 线圈地址)
  • OpenStatusAddress:开到位信号地址(Modbus 离散输入地址)

2. 自动门控逻辑

2.1 门开启条件

门会在以下情况自动开启:

  1. 小车即将进入区域:当小车到达站点且站点的 EnterDoor 字段匹配时,门会在锁定前开启
  2. 小车在区域内:当小车已进入并锁定站点时,门保持开启状态

2.2 门关闭条件

门会在以下情况自动关闭:

  • 小车离开区域后,门自动关闭

2.3 门标识符格式

站点配置中的门标识符格式为:控制器索引.门索引

示例

"EnterDoor": "1.2"  // 表示控制器索引1,门索引2
"LeaveDoor": "2.3"  // 表示控制器索引2,门索引3

3. 配置文件动态监控

系统每10秒自动检查 DoorConfig.json 文件,并根据配置变化:

  • 添加:新增的门控制器会自动创建并连接
  • 删除:已移除的门控制器会自动断开并移除
  • 修改:已修改的门控制器会自动更新(IP、端口、类型或门配置变化)

启动与停止

1. 启动任务

var doorMission = new DoorMission();
doorMission.Execute();  // 执行"启动进程"

启动流程

  1. 设置数据文件路径(DoorConfig.json
  2. 订阅交通控制事件(BeforeLockAfterLeaveOnLockAcquired
  3. 立即加载一次配置(避免监控界面在首次轮询前无数据)
  4. 启动配置监控任务(每10秒检查一次)
  5. 启动门控逻辑监控任务(每500毫秒检查一次)

2. 停止任务

doorMission.Stop();  // 执行"停止进程"

停止流程

  1. 取消事件订阅
  2. 取消所有后台任务
  3. 断开所有门控制器连接
  4. 等待任务完成(最多等待5秒)

3. 公共方法

3.1 读取门状态

bool isOpen = doorMission.GetDoorState(controllerIndex, doorIndex);
  • 参数
    • controllerIndex:门控制器索引
    • doorIndex:门索引
  • 返回值true=打开,false=关闭

3.2 设置门控制目标(自动模式)

doorMission.SetDoorControlTarget(controllerIndex, doorIndex, open);
  • 参数
    • controllerIndex:门控制器索引
    • doorIndex:门索引
    • opentrue=打开,false=关闭

注意:此方法仅设置目标控制状态,实际通信由门控制器内部线程完成,确保线程安全。此方法会立即生效,但可能被手动控制覆盖。

3.3 设置手动控制目标

bool success = doorMission.SetManualDoorControl(controllerIndex, doorIndex, open, holdSeconds);
  • 参数
    • controllerIndex:门控制器索引
    • doorIndex:门索引
    • opentrue=打开,false=关闭
    • holdSeconds:手动保持秒数(可选,默认10秒)
  • 返回值true=成功,false=失败(当有车辆占用且尝试关闭时返回false)

功能说明

  • 手动控制优先级高于自动控制
  • 手动控制会在指定时间后自动过期,恢复自动模式
  • 安全保护:当门区域内有车辆占用时,禁止手动关闭门
  • 手动控制过期后,系统自动恢复自动控制逻辑

3.4 清除手动控制

doorMission.ClearManualDoorControl(controllerIndex, doorIndex);
  • 参数
    • controllerIndex:门控制器索引
    • doorIndex:门索引

功能说明:立即清除手动控制请求,恢复自动控制模式。

3.5 清空车辆占用

doorMission.ClearCarsInArea(controllerIndex, doorIndex);
  • 参数
    • controllerIndex:门控制器索引
    • doorIndex:门索引

功能说明:清空指定门的车辆占用记录。清空后,如果门处于打开状态且没有其他小车需要进入,门会自动关闭。

3.6 获取门控制状态

var status = doorMission.GetDoorControlStatus(controllerIndex, doorIndex);
  • 参数
    • controllerIndex:门控制器索引
    • doorIndex:门索引
  • 返回值DoorControlStatus 对象,包含:
    • Target:当前目标状态(true=打开,false=关闭)
    • Source:控制来源(ControlSource.AutoControlSource.Manual
    • ManualRemainingSeconds:手动控制剩余秒数(仅当Source=Manual时有效)
    • CarsInArea:车辆占用列表

3.7 获取车辆占用情况

var cars = doorMission.GetCarsInArea(controllerIndex, doorIndex);
  • 参数
    • controllerIndex:门控制器索引
    • doorIndex:门索引
  • 返回值:车辆ID列表(IReadOnlyList<int>

配置管理

1. 配置文件格式

配置文件 DoorConfig.json 位于程序根目录,格式如下:

[
  {
    "Index": 1,
    "Ip": "192.168.1.100",
    "Port": 502,
    "Type": "ModbusDoorController",
    "Doors": [
      {
        "Index": 1,
        "ControlAddress": 0,
        "OpenStatusAddress": 0
      },
      {
        "Index": 2,
        "ControlAddress": 1,
        "OpenStatusAddress": 1
      }
    ]
  },
  {
    "Index": 2,
    "Ip": "192.168.1.101",
    "Port": 502,
    "Type": "ModbusDoorController",
    "Doors": [
      {
        "Index": 1,
        "ControlAddress": 0,
        "OpenStatusAddress": 0
      }
    ]
  }
]

2. 配置界面

通过调用 DoorMission.OpenViewer() 打开门控制器管理界面,可以:

  • 添加、删除、修改门控制器
  • 为每个门控制器添加、删除、修改门配置
  • 保存配置到 DoorConfig.json

打开配置界面

DoorMission.OpenViewer();

门控逻辑

1. 事件响应流程

1.1 BeforeLock 事件

当小车即将锁定站点时触发:

  1. 检查站点的 EnterDoor 字段
  2. 检查小车当前站点的 PreEnterDoor 字段是否匹配
  3. 如果匹配,设置 _needOpen[(controllerIndex, doorIndex)] = true
  4. 返回门的当前状态(如果门已打开则允许锁定)

1.2 OnLockAcquired 事件

当小车成功锁定站点时触发:

  1. 检查站点的 EnterDoor 字段
  2. 检查小车当前站点的 PreEnterDoor 字段是否匹配
  3. 如果匹配,将小车ID添加到 carsInAreas[(controllerIndex, doorIndex)]
  4. 设置 _needOpen[(controllerIndex, doorIndex)] = false

1.3 AfterLeave 事件

当小车离开站点时触发:

  1. 检查站点的 LeaveDoor 字段
  2. 检查小车当前站点的 RearLeaveDoor 字段是否匹配
  3. 如果匹配,从 carsInAreas[(controllerIndex, doorIndex)] 中移除小车ID

2. 门控状态监控与仲裁

MonitorDoorLogicAsync 任务每500毫秒执行一次,检查每个门的控制逻辑并进行仲裁:

// 自动目标:有车或需要打开
var needOpen = _needOpen.TryGetValue(key, out var open) && open;
var hasCarsInArea = carsInAreas.TryGetValue(key, out var cars) && cars.Count > 0;
var autoTarget = needOpen || hasCarsInArea;

// 手动请求仲裁:优先级 Manual > Auto,手动过期后自动恢复
bool finalTarget = autoTarget;
if (_manualRequests.TryGetValue(key, out var manual))
{
    if (manual.ExpireAt <= DateTime.Now)
    {
        _manualRequests.Remove(key);  // 手动控制过期,移除
    }
    else
    {
        finalTarget = manual.Target;  // 手动控制有效,使用手动目标
    }
}

// 设置门的目标控制状态
controller.SetDoorControlTarget(doorIndex, finalTarget);

逻辑说明

  • 自动目标计算
    • 如果 _needOpen[key] = true,门需要打开(小车即将进入)
    • 如果 carsInAreas[key] 中有小车,门需要保持打开(小车在区域内)
    • 其他情况,自动目标为关闭
  • 控制仲裁
    • 手动控制优先级高于自动控制
    • 如果存在有效的手动控制请求(未过期),使用手动目标
    • 手动控制过期后,自动移除并恢复自动控制
    • 最终目标写入门控制器的 DoorControlTargets 字段

站点配置

1. 站点字段说明

站点需要配置以下字段以实现门控功能:

字段名 类型 说明 示例
EnterDoor string 进站门标识符(格式:控制器索引.门索引) "1.2"
LeaveDoor string 离站门标识符(格式:控制器索引.门索引) "2.3"

2. 小车站点字段说明

小车当前站点需要配置以下字段:

字段名 类型 说明 示例
PreEnterDoor string 前方进站门标识符(与目标站点的 EnterDoor 匹配) "1.2"
RearLeaveDoor string 后方离站门标识符(与目标站点的 LeaveDoor 匹配) "2.3"

3. 配置示例

站点配置

{
  "id": 100,
  "name": "站点A",
  "fields": {
    "EnterDoor": "1.2",
    "LeaveDoor": "2.3"
  }
}

小车站点配置

{
  "id": 50,
  "name": "小车当前位置",
  "fields": {
    "PreEnterDoor": "1.2",
    "RearLeaveDoor": "2.3"
  }
}

工作流程

  1. 小车从站点50驶向站点100
  2. 到达站点100时,触发 BeforeLock 事件
  3. 系统检查站点100的 EnterDoor"1.2")是否与站点50的 PreEnterDoor"1.2")匹配
  4. 如果匹配,设置控制器1的门2为打开状态
  5. 门打开后,小车锁定站点100
  6. 触发 OnLockAcquired 事件,门保持打开状态
  7. 小车离开站点100时,触发 AfterLeave 事件
  8. 系统检查站点100的 LeaveDoor"2.3")是否与站点50的 RearLeaveDoor"2.3")匹配
  9. 如果匹配,从区域内小车列表中移除该小车
  10. 如果没有其他小车在区域内,门自动关闭

UI界面

1. 配置管理界面

打开方式

DoorMission.OpenViewer();

功能

  • 门控制器列表管理(添加、删除、修改)
  • 门列表管理(为每个控制器添加、删除、修改门)
  • 类型选择(自动识别所有带 DoorTypeAttribute 的控制器类型)
  • 配置保存到 DoorConfig.json

2. 监控界面

打开方式

DoorMission.OpenMonitor();

功能

  • 实时显示所有门的状态
  • 显示控制器索引、门索引、当前状态、控制目标、车辆占用
  • 显示控制来源和手动控制剩余时间
  • 显示控制地址和开到位信号地址
  • 手动控制门开关(打开/关闭,带安全保护)
  • 清空车辆占用记录
  • 自动刷新(默认1秒刷新间隔)

显示信息

列名 说明
控制器编码 门控制器索引
门编码 门索引
当前状态 门的当前状态(开/关,带颜色标识:绿色=打开,红色=关闭)
控制目标 门的目标控制状态(开/关,带颜色标识:绿色=开,红色=关)
车辆占用 门区域内的小车ID列表(多个ID用逗号分隔,无车辆显示"无")
控制来源 当前控制来源(自动/手动)
手动剩余(s) 手动控制剩余秒数(仅当控制来源=手动时显示,自动时显示"-"
控制地址 Modbus 线圈地址
开到位地址 Modbus 离散输入地址

手动控制功能

  • 打开按钮:设置手动打开控制,默认保持10秒
  • 关闭按钮:设置手动关闭控制,默认保持10秒
    • 安全保护:当门区域内有车辆占用时,关闭按钮自动禁用,无法执行关闭操作
    • 必须先清空车辆占用,才能手动关闭门
  • 清空占用按钮:清空选中门的车辆占用记录
    • 清空后,如果门处于打开状态且没有其他小车需要进入,门会自动关闭
    • 清空占用后,可以执行手动关闭操作

控制优先级说明

  • 手动控制优先级高于自动控制
  • 手动控制会在指定时间(默认10秒)后自动过期,恢复自动模式
  • 可以通过"清空占用"按钮清空车辆占用,然后手动关闭门

参数说明

1. 监控间隔

参数 默认值 说明
配置监控间隔 10秒 检查配置文件的间隔
门控逻辑监控间隔 500毫秒 检查门控逻辑的间隔(已优化)
监控界面刷新间隔 1秒 监控界面自动刷新间隔
手动控制默认保持时间 10秒 手动控制请求的默认过期时间

2. 线程安全说明

  • 门状态读取:通过 controller.DoorStates 字典访问,所有读写操作受锁保护
  • 门控制写入:通过 controller.SetDoorControlTarget() 设置目标状态,实际通信由门控制器内部线程完成
  • 配置同步:配置变更时使用锁保护,确保线程安全
  • 控制仲裁:手动控制请求和自动控制逻辑的仲裁在同一锁内完成,确保线程安全
  • 车辆占用管理:车辆占用的增删改查操作均受锁保护

3. 控制仲裁机制

系统采用控制仲裁机制来协调手动控制和自动控制:

  • 优先级:手动控制 > 自动控制
  • 手动控制过期:手动控制请求会在指定时间(默认10秒)后自动过期,过期后恢复自动控制
  • 安全保护:当门区域内有车辆占用时,禁止手动关闭门,确保安全
  • 仲裁流程
    1. 计算自动目标(基于车辆占用和需要打开标志)
    2. 检查是否存在有效的手动控制请求
    3. 如果手动控制未过期,使用手动目标;否则使用自动目标
    4. 将最终目标写入门控制器的 DoorControlTargets 字段

故障排查

问题1:门控制器无法连接

排查步骤

  1. 检查配置文件中的 IP 和端口是否正确
  2. 检查网络连接是否正常
  3. 查看诊断日志中的错误信息
  4. 确认门控制器硬件是否在线

诊断命令

var controllers = doorMission.GetDoorControllers();
foreach (var controller in controllers)
{
    Console.WriteLine($"控制器{controller.Index}: IP={controller.Ip}, Port={controller.Port}, State={controller.State}, Error={controller.ErrorMessage}");
}

问题2:门不自动开启

排查步骤

  1. 确认 DoorMission 任务已启动
  2. 检查站点的 EnterDoor 字段是否配置正确
  3. 检查小车站点的 PreEnterDoor 字段是否与目标站点的 EnterDoor 匹配
  4. 查看门控制器的连接状态是否为 Online
  5. 检查门的状态是否正确读取

诊断命令

// 检查门状态
bool isOpen = doorMission.GetDoorState(1, 2);
Console.WriteLine($"控制器1门2的状态: {(isOpen ? "打开" : "关闭")}");

// 检查门控制器状态
var controllers = doorMission.GetDoorControllers();
var controller = controllers.FirstOrDefault(c => c.Index == 1);
if (controller != null)
{
    Console.WriteLine($"控制器状态: {controller.State}");
    Console.WriteLine($"是否在线: {controller.IsOnline}");
    Console.WriteLine($"错误信息: {controller.ErrorMessage}");
}

问题3:配置文件更新后不生效

排查步骤

  1. 确认配置文件格式正确(JSON格式)
  2. 检查配置文件是否保存成功
  3. 等待最多10秒,系统会自动检测更新
  4. 查看诊断日志中的配置同步信息

问题4:监控界面无数据

排查步骤

  1. 确认 DoorMission 任务已启动
  2. 检查是否有配置的门控制器
  3. 查看门控制器是否成功连接
  4. 检查监控界面的刷新间隔设置

问题5:手动关闭按钮无法点击

原因

  • 门区域内有车辆占用,系统安全保护机制禁止手动关闭

解决方法

  1. 先点击"清空占用"按钮,清空车辆占用记录
  2. 清空后,关闭按钮会自动启用
  3. 然后可以执行手动关闭操作

问题6:手动控制不生效

排查步骤

  1. 检查手动控制是否已过期(默认10秒)
  2. 查看"控制来源"列,确认是否为"手动"
  3. 查看"手动剩余(s)"列,确认剩余时间
  4. 如果已过期,手动控制会自动恢复为自动模式
  5. 可以通过监控界面重新设置手动控制

附录

A. 门标识符解析

门标识符格式:控制器索引.门索引

解析规则

  • 必须包含一个点号(.
  • 点号前后必须为整数
  • 解析失败时返回 null

示例

  • "1.2"(controllerIndex: 1, doorIndex: 2)
  • "10.5"(controllerIndex: 10, doorIndex: 5)
  • "1"null (缺少点号)
  • "1.2.3"null (多个点号)
  • "a.2"null (非数字)

B. 诊断日志说明

系统会在以下情况记录诊断日志:

  • 门控制器连接成功/失败
  • 门控制器配置变更
  • 门状态读取失败
  • 门控制写入失败
  • 配置加载失败

日志位置:系统诊断日志

C. 类结构关系图

DoorMission (门控进程)
    │
    ├── BasicDoorController (抽象基类)
    │   │
    │   └── ModbusDoorController (Modbus 实现)
    │
    ├── DoorManager (配置界面)
    │
    ├── DoorMonitor (监控界面)
    │
    └── DoorModel (配置模型)

D. 控制来源枚举

public enum ControlSource
{
    Auto = 0,    // 自动控制
    Manual = 1   // 手动控制
}

E. 门控制状态结构

public class DoorControlStatus
{
    public bool Target { get; set; }                    // 当前目标状态(true=打开,false=关闭)
    public ControlSource Source { get; set; }           // 控制来源(Auto/Manual
    public double? ManualRemainingSeconds { get; set; }  // 手动控制剩余秒数(仅当Source=Manual时有效)
    public IReadOnlyList<int> CarsInArea { get; set; }  // 车辆占用列表
}

F. 版本历史

版本 日期 主要更新
1.0 2025-01 初始版本,支持 Modbus 门控制器
1.1 2025-01 新增门控仲裁机制,支持手动控制与自动控制协调
1.2 2025-01 新增车辆占用管理功能,监控界面显示车辆占用情况
1.3 2025-01 优化门控逻辑监控间隔至500ms,新增安全保护机制(占用时禁止手动关闭)

文档更新时间2025-01-21