Files
StandardSence/Doc/DEVELOPMENT_GUIDE.md
zhaowei.huang a0dc1e6cd0 refactor: 插件 UI 从 WinForms 迁移到 CycleGUI,并修复代码质量问题
将 StandardScene 各插件的配置/监控窗体从 WinForms 迁移到 CycleGUI(删除 .Designer.cs/.resx,重写为 PanelBuilder 立即模式 UI,新增 CycleUiHelper 统一对话框)。

同时修复代码审核中的问题:
- 后台文件写入加锁 + try/catch(ButtonBoxManager / DoorManager,对齐 LoopViewer.SaveTasks 模式)
- CoderFieldsMetadata.cs 启用 #nullable enable,消除 CS8632 警告
- DummyCar 移除已废弃的 rightClickAction()/SetPosition()
- CarRemoteHelper.OpenVehicleWebPage 的 Process.Start 加 try/catch
- 重命名名不副实的 Mstsc()(现为打开网页)
- 统一弃元命名为 _
- TrafficInterlockViewer 改用稳定 Id(GUID)做选择/编辑,替代行索引
- csproj 改用 $(CGUILibDir) 解析 CycleGUI,绝对路径收敛到 Directory.Build.props

构建:dotnet build StandardScene.sln → 0 错误,30 警告(均为历史遗留)。
注:static 单例状态重构(审核第 8 项)暂未处理,留待单独任务。
2026-06-26 15:00:53 +08:00

