MotionMovePlugins.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using Plugins.Motion.Models;
  5. using TeamAAS.FlowEditor.Models;
  6. using TeamAAS.FlowEditor.Plugins;
  7. using TeamAAS.Motion;
  8. namespace Plugins.Motion
  9. {
  10. [Serializable]
  11. [Plugin("轴回零", PluginCategory.硬件模块, typeof(MotionHomeModel), "Home",
  12. Description = "指定轴回零,可勾选未使能时自动使能,并等待回零完成")]
  13. public class MotionHomePlugin : BasePlugin<MotionHomeModel>
  14. {
  15. public override List<OutputField> DeclareOutputs() => new List<OutputField>
  16. {
  17. new OutputField("结果", typeof(bool)),
  18. new OutputField("已回零", typeof(bool)),
  19. new OutputField("最终位置", typeof(double)),
  20. };
  21. public override NodeRunStatus PluginRun(CancellationToken token, out Dictionary<string, object> results)
  22. {
  23. var res = new Dictionary<string, object>();
  24. results = res;
  25. NodeRunStatus Fail(string m)
  26. {
  27. res["Error"] = m;
  28. res["结果"] = false;
  29. Log(1, $"轴回零失败: {m}", TeamAAS.LogLevel.Error);
  30. return NodeRunStatus.Failed;
  31. }
  32. try
  33. {
  34. if (Model.AxisNo < 0) return Fail("回零必须指定具体轴号(不能为 -1)");
  35. var card = MotionPluginHelper.GetCard(Service<MotionManager>(), Model.MotionCardName, out var err);
  36. if (card == null) return Fail(err);
  37. err = MotionPluginHelper.EnsureConnected(card, Model.AutoConnect);
  38. if (err != null) return Fail(err);
  39. err = MotionPluginHelper.EnsureEnabled(card, Model.AxisNo, Model.AutoEnable);
  40. if (err != null) return Fail(err);
  41. err = MotionPluginHelper.CheckMotionAllowed(card);
  42. if (err != null) return Fail(err);
  43. Log(3, $"轴回零 卡={card.Name} 轴={Model.AxisNo} 模式={Model.HomeMode}");
  44. if (!card.Home(Model.AxisNo, Model.HomeMode))
  45. return Fail("下发回零失败");
  46. err = MotionPluginHelper.WaitIdle(card, Model.AxisNo, Model.WaitTimeoutMs, token);
  47. if (err != null) return Fail(err);
  48. var st = card.GetAxisStatus(Model.AxisNo);
  49. MotionPluginHelper.FillStatus(res, st);
  50. if (st == null || !st.IsHomed)
  51. return Fail("回零结束但轴未处于已回零状态");
  52. res["结果"] = true;
  53. return NodeRunStatus.Success;
  54. }
  55. catch (OperationCanceledException) { throw; }
  56. catch (Exception ex) { return Fail(ex.Message); }
  57. }
  58. }
  59. [Serializable]
  60. [Plugin("绝对定位", PluginCategory.硬件模块, typeof(MotionMoveAbsModel), "AxisArrow",
  61. Description = "单轴绝对定位,目标位置/速度可公式绑定,可勾选未使能时自动使能")]
  62. public class MotionMoveAbsPlugin : BasePlugin<MotionMoveAbsModel>
  63. {
  64. public override List<OutputField> DeclareOutputs() => new List<OutputField>
  65. {
  66. new OutputField("结果", typeof(bool)),
  67. new OutputField("最终位置", typeof(double)),
  68. new OutputField("目标位置", typeof(double)),
  69. };
  70. public override NodeRunStatus PluginRun(CancellationToken token, out Dictionary<string, object> results)
  71. {
  72. var res = new Dictionary<string, object>();
  73. results = res;
  74. NodeRunStatus Fail(string m)
  75. {
  76. res["Error"] = m;
  77. res["结果"] = false;
  78. Log(1, $"绝对定位失败: {m}", TeamAAS.LogLevel.Error);
  79. return NodeRunStatus.Failed;
  80. }
  81. try
  82. {
  83. if (Model.AxisNo < 0) return Fail("定位必须指定具体轴号(不能为 -1)");
  84. var card = MotionPluginHelper.GetCard(Service<MotionManager>(), Model.MotionCardName, out var err);
  85. if (card == null) return Fail(err);
  86. err = MotionPluginHelper.EnsureConnected(card, Model.AutoConnect);
  87. if (err != null) return Fail(err);
  88. err = MotionPluginHelper.EnsureEnabled(card, Model.AxisNo, Model.AutoEnable);
  89. if (err != null) return Fail(err);
  90. err = MotionPluginHelper.CheckMotionAllowed(card);
  91. if (err != null) return Fail(err);
  92. double target = GetValue(Model.TargetPosition);
  93. double vel = GetValue(Model.Velocity);
  94. res["目标位置"] = target;
  95. Log(3, $"绝对定位 卡={card.Name} 轴={Model.AxisNo} 目标={target:F3} 速度={vel:F3}");
  96. if (!card.MoveAbsolute(Model.AxisNo, target, vel))
  97. return Fail("下发绝对定位失败");
  98. err = MotionPluginHelper.WaitIdle(card, Model.AxisNo, Model.WaitTimeoutMs, token);
  99. if (err != null) return Fail(err);
  100. var st = card.GetAxisStatus(Model.AxisNo);
  101. MotionPluginHelper.FillStatus(res, st);
  102. if (st == null) return Fail("无法读取轴状态");
  103. if (Math.Abs(st.Position - target) > Model.InPositionTolerance)
  104. return Fail($"到位偏差超限: 实际 {st.Position:F3} 目标 {target:F3} 容差 {Model.InPositionTolerance}");
  105. res["结果"] = true;
  106. return NodeRunStatus.Success;
  107. }
  108. catch (OperationCanceledException) { throw; }
  109. catch (Exception ex) { return Fail(ex.Message); }
  110. }
  111. }
  112. [Serializable]
  113. [Plugin("相对定位", PluginCategory.硬件模块, typeof(MotionMoveRelModel), "ArrowExpandHorizontal",
  114. Description = "单轴相对定位,距离/速度可公式绑定,可勾选未使能时自动使能")]
  115. public class MotionMoveRelPlugin : BasePlugin<MotionMoveRelModel>
  116. {
  117. public override List<OutputField> DeclareOutputs() => new List<OutputField>
  118. {
  119. new OutputField("结果", typeof(bool)),
  120. new OutputField("最终位置", typeof(double)),
  121. new OutputField("相对距离", typeof(double)),
  122. };
  123. public override NodeRunStatus PluginRun(CancellationToken token, out Dictionary<string, object> results)
  124. {
  125. var res = new Dictionary<string, object>();
  126. results = res;
  127. NodeRunStatus Fail(string m)
  128. {
  129. res["Error"] = m;
  130. res["结果"] = false;
  131. Log(1, $"相对定位失败: {m}", TeamAAS.LogLevel.Error);
  132. return NodeRunStatus.Failed;
  133. }
  134. try
  135. {
  136. if (Model.AxisNo < 0) return Fail("定位必须指定具体轴号(不能为 -1)");
  137. var card = MotionPluginHelper.GetCard(Service<MotionManager>(), Model.MotionCardName, out var err);
  138. if (card == null) return Fail(err);
  139. err = MotionPluginHelper.EnsureConnected(card, Model.AutoConnect);
  140. if (err != null) return Fail(err);
  141. err = MotionPluginHelper.EnsureEnabled(card, Model.AxisNo, Model.AutoEnable);
  142. if (err != null) return Fail(err);
  143. err = MotionPluginHelper.CheckMotionAllowed(card);
  144. if (err != null) return Fail(err);
  145. double dist = GetValue(Model.Distance);
  146. double vel = GetValue(Model.Velocity);
  147. var before = card.GetAxisStatus(Model.AxisNo);
  148. double expect = (before?.Position ?? 0) + dist;
  149. res["相对距离"] = dist;
  150. Log(3, $"相对定位 卡={card.Name} 轴={Model.AxisNo} 距离={dist:F3} 速度={vel:F3}");
  151. if (!card.MoveRelative(Model.AxisNo, dist, vel))
  152. return Fail("下发相对定位失败");
  153. err = MotionPluginHelper.WaitIdle(card, Model.AxisNo, Model.WaitTimeoutMs, token);
  154. if (err != null) return Fail(err);
  155. var st = card.GetAxisStatus(Model.AxisNo);
  156. MotionPluginHelper.FillStatus(res, st);
  157. if (st == null) return Fail("无法读取轴状态");
  158. if (Math.Abs(st.Position - expect) > Model.InPositionTolerance)
  159. return Fail($"到位偏差超限: 实际 {st.Position:F3} 期望 {expect:F3} 容差 {Model.InPositionTolerance}");
  160. res["结果"] = true;
  161. return NodeRunStatus.Success;
  162. }
  163. catch (OperationCanceledException) { throw; }
  164. catch (Exception ex) { return Fail(ex.Message); }
  165. }
  166. }
  167. [Serializable]
  168. [Plugin("轴停止", PluginCategory.硬件模块, typeof(MotionStopModel), "StopCircle",
  169. Description = "平滑停止指定轴,或对整卡急停")]
  170. public class MotionStopPlugin : BasePlugin<MotionStopModel>
  171. {
  172. public override List<OutputField> DeclareOutputs() => new List<OutputField>
  173. {
  174. new OutputField("结果", typeof(bool)),
  175. new OutputField("最终位置", typeof(double)),
  176. };
  177. public override NodeRunStatus PluginRun(CancellationToken token, out Dictionary<string, object> results)
  178. {
  179. var res = new Dictionary<string, object>();
  180. results = res;
  181. NodeRunStatus Fail(string m)
  182. {
  183. res["Error"] = m;
  184. res["结果"] = false;
  185. Log(1, $"轴停止失败: {m}", TeamAAS.LogLevel.Error);
  186. return NodeRunStatus.Failed;
  187. }
  188. try
  189. {
  190. var card = MotionPluginHelper.GetCard(Service<MotionManager>(), Model.MotionCardName, out var err);
  191. if (card == null) return Fail(err);
  192. err = MotionPluginHelper.EnsureConnected(card, Model.AutoConnect);
  193. if (err != null) return Fail(err);
  194. Log(3, $"轴停止 卡={card.Name} 轴={Model.AxisNo} 急停={Model.Emergency}");
  195. bool ok = Model.Emergency ? card.EmergencyStop() : card.Stop(Model.AxisNo);
  196. if (!ok) return Fail("下发停止失败");
  197. if (Model.AxisNo >= 0)
  198. MotionPluginHelper.FillStatus(res, card.GetAxisStatus(Model.AxisNo));
  199. res["结果"] = true;
  200. return NodeRunStatus.Success;
  201. }
  202. catch (OperationCanceledException) { throw; }
  203. catch (Exception ex) { return Fail(ex.Message); }
  204. }
  205. }
  206. }