init commit

This commit is contained in:
zhaowei.huang
2026-06-14 11:19:15 +08:00
parent e79a3815a5
commit c8e540d272
174 changed files with 60830 additions and 39 deletions
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LessokajiWeaverUtilities.Utilities;
using Newtonsoft.Json;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using SimpleCore;
using StandardScene.Model;
namespace StandardScene.Scheduler
{
[MissionType(Name = "调度心跳进程",editor = typeof(HeartBeatMission))]
[I18N.DocumentTranslation(Name = "Heart Beat Mission", locale = "en")]
public class HeartBeatMission:Mission
{
[JsonIgnore] private bool _started = false;
private Thread _myThread;
private HttpClient _httpClient;
public static Mission Create()
{
return new HeartBeatMission();
}
[MethodMember(Name = "启动进程", Description = "开始下发调度心跳")]
public override void Execute()
{
if(_started) return;
status.status = "已启动";
int count = 0;
_httpClient = new HttpClient();
_myThread = new Thread(() =>
{
_started = true;
while (_started)
{
Thread.Sleep(1000);
count++;
status.status = $"已启动:{count}";
var carList = SimpleLib.GetAllCars();
foreach (var car in carList)
{
if (car is not GhostCar gCar || Commons.GetVehicleStatus(gCar)!= VehicleStatus.Normal) continue;
try
{
//((ClumsyCar)car).ImmediateCommand("pilot.SimpleSignal=1");
var ip = gCar.address;
_httpClient.GetStringAsync($"http://{ip}:8008/setValue?FieldName=SimpleSignal&Value=1");
}
catch (Exception e)
{
Console.WriteLine($"http error" + e.Message + e.StackTrace);
}
}
}
});
_myThread.Start();
}
[MethodMember(Name = "关闭进程", Description = "停止下发心跳")]
public void Stop()
{
_started = false;
_myThread?.Join(2000);
_myThread = null;
status.status = "已关闭";
}
}
}
@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using SimpleCore;
using Newtonsoft.Json;
using SimpleLite.CADTools;
using SimpleLite.Props;
using SimpleLite.UI;
using SimpleCore.Library;
using System.Threading.Tasks;
using System.Diagnostics;
using SimpleCore.Traffic;
using SimpleCore.PropType;
using System.Net.Http;
using System.Reflection;
using LessokajiWeaverUtilities.Utilities;
using SimpleLite.RCS.Signal;
namespace StandardScene.Scheduler
{
[MissionType(Name = "锁点上传迷毂", editor = typeof(NodeIsEnableMission))]
[I18N.DocumentTranslation(Name = "NodeState Upload Mission", locale = "en")]
public class NodeIsEnableMission : Mission
{
public static Mission Create()
{
return new NodeIsEnableMission();
}
public int[] stringToInt(string str)
{
return str.Split(' ').Select(s => (int)Convert.ToInt16(s, 10)).ToArray();
}
//是否连接成功
public bool iscon { get; set; }
public class NOdeIsEnableMissionStatus : MissionStatus
{
public static List<string> staions = new List<string>();
public float readOnceTime = 0;
public float readAllDataTime = 0;
public float writeOnceTime = 0;
public float writeAllDataTime = 0;
}
public override MissionStatus status { get; set; } = new NOdeIsEnableMissionStatus();
[JsonIgnore] public Thread myThread;
[JsonIgnore] private bool started = false;
[JsonIgnore] private int iterationComm = 0;
[JsonIgnore] private object sync = new();
[JsonIgnore] public static HttpClient hc = new HttpClient() { Timeout = TimeSpan.FromSeconds(2) };
[MethodMember(Name = "启动进程", Description = "开始处理上下料队列")]
public override void Execute()
{
started = true;
Task.Factory.StartNew(() => {
HttpPostData httpPostData = new HttpPostData();
Dictionary<string, Dictionary<string, bool>> Allsignal = new Dictionary<string, Dictionary<string, bool>>();
//Dictionary<string, bool> stationSignals = new Dictionary<string, bool>();
while (started)
{
try
{
//获取所有锁点的车
var sites = SimpleLib
.GetAllSites()
.Where(site => site.tags.Contains("unavailable"))
.ToList();
HashSet<int> staions = new HashSet<int>();
foreach (var site in sites)
{
staions.Add(site.id);
if (site.fields.ContainsKey("mustFree")&& site.mustFree !=null && site.mustFree.Length>0)
{
//遍历数组添加禁用点
for (int i = 0; i < site.mustFree.Length; i++)
{
staions.Add(site.mustFree[i]) ;
}
}
}
Diagnosis.Log($"向迷毂提供禁用站点", "siteIsEnable", true);
httpPostData.UploadListNode(staions);
Thread.Sleep(500);
}
catch (Exception e)
{
Diagnosis.Post($"{ExceptionFormatter.FormatEx(e)}", "禁用站点");
}
}
});
}
[MethodMember(Name = "关闭机构进程", Description = "关闭机构进程")]
public void Stop()
{
started = false;
status.status = $"已停止-循环";
}
public static string GetListsAsStrings(object obj)
{
Dictionary<string, string> result = new Dictionary<string, string>();
Type type = obj.GetType();
FieldInfo[] fieldInfo= type.GetFields();
foreach (FieldInfo property in fieldInfo)
{
if (property.FieldType== typeof(List<bool>))
{
List<bool> list = (List<bool>)property.GetValue(obj);
result[property.Name] = String.Join(",", list.Select(b => b ? "1" : "0"));
}
}
return JsonConvert.SerializeObject(result);
}
}
}
@@ -0,0 +1,432 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using SimpleCore;
using Newtonsoft.Json;
using SimpleLite.CADTools;
using SimpleLite.Props;
using SimpleLite.UI;
using SimpleCore.Library;
using System.Threading.Tasks;
using System.Diagnostics;
using SimpleCore.Traffic;
using SimpleCore.PropType;
using LessokajiWeaverUtilities.Utilities;
namespace StandardScene.Scheduler
{
[MissionType(Name = "区域流量监控", editor = typeof(RegionalTrafficControlMission))]
[I18N.DocumentTranslation(Name = "Regional Traffic Control Mission", locale = "en")]
public class RegionalTrafficControlMission : Mission
{
public static Mission Create()
{
return new RegionalTrafficControlMission();
}
/// <summary>
/// 区域流量监控状态
/// </summary>
public class RegionalTrafficControlMissionStatus : MissionStatus
{
/// <summary>
/// 区域车辆统计信息:区域编号 -> 当前车辆数量
/// </summary>
public Dictionary<string, int> RegionVehicleCounts { get; set; } = new Dictionary<string, int>();
/// <summary>
/// 区域限制信息:区域编号 -> 最大允许车辆数
/// </summary>
public Dictionary<string, int> RegionMaxCounts { get; set; } = new Dictionary<string, int>();
/// <summary>
/// 被阻止的车辆统计:区域编号 -> 被阻止次数
/// </summary>
public Dictionary<string, int> BlockedCounts { get; set; } = new Dictionary<string, int>();
}
public override MissionStatus status { get; set; } = new RegionalTrafficControlMissionStatus();
[JsonIgnore] private bool started = false;
[JsonIgnore] private object sync = new object();
/// <summary>
/// 区域内的车辆记录:区域编号 -> 车辆ID列表
/// </summary>
[JsonIgnore] private readonly Dictionary<string, HashSet<int>> carsInRegions = new Dictionary<string, HashSet<int>>();
/// <summary>
/// 启动进程
/// </summary>
[MethodMember(Name = "启动进程", Description = "开始区域流量监控")]
public override void Execute()
{
if (started)
{
Diagnosis.Post("区域流量监控已在运行中", "区域流量监控");
return;
}
started = true;
status.status = "运行中";
// 订阅交通控制事件
TrafficControl.BeforeLock += BeforeLockEvent;
TrafficControl.AfterLeave += AfterLeaveEvent;
TrafficControl.OnLockAcquired += OnLockAcquiredEvent;
// 启动统计更新任务
Task.Factory.StartNew(() =>
{
while (started)
{
try
{
UpdateRegionStatistics();
Thread.Sleep(500);
}
catch (Exception e)
{
Diagnosis.Post($"{ExceptionFormatter.FormatEx(e)}", "区域流量监控");
}
}
});
Diagnosis.Post("区域流量监控已启动", "区域流量监控", true);
}
/// <summary>
/// 停止进程
/// </summary>
[MethodMember(Name = "停止进程", Description = "停止区域流量监控")]
public void Stop()
{
if (!started)
{
return;
}
started = false;
// 取消事件订阅
TrafficControl.BeforeLock -= BeforeLockEvent;
TrafficControl.AfterLeave -= AfterLeaveEvent;
TrafficControl.OnLockAcquired -= OnLockAcquiredEvent;
status.status = "已停止";
Diagnosis.Post("区域流量监控已停止", "区域流量监控", true);
}
/// <summary>
/// 获取站点的区域信息
/// </summary>
/// <param name="site">站点</param>
/// <returns>区域标识和限制数量,如果站点不属于任何区域则返回null</returns>
private (string regionId, int maxCount)? GetRegionInfo(Site site)
{
if (site == null || site.fields == null)
{
return null;
}
// 查找所有以Region开头的字段
var regionField = site.fields.FirstOrDefault(kvp => kvp.Key.StartsWith("Region", StringComparison.OrdinalIgnoreCase));
if (regionField.Key == null)
{
return null; // 站点不属于任何区域
}
string regionId = regionField.Key; // 例如 "Region1"
// 字段值就是限制数量
if (!int.TryParse(regionField.Value, out int maxCount))
{
return null; // 无法解析限制数量
}
return (regionId, maxCount);
}
/// <summary>
/// 检查车辆是否已经在指定区域内
/// </summary>
private bool IsCarAlreadyInRegion(AbstractCar car, string regionId)
{
if (car?.status == null)
{
return false;
}
// 检查车辆当前占用的站点是否属于该区域
if (car.status.holdingLocks != null)
{
foreach (var lockedSiteId in car.status.holdingLocks)
{
var lockedSite = SimpleLib.GetSite(lockedSiteId);
var regionInfo = GetRegionInfo(lockedSite);
if (regionInfo.HasValue && regionInfo.Value.regionId == regionId)
{
return true; // 车辆已经在区域内
}
}
}
return false;
}
/// <summary>
/// BeforeLock事件处理:检查车辆是否可以进入区域
/// </summary>
private bool BeforeLockEvent(AbstractCar car, int siteId)
{
try
{
var site = SimpleLib.GetSite(siteId);
if (site == null)
{
return true;
}
// 获取站点的区域信息
var regionInfo = GetRegionInfo(site);
if (!regionInfo.HasValue)
{
return true; // 站点不属于任何区域,允许通过
}
var (regionId, maxCount) = regionInfo.Value;
// 如果最大数量为0或负数,表示不限制
if (maxCount <= 0)
{
return true;
}
// 检查车辆是否已经在区域内
lock (sync)
{
if (IsCarAlreadyInRegion(car, regionId))
{
// 车辆已经在区域内,允许通行
return true;
}
// 车辆即将进入区域,需要检查是否超过限制
// 排除当前车辆本身,因为它还没有进入区域
int currentCount = CountCarsInRegion(regionId, excludeCarId: car.id);
// 如果当前车辆数量已达到或超过限制,阻止进入
if (currentCount >= maxCount)
{
var statusObj = (RegionalTrafficControlMissionStatus)status;
if (!statusObj.BlockedCounts.ContainsKey(regionId))
{
statusObj.BlockedCounts[regionId] = 0;
}
statusObj.BlockedCounts[regionId]++;
Diagnosis.Log($"车辆 {car.id} 尝试进入区域 {regionId} 被阻止,当前车辆数: {currentCount}/{maxCount}", "区域流量监控", true);
return false; // 阻止进入
}
return true; // 允许进入
}
}
catch (Exception e)
{
Diagnosis.Post($"BeforeLockEvent错误: {ExceptionFormatter.FormatEx(e)}", "区域流量监控");
return true; // 发生错误时允许通过,避免阻塞系统
}
}
/// <summary>
/// AfterLeave事件处理:车辆离开区域时更新统计
/// </summary>
private void AfterLeaveEvent(AbstractCar car, int siteId)
{
try
{
var site = SimpleLib.GetSite(siteId);
if (site == null)
{
return;
}
// 获取站点的区域信息
var regionInfo = GetRegionInfo(site);
if (!regionInfo.HasValue)
{
return; // 站点不属于任何区域
}
string regionId = regionInfo.Value.regionId;
// 从区域车辆列表中移除该车辆
lock (sync)
{
if (carsInRegions.TryGetValue(regionId, out var carSet))
{
carSet.Remove(car.id);
if (carSet.Count == 0)
{
carsInRegions.Remove(regionId);
}
}
}
}
catch (Exception e)
{
Diagnosis.Post($"AfterLeaveEvent错误: {ExceptionFormatter.FormatEx(e)}", "区域流量监控");
}
}
/// <summary>
/// OnLockAcquired事件处理:车辆成功锁定站点时,将其加入区域统计
/// </summary>
private void OnLockAcquiredEvent(AbstractCar car, int siteId)
{
try
{
var site = SimpleLib.GetSite(siteId);
if (site == null)
{
return;
}
// 获取站点的区域信息
var regionInfo = GetRegionInfo(site);
if (!regionInfo.HasValue)
{
return; // 站点不属于任何区域
}
string regionId = regionInfo.Value.regionId;
// 将车辆添加到区域车辆列表中
lock (sync)
{
if (!carsInRegions.TryGetValue(regionId, out var carSet))
{
carSet = new HashSet<int>();
carsInRegions[regionId] = carSet;
}
carSet.Add(car.id);
}
}
catch (Exception e)
{
Diagnosis.Post($"OnLockAcquiredEvent错误: {ExceptionFormatter.FormatEx(e)}", "区域流量监控");
}
}
/// <summary>
/// 统计指定区域内的车辆数量
/// </summary>
/// <param name="regionId">区域标识</param>
/// <param name="excludeCarId">要排除的车辆ID(可选,用于排除即将进入的车辆)</param>
/// <returns>区域内的车辆数量</returns>
private int CountCarsInRegion(string regionId, int excludeCarId = -1)
{
lock (sync)
{
// 首先从已记录的车辆列表中统计
int count = 0;
if (carsInRegions.TryGetValue(regionId, out var recordedCars))
{
count = recordedCars.Count(carId => carId != excludeCarId);
}
// 同时检查所有站点,统计属于该区域且当前有车辆占用的站点
var regionSites = SimpleLib.GetAllSites()
.Where(s =>
{
var regionInfo = GetRegionInfo(s);
return regionInfo.HasValue && regionInfo.Value.regionId == regionId;
})
.ToList();
// 统计这些站点上的车辆(只统计已锁定的,不包括正在前往的)
// 因为正在前往的车辆还没有真正进入区域
var carsInRegionSites = SimpleLib.GetAllCars()
.OfType<Car>()
.Where(car =>
{
if (car?.status == null)
return false;
// 排除指定车辆
if (car.id == excludeCarId)
return false;
// 只统计已经在区域内的站点(holdingLocks
// 不统计pendingLocks,因为那些车辆还没有真正进入区域
bool inRegionSite = car.status.holdingLocks?.Any(siteId =>
{
var site = SimpleLib.GetSite(siteId);
var regionInfo = GetRegionInfo(site);
return regionInfo.HasValue && regionInfo.Value.regionId == regionId;
}) == true;
return inRegionSite;
})
.Select(car => car.id)
.ToHashSet();
// 返回两者中的较大值,确保统计准确
return Math.Max(count, carsInRegionSites.Count);
}
}
/// <summary>
/// 更新区域统计信息
/// </summary>
private void UpdateRegionStatistics()
{
try
{
lock (sync)
{
var statusObj = (RegionalTrafficControlMissionStatus)status;
statusObj.RegionVehicleCounts.Clear();
statusObj.RegionMaxCounts.Clear();
// 获取所有有区域字段的站点,按区域分组
var regionSites = SimpleLib.GetAllSites()
.Select(s =>
{
var regionInfo = GetRegionInfo(s);
return regionInfo.HasValue ? (site: s, regionId: regionInfo.Value.regionId, maxCount: regionInfo.Value.maxCount) : (site: (Site)null, regionId: (string)null, maxCount: 0);
})
.Where(x => x.site != null && !string.IsNullOrEmpty(x.regionId))
.GroupBy(x => x.regionId)
.ToList();
foreach (var group in regionSites)
{
string regionId = group.Key;
var firstItem = group.First();
// 获取最大允许数量(从第一个站点的字段值获取)
int maxCount = firstItem.maxCount;
// 统计当前车辆数量
int currentCount = CountCarsInRegion(regionId);
statusObj.RegionMaxCounts[regionId] = maxCount;
statusObj.RegionVehicleCounts[regionId] = currentCount;
}
}
}
catch (Exception e)
{
Diagnosis.Post($"UpdateRegionStatistics错误: {ExceptionFormatter.FormatEx(e)}", "区域流量监控");
}
}
}
}
@@ -0,0 +1,201 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using SimpleCore;
using Newtonsoft.Json;
using SimpleLite.CADTools;
using SimpleLite.Props;
using SimpleLite.UI;
using SimpleCore.Library;
using System.Threading.Tasks;
using System.Diagnostics;
using IoTClient.Clients.PLC;
using IoTClient.Enums;
using SimpleCore.Traffic;
using SimpleCore.PropType;
using System.Net.Http;
using System.Reflection;
using LessokajiWeaverUtilities.Utilities;
namespace StandardScene.Scheduler
{
[MissionType(Name = "安全信号交互", editor = typeof(SecuritySignalMission))]
[I18N.DocumentTranslation(Name = "Security Signal Mission", locale = "en")]
public class SecuritySignalMission : Mission
{
public static Mission Create()
{
return new SecuritySignalMission();
}
public int[] stringToInt(string str)
{
return str.Split(' ').Select(s => (int)Convert.ToInt16(s, 10)).ToArray();
}
public class NOdeIsEnableMissionStatus : MissionStatus
{
public static List<string> staions = new List<string>() { "One","Two","Three","Four","Five"};
public static List<string> signalDB = new List<string>() { "beat", "request", "allowRequest", "entering", "inplace","requestLeave" ,"allowLeave","leaving","safeLeave","AGVAlarm","PlcAlarm"};
public List<bool> One = Enumerable.Repeat(false, signalDB.Count()).ToList();
public Dictionary<string, Dictionary<string,bool>> signal = new Dictionary<string, Dictionary<string, bool>>();
public List<bool> Two = Enumerable.Repeat(false, signalDB.Count()).ToList();
public List<bool> Three = Enumerable.Repeat(false, signalDB.Count()).ToList();
public List<bool> Four = Enumerable.Repeat(false, signalDB.Count()).ToList();
public List<bool> Five = Enumerable.Repeat(false, signalDB.Count()).ToList();
public List<bool> Six = Enumerable.Repeat(false, signalDB.Count()).ToList();
public List<bool> Seven = Enumerable.Repeat(false, signalDB.Count()).ToList();
public List<bool> Eight = Enumerable.Repeat(false, signalDB.Count()).ToList();
public float readOnceTime = 0;
public float readAllDataTime = 0;
public float writeOnceTime = 0;
public float writeAllDataTime = 0;
}
public override MissionStatus status { get; set; } = new NOdeIsEnableMissionStatus();
[JsonIgnore] public Thread myThread;
[JsonIgnore] private bool started = false;
[JsonIgnore] private int iterationComm = 0;
[JsonIgnore] private object sync = new();
[JsonIgnore] public static HttpClient hc = new HttpClient() { Timeout = TimeSpan.FromSeconds(2) };
[MethodMember(Name = "启动进程", Description = "开始处理上下料队列")]
public override void Execute()
{
started = true;
Task.Factory.StartNew(() => {
HttpPostData httpPostData = new HttpPostData();
Dictionary<string, Dictionary<string, bool>> Allsignal = new Dictionary<string, Dictionary<string, bool>>();
//Dictionary<string, bool> stationSignals = new Dictionary<string, bool>();
while (started)
{
try
{
foreach (var station in NOdeIsEnableMissionStatus.staions)
{
Dictionary<string, bool> stationSignals = new Dictionary<string, bool>();
foreach (var signalName in NOdeIsEnableMissionStatus.signalDB)
{
// 根据station和signalName获取对应的bool值
bool signalValue;
switch (station)
{
case "One":
signalValue = ((NOdeIsEnableMissionStatus)status).One[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
case "Two":
signalValue = ((NOdeIsEnableMissionStatus)status).Two[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
case "Three":
signalValue = ((NOdeIsEnableMissionStatus)status).Three[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
case "Four":
signalValue = ((NOdeIsEnableMissionStatus)status).Four[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
case "Five":
signalValue = ((NOdeIsEnableMissionStatus)status).Five[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
case "Six":
signalValue = ((NOdeIsEnableMissionStatus)status).Six[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
case "Seven":
signalValue = ((NOdeIsEnableMissionStatus)status).Seven[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
case "Eight":
signalValue = ((NOdeIsEnableMissionStatus)status).Eight[(NOdeIsEnableMissionStatus.signalDB).IndexOf(signalName)];
break;
default:
throw new Exception("Invalid station name");
}
// 检查字典中是否存在指定的键,如果存在则修改其值,否则添加新的键值对
if (stationSignals.ContainsKey(signalName))
{
stationSignals[signalName] = signalValue;
}
else
{
stationSignals.Add(signalName, signalValue);
}
}
if (Allsignal.ContainsKey(station))
{
Allsignal[station] = stationSignals;
}
else {
Allsignal.Add(station, stationSignals);
}
}
string result=JsonConvert.SerializeObject(Allsignal);
//string result = GetListsAsStrings((NOdeIsEnableMissionStatus)status);
Diagnosis.Log($"向迷毂提供安全信号---{result}", "signalinfo", true);
httpPostData.UploadSignal(result);
Thread.Sleep(500);
}
catch (Exception e)
{
Diagnosis.Post($"{ExceptionFormatter.FormatEx(e)}", "安全信号");
}
}
});
}
[MethodMember(Name = "关闭机构进程", Description = "关闭机构进程")]
public void Stop()
{
started = false;
status.status = $"已停止-循环";
}
Stopwatch stopwatch3 = new Stopwatch();
Stopwatch stopwatch2 = new Stopwatch();
public static string GetListsAsStrings(object obj)
{
Dictionary<string, string> result = new Dictionary<string, string>();
Type type = obj.GetType();
FieldInfo[] fieldInfo= type.GetFields();
foreach (FieldInfo property in fieldInfo)
{
if (property.FieldType== typeof(List<bool>))
{
List<bool> list = (List<bool>)property.GetValue(obj);
result[property.Name] = String.Join(",", list.Select(b => b ? "1" : "0"));
}
}
return JsonConvert.SerializeObject(result);
}
}
}