270 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# StandardScene 开发指南
## 1. 项目定位
`StandardScene` 是一个由 `SimpleLite.exe`(CycleGUI 应用)宿主加载的场景插件库,已拆分为「基座 + 4 个卫星」共 5 个插件 DLL(基座输出 `StandardScene.dll`),不是独立 EXE。仓库主要面向 AGV/AMR 场内调度与联动控制,覆盖:
- 搬运任务与环线任务
- 区域流控与交通互锁
- 充电策略与充电桩管理
- 门禁联动与安全信号
- HTTP / MQTT / Modbus 等外围接口
## 2. 技术与运行方式
| 项目项 | 说明 |
| --- | --- |
| 语言 | `C#` |
| 框架 | `net8.0-windows` |
| 工程类型 | `Library`(基座 + 4 卫星,共 5 个插件 DLL) |
| 宿主 | `SimpleLite.exe`CycleGUI 应用) |
| 界面技术 | 由 WinForms 迁移到 CycleGUI(宿主同栈);`DeliveryViewer` 已迁移 |
| 关键入口 | `MissionType``CarType``WebApi.cs` |
### 本机依赖
`.csproj``HintPath` 指向以下依赖(宿主产物需先构建 Simple 解决方案):
- `D:\MDCS\Dependencies\Commons\CommonUsage.dll``MDCSToolBox.dll``CycleGUI.dll`
- `..\Simple\SimpleLite\bin\Debug\SimpleLite.dll``LessokajiWeaverUtilities.dll`
- `..\Simple\SimpleCore\bin\Debug\netstandard2.0\SimpleCore.dll`
### 构建与运行
> 必须先构建宿主依赖,否则会出现 `SimpleCore` 版本不匹配等编译错误。
1. 先构建宿主:`dotnet build Simple\SimpleLite\SimpleLite.csproj`(会一并构建 `SimpleCore` 项目)
2. 打开 `StandardScene.sln`,编译 `Debug|x64``Release|x64`
3. 编译后 `Directory.Build.targets` 会把 5 个插件 DLL+ PDB + `*.scene.json`)复制到 `build\plugins`
4.`build\plugins` 部署到 `SimpleLite.exe` 工作目录下的 `plugins\`,运行 `SimpleLite.exe`
## 3. 目录结构
| 路径 | 作用 |
| --- | --- |
| `CarTypes\` | 各车型与协议适配 |
| `Chained\` | 搬运任务、链式调度、环线任务 |
| `Charge\` | 充电策略、充电桩管理 |
| `ChargeStationType\` | 具体充电桩类型 |
| `InterLock\` | 区域互锁、交通控制 |
| `Scheduler\` | 心跳、安全、区域流控等后台 Mission |
| `ExtendDevice\Door\` | 门禁设备接入与联动 |
| `Model\` | 任务、配置、地图等数据模型 |
| `TCP\` / `Utils\` | TCP、JSON、Web API、Modbus 工具 |
| `Commons.cs` | 通用字段、标签、选车、路径辅助 |
| `WebApi.cs` | 对外 HTTP 接口 |
## 4. 运行时架构
运行链路通常是:
1. 宿主启动并扫描 `build\plugins`
2. 加载 `StandardScene.dll`
3. 通过特性反射识别 `MissionType``CarType`
4. 启动具体 Mission
5. Mission 调用 `SimpleLib``TrafficControl``SegmentPlan` 等核心能力
6. 车辆状态、交通状态、充电状态在运行时持续联动
## 5. 核心模块理解
### `Scheduler`
这是最适合入门的目录。
- `HeartBeatMission.cs`:最小线程式 Mission
- `RegionalTrafficControlMission.cs`:事件订阅型 Mission
- `SecuritySignalMission.cs`:安全信号类任务
### `Chained`
主业务调度的核心区域。
- `ChainedDeliveryMission.cs`:搬运任务总控(旧版 `AbstractChainedDeliveryMission.cs` 已删除)
- `TransportMission.cs`:常规运输 Mission
- `AbstractLoopMission.cs`:环线任务骨架
- `LoopMission.cs`:环线业务实例
### `Charge`
负责能量与充电协同。
- `AbstractChargeLogicMission.cs`
- `StandardChargeMission.cs`
- `ChargeStationDataService.cs`
- `ChargeStationManagementExample.cs`
### `CarTypes`
负责车型与协议适配。
- `VDA5050Car.cs`
- `Forklift.cs`
- `Kiva.cs`
- `MultiVehicleCar.cs`
- `MasterMQTTCommunication.cs`
### `WebApi.cs`
对外暴露 HTTP 能力,常见路由包括:
- `/car/createTask`
- `/car/getAllCars`
- `/car/goSite`
- `/map/getMap`
- `/task/getTask`
- `/mission_reflection/get_mission_list`
## 6. 配置文件
| 文件 | 作用 |
| --- | --- |
| `Config\traffic.json` | 交通互锁 / 区域配置 |
| `Config\ChargeStations.json` | 充电桩定义 |
| `Config\ChargeStrategyConfig.json` | 充电策略 |
| `Config\AlarmConfigs.json` | 报警配置 |
| `DoorConfig.json` | 门禁配置 |
| `tasklist.json` | 环线任务配置 |
| `simple.json` | 宿主基础配置 |
除了 JSON 文件,本仓库还大量使用 `fields``tags` 作为轻量配置入口,尤其是站点与车辆行为控制。
## 7. 快速开始案例
### 案例 A:新增一个最小 Mission
最推荐的新手入门案例,直接参考 `Scheduler\HeartBeatMission.cs`
```csharp
using System.Threading;
using Newtonsoft.Json;
using SimpleLite.RCS;
using SimpleCore;
namespace StandardScene.Scheduler
{
[MissionType(Name = "Hello Mission", editor = typeof(HelloMission))]
[I18N.DocumentTranslation(Name = "Hello Mission", locale = "en")]
public class HelloMission : Mission
{
[JsonIgnore] private bool _started;
[JsonIgnore] private Thread _thread;
public static Mission Create()
{
return new HelloMission();
}
public override void Execute()
{
if (_started) return;
_started = true;
status.status = "已启动";
_thread = new Thread(() =>
{
int count = 0;
while (_started)
{
Thread.Sleep(1000);
count++;
status.status = $"tick:{count}";
}
});
_thread.Start();
}
public void Stop()
{
_started = false;
status.status = "已停止";
}
}
}
```
#### 关键提醒
当前工程已是 SDK 风格 `.csproj``net8.0-windows`),目录下的 `.cs` 文件会被自动包含,无需再手工添加 `<Compile Include>`。新增任务/车型/驱动后,记得补上对应特性(`[MissionType]``[CarType]``[DoorType]` 等)与静态 `Create()`,否则宿主反射不到。
#### 验证方式
1. 编译解决方案并把插件部署到宿主 `plugins\`
2. 运行 `SimpleLite.exe`
3. 启动 `Hello Mission`
4. 观察 `status.status` 是否变成 `tick:1``tick:2`
### 案例 B:配置区域流控
该案例对应 `Scheduler\RegionalTrafficControlMission.cs`
给区域内站点添加字段:
```text
Region1 = 1
```
含义是:
- 站点属于 `Region1`
- `Region1` 最多允许 1 台车进入
#### 实验步骤
1. 给同一区域内多个站点加上 `Region1=1`
2. 启动“区域流量监控” Mission
3. 让两台车先后进入该区域
4. 观察第二台车是否被阻止
5. 查看 Mission 状态中的区域统计与拦截次数
## 8. 开发工作流建议
1. 先判断功能属于 `Scheduler``Chained``Charge``CarTypes` 还是 `WebApi.cs`
2. 找最接近的现有类作为模板
3. 明确配置入口是 JSON、`fields` 还是 `tags`
4. 补齐日志、状态与停止逻辑
5. 确认文件已加入工程
6. 编译后在宿主里验证是否能被识别
## 9. 调试建议
优先观察这些点:
- `status.status`
- `Diagnosis.Post` / `Diagnosis.Log`
- `car.status.pendingLocks`
- `car.status.holdingLocks`
- 站点 / 车辆的 `fields``tags`
- `WebApi.cs` 中的实际路由
推荐调试方式:
-`SimpleLite.exe` 作为外部程序启动调试
- 或先运行宿主,再附加进程
## 10. 常见坑
### 新增 Mission 看不到
优先检查:
- 是否加了 `MissionType`
- 是否有静态 `Create()`
- 是否复制到了 `build\plugins` 并部署到宿主 `plugins\`
- 卫星插件是否已在 `active-scenes.json` 中启用对应场景
### 区域流控不生效
优先检查:
- 字段名是否以 `Region` 开头
- 字段值是否能解析为整数
- Mission 是否已启动
### 任务不执行
优先检查:
- 车辆是否在线
- 路径是否可达
- 是否被互锁、流控或门控拦截
- 是否已有标签将车辆标记为忙碌或充电中