using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Timers;
using HslCommunication.ModBus;
using HslCommunication;
using HslCommunication.BasicFramework;
using System.Configuration;
namespace PLCLinker
{
///
/// PLC通信类
///
public class PLCLinker : IEquipments
{
public IEquipments ins { get; set; }
///
/// PLC 连接状态flag
///
private Boolean isConnection = false;
///
/// 激光数据记录状态flag
///
private bool isRecorded = false;
///
/// 读写异常状态flag
///
private bool exceptionBreak = false;
///
/// 系统关闭flag
///
private bool isClosing = false;
///
/// 从PLC读到的字符串
///
private static string json = "";
///
/// 将写入PLC的字符串
///
private string json2 = "";
///
/// 从plc获得结构化数据
///
private PLCMessage plcMsg;
///
/// 定时器
///
System.Timers.Timer timer;
///
/// 读PLC初始地址
///
private int startAddr = 0;
///
/// 读PLC地址长度
///
private int addrLength = 110;
///
/// plc重连标记位
///
private int linkCount = 0;
///
/// 无法获取配置文件时使用的PLC刷新频率
///
private const short PLC_TIME_SCALE = 200;
///
/// PLC的IP地址
///
private string ipString;
///
/// PLC的端口号
///
private int port;
///
/// 工作站号
///
private byte station;
///
/// 取车启动机械手PLC地址
///
private int fetching_startRobot_address;
///
/// 停车启动机械手PLC地址
///
private int parking_startRobot_address;
///
/// 停车位ID对应PLC地址
///
private int parkingSpaceID_address;
///
/// 停车激光数据入口
///
private int parkingLaserCenterX_address;
///
/// 启动激光地址
///
private int laser_start_address;
///
/// 取车完成地址
///
private int fetch_completed_address;
///
/// 取车完成已获得标志地址
///
private int fetch_completed_acknowledge_address;
///
/// 取至缓冲区地址
///
private int fetch_to_address;
///
/// 前轮距转存地址
///
private int frontWheelbase_address;
///
/// 后轮距转存地址
///
private int rearWheelbase_address;
///
/// 停车完成地址
///
private int park_completed_address;
///
/// 停车完成已获得地址
///
private int park_completed_acknowledge_address;
///
/// 激光重测总数
///
private int LASER_RESCAN_COUNT;
///
/// 激光心跳检测窗口阈值
///
private int LASER_HEARTBEAT_PERIOD;
///
/// PLC刷新频率,来自于配置文件
///
private int PLC_refresh_interval;
///
/// 激光管理list
///
private List laserMgmtList = new List();
///
/// 机械手处理单元实例
///
private RobotProcessUnit rpu1;
///
/// PLC列表中被压缩的地址块
///
private List decompressIndex;
///
/// plc构造函数
///
public PLCLinker()
{
try
{
LASER_RESCAN_COUNT = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_rescan_count"));
LASER_HEARTBEAT_PERIOD = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_countdown"));
PLC_refresh_interval = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_refresh_interval"));
parking_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parking_startRobot_address"));
parkingLaserCenterX_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingLaserCenterX_address"));
parkingSpaceID_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingSpaceID_address"));
park_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_address"));
park_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_acknowledge_address"));
fetching_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetching_startRobot_address"));
fetch_to_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_to_address"));
fetch_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_address"));
fetch_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_acknowledge_address"));
frontWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("frontWheelbase_address"));
rearWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("rearWheelbase_address"));
laser_start_address = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_start_address"));
plcMsg = new PLCMessage();
rpu1 = new RobotProcessUnit(1, parking_startRobot_address, parkingLaserCenterX_address, parkingSpaceID_address, park_completed_address, park_completed_acknowledge_address, fetching_startRobot_address, fetch_to_address, fetch_completed_address, fetch_completed_acknowledge_address, frontWheelbase_address, rearWheelbase_address);
//激光管理
for (int i = 1; i < 20; i++)
{
try
{
if (ConfigurationManager.AppSettings.AllKeys.Contains("laser" + i + "_status_address"))
{
string laser = ConfigurationManager.AppSettings.Get("laser" + i + "_status_address");
int laser_status_address = Int32.Parse(laser);
LaserProcessUnit lpu = new LaserProcessUnit(this, i, laser_start_address, laser_status_address, LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD);
laserMgmtList.Add(lpu);
plcMsg.laserMsgList.Add(lpu.laserMsg);
}
else { break; }
}
catch (Exception) { }
}
//定义plc被压缩的地址段
decompressIndex = new List();
//25-27
for (int i = 0; i < 3; i++)
{
decompressIndex.Add((25 + i).ToString());
}
//48-53
for (int i = 0; i < 6; i++)
{
decompressIndex.Add((48 + i).ToString());
}
//70-82
for (int i = 0; i < 13; i++)
{
decompressIndex.Add((70 + i).ToString());
}
}
catch (Exception)
{
Console.WriteLine("PLC相关配置文件异常");
}
}
//**************************************** PLC读写相关方法 **************************************
///
/// PLC连接对象
///
private ModBusTcpClient busTcpClient
{
get;
set;
}
///
/// 写入字符串到json2
///
/// 将写入的字符串
private void WriteMessage(string message)
{
isRecorded = true;
//json2 = "[{\"Adress\":\"1\",\"Value\":\"0043\"},{\"Adress\":\"2\",\"Value\":\"0043\"}]";
json2 = message;
}
///
/// 采集数据显示转json
///
/// 将被转为json字符串的字符串
private static void DisplayString_ToJson(string str)
{
List return_Value = new List();
if (!string.IsNullOrEmpty(str))
{
ArrayList array = GetSeparateSubString(str, 4);
int Read_Address = 0;//0地址
return_Value.Clear();
foreach (string arr in array)
{
PLCNode rv = new PLCNode();
//Console.WriteLine("地址:" + Read_Address + ": " + arr);
rv.Address = Read_Address.ToString();
rv.Value = Int32.Parse(arr, System.Globalization.NumberStyles.HexNumber).ToString();//plc数据16进制?
return_Value.Add(rv);
Read_Address++;
}
}
json = JsonHelper.SerializeObject(return_Value);//序列化
//List prv = JsonHelper.DeserializeJsonToList(json);
//Console.WriteLine(json);
}
///
/// 截取字符串到字符串数组
///
/// 输入字符串
/// 最大字符个数
///
private static ArrayList GetSeparateSubString(string txtString, int charNumber)
{
ArrayList arrList = new ArrayList();
string tempStr = txtString;
for (int i = 0; i < tempStr.Length; i += charNumber)
{
if ((tempStr.Length - i) > charNumber)
{
arrList.Add(tempStr.Substring(i, charNumber));
}
else
{
arrList.Add(tempStr.Substring(i));
}
}
return arrList;
}
///
/// 初始化定时器
///
private void InitTimer()
{
try
{
timer = new System.Timers.Timer(PLC_refresh_interval);
}
catch (Exception)
{
timer = new System.Timers.Timer(PLC_TIME_SCALE);
}
timer.AutoReset = true;
timer.Enabled = true;
timer.Elapsed += new ElapsedEventHandler(TimerUp);
}
///
/// 实时采集
///
/// 发送者对象,系统提供
/// 定时数据
private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
if (isConnection)
{
//从哪个地址开始,读取长度
PLC_Read((ushort)startAddr, (ushort)addrLength);
//LaserMonitor();
}
else
{
//plc掉线则将系统暂停
//EntityForCore.ins.globalStatus = false;
if (linkCount-- >= 0)
{
Task.Factory.StartNew(() =>
{
MyTimer mt = new MyTimer();
mt.StartTiming();
while (!isClosing)
{
mt.EndTiming();
int count;
if (mt.IsLonger(1, 1, true, out count))
{
////断线后只显示一次
//UILogServer.ins.warn("尝试重连PLC");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "PLC重连中,请稍候。。。。。。");
}
LinkStart();
Thread.Sleep(10000);
if (isConnection)
{
//EntityForCore.ins.globalStatus = true;
linkCount = 0;
break;
}
}
});
linkCount = -1;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
///
/// 从PLC读取数据
///
/// 地址
/// 值
private void PLC_Read(ushort address, ushort length)
{
try
{
OperateResult read = busTcpClient.ReadRegister(address, length);
if (read.IsSuccess)
{
string returned_value = SoftBasic.ByteToHexString(read.Content);
DisplayString_ToJson(returned_value);
}
else
{
if (!exceptionBreak)
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
isConnection = false;
exceptionBreak = true;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
///
/// 写入Json字符串到PLC
///
/// json格式字符串
private void WriteJson(string json)
{
try
{
if (!string.IsNullOrEmpty(json))
{
List PLC_Value = JsonHelper.DeserializeJsonToList(json);
foreach (var item in PLC_Value)
{
//WriteResultRender(busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value)), item.Address);
busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value));
Thread.Sleep(20);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
///
/// 判断写入是否成功
///
/// 判断结果
private static void WriteResultRender(OperateResult result)
{
if (result.IsSuccess)
{
Console.WriteLine("写入成功");
}
else
{
Console.WriteLine("写入失败");
}
}
///
/// 地址-值写入plc
///
/// 地址
/// 值
private void SendtoPLC(string addr, string value)
{
PLCNode wrv = new PLCNode();
wrv.Address = addr;
wrv.Value = value;
json2 = "[" + JsonHelper.SerializeObject(wrv) + "]";
WriteMessage(json2);
if (isConnection && isRecorded)
{
WriteJson(json2);
isRecorded = false;
}
}
/// 启动与plc的连接
private void LinkStart()
{
if (busTcpClient != null)
{
busTcpClient.ConnectClose();
}
busTcpClient = new ModBusTcpClient(ipString, port, station);
try
{
if (busTcpClient != null)
{
OperateResult connect = busTcpClient.ConnectServer();
if (connect.IsSuccess)
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCOnline);
//UILogServer.ins.info("PLC连接成功");
isConnection = true;
linkCount = 0;
}
else
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCOffline);
//UILogServer.ins.error("PLC连接失败,重试");
isConnection = false;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
InitTimer();//启动计时器
}
///
/// 将plc地址块完全解压
///
/// 原始PLC数据列表
/// 压缩数据段
/// 解压后的数据列表
private List ListDecompression(List plcList, List decompressIndex)
{
List temp = new List();
List decomPlcList = new List();
if (plcList != null && addrLength > 100)
{
try
{
for (int i = 0; i < plcList.Count; i++)
{
if (!decompressIndex.Contains(plcList[i].Address))
{
temp.Add(plcList[i].Value);
}
//定位三个被压缩区域
else
{
//默认LSB优先
int value = Int32.Parse(plcList[i].Value);
int count = 16;
while (count-- > 0)
{
temp.Add((value & 0x01).ToString());
value = value >> 1;
}
}
}
}
catch (Exception) { }
}
for (int i = 0; i < temp.Count; i++)
{
decomPlcList.Add(new PLCNode(i.ToString(), temp[i]));
}
return decomPlcList;
}
//************************************ 雷达相关方法 **************************************
///
/// 根据PLC处获得的关于激光的数据,做出相应的操作
///
private void LaserMonitor()
{
try
{
if (plcMsg.originalPlcList != null && plcMsg.originalPlcList.Count != 0)
{
foreach (LaserProcessUnit lds in laserMgmtList)
{
foreach (PLCNode p in plcMsg.originalPlcList)
{
int addr = Int32.Parse(p.Address);
int value = Int32.Parse(p.Value);
lds.LaserStatusChecking(addr, value);
}
lds.LaserRecord(plcMsg.originalPlcList);
}
}
else
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
return;
}
Thread.Sleep(200);
}
catch (Exception)
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
return;
}
}
///
/// 实时更新激光状态值
///
private void UpdateLaserStatus()
{
try
{
lock (plcMsg)
{
if (plcMsg.originalPlcList != null && plcMsg.originalPlcList.Count != 0)
{
foreach (LaserProcessUnit lds in laserMgmtList)
{
foreach (PLCNode p in plcMsg.originalPlcList)
{
int addr = Int32.Parse(p.Address);
int value = Int32.Parse(p.Value);
lds.UpdateLaserStatus(addr, value);
}
}
}
else
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
return;
}
}
}
catch (Exception)
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
return;
}
}
///
/// 等待激光空闲状态/心跳状态
///
/// 激光处理单元
private void WaitForLaserReady(LaserProcessUnit lpuTemp)
{
bool jumpOut = false;
MyTimer mt = new MyTimer();
mt.StartTiming();
lock (lpuTemp)
{
while (!jumpOut)
{
Thread.Sleep(1000);
if (plcMsg != null && plcMsg.originalPlcList.Count > lpuTemp.laser_status_address)
{
foreach (PLCNode node in plcMsg.originalPlcList)
{
//判断激光空闲状态
lock (lpuTemp.laserMsg)
{
if (node.Address.Equals(lpuTemp.laser_status_address.ToString()) && (node.Value.Equals("254") || node.Value.Equals("255")) && !lpuTemp.laserMsg.occupied)
{
lpuTemp.laserMsg.occupied = true;
jumpOut = true;
//UILogServer.ins.log("获取摆扫激光空闲状态,准备启动激光");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "获取摆扫激光空闲状态,准备启动激光");
Console.WriteLine("获取摆扫激光空闲状态,准备启动激光");
break;
}
}
}
}
mt.EndTiming();
int activationCount = 0;
if (mt.IsLonger(15, 1, false, out activationCount))
{
if (activationCount == 1)
{
//UILogServer.ins.info("启动前暂未获取摆扫激光空闲状态,继续等待");
Console.WriteLine("启动前暂未获取摆扫激光空闲状态,继续等待");
}
if (MyTimer.restart && !mt.rolledBack)
{
mt.rolledBack = true;
//UILogServer.ins.error("启动前超时未能获取摆扫空闲状态,请检查设备");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "启动前超时未能获取摆扫空闲状态,请检查设备");
Console.WriteLine("启动前超时未能获取摆扫空闲状态,请检查设备");
}
Thread.Sleep(100);
}
}
}
}
//***************公有方法****************
///
/// 获取plc数据与激光数据
///
/// 返回plc消息实例
public AbstractMessage GetMessage()
{
try
{
if (json != "")
{
plcMsg.originalPlcList = JsonHelper.DeserializeJsonToList(json);
}
if (decompressIndex != null && decompressIndex.Count != 0)
{
plcMsg.extendedPlcList = ListDecompression(plcMsg.originalPlcList, decompressIndex);
}
return (PLCMessage)plcMsg.Clone();
}
catch (Exception)
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
return new PLCMessage();
}
}
///
/// 传入信息写入plc
///
/// plc消息则传入plc,控制消息则根据指令编号分别处理
public void SetMessage(AbstractMessage message)
{
if (message.GetType().Equals(typeof(PLCMessage)))
{
PLCMessage ps = (PLCMessage)message;
for (int i = 0; i < ps.originalPlcList.Count; i++)
{
SendtoPLC(ps.originalPlcList[i].Address, ps.originalPlcList[i].Value);
}
}
else if (message.GetType().Equals(typeof(PLCNode)))
{
PLCNode pv = (PLCNode)message;
SendtoPLC(pv.Address, pv.Value);
}
else if (message.GetType().Equals(typeof(ControlMessage)))
{
ControlMessage cm = (ControlMessage)message;
if (cm != null && cm.status != 0)
{
switch (cm.status)
{
//停车startLaser--park_command_address
case 1:
//start laser scanning for parking
LaserProcessUnit lpuTemp = null;
Task.Factory.StartNew(() =>
{
string laser_start_addr = "";
foreach (LaserProcessUnit lpu in laserMgmtList)
{
if (cm.laserID == lpu.id)
{
lpuTemp = lpu;
laser_start_addr = lpu.laser_start_address.ToString();
break;
}
}
if (laser_start_addr == "")
return;
lock (lpuTemp)
{
WaitForLaserReady(lpuTemp);
SendtoPLC(laser_start_addr, "0");
lpuTemp.laserMsg.licenseNum = cm.LicenseNum;
Thread.Sleep(300);
SendtoPLC(laser_start_addr, "1");
Thread.Sleep(100);
//SendtoPLC("1", "1");//停车指令置1
//Log.WriteLog(LogType.NOT_DATABASE, "已发送激光" + lpuTemp.id + "启动指令");
Console.WriteLine("已发送激光" + lpuTemp.id + "启动指令");
//UILogServer.ins.info("已发送激光" + lpuTemp.id + "启动指令");
}
});
//Console.WriteLine("扫摆激光启动");
break;
//停车激光的6个数据,停车机械手,车位信息4个
case 2:
if (cm.RobotID == 1)
{
//停车指令置1
SendtoPLC("1", "1");
//停车启动机械手
SendtoPLC(rpu1.parking_startRobot_address.ToString(), "1");
//自动或手动输入激光雷达数据
SendtoPLC(rpu1.parking_laserCenterX_address.ToString(), cm.centerX);
SendtoPLC((rpu1.parking_laserCenterX_address + 1).ToString(), cm.centerY);
SendtoPLC((rpu1.parking_laserCenterX_address + 2).ToString(), cm.angleA);
//车位信息
SendtoPLC(rpu1.parkingSpaceID_address.ToString(), cm.parkingSpaceID);
SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), cm.parkingSpaceX);
SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), cm.parkingSpaceY);
SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), cm.parkingSpaceZ);
}
break;
//停车完成归零--park_completed_address
case 3:
if (cm.RobotID == 1)
{
//SendtoPLC(rpu1.park_completed_address.ToString(), "0");//停车完成复位
SendtoPLC(rpu1.park_completed_acknowledge_address.ToString(), "0");
SendtoPLC("1", "0");//停车指令置0
//Console.WriteLine("停车完成");
}
break;
//取车机械手,车位信息4个
case 4:
if (cm.RobotID == 1 && cm.fetchPosition != 0)
{
//前后轮轮距
SendtoPLC(rpu1.frontWheelbase.ToString(), cm.frontWheelbase.ToString());
SendtoPLC(rpu1.rearWheelbase.ToString(), cm.rearWheelbase.ToString());
//取至区域
//SendtoPLC(rpu1.fetch_to_address.ToString(), pm.fetchPosition.ToString());
SendtoPLC(rpu1.fetch_to_address.ToString(), cm.parkingSpaceX);
//车位信息
SendtoPLC(rpu1.parkingSpaceID_address.ToString(), cm.parkingSpaceID);
SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), cm.parkingSpaceX);
SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), cm.parkingSpaceY);
SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), cm.parkingSpaceZ);
SendtoPLC(rpu1.fetching_startRobot_address.ToString(), "1");
}
break;
case 5:
if (cm.RobotID == 1)
{
//取车完成复位
SendtoPLC(rpu1.fetch_completed_acknowledge_address.ToString(), "0");
SendtoPLC(rpu1.fetch_to_address.ToString(), "0");
}
break;
default:
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "输入PLC数据异常");
break;
}
}
}
else
{
//AsyncCmdServer.ins.send(AsyncCmdType.PLCWriteException);
}
}
///
/// 开启激光线程与模拟plc自动重置子线程
///
public void Start()
{
ins = this as IEquipments;
exceptionBreak = false; linkCount = 0;
try
{
ipString = ConfigurationManager.AppSettings.Get("PLC_ip_address");
port = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_port"));
station = (byte)Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_station"));
startAddr = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_start_address"));
addrLength = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_address_length"));
}
catch (Exception) {
//UILogServer.ins.error("PLC配置文件异常"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "PLC配置文件异常");
Console.WriteLine("PLC配置文件异常");
}
for (int i = startAddr; i < startAddr + addrLength; i++)
{
plcMsg.originalPlcList.Add(new PLCNode(i.ToString(), "0"));
}
LinkStart();
Task.Factory.StartNew(() =>
{
while (!isClosing)
{
LaserMonitor();
}
});
Task.Factory.StartNew(() =>
{
while (!isClosing)
{
UpdateLaserStatus();
}
});
//模拟plc与激光自动操作
Task.Factory.StartNew(() =>
{
laserAnim();
});
Task.Factory.StartNew(() =>
{
wheelbaseAnim();
});
Task.Factory.StartNew(() =>
{
autoCycling();
});
}
///
/// 系统停止
///
public void Stop()
{
exceptionBreak = false; isClosing = true;
busTcpClient.ConnectClose();//stop释放资源
//throw new NotImplementedException();
}
///
/// 模拟摆扫激光
///
private void laserAnim()
{
bool laserWorking = false;
while (!isClosing)
{
if (plcMsg.originalPlcList != null)
{
//模拟plc与激光操作
foreach (PLCNode p in plcMsg.originalPlcList)
{
int addr = Int32.Parse(p.Address);
int value = Int32.Parse(p.Value);
//模拟摆扫激光
if (laserMgmtList.Count != 0)
{
if (addr == laser_start_address)
{
//心跳
if (value == 0)
{
laserWorking = false;
SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "254");
Thread.Sleep(500);
SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "255");
Thread.Sleep(500);
}
//模拟测量
else
{
if (!laserWorking)
{
SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "1");
Thread.Sleep(300);
SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "2");
Thread.Sleep(500);
SendtoPLC((laserMgmtList[0].laser_status_address + 1).ToString(), (new Random(DateTime.Now.Millisecond).Next(4000, 7000)).ToString());
SendtoPLC((laserMgmtList[0].laser_status_address + 2).ToString(), (new Random(DateTime.Now.Millisecond).Next(4000, 7000)).ToString());
SendtoPLC((laserMgmtList[0].laser_status_address + 3).ToString(), (new Random(DateTime.Now.Millisecond).Next(90, 150)).ToString());
SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "3");
Thread.Sleep(500);
}
laserWorking = true;
}
}
}
}
}
Thread.Sleep(100);
}
}
///
/// 模拟轮距雷达
///
private void wheelbaseAnim()
{
bool working = false;
while (!isClosing)
{
if (plcMsg.originalPlcList != null)
{
//模拟plc与激光操作
foreach (PLCNode p in plcMsg.originalPlcList)
{
int addr = Int32.Parse(p.Address);
int value = Int32.Parse(p.Value);
//模拟轮距激光
if (addr == parking_startRobot_address)
{
if (value == 1)
{
if (!working)
{
working = true;
Thread.Sleep(500);
SendtoPLC(frontWheelbase_address.ToString(), (new Random(DateTime.Now.Millisecond).Next(100, 300)).ToString());
Thread.Sleep(1);
SendtoPLC(rearWheelbase_address.ToString(), (new Random(DateTime.Now.Millisecond).Next(100, 300)).ToString());
SendtoPLC("87", "3");
Thread.Sleep(500);
}
}
else
{
working = false;
SendtoPLC("87", "254");
Thread.Sleep(500);
SendtoPLC("87", "255");
Thread.Sleep(500);
}
}
}
}
Thread.Sleep(200);
}
}
///
/// 模拟PLC操作
///
private void autoCycling()
{
while (!isClosing)
{
if (plcMsg.originalPlcList != null)
{
//模拟plc与激光操作
foreach (PLCNode p in plcMsg.originalPlcList)
{
int addr = Int32.Parse(p.Address);
int value = Int32.Parse(p.Value);
//停取车复位
if (addr == park_completed_acknowledge_address && value == 0)
{
Thread.Sleep(1000);
SendtoPLC(park_completed_address.ToString(), "0");
SendtoPLC(park_completed_acknowledge_address.ToString(), "1");
}
if (addr == fetch_completed_acknowledge_address && value == 0)
{
Thread.Sleep(1000);
SendtoPLC(fetch_completed_address.ToString(), "0");
SendtoPLC(fetch_completed_acknowledge_address.ToString(), "1");
}
//停车完成
if (addr == parking_startRobot_address && value == 1)
{
Thread.Sleep(2000);
SendtoPLC(park_completed_address.ToString(), "1");
SendtoPLC(addr.ToString(), "0");
}
//取车完成
if (addr == fetching_startRobot_address && value == 1)
{
Thread.Sleep(2000);
SendtoPLC(fetch_completed_address.ToString(), "1");
SendtoPLC(addr.ToString(), "0");
}
}
}
Thread.Sleep(200);
}
}
}
///
/// 激光数据记录与处理类
///
class LaserProcessUnit
{
///
/// 激光启动对应PLC地址
///
public int laser_start_address { get; set; }
///
/// 激光状态对应PLC地址
///
public int laser_status_address { get; set; }
///
/// 激光id
///
public int id { get; set; }
private int LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD, laser_rescan_countdown, laser_heartbeat_countdown;
private bool laser_record, laser_heartbeat_test, enable_status_check = true, disordered = false;
private HashSet laser_heartbeat = new HashSet();
///
/// plc类句柄
///
private IEquipments plc = null;
///
/// 激光消息,用于保存激光数据、状态等信息
///
public LaserMessage laserMsg = new LaserMessage();
///
/// 激光处理单元构造函数,初始化各属性值
///
/// 编号
/// 停车指令地址
/// 激光状态地址
/// 激光重测次数
/// 激光心跳时间窗口
public LaserProcessUnit(IEquipments plc, int id, int park_command_address, int laser_status_address, int laser_rescan_count, int laser_heartbeat_period)
{
try
{
laserMsg.id = id;
this.id = id;
laserMsg.status = 6;
this.laser_start_address = park_command_address;
this.laser_status_address = laser_status_address;
LASER_RESCAN_COUNT = laser_rescan_count;
LASER_HEARTBEAT_PERIOD = laser_heartbeat_period;
laser_rescan_countdown = LASER_RESCAN_COUNT;
laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
this.plc = plc;
}
catch (Exception)
{
//UILogServer.ins.error("激光设备配置文件错误");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "激光设备配置文件错误");
}
}
///
/// 更新激光状态
///
/// 地址
/// 值
public void UpdateLaserStatus(int addr, int value)
{
int status_addr = laser_status_address;
if (addr == status_addr)
{
laserMsg.status = value;
//UILogServer.ins.log(value.ToString());
//系统异常状态复位
if (value != 5 && disordered)
{
disordered = false;
}
}
}
///
/// 激光状态监测
///
/// 地址
/// 值
public void LaserStatusChecking(int addr, int value)
{
if (enable_status_check)
{
int status_addr = laser_status_address;
if (addr == status_addr)
{
//after status 0, start to check laser heartbeat
if (value == 0)
{
laserMsg.abort_rescan = false;//就绪状态设置允许重测
laser_heartbeat_test = true;
}
//after status 3 or 4, start to check laser heartbeat
if (value == 3 && !laserMsg.recorded && laserMsg.licenseNum != "")
{
if (plc == null)
{
Console.WriteLine("plc为null");
}
if (plc != null)
{
PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
plc.SetMessage(pn);
//停车指令置0
MyTimer mt = new MyTimer();
mt.StartTiming();
while (laserMsg.status != 254 && laserMsg.status != 255)
{
Thread.Sleep(1000);
mt.EndTiming();
int activationCount = 0;
if (mt.IsLonger(15, 1, false, out activationCount))
{
if (activationCount == 1)
{
//UILogServer.ins.info("记录数据前未获得心跳,继续等待");
Console.WriteLine("记录数据前未获得心跳,继续等待");
}
if (MyTimer.restart && !mt.rolledBack)
{
mt.rolledBack = true;
//UILogServer.ins.error("记录数据前超时未获得心跳,请检查设备");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "记录数据前超时未获得心跳");
Console.WriteLine("记录数据前超时未获得心跳,请检查设备");
return;
}
Thread.Sleep(100);
}
}
laser_record = true;
laser_rescan_countdown = LASER_RESCAN_COUNT;
laser_heartbeat_test = true;
}
}
else if (value == 4)
{
laser_record = false;
//启动重测指令
if (laser_rescan_countdown > 0)
{
enable_status_check = false;
Task t = Task.Factory.StartNew(() =>
{
Thread.Sleep(500);
if (plc == null)
{
//plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
Console.WriteLine("plc为null");
}
if (plc != null)
{
laser_rescan_countdown--;
//停车指令置0
PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
plc.SetMessage(pn);
//未终止重测,车未开走,停车指令归零后置1
if (!laserMsg.abort_rescan)
{
//UILogServer.ins.error("激光" + laserMsg.id + "计算异常,重新测量");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "激光" + laserMsg.id + "计算异常,重新测量");
//重测检测心跳
Task rescan_wait_heartbeat = Task.Factory.StartNew(() =>
{
MyTimer mt = new MyTimer();
mt.StartTiming();
while (laserMsg.status != 254 && laserMsg.status != 255)
{
Thread.Sleep(1000);
mt.EndTiming();
int activationCount = 0;
if (mt.IsLonger(15, 1, false, out activationCount))
{
if (activationCount == 1)
{
//UILogServer.ins.info("重测前未获得心跳,继续等待");
Console.WriteLine("重测前未获得心跳,继续等待");
}
if (MyTimer.restart && !mt.rolledBack)
{
mt.rolledBack = true;
//UILogServer.ins.error("发起重测前超时未能获取摆扫激光心跳,请检查设备");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "发起重测前超时未能获取摆扫激光心跳");
Console.WriteLine("发起重测前超时未能获取摆扫激光心跳");
return;
}
Thread.Sleep(100);
}
}
});
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "获得心跳,准备发起重测");
Console.WriteLine("获得心跳,准备发起重测");
rescan_wait_heartbeat.Wait();
pn = new PLCNode(laser_start_address.ToString(), "1");
plc.SetMessage(pn);
}
}
Thread.Sleep(500);
enable_status_check = true;
});
}
else if (laser_rescan_countdown == 0)
{
//激光1异常
laser_rescan_countdown = -1;
laser_heartbeat_test = false;
//UILogServer.ins.error("激光" + laserMsg.id + "计算异常超过重测次数,请检查");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "激光" + laserMsg.id + "计算异常超过重测次数");
Console.WriteLine("激光" + laserMsg.id + "计算异常超过重测次数,请检查");
}
}
//status 5, system error
if (value == 5)
{
lock (laserMsg)
{
laser_heartbeat_test = false;
if (!disordered)
{
//UILogServer.ins.error("激光" + laserMsg.id + "系统异常,请检查");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "激光" + laserMsg.id + "系统异常");
Console.WriteLine("激光" + laserMsg.id + "系统异常,请检查");
}
disordered = true;
}
}
//find the heartbeat of laser
if (laser_heartbeat_test && laser_heartbeat_countdown-- > 0 && value != 3 && value != 4)
{
if (value == 254 || value == 255)
laser_heartbeat.Add(value);
if (laser_heartbeat.Contains(254) && laser_heartbeat.Contains(255))
{
lock (laserMsg)
{
laserMsg.disconnected = false;
}
laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
laser_heartbeat_test = false;
laser_heartbeat.Clear();
}
//fail to check laser heartbeat
if (laser_heartbeat_countdown <= 0)
{
laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
lock (laserMsg)
{
if (laserMsg.status >= 0 && !laserMsg.disconnected)
{
//UILogServer.ins.error("激光" + laserMsg.id + "心跳检测失败");
//Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "激光" + laserMsg.id + "心跳检测失败");
Console.WriteLine("激光" + laserMsg.id + "心跳检测失败");
}
laserMsg.disconnected = true;
}
}
}
}
}
else { return; }
}
///
/// 激光数据记录
///
/// plc数据列表
public void LaserRecord(List plist)
{
lock (laserMsg)
{
//激光未掉线,记录数据写入plc
if (laserMsg.status != -1)
{
if (laser_record)
{
laser_record = false;
foreach (PLCNode p in plist)
{
int addr = Int32.Parse(p.Address);
int value = Int32.Parse(p.Value);
if (addr == laser_status_address + 1)
laserMsg.data.centerX = value;
else if (addr == laser_status_address + 2)
laserMsg.data.centerY = value;
else if (addr == laser_status_address + 3)
laserMsg.data.angleA = value;
else if (addr == laser_status_address + 4)
laserMsg.data.length = value;
else if (addr == laser_status_address + 5)
laserMsg.data.width = value;
else if (addr == laser_status_address + 6)
laserMsg.data.height = value;
}
laserMsg.recorded = true;
//UILogServer.ins.info("摆扫激光测量数据已记录");
Console.WriteLine("摆扫激光测量数据已记录");
}
}
}
}
}
///
/// 机械手逻辑处理类
///
class RobotProcessUnit
{
///
/// 机械手id
///
public int id { get; set; }
///
/// 停车启动机械手对应PLC地址
///
public int parking_startRobot_address { get; set; }
///
/// 停车激光数据写入入口
///
public int parking_laserCenterX_address { get; set; }
///
/// 停车位ID对应PLC地址
///
public int parkingSpaceID_address { get; set; }
///
/// 停车完成对应PLC地址
///
public int park_completed_address { get; set; }
///
/// 用于停车完成复位PLC地址
///
public int park_completed_acknowledge_address { get; set; }
///
/// 取车启动机械手PLC地址
///
public int fetching_startRobot_address { get; set; }
///
/// 取车完成PLC地址
///
public int fetch_completed_address { get; set; }
///
/// 用于取车完成复位PLC地址
///
public int fetch_completed_acknowledge_address { get; set; }
///
/// 取车放置位置PLC地址
///
public int fetch_to_address { get; set; }
///
/// 前轮轮距记录
///
public int frontWheelbase { get; set; }
///
/// 后轮轮距记录
///
public int rearWheelbase { get; set; }
///
/// 构造函数,初始化各属性值
///
/// 编号
/// 停车启动机械手地址
/// 停车激光中心X坐标
/// 车位ID地址
/// 停车完成地址
/// 停车完成获取标志地址
/// 取车启动机械手地址
/// 取至缓冲区地址
/// 取车完成地址
/// 取车完成获得标志地址
/// 前轮距转存
/// 后轮距转存
public RobotProcessUnit(int id, int parking_startRobot_address, int parking_laserCenterX_address, int parkingSpaceID_address, int park_completed_address, int park_completed_acknowledge_address, int fetching_startRobot_address, int fetch_to_address, int fetch_completed_address, int fetch_completed_acknowledge_address, int frontWheelbase, int rearWheelbase)
{
this.id = id;
this.parking_startRobot_address = parking_startRobot_address;
this.parking_laserCenterX_address = parking_laserCenterX_address;
this.parkingSpaceID_address = parkingSpaceID_address;
this.park_completed_address = park_completed_address;
this.park_completed_acknowledge_address = park_completed_acknowledge_address;
this.fetching_startRobot_address = fetching_startRobot_address;
this.fetch_completed_address = fetch_completed_address;
this.fetch_completed_acknowledge_address = fetch_completed_acknowledge_address;
this.fetch_to_address = fetch_to_address;
this.frontWheelbase = frontWheelbase;
this.rearWheelbase = rearWheelbase;
}
}
}