diff --git a/BenchMovementModule/HardwareDrive/GantryControlBase.cs b/BenchMovementModule/HardwareDrive/GantryControlBase.cs new file mode 100644 index 0000000..4240e31 --- /dev/null +++ b/BenchMovementModule/HardwareDrive/GantryControlBase.cs @@ -0,0 +1,164 @@ +using DeviceCommand.Base; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BenchMovementModule.HardwareDrive +{ + public abstract class GantryControlBase + { + protected readonly IModbusDevice _device; + protected readonly byte _slaveAddress; + + // 默认 PLC Modbus 映射地址 + protected const ushort ADDR_HM_X_ENABLE = 0xC100; // HM0: X轴使能 + protected const ushort ADDR_HM_Y_ENABLE = 0xC101; // HM1: Y轴使能 + protected const ushort ADDR_HM_Z_ENABLE = 0xC102; // HM2: Z轴使能 + + protected const ushort ADDR_M_X_START = 30; // M30: X轴指定位置启动 + protected const ushort ADDR_M_Y_START = 31; // M31: Y轴指定位置启动 + protected const ushort ADDR_M_Z_START = 35; // M35: Z轴指定位置启动 + + protected const ushort ADDR_M_ALL_STOP = 40; // M40: 全停 + protected const ushort ADDR_M_X_STOP = 41; // M41: X轴停止 + protected const ushort ADDR_M_Y_STOP = 42; // M42: Y轴停止 + protected const ushort ADDR_M_Z_STOP = 43; // M43: Z轴停止 + + protected const ushort ADDR_M_HOME = 100; // M100: 回原点触发 + + protected const ushort ADDR_HD_X_SPEED = 0xA166; // HD230: X轴速度 (32位) + protected const ushort ADDR_HD_Y_SPEED = 0xA17A; // HD250: Y轴速度 (32位) + protected const ushort ADDR_HD_Z_SPEED = 0xA170; // HD240: Z轴速度 (32位) + + protected const ushort ADDR_HD_X_TARGET = 0xA10C; // HD140: X轴指定位置 (32位) + protected const ushort ADDR_HD_Y_TARGET = 0xA120; // HD160: Y轴指定位置 (32位) + protected const ushort ADDR_HD_Z_TARGET = 0xA116; // HD150: Z轴指定位置 (32位) + + public bool IsConnected => _device?.IsConnected ?? false; + + protected GantryControlBase(IModbusDevice device, byte slaveAddress = 1) + { + _device = device ?? throw new ArgumentNullException(nameof(device)); + _slaveAddress = slaveAddress; + } + + public async Task ConnectAsync(CancellationToken ct = default) + { + return await _device.ConnectAsync(ct); + } + + public void Close() + { + _device.Close(); + } + + /// + /// 轴使能控制 + /// + public async Task SetAxisEnableAsync(int axis, bool enable, CancellationToken ct = default) + { + ushort address = axis switch + { + 1 => ADDR_HM_X_ENABLE, // X + 2 => ADDR_HM_Y_ENABLE, // Y + 3 => ADDR_HM_Z_ENABLE, // Z + _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)") + }; + + await _device.WriteSingleCoilAsync(_slaveAddress, address, enable, ct); + } + + /// + /// 左右移动(X轴) + /// + /// 目标绝对位置(脉冲数/单位值) + /// 运行速度 + public async Task MoveLeftRightAsync(int position, int speed, CancellationToken ct = default) + { + // 1. 写入速度与目标位置(32位数据,写入连续的2个保持寄存器) + await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_X_SPEED, Int32ToUshorts(speed), ct); + await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_X_TARGET, Int32ToUshorts(position), ct); + + // 2. 边缘触发启动信号 M30 + await TriggerCoilAsync(ADDR_M_X_START, ct); + } + + /// + /// 上下移动(Z轴) + /// + /// 目标绝对位置 + /// 运行速度 + public async Task MoveUpDownAsync(int position, int speed, CancellationToken ct = default) + { + // 1. 写入速度与目标位置(32位数据) + await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Z_SPEED, Int32ToUshorts(speed), ct); + await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Z_TARGET, Int32ToUshorts(position), ct); + + // 2. 边缘触发启动信号 M35 + await TriggerCoilAsync(ADDR_M_Z_START, ct); + } + + /// + /// 前后移动(Y轴 - 预留拓展) + /// + public async Task MoveFrontBackAsync(int position, int speed, CancellationToken ct = default) + { + await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Y_SPEED, Int32ToUshorts(speed), ct); + await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Y_TARGET, Int32ToUshorts(position), ct); + await TriggerCoilAsync(ADDR_M_Y_START, ct); + } + + /// + /// 全局回零 + /// + public async Task HomeAsync(CancellationToken ct = default) + { + await TriggerCoilAsync(ADDR_M_HOME, ct); + } + + /// + /// 轴停止 + /// + /// 1:X轴, 2:Y轴, 3:Z轴, 0:全停 + public async Task StopAsync(int axis = 0, CancellationToken ct = default) + { + ushort address = axis switch + { + 0 => ADDR_M_ALL_STOP, + 1 => ADDR_M_X_STOP, + 2 => ADDR_M_Y_STOP, + 3 => ADDR_M_Z_STOP, + _ => ADDR_M_ALL_STOP + }; + + await TriggerCoilAsync(address, ct); + } + + #region 内部工具方法 + + /// + /// 触发一个点动信号(置 1 后,延时 100ms 自动置 0) + /// + protected async Task TriggerCoilAsync(ushort address, CancellationToken ct = default) + { + await _device.WriteSingleCoilAsync(_slaveAddress, address, true, ct); + await Task.Delay(100, ct); // 给予 PLC 扫描周期足够的响应时间 + await _device.WriteSingleCoilAsync(_slaveAddress, address, false, ct); + } + + /// + /// 将 32 位整型数据转换为 Modbus 的 2 个 16 位无符号整数(高低字转换) + /// + protected ushort[] Int32ToUshorts(int value) + { + // 本处采用低字在前(CDAB),如果PLC高字在前(ABCD),可将返回数组顺序颠倒 + ushort lowWord = (ushort)(value & 0xFFFF); + ushort highWord = (ushort)((value >> 16) & 0xFFFF); + return new ushort[] { lowWord, highWord }; + } + + #endregion + } +} diff --git a/BenchMovementModule/HardwareDrive/GantryControlRtu.cs b/BenchMovementModule/HardwareDrive/GantryControlRtu.cs new file mode 100644 index 0000000..8ce5fa3 --- /dev/null +++ b/BenchMovementModule/HardwareDrive/GantryControlRtu.cs @@ -0,0 +1,28 @@ +using DeviceCommand.Base; +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BenchMovementModule.HardwareDrive +{ + public class GantryControlRtu : GantryControlBase + { + // 暴露出底层的 ModbusRtu 实例以便修改串口配置 + public ModbusRtu RtuDevice => (ModbusRtu)_device; + + public GantryControlRtu(string portName, int baudRate = 9600, byte slaveAddress = 1) + : base(new ModbusRtu(), slaveAddress) + { + RtuDevice.ConfigureDevice(portName, baudRate); + } + + public GantryControlRtu(string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity, byte slaveAddress = 1) + : base(new ModbusRtu(), slaveAddress) + { + RtuDevice.ConfigureDevice(portName, baudRate, dataBits, stopBits, parity); + } + } +} diff --git a/BenchMovementModule/HardwareDrive/GantryControlTcp.cs b/BenchMovementModule/HardwareDrive/GantryControlTcp.cs new file mode 100644 index 0000000..dae9bd9 --- /dev/null +++ b/BenchMovementModule/HardwareDrive/GantryControlTcp.cs @@ -0,0 +1,27 @@ +using DeviceCommand.Base; +using Model.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BenchMovementModule.HardwareDrive +{ + public class GantryControlTcp : GantryControlBase + { + // 暴露出底层的 ModbusTcp 实例以便修改网络配置 + public ModbusTcp TcpDevice => (ModbusTcp)_device; + + public GantryControlTcp(TcpConfig config, byte slaveAddress = 1) + : base(new ModbusTcp(config), slaveAddress) + { + } + + public GantryControlTcp(string ipAddress, int port = 502, byte slaveAddress = 1) + : base(new ModbusTcp(), slaveAddress) + { + TcpDevice.ConfigureDevice(ipAddress, port); + } + } +}