Management.cs 119 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579
  1. using Basler.Pylon;
  2. using Cognex.VisionPro;
  3. using Cognex.VisionPro.ToolBlock;
  4. using CSScripting;
  5. using CSScriptLib;
  6. using MathNet.Numerics.Distributions;
  7. using MathNet.Numerics.LinearAlgebra;
  8. using MathNet.Numerics.RootFinding;
  9. using Newtonsoft.Json;
  10. using NPOI.SS.Formula.Functions;
  11. using NPOI.Util;
  12. using Opc.Ua;
  13. using OpenCvSharp;
  14. using OpenCvSharp.Flann;
  15. using Org.BouncyCastle.Crypto;
  16. using Prism.Events;
  17. using Prism.Ioc;
  18. using Prism.Mvvm;
  19. using Prism.Regions;
  20. using Prism.Services.Dialogs;
  21. using System;
  22. using System.Collections;
  23. using System.Collections.Generic;
  24. using System.Collections.ObjectModel;
  25. using System.ComponentModel;
  26. using System.Data;
  27. using System.Diagnostics;
  28. using System.Drawing;
  29. using System.IO;
  30. using System.Linq;
  31. using System.Net.Sockets;
  32. using System.Reflection.Metadata;
  33. using System.Security.Cryptography;
  34. using System.Security.Policy;
  35. using System.Text;
  36. using System.Threading;
  37. using System.Threading.Tasks;
  38. using System.Windows;
  39. using System.Windows.Documents;
  40. using System.Windows.Forms;
  41. using System.Windows.Interop;
  42. using System.Windows.Media;
  43. using System.Windows.Media.Media3D;
  44. using Team.FFFeederService;
  45. using Team.FFFeederService.Interfaces;
  46. using TeamAAS_VP;
  47. using TeamAAS_VP.Core.PLCs;
  48. using TeamAAS_VP.Core.Robots;
  49. using TeamAAS_VP.Core.ScrewDriver;
  50. using TeamAAS_VP.Data;
  51. using TeamAAS_VP.Enums;
  52. using TeamAAS_VP.Events;
  53. using TeamAAS_VP.Interfaces;
  54. using TeamAAS_VP.Models;
  55. using TeamAAS_VP.Models.Calibration;
  56. using TeamAAS_VP.Models.Feeder;
  57. using TeamAAS_VP.Models.Product;
  58. using TeamAAS_VP.Models.Torque;
  59. using TeamAAS_VP.Resources.Languages;
  60. using TeamAAS_VP.Services;
  61. using TeamAAS_VP.ViewModels.Home;
  62. using TeamAAS_VP.Views.Product;
  63. using TouchSocket.Core;
  64. using TouchSocket.SerialPorts;
  65. using TouchSocket.Sockets;
  66. using static MaterialDesignThemes.Wpf.Theme.ToolBar;
  67. using static Org.BouncyCastle.Math.EC.ECCurve;
  68. using static System.Windows.Forms.AxHost;
  69. using Timer = System.Threading.Timer;
  70. namespace TeamAAS_VP.Core
  71. {
  72. public class Management : BindableBase
  73. {
  74. #region 字段
  75. IRegionManager _regionManager;
  76. IEventAggregator _eventAggregator;
  77. IContainerProvider _container;
  78. IConfigService _configService;
  79. IRobotService _robotService;
  80. ICameraService _cameraService;
  81. IFeederService _feederService;
  82. IPlcService _plcService;
  83. ILightManagerService _lightManagerService;
  84. IProductService _productService;
  85. ICalibrationService _calibrationService;
  86. IRemoteCommandService _remoteCommandService;
  87. ISystemDatabaseService _systemDatabaseService;
  88. IMesService _mesService;
  89. Timer yieldtimer;
  90. private DateTime StartTime = DateTime.Now;
  91. SerialPortClient client;
  92. // Pressure collection
  93. /// <summary>
  94. /// 压力采集信号控制CTS
  95. /// </summary>
  96. private CancellationTokenSource _pressureCts;
  97. /// <summary>
  98. /// 压力采集超时CTS
  99. /// </summary>
  100. private CancellationTokenSource _pressureTimeoutCts;
  101. /// <summary>
  102. /// 压力采集CTS
  103. /// </summary>
  104. private CancellationTokenSource _pressureLinkedCts;
  105. /// <summary>
  106. /// 压力数据集合
  107. /// </summary>
  108. private List<(DateTime Timestamp, float Value)> _pressureSamples = new List<(DateTime, float)>();
  109. /// <summary>
  110. /// 采样间隔毫秒
  111. /// </summary>
  112. private int _pressureSampleIntervalMs = 50; //采样间隔毫秒
  113. /// <summary>
  114. /// 超时自动停止秒数
  115. /// </summary>
  116. private int _pressureMaxDurationSeconds = 30; //超时自动停止秒数
  117. List<LockResult> lockResultsAll = new List<LockResult>();//一个产品的总结果
  118. string productSn = "";//产品sn
  119. DateTime StartScrewTime = DateTime.Now;//开始锁附的时间
  120. List<string> torqueList = new List<string>();//扭力数据集合
  121. List<string> pressureList = new List<string>();//压力数据集合
  122. List<string> turnList = new List<string>();//圈数数据集合
  123. #endregion
  124. #region 属性
  125. private ObservableCollection<ShowRender> _Renders;
  126. /// <summary>
  127. /// 显示界面
  128. /// </summary>
  129. public ObservableCollection<ShowRender> Renders
  130. {
  131. get { return _Renders; }
  132. set { SetProperty(ref _Renders, value); }
  133. }
  134. public BgCommunicate BgCommunicate { get; private set; }
  135. public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; }
  136. private ObservableCollection<StatusInfo> _Status = new ObservableCollection<StatusInfo>();
  137. /// <summary>
  138. /// 状态栏集合
  139. /// </summary>
  140. public ObservableCollection<StatusInfo> Status
  141. {
  142. get { return _Status; }
  143. set { SetProperty(ref _Status, value); }
  144. }
  145. private Int64 _TotalQuantity;
  146. /// <summary>
  147. /// 总产量
  148. /// </summary>
  149. public Int64 TotalQuantity
  150. {
  151. get { return _TotalQuantity; }
  152. set { SetProperty(ref _TotalQuantity, value); }
  153. }
  154. private Int64 _TotalQuantityToday;
  155. /// <summary>
  156. /// 当天的总产量
  157. /// </summary>
  158. public Int64 TotalQuantityToday
  159. {
  160. get { return _TotalQuantityToday; }
  161. set { SetProperty(ref _TotalQuantityToday, value); }
  162. }
  163. private Int64 _CurrentUPH;
  164. /// <summary>
  165. /// 当前的UPH
  166. /// </summary>
  167. public Int64 CurrentUPH
  168. {
  169. get { return _CurrentUPH; }
  170. set { SetProperty(ref _CurrentUPH, value); }
  171. }
  172. private XYD_ScrewDriver _ScrewDriver;
  173. public XYD_ScrewDriver ScrewDriver
  174. {
  175. get { return _ScrewDriver; }
  176. set { SetProperty(ref _ScrewDriver, value); }
  177. }
  178. public Dictionary<string, object> BackupObject { get; set; } = new Dictionary<string, object>();
  179. private string _SignalValue = "0";
  180. /// <summary>
  181. /// 扭力测量仪获取的最大值
  182. /// </summary>
  183. public string SignalValue
  184. {
  185. get { return _SignalValue; }
  186. set { SetProperty(ref _SignalValue, value); }
  187. }
  188. private NumberStatistics _NumStatistics;
  189. /// <summary>
  190. /// 数量(批头、吸嘴、供料器)
  191. /// </summary>
  192. public NumberStatistics NumStatistics
  193. {
  194. get { return _NumStatistics; }
  195. set { SetProperty(ref _NumStatistics, value); }
  196. }
  197. private double _CTtime;
  198. /// <summary>
  199. /// ct
  200. /// </summary>
  201. public double CTtime
  202. {
  203. get { return _CTtime; }
  204. set { SetProperty(ref _CTtime, value); }
  205. }
  206. private bool _TorqueStatus = false;
  207. public bool TorqueStatus
  208. {
  209. get { return _TorqueStatus; }
  210. set { _TorqueStatus = value; }
  211. }
  212. private ObservableCollection<DataFormCtq> _dfc = new ObservableCollection<DataFormCtq>();
  213. /// <summary>
  214. /// CTQ数据集合
  215. /// </summary>
  216. public ObservableCollection<DataFormCtq> DFC
  217. {
  218. get { return _dfc; }
  219. set { SetProperty(ref _dfc, value); }
  220. }
  221. #endregion
  222. #region 命令
  223. #endregion
  224. #region 事件
  225. #endregion
  226. public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService,
  227. IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService,
  228. ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService,
  229. IMesService mesService)
  230. {
  231. _regionManager = regionManager;
  232. _eventAggregator = ea;
  233. _container = container;
  234. _configService = configService;
  235. _robotService = robotService;
  236. _cameraService = cameraService;
  237. _feederService = feederService;
  238. _plcService = plcService;
  239. _calibrationService = calibrationService;
  240. yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
  241. Renders = new ObservableCollection<ShowRender>();
  242. _productService = productService;
  243. _remoteCommandService = remoteCommandService;
  244. _systemDatabaseService = systemDatabaseService;
  245. _lightManagerService = lightManagerService;
  246. _mesService = mesService;
  247. }
  248. #region 读取配置参数
  249. public async Task ReadConfig()
  250. {
  251. await ReadNumber();
  252. }
  253. /// <summary>
  254. /// 读取数量配置
  255. /// </summary>
  256. public async Task ReadNumber()
  257. {
  258. try
  259. {
  260. NumStatistics = new NumberStatistics();
  261. var latestHeadChangeRecord = await _systemDatabaseService.GetLatestHeadChangeRecordAsync();
  262. if (latestHeadChangeRecord != null)
  263. {
  264. NumStatistics.HeaderNum = latestHeadChangeRecord.CurrentLockCount;
  265. }
  266. var latestNozzleChangeRecord = await _systemDatabaseService.GetLatestNozzleChangeRecordAsync();
  267. if (latestNozzleChangeRecord != null)
  268. {
  269. NumStatistics.NozzleNum = latestNozzleChangeRecord.CurrentLockCount;
  270. }
  271. NumStatistics.Feeder1Num = _configService.GetRemainingCountByFeederNumber(1);
  272. NumStatistics.Feeder2Num = _configService.GetRemainingCountByFeederNumber(2);
  273. }
  274. catch (Exception ex)
  275. {
  276. NumStatistics = new NumberStatistics();
  277. LogHelper.WriteLogError("加载数量配置文件时出错!", ex);
  278. }
  279. }
  280. #endregion
  281. #region 初始化硬件模块
  282. /// <summary>
  283. /// 初始化Feeder
  284. /// </summary>
  285. /// <returns></returns>
  286. public async Task<(bool IsSucceed, string Msg)> InitFeeders()
  287. {
  288. var feeders = _configService.GetAllFeeders();
  289. StringBuilder sb = new StringBuilder();
  290. foreach (var item in feeders)
  291. {
  292. _feederService.CreateFeeder(item.Id, item.FeederNo, item.FeederName, item.IP, item.Port, item.FeederBrand);
  293. var feeder = _feederService.GetFeeder(item.Id);
  294. Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  295. try
  296. {
  297. feeder.FeederConnectionStatusChanged += Management_FeederConnectionStatusChanged;
  298. await feeder.ConnectAsync(); //连接Feeder
  299. //SendTaskMessage($"{item.FeederName}已连接!", MessageLevel.Debug);
  300. }
  301. catch (Exception ex)
  302. {
  303. sb.AppendLine($"{item.FeederName}:{Lang.断开连接}![{ex.Message}]");
  304. SendTaskMessage($"{item.FeederName}{Lang.断开连接}!", MessageLevel.Alarm);
  305. }
  306. }
  307. if (sb.Length == 0)
  308. {
  309. return (true, "");
  310. }
  311. else
  312. {
  313. return (false, sb.ToString());
  314. }
  315. }
  316. /// <summary>
  317. /// 初始化机器人
  318. /// </summary>
  319. /// <returns></returns>
  320. public async Task<(bool IsSucceed, string Msg)> InitRobots()
  321. {
  322. var robots = _configService.GetAllRobots();
  323. StringBuilder sb = new StringBuilder();
  324. foreach (var item in robots)
  325. {
  326. _robotService.CreateRobot(item.Id, item);
  327. try
  328. {
  329. Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  330. var robot = _robotService.GetRobot(item.Id);
  331. robot.ReceivedEvent += Management_ReceivedEvent;
  332. robot.SendEvent += Management_SendEvent;
  333. robot.ConnectedEvent += Management_ConnectedEvent;
  334. robot.DisconnectedEvent += Management_DisconnectedEvent;
  335. await robot.ConnectAsync(); //连接Robot
  336. SendTaskMessage($"{item.RobotName}{Lang.已连接}!", MessageLevel.Debug);
  337. }
  338. catch (Exception ex)
  339. {
  340. sb.AppendLine($"{item.RobotName}:{Lang.断开连接}![{ex.Message}]");
  341. SendTaskMessage($"{item.RobotName}{Lang.断开连接}!", MessageLevel.Alarm);
  342. }
  343. }
  344. if (sb.Length == 0)
  345. {
  346. return (true, "");
  347. }
  348. else
  349. {
  350. return (false, sb.ToString());
  351. }
  352. }
  353. /// <summary>
  354. /// 初始化PLC
  355. /// </summary>
  356. /// <returns></returns>
  357. public async Task<(bool IsSucceed, string Msg)> InitPlc()
  358. {
  359. var plcs = _configService.GetAllPlcs();
  360. StringBuilder sb = new StringBuilder();
  361. foreach (var item in plcs)
  362. {
  363. try
  364. {
  365. _plcService.CreatePlc(item.Id, item);
  366. var plc = _plcService.GetPlc(item.Id);
  367. Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  368. plc.ConnectChangedEvent += Management_PlcConnectChangedEvent;
  369. await plc.ConnectAsync(); //连接PLC
  370. //SendTaskMessage($"{item.Name}{Lang.已连接}!", MessageLevel.Debug);
  371. }
  372. catch (Exception ex)
  373. {
  374. sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]");
  375. SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm);
  376. }
  377. }
  378. try
  379. {
  380. await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
  381. RegisterPlcMonitorAddress();
  382. }
  383. catch (Exception ex)
  384. {
  385. LogHelper.WriteLogError(Lang.为PLC写入系统参数和订阅变量时出错, ex);
  386. }
  387. if (sb.Length == 0)
  388. {
  389. return (true, "");
  390. }
  391. else
  392. {
  393. return (false, sb.ToString());
  394. }
  395. }
  396. /// <summary>
  397. /// 初始化相机
  398. /// </summary>
  399. /// <returns></returns>
  400. public async Task<(bool IsSucceed, string Msg)> InitCameras()
  401. {
  402. var cameras = _configService.GetAllCameras();
  403. StringBuilder sb = new StringBuilder();
  404. foreach (var item in cameras)
  405. {
  406. try
  407. {
  408. //Renders.Add(new ShowRender() { Id = item.Id, CameraName = item.CameraName });
  409. _cameraService.CreateCamera(item.Id, item);
  410. var camera = _cameraService.GetCamera(item.Id);
  411. Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  412. camera.CameraConnectChangedEvent += Management_CameraConnectChangedEvent;
  413. try
  414. {
  415. if (await camera.OpenDeviceAsync())
  416. {
  417. SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug);
  418. }
  419. else
  420. {
  421. SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
  422. sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!");
  423. }
  424. }
  425. catch (Exception ex)
  426. {
  427. SendTaskMessage($"{item.CameraName}{ex.Message}!", MessageLevel.Alarm);
  428. sb.AppendLine($"{item.CameraName}:{ex.Message}!");
  429. }
  430. }
  431. catch (Exception ex)
  432. {
  433. SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
  434. sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!:{ex.Message}");
  435. }
  436. }
  437. //_container.Resolve<ShowVisionRenderViewModel>().Renders = Renders;
  438. if (sb.Length == 0)
  439. {
  440. return (true, "");
  441. }
  442. else
  443. {
  444. return (false, sb.ToString());
  445. }
  446. }
  447. /// <summary>
  448. /// 初始化光源控制器
  449. /// </summary>
  450. /// <returns></returns>
  451. public async Task<(bool IsSucceed, string Msg)> InitLightControllers()
  452. {
  453. var lightcontrollers = _configService.GetAllLightControllers();
  454. StringBuilder sb = new StringBuilder();
  455. foreach (var item in lightcontrollers)
  456. {
  457. try
  458. {
  459. var lishtCtr = await _lightManagerService.RegisterControllerAsync(item.Id, item);
  460. //var lightcontroller = _cameraService.GetLightController(item.Id);
  461. //await lightcontroller.ConnectAsync(); //连接光源控制器
  462. //SendTaskMessage($"{item.LightControllerName}{Lang.已连接}!", MessageLevel.Debug);
  463. }
  464. catch (Exception ex)
  465. {
  466. //sb.AppendLine($"{item.LightControllerName}:{Lang.断开连接}![{ex.Message}]");
  467. //SendTaskMessage($"{item.LightControllerName}{Lang.断开连接}!", MessageLevel.Alarm);
  468. }
  469. }
  470. if (lightcontrollers.Count > 0)
  471. {
  472. var result = await _lightManagerService.ConnectAllAsync();
  473. if (result)
  474. {
  475. return (true, "");
  476. }
  477. else
  478. {
  479. return (false, "Light Controller Connect Failed!");
  480. }
  481. }
  482. return (true, "");
  483. //if (sb.Length == 0)
  484. //{
  485. // return (true, "");
  486. //}
  487. //else
  488. //{
  489. // return (false, sb.ToString());
  490. //}
  491. }
  492. /// <summary>
  493. /// 初始化后台TCP服务器通讯
  494. /// </summary>
  495. public void InitBgTcp()
  496. {
  497. var config = _configService.GetBgTcp();
  498. try
  499. {
  500. BgCommunicate = new BgCommunicate(config);
  501. BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent;
  502. BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent;
  503. BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent;
  504. BgCommunicate.SendEvent += BgCommunicate_SendEvent;
  505. BgCommunicate.StartListening();
  506. SendTaskMessage($"{Lang.已开启监听端口}:{config.Port}", MessageLevel.Debug);
  507. }
  508. catch (Exception ex)
  509. {
  510. SendTaskMessage($"{Lang.未开启监听端口}:{config.Port}", MessageLevel.Error);
  511. LogHelper.WriteLogError(Lang.开启后台服务器通讯时出错, ex);
  512. }
  513. }
  514. /// <summary>
  515. /// 初始化后台ModbusTCP从站
  516. /// </summary>
  517. public void InitModbusTcp()
  518. {
  519. try
  520. {
  521. var config = _configService.GetBgModbusTcp();
  522. BgModbusTcpCommunicate = new BgModbusTcpCommunicate(config);
  523. if (config.IsEnabled)
  524. {
  525. BgModbusTcpCommunicate.Listen();
  526. SendTaskMessage($"Start Modbus Tcp Slave:{BgModbusTcpCommunicate.IP}:{BgModbusTcpCommunicate.Port}:{BgModbusTcpCommunicate.SlaveID}", MessageLevel.Debug);
  527. }
  528. }
  529. catch (Exception ex)
  530. {
  531. SendTaskMessage($"No Start Modbus Tcp Slave:{ex.Message}", MessageLevel.Alarm);
  532. LogHelper.WriteLogError(Lang.开启后台ModbusTCP通讯时出错, ex);
  533. }
  534. }
  535. /// <summary>
  536. /// 初始化后台脚本
  537. /// </summary>
  538. public void InitBackgroundcript()
  539. {
  540. try
  541. {
  542. if (!Directory.Exists(FilePath.BackgroundScriptPath))
  543. {
  544. Directory.CreateDirectory(FilePath.BackgroundScriptPath);
  545. }
  546. try
  547. {
  548. string[] files = Directory.GetFiles(FilePath.BackgroundScriptPath);
  549. List<string> ScriptFilesCollection = new List<string>();
  550. foreach (string file in files)
  551. {
  552. string fileName = Path.GetFileName(file);
  553. string fileExtension = Path.GetExtension(file);
  554. if (fileExtension == ".cs")
  555. {
  556. ScriptFilesCollection.Add(file);
  557. }
  558. }
  559. foreach (var item in ScriptFilesCollection)
  560. {
  561. try
  562. {
  563. string script = FileHelper.ReadFile(item);
  564. SendTaskMessage($"{Lang.执行脚本}:{item}", MessageLevel.Info);
  565. Task.Factory.StartNew(() =>
  566. {
  567. ScriptHelper.ExecuteScriptingAsync(script, _regionManager, _eventAggregator, _container, rst =>
  568. {
  569. if (!rst.Item1)
  570. {
  571. foreach (var err in rst.Item2)
  572. {
  573. SendTaskMessage($"{Lang.后台脚本出错}:{err}", MessageLevel.Error);
  574. }
  575. }
  576. });
  577. });
  578. }
  579. catch (Exception ex)
  580. {
  581. LogHelper.WriteLogError(string.Format(Lang.开启脚本时出错0, item), ex);
  582. }
  583. }
  584. }
  585. catch (Exception ex)
  586. {
  587. LogHelper.WriteLogError(Lang.读取本地脚本文件列表时出错, ex);
  588. }
  589. }
  590. catch (Exception ex)
  591. {
  592. LogHelper.WriteLogError(Lang.开启后台脚本时出错, ex);
  593. }
  594. }
  595. /// <summary>
  596. /// 初始化电批
  597. /// </summary>
  598. /// <returns></returns>
  599. public async Task InitScrewDriver()
  600. {
  601. try
  602. {
  603. var screwDriverConfig = _configService.GetScrewDriverConfig();
  604. ScrewDriver = new XYD_ScrewDriver(screwDriverConfig.IPAdress, screwDriverConfig.Port);
  605. Status.Add(new StatusInfo(ScrewDriver.Id, Lang.电批未连接, new SolidColorBrush(Colors.Red)));
  606. ScrewDriver.ConnectStateChangedEvent += ScrewDriver_ConnectStateChangedEvent;
  607. ScrewDriver.SendTimeout = screwDriverConfig.SendTimeout;
  608. screwDriverConfig.ReceiveTimeout = screwDriverConfig.ReceiveTimeout;
  609. var isConnected = await ScrewDriver.ConnectAsync();
  610. if (isConnected)
  611. {
  612. SendTaskMessage(Lang.电批已连接, MessageLevel.Debug);
  613. }
  614. else
  615. {
  616. SendTaskMessage(Lang.电批连接失败, MessageLevel.Error);
  617. }
  618. }
  619. catch (Exception ex)
  620. {
  621. SendTaskMessage(string.Format(Lang.电批连接失败0, ex.Message), MessageLevel.Alarm);
  622. LogHelper.WriteLogError(Lang.连接电批时出错, ex);
  623. }
  624. }
  625. /// <summary>
  626. /// 初始化扭力测量仪
  627. /// </summary>
  628. /// <returns></returns>
  629. public async Task InitSignal()
  630. {
  631. var torqueConfig = _configService.GetTorqueReaderConfig();
  632. if (torqueConfig != null)
  633. {
  634. try
  635. {
  636. var port = FileHelper.ReadJsonFile<TorqueProduceModel>(FilePath.TorqueReaderConfigurationPath);
  637. if (string.IsNullOrEmpty(port.TorqueMeasureSerialPort))
  638. {
  639. client = new TouchSocket.SerialPorts.SerialPortClient();
  640. client.Connecting = (client1, e) => { return EasyTask.CompletedTask; };//即将连接到端口
  641. client.Connected = (client1, e) => { return EasyTask.CompletedTask; };//成功连接到端口
  642. client.Closing = (client1, e) => { return EasyTask.CompletedTask; };//即将从端口断开连接。此处仅主动断开才有效。
  643. client.Closed = (client1, e) => { return EasyTask.CompletedTask; };//从端口断开连接,当连接不成功时不会触发。
  644. client.Received = async (c, e) =>
  645. {
  646. //await Console.Out.WriteLineAsync(Encoding.UTF8.GetString(e.ByteBlock.Buffer));
  647. await Console.Out.WriteLineAsync(e.ByteBlock.Span.ToString(Encoding.ASCII));
  648. };
  649. client.Received = Sp_DataReceived;
  650. await client.SetupAsync(new TouchSocketConfig()
  651. .SetSerialPortOption(new SerialPortOption()
  652. {
  653. BaudRate = torqueConfig.BaudRate,//波特率
  654. DataBits = torqueConfig.DataBits,//数据位
  655. Parity = torqueConfig.Parity,//校验位
  656. PortName = torqueConfig.PortName,//COM
  657. StopBits = torqueConfig.StopBits//停止位
  658. })
  659. .SetSerialDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromMilliseconds(100) })
  660. );
  661. await client.ConnectAsync();
  662. }
  663. else
  664. {
  665. SendTaskMessage("请设置扭力测量仪串口!", MessageLevel.Error);
  666. }
  667. }
  668. catch (Exception ex)
  669. {
  670. LogHelper.WriteLogError("初始化扭力测量仪时出错!", ex);
  671. SendTaskMessage("初始化扭力测量仪时出错!" + ex.Message, MessageLevel.Error);
  672. }
  673. }
  674. else
  675. {
  676. TorqueSerialPortConfig config = new TorqueSerialPortConfig();
  677. FileHelper.WriteJsonFile(config, FilePath.TorqueReaderConfigurationPath);
  678. }
  679. }
  680. #endregion
  681. #region 机器人指令执行
  682. public Dictionary<Guid, CancellationTokenSource> RobotTCPCollection = new Dictionary<Guid, CancellationTokenSource>();
  683. /// <summary>
  684. /// 机器人TCP接收
  685. /// </summary>
  686. /// <param name="arg1"></param>
  687. /// <param name="arg2"></param>
  688. /// <param name="arg3"></param>
  689. private async void Management_ReceivedEvent(Guid robotid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e)
  690. {
  691. try
  692. {
  693. if (!RobotTCPCollection.ContainsKey(robotid))
  694. RobotTCPCollection.Add(robotid, new CancellationTokenSource());
  695. else
  696. {
  697. if (RobotTCPCollection[robotid].IsCancellationRequested)
  698. {
  699. RobotTCPCollection[robotid] = new CancellationTokenSource();
  700. }
  701. }
  702. var robot = await _robotService.GetRobotAsync(robotid);
  703. //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
  704. var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding());
  705. SendTaskMessage($"{robot.Name}Received:{buffer}", MessageLevel.Info);
  706. var _ = _remoteCommandService.ExecuteAsync(buffer, RobotTCPCollection[robotid].Token, async msg =>
  707. {
  708. try
  709. {
  710. if (robot.ConnectType == TCPConnectType.Client)
  711. {
  712. if (robot.IsConnected)
  713. {
  714. await robot.SendAsync($"{msg}");
  715. }
  716. }
  717. else
  718. {
  719. var cient = (ITcpSessionClient)arg2;
  720. if (cient.Online)
  721. {
  722. await robot.SendAsync(cient, $"{msg}");
  723. }
  724. }
  725. }
  726. catch (Exception ex)
  727. {
  728. LogHelper.WriteLogError(Lang.TCP发送数据时出错, ex);
  729. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  730. }
  731. });
  732. }
  733. catch (Exception ex)
  734. {
  735. LogHelper.WriteLogError(Lang.处理机器人接收的命令时出错, ex);
  736. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  737. }
  738. }
  739. #endregion
  740. #region 机器人&Feeder&相机连接状态事件
  741. /// <summary>
  742. /// 机器人发送事件
  743. /// </summary>
  744. /// <param name="arg1"></param>
  745. /// <param name="arg2"></param>
  746. /// <param name="arg3"></param>
  747. /// <exception cref="NotImplementedException"></exception>
  748. private void Management_SendEvent(Guid robotid, object arg2, string arg3)
  749. {
  750. var r = _robotService.GetRobot(robotid);
  751. SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info);
  752. }
  753. /// <summary>
  754. /// 机器人断开连接时
  755. /// </summary>
  756. /// <param name="arg1"></param>
  757. /// <param name="arg2"></param>
  758. /// <param name="arg3"></param>
  759. /// <exception cref="NotImplementedException"></exception>
  760. private void Management_DisconnectedEvent(Guid robotid, object arg2, ClosedEventArgs arg3)
  761. {
  762. if (RobotTCPCollection.ContainsKey(robotid))
  763. {
  764. RobotTCPCollection[robotid].Cancel();
  765. }
  766. var r = _configService.GetRobot(robotid);
  767. if (r.ConnectType == TCPConnectType.Server)
  768. {
  769. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  770. SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
  771. var robot = _robotService.GetRobot(robotid);
  772. if (robot.TcpService.Count < 1)
  773. {
  774. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  775. App.Current.Dispatcher.Invoke(new
  776. Action(() =>
  777. {
  778. sta.Message = $"{r.RobotName}{Lang.未连接}";
  779. sta.Background = new SolidColorBrush(Colors.Red);
  780. }));
  781. }
  782. }
  783. else
  784. {
  785. SendTaskMessage($"{r.RobotName}{Lang.断开连接}!", MessageLevel.Error);
  786. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  787. App.Current.Dispatcher.Invoke(new
  788. Action(() =>
  789. {
  790. sta.Message = $"{r.RobotName}{Lang.断开连接}";
  791. sta.Background = new SolidColorBrush(Colors.Red);
  792. }));
  793. }
  794. }
  795. /// <summary>
  796. /// 机器人连接成功时
  797. /// </summary>
  798. /// <param name="arg1"></param>
  799. /// <param name="arg2"></param>
  800. /// <param name="arg3"></param>
  801. /// <exception cref="NotImplementedException"></exception>
  802. private void Management_ConnectedEvent(Guid robotid, object arg2, ConnectedEventArgs arg3)
  803. {
  804. var r = _configService.GetRobot(robotid);
  805. if (r.ConnectType == TCPConnectType.Server)
  806. {
  807. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  808. SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
  809. var robot = _robotService.GetRobot(robotid);
  810. if (robot.TcpService.Count > 0)
  811. {
  812. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  813. App.Current.Dispatcher.Invoke(new
  814. Action(() =>
  815. {
  816. sta.Message = $"{r.RobotName}{Lang.已连接}";
  817. sta.Background = new SolidColorBrush(Colors.Green);
  818. }));
  819. }
  820. }
  821. else
  822. {
  823. SendTaskMessage($"{r.RobotName}{Lang.已连接}!", MessageLevel.Debug);
  824. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  825. App.Current.Dispatcher.Invoke(new
  826. Action(() =>
  827. {
  828. sta.Message = $"{r.RobotName}{Lang.已连接}";
  829. sta.Background = new SolidColorBrush(Colors.Green);
  830. }));
  831. }
  832. }
  833. /// <summary>
  834. /// Feeder连接状态改变时
  835. /// </summary>
  836. /// <param name="sender"></param>
  837. /// <param name="state"></param>
  838. private void Management_FeederConnectionStatusChanged(object sender, bool state)
  839. {
  840. IFeeder feeder = sender as IFeeder;
  841. var sta = Status.FirstOrDefault(s => s.ID == feeder.Id);
  842. if (state)
  843. {
  844. App.Current.Dispatcher.Invoke(new
  845. Action(() =>
  846. {
  847. sta.Message = $"{feeder.Name}{Lang.已连接}";
  848. sta.Background = new SolidColorBrush(Colors.Green);
  849. }));
  850. SendTaskMessage($"{feeder.Name}{Lang.已连接}!", MessageLevel.Debug);
  851. }
  852. else
  853. {
  854. App.Current.Dispatcher.Invoke(new
  855. Action(() =>
  856. {
  857. sta.Message = $"{feeder.Name}{Lang.未连接}";
  858. sta.Background = new SolidColorBrush(Colors.Red);
  859. }));
  860. SendTaskMessage($"{feeder.Name}{Lang.断开连接}!", MessageLevel.Error);
  861. }
  862. }
  863. /// <summary>
  864. /// 相机连接或者断开时
  865. /// </summary>
  866. /// <param name="id"></param>
  867. /// <param name="state"></param>
  868. private void Management_CameraConnectChangedEvent(Guid id, bool state)
  869. {
  870. var sta = Status.FirstOrDefault(s => s.ID == id);
  871. var camera = _configService.GetCamera(id);
  872. if (sta != null && camera != null)
  873. {
  874. if (state)
  875. {
  876. App.Current.Dispatcher.Invoke(new Action(() =>
  877. {
  878. sta.Message = $"{camera.CameraName}{Lang.已连接}";
  879. sta.Background = new SolidColorBrush(Colors.Green);
  880. }));
  881. }
  882. else
  883. {
  884. App.Current.Dispatcher.Invoke(new Action(() =>
  885. {
  886. sta.Message = $"{camera.CameraName}{Lang.断开连接}";
  887. sta.Background = new SolidColorBrush(Colors.Red);
  888. }));
  889. }
  890. }
  891. }
  892. /// <summary>
  893. /// PLC连接状态改变事件
  894. /// </summary>
  895. /// <param name="plc"></param>
  896. /// <param name="isconnected"></param>
  897. private async void Management_PlcConnectChangedEvent(object sender, bool isconnected)
  898. {
  899. IPlc plc = sender as IPlc;
  900. var sta = Status.FirstOrDefault(s => s.ID == plc.Id);
  901. if (plc.IsConnected)
  902. {
  903. SendTaskMessage($"{plc.Name}{Lang.已连接}!", MessageLevel.Debug);
  904. if (sta == null) return;
  905. App.Current.Dispatcher.Invoke(new
  906. Action(() =>
  907. {
  908. sta.Message = $"{plc.Name}{Lang.已连接}";
  909. sta.Background = new SolidColorBrush(Colors.Green);
  910. }));
  911. try
  912. {
  913. await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
  914. await WritePositionToPlcAsync();
  915. }
  916. catch (Exception ex)
  917. {
  918. LogHelper.WriteLogError("PLC连接成功时,写入系统参数和点位信息时出错!", ex);
  919. }
  920. }
  921. else
  922. {
  923. SendTaskMessage($"{plc.Name}{Lang.断开连接}!", MessageLevel.Error);
  924. if (sta == null) return;
  925. App.Current.Dispatcher.Invoke(new
  926. Action(() =>
  927. {
  928. sta.Message = $"{plc.Name}{Lang.未连接}";
  929. sta.Background = new SolidColorBrush(Colors.Red);
  930. }));
  931. }
  932. }
  933. /// <summary>
  934. /// 电批连接状态改变时
  935. /// </summary>
  936. /// <param name="screwDevice"></param>
  937. /// <param name="state"></param>
  938. private void ScrewDriver_ConnectStateChangedEvent(object screwDevice, bool state)
  939. {
  940. try
  941. {
  942. XYD_ScrewDriver screwDriver = screwDevice as XYD_ScrewDriver;
  943. if (state)
  944. {
  945. SendTaskMessage(Lang.电批已连接, MessageLevel.Debug);
  946. var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
  947. App.Current.Dispatcher.Invoke(new
  948. Action(() =>
  949. {
  950. sta.Message = Lang.电批已连接;
  951. sta.Background = new SolidColorBrush(Colors.Green);
  952. }));
  953. }
  954. else
  955. {
  956. SendTaskMessage(Lang.电批未连接, MessageLevel.Error);
  957. var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
  958. App.Current.Dispatcher.Invoke(new
  959. Action(() =>
  960. {
  961. sta.Message = Lang.电批未连接;
  962. sta.Background = new SolidColorBrush(Colors.Red);
  963. }));
  964. }
  965. }
  966. catch (Exception ex)
  967. {
  968. LogHelper.WriteLogError(Lang.电批连接状态改变时出错了, ex);
  969. }
  970. }
  971. #endregion
  972. #region 后台服务器通讯事件
  973. private void BgCommunicate_SendEvent(ITcpSessionClient client, string msg)
  974. {
  975. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}] Send To {Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
  976. }
  977. public Dictionary<string, CancellationTokenSource> BgCommunicateollection = new Dictionary<string, CancellationTokenSource>();
  978. private async void BgCommunicate_ReceivedEvent(ITcpSessionClient client, string msg)
  979. {
  980. try
  981. {
  982. if (!BgCommunicateollection.ContainsKey(client.Id))
  983. {
  984. BgCommunicateollection.Add(client.Id, new CancellationTokenSource());
  985. }
  986. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]ReceiveFor{Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
  987. var _ = _remoteCommandService.ExecuteAsync(msg, BgCommunicateollection[client.Id].Token, async response =>
  988. {
  989. try
  990. {
  991. if (!client.Online)
  992. {
  993. return;
  994. }
  995. await BgCommunicate.SendAsync(client, $"{response}");
  996. }
  997. catch (Exception ex)
  998. {
  999. LogHelper.WriteLogError(Lang.后台TCP发送数据时出错, ex);
  1000. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  1001. }
  1002. });
  1003. }
  1004. catch (Exception ex)
  1005. {
  1006. LogHelper.WriteLogError(Lang.处理后台服务器接收的命令时出错, ex);
  1007. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  1008. }
  1009. }
  1010. private void BgCommunicate_DisconnectedEvent(ITcpSessionClient client, ClosedEventArgs e)
  1011. {
  1012. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.断开连接}!", MessageLevel.Alarm);
  1013. if (BgCommunicateollection.ContainsKey(client.Id))
  1014. {
  1015. BgCommunicateollection[client.Id].Cancel();
  1016. }
  1017. }
  1018. private void BgCommunicate_ConnectedEvent(ITcpSessionClient client, ConnectedEventArgs e)
  1019. {
  1020. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.连接成功}!", MessageLevel.Debug);
  1021. }
  1022. /// <summary>
  1023. /// 扭力测量仪接收信息
  1024. /// </summary>
  1025. /// <param name="client"></param>
  1026. /// <param name="e"></param>
  1027. /// <returns></returns>
  1028. private async Task Sp_DataReceived(ISerialPortClient client, ReceivedDataEventArgs e)
  1029. {
  1030. try
  1031. {
  1032. string poname = client.MainSerialPort.PortName;
  1033. string data = e.ByteBlock.Span.ToString(Encoding.ASCII);
  1034. await Console.Out.WriteLineAsync(data);
  1035. string response = data.Split('\r')[0];
  1036. SendTaskMessage($"{poname}Receive:{response}", MessageLevel.Info);
  1037. SignalValue = "";
  1038. SignalValue = response;
  1039. }
  1040. catch (Exception ex)
  1041. {
  1042. LogHelper.WriteLogError("扭力测量仪接收信息时出错!", ex);
  1043. SendTaskMessage("扭力测量仪接收信息时出错!" + ex.Message, MessageLevel.Error);
  1044. Thread.Sleep(50);
  1045. }
  1046. }
  1047. #endregion
  1048. #region PLC
  1049. /// <summary>
  1050. /// 将系统参数写入PLC
  1051. /// </summary>
  1052. /// <param name="systemConfiguration"></param>
  1053. /// <returns></returns>
  1054. public async Task WriteSystemParameterToPlcAsync(SystemConfiguration systemConfiguration)
  1055. {
  1056. var addressConfig = _configService.GetPlcAddresses();
  1057. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1058. if (plc == null || !plc.IsConnected) return;
  1059. Dictionary<string, object> nodeValues = new Dictionary<string, object>();
  1060. nodeValues.Add(addressConfig.Out_WorkMode.Address, (Int16)systemConfiguration.WorkMode);
  1061. nodeValues.Add(addressConfig.Out_PickPointNum.Address, (Int16)systemConfiguration.PickPointNum);
  1062. nodeValues.Add(addressConfig.Out_DowmCameraNum.Address, (Int16)systemConfiguration.DowmCameraNum);
  1063. nodeValues.Add(addressConfig.Out_UpCameraPickNum.Address, (Int16)systemConfiguration.UpCameraPickNum);
  1064. nodeValues.Add(addressConfig.Out_UpCameraPutNum.Address, (Int16)systemConfiguration.UpCameraPutNum);
  1065. nodeValues.Add(addressConfig.Out_UPCameracheckNum.Address, (Int16)systemConfiguration.UPCameracheckNum);
  1066. nodeValues.Add(addressConfig.Out_FixedCameraPickNum.Address, (Int16)systemConfiguration.FixedCameraPickNum);
  1067. nodeValues.Add(addressConfig.Out_FixedCameraPutNum.Address, (Int16)systemConfiguration.FixedCameraPutNum);
  1068. nodeValues.Add(addressConfig.Out_FixedCameracheckNum.Address, (Int16)systemConfiguration.FixedCameracheckNum);
  1069. nodeValues.Add(addressConfig.Out_ScrewTeachNum.Address, (Int16)systemConfiguration.ScrewTeachNum);
  1070. var res = await plc.WriteNodesAsync(nodeValues);
  1071. }
  1072. /// <summary>
  1073. /// 注册需要监控的PLC地址
  1074. /// </summary>
  1075. public void RegisterPlcMonitorAddress()
  1076. {
  1077. var addressConfig = _configService.GetPlcAddresses();
  1078. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1079. if (plc == null || !plc.IsConnected) return;
  1080. //PLC地址数组
  1081. List<string> monitorNodeIds = new List<string>()
  1082. {
  1083. addressConfig.In_DowmCameraExe.Address,
  1084. addressConfig.In_UpCameraPickExe.Address,
  1085. addressConfig.In_UpCameraPutExe.Address,
  1086. addressConfig.In_UPCameracheckExe.Address,
  1087. addressConfig.In_FixedCameraPickExe.Address,
  1088. addressConfig.In_FixedCameraPutExe.Address,
  1089. addressConfig.In_FixedCameracheckExe.Address,
  1090. addressConfig.In_WorkStart.Address,
  1091. addressConfig.In_WorkDone.Address,
  1092. //addressConfig.In_MesCheck.Address,
  1093. addressConfig.In_RequestPosition.Address,
  1094. addressConfig.In_QrCodePhotoRequest.Address,
  1095. addressConfig.In_ScrewTeachExe.Address,
  1096. addressConfig.In_PickINC.Address,
  1097. };
  1098. for (int i = 0; i < 10; i++)
  1099. {
  1100. monitorNodeIds.Add(string.Format(addressConfig.In_MesCheck.Address, i));
  1101. }
  1102. //订阅PLC地址变化
  1103. plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger);
  1104. }
  1105. /// <summary>
  1106. /// 写入点位信息给PLC
  1107. /// </summary>
  1108. /// <returns></returns>
  1109. public async Task WritePositionToPlcAsync()
  1110. {
  1111. var addressConfig = _configService.GetPlcAddresses();
  1112. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1113. if (plc == null || !plc.IsConnected) return;
  1114. var current = _productService.GetCurrentProduct();
  1115. if (current == null) return;
  1116. if (current.PickCameraPoints != null && current.PickCameraPoints.Count > 0)
  1117. {
  1118. foreach (var item in current.PickCameraPoints)
  1119. {
  1120. await item.WriteToPlcAddress(addressConfig.Out_PickCamera, plc);
  1121. }
  1122. }
  1123. if (current.PickPoints != null && current.PickPoints.Count > 0)
  1124. {
  1125. foreach (var item in current.PickPoints)
  1126. {
  1127. await item.WriteToPlcAddress(addressConfig.Out_Pick, plc);
  1128. }
  1129. }
  1130. if (current.SecPosCameraPoints != null && current.SecPosCameraPoints.Count > 0)
  1131. {
  1132. foreach (var item in current.SecPosCameraPoints)
  1133. {
  1134. await item.WriteToPlcAddress(addressConfig.Out_SecPosCamera, plc);
  1135. }
  1136. }
  1137. if (current.ScrewCameraPoints != null && current.ScrewCameraPoints.Count > 0)
  1138. {
  1139. foreach (var item in current.ScrewCameraPoints)
  1140. {
  1141. await item.WriteToPlcAddress(addressConfig.Out_ScrewCamera, plc);
  1142. }
  1143. }
  1144. if (current.ScrewPoints != null && current.ScrewPoints.Count > 0)
  1145. {
  1146. foreach (var item in current.ScrewPoints)
  1147. {
  1148. await item.WriteToPlcAddressEx(addressConfig.Out_Screw, plc);
  1149. }
  1150. await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)current.ScrewPoints.Count);
  1151. }
  1152. if (current.CheckCameraPoints != null && current.CheckCameraPoints.Count > 0)
  1153. {
  1154. foreach (var item in current.CheckCameraPoints)
  1155. {
  1156. await item.WriteToPlcAddress(addressConfig.Out_CheckCamera, plc);
  1157. }
  1158. }
  1159. if (current.QrCodePoints != null && current.QrCodePoints.Count > 0)
  1160. {
  1161. foreach (var item in current.QrCodePoints)
  1162. {
  1163. await item.WriteToPlcAddress(addressConfig.Out_QrCodeCamera, plc);
  1164. }
  1165. }
  1166. }
  1167. PointF[] DowmCameraResults = new PointF[10];
  1168. PointF[] UpCameraPutResults = new PointF[10];
  1169. bool _LastDowmCameraExe = false;
  1170. bool _LastScrewTeachExe = false;
  1171. bool _LastUpCameraPickExe = false;
  1172. bool _LastUpCameraPutExe = false;
  1173. bool _LastUPCameracheckExe = false;
  1174. bool _LastFixedCameraPickExe = false;
  1175. bool _LastFixedCameraPutExe = false;
  1176. bool _LastFixedCameracheckExe = false;
  1177. Int16 _LastWorkStart = 0;
  1178. Int16 _LastWorkDone = 0;
  1179. Int16 _LastRequestPosition = 0;
  1180. Int16 _LastQrCodePhotoRequest = 0;
  1181. Int16[] _LastMesCheck = new Int16[10];
  1182. Int16 _LastPickINC = 0;
  1183. DateTime[] _LastMesCheckTime = new DateTime[10];
  1184. /// <summary>
  1185. /// PLC命令触发时
  1186. /// </summary>
  1187. /// <param name="tuple"></param>
  1188. private async void PlcCommandTrigger((string key, string nodeId, object value) tuple)
  1189. {
  1190. try
  1191. {
  1192. if (tuple.key != "AutoSensor")
  1193. {
  1194. return;
  1195. }
  1196. var addressConfig = _configService.GetPlcAddresses();
  1197. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1198. if (plc == null || !plc.IsConnected) return;
  1199. // 获取当前产品
  1200. var currentProduct = _productService.GetCurrentProduct();
  1201. if (currentProduct == null)
  1202. {
  1203. return;
  1204. }
  1205. //获取产品编码
  1206. _productService.CurrentProductCode = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 0));
  1207. //如果产品编码为空,则以当前的时间戳作为编码
  1208. if (string.IsNullOrEmpty(_productService.CurrentProductCode))
  1209. {
  1210. _productService.CurrentProductCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
  1211. }
  1212. // 触发下相机拍照
  1213. if (addressConfig.In_DowmCameraExe.Address.Contains(tuple.nodeId))
  1214. {
  1215. if (tuple.value is bool state)
  1216. {
  1217. if (_LastDowmCameraExe != state)
  1218. {
  1219. _LastDowmCameraExe = state;
  1220. }
  1221. else
  1222. {
  1223. return;
  1224. }
  1225. if (state)
  1226. {
  1227. SendTaskMessage(Lang.触发下相机拍照, MessageLevel.Debug);
  1228. //相机的编号
  1229. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_DowmCameraNum.Address);
  1230. SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
  1231. // 获取流程
  1232. var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
  1233. if (process == null)
  1234. {
  1235. SendTaskMessage(string.Format(Lang.固定向上相机1视觉流程流程ID0, currentProduct.FixedUpCamera1ProcedureId), MessageLevel.Alarm);
  1236. await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
  1237. return;
  1238. }
  1239. // 获取机器人当前坐标
  1240. var robot = _robotService.GetAllRobots().FirstOrDefault();
  1241. if (robot == null)
  1242. {
  1243. SendTaskMessage(Lang.未找到机器人无法执行上相机锁附组装拍照视觉任务, MessageLevel.Alarm);
  1244. await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
  1245. return;
  1246. }
  1247. var currentPosition = robot.GetRobotPos();
  1248. // 执行视觉任务
  1249. var _cts = new CancellationTokenSource();
  1250. ImageParameters imgPara = new ImageParameters();
  1251. imgPara.SNCode = productSn;
  1252. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, null, _cts.Token, cameraIndex, null, imgPara);
  1253. if (visionResult.IsSucceed)
  1254. {
  1255. //披头偏差
  1256. float offsetX = (float)(visionResult.X - currentPosition.X);
  1257. float offsetY = (float)(visionResult.Y - currentPosition.Y);
  1258. DowmCameraResults[cameraIndex] = new PointF(offsetX, offsetY);
  1259. await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
  1260. return;
  1261. }
  1262. else
  1263. {
  1264. await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
  1265. return;
  1266. }
  1267. }
  1268. else
  1269. {
  1270. SendTaskMessage(Lang.触发下相机拍照信号已关闭, MessageLevel.Alarm);
  1271. await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)0);
  1272. }
  1273. }
  1274. }
  1275. // 触发下相机拍照披头
  1276. if (addressConfig.In_ScrewTeachExe.Address.Contains(tuple.nodeId))
  1277. {
  1278. if (tuple.value is bool state)
  1279. {
  1280. if (_LastScrewTeachExe != state)
  1281. {
  1282. _LastScrewTeachExe = state;
  1283. }
  1284. else
  1285. {
  1286. return;
  1287. }
  1288. if (state)
  1289. {
  1290. SendTaskMessage(Lang.触发下相机拍照, MessageLevel.Debug);
  1291. //相机的编号
  1292. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_DowmCameraNum.Address);
  1293. SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
  1294. // 获取流程
  1295. var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
  1296. if (process == null)
  1297. {
  1298. SendTaskMessage(string.Format(Lang.固定向上相机1视觉流程流程ID0, currentProduct.FixedUpCamera1ProcedureId), MessageLevel.Alarm);
  1299. await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
  1300. return;
  1301. }
  1302. // 获取机器人当前坐标
  1303. var robot = _robotService.GetAllRobots().FirstOrDefault();
  1304. if (robot == null)
  1305. {
  1306. SendTaskMessage(Lang.未找到机器人无法执行上相机锁附组装拍照视觉任务, MessageLevel.Alarm);
  1307. await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
  1308. return;
  1309. }
  1310. var currentPosition = robot.GetRobotPos();
  1311. // 执行视觉任务
  1312. var _cts = new CancellationTokenSource();
  1313. ImageParameters imgPara = new ImageParameters();
  1314. imgPara.SNCode = productSn;
  1315. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, null, _cts.Token, cameraIndex, null, imgPara);
  1316. if (visionResult.IsSucceed)
  1317. {
  1318. //披头偏差
  1319. float offsetX = (float)(visionResult.X - currentPosition.X);
  1320. float offsetY = (float)(visionResult.Y - currentPosition.Y);
  1321. DowmCameraResults[cameraIndex] = new PointF(offsetX, offsetY);
  1322. await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)1);
  1323. return;
  1324. }
  1325. else
  1326. {
  1327. await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
  1328. return;
  1329. }
  1330. }
  1331. else
  1332. {
  1333. SendTaskMessage(Lang.触发下相机拍照信号已关闭, MessageLevel.Alarm);
  1334. await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)0);
  1335. }
  1336. }
  1337. }
  1338. // 触发上相机取料拍照
  1339. else if (addressConfig.In_UpCameraPickExe.Address.Contains(tuple.nodeId))
  1340. {
  1341. if (tuple.value is bool state)
  1342. {
  1343. if (_LastUpCameraPickExe != state)
  1344. {
  1345. _LastUpCameraPickExe = state;
  1346. }
  1347. else
  1348. {
  1349. return;
  1350. }
  1351. if (state)
  1352. {
  1353. SendTaskMessage(Lang.触发上相机取料拍照, MessageLevel.Debug);
  1354. //相机的编号
  1355. //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPickNum.Address);
  1356. await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)1);
  1357. }
  1358. else
  1359. {
  1360. SendTaskMessage(Lang.触发上相机取料拍照信号已关闭, MessageLevel.Alarm);
  1361. await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)0);
  1362. }
  1363. }
  1364. }
  1365. // 上相机锁附/组装拍照
  1366. else if (addressConfig.In_UpCameraPutExe.Address.Contains(tuple.nodeId))
  1367. {
  1368. if (tuple.value is bool state)
  1369. {
  1370. if (_LastUpCameraPutExe != state)
  1371. {
  1372. _LastUpCameraPutExe = state;
  1373. }
  1374. else
  1375. {
  1376. return;
  1377. }
  1378. if (state)
  1379. {
  1380. SendTaskMessage(Lang.触发上相机锁附组装拍照, MessageLevel.Debug);
  1381. //相机的编号
  1382. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPutNum.Address);
  1383. SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
  1384. //视觉流程ID
  1385. Guid procedureId = currentProduct.MoveDownCameraLockPhotoProcedureId;
  1386. //获取锁付拍照的点位
  1387. var pos = currentProduct.ScrewCameraPoints.FirstOrDefault(p => p.Number == cameraIndex);
  1388. if (pos != null)
  1389. {
  1390. procedureId = pos.VisionProcessID;
  1391. }
  1392. // 获取流程
  1393. var process = _productService.GetCurrentProductProcedureModelById(procedureId);
  1394. if (process == null)
  1395. {
  1396. SendTaskMessage(string.Format(Lang.未找到上相机锁附组装拍照对应的视觉流程流程ID0, procedureId), MessageLevel.Alarm);
  1397. await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
  1398. return;
  1399. }
  1400. // 获取机器人当前坐标
  1401. var robot = _robotService.GetAllRobots().FirstOrDefault();
  1402. if (robot == null)
  1403. {
  1404. SendTaskMessage(Lang.未找到机器人无法执行上相机锁附组装拍照视觉任务, MessageLevel.Alarm);
  1405. await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
  1406. return;
  1407. }
  1408. var currentPosition = robot.GetRobotPos();
  1409. // 执行视觉任务
  1410. var _cts = new CancellationTokenSource();
  1411. ImageParameters imgPara = new ImageParameters();
  1412. imgPara.SNCode = productSn;
  1413. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, cameraIndex, null, imgPara);
  1414. if (visionResult.IsSucceed)
  1415. {
  1416. //是拍一个锁一个还是拍两个点锁所有
  1417. var systemConfig = _configService.GetSystemConfiguration();
  1418. //拍1打1
  1419. if (systemConfig.WorkMode == 1)
  1420. {
  1421. UpCameraPutResults[1] = new PointF((float)visionResult.X, (float)visionResult.Y);
  1422. }
  1423. else
  1424. {
  1425. UpCameraPutResults[cameraIndex] = new PointF((float)visionResult.X, (float)visionResult.Y);
  1426. }
  1427. await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
  1428. }
  1429. else
  1430. {
  1431. await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
  1432. }
  1433. }
  1434. else
  1435. {
  1436. SendTaskMessage(Lang.触发上相机锁附组装拍照信号已关闭, MessageLevel.Alarm);
  1437. await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)0);
  1438. }
  1439. }
  1440. }
  1441. // 上相机检测拍照
  1442. else if (addressConfig.In_UPCameracheckExe.Address.Contains(tuple.nodeId))
  1443. {
  1444. if (tuple.value is bool state)
  1445. {
  1446. if (_LastUPCameracheckExe != state)
  1447. {
  1448. _LastUPCameracheckExe = state;
  1449. }
  1450. else
  1451. {
  1452. return;
  1453. }
  1454. if (state)
  1455. {
  1456. SendTaskMessage(Lang.触发上相机检测拍照, MessageLevel.Debug);
  1457. //相机的编号
  1458. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UPCameracheckNum.Address);
  1459. SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
  1460. //视觉流程ID
  1461. Guid procedureId = Guid.Empty;
  1462. //获取锁付拍照的点位
  1463. var pos = currentProduct.CheckCameraPoints.FirstOrDefault(p => p.Number == cameraIndex);
  1464. if (pos != null)
  1465. {
  1466. procedureId = pos.VisionProcessID;
  1467. }
  1468. // 获取流程
  1469. var process = _productService.GetCurrentProductProcedureModelById(procedureId);
  1470. if (process == null)
  1471. {
  1472. SendTaskMessage(string.Format("未找到点位:{0}的视觉流程:{1}", cameraIndex, procedureId), MessageLevel.Alarm);
  1473. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
  1474. return;
  1475. }
  1476. // 执行视觉任务
  1477. var _cts = new CancellationTokenSource();
  1478. ImageParameters imgPara = new ImageParameters();
  1479. imgPara.SNCode = productSn;
  1480. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, null, _cts.Token, cameraIndex, null, imgPara);
  1481. if (visionResult.IsSucceed)
  1482. {
  1483. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
  1484. SendTaskMessage($"点位{cameraIndex}检测OK", MessageLevel.Debug);
  1485. }
  1486. else
  1487. {
  1488. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
  1489. SendTaskMessage($"点位{cameraIndex}检测NG", MessageLevel.Error);
  1490. }
  1491. }
  1492. else
  1493. {
  1494. SendTaskMessage(Lang.触发上相机检测拍照信号已关闭, MessageLevel.Alarm);
  1495. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)0);
  1496. }
  1497. }
  1498. }
  1499. // 固定相机取料拍照
  1500. else if (addressConfig.In_FixedCameraPickExe.Address.Contains(tuple.nodeId))
  1501. {
  1502. if (tuple.value is bool state)
  1503. {
  1504. if (_LastFixedCameraPickExe != state)
  1505. {
  1506. _LastFixedCameraPickExe = state;
  1507. }
  1508. else
  1509. {
  1510. return;
  1511. }
  1512. if (state)
  1513. {
  1514. SendTaskMessage(Lang.触发固定相机取料拍照, MessageLevel.Debug);
  1515. //相机的编号
  1516. //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameraPickNum.Address);
  1517. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  1518. }
  1519. else
  1520. {
  1521. SendTaskMessage(Lang.触发固定相机取料拍照信号已关闭, MessageLevel.Alarm);
  1522. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)0);
  1523. }
  1524. }
  1525. }
  1526. // 固定相机锁附/组装拍照
  1527. else if (addressConfig.In_FixedCameraPutExe.Address.Contains(tuple.nodeId))
  1528. {
  1529. if (tuple.value is bool state)
  1530. {
  1531. if (_LastFixedCameraPutExe != state)
  1532. {
  1533. _LastFixedCameraPutExe = state;
  1534. }
  1535. else
  1536. {
  1537. return;
  1538. }
  1539. if (state)
  1540. {
  1541. SendTaskMessage(Lang.触发固定相机锁附组装拍照, MessageLevel.Debug);
  1542. //相机的编号
  1543. //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameraPutNum.Address);
  1544. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)1);
  1545. }
  1546. else
  1547. {
  1548. SendTaskMessage(Lang.触发固定相机锁附组装拍照信号已关闭, MessageLevel.Alarm);
  1549. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)0);
  1550. }
  1551. }
  1552. }
  1553. // 固定相机检测拍照
  1554. else if (addressConfig.In_FixedCameracheckExe.Address.Contains(tuple.nodeId))
  1555. {
  1556. if (tuple.value is bool state)
  1557. {
  1558. if (_LastFixedCameracheckExe != state)
  1559. {
  1560. _LastFixedCameracheckExe = state;
  1561. }
  1562. else
  1563. {
  1564. return;
  1565. }
  1566. if (state)
  1567. {
  1568. SendTaskMessage(Lang.触发固定相机检测拍照, MessageLevel.Debug);
  1569. //相机的编号
  1570. //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
  1571. await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
  1572. }
  1573. else
  1574. {
  1575. SendTaskMessage(Lang.触发固定相机检测拍照信号已关闭, MessageLevel.Alarm);
  1576. await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)0);
  1577. }
  1578. }
  1579. }
  1580. // 开始锁付
  1581. else if (addressConfig.In_WorkStart.Address.Contains(tuple.nodeId))
  1582. {
  1583. if (tuple.value is Int16 state)
  1584. {
  1585. if (_LastWorkStart != state)
  1586. {
  1587. _LastWorkStart = state;
  1588. }
  1589. else
  1590. {
  1591. return;
  1592. }
  1593. if (state == 1)
  1594. {
  1595. SendTaskMessage(Lang.收到开始锁付信号, MessageLevel.Debug);
  1596. StartScrewTime = DateTime.Now;
  1597. //位置编号
  1598. Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
  1599. SendTaskMessage(string.Format(Lang.编号0, positionIndex), MessageLevel.Info);
  1600. // 开始采集压力值
  1601. StartPressureCollection(currentProduct.Name, _productService.CurrentProductCode, positionIndex);
  1602. }
  1603. else
  1604. {
  1605. SendTaskMessage(Lang.开始锁付信号已关闭, MessageLevel.Alarm);
  1606. // 关闭时的处理(如需)可放在这里
  1607. }
  1608. }
  1609. }
  1610. // 停止锁付
  1611. else if (addressConfig.In_WorkDone.Address.Contains(tuple.nodeId))
  1612. {
  1613. if (tuple.value is Int16 state)
  1614. {
  1615. if (_LastWorkDone != state)
  1616. {
  1617. _LastWorkDone = state;
  1618. }
  1619. else
  1620. {
  1621. return;
  1622. }
  1623. if (state == 1 || state == 2)
  1624. {
  1625. if (TorqueStatus)
  1626. {
  1627. }
  1628. SendTaskMessage(Lang.收到停止锁付信号, MessageLevel.Debug);
  1629. //位置编号
  1630. Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
  1631. SendTaskMessage(string.Format(Lang.编号0, positionIndex), MessageLevel.Info);
  1632. //获取当前锁付点
  1633. var screwPoint = currentProduct.ScrewPoints.FirstOrDefault(p => p.Number == positionIndex);
  1634. //获取当前的机器人点位
  1635. var robot = _robotService.GetAllRobots().FirstOrDefault();
  1636. var currentPosition = robot.GetRobotPos();
  1637. //读取压力值
  1638. float pressure = plc.ReadNode<float>(addressConfig.In_PressureValue.Address);
  1639. //当前用户名
  1640. string currentUserName = _systemDatabaseService.GetCurrentUser().UserName;
  1641. //吸嘴最后一次的记录
  1642. var nozzleRecord = await _systemDatabaseService.GetLatestNozzleChangeRecordAsync();
  1643. //最后一次的吸嘴编号
  1644. string nozzleNumber = nozzleRecord != null ? nozzleRecord.NozzleBatchNumber : "N/A";
  1645. //披头最后一次的记录
  1646. var headRecord = await _systemDatabaseService.GetLatestHeadChangeRecordAsync();
  1647. //最后一次的披头编号
  1648. string headNumber = headRecord != null ? headRecord.HeadBatchNumber : "N/A";
  1649. var cdata = _configService.GetCTQDataInfo();//获取ctq数据参数
  1650. await Task.Delay(60);
  1651. //获取电批结果
  1652. bool isSucced = ScrewDriver.GetData();
  1653. LockResult lockResult = new LockResult();
  1654. lockResult.ScrewdriverGetDataSucceed = isSucced;
  1655. lockResult.Number = positionIndex;
  1656. lockResult.LockPassed = ScrewDriver.Success;
  1657. lockResult.ProductName = currentProduct.Name;
  1658. lockResult.ProductNumber = _productService.CurrentProductCode;
  1659. lockResult.LockTurns = (float)ScrewDriver.Truns;
  1660. lockResult.LockTorque = (float)ScrewDriver.TorqueValue;
  1661. lockResult.LockDuration = (float)ScrewDriver.FinalTime;
  1662. lockResult.ScrewdriverProgramNumber = ScrewDriver.ProgramNumber;
  1663. lockResult.ResultDetails = ScrewDriver.ErrorInfo;
  1664. lockResult.Pressure = pressure;
  1665. lockResult.TargetTorqueUpperLimit = ScrewDriver.TargetTorqueUpperLimit;
  1666. lockResult.TargetTorqueLowerLimit = ScrewDriver.TargetTorqueLowerLimit;
  1667. lockResult.TargetTurnsUpperLimit = ScrewDriver.TargetTurnsUpperLimit / 360;
  1668. lockResult.TargetTurnsLowerLimit = ScrewDriver.TargetTurnsLowerLimit / 360;
  1669. lockResult.TargetLockSpeed = ScrewDriver.TargetLockSpeed;
  1670. lockResult.PositionX = currentPosition.X;
  1671. lockResult.PositionY = currentPosition.Y;
  1672. lockResult.StartPositionZ = screwPoint.Z_Position_Start;
  1673. lockResult.EndPositionZ = currentPosition.Z;
  1674. lockResult.LockDescentSpeed = screwPoint.Z_Velocity_Stop;
  1675. lockResult.FeederNumber = screwPoint != null ? screwPoint.Feeder : 0;
  1676. lockResult.NozzleNumber = nozzleNumber;
  1677. lockResult.HeadNumber = headNumber;
  1678. lockResult.OperatorName = currentUserName;
  1679. lockResult.ProductImagePath = "";
  1680. lockResult.WaveDatas = ScrewDriver.WaveDatas;
  1681. //获取系统参数
  1682. var systemConfig = _configService.GetSystemConfiguration();
  1683. //判断是否保存锁付曲线
  1684. if (systemConfig.IsSaveScrewCurve)
  1685. {
  1686. //锁付曲线的保存路径为:systemConfig.ScrewCurvePath//年月//年月日//配方名//产品SN//产品SN+螺丝索引
  1687. string datePath = DateTime.Now.ToString("yyyy-MM") + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\";
  1688. string dirPath = System.IO.Path.Combine(systemConfig.ScrewCurvePath, datePath, currentProduct.Name, lockResult.ProductNumber);
  1689. if (!Directory.Exists(dirPath))
  1690. {
  1691. Directory.CreateDirectory(dirPath);
  1692. }
  1693. string curveFileName = $"{lockResult.ProductNumber}-{lockResult.Number}.png";
  1694. //锁付CSV保存路径
  1695. string curveFileFullPath = System.IO.Path.Combine(dirPath, $"{lockResult.ProductNumber}-{lockResult.Number}.csv");
  1696. //锁付曲线保存路径
  1697. lockResult.LockCurveImagePath = System.IO.Path.Combine(dirPath, curveFileName);
  1698. var _ = lockResult.SaveToCsvAsync(curveFileFullPath);
  1699. }
  1700. if (lockResult.Number == 1)
  1701. {
  1702. torqueList.Clear();
  1703. pressureList.Clear();
  1704. turnList.Clear();
  1705. }
  1706. torqueList.Add($"{lockResult.Number}-{lockResult.LockTorque:F2}");
  1707. pressureList.Add($"{lockResult.Number}-{lockResult.Pressure:F2}");
  1708. turnList.Add($"{lockResult.Number}-{lockResult.LockTurns:F2}");
  1709. SendTaskMessage($"螺丝序号:{lockResult.Number},扭力:{lockResult.LockTorque},压力:{lockResult.Pressure},圈数:{lockResult.LockTurns}", MessageLevel.Info);
  1710. lockResultsAll.Add(lockResult);
  1711. App.Current.Dispatcher.Invoke(() =>
  1712. {
  1713. _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult);
  1714. });
  1715. //记录锁付结果至数据库
  1716. await _systemDatabaseService.RecordLockResultAsync(lockResult);
  1717. //披头数量+1
  1718. NumStatistics.HeaderNum = await _systemDatabaseService.IncrementLatestHeadLockCountAsync(currentUserName);
  1719. //吸嘴数量+1
  1720. NumStatistics.NozzleNum = await _systemDatabaseService.IncrementLatestNozzleLockCountAsync(currentUserName);
  1721. await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
  1722. // 停止采集压力并保存
  1723. await StopAndSavePressureCollectionAsync(currentProduct.Name, _productService.CurrentProductCode, positionIndex);
  1724. try
  1725. {
  1726. #region 数据
  1727. DFC.Clear();
  1728. bool torqueRes, turnRes, pressureRes;
  1729. if (lockResult.LockTorque >= lockResult.TargetTorqueLowerLimit && lockResult.LockTorque <= lockResult.TargetTorqueUpperLimit)
  1730. {
  1731. torqueRes = true;
  1732. }
  1733. else torqueRes = false;
  1734. if (lockResult.Pressure >= cdata.CTQ_LSL_Pressure && lockResult.Pressure <= cdata.CTQ_USL_Pressure)
  1735. {
  1736. pressureRes = true;
  1737. }
  1738. else pressureRes = false;
  1739. if (lockResult.LockTurns >= lockResult.TargetTurnsLowerLimit && lockResult.LockTurns <= lockResult.TargetTurnsUpperLimit)
  1740. {
  1741. turnRes = true;
  1742. }
  1743. else turnRes = false;
  1744. DFC.Add(new DataFormCtq
  1745. {
  1746. PPID = productSn,
  1747. PROCESS_NAME = cdata.PROCESS_NAME,
  1748. PROCESS_START_TIME = StartScrewTime.ToString(),
  1749. CTQ_NAME = "Torque",
  1750. CTQ_VALUE = lockResult.LockTorque,
  1751. CTQ_LSL = lockResult.TargetTorqueLowerLimit,
  1752. CTQ_USL = lockResult.TargetTorqueUpperLimit,
  1753. PROCESS_END_TIME = DateTime.Now.ToString(),
  1754. SUPPLIER_NAME = cdata.SUPPLIER_NAME,
  1755. COMMODITY_TYPE = cdata.COMMODITY_TYPE,
  1756. REVISION = cdata.REVISION,
  1757. WO = cdata.WO,
  1758. MFG_LOT = cdata.MFG_LOT,
  1759. MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
  1760. PROCESS_OUTCOME = torqueRes ? "PASS" : "FAIL",
  1761. PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
  1762. CTQ_UNIT_OF_MEASURE = "kgf.cm",
  1763. ERROR_MESSAGE = torqueRes ? "" : "Torque_Spec OOS"
  1764. });
  1765. DFC.Add(new DataFormCtq
  1766. {
  1767. PPID = productSn,
  1768. PROCESS_NAME = cdata.PROCESS_NAME,
  1769. PROCESS_START_TIME = StartScrewTime.ToString(),
  1770. CTQ_NAME = "Turn",
  1771. CTQ_VALUE = lockResult.LockTurns,
  1772. CTQ_LSL = lockResult.TargetTurnsLowerLimit,
  1773. CTQ_USL = lockResult.TargetTurnsUpperLimit,
  1774. PROCESS_END_TIME = DateTime.Now.ToString(),
  1775. SUPPLIER_NAME = cdata.SUPPLIER_NAME,
  1776. COMMODITY_TYPE = cdata.COMMODITY_TYPE,
  1777. REVISION = cdata.REVISION,
  1778. WO = cdata.WO,
  1779. MFG_LOT = cdata.MFG_LOT,
  1780. MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
  1781. PROCESS_OUTCOME = turnRes ? "PASS" : "FAIL",
  1782. PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
  1783. CTQ_UNIT_OF_MEASURE = "圈",
  1784. ERROR_MESSAGE = turnRes ? "" : "Turn_Spec OOS"
  1785. });
  1786. DFC.Add(new DataFormCtq
  1787. {
  1788. PPID = productSn,
  1789. PROCESS_NAME = cdata.PROCESS_NAME,
  1790. PROCESS_START_TIME = StartScrewTime.ToString(),
  1791. CTQ_NAME = "Pressure",
  1792. CTQ_VALUE = lockResult.Pressure,
  1793. CTQ_LSL = cdata.CTQ_LSL_Pressure,
  1794. CTQ_USL = cdata.CTQ_USL_Pressure,
  1795. PROCESS_END_TIME = DateTime.Now.ToString(),
  1796. SUPPLIER_NAME = cdata.SUPPLIER_NAME,
  1797. COMMODITY_TYPE = cdata.COMMODITY_TYPE,
  1798. REVISION = cdata.REVISION,
  1799. WO = cdata.WO,
  1800. MFG_LOT = cdata.MFG_LOT,
  1801. MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
  1802. PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
  1803. PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
  1804. CTQ_UNIT_OF_MEASURE = "N",
  1805. ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
  1806. });
  1807. foreach (var item in DFC)
  1808. {
  1809. FileHelper.WriteDataToCSV(item);
  1810. }
  1811. #endregion
  1812. }
  1813. catch (Exception ex)
  1814. {
  1815. SendTaskMessage("CTQ数据存储时出错" + ex.Message, MessageLevel.Error);
  1816. }
  1817. }
  1818. else
  1819. {
  1820. SendTaskMessage(Lang.停止锁付信号已关闭, MessageLevel.Alarm);
  1821. }
  1822. }
  1823. }
  1824. // 多相机坐标合并
  1825. else if (addressConfig.In_RequestPosition.Address.Contains(tuple.nodeId))
  1826. {
  1827. if (tuple.value is Int16 state)
  1828. {
  1829. if (_LastRequestPosition != state)
  1830. {
  1831. _LastRequestPosition = state;
  1832. }
  1833. else
  1834. {
  1835. return;
  1836. }
  1837. if (state == 1)
  1838. {
  1839. SendTaskMessage(Lang.收到多相机坐标合并请求开始合并, MessageLevel.Debug);
  1840. //位置编号
  1841. Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
  1842. //是拍一个锁一个还是拍两个点锁所有
  1843. var systemConfig = _configService.GetSystemConfiguration();
  1844. //拍1打1
  1845. if (systemConfig.WorkMode == 1)
  1846. {
  1847. var point = currentProduct.ScrewPoints.FirstOrDefault(p => p.Number == positionIndex);
  1848. if (point == null)
  1849. {
  1850. SendTaskMessage($"点:{positionIndex}不存在", MessageLevel.Info);
  1851. await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
  1852. return;
  1853. }
  1854. point = point.Clone();
  1855. point.X_Position = UpCameraPutResults[1].X + DowmCameraResults[1].X;
  1856. point.Y_Position = UpCameraPutResults[1].Y + DowmCameraResults[1].Y;
  1857. SendTaskMessage($"点:{positionIndex},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
  1858. await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
  1859. }
  1860. //拍1打所有
  1861. else if (systemConfig.WorkMode == 2)
  1862. {
  1863. //根据UpCameraPutResults[]中的索引1、2,和拍照点对应的Local下的坐标,从创建Local坐标系
  1864. PointF worldP1 = new PointF(UpCameraPutResults[1].X, UpCameraPutResults[1].Y);
  1865. PointF worldP2 = new PointF(UpCameraPutResults[2].X, UpCameraPutResults[2].Y);
  1866. PointF localP1 = new PointF(currentProduct.ScrewCameraLocalPos1.X_Position, currentProduct.ScrewCameraLocalPos1.Y_Position);
  1867. PointF localP2 = new PointF(currentProduct.ScrewCameraLocalPos2.X_Position, currentProduct.ScrewCameraLocalPos2.Y_Position);
  1868. CoordinateTransformer local = new CoordinateTransformer(worldP1, worldP2, localP1, localP2);
  1869. for (int i = 0; i < currentProduct.ScrewPoints.Count; i++)
  1870. {
  1871. var localPoint = new PointF(currentProduct.ScrewPoints[i].X_Position + currentProduct.ScrewPoints[i].X_Offset,
  1872. currentProduct.ScrewPoints[i].Y_Position + currentProduct.ScrewPoints[i].Y_Offset);
  1873. var worldPoint = local.ToOldCoord(localPoint.X, localPoint.Y);
  1874. var point = currentProduct.ScrewPoints[i].Clone();
  1875. //锁付点位在Local中已经加了偏移,这里写回PLC时需要将偏移清零,否则写入PLC端时会重复计算偏移
  1876. point.X_Offset = 0;
  1877. point.Y_Offset = 0;
  1878. point.X_Position = (float)worldPoint[0];
  1879. point.Y_Position = (float)worldPoint[1];
  1880. SendTaskMessage($"点:{i},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
  1881. await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
  1882. }
  1883. await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)currentProduct.ScrewPoints.Count);
  1884. }
  1885. await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
  1886. }
  1887. else
  1888. {
  1889. SendTaskMessage(string.Format(Lang.多相机坐标合并请求已结束或被取消state0, state), MessageLevel.Alarm);
  1890. await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)0);
  1891. }
  1892. }
  1893. }
  1894. // PLC请求二维码拍照位置
  1895. else if (addressConfig.In_QrCodePhotoRequest.Address.Contains(tuple.nodeId))
  1896. {
  1897. if (tuple.value is Int16 state)
  1898. {
  1899. if (_LastQrCodePhotoRequest != state)
  1900. {
  1901. _LastQrCodePhotoRequest = state;
  1902. }
  1903. else
  1904. {
  1905. return;
  1906. }
  1907. if (state == 1)
  1908. {
  1909. SendTaskMessage("收到PLC二维码拍照位置请求", MessageLevel.Debug);
  1910. if (currentProduct.QrCodePoints == null || currentProduct.QrCodePoints.Count == 0)
  1911. {
  1912. SendTaskMessage("未找到示教后的二维码拍照点位", MessageLevel.Alarm);
  1913. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
  1914. return;
  1915. }
  1916. var qrpoint = currentProduct.QrCodePoints[0];
  1917. //发送点位
  1918. bool SendSuccess = await qrpoint.WriteToPlcAddress(addressConfig.Out_QrCodeCamera, plc);
  1919. if (SendSuccess)
  1920. {
  1921. SendTaskMessage("二维码拍照点位发送成功", MessageLevel.Alarm);
  1922. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
  1923. Guid qrCodeProcedureId = currentProduct.QrCodeProcedureId;
  1924. if (qrCodeProcedureId == Guid.Empty)
  1925. {
  1926. // 如果没有配置二维码视觉流程,直接返回成功
  1927. SendTaskMessage("未配置二维码视觉流程,跳过扫码", MessageLevel.Info);
  1928. return;
  1929. }
  1930. }
  1931. else
  1932. {
  1933. SendTaskMessage("二维码拍照点位发送失败", MessageLevel.Alarm);
  1934. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
  1935. }
  1936. }
  1937. else
  1938. {
  1939. SendTaskMessage("二维码拍照点位发送信号已关闭", MessageLevel.Alarm);
  1940. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)0);
  1941. }
  1942. }
  1943. }
  1944. // 螺丝供料器螺丝递减
  1945. else if (addressConfig.In_PickINC.Address.Contains(tuple.nodeId))
  1946. {
  1947. if (tuple.value is Int16 state)
  1948. {
  1949. if (_LastPickINC != state)
  1950. {
  1951. _LastPickINC = state;
  1952. }
  1953. else
  1954. {
  1955. return;
  1956. }
  1957. if (state != 0)
  1958. {
  1959. SendTaskMessage($"螺丝供料器...", MessageLevel.Info);
  1960. await plc.WriteNodeAsync(addressConfig.In_PickINC.Address, (Int16)0);
  1961. var feeders = _configService.GetRemainingCountByFeederNumber(state);
  1962. if (state == 1)
  1963. {
  1964. NumStatistics.Feeder1Num = _configService.DecrementScrewCountByFeederNumber(feeders);
  1965. }
  1966. else if (state == 2)
  1967. {
  1968. NumStatistics.Feeder2Num = _configService.DecrementScrewCountByFeederNumber(feeders);
  1969. }
  1970. }
  1971. }
  1972. }
  1973. // 过站检查
  1974. else
  1975. {
  1976. for (int i = 0; i < 10; i++)
  1977. {
  1978. if (string.Format(addressConfig.In_MesCheck.Address, i).Contains(tuple.nodeId))
  1979. {
  1980. if (tuple.value is Int16 state)
  1981. {
  1982. if (_LastMesCheck[i] != state)
  1983. {
  1984. _LastMesCheck[i] = state;
  1985. }
  1986. else
  1987. {
  1988. return;
  1989. }
  1990. string code = "";
  1991. //plc启用的模式
  1992. bool models = plc.ReadNode<bool>(addressConfig.Cam_code_mode.Address);
  1993. if (models && state == 1)
  1994. {
  1995. //拍照读码
  1996. SendTaskMessage(Lang.触发上相机锁附组装拍照, MessageLevel.Debug);
  1997. //相机的编号
  1998. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPutNum.Address);
  1999. SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
  2000. Guid qrCodeProcedureId = currentProduct.QrCodeProcedureId;
  2001. //视觉流程ID
  2002. var qrCodeProcess = _productService.GetCurrentProductProcedureModelById(qrCodeProcedureId);
  2003. if (qrCodeProcess == null)
  2004. {
  2005. SendTaskMessage($"未找到二维码视觉流程,流程ID: {qrCodeProcedureId}", MessageLevel.Alarm);
  2006. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
  2007. return;
  2008. }
  2009. SendTaskMessage($"开始执行二维码扫码视觉流程", MessageLevel.Debug);
  2010. var _cts = new CancellationTokenSource();
  2011. await _remoteCommandService.SetLightBeforePhoto(qrCodeProcess);
  2012. var qrCodeResult = _remoteCommandService.ExecutePhoto(qrCodeProcess, out CogToolBlockTerminalCollection outputCollection);
  2013. if (qrCodeResult && outputCollection.Contains("QR"))
  2014. {
  2015. code = outputCollection["QR"].Value as string;
  2016. if (!string.IsNullOrEmpty(code))
  2017. {
  2018. SendTaskMessage($"二维码扫码成功:{code}", MessageLevel.Info);
  2019. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
  2020. }
  2021. else
  2022. {
  2023. SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
  2024. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
  2025. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
  2026. return;
  2027. }
  2028. }
  2029. else
  2030. {
  2031. code = "";
  2032. SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
  2033. await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
  2034. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
  2035. return;
  2036. }
  2037. }
  2038. else
  2039. {
  2040. code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
  2041. }
  2042. productSn = code;
  2043. //询问mes
  2044. if (state == 1)
  2045. {
  2046. //这里缺少从MES获取产品配方的内容,需要补充
  2047. _LastMesCheckTime[i] = DateTime.UtcNow;
  2048. LogHelper.WriteLogMes($"【mes开始QUERY】");
  2049. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  2050. (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  2051. if (i == 0)
  2052. {
  2053. SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
  2054. }
  2055. else
  2056. {
  2057. SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
  2058. }
  2059. if (isSuccess)
  2060. {
  2061. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2062. await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
  2063. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
  2064. LogHelper.WriteLogMes($"询问mes成功");
  2065. SendTaskMessage($"询问mes成功", MessageLevel.Debug);
  2066. }
  2067. else
  2068. {
  2069. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2070. await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
  2071. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
  2072. LogHelper.WriteLogMes($"询问mes失败");
  2073. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  2074. }
  2075. LogHelper.WriteLogMes($"【mes结束QUERY】");
  2076. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  2077. }
  2078. // 上传本站数据
  2079. else if (state == 2)
  2080. {
  2081. SendTaskMessage($"收到{i}上传本站数据请求...", MessageLevel.Debug);
  2082. //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
  2083. if (i == 0)
  2084. {
  2085. CTtime = DateTime.UtcNow.Subtract(_LastMesCheckTime[i]).TotalSeconds;
  2086. }
  2087. //读取产品结果
  2088. Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address, i));
  2089. //目前只记录当前站
  2090. if (i == 0)
  2091. await _systemDatabaseService.RecordProductionAsync(new ProductionRecord()
  2092. {
  2093. ProductName = currentProduct.Name,
  2094. ProductCode = code,
  2095. DeviceId = i,
  2096. DeviceName = "",
  2097. Category = resultIndex == 1 ? "OK" : "NG",
  2098. Quantity = 1,
  2099. Remark = $"TotalSeconds:{DateTime.UtcNow.Subtract(_LastMesCheckTime[i]).TotalSeconds.ToString("F2")}",
  2100. });
  2101. LogHelper.WriteLogMes($"【mes开始ADD】");
  2102. SendTaskMessage($"mes开始ADD", MessageLevel.Info);
  2103. //上传mes
  2104. string torque = string.Join(",", torqueList);
  2105. string pressure = string.Join(",", pressureList);
  2106. string turn = string.Join(",", turnList);
  2107. (bool isSuccess, string response) = await _mesService.SubmitGetAsync(code, "", torque, pressure, turn, resultIndex == 1 ? true : false, _LastMesCheckTime[i], DateTime.UtcNow);
  2108. if (isSuccess)
  2109. {
  2110. LogHelper.WriteLogMes($"上传mes成功");
  2111. SendTaskMessage($"上传mes成功", MessageLevel.Debug);
  2112. }
  2113. else
  2114. {
  2115. LogHelper.WriteLogMes($"上传mes失败");
  2116. SendTaskMessage($"上传mes失败", MessageLevel.Error);
  2117. }
  2118. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
  2119. WriteProductLog(lockResultsAll, code, CTtime);
  2120. LogHelper.WriteLogMes($"【mes结束ADD】");
  2121. SendTaskMessage($"mes结束ADD", MessageLevel.Info);
  2122. }
  2123. else
  2124. {
  2125. SendTaskMessage($"{i}过站检查信号:state={state},处理为默认状态", MessageLevel.Alarm);
  2126. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)0);
  2127. }
  2128. }
  2129. }
  2130. }
  2131. }
  2132. }
  2133. catch (Exception ex)
  2134. {
  2135. SendTaskMessage(ex.Message, MessageLevel.Error);
  2136. }
  2137. }
  2138. #endregion
  2139. #region 方法
  2140. public void SendTaskMessage(string msg, MessageLevel level)
  2141. {
  2142. App.Current.Dispatcher.Invoke(() =>
  2143. {
  2144. _eventAggregator.GetEvent<TaskMessageNotification>().Publish(new Models.MessageStruct() { Message = msg, level = level });
  2145. });
  2146. }
  2147. #region Pressure collection helpers
  2148. /// <summary>
  2149. /// 开始采集压力值
  2150. /// </summary>
  2151. /// <param name="productName">配方名称</param>
  2152. /// <param name="productCode">产品编号</param>
  2153. /// <param name="positionIndex">锁付点编号</param>
  2154. private void StartPressureCollection(string productName, string productCode, int positionIndex)
  2155. {
  2156. try
  2157. {
  2158. // cancel existing if any
  2159. _pressureCts?.Cancel();
  2160. _pressureTimeoutCts?.Cancel();
  2161. _pressureLinkedCts?.Dispose();
  2162. _pressureSamples?.Clear();
  2163. _pressureCts = new CancellationTokenSource();
  2164. _pressureTimeoutCts = new CancellationTokenSource();
  2165. // timeout after configured seconds
  2166. _pressureTimeoutCts.CancelAfter(TimeSpan.FromSeconds(_pressureMaxDurationSeconds));
  2167. // link tokens so either stop or timeout cancels
  2168. _pressureLinkedCts = CancellationTokenSource.CreateLinkedTokenSource(_pressureCts.Token, _pressureTimeoutCts.Token);
  2169. var token = _pressureLinkedCts.Token;
  2170. var addressConfig = _configService.GetPlcAddresses();
  2171. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  2172. if (plc == null || !plc.IsConnected) return;
  2173. Task.Run(async () =>
  2174. {
  2175. SendTaskMessage($"Pressure collection started for position {positionIndex}", MessageLevel.Debug);
  2176. while (!token.IsCancellationRequested)
  2177. {
  2178. try
  2179. {
  2180. float pressure = plc.ReadNode<float>(addressConfig.In_PressureValue.Address);
  2181. lock (_pressureSamples)
  2182. {
  2183. _pressureSamples.Add((DateTime.Now, pressure));
  2184. }
  2185. }
  2186. catch (Exception ex)
  2187. {
  2188. LogHelper.WriteLogError("采集压力值时出错", ex);
  2189. }
  2190. await Task.Delay(_pressureSampleIntervalMs);
  2191. }
  2192. // if cancelled due to timeout
  2193. if (_pressureTimeoutCts.IsCancellationRequested && !_pressureCts.IsCancellationRequested)
  2194. {
  2195. SendTaskMessage("Pressure collection timed out, saving collected data.", MessageLevel.Alarm);
  2196. await StopAndSavePressureCollectionAsync(productName, productCode, positionIndex);
  2197. }
  2198. }, token);
  2199. }
  2200. catch (Exception ex)
  2201. {
  2202. LogHelper.WriteLogError("StartPressureCollection error", ex);
  2203. }
  2204. }
  2205. /// <summary>
  2206. /// 停止采集并保存压力数据
  2207. /// </summary>
  2208. /// <param name="productName"></param>
  2209. /// <param name="productCode"></param>
  2210. /// <param name="positionIndex"></param>
  2211. /// <returns></returns>
  2212. private async Task StopAndSavePressureCollectionAsync(string productName, string productCode, int positionIndex)
  2213. {
  2214. try
  2215. {
  2216. // cancel sampling
  2217. _pressureCts?.Cancel();
  2218. // allow worker to observe cancel
  2219. await Task.Delay(50);
  2220. List<(DateTime Timestamp, float Value)> snapshot;
  2221. lock (_pressureSamples)
  2222. {
  2223. snapshot = new List<(DateTime, float)>(_pressureSamples);
  2224. }
  2225. if (snapshot.Count == 0)
  2226. {
  2227. SendTaskMessage("No pressure samples collected.", MessageLevel.Info);
  2228. return;
  2229. }
  2230. // save to file under configured path
  2231. try
  2232. {
  2233. //获取系统参数
  2234. var systemConfig = _configService.GetSystemConfiguration();
  2235. //判断是否保存锁付曲线
  2236. if (systemConfig.IsSaveScrewCurve)
  2237. {
  2238. string basePath = systemConfig?.ScrewCurvePath ?? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
  2239. string datePath = DateTime.Now.ToString("yyyy-MM") + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\";
  2240. string dirPath = Path.Combine(basePath, datePath, productName ?? "UnknownProduct", productCode ?? DateTime.Now.ToString("yyyyMMddHHmmssfff"));
  2241. if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
  2242. string fileName = $"pressure-{productCode}-{positionIndex}-{DateTime.Now.ToString("HHmmss")}.csv";
  2243. string fullPath = Path.Combine(dirPath, fileName);
  2244. var sb = new StringBuilder();
  2245. sb.AppendLine("Timestamp,Value");
  2246. foreach (var s in snapshot)
  2247. {
  2248. sb.AppendLine($"{s.Timestamp:O},{s.Value}");
  2249. }
  2250. File.WriteAllText(fullPath, sb.ToString());
  2251. SendTaskMessage($"Pressure samples saved to {fullPath}", MessageLevel.Debug);
  2252. }
  2253. }
  2254. catch (Exception ex)
  2255. {
  2256. LogHelper.WriteLogError("保存压力采样文件时出错", ex);
  2257. SendTaskMessage("保存压力采样文件时出错: " + ex.Message, MessageLevel.Error);
  2258. }
  2259. }
  2260. catch (Exception ex)
  2261. {
  2262. LogHelper.WriteLogError("StopAndSavePressureCollectionAsync error", ex);
  2263. }
  2264. finally
  2265. {
  2266. try
  2267. {
  2268. _pressureLinkedCts?.Cancel();
  2269. _pressureLinkedCts?.Dispose();
  2270. _pressureTimeoutCts?.Dispose();
  2271. _pressureCts?.Dispose();
  2272. _pressureSamples?.Clear();
  2273. }
  2274. catch { }
  2275. }
  2276. }
  2277. #endregion
  2278. private async void DoYieldTime(object state)
  2279. {
  2280. try
  2281. {
  2282. //获取当前产品
  2283. var currentproduct = _productService.GetCurrentProduct();
  2284. if (currentproduct == null) return;
  2285. TotalQuantity = await _systemDatabaseService.GetOverallProductionAsync(currentproduct.Name);
  2286. TotalQuantityToday = await _systemDatabaseService.GetTodayProductionAsync(currentproduct.Name);
  2287. CurrentUPH = await _systemDatabaseService.GetLastHourProductionAsync(currentproduct.Name);
  2288. }
  2289. catch (Exception)
  2290. {
  2291. }
  2292. }
  2293. #region vm启动检测
  2294. /// <summary>
  2295. /// 杀死所有VM有关进程
  2296. /// </summary>
  2297. public void KillVMProcess()
  2298. {
  2299. KillProcess("VisionMasterServerApp");
  2300. KillProcess("VisionMaster");
  2301. KillProcess("VmModuleProxy.exe");
  2302. KillProcess("vServerApp.exe");
  2303. }
  2304. /// <summary>
  2305. /// 杀死指定进程名的进程
  2306. /// </summary>
  2307. /// <param name="strKillName"></param>
  2308. public void KillProcess(string strKillName)
  2309. {
  2310. foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
  2311. {
  2312. if (p.ProcessName.Contains(strKillName))
  2313. {
  2314. try
  2315. {
  2316. p.Kill();
  2317. p.WaitForExit();
  2318. }
  2319. catch (Exception ex)
  2320. {
  2321. LogHelper.WriteLogError(string.Format(Lang.杀死进程0时失败, strKillName), ex);
  2322. }
  2323. }
  2324. }
  2325. }
  2326. #endregion
  2327. #region 产品锁付记录进行存储
  2328. /// <summary>
  2329. /// 产品锁付记录进行存储
  2330. /// </summary>
  2331. /// <param name="result">结果</param>
  2332. public void WriteProductLog(List<LockResult> lockResults, string rfid, double ct)
  2333. {
  2334. try
  2335. {
  2336. string result = "";//产品的总结果
  2337. foreach (var item in lockResults)
  2338. {
  2339. result = "OK";
  2340. if (!item.LockPassed)
  2341. {
  2342. result = "NG";
  2343. break;
  2344. }
  2345. }
  2346. DateTime dt = DateTime.Now;
  2347. int number = lockResults.Count;//螺丝数量
  2348. string path = $"D:\\Data\\生产数据\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}.csv";
  2349. StringBuilder sb = new StringBuilder();
  2350. //具体的ct需要优化
  2351. sb.Append($"{dt.ToString("yyyy-MM-dd HH:mm:ss")},{lockResults[0].ProductName},{Math.Round(ct, 3)},{rfid},{result},{lockResults[number - 1].NozzleNumber},{lockResults[number - 1].HeadNumber},");
  2352. foreach (var item in lockResults)
  2353. {
  2354. try
  2355. {
  2356. sb.Append($"{item.LockPassed},{item.ResultDetails},{item.LockTorque},{item.TargetTorqueUpperLimit},{item.TargetTorqueLowerLimit},{item.LockTurns},{item.TargetTurnsUpperLimit},{item.TargetTurnsLowerLimit},{item.Pressure},{item.PositionX},{item.PositionY},{item.StartPositionZ},{item.EndPositionZ},{item.LockDescentSpeed},");
  2357. }
  2358. catch (Exception)
  2359. {
  2360. sb.Append($",,,,,,,,,,,,,,");
  2361. }
  2362. }
  2363. //========================
  2364. if (!Directory.Exists(Path.GetDirectoryName(path))) //判断文件夹是否
  2365. {
  2366. Directory.CreateDirectory(Path.GetDirectoryName(path)); //创建文件夹
  2367. }
  2368. if (File.Exists(path))
  2369. {
  2370. // 使用 StreamWriter 以追加模式打开文件
  2371. StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
  2372. sw.WriteLine(sb.ToString().TrimEnd(','));
  2373. sw.Close();
  2374. sw.Dispose();
  2375. }
  2376. else
  2377. {
  2378. StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
  2379. StringBuilder sb1 = new StringBuilder();
  2380. StringBuilder sb_up = new StringBuilder();
  2381. StringBuilder sb_down = new StringBuilder();
  2382. sb1.Append("时间,产品名称,CT,RFID,产品结果,吸嘴数量,披头数量,");
  2383. for (int i = 0; i < number; i++)
  2384. {
  2385. sb1.Append($"螺丝{i + 1}结果,螺丝{i + 1}结果详情,螺丝{i + 1}扭矩,螺丝{i + 1}扭矩上限,螺丝{i + 1}扭矩下限,螺丝{i + 1}圈数,螺丝{i + 1}圈数上限,螺丝{i + 1}圈数下限,螺丝{i + 1}压力值,螺丝{i + 1}锁附X,螺丝{i + 1}锁附Y,螺丝{i + 1}开始位置Z,螺丝{i + 1}结束位置Z,螺丝{i + 1}锁附下降速度,");
  2386. }
  2387. sw.WriteLine(sb1.ToString().TrimEnd(','));
  2388. sw.WriteLine(sb.ToString().TrimEnd(','));
  2389. sw.Close();
  2390. sw.Dispose();
  2391. }
  2392. }
  2393. catch (Exception ex)
  2394. {
  2395. LogHelper.WriteLogError("写入产品记录时出错!", ex);
  2396. }
  2397. lockResultsAll.Clear();
  2398. }
  2399. #endregion
  2400. #endregion
  2401. }
  2402. }