| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using TeamAAS.Global.Devices;
- using TeamAAS.Motion.Models;
- namespace TeamAAS.Motion.Motions
- {
- /// <summary>
- /// 仿真运动卡:无硬件环境下的全功能实现(联调/演示/单元测试用)。
- /// </summary>
- public class SimulatedMotionCard : IMotionCard, IMasterFollowHost, IMotionSimulation, IMotionSafetyHost, IMotionIoHost
- {
- private readonly MotionDeviceConfig _cfg;
- private int _axisCount;
- private IAxis[] _axes = Array.Empty<IAxis>();
- private Dictionary<int, IAxis> _axisMap = new Dictionary<int, IAxis>();
- private Dictionary<int, SimulatedAxis> _hwAxes = new Dictionary<int, SimulatedAxis>();
- private Dictionary<int, MotionAxisConfig> _axisCfgs = new Dictionary<int, MotionAxisConfig>();
- private readonly MasterFollowSession _follow = new MasterFollowSession();
- private readonly MotionSafetyGuard _guard;
- private readonly bool[] _localDi = new bool[64];
- private readonly bool[] _localDo = new bool[64];
- private readonly bool[] _ecatDi = new bool[256];
- private readonly bool[] _ecatDo = new bool[256];
- private Timer _updateTimer;
- private bool _isConnected;
- private readonly object _lock = new object();
- private const double UpdateIntervalMs = 10;
- public string Name => _cfg.Name;
- public bool IsConnected => _isConnected;
- public int AxisCount => _axisCount;
- public bool IsEstopActive => _guard.EstopActive;
- public bool IsStopActive => _guard.StopActive;
- internal MotionDeviceConfig DeviceConfig => _cfg;
- public event EventHandler<MotionConnectionStateChangedEventArgs> ConnectionStateChanged;
- public event EventHandler<MotionErrorEventArgs> ErrorOccurred;
- public event EventHandler SafetyChanged;
- public SimulatedMotionCard(MotionDeviceConfig cfg)
- {
- _cfg = cfg ?? new MotionDeviceConfig();
- RebuildAxes();
- _guard = new MotionSafetyGuard(
- () => _cfg,
- ReadDI,
- OnSafetyEstopRise,
- OnSafetyEstopHold,
- OnSafetyStopRise);
- _guard.Changed += (_, __) =>
- {
- try { SafetyChanged?.Invoke(this, EventArgs.Empty); }
- catch { }
- };
- }
- public bool AllowEnable(out string reason) => _guard.AllowEnable(out reason);
- public bool AllowMotion(out string reason) => _guard.AllowMotion(out reason);
- private bool RejectEnable()
- {
- if (_guard.AllowEnable(out var reason)) return false;
- RaiseError(reason);
- return true;
- }
- private bool RejectMotion()
- {
- if (_guard.AllowMotion(out var reason)) return false;
- RaiseError(reason);
- return true;
- }
- private void RaiseError(string message)
- {
- ErrorOccurred?.Invoke(this, new MotionErrorEventArgs(message));
- }
- private void OnSafetyEstopRise()
- {
- if (!_isConnected) return;
- EmergencyStop();
- }
- private void OnSafetyEstopHold()
- {
- if (!_isConnected) return;
- SimulatedAxis[] axes;
- lock (_lock)
- {
- if (!_isConnected) return;
- axes = _hwAxes.Values.ToArray();
- }
- foreach (var a in axes) a.Disable();
- }
- private void OnSafetyStopRise()
- {
- if (!_isConnected) return;
- Stop(-1);
- }
- public bool CanSimulateDi => true;
- public int GetDiCount(MotionIoBank bank)
- => bank == MotionIoBank.EtherCat
- ? ClampCount(_cfg.InputCount, _ecatDi.Length, 16)
- : ClampCount(_cfg.LocalInputCount, _localDi.Length, 16);
- public int GetDoCount(MotionIoBank bank)
- => bank == MotionIoBank.EtherCat
- ? ClampCount(_cfg.OutputCount, _ecatDo.Length, 16)
- : ClampCount(_cfg.LocalOutputCount, _localDo.Length, 16);
- private static int ClampCount(int configured, int max, int fallback)
- {
- if (configured <= 0) return Math.Min(fallback, max);
- return Math.Min(configured, max);
- }
- private static bool[] BankDi(MotionIoBank bank, bool[] local, bool[] ecat)
- => bank == MotionIoBank.EtherCat ? ecat : local;
- public bool ReadDI(int portIndex) => ReadDI(MotionIoBank.Local, portIndex);
- public bool ReadDI(MotionIoBank bank, int index)
- {
- var bits = BankDi(bank, _localDi, _ecatDi);
- if (index < 0 || index >= bits.Length) return false;
- return bits[index];
- }
- public bool ReadDO(MotionIoBank bank, int index)
- {
- var bits = BankDi(bank, _localDo, _ecatDo);
- if (index < 0 || index >= bits.Length) return false;
- return bits[index];
- }
- public bool WriteDO(int portIndex, bool value) => WriteDO(MotionIoBank.Local, portIndex, value);
- public bool WriteDO(MotionIoBank bank, int index, bool value)
- {
- var bits = BankDi(bank, _localDo, _ecatDo);
- if (index < 0 || index >= bits.Length) return false;
- bits[index] = value;
- return true;
- }
- public bool WriteDI(MotionIoBank bank, int index, bool value)
- {
- var bits = BankDi(bank, _localDi, _ecatDi);
- if (index < 0 || index >= bits.Length) return false;
- bits[index] = value;
- return true;
- }
- public void ReloadFromConfig()
- {
- lock (_lock)
- {
- _follow.Clear();
- RebuildAxes();
- }
- }
- public bool Open()
- {
- lock (_lock)
- {
- if (_isConnected)
- {
- EnsureTimerUnlocked();
- return true;
- }
- _isConnected = true;
- EnsureTimerUnlocked();
- }
- _guard.Start();
- ConnectionStateChanged?.Invoke(this, new MotionConnectionStateChangedEventArgs(true));
- return true;
- }
- public void Simulate(double deltaSeconds)
- {
- if (deltaSeconds <= 0) return;
- SimulatedAxis[] axes;
- lock (_lock)
- {
- if (!_isConnected) return;
- EnsureTimerUnlocked();
- axes = _hwAxes.Values.ToArray();
- }
- foreach (var axis in axes)
- axis.Update(deltaSeconds);
- }
- public void FinishDiscreteMoves()
- {
- SimulatedAxis[] axes;
- lock (_lock)
- {
- if (!_isConnected) return;
- axes = _hwAxes.Values.ToArray();
- }
- double dt = 0;
- foreach (var axis in axes)
- dt = Math.Max(dt, axis.RemainingDiscreteSeconds());
- if (dt > 0)
- Simulate(dt + 1e-6);
- else
- {
- foreach (var axis in axes)
- axis.SnapDiscreteIfIdleVelocity();
- }
- }
- private void EnsureTimerUnlocked()
- {
- if (!_isConnected) return;
- if (_updateTimer != null) return;
- _updateTimer = new Timer(UpdateAxes, null, 0, (int)UpdateIntervalMs);
- }
- public void Close()
- {
- _guard.Stop();
- Timer timerToDispose = null;
- lock (_lock)
- {
- if (!_isConnected) return;
- _isConnected = false;
- timerToDispose = _updateTimer;
- _updateTimer = null;
- _follow.Clear();
- }
- timerToDispose?.Dispose();
- ConnectionStateChanged?.Invoke(this, new MotionConnectionStateChangedEventArgs(false));
- }
- void IMasterFollowHost.BeginSoloMasterFollow(int masterAxisNo, IEnumerable<IAxis> slaves)
- => _follow.Begin(masterAxisNo, slaves);
- void IMasterFollowHost.ReleaseMasterFollow() => _follow.Release();
- IDisposable IMasterFollowHost.SuspendFollowRelease() => _follow.Suspend();
- internal MotionAxisConfig GetAxisConfig(int axisNo)
- {
- if (_axisCfgs.TryGetValue(axisNo, out var cfg) && cfg != null)
- return cfg;
- return new MotionAxisConfig { AxisNo = axisNo };
- }
- private void ReleaseFollowIfIndependent(int axis)
- {
- if (_follow.Suspended || _follow.IsReleasing) return;
- if (axis >= 0 && TryCombined(axis, out _)) return;
- _follow.Release();
- }
- public bool SetEnable(int axis, bool enable)
- {
- if (enable && RejectEnable()) return false;
- if (!_isConnected) return false;
- if (axis < 0)
- {
- foreach (var a in _hwAxes.Values) { if (enable) a.Enable(); else a.Disable(); }
- return true;
- }
- if (TryCombined(axis, out var combined))
- {
- if (enable) combined.Enable(); else combined.Disable();
- return true;
- }
- if (!_hwAxes.TryGetValue(axis, out var hw)) return false;
- if (enable) hw.Enable(); else hw.Disable();
- return true;
- }
- public bool Home(int axis, int mode = 0)
- {
- if (RejectMotion()) return false;
- if (!_isConnected || !IsValidAxis(axis)) return false;
- if (TryCombined(axis, out var combined))
- {
- combined.Home((HomeMode)mode);
- return true;
- }
- ReleaseFollowIfIndependent(axis);
- if (!_hwAxes.TryGetValue(axis, out var hw)) return false;
- hw.Home((HomeMode)mode);
- return true;
- }
- public bool IsHomed(int axis)
- {
- if (!IsValidAxis(axis)) return false;
- return _axisMap[axis].IsHomed;
- }
- public bool MoveAbsolute(int axis, double position, double velocity)
- {
- if (RejectMotion()) return false;
- if (!_isConnected || !IsValidAxis(axis)) return false;
- if (TryCombined(axis, out var combined))
- {
- combined.Velocity = velocity;
- combined.MoveTo(position);
- return true;
- }
- ReleaseFollowIfIndependent(axis);
- var a = _axisMap[axis];
- var cfg = GetAxisConfig(axis);
- a.Velocity = Math.Abs(cfg.ClampVelocity(velocity));
- a.MoveTo(cfg.ClampPosition(position));
- return true;
- }
- public bool MoveRelative(int axis, double distance, double velocity)
- {
- if (RejectMotion()) return false;
- if (!_isConnected || !IsValidAxis(axis)) return false;
- if (TryCombined(axis, out var combined))
- {
- combined.Velocity = velocity;
- combined.MoveBy(distance);
- return true;
- }
- ReleaseFollowIfIndependent(axis);
- var a = _axisMap[axis];
- var cfg = GetAxisConfig(axis);
- a.Velocity = Math.Abs(cfg.ClampVelocity(velocity));
- double target = cfg.ClampPosition(a.CommandPosition + distance);
- a.MoveTo(target);
- return true;
- }
- public bool JogStart(int axis, int direction, double velocity)
- {
- if (RejectMotion()) return false;
- if (!_isConnected || !IsValidAxis(axis)) return false;
- if (TryCombined(axis, out var combined))
- {
- combined.Jog((direction >= 0 ? 1 : -1) * Math.Abs(velocity));
- return true;
- }
- ReleaseFollowIfIndependent(axis);
- var dir = direction >= 0 ? 1 : -1;
- var axisObj = _axisMap[axis];
- double vel = GetAxisConfig(axis).ClampJog(dir * Math.Abs(velocity), axisObj.CommandPosition);
- axisObj.Jog(vel);
- return true;
- }
- public bool JogStop(int axis)
- {
- if (!IsValidAxis(axis)) return false;
- return Stop(axis);
- }
- public bool Stop(int axis = -1)
- {
- if (!_isConnected) return false;
- if (axis < 0)
- {
- _follow.Release();
- foreach (var a in _hwAxes.Values) a.Stop();
- return true;
- }
- if (!IsValidAxis(axis)) return false;
- if (TryCombined(axis, out var combined))
- {
- combined.Stop();
- return true;
- }
- ReleaseFollowIfIndependent(axis);
- _axisMap[axis].Stop();
- return true;
- }
- public AxisStatus GetAxisStatus(int axis)
- {
- if (!IsValidAxis(axis)) return null;
- var a = _axisMap[axis];
- return new AxisStatus
- {
- Index = axis,
- Name = a.Name,
- Position = a.ActualPosition,
- Velocity = a.ActualVelocity,
- IsMoving = a.IsMoving,
- IsHomed = a.IsHomed,
- IsEnabled = a.IsEnabled
- };
- }
- public List<AxisStatus> GetAllAxisStatus()
- {
- var list = new List<AxisStatus>(_axes.Length);
- foreach (var a in _axes)
- list.Add(GetAxisStatus(a.AxisNo));
- return list;
- }
- public IAxis GetAxis(int axisNo)
- {
- if (!IsValidAxis(axisNo))
- throw new ArgumentOutOfRangeException(nameof(axisNo), "轴号超出范围");
- return _axisMap[axisNo];
- }
- public IList<IAxis> GetAxes() => _axes.ToList();
- public bool MoveLinear(double[] targetPositions, double velocity)
- {
- if (RejectMotion()) return false;
- if (!_isConnected || targetPositions == null) return false;
- _follow.Release();
- var hw = _hwAxes.Values.OrderBy(a => a.AxisNo).ToList();
- if (targetPositions.Length > hw.Count) return false;
- for (int i = 0; i < targetPositions.Length; i++)
- {
- var cfg = GetAxisConfig(hw[i].AxisNo);
- hw[i].Velocity = Math.Abs(cfg.ClampVelocity(velocity));
- hw[i].MoveTo(cfg.ClampPosition(targetPositions[i]));
- }
- return true;
- }
- public bool MoveArc(double[] centerPoint, double[] targetPositions, double velocity)
- => MoveLinear(targetPositions, velocity);
- public bool EmergencyStop()
- {
- if (!_isConnected) return false;
- _follow.Clear();
- foreach (var axis in _hwAxes.Values) axis.Stop();
- return true;
- }
- private bool IsValidAxis(int axis) => _axisMap.ContainsKey(axis);
- private bool TryCombined(int axis, out CombinedMotionAxis combined)
- {
- combined = null;
- if (_axisMap.TryGetValue(axis, out var a) && a is CombinedMotionAxis c)
- {
- combined = c;
- return true;
- }
- return false;
- }
- private void RebuildAxes()
- {
- _follow.Clear();
- var oldHw = _hwAxes;
- var cfgs = MotionAxisCatalog.GetEffective(_cfg);
- _hwAxes = new Dictionary<int, SimulatedAxis>();
- _axisCfgs = new Dictionary<int, MotionAxisConfig>();
- _axisMap = new Dictionary<int, IAxis>();
- var view = new List<IAxis>(cfgs.Count);
- foreach (var cfg in cfgs)
- {
- var axis = new SimulatedAxis(this, cfg.AxisNo)
- {
- Name = string.IsNullOrWhiteSpace(cfg.Name) ? $"Axis-{cfg.AxisNo}" : cfg.Name,
- Velocity = cfg.Velocity,
- Acceleration = cfg.Acceleration,
- Deceleration = cfg.Deceleration,
- Jerk = cfg.Jerk
- };
- if (oldHw != null && oldHw.TryGetValue(cfg.AxisNo, out var prev))
- {
- axis.SetPosition(prev.ActualPosition);
- }
- _hwAxes[cfg.AxisNo] = axis;
- _axisMap[cfg.AxisNo] = axis;
- _axisCfgs[cfg.AxisNo] = cfg;
- axis.BindSafety(cfg);
- }
- foreach (var cfg in cfgs)
- {
- if (cfg.IsGrouped && _hwAxes.TryGetValue(cfg.AxisNo, out var master))
- {
- var combined = new CombinedMotionAxis(this, cfg, master, no =>
- _hwAxes.TryGetValue(no, out var a) ? a : null);
- _axisMap[cfg.AxisNo] = combined;
- view.Add(combined);
- }
- else if (_axisMap.TryGetValue(cfg.AxisNo, out var hw))
- {
- view.Add(hw);
- }
- }
- _axes = view.ToArray();
- _axisCount = _axes.Length;
- }
- private void UpdateAxes(object state)
- {
- Simulate(UpdateIntervalMs / 1000.0);
- }
- }
- public class SimulatedAxis : IAxis
- {
- private readonly SimulatedMotionCard _owner;
- private readonly object _lock = new object();
- private AxisState _state = AxisState.Off;
- private bool _isEnabled;
- private bool _isMoving;
- private bool _isHomed;
- private double _commandPos;
- private double _actualPos;
- private double _actualVel;
- private double _targetPos;
- private double _velocity = 100.0;
- private double _accel = 500.0;
- private double _decel = 500.0;
- private double _jerk = 1000.0;
- private double _jogVelocity;
- private MotionAxisConfig _safety = new MotionAxisConfig();
- public int AxisNo { get; }
- public string Name { get; set; }
- public AxisState State => _state;
- public bool IsEnabled => _isEnabled;
- public bool IsMoving => _isMoving;
- public bool IsHomed => _isHomed;
- public double CommandPosition => _commandPos;
- public double ActualPosition => _actualPos;
- public double ActualVelocity => _actualVel;
- public double Velocity { get => _velocity; set => _velocity = value; }
- public double Acceleration { get => _accel; set => _accel = value; }
- public double Deceleration { get => _decel; set => _decel = value; }
- public double Jerk { get => _jerk; set => _jerk = value; }
- public event EventHandler<AxisMotionEventArgs> MotionStarted;
- public event EventHandler<AxisMotionEventArgs> MotionCompleted;
- public event EventHandler<AxisStateChangedEventArgs> StateChanged;
- public event EventHandler<AxisErrorEventArgs> ErrorOccurred;
- public SimulatedAxis(SimulatedMotionCard owner, int axisNo)
- {
- _owner = owner;
- AxisNo = axisNo;
- Name = $"Axis-{axisNo}";
- }
- internal void BindSafety(MotionAxisConfig cfg)
- {
- _safety = cfg ?? new MotionAxisConfig { AxisNo = AxisNo };
- }
- internal double RemainingDiscreteSeconds()
- {
- lock (_lock)
- {
- if (!_isMoving || _state != AxisState.DiscreteMotion) return 0;
- if (_velocity < 1e-9) return 0;
- return Math.Abs(_targetPos - _actualPos) / _velocity;
- }
- }
- internal void SnapDiscreteIfIdleVelocity()
- {
- lock (_lock)
- {
- if (!_isMoving || _state != AxisState.DiscreteMotion) return;
- _actualPos = _targetPos;
- _commandPos = _targetPos;
- _actualVel = 0;
- _isMoving = false;
- SetState(AxisState.StandStill);
- OnMotionCompleted(new AxisMotionEventArgs(AxisNo, _targetPos, _actualPos));
- }
- }
- internal void Update(double deltaTime)
- {
- lock (_lock)
- {
- if (!_isEnabled || _state == AxisState.Error || _state == AxisState.Off)
- return;
- if (_state == AxisState.ContinuousMotion && Math.Abs(_jogVelocity) > 0.0001)
- {
- double delta = _jogVelocity * deltaTime;
- double next = _safety.ClampPosition(_actualPos + delta);
- if (Math.Abs(next - _actualPos) < 1e-9)
- {
- _jogVelocity = 0;
- _actualVel = 0;
- SetState(AxisState.StandStill);
- _isMoving = false;
- OnMotionCompleted(new AxisMotionEventArgs(AxisNo, _actualPos, _actualPos));
- return;
- }
- _commandPos = next;
- _actualPos = next;
- _actualVel = _jogVelocity;
- return;
- }
- if (_state == AxisState.DiscreteMotion)
- {
- double remaining = _targetPos - _actualPos;
- double distance = Math.Abs(remaining);
- if (distance < 0.0001)
- {
- _actualPos = _targetPos;
- _commandPos = _targetPos;
- _actualVel = 0;
- SetState(AxisState.StandStill);
- _isMoving = false;
- OnMotionCompleted(new AxisMotionEventArgs(AxisNo, _targetPos, _actualPos));
- return;
- }
- double speed = Math.Sign(remaining) * Math.Max(_velocity, 1e-6);
- double step = speed * deltaTime;
- if (Math.Abs(step) > Math.Abs(remaining) || _velocity < 1e-9)
- step = remaining;
- _actualPos += step;
- _commandPos = _actualPos;
- _actualVel = deltaTime > 1e-12 ? step / deltaTime : 0;
- }
- }
- }
- private void StartMoveTo(double target)
- {
- if (_owner != null && !_owner.AllowMotion(out var reason))
- {
- OnError(reason);
- return;
- }
- lock (_lock)
- {
- if (!_isEnabled) { OnError("轴未使能,无法运动"); return; }
- if (_state == AxisState.Error) { OnError("轴处于错误状态"); return; }
- _velocity = Math.Abs(_safety.ClampVelocity(_velocity));
- _targetPos = _safety.ClampPosition(target);
- _jogVelocity = 0;
- if (Math.Abs(_targetPos - _actualPos) < 0.0001 || _velocity < 1e-9)
- {
- _actualPos = _targetPos;
- _commandPos = _targetPos;
- _actualVel = 0;
- _isMoving = false;
- SetState(AxisState.StandStill);
- OnMotionCompleted(new AxisMotionEventArgs(AxisNo, _targetPos, _actualPos));
- return;
- }
- SetState(AxisState.DiscreteMotion);
- _isMoving = true;
- OnMotionStarted(new AxisMotionEventArgs(AxisNo, _targetPos, _actualPos));
- }
- }
- public void Enable()
- {
- if (_owner != null && !_owner.AllowEnable(out var reason))
- {
- OnError(reason);
- return;
- }
- lock (_lock)
- {
- if (_isEnabled) return;
- _isEnabled = true;
- if (_state == AxisState.Off) SetState(AxisState.StandStill);
- }
- }
- public void Disable()
- {
- lock (_lock)
- {
- if (!_isEnabled) return;
- _isMoving = false;
- _jogVelocity = 0;
- SetState(AxisState.Off);
- _isEnabled = false;
- }
- }
- public void MoveTo(double position) => StartMoveTo(position);
- public void MoveBy(double distance) => StartMoveTo(_actualPos + distance);
- public void Jog(double velocity)
- {
- if (_owner != null && !_owner.AllowMotion(out var reason))
- {
- OnError(reason);
- return;
- }
- lock (_lock)
- {
- if (!_isEnabled) { OnError("轴未使能,无法点动"); return; }
- if (_state == AxisState.Error) { OnError("轴处于错误状态"); return; }
- _jogVelocity = _safety.ClampJog(velocity, _actualPos);
- if (Math.Abs(_jogVelocity) < 1e-9)
- {
- _isMoving = false;
- _actualVel = 0;
- SetState(AxisState.StandStill);
- return;
- }
- SetState(AxisState.ContinuousMotion);
- _isMoving = true;
- _actualVel = _jogVelocity;
- OnMotionStarted(new AxisMotionEventArgs(AxisNo, double.NaN, _actualPos));
- }
- }
- public void Stop()
- {
- lock (_lock)
- {
- if (!_isMoving) return;
- _jogVelocity = 0;
- _actualVel = 0;
- SetState(AxisState.StandStill);
- _isMoving = false;
- OnMotionCompleted(new AxisMotionEventArgs(AxisNo, _targetPos, _actualPos));
- }
- }
- public void Home(HomeMode mode = HomeMode.Default)
- {
- if (_owner != null && !_owner.AllowMotion(out var reason))
- {
- OnError(reason);
- return;
- }
- lock (_lock)
- {
- if (!_isEnabled) { OnError("轴未使能,无法回零"); return; }
- _isMoving = false;
- _jogVelocity = 0;
- _actualVel = 0;
- _actualPos = 0;
- _commandPos = 0;
- _targetPos = 0;
- _isHomed = true;
- SetState(AxisState.StandStill);
- OnMotionCompleted(new AxisMotionEventArgs(AxisNo, 0, 0));
- }
- }
- public void SetPosition(double position)
- {
- lock (_lock)
- {
- _actualPos = position;
- _commandPos = position;
- }
- }
- public void SetMotionParams(MotionParams parameters)
- {
- lock (_lock)
- {
- if (parameters == null) return;
- _velocity = parameters.Velocity;
- _accel = parameters.Acceleration;
- _decel = parameters.Deceleration;
- _jerk = parameters.Jerk;
- }
- }
- private void SetState(AxisState newState)
- {
- if (_state == newState) return;
- var old = _state;
- _state = newState;
- OnStateChanged(new AxisStateChangedEventArgs(AxisNo, old, newState));
- }
- protected virtual void OnMotionStarted(AxisMotionEventArgs e) => MotionStarted?.Invoke(this, e);
- protected virtual void OnMotionCompleted(AxisMotionEventArgs e) => MotionCompleted?.Invoke(this, e);
- protected virtual void OnStateChanged(AxisStateChangedEventArgs e) => StateChanged?.Invoke(this, e);
- protected virtual void OnError(string message) => ErrorOccurred?.Invoke(this, new AxisErrorEventArgs(AxisNo, message));
- }
- public class SimulatedIOCard : IIOCard
- {
- private readonly MotionDeviceConfig _cfg;
- private readonly bool[] _inputs;
- private readonly bool[] _outputs;
- public string Name => _cfg.Name;
- public int InputCount => _inputs.Length;
- public int OutputCount => _outputs.Length;
- public bool IsConnected { get; private set; }
- public SimulatedIOCard(MotionDeviceConfig cfg)
- {
- _cfg = cfg ?? new MotionDeviceConfig();
- _inputs = new bool[Math.Max(1, _cfg.InputCount)];
- _outputs = new bool[Math.Max(1, _cfg.OutputCount)];
- }
- public bool Open() { IsConnected = true; return true; }
- public void Close() { IsConnected = false; }
- public bool[] ReadAllInputs()
- {
- lock (_inputs) { return (bool[])_inputs.Clone(); }
- }
- public bool[] ReadAllOutputs()
- {
- lock (_outputs) { return (bool[])_outputs.Clone(); }
- }
- public bool WriteOutput(int index, bool value)
- {
- if (index < 0 || index >= _outputs.Length) return false;
- lock (_outputs) { _outputs[index] = value; }
- return true;
- }
- public bool WriteOutputs(bool[] values)
- {
- if (values == null) return false;
- lock (_outputs)
- {
- int n = Math.Min(values.Length, _outputs.Length);
- for (int i = 0; i < n; i++) _outputs[i] = values[i];
- }
- return true;
- }
- }
- }
|