MotionMovePlugins.cs 10 KB

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