165 lines
6.6 KiB
C#
165 lines
6.6 KiB
C#
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<bool> ConnectAsync(CancellationToken ct = default)
|
||
{
|
||
return await _device.ConnectAsync(ct);
|
||
}
|
||
|
||
public void Close()
|
||
{
|
||
_device.Close();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轴使能控制
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 左右移动(X轴)
|
||
/// </summary>
|
||
/// <param name="position">目标绝对位置(脉冲数/单位值)</param>
|
||
/// <param name="speed">运行速度</param>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上下移动(Z轴)
|
||
/// </summary>
|
||
/// <param name="position">目标绝对位置</param>
|
||
/// <param name="speed">运行速度</param>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 前后移动(Y轴 - 预留拓展)
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全局回零
|
||
/// </summary>
|
||
public async Task HomeAsync(CancellationToken ct = default)
|
||
{
|
||
await TriggerCoilAsync(ADDR_M_HOME, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轴停止
|
||
/// </summary>
|
||
/// <param name="axis">1:X轴, 2:Y轴, 3:Z轴, 0:全停</param>
|
||
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 内部工具方法
|
||
|
||
/// <summary>
|
||
/// 触发一个点动信号(置 1 后,延时 100ms 自动置 0)
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将 32 位整型数据转换为 Modbus 的 2 个 16 位无符号整数(高低字转换)
|
||
/// </summary>
|
||
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
|
||
}
|
||
}
|