新增 scene.signal 信号交互插件,落地 PLC 握手与扫车放行。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using SimpleCore.Library;
|
||||
using SimpleLite.RCS.CarTypes;
|
||||
using StandardScene.Signal.Model;
|
||||
using StandardScene.Signal.Plc;
|
||||
|
||||
namespace StandardScene.Signal.Logic
|
||||
{
|
||||
/// <summary>1s 扫全场车,对齐反编译 DefaultPlugin.ExcuteThreadMethod + StarSignManage。</summary>
|
||||
public sealed class CarScanWorker : IDisposable
|
||||
{
|
||||
private readonly Func<IReadOnlyList<PlcStationRuntime>> _runtimes;
|
||||
private readonly int _tickMs;
|
||||
private readonly object _configLock = new object();
|
||||
private Dictionary<int, HandshakePointModel> _handshake = new Dictionary<int, HandshakePointModel>();
|
||||
private Dictionary<int, ReleasePointModel> _release = new Dictionary<int, ReleasePointModel>();
|
||||
private readonly Dictionary<string, int> _rateFlowLog = new Dictionary<string, int>();
|
||||
private readonly Dictionary<int, DateTime> _chargeStarted = new Dictionary<int, DateTime>();
|
||||
private readonly Dictionary<int, DateTime> _unknownTypeLog = new Dictionary<int, DateTime>();
|
||||
private CancellationTokenSource _cts;
|
||||
private Thread _thread;
|
||||
private int _tickCount;
|
||||
|
||||
public CarScanWorker(Func<IReadOnlyList<PlcStationRuntime>> runtimes, int tickMs)
|
||||
{
|
||||
_runtimes = runtimes ?? throw new ArgumentNullException(nameof(runtimes));
|
||||
_tickMs = Math.Max(100, tickMs);
|
||||
}
|
||||
|
||||
public int TickCount => _tickCount;
|
||||
|
||||
public void ReplaceConfig(IEnumerable<HandshakePointModel> handshake, IEnumerable<ReleasePointModel> release)
|
||||
{
|
||||
lock (_configLock)
|
||||
{
|
||||
_handshake = (handshake ?? Array.Empty<HandshakePointModel>())
|
||||
.Where(x => x != null && x.Sit > 0 && !string.IsNullOrWhiteSpace(x.SignalType))
|
||||
.GroupBy(x => x.Sit)
|
||||
.ToDictionary(g => g.Key, g => g.First());
|
||||
_release = (release ?? Array.Empty<ReleasePointModel>())
|
||||
.Where(x => x != null && x.Sit > 0)
|
||||
.GroupBy(x => x.Sit)
|
||||
.ToDictionary(g => g.Key, g => g.First());
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (_thread != null && _thread.IsAlive) return;
|
||||
_cts = new CancellationTokenSource();
|
||||
_thread = new Thread(Loop)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "SignalScan"
|
||||
};
|
||||
_thread.Start();
|
||||
Diagnosis.Log("扫车握手线程已启动", "Signal", true);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
try { _cts?.Cancel(); }
|
||||
catch { }
|
||||
try { _thread?.Join(2000); }
|
||||
catch { }
|
||||
_thread = null;
|
||||
Diagnosis.Log("扫车握手线程已停止", "Signal", true);
|
||||
}
|
||||
|
||||
public void Dispose() => Stop();
|
||||
|
||||
private void Loop()
|
||||
{
|
||||
var token = _cts.Token;
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
ScanOnce();
|
||||
Interlocked.Increment(ref _tickCount);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Diagnosis.Log($"检测信号停止的AGV是否可以放行异常:{ex.Message}", "Signal", true);
|
||||
}
|
||||
|
||||
try { Thread.Sleep(_tickMs); }
|
||||
catch (ThreadInterruptedException) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
internal void ScanOnce()
|
||||
{
|
||||
Dictionary<int, HandshakePointModel> handshake;
|
||||
Dictionary<int, ReleasePointModel> release;
|
||||
lock (_configLock)
|
||||
{
|
||||
handshake = _handshake;
|
||||
release = _release;
|
||||
}
|
||||
|
||||
PlcStationRuntime Find(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return null;
|
||||
var list = _runtimes() ?? Array.Empty<PlcStationRuntime>();
|
||||
return list.FirstOrDefault(x =>
|
||||
string.Equals(x.Config.JgName, name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
foreach (var car in SignalCarAdapter.All())
|
||||
{
|
||||
if (car == null) continue;
|
||||
var sit = SignalCarAdapter.PositionId(car);
|
||||
var spec = ResolveSpec(sit, handshake);
|
||||
|
||||
if (SignalCarAdapter.IsStopped(car))
|
||||
{
|
||||
if (spec != null)
|
||||
DispatchStopped(car, spec, Find);
|
||||
ReleasePointHandler.OnStopped(car, sit, release);
|
||||
}
|
||||
else if (spec != null && spec.Is("JGControl"))
|
||||
{
|
||||
JgControlHandler.OnMoving(car, spec, Find);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SignalStopSpec ResolveSpec(int sit, IReadOnlyDictionary<int, HandshakePointModel> handshake)
|
||||
{
|
||||
if (sit <= 0) return null;
|
||||
|
||||
if (SignalCarAdapter.TryReadSignalStop(sit, out var type, out var parms))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type))
|
||||
return null;
|
||||
return SignalStopSpec.Parse(type, parms);
|
||||
}
|
||||
|
||||
if (handshake != null && handshake.TryGetValue(sit, out var model))
|
||||
return SignalStopSpec.From(model);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void DispatchStopped(Car car, SignalStopSpec spec, Func<string, PlcStationRuntime> find)
|
||||
{
|
||||
if (spec.Is("TimedCharging"))
|
||||
{
|
||||
TimedChargeHandler.OnStopped(car, spec, _chargeStarted);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spec.Is("JGControl"))
|
||||
{
|
||||
JgControlHandler.OnStopped(car, spec, find, _rateFlowLog);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spec.Is("PointControl"))
|
||||
{
|
||||
PointControlHandler.OnStopped(car, spec, find);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spec.Is("RateFlowControl"))
|
||||
{
|
||||
RateFlowHandler.OnStopped(car, spec, _rateFlowLog);
|
||||
return;
|
||||
}
|
||||
|
||||
var sit = SignalCarAdapter.PositionId(car);
|
||||
if (_unknownTypeLog.TryGetValue(sit, out var last) && (DateTime.Now - last).TotalSeconds < 10)
|
||||
return;
|
||||
_unknownTypeLog[sit] = DateTime.Now;
|
||||
Diagnosis.Log($"信号类型【{spec.SignalType}】未找到匹配的业务处理模块", "Signal", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SimpleCore.Library;
|
||||
using SimpleLite.RCS.CarTypes;
|
||||
using StandardScene.Signal.Model;
|
||||
using StandardScene.Signal.Plc;
|
||||
|
||||
namespace StandardScene.Signal.Logic
|
||||
{
|
||||
/// <summary>对齐反编译 DefaultPlugin.JGControl / JGJudge / RequestIn / Arrived。</summary>
|
||||
public static class JgControlHandler
|
||||
{
|
||||
public static void OnStopped(Car car, SignalStopSpec spec, Func<string, PlcStationRuntime> find, IDictionary<string, int> rateFlowLog)
|
||||
{
|
||||
var jgName = spec.Part(0).Trim();
|
||||
var action = spec.Part(1).Trim();
|
||||
var rateFlow = spec.Part(2).Trim();
|
||||
if (string.IsNullOrEmpty(jgName))
|
||||
{
|
||||
Diagnosis.Log($"AGV{car.id}停在地标{SignalCarAdapter.PositionId(car)},读取配置机构名称为空", "JGControl", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(rateFlow) && !RateFlowHandler.AllowPass(car, rateFlow, rateFlowLog))
|
||||
{
|
||||
Diagnosis.Log($"AGV{car.id}停在地标{SignalCarAdapter.PositionId(car)},限流禁止通行", "JGControl", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(action, "RequestIn", StringComparison.OrdinalIgnoreCase))
|
||||
RequestIn(jgName, car, find);
|
||||
else if (string.Equals(action, "Arrived", StringComparison.OrdinalIgnoreCase))
|
||||
Arrived(jgName, car, find);
|
||||
}
|
||||
|
||||
public static void OnMoving(Car car, SignalStopSpec spec, Func<string, PlcStationRuntime> find)
|
||||
{
|
||||
var jgName = spec.Part(0).Trim();
|
||||
var action = spec.Part(1).Trim();
|
||||
if (string.IsNullOrEmpty(jgName))
|
||||
return;
|
||||
if (string.Equals(action, "RequestIn", StringComparison.OrdinalIgnoreCase))
|
||||
RequestInJudge(jgName, car, find);
|
||||
}
|
||||
|
||||
private static void RequestIn(string jgName, Car car, Func<string, PlcStationRuntime> find)
|
||||
{
|
||||
var rt = find(jgName);
|
||||
if (rt == null)
|
||||
{
|
||||
Diagnosis.Log($"{jgName} 未能找到机构", "JGControl", true);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (rt.Sync)
|
||||
{
|
||||
if (rt.ReadSignal == SignalReadValue.允许进入 &&
|
||||
rt.RequestInAgvNo == 0 &&
|
||||
rt.ReadWriteSignal == SignalWriteValue.无状态)
|
||||
{
|
||||
if (rt.Config.LineType is SignalLineType.单牵引下线机构 or SignalLineType.双牵引下线机构)
|
||||
{
|
||||
var inside = SignalCarAdapter.CarsAt(rt.Config.JgPointId);
|
||||
if (inside.Count > 0)
|
||||
{
|
||||
Diagnosis.Log(
|
||||
$"{jgName} 机构内有AGV【{string.Join(",", inside.Select(x => x.id))}】暂不放行AGV{car.id}",
|
||||
"JGControl", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Diagnosis.Log($"{jgName} 机构允许进入,通知AGV{car.id}启动,通知机构AGV进入中", "JGControl", true);
|
||||
rt.WriteSignal = SignalWriteValue.进入中;
|
||||
rt.RequestInAgvNo = car.id;
|
||||
SignalCarAdapter.StopCharge(car);
|
||||
SignalCarAdapter.Start(car);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rt.ReadSignal != SignalReadValue.允许进入 &&
|
||||
rt.RequestInAgvNo != car.id &&
|
||||
SignalCarAdapter.IsMoving(car))
|
||||
{
|
||||
SignalCarAdapter.Stop(car);
|
||||
Diagnosis.Log($"{jgName} 机构不允许进入,监控到AGV启动,暂停AGV{car.id}", "JGControl", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RequestInJudge(string jgName, Car car, Func<string, PlcStationRuntime> find)
|
||||
{
|
||||
var rt = find(jgName);
|
||||
if (rt == null)
|
||||
{
|
||||
Diagnosis.Log($"{jgName} 未能找到机构", "JGControl", true);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (rt.Sync)
|
||||
{
|
||||
if (rt.ReadSignal != SignalReadValue.允许进入 &&
|
||||
rt.RequestInAgvNo != car.id &&
|
||||
SignalCarAdapter.IsMoving(car))
|
||||
{
|
||||
SignalCarAdapter.Stop(car);
|
||||
Diagnosis.Log($"{jgName} 机构不允许进入,监控到AGV启动,暂停AGV{car.id}", "JGControl", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Arrived(string jgName, Car car, Func<string, PlcStationRuntime> find)
|
||||
{
|
||||
var rt = find(jgName);
|
||||
if (rt == null)
|
||||
{
|
||||
Diagnosis.Log($"{jgName} 未能找到机构", "JGControl", true);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (rt.Sync)
|
||||
{
|
||||
if (rt.InAgvNo == car.id)
|
||||
return;
|
||||
Diagnosis.Log($"AGV{car.id}已到达机构{jgName}", "JGControl", true);
|
||||
rt.WriteSignal = SignalWriteValue.到位;
|
||||
rt.InAgvNo = car.id;
|
||||
rt.RequestInAgvNo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using SimpleCore.Library;
|
||||
using SimpleLite.RCS.CarTypes;
|
||||
using StandardScene.Signal.Model;
|
||||
using StandardScene.Signal.Plc;
|
||||
|
||||
namespace StandardScene.Signal.Logic
|
||||
{
|
||||
/// <summary>对齐反编译 DefaultPlugin.PointControl:牵引棒升/降到位后再放行。</summary>
|
||||
public static class PointControlHandler
|
||||
{
|
||||
public static void OnStopped(Car car, SignalStopSpec spec, Func<string, PlcStationRuntime> find)
|
||||
{
|
||||
var action = spec.Part(0).Trim();
|
||||
var jgName = spec.Part(1).Trim();
|
||||
if (string.IsNullOrEmpty(action))
|
||||
{
|
||||
Diagnosis.Log($"AGV{car.id}停在地标{SignalCarAdapter.PositionId(car)},读取配置特殊点名称为空", "SetPin", true);
|
||||
return;
|
||||
}
|
||||
|
||||
var waitLeave = false;
|
||||
if (!string.IsNullOrEmpty(jgName))
|
||||
{
|
||||
var rt = find(jgName);
|
||||
if (rt != null)
|
||||
{
|
||||
lock (rt.Sync)
|
||||
waitLeave = rt.ReadSignal != SignalReadValue.允许离开;
|
||||
}
|
||||
}
|
||||
|
||||
var pos = SignalCarAdapter.PositionId(car);
|
||||
switch (action)
|
||||
{
|
||||
case "UP1":
|
||||
PinThenGo(car, pos, waitLeave, jgName, "SetPin1Up");
|
||||
break;
|
||||
case "UP2":
|
||||
PinThenGo(car, pos, waitLeave, jgName, "SetPin1Up", "SetPin2Up");
|
||||
break;
|
||||
case "Down1":
|
||||
PinThenGo(car, pos, waitLeave, jgName, "SetPin1Down");
|
||||
break;
|
||||
case "Down2":
|
||||
PinThenGo(car, pos, waitLeave, jgName, "SetPin1Down", "SetPin2Down");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PinThenGo(Car car, int pos, bool waitLeave, string jgName, params string[] actions)
|
||||
{
|
||||
var done = true;
|
||||
foreach (var a in actions)
|
||||
{
|
||||
if (!SignalCarAdapter.IsActionFinish(car, a))
|
||||
done = false;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
{
|
||||
foreach (var a in actions)
|
||||
SignalCarAdapter.Control(car, a);
|
||||
return;
|
||||
}
|
||||
|
||||
if (waitLeave)
|
||||
{
|
||||
Diagnosis.Log($"AGV{car.id}停在地标{pos},需要读取{jgName}工位的允许离开", "SetPin", true);
|
||||
return;
|
||||
}
|
||||
|
||||
SignalCarAdapter.Start(car);
|
||||
Diagnosis.Log($"AGV{car.id}停在地标{pos},牵引棒动作到位,已通知AGV启动", "SetPin", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SimpleCore.Library;
|
||||
using SimpleLite.RCS.CarTypes;
|
||||
using StandardScene.Signal.Plc;
|
||||
|
||||
namespace StandardScene.Signal.Logic
|
||||
{
|
||||
/// <summary>
|
||||
/// 对齐反编译 DefaultPlugin.RateFlowControl。
|
||||
/// 独立类型用分号:区域;车组;限额;点1,点2。JGControl 第三段用短横:区域-车组-限额-点1,点2。
|
||||
/// </summary>
|
||||
public static class RateFlowHandler
|
||||
{
|
||||
public static void OnStopped(Car car, SignalStopSpec spec, IDictionary<string, int> logByArea)
|
||||
{
|
||||
if (AllowPass(car, spec.SignalParams, logByArea, sep: ';'))
|
||||
{
|
||||
SignalCarAdapter.StopCharge(car);
|
||||
SignalCarAdapter.Start(car);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AllowPass(Car car, string rateFlowString, IDictionary<string, int> logByArea) =>
|
||||
AllowPass(car, rateFlowString, logByArea, sep: '-');
|
||||
|
||||
private static bool AllowPass(Car car, string raw, IDictionary<string, int> logByArea, char sep)
|
||||
{
|
||||
try
|
||||
{
|
||||
var parts = (raw ?? "").Split(sep);
|
||||
var area = parts.Length > 0 ? parts[0] : "";
|
||||
var group = parts.Length > 1 ? parts[1] : "";
|
||||
var limit = 0;
|
||||
if (parts.Length > 2)
|
||||
int.TryParse(parts[2], out limit);
|
||||
var sites = new List<int>();
|
||||
if (parts.Length > 3)
|
||||
{
|
||||
foreach (var s in parts[3].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (int.TryParse(s.Trim(), out var id))
|
||||
sites.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
var others = SignalCarAdapter.CarsAt(sites)
|
||||
.Where(x => x.id != car.id && string.Equals(SignalCarAdapter.GroupId(x), group, StringComparison.Ordinal))
|
||||
.ToList();
|
||||
var count = others.Count;
|
||||
if (count < limit)
|
||||
{
|
||||
Diagnosis.Log(
|
||||
$"限流区域{area}限制AGV组{group}流量{limit}辆AGV,当前停放{count},放行AGV{car.id}",
|
||||
"RateFlow", true);
|
||||
Note(logByArea, area, car, raw);
|
||||
return true;
|
||||
}
|
||||
|
||||
Diagnosis.Log(
|
||||
$"限流区域{area}限制AGV组{group}流量{limit}辆AGV,当前停放{count},无法放行",
|
||||
"RateFlow", true);
|
||||
Note(logByArea, area, car, raw);
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Diagnosis.Log($"处理区域限流业务异常:{ex.Message}", "RateFlow", true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Note(IDictionary<string, int> logByArea, string area, Car car, string raw)
|
||||
{
|
||||
if (logByArea == null) return;
|
||||
var changed = !logByArea.TryGetValue(area, out var last) || last != car.id;
|
||||
logByArea[area] = car.id;
|
||||
if (changed)
|
||||
Diagnosis.Log($"AGV{car.id}停在地标{SignalCarAdapter.PositionId(car)},配置参数:【{raw}】", "RateFlow", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using SimpleLite.RCS.CarTypes;
|
||||
using StandardScene.Signal.Model;
|
||||
using StandardScene.Signal.Plc;
|
||||
|
||||
namespace StandardScene.Signal.Logic
|
||||
{
|
||||
/// <summary>对齐反编译 StarSignManage:配置点停稳则停充并放行。</summary>
|
||||
public static class ReleasePointHandler
|
||||
{
|
||||
public static void OnStopped(Car car, int sit, IReadOnlyDictionary<int, ReleasePointModel> points)
|
||||
{
|
||||
if (points == null || !points.TryGetValue(sit, out var p) || p == null || !p.IsUse)
|
||||
return;
|
||||
SignalCarAdapter.StopCharge(car);
|
||||
SignalCarAdapter.Start(car);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using StandardScene.Signal.Model;
|
||||
|
||||
namespace StandardScene.Signal.Logic
|
||||
{
|
||||
/// <summary>握手点解析结果。参数格式与反编译 SignalStop.SignalParams 一致。</summary>
|
||||
public sealed class SignalStopSpec
|
||||
{
|
||||
public string SignalType { get; init; } = "";
|
||||
public string SignalParams { get; init; } = "";
|
||||
public string[] Parts { get; init; } = Array.Empty<string>();
|
||||
|
||||
public string Part(int index)
|
||||
{
|
||||
if (index < 0 || index >= Parts.Length)
|
||||
return "";
|
||||
return Parts[index] ?? "";
|
||||
}
|
||||
|
||||
public static SignalStopSpec Parse(string signalType, string signalParams)
|
||||
{
|
||||
var type = (signalType ?? "").Trim();
|
||||
var raw = signalParams ?? "";
|
||||
return new SignalStopSpec
|
||||
{
|
||||
SignalType = type,
|
||||
SignalParams = raw,
|
||||
Parts = raw.Split(new[] { ';' }, StringSplitOptions.None)
|
||||
};
|
||||
}
|
||||
|
||||
public static SignalStopSpec From(HandshakePointModel model)
|
||||
{
|
||||
if (model == null)
|
||||
return null;
|
||||
return Parse(model.SignalType, model.SignalParams);
|
||||
}
|
||||
|
||||
public bool Is(string type) =>
|
||||
string.Equals(SignalType, type, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SimpleCore.Library;
|
||||
using SimpleLite.RCS.CarTypes;
|
||||
using StandardScene.Signal.Plc;
|
||||
|
||||
namespace StandardScene.Signal.Logic
|
||||
{
|
||||
/// <summary>对齐反编译 DefaultPlugin.TimedCharging:时长 / 上限电量 / 下限电量。</summary>
|
||||
public static class TimedChargeHandler
|
||||
{
|
||||
public static void OnStopped(Car car, SignalStopSpec spec, IDictionary<int, DateTime> chargeStarted)
|
||||
{
|
||||
int.TryParse(spec.Part(0), out var maxSeconds);
|
||||
int.TryParse(spec.Part(1), out var maxSoc);
|
||||
int.TryParse(spec.Part(2), out var minSoc);
|
||||
|
||||
var charged = SignalCarAdapter.ChargeSeconds(car, chargeStarted);
|
||||
var soc = SignalCarAdapter.Soc(car);
|
||||
var pos = SignalCarAdapter.PositionId(car);
|
||||
|
||||
if (SignalCarAdapter.IsCharging(car))
|
||||
{
|
||||
Diagnosis.Log(
|
||||
$"AGV{car.id}实时电量{soc}停在地标{pos}上已充电{charged}秒,信号停止类型为定时充电,参数为:{maxSeconds},{maxSoc},{minSoc}",
|
||||
"Charge", true);
|
||||
|
||||
if (maxSoc != 0 && soc >= maxSoc)
|
||||
{
|
||||
Diagnosis.Log($"AGV{car.id}电量大于配置的最高充电电量,故停止充电", "Charge", true);
|
||||
SignalCarAdapter.StopCharge(car);
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxSeconds != 0 && charged >= maxSeconds)
|
||||
{
|
||||
if (minSoc != 0 && soc <= minSoc)
|
||||
{
|
||||
Diagnosis.Log($"AGV{car.id}充电时长已到达{maxSeconds}秒,但仍未充电至{minSoc}继续充电", "Charge", true);
|
||||
return;
|
||||
}
|
||||
|
||||
Diagnosis.Log($"AGV{car.id}充电时长已到达{maxSeconds}秒,故停止充电", "Charge", true);
|
||||
SignalCarAdapter.StopCharge(car);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SignalCarAdapter.IsStopped(car))
|
||||
{
|
||||
Diagnosis.Log($"AGV{car.id}已经停止充电,故放行AGV", "Charge", true);
|
||||
SignalCarAdapter.Start(car);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user