Management.cs 155 KB

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