HouseMotor.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. using System;
  2. namespace AutoFocusTool.Serial
  3. {
  4. /// <summary>
  5. /// 单舱室马达+光源的语义化控制接口。封装 Protocol+SerialMotor,
  6. /// 给 UI/对焦逻辑直接调。所有动作同步阻塞到下位机回复。
  7. ///
  8. /// 重要:移动是开环+固定延时(motorDelay),下位机回复只代表"收到指令",
  9. /// 不代表机械停稳。每次移动后等 MotorDelayMs 再抓图,否则运动模糊。
  10. /// </summary>
  11. public class HouseMotor : IDisposable
  12. {
  13. private readonly SerialMotor _serial;
  14. /// <summary>电机到位延时(ms),移动后等待机械稳定。真机标定,默认 1500。</summary>
  15. public int MotorDelayMs { get; set; } = 1500;
  16. public string PortName => _serial.PortName;
  17. public bool IsOpen => _serial.IsOpen;
  18. public Action<string> Log
  19. {
  20. get => _serial.Log;
  21. set => _serial.Log = value;
  22. }
  23. public HouseMotor(string portName)
  24. {
  25. _serial = new SerialMotor(portName);
  26. }
  27. public bool Open() => _serial.Open();
  28. public void Close() => _serial.Close();
  29. /// <summary>握手,返回下位机自报的 houseSn(失败 -1)。</summary>
  30. public int ShakeHands()
  31. {
  32. var r = _serial.Send(Protocol.ShakeHands());
  33. return r == null ? -1 : Protocol.ParseShakeHands(r);
  34. }
  35. /// <summary>读本舱绑定的相机序列号 CCDSN(EEPROM,int)。失败 -1。</summary>
  36. public int ReadCCDSN()
  37. {
  38. var r = _serial.Send(Protocol.GetCCDSN());
  39. return r == null ? -1 : Protocol.ParseEepromInt(r);
  40. }
  41. /// <summary>读 EEPROM 灯光亮度(只读)。失败 -1。</summary>
  42. public int ReadLightBrightness()
  43. {
  44. var r = _serial.Send(Protocol.ReadLightBrightness());
  45. return r == null ? -1 : Protocol.ParseEepromInt(r);
  46. }
  47. /// <summary>读第 wellNum(1-16) 个well的水平电机位置脉冲(EEPROM)。失败 -1。</summary>
  48. public int ReadWellHorizontalPos(int wellNum)
  49. {
  50. var r = _serial.Send(Protocol.ReadWellHorizontalPos(wellNum));
  51. return r == null ? -1 : Protocol.ParseEepromInt(r);
  52. }
  53. /// <summary>
  54. /// 转动培养皿到第 wellNum(1-16) 个well对准相机:读EEPROM该well位置 → 水平电机绝对运动过去。
  55. /// 返回该well的水平脉冲位置,失败 -1。
  56. /// </summary>
  57. public int RotateToWell(int wellNum)
  58. {
  59. int pos = ReadWellHorizontalPos(wellNum);
  60. if (pos < 0) { Log?.Invoke($"读well{wellNum}位置失败"); return -1; }
  61. bool ok = HorizontalMoveTo(pos);
  62. Log?.Invoke($"转到well{wellNum} 位置脉冲={pos} {(ok ? "OK" : "失败")}");
  63. return ok ? pos : -1;
  64. }
  65. /// <summary>读第 wellNum(1-16) 个well的Z对焦零点脉冲(EEPROM)。失败 -1。</summary>
  66. public int ReadWellFocusZero(int wellNum)
  67. {
  68. var r = _serial.Send(Protocol.ReadWellFocusZero(wellNum));
  69. return r == null ? -1 : Protocol.ParseEepromInt(r);
  70. }
  71. /// <summary>读垂直电机扫描间隔脉冲(每层Z步距,EEPROM)。失败 -1。</summary>
  72. public int ReadScanStep()
  73. {
  74. var r = _serial.Send(Protocol.ReadScanStep());
  75. return r == null ? -1 : Protocol.ParseEepromInt(r);
  76. }
  77. // ── 光源 ──
  78. public bool OpenLED() => _serial.Send(Protocol.OpenLED()) != null;
  79. public bool CloseLED() => _serial.Send(Protocol.CloseLED()) != null;
  80. // ── 垂直电机(Z=对焦轴)──
  81. /// <summary>Z 复位回零,等待 MotorDelayMs。</summary>
  82. public bool VerticalReset()
  83. => _serial.Send(Protocol.VerticalReset(), MotorDelayMs) != null;
  84. /// <summary>Z 绝对运动到指定脉冲,等待 MotorDelayMs 稳定。</summary>
  85. public bool VerticalMoveTo(int pulse)
  86. => _serial.Send(Protocol.VerticalAbsolute(pulse), MotorDelayMs) != null;
  87. /// <summary>Z 绝对运动,自定义稳定延时(ms)。扫描小步移动用短延时提速。</summary>
  88. public bool VerticalMoveTo(int pulse, int delayMs)
  89. => _serial.Send(Protocol.VerticalAbsolute(pulse), delayMs) != null;
  90. /// <summary>Z 相对正转 pulse 步。</summary>
  91. public bool VerticalForward(int pulse)
  92. => _serial.Send(Protocol.VerticalForward(pulse), MotorDelayMs) != null;
  93. /// <summary>Z 相对反转 pulse 步。</summary>
  94. public bool VerticalBackward(int pulse)
  95. => _serial.Send(Protocol.VerticalBackward(pulse), MotorDelayMs) != null;
  96. /// <summary>读 Z 当前位置脉冲。失败 -1。</summary>
  97. public int ReadVerticalPosition()
  98. {
  99. var r = _serial.Send(Protocol.ReadVerticalMotor());
  100. return r == null ? -1 : Protocol.ParseMotorPosition(r);
  101. }
  102. // ── 水平电机(皿孔定位)──
  103. public bool HorizontalReset()
  104. => _serial.Send(Protocol.HorizontalReset(), MotorDelayMs) != null;
  105. public bool HorizontalMoveTo(int pulse)
  106. => _serial.Send(Protocol.HorizontalAbsolute(pulse), MotorDelayMs) != null;
  107. /// <summary>水平绝对运动,自定义稳定延时(ms)。扫描小步移动用短延时提速。</summary>
  108. public bool HorizontalMoveTo(int pulse, int delayMs)
  109. => _serial.Send(Protocol.HorizontalAbsolute(pulse), delayMs) != null;
  110. public bool HorizontalForward(int pulse)
  111. => _serial.Send(Protocol.HorizontalForward(pulse), MotorDelayMs) != null;
  112. public bool HorizontalBackward(int pulse)
  113. => _serial.Send(Protocol.HorizontalBackward(pulse), MotorDelayMs) != null;
  114. public int ReadHorizontalPosition()
  115. {
  116. var r = _serial.Send(Protocol.ReadHorizontalMotor());
  117. return r == null ? -1 : Protocol.ParseMotorPosition(r);
  118. }
  119. public void Dispose() => _serial.Dispose();
  120. }
  121. }