C00225155-02/C00225155/MegaRobo.C00225155/MegaRobo.C00225155.ControlD.../TemperatureControl/HighTemperatureMotorControl...

465 lines
19 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using MegaRobo.Connections;
using MegaRobo.Connections.Adapters;
using MegaRobo.Connections.Modbus;
using MegaRobo.Connections.Sockets.Tcp;
using MegaRobo.Contract;
using MegaRobo.ControlDevices.Abstractions;
using MegaRobo.Logger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using static MegaRobo.Connections.Modbus.ModbusParams;
namespace MegaRobo.C00225155.ControlDevices
{
/// <summary>
/// 高温震荡电机驱动器控制服务
/// </summary>
public class HighTemperatureMotorControlService : ConnectorBase<MegaTcpClient>
{
/// <summary>
/// 寄存器地址枚举十六进制转十进制Modbus 需传入十进制地址)
/// </summary>
private enum MotorRegisterAddress : ushort
{
= 0x00, // 0x00十进制0启停控制
= 0x02, // 0x02十进制2模式切换
= 0x06, // 0x06十进制6速度指令
= 0x4A, // 0x4A十进制74清除故障
= 0xE3, // 0xE3十进制227驱动器状态
= 0xE4 // 0xE4十进制228电机实际转速
}
/// <summary>
/// 写入数据枚举
/// </summary>
private enum MotorWriteData : ushort
{
= 0x0000, // 启停控制0=停止
= 0x0001, // 启停控制1=启动
= 0x00C4, // 工作模式0x00C4=速度模式
= 0x00D0 // 工作模式0x00D0=位置模式
}
/// <summary>
/// 驱动器状态位解析(对应 0xE3 寄存器的 bit 位)
/// </summary>
public class MotorState
{
public bool { get; set; } // bit00=停机1=启动
public bool { get; set; } // bit11=故障
public bool { get; set; } // bit21=故障
public bool { get; set; } // bit31=故障
public bool { get; set; }// bit41=故障
public bool { get; set; } // bit51=故障
public bool { get; set; } // bit61=故障
public bool { get; set; }// bit70=PC控制1=PLC控制
public string { get; set; } // 汇总故障信息
}
public override async Task<string> Initialize(ICoreService coreService, params object[] args)
{
CoreService = coreService;
try
{
base.CoreService = coreService;
if (args is [IPEndPoint remoteHost, ..])
{
base.ConnectorAdapter = new MegaTcpClient
{
Logger = coreService.Logger,
Name = base.Name
};
if (base.ConnectorAdapter != null)
{
base.ConnectorAdapter.DataReceived += ConnectorOnDataReceived;
}
ConnectionState = await base.ConnectorAdapter.ConnectAsync(remoteHost);
}
}
catch (Exception ex)
{
Logger.LogException(ex);
return await Task.FromResult(ex.Message);
}
return string.Empty;
}
private void ConnectorOnDataReceived(object sender, TcpMessage tcpMsg)
{
if (tcpMsg is null || tcpMsg.Data == null || tcpMsg.Data.Length == 0)
return;
string hexData = BitConverter.ToString(tcpMsg.Data).Replace("-", " ");
Logger.LogInformation($"接收到电机驱动器数据(十六进制):{hexData}");
}
public override Task<ConnectionState> ReconnectAsync()
{
return base.ReconnectAsync();
}
public override async Task<ConnectionState> CheckConnected()
{
var state = ConnectionState.None;
if (ConnectorAdapter is not null)
{
state = await ConnectorAdapter.CheckConnectedAsync();
}
ConnectionState = state;
return state;
}
/// <summary>
/// 电机启停控制
/// </summary>
/// <param name="id">设备从站号</param>
/// <param name="isStart"></param>
/// <returns></returns>
public async Task<bool> ControlMotorStartStop(byte id, bool isStart)
{
try
{
// 1. 确定写入数据:启动=0x0001停止=0x0000
MotorWriteData writeData = isStart ? MotorWriteData. : MotorWriteData.;
// 2. 调用 Modbus 写单个寄存器功能码06地址=启停控制0x00字节顺序AB高字节在前
var writeResult = ModbusRTU.WriteRegisterSingle(
deviceAdress: id, // 从站地址默认1
startAdress: (ushort)MotorRegisterAddress.,
lstData: (ushort)writeData,
byteOrder: ByteOrder.AB // 协议要求高字节在前
);
if (!writeResult.IsSuccessed)
{
Logger.LogError($"启停控制指令构建失败:{writeResult.Message}");
return false;
}
// 3. 发送指令并获取响应
var tcpMessage = await ConnectorAdapter.WriteAndGetReplyAsync(writeResult.Respond, TimeSpan.FromSeconds(5));
if (tcpMessage == null || tcpMessage.Data == null)
{
Logger.LogError("启停控制未收到响应");
return false;
}
// 4. 验证响应(协议要求写成功后返回原报文)
bool isResponseMatch = CompareBytes(writeResult.Respond, tcpMessage.Data);
if (!isResponseMatch)
{
Logger.LogError($"启停控制响应不匹配:发送={BitConverter.ToString(writeResult.Respond)}, 接收={BitConverter.ToString(tcpMessage.Data)}");
return false;
}
Logger.LogInformation($"{(isStart ? "" : "")}电机成功");
return true;
}
catch (Exception ex)
{
Logger.LogException(ex, null, LogEvent.Error, null, LogLevel.Error, "HighTemperatureMotorControlService", "ControlMotorStartStop", 150, false);
return false;
}
}
/// <summary>
/// 设置电机速度(速度模式下)
/// </summary>
/// <param name="id">设备从站号</param>
/// <param name="targetSpeed">目标速度0-3000 RPM协议上限3000</param>
public async Task<bool> SetMotorSpeed(byte id, int targetSpeed)
{
try
{
// 1. 参数校验:速度范围 0-3000 RPM协议规定
if (targetSpeed < 0 || targetSpeed > 3000)
{
Logger.LogError($"速度值超出范围0-3000 RPM{targetSpeed}");
return false;
}
// 2. 切换到速度模式(必须先设置模式,再写速度)
bool modeSuccess = await SwitchToSpeedMode(id);
if (!modeSuccess)
{
Logger.LogError("切换速度模式失败,无法设置速度");
return false;
}
// 3. 计算速度指令值:写入值 = (目标速度 / 3000) * 8192协议公式
ushort speedCommand = (ushort)Math.Round((targetSpeed / 3000.0) * 8192);
Logger.LogInformation($"目标速度={targetSpeed} RPM计算后指令值=0x{speedCommand:X4}");
// 4. 写速度指令到寄存器 0x06功能码06
var writeResult = ModbusRTU.WriteRegisterSingle(
deviceAdress: id,
startAdress: (ushort)MotorRegisterAddress.,
lstData: speedCommand,
byteOrder: ByteOrder.AB // 高字节在前
);
if (!writeResult.IsSuccessed)
{
Logger.LogError($"速度指令构建失败:{writeResult.Message}");
return false;
}
// 5. 发送指令并验证响应
var tcpMessage = await ConnectorAdapter.WriteAndGetReplyAsync(writeResult.Respond, TimeSpan.FromSeconds(5));
if (tcpMessage == null || tcpMessage.Data == null)
{
Logger.LogError("设置速度未收到响应");
return false;
}
// 6. 验证响应(写成功返回原报文)
bool isResponseMatch = CompareBytes(writeResult.Respond, tcpMessage.Data);
if (!isResponseMatch)
{
Logger.LogError($"速度设置响应不匹配:发送={BitConverter.ToString(writeResult.Respond)}, 接收={BitConverter.ToString(tcpMessage.Data)}");
return false;
}
Logger.LogInformation($"设置电机速度成功:{targetSpeed} RPM指令值=0x{speedCommand:X4}");
return true;
}
catch (Exception ex)
{
Logger.LogException(ex, null, LogEvent.Error, null, LogLevel.Error, "HighTemperatureMotorControlService", "SetMotorSpeed", 150, false);
return false;
}
}
/// <summary>
/// 获取电机驱动器状态(运行状态+故障信息)
/// </summary>
/// <param name="id">设备从站号</param>
public async Task<MotorState> GetMotorState(byte id)
{
try
{
// 1. 构建读状态指令地址0xE3十进制227读1个寄存器状态是16位
var readResult = ModbusRTU.GetReadMessage(
slaveStation: id,
readType: ModbusReadCodes.READ_HOLDING_REGISTERS, // 功能码03
startAdr: (ushort)MotorRegisterAddress.,
length: 1 // 状态寄存器是1个16位寄存器长度=1
);
if (!readResult.IsSuccessed)
{
Logger.LogError($"读状态指令构建失败:{readResult.Message}");
return new MotorState { = "指令构建失败" };
}
// 2. 发送指令并获取响应
var tcpMessage = await ConnectorAdapter.WriteAndGetReplyAsync(readResult.Respond, TimeSpan.FromSeconds(5));
if (tcpMessage == null || tcpMessage.Data == null)
{
Logger.LogError("读状态未收到响应");
return new MotorState { = "未收到响应" };
}
// 3. 解析响应16位状态字字节顺序AB
var parseResult = ModbusRTU.ReadRegisterUShort(tcpMessage.Data, ByteOrder.AB);
if (!parseResult.IsSuccessed)
{
Logger.LogError($"状态解析失败:{parseResult.Message}");
return new MotorState { = parseResult.Message };
}
// 4. 解析状态字的各个bit位协议表5-22
ushort statusWord = parseResult.Respond[0];
var motorState = new MotorState
{
= (statusWord & (1 << 0)) != 0, // bit0
= (statusWord & (1 << 1)) != 0, // bit1
= (statusWord & (1 << 2)) != 0, // bit2
= (statusWord & (1 << 3)) != 0, // bit3
= (statusWord & (1 << 4)) != 0,// bit4
= (statusWord & (1 << 5)) != 0, // bit5
= (statusWord & (1 << 6)) != 0, // bit6
= (statusWord & (1 << 7)) != 0 // bit7
};
// 5. 汇总故障描述
var errors = new List<string>();
if (motorState.) errors.Add("过流");
if (motorState.) errors.Add("过压");
if (motorState.) errors.Add("编码器故障");
if (motorState.) errors.Add("位置偏差过大");
if (motorState.) errors.Add("欠压");
if (motorState.) errors.Add("过载");
motorState. = errors.Count > 0
? $"故障:{string.Join("", errors)}"
: "无故障";
Logger.LogInformation($"电机状态:运行状态={(motorState.运行状态 ? "" : "")}{motorState.故障描述}");
return motorState;
}
catch (Exception ex)
{
Logger.LogException(ex, null, LogEvent.Error, null, LogLevel.Error, "HighTemperatureMotorControlService", "GetMotorState", 150, false);
return new MotorState { = $"异常:{ex.Message}" };
}
}
/// <summary>
/// 获取电机实际转速
/// </summary>
/// <param name="id">设备从站号</param>
public async Task<int> GetMotorActualSpeed(byte id)
{
try
{
// 1. 构建读转速指令地址0xE4十进制228读1个寄存器
var readResult = ModbusRTU.GetReadMessage(
slaveStation: id,
readType: ModbusReadCodes.READ_HOLDING_REGISTERS,
startAdr: (ushort)MotorRegisterAddress.,
length: 1
);
if (!readResult.IsSuccessed)
{
Logger.LogError($"读转速指令构建失败:{readResult.Message}");
return -1;
}
// 2. 发送指令并获取响应
var tcpMessage = await ConnectorAdapter.WriteAndGetReplyAsync(readResult.Respond, TimeSpan.FromSeconds(5));
if (tcpMessage == null || tcpMessage.Data == null)
{
Logger.LogError("读转速未收到响应");
return -1;
}
// 3. 解析转速16位无符号数直接表示RPM
var parseResult = ModbusRTU.ReadRegisterUShort(tcpMessage.Data, ByteOrder.AB);
if (!parseResult.IsSuccessed)
{
Logger.LogError($"转速解析失败:{parseResult.Message}");
return -1;
}
int actualSpeed = parseResult.Respond[0];
Logger.LogInformation($"电机实际转速:{actualSpeed} RPM");
return actualSpeed;
}
catch (Exception ex)
{
Logger.LogException(ex, null, LogEvent.Error, null, LogLevel.Error, "HighTemperatureMotorControlService", "GetMotorActualSpeed", 150, false);
return -1;
}
}
/// <summary>
/// 清除电机故障
/// </summary>
/// <param name="id">设备从站号</param>
/// <returns></returns>
public async Task<bool> ClearMotorFault(byte id)
{
try
{
// 协议规定写入任意值到0x4A即可清除故障此处写0x0000
var writeResult = ModbusRTU.WriteRegisterSingle(
deviceAdress: id,
startAdress: (ushort)MotorRegisterAddress.,
lstData: (ushort)0x0000,
byteOrder: ByteOrder.AB
);
if (!writeResult.IsSuccessed)
{
Logger.LogError($"清除故障指令构建失败:{writeResult.Message}");
return false;
}
var tcpMessage = await ConnectorAdapter.WriteAndGetReplyAsync(writeResult.Respond, TimeSpan.FromSeconds(5));
if (tcpMessage == null || tcpMessage.Data == null)
{
Logger.LogError("清除故障未收到响应");
return false;
}
bool isResponseMatch = CompareBytes(writeResult.Respond, tcpMessage.Data);
if (isResponseMatch)
{
Logger.LogInformation("清除电机故障成功");
return true;
}
else
{
Logger.LogError("清除故障响应不匹配");
return false;
}
}
catch (Exception ex)
{
Logger.LogException(ex, null, LogEvent.Error, null, LogLevel.Error, "HighTemperatureMotorControlService", "ClearMotorFault", 150, false);
return false;
}
}
/// <summary>
/// 切换到速度模式内部调用设置模式寄存器0x02为0x00C4
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private async Task<bool> SwitchToSpeedMode(byte id)
{
var writeResult = ModbusRTU.WriteRegisterSingle(
deviceAdress: id,
startAdress: (ushort)MotorRegisterAddress.,
lstData: (ushort)MotorWriteData.,
byteOrder: ByteOrder.AB
);
if (!writeResult.IsSuccessed)
{
Logger.LogError($"切换速度模式指令构建失败:{writeResult.Message}");
return false;
}
var tcpMessage = await ConnectorAdapter.WriteAndGetReplyAsync(writeResult.Respond, TimeSpan.FromSeconds(5));
if (tcpMessage == null || tcpMessage.Data == null)
{
Logger.LogError("切换速度模式未收到响应");
return false;
}
bool isMatch = CompareBytes(writeResult.Respond, tcpMessage.Data);
if (isMatch)
{
Logger.LogInformation("切换到速度模式成功");
return true;
}
else
{
Logger.LogError("切换速度模式响应不匹配");
return false;
}
}
/// <summary>
/// 比较两个字节数组是否相等(验证响应报文)
/// </summary>
private bool CompareBytes(byte[] source, byte[] target)
{
if (source.Length != target.Length) return false;
for (int i = 0; i < source.Length; i++)
{
if (source[i] != target[i]) return false;
}
return true;
}
}
}