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; } } }