SimulatedDevices.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace TeamAAS.Motion
  5. {
  6. /// <summary>
  7. /// 仿真运动卡:无硬件环境下的全功能实现(联调/演示/单元测试用)。
  8. /// 轴位置按指令速度渐变逼近目标(后台定时器推进),IO 点内存模拟。
  9. /// 品牌适配器(雷赛/固高/IMC60G)实现 IMotionCard 时可直接参照本类的状态机结构。
  10. /// </summary>
  11. public class SimulatedMotionCard : TeamAAS.Global.Devices.IMotionCard
  12. {
  13. private readonly MotionDeviceConfig _cfg;
  14. private readonly object _sync = new object();
  15. private readonly double[] _pos;
  16. private readonly double[] _target;
  17. private readonly double[] _vel;
  18. private readonly bool[] _moving;
  19. private readonly bool[] _homed;
  20. private readonly bool[] _enabled;
  21. public string Name => _cfg.Name;
  22. public int AxisCount => _cfg.AxisCount;
  23. public bool IsConnected { get; private set; }
  24. public SimulatedMotionCard(MotionDeviceConfig cfg)
  25. {
  26. _cfg = cfg ?? new MotionDeviceConfig();
  27. int n = Math.Max(1, _cfg.AxisCount);
  28. _pos = new double[n];
  29. _target = new double[n];
  30. _vel = new double[n];
  31. _moving = new bool[n];
  32. _homed = new bool[n];
  33. _enabled = new bool[n];
  34. // 后台轮询推进仿真轴运动(50ms 周期)
  35. var t = new System.Threading.Timer(Tick, null, 50, 50);
  36. }
  37. private void Tick(object state)
  38. {
  39. lock (_sync)
  40. {
  41. for (int i = 0; i < _pos.Length; i++)
  42. {
  43. if (!_moving[i]) continue;
  44. double step = _vel[i] * 0.05; // 50ms 周期
  45. double diff = _target[i] - _pos[i];
  46. if (Math.Abs(diff) <= step) { _pos[i] = _target[i]; _moving[i] = false; }
  47. else _pos[i] += Math.Sign(diff) * step;
  48. }
  49. }
  50. }
  51. public bool Open() { IsConnected = true; return true; }
  52. public void Close() { IsConnected = false; }
  53. public bool SetEnable(int axis, bool enable)
  54. {
  55. ApplyAxis(ref axis);
  56. lock (_sync) { _enabled[axis] = enable; }
  57. return true;
  58. }
  59. public bool Home(int axis, int mode = 0)
  60. {
  61. ApplyAxis(ref axis);
  62. lock (_sync) { _pos[axis] = 0; _target[axis] = 0; _moving[axis] = false; _homed[axis] = true; }
  63. return true;
  64. }
  65. public bool IsHomed(int axis) { lock (_sync) { return _homed[ClampAxis(axis)]; } }
  66. public bool MoveAbsolute(int axis, double position, double velocity)
  67. {
  68. ApplyAxis(ref axis);
  69. lock (_sync) { _target[axis] = position; _vel[axis] = Math.Abs(velocity) <= 0 ? 1 : Math.Abs(velocity); _moving[axis] = true; }
  70. return true;
  71. }
  72. public bool MoveRelative(int axis, double distance, double velocity)
  73. {
  74. lock (_sync) { return MoveAbsolute(axis, _pos[ClampAxis(axis)] + distance, velocity); }
  75. }
  76. public bool JogStart(int axis, int direction, double velocity)
  77. {
  78. ApplyAxis(ref axis);
  79. lock (_sync) { _target[axis] = direction >= 0 ? double.MaxValue : double.MinValue; _vel[axis] = Math.Abs(velocity) <= 0 ? 1 : Math.Abs(velocity); _moving[axis] = true; }
  80. return true;
  81. }
  82. public bool JogStop(int axis)
  83. {
  84. lock (_sync) { int i = ClampAxis(axis); _target[i] = _pos[i]; _moving[i] = false; }
  85. return true;
  86. }
  87. public bool Stop(int axis = -1)
  88. {
  89. lock (_sync)
  90. {
  91. for (int i = 0; i < _pos.Length; i++)
  92. {
  93. if (axis >= 0 && i != axis) continue;
  94. _target[i] = _pos[i]; _moving[i] = false;
  95. }
  96. }
  97. return true;
  98. }
  99. public TeamAAS.Global.Devices.AxisStatus GetAxisStatus(int axis)
  100. {
  101. int i = ClampAxis(axis);
  102. lock (_sync)
  103. {
  104. return new TeamAAS.Global.Devices.AxisStatus
  105. {
  106. Index = i,
  107. Name = $"轴{i}",
  108. Position = _pos[i],
  109. Velocity = _moving[i] ? _vel[i] : 0,
  110. IsMoving = _moving[i],
  111. IsHomed = _homed[i],
  112. IsEnabled = _enabled[i],
  113. };
  114. }
  115. }
  116. public List<TeamAAS.Global.Devices.AxisStatus> GetAllAxisStatus()
  117. {
  118. var list = new List<TeamAAS.Global.Devices.AxisStatus>();
  119. for (int i = 0; i < AxisCount; i++) list.Add(GetAxisStatus(i));
  120. return list;
  121. }
  122. private int ClampAxis(int axis) => Math.Max(0, Math.Min(axis < 0 ? 0 : axis, _pos.Length - 1));
  123. private void ApplyAxis(ref int axis)
  124. {
  125. if (axis < 0) axis = 0;
  126. if (axis >= _pos.Length) axis = _pos.Length - 1;
  127. }
  128. }
  129. /// <summary>仿真 IO 卡(16进/16出,内存模拟,批量接口齐全)。</summary>
  130. public class SimulatedIOCard : TeamAAS.Global.Devices.IIOCard
  131. {
  132. private readonly MotionDeviceConfig _cfg;
  133. private readonly bool[] _inputs;
  134. private readonly bool[] _outputs;
  135. public string Name => _cfg.Name;
  136. public int InputCount => _inputs.Length;
  137. public int OutputCount => _outputs.Length;
  138. public bool IsConnected { get; private set; }
  139. public SimulatedIOCard(MotionDeviceConfig cfg)
  140. {
  141. _cfg = cfg ?? new MotionDeviceConfig();
  142. _inputs = new bool[Math.Max(1, _cfg.InputCount)];
  143. _outputs = new bool[Math.Max(1, _cfg.OutputCount)];
  144. }
  145. public bool Open() { IsConnected = true; return true; }
  146. public void Close() { IsConnected = false; }
  147. public bool[] ReadAllInputs()
  148. {
  149. lock (_inputs) { return (bool[])_inputs.Clone(); }
  150. }
  151. public bool[] ReadAllOutputs()
  152. {
  153. lock (_outputs) { return (bool[])_outputs.Clone(); }
  154. }
  155. public bool WriteOutput(int index, bool value)
  156. {
  157. if (index < 0 || index >= _outputs.Length) return false;
  158. lock (_outputs) { _outputs[index] = value; }
  159. return true;
  160. }
  161. public bool WriteOutputs(bool[] values)
  162. {
  163. if (values == null) return false;
  164. lock (_outputs)
  165. {
  166. int n = Math.Min(values.Length, _outputs.Length);
  167. for (int i = 0; i < n; i++) _outputs[i] = values[i];
  168. }
  169. return true;
  170. }
  171. }
  172. }