PLCLinker.cs 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using HslCommunication.ModBus;
  7. using HslCommunication;
  8. using HslCommunication.BasicFramework;
  9. using System.Net;
  10. using System.Threading;
  11. using System.Collections;
  12. using System.Timers;
  13. using HslCommunication.Controls;
  14. using parkMonitor.entity;
  15. using parkMonitor.tools;
  16. using parkMonitor.model;
  17. using System.Diagnostics;
  18. using System.Configuration;
  19. using parkMonitor.server.uiLogServer;
  20. using parkMonitor.LOG;
  21. namespace parkMonitor.server
  22. {
  23. /// <summary>
  24. /// PLC通信类
  25. /// </summary>
  26. public class PLCLinker : IEquipments
  27. {
  28. private Boolean isConnection = false;
  29. private bool isRecorded = false, exceptionBreak = false, isClosing = false;
  30. private static string json = "";//读到的数据
  31. private string json2 = "";//写入的数据
  32. private PLCMessage plcMsg = new PLCMessage();
  33. System.Timers.Timer timer;
  34. //parameteres for plc read function
  35. private int startAddr = 0;
  36. private int addrLength = 110;
  37. /// <summary> plc重连标记位 </summary>
  38. private int linkCount = 0;
  39. //plc 基本配置
  40. private const short PLC_TIME_SCALE = 100;
  41. private const short LASER_TIME_SCALE = 5000;
  42. private string ipString;
  43. private int port;
  44. private byte station;
  45. //addresses for machine arm controlling
  46. private int fetching_startRobot_address;
  47. private int parking_startRobot_address;
  48. //addresses for laser data to be written to plc
  49. private int parkingSpaceID_address;
  50. //addresses for space info to be written to plc
  51. private int parkingLaserCenterX_address;
  52. //parameters(addresses) for Laser monitoring
  53. private int laser_start_address;
  54. private int fetch_completed_address;
  55. private int fetch_completed_acknowledge_address;
  56. private int fetch_to_address;
  57. private int frontWheelbase_address;
  58. private int rearWheelbase_address;
  59. private int park_completed_address;
  60. private int park_completed_acknowledge_address;
  61. private int LASER_RESCAN_COUNT;
  62. private int LASER_HEARTBEAT_PERIOD;
  63. private int PLC_refresh_interval;
  64. /// <summary>
  65. /// 激光管理list
  66. /// </summary>
  67. private List<LaserProcessUnit> laserMgmtList = new List<LaserProcessUnit>();
  68. private RobotProcessUnit rpu1;
  69. private List<string> decompressIndex;
  70. /// <summary>
  71. /// plc构造函数
  72. /// </summary>
  73. public PLCLinker()
  74. {
  75. try
  76. {
  77. LASER_RESCAN_COUNT = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_rescan_count"));
  78. LASER_HEARTBEAT_PERIOD = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_countdown"));
  79. PLC_refresh_interval = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_refresh_interval"));
  80. parking_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parking_startRobot_address"));
  81. parkingLaserCenterX_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingLaserCenterX_address"));
  82. parkingSpaceID_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingSpaceID_address"));
  83. park_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_address"));
  84. park_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_acknowledge_address"));
  85. fetching_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetching_startRobot_address"));
  86. fetch_to_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_to_address"));
  87. fetch_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_address"));
  88. fetch_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_acknowledge_address"));
  89. frontWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("frontWheelbase_address"));
  90. rearWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("rearWheelbase_address"));
  91. laser_start_address = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_start_address"));
  92. 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);
  93. //激光管理
  94. for (int i = 1; i < 20; i++)
  95. {
  96. try
  97. {
  98. string laser = ConfigurationManager.AppSettings.Get("laser" + i + "_status_address");
  99. int laser_status_address = Int32.Parse(laser);
  100. LaserProcessUnit lpu = new LaserProcessUnit(i, laser_start_address, laser_status_address, LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD);
  101. laserMgmtList.Add(lpu);
  102. plcMsg.laserMsgList.Add(lpu.laserMsg);
  103. }
  104. catch (Exception) { }
  105. }
  106. //定义plc被压缩的地址段
  107. decompressIndex = new List<string>();
  108. //25-27
  109. for (int i = 0; i < 3; i++)
  110. {
  111. decompressIndex.Add((25 + i).ToString());
  112. }
  113. //48-53
  114. for (int i = 0; i < 6; i++)
  115. {
  116. decompressIndex.Add((48 + i).ToString());
  117. }
  118. //70-76
  119. for (int i = 0; i < 7; i++)
  120. {
  121. decompressIndex.Add((70 + i).ToString());
  122. }
  123. }
  124. catch (Exception)
  125. {
  126. Console.WriteLine("PLC相关配置文件异常");
  127. }
  128. }
  129. //**************************************** PLC读写相关方法 **************************************
  130. private ModBusTcpClient busTcpClient
  131. {
  132. get;
  133. set;
  134. }
  135. private void WriteMessage(string message)
  136. {
  137. isRecorded = true;
  138. //json2 = "[{\"Adress\":\"1\",\"Value\":\"0043\"},{\"Adress\":\"2\",\"Value\":\"0043\"}]";
  139. json2 = message;
  140. }
  141. ///<summary>采集数据显示转json</summary>
  142. private static void DisplayString_ToJson(string str)
  143. {
  144. List<PLCNode> return_Value = new List<PLCNode>();
  145. if (!string.IsNullOrEmpty(str))
  146. {
  147. ArrayList array = GetSeparateSubString(str, 4);
  148. int Read_Address = 0;//0地址
  149. return_Value.Clear();
  150. foreach (string arr in array)
  151. {
  152. PLCNode rv = new PLCNode();
  153. //Console.WriteLine("地址:" + Read_Address + ": " + arr);
  154. rv.Address = Read_Address.ToString();
  155. rv.Value = Int32.Parse(arr, System.Globalization.NumberStyles.HexNumber).ToString();//plc数据16进制?
  156. return_Value.Add(rv);
  157. Read_Address++;
  158. }
  159. }
  160. json = JsonHelper.SerializeObject(return_Value);//序列化
  161. //List<PLCValue> prv = JsonHelper.DeserializeJsonToList<PLCValue>(json);
  162. //Console.WriteLine(json);
  163. }
  164. ///<summary>截取</summary>
  165. private static ArrayList GetSeparateSubString(string txtString, int charNumber)
  166. {
  167. ArrayList arrList = new ArrayList();
  168. string tempStr = txtString;
  169. for (int i = 0; i < tempStr.Length; i += charNumber)
  170. {
  171. if ((tempStr.Length - i) > charNumber)
  172. {
  173. arrList.Add(tempStr.Substring(i, charNumber));
  174. }
  175. else
  176. {
  177. arrList.Add(tempStr.Substring(i));
  178. }
  179. }
  180. return arrList;
  181. }
  182. private void InitTimer()
  183. {
  184. try
  185. {
  186. timer = new System.Timers.Timer(PLC_refresh_interval);
  187. }
  188. catch (Exception)
  189. {
  190. timer = new System.Timers.Timer(PLC_TIME_SCALE);
  191. }
  192. timer.AutoReset = true;
  193. timer.Enabled = true;
  194. timer.Elapsed += new ElapsedEventHandler(TimerUp);
  195. }
  196. ///<summary>实时采集</summary>
  197. private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
  198. {
  199. try
  200. {
  201. if (isConnection)
  202. {
  203. //从哪个地址开始,读取长度
  204. PLC_Read((ushort)startAddr, (ushort)addrLength);
  205. //LaserMonitor();
  206. }
  207. else
  208. {
  209. if (linkCount-- >= 0)
  210. {
  211. Task.Factory.StartNew(() =>
  212. {
  213. while (!isClosing)
  214. {
  215. Console.WriteLine("尝试重连plc");
  216. UILogServer.ins.log("尝试重连plc");
  217. LinkStart();
  218. Thread.Sleep(10000);
  219. if (isConnection)
  220. {
  221. linkCount = 0;
  222. break;
  223. }
  224. }
  225. });
  226. linkCount = -1;
  227. }
  228. }
  229. }
  230. catch (Exception ex)
  231. {
  232. Console.WriteLine(ex.Message);
  233. }
  234. }
  235. ///<summary>读取</summary>
  236. private void PLC_Read(ushort address, ushort length)
  237. {
  238. try
  239. {
  240. OperateResult<byte[]> read = busTcpClient.ReadRegister(address, length);
  241. if (read.IsSuccess)
  242. {
  243. string returned_value = SoftBasic.ByteToHexString(read.Content);
  244. DisplayString_ToJson(returned_value);
  245. }
  246. else
  247. {
  248. if (!exceptionBreak)
  249. {
  250. AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
  251. Console.WriteLine("读取失败");
  252. isConnection = false;
  253. exceptionBreak = true;
  254. }
  255. }
  256. }
  257. catch (Exception ex)
  258. {
  259. Console.WriteLine(ex.Message);
  260. }
  261. }
  262. ///<summary>写入</summary>
  263. private void WriteJson(string json)
  264. {
  265. try
  266. {
  267. if (!string.IsNullOrEmpty(json))
  268. {
  269. List<PLCNode> PLC_Value = JsonHelper.DeserializeJsonToList<PLCNode>(json);
  270. foreach (var item in PLC_Value)
  271. {
  272. //WriteResultRender(busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value)), item.Address);
  273. busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value));
  274. Thread.Sleep(20);
  275. }
  276. }
  277. }
  278. catch (Exception ex)
  279. {
  280. Console.WriteLine(ex.Message);
  281. }
  282. }
  283. ///<summary>写入判断</summary>
  284. private static void WriteResultRender(OperateResult result, string address)
  285. {
  286. if (result.IsSuccess)
  287. {
  288. Console.WriteLine("写入成功");
  289. }
  290. else
  291. {
  292. Console.WriteLine("写入失败");
  293. }
  294. }
  295. ///<summary>地址-值写入plc</summary>
  296. private void SendtoPLC(string addr, string value)
  297. {
  298. PLCNode wrv = new PLCNode();
  299. wrv.Address = addr;
  300. wrv.Value = value;
  301. json2 = "[" + JsonHelper.SerializeObject(wrv) + "]";
  302. WriteMessage(json2);
  303. if (isConnection && isRecorded)
  304. {
  305. WriteJson(json2);
  306. isRecorded = false;
  307. }
  308. }
  309. /// <summary>启动与plc的连接</summary>
  310. private void LinkStart()
  311. {
  312. if (busTcpClient != null)
  313. {
  314. busTcpClient.ConnectClose();
  315. }
  316. busTcpClient = new ModBusTcpClient(ipString, port, station);
  317. try
  318. {
  319. OperateResult connect = busTcpClient.ConnectServer();
  320. if (connect.IsSuccess)
  321. {
  322. AsyncCmdServer.ins.send(AsyncCmdType.PLCOnline);
  323. Console.WriteLine("连接成功");
  324. UILogServer.ins.log("PLC连接成功");
  325. isConnection = true;
  326. linkCount = 0;
  327. }
  328. else
  329. {
  330. AsyncCmdServer.ins.send(AsyncCmdType.PLCOffline);
  331. Console.WriteLine("连接失败,重试");
  332. UILogServer.ins.error("PLC连接失败,重试");
  333. isConnection = false;
  334. }
  335. }
  336. catch (Exception ex)
  337. {
  338. Console.WriteLine(ex.Message);
  339. }
  340. InitTimer();//启动计时器
  341. }
  342. /// <summary>将plc地址块完全解压</summary>
  343. private List<PLCNode> ListDecompression(List<PLCNode> plcList, List<string> decompressIndex)
  344. {
  345. List<string> temp = new List<string>();
  346. List<PLCNode> decomPlcList = new List<PLCNode>();
  347. if (plcList != null && addrLength > 100)
  348. {
  349. try
  350. {
  351. for (int i = 0; i < plcList.Count; i++)
  352. {
  353. if (!decompressIndex.Contains(plcList[i].Address))
  354. {
  355. temp.Add(plcList[i].Value);
  356. }
  357. //定位三个被压缩区域
  358. else
  359. {
  360. //默认LSB优先
  361. int value = Int32.Parse(plcList[i].Value);
  362. int count = 16;
  363. while (count-- > 0)
  364. {
  365. temp.Add((value & 0x01).ToString());
  366. value = value >> 1;
  367. }
  368. }
  369. }
  370. }
  371. catch (Exception) { }
  372. }
  373. for (int i = 0; i < temp.Count; i++)
  374. {
  375. decomPlcList.Add(new PLCNode(i.ToString(), temp[i]));
  376. }
  377. return decomPlcList;
  378. }
  379. //************************************ 雷达相关方法 **************************************
  380. /*
  381. * 激光监听PARK_STATUS, 0等待,1启动,其余异常
  382. * PARK_STATUS 控制:
  383. * 核心线程调用SetMessage将其置1,plc线程检测到PARK_COMPLETED则复位到0,(核心将plc“PARK_COMPLETED”复位),其余异常情况由监控或核心线程置2或其他值
  384. *
  385. * 读到LASER_STATUS(扫摆激光状态),监控线程显示该状态,一旦为状态5,处理完成后置0
  386. *
  387. * */
  388. private void LaserMonitor()
  389. {
  390. try
  391. {
  392. if (plcMsg.originalPlcList != null)
  393. {
  394. foreach (LaserProcessUnit lds in laserMgmtList)
  395. {
  396. foreach (PLCNode p in plcMsg.originalPlcList)
  397. {
  398. int addr = Int32.Parse(p.Address);
  399. int value = Int32.Parse(p.Value);
  400. lds.LaserStatusChecking(addr, value);
  401. }
  402. lds.LaserRecord(plcMsg.originalPlcList);
  403. }
  404. }
  405. else
  406. {
  407. AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
  408. return;
  409. }
  410. Thread.Sleep(200);
  411. }
  412. catch (Exception)
  413. {
  414. AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
  415. return;
  416. }
  417. }
  418. private void UpdateLaserStatus()
  419. {
  420. try
  421. {
  422. lock (plcMsg)
  423. {
  424. if (plcMsg.originalPlcList != null)
  425. {
  426. foreach (LaserProcessUnit lds in laserMgmtList)
  427. {
  428. foreach (PLCNode p in plcMsg.originalPlcList)
  429. {
  430. int addr = Int32.Parse(p.Address);
  431. int value = Int32.Parse(p.Value);
  432. lds.UpdateLaserStatus(addr, value);
  433. }
  434. }
  435. }
  436. else
  437. {
  438. AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
  439. return;
  440. }
  441. }
  442. }
  443. catch (Exception)
  444. {
  445. AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
  446. return;
  447. }
  448. }
  449. private void WaitForLaserReady(LaserProcessUnit lpuTemp)
  450. {
  451. bool jumpOut = false;
  452. MyTimer mt = new MyTimer();
  453. mt.StartTiming();
  454. lock (lpuTemp)
  455. {
  456. while (!jumpOut)
  457. {
  458. Thread.Sleep(1000);
  459. if (plcMsg != null && plcMsg.originalPlcList.Count > lpuTemp.laser_status_address)
  460. {
  461. foreach (PLCNode node in plcMsg.originalPlcList)
  462. {
  463. //判断激光空闲状态
  464. lock (lpuTemp.laserMsg)
  465. {
  466. if (node.Address.Equals(lpuTemp.laser_status_address.ToString()) && (node.Value.Equals("254") || node.Value.Equals("255")) && !lpuTemp.laserMsg.occupied)
  467. {
  468. lpuTemp.laserMsg.occupied = true;
  469. jumpOut = true;
  470. UILogServer.ins.log("获取摆扫激光空闲状态,准备启动激光");
  471. break;
  472. }
  473. }
  474. }
  475. }
  476. mt.EndTiming();
  477. int activationCount = 0;
  478. if (mt.IsLonger(15, 1, false, out activationCount))
  479. {
  480. if (activationCount == 1)
  481. {
  482. UILogServer.ins.info("启动前暂未获取摆扫激光空闲状态,继续等待");
  483. }
  484. if (MyTimer.restart && !mt.rolledBack)
  485. {
  486. mt.rolledBack = true;
  487. UILogServer.ins.error("启动前超时未能获取摆扫空闲状态,请检查设备");
  488. }
  489. }
  490. }
  491. }
  492. }
  493. //***************公有方法****************
  494. /// <summary>
  495. /// 获取plc数据与激光数据
  496. /// </summary>
  497. /// <returns>返回plc消息实例</returns>
  498. public AbstractMessage GetMessage()
  499. {
  500. try
  501. {
  502. plcMsg.originalPlcList = JsonHelper.DeserializeJsonToList<PLCNode>(json);
  503. if (decompressIndex != null && decompressIndex.Count != 0)
  504. {
  505. plcMsg.extendedPlcList = ListDecompression(plcMsg.originalPlcList, decompressIndex);
  506. }
  507. return (PLCMessage)plcMsg.Clone();
  508. }
  509. catch (Exception)
  510. {
  511. AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
  512. return new PLCMessage();
  513. }
  514. }
  515. /// <summary>
  516. /// 传入信息写入plc
  517. /// </summary>
  518. /// <param name="message">plc消息则传入plc,控制消息则根据指令编号分别处理</param>
  519. public void SetMessage(AbstractMessage message)
  520. {
  521. if (message.GetType().Equals(typeof(PLCMessage)))
  522. {
  523. PLCMessage ps = (PLCMessage)message;
  524. for (int i = 0; i < ps.originalPlcList.Count; i++)
  525. {
  526. SendtoPLC(ps.originalPlcList[i].Address, ps.originalPlcList[i].Value);
  527. }
  528. }
  529. else if (message.GetType().Equals(typeof(PLCNode)))
  530. {
  531. PLCNode pv = (PLCNode)message;
  532. SendtoPLC(pv.Address, pv.Value);
  533. }
  534. else if (message.GetType().Equals(typeof(ControlMessage)))
  535. {
  536. ControlMessage cm = (ControlMessage)message;
  537. if (cm != null && cm.status != 0)
  538. {
  539. switch (cm.status)
  540. {
  541. //停车startLaser--park_command_address
  542. case 1:
  543. //start laser scanning for parking
  544. LaserProcessUnit lpuTemp = null;
  545. Task.Factory.StartNew(() =>
  546. {
  547. string laser_start_addr = "";
  548. foreach (LaserProcessUnit lpu in laserMgmtList)
  549. {
  550. if (cm.laserID == lpu.id)
  551. {
  552. lpuTemp = lpu;
  553. laser_start_addr = lpu.laser_start_address.ToString();
  554. break;
  555. }
  556. }
  557. if (laser_start_addr == "")
  558. return;
  559. lock (lpuTemp)
  560. {
  561. WaitForLaserReady(lpuTemp);
  562. SendtoPLC(laser_start_addr, "0");
  563. lpuTemp.laserMsg.licenseNum = cm.LicenseNum;
  564. Thread.Sleep(300);
  565. SendtoPLC(laser_start_addr, "1");
  566. Thread.Sleep(100);
  567. //SendtoPLC("1", "1");//停车指令置1
  568. Log.WriteLog("已发送激光" + lpuTemp.id + "启动指令");
  569. UILogServer.ins.info("已发送激光" + lpuTemp.id + "启动指令");
  570. }
  571. });
  572. //Console.WriteLine("扫摆激光启动");
  573. break;
  574. //停车激光的6个数据,停车机械手,车位信息4个
  575. case 2:
  576. if (cm.RobotID == 1)
  577. {
  578. //停车指令置1
  579. SendtoPLC("1", "1");
  580. //停车启动机械手
  581. SendtoPLC(rpu1.parking_startRobot_address.ToString(), "1");
  582. //自动或手动输入激光雷达数据
  583. SendtoPLC(rpu1.parking_laserCenterX_address.ToString(), cm.centerX);
  584. SendtoPLC((rpu1.parking_laserCenterX_address + 1).ToString(), cm.centerY);
  585. SendtoPLC((rpu1.parking_laserCenterX_address + 2).ToString(), cm.angleA);
  586. //车位信息
  587. SendtoPLC(rpu1.parkingSpaceID_address.ToString(), cm.parkingSpaceID);
  588. SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), cm.parkingSpaceX);
  589. SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), cm.parkingSpaceY);
  590. SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), cm.parkingSpaceZ);
  591. }
  592. break;
  593. //停车完成归零--park_completed_address
  594. case 3:
  595. if (cm.RobotID == 1)
  596. {
  597. //SendtoPLC(rpu1.park_completed_address.ToString(), "0");//停车完成复位
  598. SendtoPLC(rpu1.park_completed_acknowledge_address.ToString(), "0");
  599. SendtoPLC("1", "0");//停车指令置0
  600. //Console.WriteLine("停车完成");
  601. }
  602. break;
  603. //取车机械手,车位信息4个
  604. case 4:
  605. if (cm.RobotID == 1 && cm.fetchPosition != 0)
  606. {
  607. //前后轮轮距
  608. SendtoPLC(rpu1.frontWheelbase.ToString(), cm.frontWheelbase.ToString());
  609. SendtoPLC(rpu1.rearWheelbase.ToString(), cm.rearWheelbase.ToString());
  610. //取至区域
  611. //SendtoPLC(rpu1.fetch_to_address.ToString(), pm.fetchPosition.ToString());
  612. SendtoPLC(rpu1.fetch_to_address.ToString(), cm.parkingSpaceX);
  613. //车位信息
  614. SendtoPLC(rpu1.parkingSpaceID_address.ToString(), cm.parkingSpaceID);
  615. SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), cm.parkingSpaceX);
  616. SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), cm.parkingSpaceY);
  617. SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), cm.parkingSpaceZ);
  618. SendtoPLC(rpu1.fetching_startRobot_address.ToString(), "1");
  619. }
  620. break;
  621. case 5:
  622. if (cm.RobotID == 1)
  623. {
  624. //取车完成复位
  625. SendtoPLC(rpu1.fetch_completed_acknowledge_address.ToString(), "0");
  626. SendtoPLC(rpu1.fetch_to_address.ToString(), "0");
  627. }
  628. break;
  629. default: Console.WriteLine("输入plc数据异常"); break;
  630. }
  631. }
  632. }
  633. else
  634. {
  635. AsyncCmdServer.ins.send(AsyncCmdType.PLCWriteException);
  636. Debug.WriteLine("输入字符串有误");
  637. }
  638. }
  639. /// <summary>
  640. /// 开启激光线程与模拟plc自动重置子线程
  641. /// </summary>
  642. public void Start()
  643. {
  644. exceptionBreak = false; linkCount = 0;
  645. try
  646. {
  647. ipString = ConfigurationManager.AppSettings.Get("PLC_ip_address");
  648. port = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_port"));
  649. station = (byte)Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_station"));
  650. startAddr = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_start_address"));
  651. addrLength = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_address_length"));
  652. }
  653. catch (Exception) { UILogServer.ins.error("PLC配置文件异常"); }
  654. LinkStart();
  655. Task.Factory.StartNew(() =>
  656. {
  657. while (!isClosing)
  658. {
  659. LaserMonitor();
  660. }
  661. });
  662. Task.Factory.StartNew(() =>
  663. {
  664. while (!isClosing)
  665. {
  666. UpdateLaserStatus();
  667. }
  668. });
  669. //模拟plc与激光自动操作
  670. Task.Factory.StartNew(() =>
  671. {
  672. laserAnim();
  673. });
  674. Task.Factory.StartNew(() =>
  675. {
  676. wheelbaseAnim();
  677. });
  678. Task.Factory.StartNew(() =>
  679. {
  680. autoCycling();
  681. });
  682. }
  683. /// <summary>
  684. /// 系统停止
  685. /// </summary>
  686. public void Stop()
  687. {
  688. exceptionBreak = false; isClosing = true;
  689. busTcpClient.ConnectClose();//stop释放资源
  690. //throw new NotImplementedException();
  691. }
  692. private void laserAnim()
  693. {
  694. bool laserWorking = false;
  695. while (!isClosing)
  696. {
  697. if (plcMsg.originalPlcList != null)
  698. {
  699. //模拟plc与激光操作
  700. foreach (PLCNode p in plcMsg.originalPlcList)
  701. {
  702. int addr = Int32.Parse(p.Address);
  703. int value = Int32.Parse(p.Value);
  704. //模拟摆扫激光
  705. if (laserMgmtList.Count != 0)
  706. {
  707. if (addr == laser_start_address)
  708. {
  709. //心跳
  710. if (value == 0)
  711. {
  712. laserWorking = false;
  713. SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "254");
  714. Thread.Sleep(200);
  715. SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "255");
  716. Thread.Sleep(200);
  717. }
  718. //模拟测量
  719. else
  720. {
  721. if (!laserWorking)
  722. {
  723. SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "1");
  724. Thread.Sleep(300);
  725. SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "2");
  726. Thread.Sleep(500);
  727. SendtoPLC((laserMgmtList[0].laser_status_address + 1).ToString(), (new Random(DateTime.Now.Millisecond).Next(4000, 7000)).ToString());
  728. Thread.Sleep(1);
  729. SendtoPLC((laserMgmtList[0].laser_status_address + 2).ToString(), (new Random(DateTime.Now.Millisecond).Next(4000, 7000)).ToString());
  730. Thread.Sleep(1);
  731. SendtoPLC((laserMgmtList[0].laser_status_address + 3).ToString(), (new Random(DateTime.Now.Millisecond).Next(90, 150)).ToString());
  732. Thread.Sleep(1);
  733. SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "3");
  734. Thread.Sleep(500);
  735. }
  736. laserWorking = true;
  737. }
  738. }
  739. }
  740. }
  741. }
  742. Thread.Sleep(100);
  743. }
  744. }
  745. private void wheelbaseAnim()
  746. {
  747. bool working = false;
  748. while (!isClosing)
  749. {
  750. if (plcMsg.originalPlcList != null)
  751. {
  752. //模拟plc与激光操作
  753. foreach (PLCNode p in plcMsg.originalPlcList)
  754. {
  755. int addr = Int32.Parse(p.Address);
  756. int value = Int32.Parse(p.Value);
  757. //模拟轮距激光
  758. if (addr == parking_startRobot_address)
  759. {
  760. if (value == 1)
  761. {
  762. if (!working)
  763. {
  764. working = true;
  765. Thread.Sleep(500);
  766. SendtoPLC(frontWheelbase_address.ToString(), (new Random(DateTime.Now.Millisecond).Next(100, 300)).ToString());
  767. Thread.Sleep(1);
  768. SendtoPLC(rearWheelbase_address.ToString(), (new Random(DateTime.Now.Millisecond).Next(100, 300)).ToString());
  769. SendtoPLC("81", "3");
  770. Thread.Sleep(500);
  771. }
  772. }
  773. else
  774. {
  775. working = false;
  776. SendtoPLC("81", "254");
  777. Thread.Sleep(500);
  778. SendtoPLC("81", "255");
  779. Thread.Sleep(500);
  780. }
  781. }
  782. }
  783. }
  784. Thread.Sleep(200);
  785. }
  786. }
  787. private void autoCycling()
  788. {
  789. while (!isClosing)
  790. {
  791. if (plcMsg.originalPlcList != null)
  792. {
  793. //模拟plc与激光操作
  794. foreach (PLCNode p in plcMsg.originalPlcList)
  795. {
  796. int addr = Int32.Parse(p.Address);
  797. int value = Int32.Parse(p.Value);
  798. //停取车复位
  799. if (addr == park_completed_acknowledge_address && value == 0)
  800. {
  801. Thread.Sleep(1000);
  802. SendtoPLC(park_completed_address.ToString(), "0");
  803. SendtoPLC(park_completed_acknowledge_address.ToString(), "1");
  804. }
  805. if (addr == fetch_completed_acknowledge_address && value == 0)
  806. {
  807. Thread.Sleep(1000);
  808. SendtoPLC(fetch_completed_address.ToString(), "0");
  809. SendtoPLC(fetch_completed_acknowledge_address.ToString(), "1");
  810. }
  811. //停车完成
  812. if (addr == parking_startRobot_address && value == 1)
  813. {
  814. Thread.Sleep(2000);
  815. SendtoPLC(park_completed_address.ToString(), "1");
  816. SendtoPLC(addr.ToString(), "0");
  817. }
  818. //取车完成
  819. if (addr == fetching_startRobot_address && value == 1)
  820. {
  821. Thread.Sleep(2000);
  822. SendtoPLC(fetch_completed_address.ToString(), "1");
  823. SendtoPLC(addr.ToString(), "0");
  824. }
  825. }
  826. }
  827. Thread.Sleep(200);
  828. }
  829. }
  830. }
  831. /// <summary>
  832. /// 激光数据记录与处理类
  833. /// </summary>
  834. class LaserProcessUnit
  835. {
  836. public int laser_start_address { get; set; }
  837. public int laser_status_address { get; set; }
  838. public int id { get; set; }
  839. private int LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD, laser_rescan_countdown, laser_heartbeat_countdown;
  840. private bool laser_record, laser_heartbeat_test, enable_status_check = true, disconnected = false, disordered = false;
  841. private HashSet<int> laser_heartbeat = new HashSet<int>();
  842. private IEquipments plc = null;
  843. public LaserMessage laserMsg = new LaserMessage();
  844. public LaserProcessUnit(int id, int park_command_address, int laser_status_address, int laser_rescan_count, int laser_heartbeat_period)
  845. {
  846. try
  847. {
  848. laserMsg.id = id;
  849. this.id = id;
  850. laserMsg.status = 6;
  851. this.laser_start_address = park_command_address;
  852. this.laser_status_address = laser_status_address;
  853. LASER_RESCAN_COUNT = laser_rescan_count;
  854. LASER_HEARTBEAT_PERIOD = laser_heartbeat_period;
  855. laser_rescan_countdown = LASER_RESCAN_COUNT;
  856. laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
  857. plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
  858. }
  859. catch (Exception)
  860. {
  861. UILogServer.ins.error("激光设备配置文件错误");
  862. }
  863. }
  864. /// <summary>
  865. /// 更新激光状态
  866. /// </summary>
  867. /// <param name="addr"></param>
  868. /// <param name="value"></param>
  869. public void UpdateLaserStatus(int addr, int value)
  870. {
  871. int status_addr = laser_status_address;
  872. if (addr == status_addr)
  873. {
  874. laserMsg.status = value;
  875. //UILogServer.ins.log(value.ToString());
  876. //系统异常状态复位
  877. if (value != 5 && disordered)
  878. {
  879. disordered = false;
  880. }
  881. }
  882. }
  883. ///<summary>激光状态监测</summary>
  884. public void LaserStatusChecking(int addr, int value)
  885. {
  886. if (enable_status_check)
  887. {
  888. int status_addr = laser_status_address;
  889. if (addr == status_addr)
  890. {
  891. //after status 0, start to check laser heartbeat
  892. if (value == 0)
  893. {
  894. laserMsg.abort_rescan = false;//就绪状态设置允许重测
  895. laser_heartbeat_test = true;
  896. }
  897. //after status 3 or 4, start to check laser heartbeat
  898. if (value == 3 && !laserMsg.recorded && laserMsg.licenseNum != "")
  899. {
  900. if (plc == null)
  901. {
  902. plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
  903. }
  904. if (plc != null)
  905. {
  906. PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
  907. plc.SetMessage(pn);
  908. //停车指令置0
  909. MyTimer mt = new MyTimer();
  910. mt.StartTiming();
  911. while (laserMsg.status != 254 && laserMsg.status != 255)
  912. {
  913. Thread.Sleep(1000);
  914. mt.EndTiming();
  915. int activationCount = 0;
  916. if (mt.IsLonger(15, 1, false, out activationCount))
  917. {
  918. if (activationCount == 1)
  919. {
  920. UILogServer.ins.info("记录数据前未获得心跳,继续等待");
  921. }
  922. if (MyTimer.restart && !mt.rolledBack)
  923. {
  924. mt.rolledBack = true;
  925. UILogServer.ins.error("记录数据前超时未获得心跳,请检查设备");
  926. }
  927. }
  928. }
  929. laser_record = true;
  930. laser_rescan_countdown = LASER_RESCAN_COUNT;
  931. laser_heartbeat_test = true;
  932. }
  933. }
  934. else if (value == 4)
  935. {
  936. laser_record = false;
  937. //启动重测指令
  938. if (laser_rescan_countdown > 0)
  939. {
  940. enable_status_check = false;
  941. Task t = Task.Factory.StartNew(() =>
  942. {
  943. Thread.Sleep(500);
  944. if (plc == null)
  945. {
  946. plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
  947. }
  948. if (plc != null)
  949. {
  950. laser_rescan_countdown--;
  951. //停车指令置0
  952. PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
  953. plc.SetMessage(pn);
  954. //未终止重测,车未开走,停车指令归零后置1
  955. if (!laserMsg.abort_rescan)
  956. {
  957. UILogServer.ins.error("激光" + laserMsg.id + "计算异常,重新测量");
  958. //重测检测心跳
  959. Task rescan_wait_heartbeat = Task.Factory.StartNew(() =>
  960. {
  961. MyTimer mt = new MyTimer();
  962. mt.StartTiming();
  963. while (laserMsg.status != 254 && laserMsg.status != 255)
  964. {
  965. Thread.Sleep(1000);
  966. mt.EndTiming();
  967. int activationCount = 0;
  968. if (mt.IsLonger(15, 1, false, out activationCount))
  969. {
  970. if (activationCount == 1)
  971. {
  972. UILogServer.ins.info("重测前未获得心跳,继续等待");
  973. }
  974. if (MyTimer.restart && !mt.rolledBack)
  975. {
  976. mt.rolledBack = true;
  977. UILogServer.ins.error("发起重测前超时未能获取摆扫激光心跳,请检查设备");
  978. }
  979. }
  980. }
  981. });
  982. UILogServer.ins.log("获得心跳,准备发起重测");
  983. rescan_wait_heartbeat.Wait();
  984. pn = new PLCNode(laser_start_address.ToString(), "1");
  985. plc.SetMessage(pn);
  986. }
  987. }
  988. Thread.Sleep(500);
  989. enable_status_check = true;
  990. });
  991. }
  992. else if (laser_rescan_countdown == 0)
  993. {
  994. //激光1异常
  995. laser_rescan_countdown = -1;
  996. laser_heartbeat_test = false;
  997. UILogServer.ins.error("激光" + laserMsg.id + "计算异常超过重测次数,请检查");
  998. }
  999. }
  1000. //status 5, system error
  1001. if (value == 5)
  1002. {
  1003. lock (laserMsg)
  1004. {
  1005. laser_heartbeat_test = false;
  1006. if (!disordered)
  1007. {
  1008. UILogServer.ins.error("激光系统异常,请检查");
  1009. }
  1010. disordered = true;
  1011. }
  1012. }
  1013. //find the heartbeat of laser
  1014. if (laser_heartbeat_test && laser_heartbeat_countdown-- > 0 && value != 3 && value != 4)
  1015. {
  1016. if (value == 254 || value == 255)
  1017. laser_heartbeat.Add(value);
  1018. if (laser_heartbeat.Contains(254) && laser_heartbeat.Contains(255))
  1019. {
  1020. disconnected = false;
  1021. laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
  1022. laser_heartbeat_test = false;
  1023. Console.WriteLine("激光" + laserMsg.id + "已检测到心跳");
  1024. laser_heartbeat.Clear();
  1025. }
  1026. //fail to check laser heartbeat
  1027. if (laser_heartbeat_countdown <= 0)
  1028. {
  1029. laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
  1030. lock (laserMsg)
  1031. {
  1032. if (laserMsg.status >= 0)
  1033. {
  1034. UILogServer.ins.error("激光" + laserMsg.id + "心跳检测失败");
  1035. }
  1036. disconnected = true;
  1037. laserMsg.status = -1;
  1038. }
  1039. }
  1040. }
  1041. }
  1042. }
  1043. else { return; }
  1044. }
  1045. /// <summary>激光数据记录</summary>
  1046. public void LaserRecord(List<PLCNode> plist)
  1047. {
  1048. lock (laserMsg)
  1049. {
  1050. //激光未掉线,记录数据写入plc
  1051. if (laserMsg.status != -1)
  1052. {
  1053. if (laser_record)
  1054. {
  1055. laser_record = false;
  1056. foreach (PLCNode p in plist)
  1057. {
  1058. int addr = Int32.Parse(p.Address);
  1059. int value = Int32.Parse(p.Value);
  1060. if (addr == laser_status_address + 1)
  1061. laserMsg.data.centerX = value;
  1062. else if (addr == laser_status_address + 2)
  1063. laserMsg.data.centerY = value;
  1064. else if (addr == laser_status_address + 3)
  1065. laserMsg.data.angleA = value;
  1066. else if (addr == laser_status_address + 4)
  1067. laserMsg.data.length = value;
  1068. else if (addr == laser_status_address + 5)
  1069. laserMsg.data.width = value;
  1070. else if (addr == laser_status_address + 6)
  1071. laserMsg.data.height = value;
  1072. }
  1073. laserMsg.recorded = true;
  1074. UILogServer.ins.info("摆扫激光测量数据已记录");
  1075. }
  1076. }
  1077. }
  1078. }
  1079. }
  1080. /// <summary>
  1081. /// 机械手逻辑处理类
  1082. /// </summary>
  1083. class RobotProcessUnit
  1084. {
  1085. public int id { get; set; }
  1086. public int parking_startRobot_address { get; set; }
  1087. public int parking_laserCenterX_address { get; set; }
  1088. public int parkingSpaceID_address { get; set; }
  1089. public int park_completed_address { get; set; }
  1090. public int park_completed_acknowledge_address { get; set; }
  1091. public int fetching_startRobot_address { get; set; }
  1092. public int fetch_completed_address { get; set; }
  1093. public int fetch_completed_acknowledge_address { get; set; }
  1094. public int fetch_to_address { get; set; }
  1095. public int frontWheelbase { get; set; }
  1096. public int rearWheelbase { get; set; }
  1097. 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)
  1098. {
  1099. this.id = id;
  1100. this.parking_startRobot_address = parking_startRobot_address;
  1101. this.parking_laserCenterX_address = parking_laserCenterX_address;
  1102. this.parkingSpaceID_address = parkingSpaceID_address;
  1103. this.park_completed_address = park_completed_address;
  1104. this.park_completed_acknowledge_address = park_completed_acknowledge_address;
  1105. this.fetching_startRobot_address = fetching_startRobot_address;
  1106. this.fetch_completed_address = fetch_completed_address;
  1107. this.fetch_completed_acknowledge_address = fetch_completed_acknowledge_address;
  1108. this.fetch_to_address = fetch_to_address;
  1109. this.frontWheelbase = frontWheelbase;
  1110. this.rearWheelbase = rearWheelbase;
  1111. }
  1112. }
  1113. }