| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910 |
- using Cognex.VisionPro.ToolBlock;
- using MahApps.Metro.Controls;
- using NPOI.OpenXmlFormats.Vml;
- using Opc.Ua;
- using Org.BouncyCastle.Crypto;
- using Prism.Events;
- using Prism.Ioc;
- using Prism.Mvvm;
- using Prism.Regions;
- using SqlSugar;
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Drawing;
- using System.IO;
- using System.IO.Compression;
- using System.Linq;
- using System.Net.Sockets;
- using System.Security.Claims;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Web;
- using System.Web.UI.WebControls;
- using System.Windows.Media;
- using Team.FFFeederService.Interfaces;
- using TeamAAS_VP.Core.PLCs;
- using TeamAAS_VP.Core.ScrewDriver;
- using TeamAAS_VP.Data;
- using TeamAAS_VP.Enums;
- using TeamAAS_VP.Events;
- using TeamAAS_VP.Interfaces;
- using TeamAAS_VP.Models;
- using TeamAAS_VP.Models.PLC;
- using TeamAAS_VP.Models.Torque;
- using TeamAAS_VP.Resources.Languages;
- using TeamAAS_VP.Views.Product;
- using TouchSocket.Core;
- using TouchSocket.SerialPorts;
- using TouchSocket.Sockets;
- using Timer = System.Threading.Timer;
- namespace TeamAAS_VP.Core
- {
- public class Management : BindableBase
- {
- #region 字段
- IRegionManager _regionManager;
- IEventAggregator _eventAggregator;
- IContainerProvider _container;
- IConfigService _configService;
- IRobotService _robotService;
- ICameraService _cameraService;
- IFeederService _feederService;
- IPlcService _plcService;
- ILightManagerService _lightManagerService;
- IProductService _productService;
- ICalibrationService _calibrationService;
- IRemoteCommandService _remoteCommandService;
- ISystemDatabaseService _systemDatabaseService;
- IMesService _mesService;
- Timer yieldtimer;
- private DateTime StartTime = DateTime.Now;
- SerialPortClient client;
- // Pressure collection
- /// <summary>
- /// 压力采集信号控制CTS
- /// </summary>
- private CancellationTokenSource[] _pressureCts = new CancellationTokenSource[100];
- /// <summary>
- /// 压力采集超时CTS
- /// </summary>
- private CancellationTokenSource[] _pressureTimeoutCts = new CancellationTokenSource[100];
- /// <summary>
- /// 压力采集CTS
- /// </summary>
- private CancellationTokenSource[] _pressureLinkedCts = new CancellationTokenSource[100];
- /// <summary>
- /// 压力数据集合
- /// </summary>
- private List<(DateTime Timestamp, float Value)> _pressureSamples = new List<(DateTime, float)>();
- /// <summary>
- /// 采样间隔毫秒
- /// </summary>
- private int _pressureSampleIntervalMs = 50; //采样间隔毫秒
- /// <summary>
- /// 超时自动停止秒数
- /// </summary>
- private int _pressureMaxDurationSeconds = 30; //超时自动停止秒数
- DateTime[] StartCtqTime = new DateTime[3];//开始采集Ctq数据的时间
- /// <summary>
- /// 上次执行上传csv的日期
- /// </summary>
- private DateTime _lastCompressDate = DateTime.MinValue;
- /// <summary>
- /// 当天是否上传过csv
- /// </summary>
- private bool _hasCompressedToday = false;
- List<LockResult> lockResultsAll = new List<LockResult>();//一个产品的总结果
- string productSn = "";//产品sn
- DateTime StartScrewTime = DateTime.Now;//开始锁附的时间
- #endregion
- #region 属性
- /// <summary>
- /// 当前顶部显示的运行模式
- /// </summary>
- private RunDisplayMode _CurrentDisplayMode = RunDisplayMode.Unknown;
- public RunDisplayMode CurrentDisplayMode
- {
- get { return _CurrentDisplayMode; }
- set { SetProperty(ref _CurrentDisplayMode, value); }
- }
- private ObservableCollection<ShowRender> _Renders;
- /// <summary>
- /// 显示界面
- /// </summary>
- public ObservableCollection<ShowRender> Renders
- {
- get { return _Renders; }
- set { SetProperty(ref _Renders, value); }
- }
- public BgCommunicate BgCommunicate { get; private set; }
- public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; }
- private ObservableCollection<StatusInfo> _Status = new ObservableCollection<StatusInfo>();
- /// <summary>
- /// 状态栏集合
- /// </summary>
- public ObservableCollection<StatusInfo> Status
- {
- get { return _Status; }
- set { SetProperty(ref _Status, value); }
- }
- private Int64 _TotalQuantity;
- /// <summary>
- /// 总产量
- /// </summary>
- public Int64 TotalQuantity
- {
- get { return _TotalQuantity; }
- set { SetProperty(ref _TotalQuantity, value); }
- }
- private Int64 _TotalQuantityToday;
- /// <summary>
- /// 当天的总产量
- /// </summary>
- public Int64 TotalQuantityToday
- {
- get { return _TotalQuantityToday; }
- set { SetProperty(ref _TotalQuantityToday, value); }
- }
- private Int64 _CurrentUPH;
- /// <summary>
- /// 当前的UPH
- /// </summary>
- public Int64 CurrentUPH
- {
- get { return _CurrentUPH; }
- set { SetProperty(ref _CurrentUPH, value); }
- }
- private Int64 _ThrowNumber;
- /// <summary>
- /// 抛料数
- /// </summary>
- public Int64 ThrowNumber
- {
- get { return _ThrowNumber; }
- set { SetProperty(ref _ThrowNumber, value); }
- }
- private Int64 _NgNumber;
- /// <summary>
- /// ng数量
- /// </summary>
- public Int64 NgNumber
- {
- get { return _NgNumber; }
- set { SetProperty(ref _NgNumber, value); }
- }
- private double _Yield;
- /// <summary>
- /// 良率
- /// </summary>
- public double Yield
- {
- get { return _Yield; }
- set { SetProperty(ref _Yield, value); }
- }
- private XYD_ScrewDriver _ScrewDriver;
- public XYD_ScrewDriver ScrewDriver
- {
- get { return _ScrewDriver; }
- set { SetProperty(ref _ScrewDriver, value); }
- }
- public Dictionary<string, object> BackupObject { get; set; } = new Dictionary<string, object>();
- private string _SignalValue = "0";
- /// <summary>
- /// 扭力测量仪获取的最大值
- /// </summary>
- public string SignalValue
- {
- get { return _SignalValue; }
- set { SetProperty(ref _SignalValue, value); }
- }
- private NumberStatistics _NumStatistics;
- /// <summary>
- /// 数量(批头、吸嘴、供料器)
- /// </summary>
- public NumberStatistics NumStatistics
- {
- get { return _NumStatistics; }
- set { SetProperty(ref _NumStatistics, value); }
- }
- private double _CTtime;
- /// <summary>
- /// ct
- /// </summary>
- public double CTtime
- {
- get { return _CTtime; }
- set { SetProperty(ref _CTtime, value); }
- }
- private bool _TorqueStatus = false;
- public bool TorqueStatus
- {
- get { return _TorqueStatus; }
- set { _TorqueStatus = value; }
- }
- private ObservableCollection<DataFormCtq> _dfc = new ObservableCollection<DataFormCtq>();
- /// <summary>
- /// CTQ数据集合
- /// </summary>
- public ObservableCollection<DataFormCtq> DFC
- {
- get { return _dfc; }
- set { SetProperty(ref _dfc, value); }
- }
- private ObservableCollection<ProductModel> _ProductList;
- public ObservableCollection<ProductModel> ProductList
- {
- get { return _ProductList; }
- set { SetProperty(ref _ProductList, value); }
- }
- #endregion
- #region 命令
- #endregion
- #region 事件
- #endregion
- public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService,
- IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService,
- ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService,
- IMesService mesService)
- {
- _regionManager = regionManager;
- _eventAggregator = ea;
- _container = container;
- _configService = configService;
- _robotService = robotService;
- _cameraService = cameraService;
- _feederService = feederService;
- _plcService = plcService;
- _calibrationService = calibrationService;
- yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
- Renders = new ObservableCollection<ShowRender>();
- _productService = productService;
- _remoteCommandService = remoteCommandService;
- _systemDatabaseService = systemDatabaseService;
- _lightManagerService = lightManagerService;
- _mesService = mesService;
- _eventAggregator.GetEvent<CurrentStatusNotification>().Subscribe(CurrentRunStatus);
- }
- #region 读取配置参数
- public async Task ReadConfig()
- {
- await ReadNumber();
- }
- /// <summary>
- /// 读取数量配置
- /// </summary>
- public async Task ReadNumber()
- {
- try
- {
- NumStatistics = new NumberStatistics();
- var latestHeadChangeRecord = await _systemDatabaseService.GetLatestHeadChangeRecordAsync();
- if (latestHeadChangeRecord != null)
- {
- NumStatistics.HeaderNum = latestHeadChangeRecord.CurrentLockCount;
- }
- var latestNozzleChangeRecord = await _systemDatabaseService.GetLatestNozzleChangeRecordAsync();
- if (latestNozzleChangeRecord != null)
- {
- NumStatistics.NozzleNum = latestNozzleChangeRecord.CurrentLockCount;
- }
- NumStatistics.Feeder1Num = _configService.GetRemainingCountByFeederNumber(1);
- NumStatistics.Feeder2Num = _configService.GetRemainingCountByFeederNumber(2);
- }
- catch (Exception ex)
- {
- NumStatistics = new NumberStatistics();
- LogHelper.WriteLogError("加载数量配置文件时出错!", ex);
- }
- }
- #endregion
- #region 初始化硬件模块
- /// <summary>
- /// 初始化Feeder
- /// </summary>
- /// <returns></returns>
- public async Task<(bool IsSucceed, string Msg)> InitFeeders()
- {
- var feeders = _configService.GetAllFeeders();
- StringBuilder sb = new StringBuilder();
- foreach (var item in feeders)
- {
- _feederService.CreateFeeder(item.Id, item.FeederNo, item.FeederName, item.IP, item.Port, item.FeederBrand);
- var feeder = _feederService.GetFeeder(item.Id);
- Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- try
- {
- feeder.FeederConnectionStatusChanged += Management_FeederConnectionStatusChanged;
- await feeder.ConnectAsync(); //连接Feeder
- //SendTaskMessage($"{item.FeederName}已连接!", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- sb.AppendLine($"{item.FeederName}:{Lang.断开连接}![{ex.Message}]");
- SendTaskMessage($"{item.FeederName}{Lang.断开连接}!", MessageLevel.Alarm);
- }
- }
- if (sb.Length == 0)
- {
- return (true, "");
- }
- else
- {
- return (false, sb.ToString());
- }
- }
- /// <summary>
- /// 初始化机器人
- /// </summary>
- /// <returns></returns>
- public async Task<(bool IsSucceed, string Msg)> InitRobots()
- {
- var robots = _configService.GetAllRobots();
- StringBuilder sb = new StringBuilder();
- foreach (var item in robots)
- {
- _robotService.CreateRobot(item.Id, item);
- try
- {
- Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- var robot = _robotService.GetRobot(item.Id);
- robot.ReceivedEvent += Management_ReceivedEvent;
- robot.SendEvent += Management_SendEvent;
- robot.ConnectedEvent += Management_ConnectedEvent;
- robot.DisconnectedEvent += Management_DisconnectedEvent;
- await robot.ConnectAsync(); //连接Robot
- SendTaskMessage($"{item.RobotName}{Lang.已连接}!", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- sb.AppendLine($"{item.RobotName}:{Lang.断开连接}![{ex.Message}]");
- SendTaskMessage($"{item.RobotName}{Lang.断开连接}!", MessageLevel.Alarm);
- }
- }
- if (sb.Length == 0)
- {
- return (true, "");
- }
- else
- {
- return (false, sb.ToString());
- }
- }
- /// <summary>
- /// 初始化PLC
- /// </summary>
- /// <returns></returns>
- public async Task<(bool IsSucceed, string Msg)> InitPlc()
- {
- var plcs = _configService.GetAllPlcs();
- StringBuilder sb = new StringBuilder();
- foreach (var item in plcs)
- {
- try
- {
- _plcService.CreatePlc(item.Id, item);
- var plc = _plcService.GetPlc(item.Id);
- Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- plc.ConnectChangedEvent += Management_PlcConnectChangedEvent;
- await plc.ConnectAsync(); //连接PLC
- //SendTaskMessage($"{item.Name}{Lang.已连接}!", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]");
- SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm);
- }
- }
- try
- {
- await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
- RegisterPlcMonitorAddress();
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.为PLC写入系统参数和订阅变量时出错, ex);
- }
- if (sb.Length == 0)
- {
- return (true, "");
- }
- else
- {
- return (false, sb.ToString());
- }
- }
- /// <summary>
- /// 初始化相机
- /// </summary>
- /// <returns></returns>
- public async Task<(bool IsSucceed, string Msg)> InitCameras()
- {
- var cameras = _configService.GetAllCameras();
- StringBuilder sb = new StringBuilder();
- foreach (var item in cameras)
- {
- try
- {
- //Renders.Add(new ShowRender() { Id = item.Id, CameraName = item.CameraName });
- _cameraService.CreateCamera(item.Id, item);
- var camera = _cameraService.GetCamera(item.Id);
- Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- camera.CameraConnectChangedEvent += Management_CameraConnectChangedEvent;
- try
- {
- if (await camera.OpenDeviceAsync())
- {
- SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug);
- }
- else
- {
- SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
- sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!");
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage($"{item.CameraName}{ex.Message}!", MessageLevel.Alarm);
- sb.AppendLine($"{item.CameraName}:{ex.Message}!");
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
- sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!:{ex.Message}");
- }
- }
- //_container.Resolve<ShowVisionRenderViewModel>().Renders = Renders;
- if (sb.Length == 0)
- {
- return (true, "");
- }
- else
- {
- return (false, sb.ToString());
- }
- }
- /// <summary>
- /// 初始化光源控制器
- /// </summary>
- /// <returns></returns>
- public async Task<(bool IsSucceed, string Msg)> InitLightControllers()
- {
- var lightcontrollers = _configService.GetAllLightControllers();
- StringBuilder sb = new StringBuilder();
- foreach (var item in lightcontrollers)
- {
- try
- {
- var lishtCtr = await _lightManagerService.RegisterControllerAsync(item.Id, item);
- //var lightcontroller = _cameraService.GetLightController(item.Id);
- //await lightcontroller.ConnectAsync(); //连接光源控制器
- //SendTaskMessage($"{item.LightControllerName}{Lang.已连接}!", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- //sb.AppendLine($"{item.LightControllerName}:{Lang.断开连接}![{ex.Message}]");
- //SendTaskMessage($"{item.LightControllerName}{Lang.断开连接}!", MessageLevel.Alarm);
- }
- }
- if (lightcontrollers.Count > 0)
- {
- var result = await _lightManagerService.ConnectAllAsync();
- if (result)
- {
- return (true, "");
- }
- else
- {
- return (false, "Light Controller Connect Failed!");
- }
- }
- return (true, "");
- //if (sb.Length == 0)
- //{
- // return (true, "");
- //}
- //else
- //{
- // return (false, sb.ToString());
- //}
- }
- /// <summary>
- /// 初始化后台TCP服务器通讯
- /// </summary>
- public void InitBgTcp()
- {
- var config = _configService.GetBgTcp();
- try
- {
- BgCommunicate = new BgCommunicate(config);
- BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent;
- BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent;
- BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent;
- BgCommunicate.SendEvent += BgCommunicate_SendEvent;
- BgCommunicate.StartListening();
- SendTaskMessage($"{Lang.已开启监听端口}:{config.Port}", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- SendTaskMessage($"{Lang.未开启监听端口}:{config.Port}", MessageLevel.Error);
- LogHelper.WriteLogError(Lang.开启后台服务器通讯时出错, ex);
- }
- }
- /// <summary>
- /// 初始化后台ModbusTCP从站
- /// </summary>
- public void InitModbusTcp()
- {
- try
- {
- var config = _configService.GetBgModbusTcp();
- BgModbusTcpCommunicate = new BgModbusTcpCommunicate(config);
- if (config.IsEnabled)
- {
- BgModbusTcpCommunicate.Listen();
- SendTaskMessage($"Start Modbus Tcp Slave:{BgModbusTcpCommunicate.IP}:{BgModbusTcpCommunicate.Port}:{BgModbusTcpCommunicate.SlaveID}", MessageLevel.Debug);
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage($"No Start Modbus Tcp Slave:{ex.Message}", MessageLevel.Alarm);
- LogHelper.WriteLogError(Lang.开启后台ModbusTCP通讯时出错, ex);
- }
- }
- /// <summary>
- /// 初始化后台脚本
- /// </summary>
- public void InitBackgroundcript()
- {
- try
- {
- if (!Directory.Exists(FilePath.BackgroundScriptPath))
- {
- Directory.CreateDirectory(FilePath.BackgroundScriptPath);
- }
- try
- {
- string[] files = Directory.GetFiles(FilePath.BackgroundScriptPath);
- List<string> ScriptFilesCollection = new List<string>();
- foreach (string file in files)
- {
- string fileName = Path.GetFileName(file);
- string fileExtension = Path.GetExtension(file);
- if (fileExtension == ".cs")
- {
- ScriptFilesCollection.Add(file);
- }
- }
- foreach (var item in ScriptFilesCollection)
- {
- try
- {
- string script = FileHelper.ReadFile(item);
- SendTaskMessage($"{Lang.执行脚本}:{item}", MessageLevel.Info);
- Task.Factory.StartNew(() =>
- {
- ScriptHelper.ExecuteScriptingAsync(script, _regionManager, _eventAggregator, _container, rst =>
- {
- if (!rst.Item1)
- {
- foreach (var err in rst.Item2)
- {
- SendTaskMessage($"{Lang.后台脚本出错}:{err}", MessageLevel.Error);
- }
- }
- });
- });
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(string.Format(Lang.开启脚本时出错0, item), ex);
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.读取本地脚本文件列表时出错, ex);
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.开启后台脚本时出错, ex);
- }
- }
- /// <summary>
- /// 初始化电批
- /// </summary>
- /// <returns></returns>
- public async Task InitScrewDriver()
- {
- try
- {
- var screwDriverConfig = _configService.GetScrewDriverConfig();
- ScrewDriver = new XYD_ScrewDriver(screwDriverConfig.IPAdress, screwDriverConfig.Port);
- Status.Add(new StatusInfo(ScrewDriver.Id, Lang.电批未连接, new SolidColorBrush(Colors.Red)));
- ScrewDriver.ConnectStateChangedEvent += ScrewDriver_ConnectStateChangedEvent;
- ScrewDriver.SendTimeout = screwDriverConfig.SendTimeout;
- screwDriverConfig.ReceiveTimeout = screwDriverConfig.ReceiveTimeout;
- var isConnected = await ScrewDriver.ConnectAsync();
- if (isConnected)
- {
- SendTaskMessage(Lang.电批已连接, MessageLevel.Debug);
- }
- else
- {
- SendTaskMessage(Lang.电批连接失败, MessageLevel.Error);
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage(string.Format(Lang.电批连接失败0, ex.Message), MessageLevel.Alarm);
- LogHelper.WriteLogError(Lang.连接电批时出错, ex);
- }
- }
- /// <summary>
- /// 初始化扭力测量仪
- /// </summary>
- /// <returns></returns>
- public async Task InitSignal()
- {
- var torqueConfig = _configService.GetTorqueReaderConfig();
- if (torqueConfig != null)
- {
- try
- {
- var port = FileHelper.ReadJsonFile<TorqueProduceModel>(FilePath.TorqueReaderConfigurationPath);
- if (string.IsNullOrEmpty(port.TorqueMeasureSerialPort))
- {
- client = new TouchSocket.SerialPorts.SerialPortClient();
- client.Connecting = (client1, e) => { return EasyTask.CompletedTask; };//即将连接到端口
- client.Connected = (client1, e) => { return EasyTask.CompletedTask; };//成功连接到端口
- client.Closing = (client1, e) => { return EasyTask.CompletedTask; };//即将从端口断开连接。此处仅主动断开才有效。
- client.Closed = (client1, e) => { return EasyTask.CompletedTask; };//从端口断开连接,当连接不成功时不会触发。
- client.Received = async (c, e) =>
- {
- //await Console.Out.WriteLineAsync(Encoding.UTF8.GetString(e.ByteBlock.Buffer));
- await Console.Out.WriteLineAsync(e.ByteBlock.Span.ToString(Encoding.ASCII));
- };
- client.Received = Sp_DataReceived;
- await client.SetupAsync(new TouchSocketConfig()
- .SetSerialPortOption(new SerialPortOption()
- {
- BaudRate = torqueConfig.BaudRate,//波特率
- DataBits = torqueConfig.DataBits,//数据位
- Parity = torqueConfig.Parity,//校验位
- PortName = torqueConfig.PortName,//COM
- StopBits = torqueConfig.StopBits//停止位
- })
- .SetSerialDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromMilliseconds(100) })
- );
- await client.ConnectAsync();
- }
- else
- {
- SendTaskMessage("请设置扭力测量仪串口!", MessageLevel.Error);
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("初始化扭力测量仪时出错!", ex);
- SendTaskMessage("初始化扭力测量仪时出错!" + ex.Message, MessageLevel.Error);
- }
- }
- else
- {
- TorqueSerialPortConfig config = new TorqueSerialPortConfig();
- FileHelper.WriteJsonFile(config, FilePath.TorqueReaderConfigurationPath);
- }
- }
- #endregion
- #region 机器人指令执行
- public Dictionary<Guid, CancellationTokenSource> RobotTCPCollection = new Dictionary<Guid, CancellationTokenSource>();
- /// <summary>
- /// 机器人TCP接收
- /// </summary>
- /// <param name="arg1"></param>
- /// <param name="arg2"></param>
- /// <param name="arg3"></param>
- private async void Management_ReceivedEvent(Guid robotid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e)
- {
- try
- {
- if (!RobotTCPCollection.ContainsKey(robotid))
- RobotTCPCollection.Add(robotid, new CancellationTokenSource());
- else
- {
- if (RobotTCPCollection[robotid].IsCancellationRequested)
- {
- RobotTCPCollection[robotid] = new CancellationTokenSource();
- }
- }
- var robot = await _robotService.GetRobotAsync(robotid);
- //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
- var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding());
- SendTaskMessage($"{robot.Name}Received:{buffer}", MessageLevel.Info);
- var _ = _remoteCommandService.ExecuteAsync(buffer, RobotTCPCollection[robotid].Token, async msg =>
- {
- try
- {
- if (robot.ConnectType == TCPConnectType.Client)
- {
- if (robot.IsConnected)
- {
- await robot.SendAsync($"{msg}");
- }
- }
- else
- {
- var cient = (ITcpSessionClient)arg2;
- if (cient.Online)
- {
- await robot.SendAsync(cient, $"{msg}");
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.TCP发送数据时出错, ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- });
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.处理机器人接收的命令时出错, ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- }
- #endregion
- #region 机器人&Feeder&相机连接状态事件
- /// <summary>
- /// 机器人发送事件
- /// </summary>
- /// <param name="arg1"></param>
- /// <param name="arg2"></param>
- /// <param name="arg3"></param>
- /// <exception cref="NotImplementedException"></exception>
- private void Management_SendEvent(Guid robotid, object arg2, string arg3)
- {
- var r = _robotService.GetRobot(robotid);
- SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info);
- }
- /// <summary>
- /// 机器人断开连接时
- /// </summary>
- /// <param name="arg1"></param>
- /// <param name="arg2"></param>
- /// <param name="arg3"></param>
- /// <exception cref="NotImplementedException"></exception>
- private void Management_DisconnectedEvent(Guid robotid, object arg2, ClosedEventArgs arg3)
- {
- if (RobotTCPCollection.ContainsKey(robotid))
- {
- RobotTCPCollection[robotid].Cancel();
- }
- var r = _configService.GetRobot(robotid);
- if (r.ConnectType == TCPConnectType.Server)
- {
- ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
- SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
- var robot = _robotService.GetRobot(robotid);
- if (robot.TcpService.Count < 1)
- {
- var sta = Status.FirstOrDefault(s => s.ID == robotid);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{r.RobotName}{Lang.未连接}";
- sta.Background = new SolidColorBrush(Colors.Red);
- }));
- }
- }
- else
- {
- SendTaskMessage($"{r.RobotName}{Lang.断开连接}!", MessageLevel.Error);
- var sta = Status.FirstOrDefault(s => s.ID == robotid);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{r.RobotName}{Lang.断开连接}";
- sta.Background = new SolidColorBrush(Colors.Red);
- }));
- }
- }
- /// <summary>
- /// 机器人连接成功时
- /// </summary>
- /// <param name="arg1"></param>
- /// <param name="arg2"></param>
- /// <param name="arg3"></param>
- /// <exception cref="NotImplementedException"></exception>
- private void Management_ConnectedEvent(Guid robotid, object arg2, ConnectedEventArgs arg3)
- {
- var r = _configService.GetRobot(robotid);
- if (r.ConnectType == TCPConnectType.Server)
- {
- ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
- SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
- var robot = _robotService.GetRobot(robotid);
- if (robot.TcpService.Count > 0)
- {
- var sta = Status.FirstOrDefault(s => s.ID == robotid);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{r.RobotName}{Lang.已连接}";
- sta.Background = new SolidColorBrush(Colors.Green);
- }));
- }
- }
- else
- {
- SendTaskMessage($"{r.RobotName}{Lang.已连接}!", MessageLevel.Debug);
- var sta = Status.FirstOrDefault(s => s.ID == robotid);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{r.RobotName}{Lang.已连接}";
- sta.Background = new SolidColorBrush(Colors.Green);
- }));
- }
- }
- /// <summary>
- /// Feeder连接状态改变时
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="state"></param>
- private void Management_FeederConnectionStatusChanged(object sender, bool state)
- {
- IFeeder feeder = sender as IFeeder;
- var sta = Status.FirstOrDefault(s => s.ID == feeder.Id);
- if (state)
- {
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{feeder.Name}{Lang.已连接}";
- sta.Background = new SolidColorBrush(Colors.Green);
- }));
- SendTaskMessage($"{feeder.Name}{Lang.已连接}!", MessageLevel.Debug);
- }
- else
- {
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{feeder.Name}{Lang.未连接}";
- sta.Background = new SolidColorBrush(Colors.Red);
- }));
- SendTaskMessage($"{feeder.Name}{Lang.断开连接}!", MessageLevel.Error);
- }
- }
- /// <summary>
- /// 相机连接或者断开时
- /// </summary>
- /// <param name="id"></param>
- /// <param name="state"></param>
- private void Management_CameraConnectChangedEvent(Guid id, bool state)
- {
- var sta = Status.FirstOrDefault(s => s.ID == id);
- var camera = _configService.GetCamera(id);
- if (sta != null && camera != null)
- {
- if (state)
- {
- App.Current.Dispatcher.Invoke(new Action(() =>
- {
- sta.Message = $"{camera.CameraName}{Lang.已连接}";
- sta.Background = new SolidColorBrush(Colors.Green);
- }));
- }
- else
- {
- App.Current.Dispatcher.Invoke(new Action(() =>
- {
- sta.Message = $"{camera.CameraName}{Lang.断开连接}";
- sta.Background = new SolidColorBrush(Colors.Red);
- }));
- }
- }
- }
- /// <summary>
- /// PLC连接状态改变事件
- /// </summary>
- /// <param name="plc"></param>
- /// <param name="isconnected"></param>
- private async void Management_PlcConnectChangedEvent(object sender, bool isconnected)
- {
- IPlc plc = sender as IPlc;
- var sta = Status.FirstOrDefault(s => s.ID == plc.Id);
- if (plc.IsConnected)
- {
- SendTaskMessage($"{plc.Name}{Lang.已连接}!", MessageLevel.Debug);
- if (sta == null) return;
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{plc.Name}{Lang.已连接}";
- sta.Background = new SolidColorBrush(Colors.Green);
- }));
- try
- {
- await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
- await WriteParameterToPlcExAsync();
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("PLC连接成功时,写入系统参数和点位信息时出错!", ex);
- }
- }
- else
- {
- SendTaskMessage($"{plc.Name}{Lang.断开连接}!", MessageLevel.Error);
- if (sta == null) return;
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{plc.Name}{Lang.未连接}";
- sta.Background = new SolidColorBrush(Colors.Red);
- }));
- }
- }
- /// <summary>
- /// 电批连接状态改变时
- /// </summary>
- /// <param name="screwDevice"></param>
- /// <param name="state"></param>
- private void ScrewDriver_ConnectStateChangedEvent(object screwDevice, bool state)
- {
- try
- {
- XYD_ScrewDriver screwDriver = screwDevice as XYD_ScrewDriver;
- if (state)
- {
- SendTaskMessage(Lang.电批已连接, MessageLevel.Debug);
- var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = Lang.电批已连接;
- sta.Background = new SolidColorBrush(Colors.Green);
- }));
- }
- else
- {
- SendTaskMessage(Lang.电批未连接, MessageLevel.Error);
- var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = Lang.电批未连接;
- sta.Background = new SolidColorBrush(Colors.Red);
- }));
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.电批连接状态改变时出错了, ex);
- }
- }
- #endregion
- #region 后台服务器通讯事件
- private void BgCommunicate_SendEvent(ITcpSessionClient client, string msg)
- {
- SendTaskMessage($"{Lang.服务器}[{client.ServicePort}] Send To {Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
- }
- public Dictionary<string, CancellationTokenSource> BgCommunicateollection = new Dictionary<string, CancellationTokenSource>();
- private async void BgCommunicate_ReceivedEvent(ITcpSessionClient client, string msg)
- {
- try
- {
- if (!BgCommunicateollection.ContainsKey(client.Id))
- {
- BgCommunicateollection.Add(client.Id, new CancellationTokenSource());
- }
- SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]ReceiveFor{Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
- var _ = _remoteCommandService.ExecuteAsync(msg, BgCommunicateollection[client.Id].Token, async response =>
- {
- try
- {
- if (!client.Online)
- {
- return;
- }
- await BgCommunicate.SendAsync(client, $"{response}");
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.后台TCP发送数据时出错, ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- });
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(Lang.处理后台服务器接收的命令时出错, ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- }
- private void BgCommunicate_DisconnectedEvent(ITcpSessionClient client, ClosedEventArgs e)
- {
- SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.断开连接}!", MessageLevel.Alarm);
- if (BgCommunicateollection.ContainsKey(client.Id))
- {
- BgCommunicateollection[client.Id].Cancel();
- }
- }
- private void BgCommunicate_ConnectedEvent(ITcpSessionClient client, ConnectedEventArgs e)
- {
- SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.连接成功}!", MessageLevel.Debug);
- }
- /// <summary>
- /// 扭力测量仪接收信息
- /// </summary>
- /// <param name="client"></param>
- /// <param name="e"></param>
- /// <returns></returns>
- private async Task Sp_DataReceived(ISerialPortClient client, ReceivedDataEventArgs e)
- {
- try
- {
- string poname = client.MainSerialPort.PortName;
- string data = e.ByteBlock.Span.ToString(Encoding.ASCII);
- await Console.Out.WriteLineAsync(data);
- string response = data.Split('\r')[0];
- SendTaskMessage($"{poname}Receive:{response}", MessageLevel.Info);
- SignalValue = "";
- SignalValue = response;
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("扭力测量仪接收信息时出错!", ex);
- SendTaskMessage("扭力测量仪接收信息时出错!" + ex.Message, MessageLevel.Error);
- Thread.Sleep(50);
- }
- }
- #endregion
- #region PLC
- /// <summary>
- /// 将系统参数写入PLC
- /// </summary>
- /// <param name="systemConfiguration"></param>
- /// <returns></returns>
- public async Task WriteSystemParameterToPlcAsync(SystemConfiguration systemConfiguration)
- {
- var addressConfig = _configService.GetPlcAddresses();
- var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
- if (plc == null || !plc.IsConnected) return;
- Dictionary<string, object> nodeValues = new Dictionary<string, object>();
- nodeValues.Add(addressConfig.Out_WorkMode.Address, (Int16)systemConfiguration.WorkMode);
- nodeValues.Add(addressConfig.Out_PickPointNum.Address, (Int16)systemConfiguration.PickPointNum);
- nodeValues.Add(addressConfig.Out_DowmCameraNum.Address, (Int16)systemConfiguration.DowmCameraNum);
- nodeValues.Add(addressConfig.Out_UpCameraPickNum.Address, (Int16)systemConfiguration.UpCameraPickNum);
- nodeValues.Add(addressConfig.Out_UpCameraPutNum.Address, (Int16)systemConfiguration.UpCameraPutNum);
- nodeValues.Add(addressConfig.Out_UPCameracheckNum.Address, (Int16)systemConfiguration.UPCameracheckNum);
- nodeValues.Add(addressConfig.Out_FixedCameraPickNum.Address, (Int16)systemConfiguration.FixedCameraPickNum);
- nodeValues.Add(addressConfig.Out_FixedCameraPutNum.Address, (Int16)systemConfiguration.FixedCameraPutNum);
- nodeValues.Add(addressConfig.Out_FixedCameracheckNum.Address, (Int16)systemConfiguration.FixedCameracheckNum);
- nodeValues.Add(addressConfig.Out_ScrewTeachNum.Address, (Int16)systemConfiguration.ScrewTeachNum);
- var res = await plc.WriteNodesAsync(nodeValues);
- }
- /// <summary>
- /// 注册需要监控的PLC地址
- /// </summary>
- public void RegisterPlcMonitorAddress()
- {
- var addressConfig = _configService.GetPlcAddresses();
- var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
- if (plc == null || !plc.IsConnected) return;
- //PLC地址数组
- List<string> monitorNodeIds = new List<string>()
- {
- addressConfig.In_DowmCameraExe.Address,
- addressConfig.In_UpCameraPickExe.Address,
- addressConfig.In_UpCameraPutExe.Address,
- addressConfig.In_UPCameracheckExe.Address,
- addressConfig.In_FixedCameraPickExe.Address,
- addressConfig.In_FixedCameraPutExe.Address,
- addressConfig.In_FixedCameracheckExe.Address,
- addressConfig.In_WorkStart.Address,
- addressConfig.In_WorkDone.Address,
- //addressConfig.In_MesCheck.Address,
- addressConfig.In_RequestPosition.Address,
- addressConfig.In_QrCodePhotoRequest.Address,
- addressConfig.In_ScrewTeachExe.Address,
- addressConfig.In_Screw_checkExe.Address,
- addressConfig.In_PickINC.Address,
- addressConfig.In_Throw.Address,
- addressConfig.RunMode.Address,
- addressConfig.AutoRunning.Address,
- addressConfig.ManualMode.Address,
- addressConfig.ClearMode.Address,
- addressConfig.Fault.Address,
- addressConfig.In_FzCameraPixExe.Address,
- };
- var systemconfig = _configService.GetSystemConfiguration();
- for (int i = 0; i < 10; i++)
- {
- if (systemconfig.DoubleSoftMode && i == 1)
- {
- continue;
- }
- monitorNodeIds.Add(string.Format(addressConfig.In_MesCheck.Address, i));
- }
- //订阅PLC地址变化
- //plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
- plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
- // 2. 监听重连事件,重连成功后自动重新订阅
- plc.ConnectChangedEvent -= Plc_ConnectChanged; // 防止重复注册
- plc.ConnectChangedEvent += Plc_ConnectChanged;
- // 定义重连处理方法(写在同一个类里即可)
- void Plc_ConnectChanged(object sender, bool isConnected)
- {
- if (isConnected)
- {
- // 重连成功后,重新订阅节点
- plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
- }
- }
- }
- /// <summary>
- /// 将产品的参数统一写入PLC
- /// </summary>
- /// <returns></returns>
- public async Task WriteParameterToPlcExAsync()
- {
- await WritePositionToPlcAsync();// 写入点位信息给PLC
- //await WriteParameterToPlcAsync();// 写入组装上下限给PLC
- await WriteProductLoadModeToPLC();//把当前产品型号,写入PLC
- }
- /// <summary>
- /// 写入点位信息给PLC
- /// </summary>
- /// <returns></returns>
- public async Task WritePositionToPlcAsync()
- {
- var addressConfig = _configService.GetPlcAddresses();
- var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
- if (plc == null || !plc.IsConnected) return;
- var current = _productService.GetCurrentProduct();
- if (current == null) return;
- _LastAutoRunning = plc.ReadNode<bool>(addressConfig.AutoRunning.Address);
- if (current.PickCameraPoints != null && current.PickCameraPoints.Count > 0)
- {
- foreach (var item in current.PickCameraPoints)
- {
- await item.WriteToPlcAddress(addressConfig.Out_PickCamera, plc);
- }
- }
- if (current.PickPoints != null && current.PickPoints.Count > 0)
- {
- foreach (var item in current.PickPoints)
- {
- await item.WriteToPlcAddress(addressConfig.Out_Pick, plc, item.Feeder);
- //await item.WriteToPlcAddress(addressConfig.Out_Pick, plc);
- }
- }
- if (current.SecPosCameraPoints != null && current.SecPosCameraPoints.Count > 0)
- {
- foreach (var item in current.SecPosCameraPoints)
- {
- await item.WriteToPlcAddress(addressConfig.Out_SecPosCamera, plc);
- }
- }
- if (current.ScrewCameraPoints != null && current.ScrewCameraPoints.Count > 0)
- {
- int index = 0;
- foreach (var item in current.ScrewCameraPoints)
- {
- //根据使用的点位进行排序
- if (item.IsUse)
- {
- index++;
- await item.WriteToPlcAddress(addressConfig.Out_ScrewCamera, plc, index);
- }
- }
- }
- if (current.ScrewPoints != null && current.ScrewPoints.Count > 0)
- {
- int index = 0;
- foreach (var item in current.ScrewPoints)
- {
- if (item.IsUse)
- {
- index++;
- await item.WriteToPlcAddressEx(addressConfig.Out_Screw, plc, index);
- }
- }
- await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)index);
- }
- if (current.CheckCameraPoints != null && current.CheckCameraPoints.Count > 0)
- {
- int index = 0;
- foreach (var item in current.CheckCameraPoints)
- {
- if (item.IsUse)
- {
- index++;
- await item.WriteToPlcAddress(addressConfig.Out_CheckCamera, plc, index);
- }
- }
- }
- if (current.QrCodePoints != null && current.QrCodePoints.Count > 0)
- {
- foreach (var item in current.QrCodePoints)
- {
- await item.WriteToPlcAddress(addressConfig.Out_QrCodeCamera, plc);
- }
- }
- }
- /// <summary>
- /// 将当前产品类型写入PLC
- /// </summary>
- /// <param name="mode"></param>
- public async Task WriteProductLoadModeToPLC(int modeIndex)
- {
- var addressConfig = _configService.GetPlcAddresses();
- var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
- if (plc == null || !plc.IsConnected) return;
- await plc.WriteNodeAsync(addressConfig.Out_ProductLoadMode.Address, (Int16)modeIndex);
- }
- /// <summary>
- /// 将当前产品类型写入PLC
- /// </summary>
- /// <param name="mode"></param>
- public async Task WriteProductLoadModeToPLC()
- {
- var addressConfig = _configService.GetPlcAddresses();
- var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
- if (plc == null || !plc.IsConnected) return;
- var current = _productService.GetCurrentProduct();
- if (current == null) return;
- var qMes = await _systemDatabaseService.QueryProductFromMesAsync(current.Name);
- if (qMes == null) return;
- await plc.WriteNodeAsync(addressConfig.Out_ProductLoadMode.Address, (Int16)qMes.ProductLoadMode);
- }
- PointF[] DowmCameraResults = new PointF[10];
- PointF[] UpCameraPutResults = new PointF[10];
- bool _LastDowmCameraExe = false;
- bool _LastScrewTeachExe = false;
- bool _LastUpCameraPickExe = false;
- bool _LastScrewFuJianExe = false;
- bool _LastUpCameraPutExe = false;
- bool _LastUPCameracheckExe = false;
- bool _LastFixedCameraPickExe = false;
- bool _LastFixedCameraPutExe = false;
- bool _LastFixedCameracheckExe = false;
- bool _LastFzCameracheckExe = false;
- bool _LastThrowExe = false;
- bool _LastRunModel = false;
- public bool _LastAutoRunning = false;
- bool _LastManualMode = false;
- bool _LastClearMode = false;
- bool _LastFault = false;
- Int16 _LastWorkStart = 0;
- Int16 _LastWorkDone = 0;
- Int16 _LastRequestPosition = 0;
- Int16 _LastQrCodePhotoRequest = 0;
- Int16[] _LastMesCheck = new Int16[10];
- Int16 _LastPickINC = 0;
- DateTime[] _LastMesCheckTime = new DateTime[10];
- Dictionary<string, string> mes_cc = new Dictionary<string, string>();
- Dictionary<string, double> Point = new Dictionary<string, double>();
- string[] ProductMainSN { get; set; } = new string[10];//产品主sn
- string[] model_num { get; set; } = new string[10];//产品model_num
- string[] wo { get; set; } = new string[10];//产品wo
- string[] color { get; set; } = new string[10];//产品color
- string[] ppid { get; set; } = new string[10];//产品ppid
- string[] revision { get; set; } = new string[10];//产品revision
- Dictionary<string, string> dataToMes = new Dictionary<string, string>();//上传mes的数据
- List<string> resultToMes { get; set; } = new List<string>();//上传mes的数据
- /// <summary>
- /// PLC命令触发时
- /// </summary>
- /// <param name="tuple"></param>
- private async void PlcCommandTrigger((string key, string nodeId, object value) tuple)
- {
- try
- {
- if (tuple.key != "AutoSensor")
- {
- SendTaskMessage("PLC指令错误", MessageLevel.Debug);
- return;
- }
- var addressConfig = _configService.GetPlcAddresses();
- var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
- if (plc == null || !plc.IsConnected)
- {
- SendTaskMessage("plc为空", MessageLevel.Debug);
- return;
- }
- // 获取当前产品
- var currentProduct = _productService.GetCurrentProduct();
- if (currentProduct == null)
- {
- return;
- }
- ////获取产品编码
- //_productService.CurrentProductCode = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 0));
- ////如果产品编码为空,则以当前的时间戳作为编码
- //if (string.IsNullOrEmpty(_productService.CurrentProductCode))
- //{
- // _productService.CurrentProductCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
- //}
- // 触发下相机拍照
- if (addressConfig.In_DowmCameraExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastDowmCameraExe != state)
- {
- _LastDowmCameraExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发下相机拍照, MessageLevel.Debug);
- //相机的编号
- Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_DowmCameraNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
- // 获取流程
- var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
- if (process == null)
- {
- SendTaskMessage(string.Format(Lang.固定向上相机1视觉流程流程ID0, currentProduct.FixedUpCamera1ProcedureId), MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
- return;
- }
- // 获取机器人当前坐标
- var robot = _robotService.GetAllRobots().FirstOrDefault();
- if (robot == null)
- {
- SendTaskMessage(Lang.未找到机器人无法执行上相机锁附组装拍照视觉任务, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
- return;
- }
- var currentPosition = robot.GetRobotPos();
- // 执行视觉任务
- var _cts = new CancellationTokenSource();
- ImageParameters imgPara = new ImageParameters();
- imgPara.SNCode = productSn;
- var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, null, _cts.Token, cameraIndex, cameraIndex, null, imgPara);
- if (visionResult.IsSucceed)
- {
- //披头偏差
- float offsetX = (float)(visionResult.X - currentPosition.X);
- float offsetY = (float)(visionResult.Y - currentPosition.Y);
- DowmCameraResults[cameraIndex] = new PointF(offsetX, offsetY);
- await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
- return;
- }
- else
- {
- await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
- return;
- }
- }
- else
- {
- SendTaskMessage(Lang.触发下相机拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)0);
- }
- }
- }
- // 触发下相机拍照披头
- if (addressConfig.In_ScrewTeachExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastScrewTeachExe != state)
- {
- _LastScrewTeachExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发下相机拍照, MessageLevel.Debug);
- //相机的编号
- Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_DowmCameraNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
- // 获取流程
- var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
- if (process == null)
- {
- SendTaskMessage(string.Format(Lang.固定向上相机1视觉流程流程ID0, currentProduct.FixedUpCamera1ProcedureId), MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
- return;
- }
- // 获取机器人当前坐标
- var robot = _robotService.GetAllRobots().FirstOrDefault();
- if (robot == null)
- {
- SendTaskMessage(Lang.未找到机器人无法执行上相机锁附组装拍照视觉任务, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
- return;
- }
- var currentPosition = robot.GetRobotPos();
- // 执行视觉任务
- var _cts = new CancellationTokenSource();
- ImageParameters imgPara = new ImageParameters();
- imgPara.SNCode = productSn;
- var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, null, _cts.Token, cameraIndex, cameraIndex, null, imgPara);
- if (visionResult.IsSucceed)
- {
- //披头偏差
- float offsetX = (float)(visionResult.X - currentPosition.X);
- float offsetY = (float)(visionResult.Y - currentPosition.Y);
- DowmCameraResults[cameraIndex] = new PointF(offsetX, offsetY);
- await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)1);
- return;
- }
- else
- {
- await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
- return;
- }
- }
- else
- {
- SendTaskMessage(Lang.触发下相机拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)0);
- }
- }
- }
- // 触发上相机取料拍照
- else if (addressConfig.In_UpCameraPickExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastUpCameraPickExe != state)
- {
- _LastUpCameraPickExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发上相机取料拍照, MessageLevel.Debug);
- //相机的编号
- //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPickNum.Address);
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage(Lang.触发上相机取料拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)0);
- }
- }
- }
- // 上相机锁附/组装拍照
- else if (addressConfig.In_UpCameraPutExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastUpCameraPutExe != state)
- {
- _LastUpCameraPutExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发上相机锁附组装拍照, MessageLevel.Debug);
- //相机的编号
- Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPutNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
- //视觉流程ID
- Guid procedureId = currentProduct.MoveDownCameraLockPhotoProcedureId;
- List<PlcPoint> plcPoints = new List<PlcPoint>();
- foreach (var item in currentProduct.ScrewCameraPoints)
- {
- if (item.IsUse)
- {
- plcPoints.Add(item);
- }
- }
- int num = plcPoints.Count;
- //获取锁付拍照的点位
- var pos = plcPoints[cameraIndex - 1];
- if (pos != null)
- {
- procedureId = pos.VisionProcessID;
- }
- // 获取流程
- var process = _productService.GetCurrentProductProcedureModelById(procedureId);
- if (process == null)
- {
- SendTaskMessage(string.Format(Lang.未找到上相机锁附组装拍照对应的视觉流程流程ID0, procedureId), MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
- return;
- }
- // 获取机器人当前坐标
- var robot = _robotService.GetAllRobots().FirstOrDefault();
- if (robot == null)
- {
- SendTaskMessage(Lang.未找到机器人无法执行上相机锁附组装拍照视觉任务, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
- return;
- }
- var currentPosition = robot.GetRobotPos();
- var systemConfig = _configService.GetSystemConfiguration();
- // 执行视觉任务
- var _cts = new CancellationTokenSource();
- ImageParameters imgPara = new ImageParameters();
- imgPara.SNCode = productSn;
- var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, cameraIndex, num, null, imgPara);
- if (visionResult.IsSucceed)
- {
- //是拍一个锁一个还是拍两个点锁所有
- if (systemConfig.IsBasePartOpenLightKB)
- {
- if (mes_cc.ContainsKey(visionResult.distance.Split(',')[0]))
- {
- mes_cc[visionResult.distance.Split(',')[0]] = visionResult.distance.Split(',')[1];
- }
- else
- {
- mes_cc.Add(visionResult.distance.Split(',')[0], visionResult.distance.Split(',')[1]);
- }
- }
- //拍1打1
- if (systemConfig.WorkMode == 1)
- {
- UpCameraPutResults[1] = new PointF((float)visionResult.X, (float)visionResult.Y);
- }
- else if (systemConfig.WorkMode == 2)
- {
- UpCameraPutResults[cameraIndex] = new PointF((float)visionResult.X, (float)visionResult.Y);
- }
- else if (systemConfig.WorkMode == 3)
- {
- if (cameraIndex <= 3)
- {
- UpCameraPutResults[1] = new PointF((float)visionResult.X, (float)visionResult.Y);
- }
- else
- {
- UpCameraPutResults[cameraIndex] = new PointF((float)visionResult.X, (float)visionResult.Y);
- }
- }
- if (resultToMes.Contains($"Screw{cameraIndex}_Fail"))
- {
- resultToMes.Remove($"Screw{cameraIndex}_Fail");
- SendTaskMessage($"Screw{cameraIndex}:重复拍照成功", MessageLevel.Debug);
- }
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
- }
- else
- {
- if (systemConfig.IsBasePartOpenLightKB)
- {
- if (mes_cc.ContainsKey(visionResult.distance.Split(',')[0]))
- {
- mes_cc[visionResult.distance.Split(',')[0]] = visionResult.distance.Split(',')[1];
- }
- else
- {
- if (mes_cc.ContainsKey(cameraIndex.ToString()))
- {
- mes_cc[cameraIndex.ToString()] = "0";
- }
- else
- {
- mes_cc.Add(cameraIndex.ToString(), "0");
- }
- }
- }
- if (!resultToMes.Contains($"Screw{cameraIndex}_Fail"))
- {
- resultToMes.Add($"Screw{cameraIndex}_Fail");
- SendTaskMessage($"Screw{cameraIndex}:拍照失败", MessageLevel.Error);
- }
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
- }
- }
- else
- {
- SendTaskMessage(Lang.触发上相机锁附组装拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)0);
- }
- }
- }
- // 上相机检测拍照
- else if (addressConfig.In_UPCameracheckExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastUPCameracheckExe != state)
- {
- _LastUPCameracheckExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发上相机检测拍照, MessageLevel.Debug);
- //相机的编号
- Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UPCameracheckNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
- //获取锁付拍照的点位
- List<PlcPoint> plcPoints = new List<PlcPoint>();
- foreach (var item in currentProduct.CheckCameraPoints)
- {
- if (item.IsUse)
- {
- plcPoints.Add(item);
- }
- }
- int num = plcPoints.Count;
- //视觉流程ID
- Guid procedureId = Guid.Empty;
- //获取锁付拍照的点位
- var pos = plcPoints[cameraIndex - 1];
- if (pos != null)
- {
- procedureId = pos.VisionProcessID;
- }
- // 获取流程
- var process = _productService.GetCurrentProductProcedureModelById(procedureId);
- if (process == null)
- {
- SendTaskMessage(string.Format("未找到点位:{0}的视觉流程:{1}", cameraIndex, procedureId), MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
- return;
- }
- // 获取机器人当前坐标
- var robot = _robotService.GetAllRobots().FirstOrDefault();
- if (robot == null)
- {
- SendTaskMessage("未找到机器人无法执行 上相机检测拍照视觉任务", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
- return;
- }
- var currentPosition = robot.GetRobotPos();
- // 执行视觉任务
- var _cts = new CancellationTokenSource();
- var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, cameraIndex, num, null, null);
- if (visionResult.IsSucceed)
- {
- await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
- SendTaskMessage($"点位{cameraIndex}检测OK", MessageLevel.Debug);
- }
- else
- {
- await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
- SendTaskMessage($"点位{cameraIndex}检测NG", MessageLevel.Error);
- }
- }
- else
- {
- SendTaskMessage(Lang.触发上相机检测拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)0);
- }
- }
- }
- //下相机拍照螺丝复检
- else if (addressConfig.In_Screw_checkExe.Address.Contains(tuple.nodeId))
- {
- Point.Clear();
- if (tuple.value is bool state)
- {
- if (_LastScrewFuJianExe != state)
- {
- _LastScrewFuJianExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发相机拍照螺丝复检, MessageLevel.Debug);
- //相机的编号
- Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_DowmCameraNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
- // 获取流程
- var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCameraProcedureId);
- if (process == null)
- {
- SendTaskMessage(string.Format(Lang.固定向上相机视觉流程流程ID, currentProduct.FixedUpCameraProcedureId), MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_Screw_check_status.Address, (Int16)2);
- return;
- }
- // 获取机器人当前坐标
- var robot = _robotService.GetAllRobots().FirstOrDefault();
- if (robot == null)
- {
- SendTaskMessage(Lang.未找到机器人无法执行上相机锁附组装拍照视觉任务, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_Screw_check_status.Address, (Int16)2);
- return;
- }
- var currentPosition = robot.GetRobotPos();
- // 执行视觉任务
- var _cts = new CancellationTokenSource();
- ImageParameters imgPara = new ImageParameters();
- imgPara.SNCode = productSn;
- var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint1(process, null, null, _cts.Token, cameraIndex, cameraIndex, null, imgPara);
- //string X, Y, U;
- if (visionResult.IsSucceed)
- {
- //披头偏差
- //float offsetX = (float)(visionResult.X - currentPosition.X);
- //float offsetY = (float)(visionResult.Y - currentPosition.Y);
- string[] keys = { "X", "Y", "U" };
- double[] values = { visionResult.X, visionResult.Y, visionResult.U };
- for (int i = 0; i < keys.Length; i++)
- {
- Point.Add(keys[i], values[i]);
- }
- // 2. 生成CSV文件(替换成你的保存路径)
- string csvPath = @"D:\视觉检测数据\XYU结果.csv";
- // 调用生成方法(appendMode=true 每次拍照新增一行,不会覆盖历史数据)
- ExportDictionaryToCsv(Point, csvPath, appendMode: true);
- //DowmCameraResults[cameraIndex] = new PointF(offsetX, offsetY);
- //ExportDictionaryToCsv1(ProductMainSN[1], visionResult.X, visionResult.Y, visionResult.U);
- await plc.WriteNodeAsync(addressConfig.Out_Screw_check_status.Address, (Int16)1);
- return;
- }
- else
- {
- await plc.WriteNodeAsync(addressConfig.Out_Screw_check_status.Address, (Int16)2);
- return;
- }
- }
- else
- {
- SendTaskMessage(Lang.触发下相机拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_Screw_check_status.Address, (Int16)0);
- }
- }
- }
- // 固定相机取料拍照
- else if (addressConfig.In_FixedCameraPickExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastFixedCameraPickExe != state)
- {
- _LastFixedCameraPickExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发固定相机取料拍照, MessageLevel.Debug);
- //相机的编号
- //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameraPickNum.Address);
- await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage(Lang.触发固定相机取料拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)0);
- }
- }
- }
- // 固定相机锁附/组装拍照
- else if (addressConfig.In_FixedCameraPutExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastFixedCameraPutExe != state)
- {
- _LastFixedCameraPutExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发固定相机锁附组装拍照, MessageLevel.Debug);
- //相机的编号
- //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameraPutNum.Address);
- await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage(Lang.触发固定相机锁附组装拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)0);
- }
- }
- }
- // 固定相机检测拍照
- else if (addressConfig.In_FixedCameracheckExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastFixedCameracheckExe != state)
- {
- _LastFixedCameracheckExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage(Lang.触发固定相机检测拍照, MessageLevel.Debug);
- //相机的编号
- //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
- await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage(Lang.触发固定相机检测拍照信号已关闭, MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)0);
- }
- }
- }
- // 翻转相机检测拍照
- else if (addressConfig.In_FzCameraPixExe.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastFzCameracheckExe != state)
- {
- _LastFzCameracheckExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- int i = 5;
- SendTaskMessage("触发翻转相机拍照", MessageLevel.Debug);
- var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 1));
- string resultphoto = "";
- //这里缺少从MES获取产品配方的内容,需要补充
- _LastMesCheckTime[5] = (await _mesService.GetServerTimeAsync(5, code, 2)).Now;
- var stationConfig2 = _configService.GetDeviceInfo(0);
- LogHelper.WriteLogMes($"【mes开始QUERY】");
- SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
- //if (stationConfig2.EnableMES)
- //{
- // (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
- // if (isSuccess)
- // {
- // string ProductMainSN_Temp = "";
- // LogHelper.WriteLogMes($"询问mes成功");
- // SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- // string[] item = response.Split('\n');
- // //获取过度件sn
- // string snItem = item.FirstOrDefault(f => f.Contains("sn="));
- // if (snItem != null)
- // {
- // ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
- // SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
- // }
- // LogHelper.WriteLogMes($"询问mes成功");
- // SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- // //20260214,螺丝机特别版
- // (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
- // if (isSuccess2)
- // {
- // LogHelper.WriteLogMes($"询问mes成功");
- // SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
- // string[] items = response2.Split('\n');
- // //获取产品主sn和wo用于后续上传数据使用
- // string snItem2 = items.FirstOrDefault(f => f.Contains("sn="));
- // if (snItem2 != null)
- // {
- // var codesn = snItem2.Replace("sn=", "").Trim();
- // //_productService.CurrentProductCode = codesn;
- // SendTaskMessage($"产品主sn:{codesn}", MessageLevel.Info);
- // }
- // string woItem = item.FirstOrDefault(f => f.Contains("wo="));
- // if (woItem != null)
- // {
- // wo[i] = woItem.Replace("wo=", "").Trim();
- // SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
- // }
- // string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
- // if (modelItem != null)
- // {
- // model_num[i] = modelItem.Replace("model_num=", "").Trim();
- // SendTaskMessage($"model_num:{model_num[i]}", MessageLevel.Info);
- // }
- // string colorItem = item.FirstOrDefault(f => f.Contains("color="));
- // if (colorItem != null)
- // {
- // color[i] = colorItem.Replace("color=", "").Trim();
- // SendTaskMessage($"color:{color[i]}", MessageLevel.Info);
- // }
- // string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
- // if (ppidItem != null)
- // {
- // ppid[5] = ppidItem.Replace("ppid=", "").Trim();
- // SendTaskMessage($"ppid:{ppid[5]}", MessageLevel.Info);
- // }
- // string revisionItem = item.FirstOrDefault(f => f.Contains("stage="));
- // if (revisionItem != null)
- // {
- // revision[5] = revisionItem.Replace("stage=", "").Trim();
- // SendTaskMessage($"stage:{revision[5]}", MessageLevel.Info);
- // }
- // LogHelper.WriteLogMes($"第二次询问mes成功");
- // SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
- // }
- // else
- // {
- // LogHelper.WriteLogMes($"第二次询问mes失败");
- // SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
- // await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
- // return;
- // }
- // }
- // else
- // {
- // LogHelper.WriteLogMes($"询问mes失败");
- // SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
- // await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
- // return;
- // }
- //}
- //else
- //{
- // SendTaskMessage($"mes未启用", MessageLevel.Info);
- //}
- Guid FzCameraProcedureId = currentProduct.FzCameraProcedureId;
- var FzCameraProcess = _productService.GetCurrentProductProcedureModelById(FzCameraProcedureId);
- if (FzCameraProcess == null)
- {
- SendTaskMessage($"未找到翻转相机视觉流程,流程ID: {FzCameraProcedureId}", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
- return;
- }
- SendTaskMessage($"开始执行翻转相机视觉流程", MessageLevel.Debug);
- var _cts = new CancellationTokenSource();
- await _remoteCommandService.SetLightBeforePhoto(FzCameraProcess);
- var FzCameraResult = _remoteCommandService.ExecutePhotoGetDistance(FzCameraProcess, null);
- if (FzCameraResult)
- {
- SendTaskMessage("翻转相机拍照成功", MessageLevel.Debug);
- resultphoto = "Pass";
- await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage("翻转相机拍照失败", MessageLevel.Alarm);
- resultphoto = "Fail";
- await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
- }
- if (stationConfig2.SaveCsv)
- {
- List<DataFormCtq> DFC = new List<DataFormCtq>();
- string saveppid = "NA";
- string names = currentProduct.Name;
- if (stationConfig2.SaveCsvPPID) saveppid = ppid[i];
- DateTime servertime = DateTime.Now;
- // Dictionary<string, double> adjacentDiffDict1 = GetAdjacentDiffDict(keyData1);
- //判断锁付路径字符串是否为空,如果不为空则保存,否则不保存
- if (!string.IsNullOrEmpty(stationConfig2.SaveCsvPath))
- {
- DFC.Add(new DataFormCtq
- {
- PPID = saveppid,
- PROCESS_NAME = stationConfig2.DataInfo.PROCESS_NAME,
- PROCESS_START_TIME = _LastMesCheckTime[5].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- CTQ_NAME = "FzCameraPhoto",
- CTQ_VALUE = 0,
- CTQ_LSL = 0,
- CTQ_USL = 0,
- PROCESS_END_TIME = servertime.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- SUPPLIER_NAME = stationConfig2.DataInfo.SUPPLIER_NAME,
- COMMODITY_TYPE = stationConfig2.DataInfo.COMMODITY_TYPE,
- REVISION = stationConfig2.DataInfo.REVISION + "_" + revision[i],
- WO = "wo",//
- MFG_LOT = stationConfig2.DataInfo.MFG_LOT,//
- MFG_ASSY_LINE = stationConfig2.DataInfo.MFG_ASSY_LINE,
- PROCESS_OUTCOME = resultphoto,
- PROCESS_MACHINE_ID = stationConfig2.DataInfo.PROCESS_MACHINE_ID,
- CTQ_UNIT_OF_MEASURE = "mm",
- ERROR_MESSAGE = "",
- PD_ATTR_01 = _productService.CurrentProductCode,//
- PD_ATTR_02 = "",
- PD_ATTR_03 = "",
- PD_ATTR_04 = code,
- PD_ATTR_05 = "",
- });
- bool recordResult = RecordStationResult(0, DFC, _productService.CurrentProductCode, servertime.Subtract(_LastMesCheckTime[5]).TotalSeconds, _LastMesCheckTime[5], stationConfig2.SaveCsvPath);
- if (recordResult)
- {
- SendTaskMessage($"翻转相机拍照产品记录保存成功", MessageLevel.Debug);
- }
- else
- {
- SendTaskMessage($"{stationConfig2.DeviceName}产品记录保存失败", MessageLevel.Error);
- }
- }
- else
- {
- SendTaskMessage($"{stationConfig2.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
- }
- }
- }
- else
- {
- SendTaskMessage($"触发翻转相机检测拍照信号已关闭", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)0);
- }
- }
- }
- // 开始锁付
- else if (addressConfig.In_WorkStart.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is Int16 state)
- {
- if (_LastWorkStart != state)
- {
- _LastWorkStart = state;
- }
- else
- {
- return;
- }
- var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 0));
- if (state == 1)
- {
- SendTaskMessage(Lang.收到开始锁付信号, MessageLevel.Debug);
- StartScrewTime = DateTime.Now;
- //位置编号
- Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, positionIndex), MessageLevel.Info);
- // 开始采集压力值,ProductMainSN[i]
- //StartPressureCollection(currentProduct.Name, _productService.CurrentProductCode, 0);
- StartPressureCollection(currentProduct.Name, _productService.CurrentProductCode, 0);
- }
- else
- {
- SendTaskMessage(Lang.开始锁付信号已关闭, MessageLevel.Alarm);
- // 关闭时的处理(如需)可放在这里
- }
- }
- }
- // 停止锁付
- else if (addressConfig.In_WorkDone.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is Int16 state)
- {
- if (_LastWorkDone != state)
- {
- _LastWorkDone = state;
- }
- else
- {
- return;
- }
- if (state == 1 || state == 2)
- {
- if (TorqueStatus)
- {
- }
- SendTaskMessage(Lang.收到停止锁付信号, MessageLevel.Debug);
- //位置编号
- Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, positionIndex), MessageLevel.Info);
- //获取当前锁付点
- var screwPoint = currentProduct.ScrewPoints.FirstOrDefault(p => p.Number == positionIndex);
- //获取当前的机器人点位
- var robot = _robotService.GetAllRobots().FirstOrDefault();
- var currentPosition = robot.GetRobotPos();
- //读取压力值
- float pressure = _maxPressure;
- //当前用户名
- string currentUserName = _systemDatabaseService.GetCurrentUser().UserName;
- //吸嘴最后一次的记录
- var nozzleRecord = await _systemDatabaseService.GetLatestNozzleChangeRecordAsync();
- //最后一次的吸嘴编号
- string nozzleNumber = nozzleRecord != null ? nozzleRecord.NozzleBatchNumber : "N/A";
- //披头最后一次的记录
- var headRecord = await _systemDatabaseService.GetLatestHeadChangeRecordAsync();
- //最后一次的披头编号
- string headNumber = headRecord != null ? headRecord.HeadBatchNumber : "N/A";
- await Task.Delay(60);
- //获取电批结果
- bool isSucced = ScrewDriver.GetData();
- LockResult lockResult = new LockResult();
- lockResult.ScrewdriverGetDataSucceed = isSucced;
- lockResult.Number = positionIndex;
- lockResult.LockPassed = ScrewDriver.Success;
- lockResult.ProductName = currentProduct.Name;
- lockResult.ProductNumber = _productService.CurrentProductCode;
- lockResult.LockTurns = (float)ScrewDriver.Truns;
- lockResult.LockTorque = (float)ScrewDriver.TorqueValue;
- lockResult.LockDuration = (float)ScrewDriver.FinalTime;
- lockResult.ScrewdriverProgramNumber = ScrewDriver.ProgramNumber;
- lockResult.ResultDetails = ScrewDriver.ErrorInfo;
- lockResult.Pressure = pressure;
- lockResult.TargetTorqueUpperLimit = ScrewDriver.TargetTorqueUpperLimit;
- lockResult.TargetTorqueLowerLimit = ScrewDriver.TargetTorqueLowerLimit;
- lockResult.TargetTurnsUpperLimit = ScrewDriver.TargetTurnsUpperLimit / 360;
- lockResult.TargetTurnsLowerLimit = ScrewDriver.TargetTurnsLowerLimit / 360;
- lockResult.TargetLockSpeed = ScrewDriver.TargetLockSpeed;
- lockResult.PositionX = currentPosition.X;
- lockResult.PositionY = currentPosition.Y;
- lockResult.StartPositionZ = screwPoint.Z_Position_Start;
- lockResult.EndPositionZ = currentPosition.Z;
- lockResult.LockDescentSpeed = screwPoint.Z_Velocity_Stop;
- lockResult.FeederNumber = screwPoint != null ? screwPoint.Feeder : 0;
- lockResult.NozzleNumber = nozzleNumber;
- lockResult.HeadNumber = headNumber;
- lockResult.OperatorName = currentUserName;
- lockResult.ProductImagePath = "";
- lockResult.WaveDatas = ScrewDriver.WaveDatas;
- //pressure = 0;
- //获取系统参数
- var systemConfig = _configService.GetSystemConfiguration();
- //判断是否保存锁付曲线
- if (systemConfig.IsSaveScrewCurve)
- {
- //锁付曲线的保存路径为:systemConfig.ScrewCurvePath//年月//年月日//配方名//产品SN//产品SN+螺丝索引
- string datePath = DateTime.Now.ToString("yyyy-MM") + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\";
- string dirPath = System.IO.Path.Combine(systemConfig.ScrewCurvePath, datePath, currentProduct.Name, lockResult.ProductNumber);
- if (!Directory.Exists(dirPath))
- {
- Directory.CreateDirectory(dirPath);
- }
- string curveFileName = $"{lockResult.ProductNumber}-{lockResult.Number}.png";
- //锁付CSV保存路径
- string curveFileFullPath = System.IO.Path.Combine(dirPath, $"{lockResult.ProductNumber}-{lockResult.Number}.csv");
- //锁付曲线保存路径
- lockResult.LockCurveImagePath = System.IO.Path.Combine(dirPath, curveFileName);
- var _ = lockResult.SaveToCsvAsync(curveFileFullPath);
- }
- if (lockResult.Number == 1)
- {
- dataToMes.Clear();
- resultToMes.Clear();
- lockResultsAll.Clear();
- }
- //基于当前的锁付结果和产品的规格参数判断锁付结果是否合格
- var stationConfig = _configService.GetDeviceInfo(0);
- bool torqueRes = false, turnRes = false, pressureRes = false;
- bool lastRes = false;//默认不合格,只有当扭力、圈数、压力都在设定的上下限范围内时,才判定为锁付合格
- if (lockResult.LockTorque >= lockResult.TargetTorqueLowerLimit && lockResult.LockTorque <= lockResult.TargetTorqueUpperLimit)
- {
- torqueRes = true;
- }
- if (lockResult.Pressure >= stationConfig.DataInfo.CTQ_LSL_Pressure && lockResult.Pressure <= stationConfig.DataInfo.CTQ_USL_Pressure)
- {
- pressureRes = true;
- }
- if (lockResult.LockTurns >= lockResult.TargetTurnsLowerLimit && lockResult.LockTurns <= lockResult.TargetTurnsUpperLimit)
- {
- turnRes = true;
- }
- if (torqueRes == true && turnRes == true && pressureRes == true)//当扭力、圈数、压力都在设定的上下限范围内时,才判定为锁付合格
- {
- lastRes = true;
- }
- if (dataToMes.Keys.Contains($"Torque{lockResult.Number}"))
- {
- dataToMes.Remove($"Torque{lockResult.Number}");
- }
- if (dataToMes.Keys.Contains($"Turn{lockResult.Number}"))
- {
- dataToMes.Remove($"Turn{lockResult.Number}");
- }
- if (dataToMes.Keys.Contains($"Pressure{lockResult.Number}"))
- {
- dataToMes.Remove($"Pressure{lockResult.Number}");
- }
- lockResult.LockPassed = lastRes;
- dataToMes.Add($"Torque{lockResult.Number}", $"{lockResult.LockTorque:F2}");
- dataToMes.Add($"Turn{lockResult.Number}", $"{lockResult.LockTurns:F2}");
- dataToMes.Add($"Pressure{lockResult.Number}", $"{lockResult.Pressure:F2}");
- //dataToMes.Add($"LastResult{lockResult.Number}", $"{lastRes}");
- if (!lastRes)//如果不合格,则在MES结果中添加"Screw{lockResult.Number}_Fail"
- {
- if (!resultToMes.Contains($"Screw{lockResult.Number}_Fail"))
- {
- resultToMes.Add($"Screw{lockResult.Number}_Fail");
- SendTaskMessage($"Screw{lockResult.Number}:锁附不合格", MessageLevel.Error);
- }
- }
- SendTaskMessage($"螺丝序号:{lockResult.Number},扭力:{lockResult.LockTorque},压力:{lockResult.Pressure},圈数:{lockResult.LockTurns}", MessageLevel.Info);
- _maxPressure = 0;
- lockResultsAll.Add(lockResult);
- App.Current.Dispatcher.Invoke(() =>
- {
- _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult);
- });
- //记录锁付结果至数据库
- await _systemDatabaseService.RecordLockResultAsync(lockResult);
- //披头数量+1
- NumStatistics.HeaderNum = await _systemDatabaseService.IncrementLatestHeadLockCountAsync(currentUserName);
- //吸嘴数量+1
- NumStatistics.NozzleNum = await _systemDatabaseService.IncrementLatestNozzleLockCountAsync(currentUserName);
- await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
- // 停止采集压力并保存
- await StopAndSavePressureCollectionAsync(currentProduct.Name, _productService.CurrentProductCode, positionIndex);
- pressure = 0;
- }
- else
- {
- SendTaskMessage(Lang.停止锁付信号已关闭, MessageLevel.Alarm);
- }
- }
- }
- // 多相机坐标合并
- else if (addressConfig.In_RequestPosition.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is Int16 state)
- {
- if (_LastRequestPosition != state)
- {
- _LastRequestPosition = state;
- }
- else
- {
- return;
- }
- if (state == 1)
- {
- SendTaskMessage(Lang.收到多相机坐标合并请求开始合并, MessageLevel.Debug);
- //位置编号
- Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
- //是拍一个锁一个还是拍两个点锁所有
- var systemConfig = _configService.GetSystemConfiguration();
- //拍1打1
- if (systemConfig.WorkMode == 1)
- {
- List<PlcPoint> plcPoints = new List<PlcPoint>();
- foreach (var item in currentProduct.ScrewPoints)
- {
- if (item.IsUse)
- {
- plcPoints.Add(item);
- }
- }
- var TempPoint = plcPoints[positionIndex - 1];
- if (TempPoint == null)
- {
- SendTaskMessage($"点:{positionIndex}不存在", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
- return;
- }
- var PositionPoint = TempPoint.Clone();
- PositionPoint.X_Position = UpCameraPutResults[1].X + DowmCameraResults[1].X;
- PositionPoint.Y_Position = UpCameraPutResults[1].Y + DowmCameraResults[1].Y;
- SendTaskMessage($"点:{positionIndex},{PositionPoint.X_Position:F3},{PositionPoint.Y_Position:F4}", MessageLevel.Info);
- if (PositionPoint.X_Position == 0 || PositionPoint.Y_Position == 0)
- {
- SendTaskMessage("拟合位置为0,请检查", MessageLevel.Error);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
- return;
- }
- if (_configService.GetDeviceInfo().EnableXY)
- {
- //验证当前锁附点位与设置锁附点位的差值是否超限,超限则报警并停止流程
- //目前验证已OK 缺少切换按钮
- try
- {
- var ScrewLimit = currentProduct.GlobalParamListCollection.FirstOrDefault((p) => p.Number == positionIndex - 1);
- //判断实际偏差与设置的点位差数是否偏差过大
- float XOffsetPoint = Math.Abs(PositionPoint.X_Position - (TempPoint.X_Position + TempPoint.X_Offset));
- float YOffsetPoint = Math.Abs(PositionPoint.Y_Position - (TempPoint.Y_Position + TempPoint.Y_Offset));
- if (!(XOffsetPoint >= float.Parse(ScrewLimit.Param1) && XOffsetPoint <= float.Parse(ScrewLimit.Param2)) ||
- !(YOffsetPoint >= float.Parse(ScrewLimit.Param3) && YOffsetPoint <= float.Parse(ScrewLimit.Param4)))
- {
- SendTaskMessage($"当前锁附点位{positionIndex}与设置锁附点位差值超限,X偏差:{XOffsetPoint},Y偏差{YOffsetPoint}", MessageLevel.Error);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
- return;
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage($"当前锁附点位与设置锁附点位差值未设置:" + ex.Message, MessageLevel.Error);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
- return;
- }
- }
- await PositionPoint.WriteToPlcAddress(addressConfig.Out_Screw, plc, positionIndex);
- }
- //拍2打所有
- else if (systemConfig.WorkMode == 2)
- {
- //根据UpCameraPutResults[]中的索引1、2,和拍照点对应的Local下的坐标,从创建Local坐标系
- PointF worldP1 = new PointF(UpCameraPutResults[1].X, UpCameraPutResults[1].Y);
- PointF worldP2 = new PointF(UpCameraPutResults[2].X, UpCameraPutResults[2].Y);
- PointF localP1 = new PointF(currentProduct.ScrewCameraLocalPos1.X_Position, currentProduct.ScrewCameraLocalPos1.Y_Position);
- PointF localP2 = new PointF(currentProduct.ScrewCameraLocalPos2.X_Position, currentProduct.ScrewCameraLocalPos2.Y_Position);
- CoordinateTransformer local = new CoordinateTransformer(worldP1, worldP2, localP1, localP2);
- for (int i = 0; i < currentProduct.ScrewPoints.Count; i++)
- {
- var localPoint = new PointF(currentProduct.ScrewPoints[i].X_Position + currentProduct.ScrewPoints[i].X_Offset,
- currentProduct.ScrewPoints[i].Y_Position + currentProduct.ScrewPoints[i].Y_Offset);
- var worldPoint = local.ToOldCoord(localPoint.X, localPoint.Y);
- var point = currentProduct.ScrewPoints[i].Clone();
- //锁付点位在Local中已经加了偏移,这里写回PLC时需要将偏移清零,否则写入PLC端时会重复计算偏移
- point.X_Offset = 0;
- point.Y_Offset = 0;
- point.X_Position = (float)worldPoint[0];
- point.Y_Position = (float)worldPoint[1];
- SendTaskMessage($"点:{i},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
- if (_configService.GetDeviceInfo().ScrewOverrun)
- {
- try
- {
- var ScrewLimit = currentProduct.GlobalParamListCollection.FirstOrDefault((p) => p.Number == positionIndex - 1);
- //判断实际偏差与设置的点位差数是否偏差过大
- float XOffsetPoint = Math.Abs(localPoint.X - (float)worldPoint[0]);
- float YOffsetPoint = Math.Abs(localPoint.Y - (float)worldPoint[1]);
- if ((XOffsetPoint >= float.Parse(ScrewLimit.Param1) && XOffsetPoint <= float.Parse(ScrewLimit.Param2)) ||
- (YOffsetPoint >= float.Parse(ScrewLimit.Param3) && YOffsetPoint <= float.Parse(ScrewLimit.Param4)))
- {
- SendTaskMessage($"当前锁附点位{i}与设置锁附点位差值超限,X偏差:{XOffsetPoint},Y偏差{YOffsetPoint}", MessageLevel.Error);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
- return;
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage($"当前锁附点位与设置锁附点位差值超限:" + ex.Message, MessageLevel.Error);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
- }
- }
- await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
- }
- await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)currentProduct.ScrewPoints.Count);
- }
- //拍2打所有
- else if (systemConfig.WorkMode == 3)
- {
- if (positionIndex <= 3)
- {
- List<PlcPoint> plcPoints = new List<PlcPoint>();
- foreach (var item in currentProduct.ScrewPoints)
- {
- if (item.IsUse)
- {
- plcPoints.Add(item);
- }
- }
- var point = plcPoints[positionIndex - 1];
- if (point == null)
- {
- SendTaskMessage($"点:{positionIndex}不存在", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
- return;
- }
- point = point.Clone();
- point.X_Position = UpCameraPutResults[1].X + DowmCameraResults[1].X;
- point.Y_Position = UpCameraPutResults[1].Y + DowmCameraResults[1].Y;
- SendTaskMessage($"点:{positionIndex},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
- await point.WriteToPlcAddress(addressConfig.Out_Screw, plc, positionIndex);
- }
- else
- {
- //根据UpCameraPutResults[]中的索引1、2,和拍照点对应的Local下的坐标,从创建Local坐标系
- PointF worldP1 = new PointF(UpCameraPutResults[4].X, UpCameraPutResults[4].Y);
- PointF worldP2 = new PointF(UpCameraPutResults[5].X, UpCameraPutResults[5].Y);
- PointF localP1 = new PointF(currentProduct.ScrewCameraLocalPos1.X_Position, currentProduct.ScrewCameraLocalPos1.Y_Position);
- PointF localP2 = new PointF(currentProduct.ScrewCameraLocalPos2.X_Position, currentProduct.ScrewCameraLocalPos2.Y_Position);
- CoordinateTransformer local = new CoordinateTransformer(worldP1, worldP2, localP1, localP2);
- for (int i = 0; i < currentProduct.ScrewPoints.Count; i++)
- {
- var localPoint = new PointF(currentProduct.ScrewPoints[i].X_Position + currentProduct.ScrewPoints[i].X_Offset,
- currentProduct.ScrewPoints[i].Y_Position + currentProduct.ScrewPoints[i].Y_Offset);
- var worldPoint = local.ToOldCoord(localPoint.X, localPoint.Y);
- var point = currentProduct.ScrewPoints[i].Clone();
- //锁付点位在Local中已经加了偏移,这里写回PLC时需要将偏移清零,否则写入PLC端时会重复计算偏移
- point.X_Offset = 0;
- point.Y_Offset = 0;
- point.X_Position = (float)worldPoint[0];
- point.Y_Position = (float)worldPoint[1];
- SendTaskMessage($"点:{i},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
- await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
- }
- await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)currentProduct.ScrewPoints.Count);
- }
- }
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage(string.Format(Lang.多相机坐标合并请求已结束或被取消state0, state), MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)0);
- }
- }
- }
- // PLC请求二维码拍照位置
- else if (addressConfig.In_QrCodePhotoRequest.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is Int16 state)
- {
- if (_LastQrCodePhotoRequest != state)
- {
- _LastQrCodePhotoRequest = state;
- }
- else
- {
- return;
- }
- if (state == 1)
- {
- SendTaskMessage("收到PLC二维码拍照位置请求", MessageLevel.Debug);
- if (currentProduct.QrCodePoints == null || currentProduct.QrCodePoints.Count == 0)
- {
- SendTaskMessage("未找到示教后的二维码拍照点位", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
- return;
- }
- var qrpoint = currentProduct.QrCodePoints[0];
- //发送点位
- bool SendSuccess = await qrpoint.WriteToPlcAddress(addressConfig.Out_QrCodeCamera, plc);
- if (SendSuccess)
- {
- SendTaskMessage("二维码拍照点位发送成功", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
- Guid qrCodeProcedureId = currentProduct.QrCodeProcedureId;
- if (qrCodeProcedureId == Guid.Empty)
- {
- // 如果没有配置二维码视觉流程,直接返回成功
- SendTaskMessage("未配置二维码视觉流程,跳过扫码", MessageLevel.Info);
- return;
- }
- }
- else
- {
- SendTaskMessage("二维码拍照点位发送失败", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
- }
- }
- else
- {
- SendTaskMessage("二维码拍照点位发送信号已关闭", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)0);
- }
- }
- }
- // 螺丝供料器螺丝递减
- else if (addressConfig.In_PickINC.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is Int16 state)
- {
- if (_LastPickINC != state)
- {
- _LastPickINC = state;
- }
- else
- {
- return;
- }
- if (state != 0)
- {
- SendTaskMessage($"螺丝供料器...", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.In_PickINC.Address, (Int16)0);
- var feeders = _configService.GetRemainingCountByFeederNumber(state);
- if (state == 1)
- {
- NumStatistics.Feeder1Num = _configService.DecrementScrewCountByFeederNumber(feeders);
- }
- else if (state == 2)
- {
- NumStatistics.Feeder2Num = _configService.DecrementScrewCountByFeederNumber(feeders);
- }
- }
- }
- }
- // 抛料计数
- else if (addressConfig.In_Throw.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastThrowExe != state)
- {
- _LastThrowExe = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage("收到抛料信号", MessageLevel.Info);
- await _systemDatabaseService.RecordThrowNumberAsync(new ThrowRecord()
- {
- DayTime = DateTime.Now,
- ThrowCount = 1
- });
- }
- }
- }
- // 切换成自动运行模式
- else if (addressConfig.AutoRunning.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastAutoRunning != state)
- {
- _LastAutoRunning = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage("收到切换成自动模式", MessageLevel.Info);
- }
- else
- {
- SendTaskMessage("收到关闭自动模式", MessageLevel.Info);
- }
- CurrentRunStatus();
- }
- }
- // 切换成维修模式
- else if (addressConfig.ManualMode.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastManualMode != state)
- {
- _LastManualMode = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage("收到切换成维修模式", MessageLevel.Info);
- }
- else
- {
- SendTaskMessage("收到退出维修模式", MessageLevel.Info);
- }
- CurrentRunStatus();
- }
- }
- // 切换成流线模式
- else if (addressConfig.ClearMode.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastClearMode != state)
- {
- _LastClearMode = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendTaskMessage("收到切换成流线模式", MessageLevel.Info);
- }
- else
- {
- SendTaskMessage("收到退出流线模式", MessageLevel.Info);
- }
- CurrentRunStatus();
- }
- }
- //plc报警
- else if (addressConfig.Fault.Address.Contains(tuple.nodeId))
- {
- if (tuple.value is bool state)
- {
- if (_LastFault != state)
- {
- _LastFault = state;
- }
- else
- {
- return;
- }
- if (state)
- {
- SendAlarmToUi(plc);
- SendTaskMessage("收到PLC报警", MessageLevel.Error);
- }
- else
- {
- SendTaskMessage("收到PLC消除报警", MessageLevel.Debug);
- }
- }
- }
- // 过站检查
- else
- {
- for (int i = 0; i < 10; i++)
- {
- if (string.Format(addressConfig.In_MesCheck.Address, i).Contains(tuple.nodeId))
- {
- if (tuple.value is Int16 state)
- {
- //var oldState = _LastMesCheck[i];
- //_LastMesCheck[i] = state;
- //SendTaskMessage($"站点{i},收到PLC状态为:{state},旧状态为:{oldState}",MessageLevel.Info);
- //if (oldState == state)
- //{
- // return;
- //}
- if (_LastMesCheck[i] != state)
- {
- _LastMesCheck[i] = state;
- }
- else
- {
- return;
- }
- var systemConfig = _configService.GetSystemConfiguration();
- string code = "";
- //plc启用的模式
- bool models = plc.ReadNode<bool>(addressConfig.Cam_code_mode.Address);
- if (models && state == 1)
- {
- //拍照读码
- SendTaskMessage(Lang.触发上相机锁附组装拍照, MessageLevel.Debug);
- //相机的编号
- Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPutNum.Address);
- SendTaskMessage(string.Format(Lang.编号0, cameraIndex), MessageLevel.Info);
- Guid qrCodeProcedureId = currentProduct.QrCodeProcedureId;
- //视觉流程ID
- var qrCodeProcess = _productService.GetCurrentProductProcedureModelById(qrCodeProcedureId);
- if (qrCodeProcess == null)
- {
- SendTaskMessage($"未找到二维码视觉流程,流程ID: {qrCodeProcedureId}", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
- return;
- }
- SendTaskMessage($"开始执行二维码扫码视觉流程", MessageLevel.Debug);
- var _cts = new CancellationTokenSource();
- await _remoteCommandService.SetLightBeforePhoto(qrCodeProcess);
- var qrCodeResult = _remoteCommandService.ExecutePhoto(i + 1, qrCodeProcess, out CogToolBlockTerminalCollection outputCollection);
- if (qrCodeResult && outputCollection.Contains("QR"))
- {
- code = outputCollection["QR"].Value as string;
- code = code.ToUpper();
- if (!string.IsNullOrEmpty(code) && code.Length > 5)
- {
- if (systemConfig.IsBasePartCodeChooseScrew)//是否基于零件码,判断是不是当站要打的螺丝
- {
- var val = CheckCode(code, systemConfig.ChooseScrewModel);
- if (val)
- {
- SendTaskMessage($"是当站螺丝:{code}", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage($"不是当站螺丝:{code}", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
- return;
- }
- }
- bool _isSuccess = plc.WriteNode<string>(string.Format(addressConfig.In_Code.Address, 0), code);
- if (_isSuccess)
- {
- SendTaskMessage($"二维码扫码成功:{code}", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
- }
- else
- {
- SendTaskMessage($"二维码扫码成功:{code}", MessageLevel.Info);
- SendTaskMessage($"发送plc二维码失败:{code}", MessageLevel.Error);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
- }
- }
- else
- {
- SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
- return;
- }
- }
- else
- {
- code = "";
- SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
- await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
- return;
- }
- }
- else
- {
- code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
- }
- //if (!(i == 0 || i == 7))
- //{
- // return;
- //}
- productSn = code;
- SendTaskMessage($"收到plc信号{state}", MessageLevel.Debug);
- //询问mes
- if (state == 1)
- {
- SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
- //获取过站时间
- _LastMesCheckTime[i] = (await _mesService.GetServerTimeAsync(i, code, 2)).Now;
- if (_configService.GetDeviceInfo().EnableMES)
- {
- LogHelper.WriteLogMes($"【mes开始QUERY】");
- SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
- //dataToMes.Clear();
- if (systemConfig.IsBasePartCodeGetSN)//是否基于零件码,判断是否过站
- {
- SendTaskMessage($"基于零件码,判断是否过站", MessageLevel.Debug);
- (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);//基于电池的SN获取产品SN,询问mes
- if (isSuccess)
- {
- string ProductMainSN_Temp = "";
- LogHelper.WriteLogMes($"询问mes成功");
- SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- string[] item = response.Split('\n');
- //获取过度件sn
- string snItem = item.FirstOrDefault(f => f.Contains("sn="));
- if (snItem != null)
- {
- ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
- SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
- }
- LogHelper.WriteLogMes($"询问mes成功");
- SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- //20260214,螺丝机特别版
- (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
- if (isSuccess2)
- {
- LogHelper.WriteLogMes($"询问mes成功");
- SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
- item = response2.Split('\n');
- snItem = item.FirstOrDefault(f => f.Contains("sn="));
- if (snItem != null)
- {
- ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
- if (i == 0)
- {
- _productService.CurrentProductCode = ProductMainSN[i];
- }
- //_eventAggregator.GetEvent<DelaySaveImageNotification>().Publish(true);//通知界面延迟保存图片,等待MES查询结果返回,避免图片和数据不同步
- SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
- }
- string woItem = item.FirstOrDefault(f => f.Contains("wo="));
- if (woItem != null)
- {
- wo[i] = woItem.Replace("wo=", "").Trim();
- SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
- }
- string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
- if (modelItem != null)
- {
- model_num[i] = modelItem.Replace("model_num=", "").Trim();
- SendTaskMessage($"model_num:{model_num[i]}", MessageLevel.Info);
- }
- string colorItem = item.FirstOrDefault(f => f.Contains("color="));
- if (colorItem != null)
- {
- color[i] = colorItem.Replace("color=", "").Trim();
- SendTaskMessage($"color:{color[i]}", MessageLevel.Info);
- }
- string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
- if (ppidItem != null)
- {
- ppid[i] = ppidItem.Replace("ppid=", "").Trim();
- SendTaskMessage($"ppid:{ppid[i]}", MessageLevel.Info);
- }
- string revisionItem = item.FirstOrDefault(f => f.Contains("stage="));
- if (revisionItem != null)
- {
- revision[i] = revisionItem.Replace("stage=", "").Trim();
- SendTaskMessage($"stage:{revision[i]}", MessageLevel.Info);
- }
- LogHelper.WriteLogMes($"第二次询问mes成功");
- SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
- //切换产品
- if (i == 0)//i=0时才会切换产品
- {
- var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num[i], color[i]);
- if (q != null && !string.IsNullOrEmpty(q.ProductName))
- {
- ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
- Guid productId = Guid.Empty;
- foreach (var itt in ProductList)
- {
- if (itt.Name == q.ProductName)
- {
- productId = itt.ID;
- break;
- }
- }
- if (currentProduct.ID != productId)
- {
- //切换产品
- await _productService.LoadProductAsync(productId);
- _productService.SetCurrentProduct(productId);
- await WriteParameterToPlcExAsync();
- SendTaskMessage($"切换产品成功", MessageLevel.Debug);
- }
- }
- }
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
- }
- else
- {
- LogHelper.WriteLogMes($"第二次询问mes失败");
- SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
- }
- }
- else
- {
- LogHelper.WriteLogMes($"询问mes失败");
- SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
- }
- }
- else //直接基于RFID询问是否过站
- {
- SendTaskMessage($"基于RFID询问是否过站", MessageLevel.Debug);
- (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
- if (isSuccess)
- {
- string ProductMainSN_Temp = "";
- LogHelper.WriteLogMes($"询问mes成功");
- SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- string[] item = response.Split('\n');
- //获取过度件sn
- string snItem = item.FirstOrDefault(f => f.Contains("sn="));
- if (snItem != null)
- {
- ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
- SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
- }
- LogHelper.WriteLogMes($"询问mes成功");
- SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
- if (isSuccess2)
- {
- item = response2.Split('\n');
- snItem = item.FirstOrDefault(f => f.Contains("sn="));
- if (snItem != null)
- {
- ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
- if (i == 0)
- {
- _productService.CurrentProductCode = ProductMainSN[i];
- }
- SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
- }
- string woItem = item.FirstOrDefault(f => f.Contains("wo="));
- if (woItem != null)
- {
- wo[i] = woItem.Replace("wo=", "").Trim();
- SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
- }
- string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
- if (modelItem != null)
- {
- model_num[i] = modelItem.Replace("model_num=", "").Trim();
- SendTaskMessage($"model_num:{model_num[i]}", MessageLevel.Info);
- }
- string colorItem = item.FirstOrDefault(f => f.Contains("color="));
- if (colorItem != null)
- {
- color[i] = colorItem.Replace("color=", "").Trim();
- SendTaskMessage($"color:{color[i]}", MessageLevel.Info);
- }
- string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
- if (ppidItem != null)
- {
- ppid[i] = ppidItem.Replace("ppid=", "").Trim();
- SendTaskMessage($"ppid:{ppid[i]}", MessageLevel.Info);
- }
- string revisionItem = item.FirstOrDefault(f => f.Contains("stage="));
- if (revisionItem != null)
- {
- revision[i] = revisionItem.Replace("stage=", "").Trim();
- SendTaskMessage($"stage:{revision[i]}", MessageLevel.Info);
- }
- LogHelper.WriteLogMes($"第二次询问mes成功");
- SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
- //切换产品
- if (i == 0)//i=0时才会切换产品
- {
- var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num[i], color[i]);
- if (q != null && !string.IsNullOrEmpty(q.ProductName))
- {
- ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
- Guid productId = Guid.Empty;
- foreach (var itt in ProductList)
- {
- if (itt.Name == q.ProductName)
- {
- productId = itt.ID;
- break;
- }
- }
- if (currentProduct.ID != productId)
- {
- //切换产品
- await _productService.LoadProductAsync(productId);
- _productService.SetCurrentProduct(productId);
- await WriteParameterToPlcExAsync();
- SendTaskMessage($"切换产品成功", MessageLevel.Debug);
- }
- }
- }
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
- return;
- }
- else
- {
- LogHelper.WriteLogMes($"第二次询问mes失败");
- SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- if (models)
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
- SendTaskMessage($"发送plc信号3", MessageLevel.Debug);
- return;
- }
- else
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
- SendTaskMessage($"发送plc信号2", MessageLevel.Debug);
- return;
- }
- }
- }
- else
- {
- LogHelper.WriteLogMes($"询问mes失败");
- SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- if (models)
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
- SendTaskMessage($"发送plc信号3", MessageLevel.Debug);
- return;
- }
- else
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
- SendTaskMessage($"发送plc信号2", MessageLevel.Debug);
- return;
- }
- }
- }
- LogHelper.WriteLogMes($"【mes结束QUERY】");
- SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
- }
- else
- {
- ProductMainSN[i] = DateTime.Now.ToString("yyyyMMddHHmmssfff");
- if (i == 0)
- {
- _productService.CurrentProductCode = ProductMainSN[i];
- }
- LogHelper.WriteLogMes($"【未启用mes】");
- SendTaskMessage($"未启用mes", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
- SendTaskMessage($"发送plc信号2", MessageLevel.Debug);
- }
- }
- // 上传本站数据
- else if (state == 2)
- {
- DFC.Clear();//CTQ数据集合
- // string productccode = ProductMainSN[i];
- //获取当前工位的配置
- var stationConfig = _configService.GetDeviceInfo(i);
- var sysConfig = _configService.GetSystemConfiguration();
- SendTaskMessage($"收到{i}:{stationConfig.DeviceName}上传本站数据请求...", MessageLevel.Debug);
- //从服务器中获取当前时间
- LogHelper.WriteLogMes($"【从服务器中获取当前时间】");
- SendTaskMessage($"从服务器中获取当前时间", MessageLevel.Info);
- var serverTimeResult = await _mesService.GetServerTimeAsync(i, ProductMainSN[i], 2);
- //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
- if (i == 0)
- {
- CTtime = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds;
- _eventAggregator.GetEvent<DelaySaveImageNotification>().Publish(true);//通知界面延迟保存图片,等待MES查询结果返回,避免图片和数据不同步
- }
- //读取产品结果
- Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address, i));
- //目前只记录当前站
- if (i == 0)
- await _systemDatabaseService.RecordProductionAsync(new ProductionRecord()
- {
- ProductName = currentProduct.Name,
- ProductCode = ProductMainSN[i],
- DeviceId = i,
- DeviceName = "",
- Category = resultIndex == 1 ? "OK" : "NG",
- Quantity = 1,
- Remark = $"TotalSeconds:{serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds.ToString("F2")}",
- });
- LogHelper.WriteLogMes($"【mes开始ADD】");
- SendTaskMessage($"mes开始ADD", MessageLevel.Info);
- if (i == 0)
- {
- foreach (var lockResult in lockResultsAll)
- {
- bool torqueRes, turnRes, pressureRes;
- if (lockResult.LockTorque >= lockResult.TargetTorqueLowerLimit && lockResult.LockTorque <= lockResult.TargetTorqueUpperLimit)
- {
- torqueRes = true;
- }
- else torqueRes = false;
- if (lockResult.Pressure >= stationConfig.DataInfo.CTQ_LSL_Pressure && lockResult.Pressure <= stationConfig.DataInfo.CTQ_USL_Pressure)
- {
- pressureRes = true;
- }
- else pressureRes = false;
- if (lockResult.LockTurns >= lockResult.TargetTurnsLowerLimit && lockResult.LockTurns <= lockResult.TargetTurnsUpperLimit)
- {
- turnRes = true;
- }
- else turnRes = false;
- string midValue = "NA", saveppid = "NA";
- if (stationConfig.SaveCsvPPID) saveppid = ppid[i];
- midValue = ((lockResult.TargetTorqueLowerLimit + lockResult.TargetTorqueUpperLimit) / 2).ToString("F3");
- DFC.Add(new DataFormCtq
- {
- PPID = saveppid,
- ScrewNum = lockResult.Number,
- PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
- PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- CTQ_NAME = "Torque",
- CTQ_VALUE = lockResult.LockTorque,
- CTQ_LSL = lockResult.TargetTorqueLowerLimit,
- CTQ_USL = lockResult.TargetTorqueUpperLimit,
- PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
- COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
- REVISION = stationConfig.DataInfo.REVISION + "_" + revision[i],
- WO = wo[i],
- MFG_LOT = stationConfig.DataInfo.MFG_LOT,
- MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
- PROCESS_OUTCOME = torqueRes ? "PASS" : "FAIL",
- PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
- CTQ_UNIT_OF_MEASURE = "kgf.cm",
- ERROR_MESSAGE = torqueRes ? "NA" : "Torque_Spec OOS",
- PD_ATTR_01 = ProductMainSN[i],
- PD_ATTR_02 = midValue,
- PD_ATTR_03 = "NA",
- PD_ATTR_04 = productSn,
- PD_ATTR_05 = "NA",
- });
- midValue = ((lockResult.TargetTurnsLowerLimit + lockResult.TargetTurnsUpperLimit) / 2).ToString("F3");
- DFC.Add(new DataFormCtq
- {
- PPID = saveppid,
- ScrewNum = lockResult.Number,
- PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
- PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- CTQ_NAME = "Turn",
- CTQ_VALUE = lockResult.LockTurns,
- CTQ_LSL = lockResult.TargetTurnsLowerLimit,
- CTQ_USL = lockResult.TargetTurnsUpperLimit,
- PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
- COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
- REVISION = stationConfig.DataInfo.REVISION + "_" + revision[i],
- WO = wo[i],
- MFG_LOT = stationConfig.DataInfo.MFG_LOT,
- MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
- PROCESS_OUTCOME = turnRes ? "PASS" : "FAIL",
- PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
- CTQ_UNIT_OF_MEASURE = "Turn",
- ERROR_MESSAGE = turnRes ? "NA" : "Turn_Spec OOS",
- PD_ATTR_01 = ProductMainSN[i],
- PD_ATTR_02 = midValue,
- PD_ATTR_03 = "NA",
- PD_ATTR_04 = productSn,
- PD_ATTR_05 = "NA",
- });
- midValue = ((stationConfig.DataInfo.CTQ_LSL_Pressure + stationConfig.DataInfo.CTQ_USL_Pressure) / 2).ToString("F3");
- DFC.Add(new DataFormCtq
- {
- PPID = saveppid,
- ScrewNum = lockResult.Number,
- PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
- PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- CTQ_NAME = "Pressure",
- CTQ_VALUE = lockResult.Pressure,
- CTQ_LSL = stationConfig.DataInfo.CTQ_LSL_Pressure,
- CTQ_USL = stationConfig.DataInfo.CTQ_USL_Pressure,
- PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
- COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
- REVISION = stationConfig.DataInfo.REVISION + "_" + revision[i],
- WO = wo[i],
- MFG_LOT = stationConfig.DataInfo.MFG_LOT,
- MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
- PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
- PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
- CTQ_UNIT_OF_MEASURE = "kg",
- ERROR_MESSAGE = pressureRes ? "NA" : "Pressure_Spec OOS",
- PD_ATTR_01 = ProductMainSN[i],
- PD_ATTR_02 = midValue,
- PD_ATTR_03 = "NA",
- PD_ATTR_04 = productSn,
- PD_ATTR_05 = "NA",
- });
- }
- if (systemConfig.IsBasePartOpenLightKB)
- {
- string midValue = "999", saveppid = "NA";
- double upvlalue = 0, doenvlaue = 0;
- if (stationConfig.SaveCsvPPID) saveppid = ppid[i];
- bool pressureRes = true;
- foreach (var item in mes_cc)
- {
- switch (item.Key)
- {
- case "1":
- upvlalue = Convert.ToDouble(currentProduct.GlobalParamEx.CC1DownLimit.ToString("F3"));
- doenvlaue = Convert.ToDouble(currentProduct.GlobalParamEx.CC1UpLimit.ToString("F3"));
- midValue = ((currentProduct.GlobalParamEx.CC1DownLimit + currentProduct.GlobalParamEx.CC1UpLimit) / 2).ToString("F3");
- if (Convert.ToDouble(item.Value) < upvlalue || Convert.ToDouble(item.Value) > doenvlaue)
- {
- resultToMes.Add($"CC{item.Key}_Fail");
- SendTaskMessage($"CC{item.Key}:超限", MessageLevel.Error);
- }
- break;
- case "2":
- upvlalue = Convert.ToDouble(currentProduct.GlobalParamEx.CC2DownLimit.ToString("F3"));
- doenvlaue = Convert.ToDouble(currentProduct.GlobalParamEx.CC2UpLimit.ToString("F3"));
- midValue = ((currentProduct.GlobalParamEx.CC2DownLimit + currentProduct.GlobalParamEx.CC2UpLimit) / 2).ToString("F3");
- if (Convert.ToDouble(item.Value) < upvlalue || Convert.ToDouble(item.Value) > doenvlaue)
- {
- resultToMes.Add($"CC{item.Key}_Fail");
- SendTaskMessage($"CC{item.Key}:超限", MessageLevel.Error);
- }
- break;
- }
- dataToMes.Add($"CC{item.Key}", $"{item.Value}");
- DFC.Add(new DataFormCtq
- {
- PPID = saveppid,
- ScrewNum = 1,
- PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
- PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- CTQ_NAME = $"CC{item.Key}",
- CTQ_VALUE = Convert.ToDouble(item.Value.ToString()),
- CTQ_LSL = doenvlaue,
- CTQ_USL = upvlalue,
- PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
- SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
- COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
- REVISION = stationConfig.DataInfo.REVISION + "_" + revision[i],
- WO = wo[i],
- MFG_LOT = stationConfig.DataInfo.MFG_LOT,
- MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
- PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
- PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
- CTQ_UNIT_OF_MEASURE = "mm",
- ERROR_MESSAGE = pressureRes ? "NA" : $"CC{item.Key} OOS",
- PD_ATTR_01 = ProductMainSN[i],
- PD_ATTR_02 = midValue,
- PD_ATTR_03 = "NA",
- PD_ATTR_04 = productSn,
- PD_ATTR_05 = "NA",
- });
- }
- }
- }
- //上传mes
- if (stationConfig.EnableMES)
- {
- //测试使用,强制上传mes为pass
- if (sysConfig.IsMesResult)
- {
- resultToMes.Clear();
- }
- (bool isSuccess, string response) = await _mesService.SubmitGetExAsync(ProductMainSN[i], "", dataToMes, resultToMes, _LastMesCheckTime[i], serverTimeResult.Now);
- if (isSuccess)
- {
- LogHelper.WriteLogMes($"上传mes成功");
- SendTaskMessage($"上传mes成功", MessageLevel.Debug);
- }
- else
- {
- LogHelper.WriteLogMes($"上传mes失败");
- SendTaskMessage($"上传mes失败", MessageLevel.Error);
- }
- }
- else
- {
- LogHelper.WriteLogMes($"上传mes成功");
- SendTaskMessage($"上传mes成功", MessageLevel.Debug);
- }
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
- if (stationConfig.SaveCsv)
- {
- if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath))
- {
- bool recordResult = false;
- recordResult = RecordStationResult(i, DFC, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
- if (recordResult)
- {
- SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
- //上传数据
- try
- {
- if (stationConfig.EnableMES)
- {
- DateTime dt = DateTime.Now;
- string filename = $"{ProductMainSN[i]}_{dt.ToString("yyyyMMddHHmmss")}";
- var device = _configService.GetDeviceInfo();
- var config = _configService.GetSystemConfiguration();
- (bool isSuc, string resp) = await _mesService.SendFtpFileAsync(ProductMainSN[i], filename);
- if (isSuc)
- {
- LogHelper.WriteLogMes($"上传数据成功");
- SendTaskMessage($"上传数据成功", MessageLevel.Debug);
- string filePath = $"D:\\image\\Recored\\{dt.ToString("yyyy-MM")}\\{dt.ToString("MM-dd")}\\{currentProduct.Name}\\{ProductMainSN[i]}";
- //string source_csv2 = $"{stationConfig.SaveCsvPath}\\{dt.ToString("yyyy-MM")}\\{i}_{stationConfig.DeviceName}_{dt.ToString("yyyy-MM-dd")}";
- if (!Directory.Exists(filePath))
- {
- Directory.CreateDirectory(filePath);
- }
- string csvfilename = $"{i}_{stationConfig.DeviceName}_{dt.ToString("yyyy-MM-dd")}";
- //复制csv
- string source_csv = $"{stationConfig.SaveCsvPath}\\{dt.ToString("yyyy-MM")}\\{i}_{stationConfig.DeviceName}_{dt.ToString("yyyy-MM-dd")}.csv";
- string target_csv = Path.Combine(filePath, Path.GetFileName(source_csv));
- File.Copy(source_csv, target_csv, true);
- //复制log
- string source_log = $"..\\Log\\LogInfo\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}.txt";
- string target_log = Path.Combine(filePath, Path.GetFileName(source_log));
- File.Copy(source_log, target_log, true);
- //判断是否保存锁付曲线
- if (systemConfig.IsSaveScrewCurve)
- {
- string target_Directory = filePath + "\\扭力曲线\\";
- string source_Torque_Image = config.ScrewCurvePath + $"\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}\\{currentProduct.Name}\\{ProductMainSN[i]}";
- try
- {
- var col = Directory.GetFiles(source_Torque_Image);
- Directory.CreateDirectory(target_Directory);
- foreach (var item in col)
- {
- string target_Torque = target_Directory + item.Replace(source_Torque_Image, "");
- File.Copy(item, target_Torque, true);
- }
- }
- catch (Exception)
- {
- SendTaskMessage($"扭力曲线图读取失败", MessageLevel.Error);
- }
- }
- CompressionImage(filePath, filename, device.Station, device.FixtureId);
- //上传csv
- bool isAfter20 = dt.Hour >= 20;
- //判断是否是新的一天
- bool isNewDay = dt.Date != _lastCompressDate.Date;
- //当天还没执行过压缩
- if (isAfter20 && isNewDay && !_hasCompressedToday)
- {
- // 执行压缩
- CompressionSingleCsv(source_csv, csvfilename, device.Station, device.FixtureId);
- _lastCompressDate = dt;
- _hasCompressedToday = true;
- LogHelper.WriteLogMes("csv上传数据成功");
- SendTaskMessage($"csv上传数据成功", MessageLevel.Debug);
- }
- // 跨天后重置当天执行标记
- if (!isNewDay && _hasCompressedToday)
- {
- _hasCompressedToday = false;
- }
- }
- else
- {
- LogHelper.WriteLogMes($"上传数据失败");
- SendTaskMessage($"上传数据失败", MessageLevel.Error);
- }
- }
- else
- {
- LogHelper.WriteLogMes($"未启用mes");
- SendTaskMessage($"未启用mes", MessageLevel.Error);
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage($"上传数据时出错:{ex.Message}", MessageLevel.Error);
- LogHelper.WriteLogError($"上传数据时出错", ex);
- }
- }
- else
- {
- SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error);
- }
- }
- else
- {
- SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
- }
- }
- else
- {
- SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug);
- }
- WriteProductLog(lockResultsAll, ProductMainSN[i], CTtime);
- mes_cc.Clear();
- LogHelper.WriteLogMes($"【mes结束ADD】");
- SendTaskMessage($"mes结束ADD", MessageLevel.Info);
- }
- //kb 螺丝站位询问mes 具体需求跟plc对接
- else if (state == 5)
- {
- SendTaskMessage($"收到KB Screw站点{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
- //获取过站时间
- _LastMesCheckTime[i] = (await _mesService.GetServerTimeAsync(i, code, 2)).Now;
- if (_configService.GetDeviceInfo().EnableMES)
- {
- LogHelper.WriteLogMes($"【mes开始QUERY】");
- SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
- SendTaskMessage($"基于RFID询问是否过站", MessageLevel.Debug);
- (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
- //如果成功的话就代表跟正常mes询问一样,当前站需工作
- if (isSuccess)
- {
- string ProductMainSN_Temp = "";
- LogHelper.WriteLogMes($"询问mes成功");
- SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- string[] item = response.Split('\n');
- //获取过度件sn
- string snItem = item.FirstOrDefault(f => f.Contains("sn="));
- if (snItem != null)
- {
- ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
- SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
- }
- LogHelper.WriteLogMes($"询问mes成功");
- SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
- (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
- if (isSuccess2)
- {
- item = response2.Split('\n');
- snItem = item.FirstOrDefault(f => f.Contains("sn="));
- if (snItem != null)
- {
- ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
- if (i == 0)
- {
- _productService.CurrentProductCode = ProductMainSN[i];
- }
- SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
- }
- string woItem = item.FirstOrDefault(f => f.Contains("wo="));
- if (woItem != null)
- {
- wo[i] = woItem.Replace("wo=", "").Trim();
- SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
- }
- string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
- if (modelItem != null)
- {
- model_num[i] = modelItem.Replace("model_num=", "").Trim();
- SendTaskMessage($"model_num:{model_num[i]}", MessageLevel.Info);
- }
- string colorItem = item.FirstOrDefault(f => f.Contains("color="));
- if (colorItem != null)
- {
- color[i] = colorItem.Replace("color=", "").Trim();
- SendTaskMessage($"color:{color[i]}", MessageLevel.Info);
- }
- string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
- if (ppidItem != null)
- {
- ppid[i] = ppidItem.Replace("ppid=", "").Trim();
- SendTaskMessage($"ppid:{ppid[i]}", MessageLevel.Info);
- }
- string revisionItem = item.FirstOrDefault(f => f.Contains("stage="));
- if (revisionItem != null)
- {
- revision[i] = revisionItem.Replace("stage=", "").Trim();
- SendTaskMessage($"stage:{revision[i]}", MessageLevel.Info);
- }
- LogHelper.WriteLogMes($"第二次询问mes成功");
- SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
- //切换产品
- if (i == 0)//i=0时才会切换产品
- {
- var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num[i], color[i]);
- if (q != null && !string.IsNullOrEmpty(q.ProductName))
- {
- ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
- Guid productId = Guid.Empty;
- foreach (var itt in ProductList)
- {
- if (itt.Name == q.ProductName)
- {
- productId = itt.ID;
- break;
- }
- }
- if (currentProduct.ID != productId)
- {
- //切换产品
- await _productService.LoadProductAsync(productId);
- _productService.SetCurrentProduct(productId);
- await WriteParameterToPlcExAsync();
- SendTaskMessage($"切换产品成功", MessageLevel.Debug);
- }
- }
- }
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
- }
- else
- {
- LogHelper.WriteLogMes($"第二次询问mes失败");
- SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- if (models)
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
- }
- else
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
- }
- }
- }
- else
- {
- LogHelper.WriteLogMes($"询问mes失败");
- SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
- //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- //表示前面的kb screw站点已经打完螺丝并且过站成功到3d aoi,根据plc的需求直接放行
- if (response.Contains("3D AOI"))
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
- return;
- }
- //表示kb组装 站点ng 具体写入型号跟plc对接
- else if (response.Contains("C_KB_Link"))
- {
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)5);
- return;
- }
- // 后面还有一些判断条件也需跟当前AE对接
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
- }
- LogHelper.WriteLogMes($"【mes结束QUERY】");
- SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
- }
- else
- {
- ProductMainSN[i] = DateTime.Now.ToString("yyyyMMddHHmmssfff");
- if (i == 0)
- {
- _productService.CurrentProductCode = ProductMainSN[i];
- }
- LogHelper.WriteLogMes($"【未启用mes】");
- SendTaskMessage($"未启用mes", MessageLevel.Info);
- await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
- }
- }
- else
- {
- SendTaskMessage($"{i}过站检查信号:state={state},处理为默认状态", MessageLevel.Alarm);
- await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)0);
- return;
- }
- // _LastMesCheck[i] = 0;
- }
- }
- }
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- }
- }
- #endregion
- #region 方法
- public void SendTaskMessage(string msg, MessageLevel level)
- {
- App.Current.Dispatcher.Invoke(() =>
- {
- _eventAggregator.GetEvent<TaskMessageNotification>().Publish(new Models.MessageStruct() { Message = msg, level = level });
- });
- }
- #region 界面状态显示
- // 新增字段
- private readonly object _runStatusLock = new object();
- private RunDisplayMode _lastRunDisplayMode = RunDisplayMode.Unknown;
- /// <summary>
- /// 刷新当前运行状态
- /// </summary>
- public void CurrentRunStatus()
- {
- lock (_runStatusLock)
- {
- RunDisplayMode mode;
- try
- {
- mode = EvaluateRunDisplayMode();
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("刷新运行状态时出错", ex);
- mode = RunDisplayMode.Manual;
- }
- ApplyRunDisplayMode(mode);
- }
- }
- /// <summary>
- /// 计算当前应该显示的模式
- /// </summary>
- private RunDisplayMode EvaluateRunDisplayMode()
- {
- // 1. 流线模式优先
- if (_LastClearMode)
- {
- return RunDisplayMode.Clear;
- }
- // 2. 调机模式次优先
- if (_LastManualMode)
- {
- return RunDisplayMode.Manual;
- }
- // 3. 没进自动运行,默认按调机显示
- if (!_LastAutoRunning)
- {
- return RunDisplayMode.Manual;
- }
- // 4. 自动运行时,再检查前置条件
- bool connectStatus = IsAllDeviceConnected();
- bool mesStatus = IsMesReady();
- bool paraStatus = IsParameterReady();
- if (connectStatus && mesStatus && paraStatus)
- {
- return RunDisplayMode.Auto;
- }
- return RunDisplayMode.Manual;
- }
- /// <summary>
- /// 所有设备是否连接正常
- /// </summary>
- private bool IsAllDeviceConnected()
- {
- List<StatusInfo> statusSnapshot = null;
- App.Current.Dispatcher.Invoke(() =>
- {
- statusSnapshot = Status?.ToList() ?? new List<StatusInfo>();
- });
- if (statusSnapshot.Count == 0)
- {
- return false;
- }
- foreach (var item in statusSnapshot)
- {
- // 注意:这里不要直接 item.Background == Brushes.Red
- if (item?.Background is SolidColorBrush brush)
- {
- bool res = true;
- App.Current.Dispatcher.Invoke(() =>
- {
- if (brush.Color == Colors.Red)
- {
- SendTaskMessage("当前设备存在连接失败,请检查..." + item.Message, MessageLevel.Error);
- res = false;
- }
- });
- if (!res)
- {
- return false;
- }
- }
- }
- return true;
- }
- /// <summary>
- /// MES相关配置是否满足
- /// </summary>
- private bool IsMesReady()
- {
- var allDevices = _configService.GetAllDeviceInfos();
- for (int i = 0; i < ((allDevices.Count >= 8) ? 2 : 1); i++)
- {
- var stationConfig = allDevices.FirstOrDefault(d => d.DeviceNo == (i == 0 ? 0 : 7));
- if (stationConfig == null)
- {
- SendTaskMessage("当前MES未配置,请检查...", MessageLevel.Error);
- return false;
- }
- if (string.IsNullOrEmpty(stationConfig.SaveCsvPath) && i == 0)
- {
- SendTaskMessage("当前CSV路径为空,请检查...", MessageLevel.Error);
- return false;
- }
- if (!stationConfig.EnableMES || !stationConfig.SaveCsv)
- {
- SendTaskMessage("当前未启用MES或未启用CSV保存,请检查...", MessageLevel.Error);
- return false;
- }
- }
- return true;
- }
- /// <summary>
- /// 参数相关配置是否满足
- /// </summary>
- private bool IsParameterReady()
- {
- var systemConfig = _configService.GetSystemConfiguration();
- if (systemConfig == null)
- {
- SendTaskMessage("当前无系统文件,请检查...", MessageLevel.Error);
- return false;
- }
- if (!systemConfig.IsSaveScrewCurve)
- {
- SendTaskMessage("当前保存扭力曲线未勾选,请检查...", MessageLevel.Error);
- return false;
- }
- if (string.IsNullOrEmpty(systemConfig.ScrewCurvePath))
- {
- SendTaskMessage("当前保存扭力曲线为空,请检查...", MessageLevel.Error);
- return false;
- }
- return true;
- }
- /// <summary>
- /// 应用显示模式到UI
- /// </summary>
- private void ApplyRunDisplayMode(RunDisplayMode mode)
- {
- // 模式没变化就不重复刷UI,也不重复打日志
- if (_lastRunDisplayMode == mode)
- {
- return;
- }
- _lastRunDisplayMode = mode;
- App.Current.Dispatcher.Invoke(() =>
- {
- switch (mode)
- {
- case RunDisplayMode.Auto:
- CurrentDisplayMode = mode;
- SendTaskMessage("当前为运行模式", MessageLevel.Debug);
- break;
- case RunDisplayMode.Clear:
- CurrentDisplayMode = mode;
- SendTaskMessage("当前为流线模式", MessageLevel.Info);
- break;
- case RunDisplayMode.Manual:
- default:
- CurrentDisplayMode = mode;
- SendTaskMessage("当前为调机模式", MessageLevel.Info);
- break;
- }
- });
- }
- #endregion
- #region 压力采集
- private float _maxPressure = float.MinValue;
- /// <summary>
- /// 开始采集压力值
- /// </summary>
- /// <param name="productName">配方名称</param>
- /// <param name="productCode">产品编号</param>
- /// <param name="positionIndex">锁付点编号</param>
- private void StartPressureCollection(string productName, string productCode, int positionIndex)
- {
- try
- {
- // cancel existing if any
- //_pressureCts?.Cancel();
- //_pressureTimeoutCts?.Cancel();
- //_pressureLinkedCts?.Dispose();
- //_pressureSamples?.Clear();
- //_pressureTimeoutCts[positionIndex]?.Cancel();
- _pressureSamples?.Clear();
- _pressureCts[positionIndex] = new CancellationTokenSource();
- _pressureTimeoutCts[positionIndex] = new CancellationTokenSource();
- //_pressureCts = new CancellationTokenSource();
- //_pressureTimeoutCts = new CancellationTokenSource();
- // timeout after configured seconds
- _pressureTimeoutCts[positionIndex].CancelAfter(TimeSpan.FromSeconds(_pressureMaxDurationSeconds));
- // link tokens so either stop or timeout cancels
- _pressureLinkedCts[positionIndex] = CancellationTokenSource.CreateLinkedTokenSource(_pressureCts[positionIndex].Token, _pressureTimeoutCts[positionIndex].Token);
- var token = _pressureLinkedCts[positionIndex].Token;
- var addressConfig = _configService.GetPlcAddresses();
- var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
- if (plc == null || !plc.IsConnected) return;
- Task.Run(async () =>
- {
- SendTaskMessage($"Pressure collection started for position {positionIndex}", MessageLevel.Debug);
- while (!token.IsCancellationRequested)
- {
- try
- {
- float pressure = plc.ReadNode<float>(addressConfig.In_PressureValue.Address);
- lock (_pressureSamples)
- {
- //SendTaskMessage($"压力采集时出错:{pressure}", MessageLevel.Info);
- _pressureSamples.Add((DateTime.Now, pressure));
- if (pressure > _maxPressure)
- {
- _maxPressure = pressure;
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("采集压力值时出错", ex);
- }
- await Task.Delay(_pressureSampleIntervalMs);
- }
- SendTaskMessage($"Pressure {_pressureSamples}", MessageLevel.Debug);
- // if cancelled due to timeout
- //if (_pressureTimeoutCts[positionIndex].IsCancellationRequested && !_pressureCts[positionIndex].IsCancellationRequested)
- //{
- // SendTaskMessage("Pressure collection timed out, saving collected data.", MessageLevel.Alarm);
- // await StopAndSavePressureCollectionAsync(productName, productCode, positionIndex);
- //}
- }, token);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("StartPressureCollection error", ex);
- SendTaskMessage($"压力采集时出错:{ex.Message}", MessageLevel.Error);
- }
- }
- /// <summary>
- /// 停止采集并保存压力数据
- /// </summary>
- /// <param name="productName"></param>
- /// <param name="productCode"></param>
- /// <param name="positionIndex"></param>
- /// <returns></returns>
- private async Task StopAndSavePressureCollectionAsync(string productName, string productCode, int positionIndex)
- {
- try
- {
- // 获取当前产品
- var currentProduct = _productService.GetCurrentProduct();
- if (currentProduct == null)
- {
- return;
- }
- // cancel sampling
- //_pressureCts?.Cancel();
- // allow worker to observe cancel
- //await Task.Delay(50);
- List<(DateTime Timestamp, float Value)> snapshot;
- lock (_pressureSamples)
- {
- snapshot = new List<(DateTime, float)>(_pressureSamples);
- }
- if (snapshot.Count == 0)
- {
- SendTaskMessage("No pressure samples collected.", MessageLevel.Info);
- return;
- }
- // save to file under configured path
- try
- {
- //获取系统参数
- var systemConfig = _configService.GetSystemConfiguration();
- string datePath = DateTime.Now.ToString("yyyy-MM") + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\";
- string dirPath = System.IO.Path.Combine(systemConfig.ScrewCurvePath, datePath, currentProduct.Name, positionIndex.ToString());
- if (!Directory.Exists(dirPath))
- {
- Directory.CreateDirectory(dirPath);
- }
- string fileName = $"pressure-{productCode}-{positionIndex}-{DateTime.Now.ToString("HHmmss")}.csv";
- string fullPath = Path.Combine(dirPath, fileName);
- string pngfileName = $"pressure-{productCode}-{positionIndex}-{DateTime.Now.ToString("HHmmss")}.png";
- string pngPath = Path.Combine(dirPath, pngfileName);
- if (!systemConfig.IsSaveScrewCurve)
- {
- fullPath = string.Empty;
- pngPath = string.Empty;
- }
- App.Current.Dispatcher.Invoke(() =>
- {
- _eventAggregator.GetEvent<PressureFinishNotification>().Publish((true, snapshot.ToArray(), pngPath));
- });
- //判断是否保存锁付曲线
- if (systemConfig.IsSaveScrewCurve)
- {
- if (!string.IsNullOrEmpty(fullPath))
- {
- var sb = new StringBuilder();
- sb.AppendLine("Timestamp,Value");
- foreach (var s in snapshot)
- {
- sb.AppendLine($"{s.Timestamp:O},{s.Value}");
- }
- File.WriteAllText(fullPath, sb.ToString());
- SendTaskMessage($"Pressure samples saved to {fullPath}", MessageLevel.Debug);
- }
- }
- //var sb = new StringBuilder();
- //sb.AppendLine("Timestamp,Value");
- //foreach (var s in snapshot)
- //{
- // sb.AppendLine($"{s.Timestamp:O},{s.Value}");
- //}
- //File.WriteAllText(fullPath, sb.ToString());
- // SendTaskMessage($"Pressure samples saved to {fullPath}", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存压力采样文件时出错", ex);
- SendTaskMessage("保存压力采样文件时出错: " + ex.Message, MessageLevel.Error);
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("StopAndSavePressureCollectionAsync error", ex);
- }
- finally
- {
- try
- {
- _pressureLinkedCts[positionIndex]?.Cancel();
- _pressureLinkedCts[positionIndex]?.Dispose();
- _pressureTimeoutCts[positionIndex]?.Dispose();
- _pressureCts[positionIndex]?.Dispose();
- _pressureSamples?.Clear();
- //_maxPressure = 0;
- }
- catch { }
- }
- }
- #endregion
- #region 产品记录
- private async void DoYieldTime(object state)
- {
- try
- {
- //获取当前产品
- var currentproduct = _productService.GetCurrentProduct();
- if (currentproduct == null) return;
- TotalQuantity = await _systemDatabaseService.GetOverallProductionAsync(currentproduct.Name);
- TotalQuantityToday = await _systemDatabaseService.GetTodayProductionAsync(currentproduct.Name);
- CurrentUPH = await _systemDatabaseService.GetLastHourProductionAsync(currentproduct.Name);
- //
- ThrowNumber = await _systemDatabaseService.GetThrowNumberAsync();
- NgNumber = await _systemDatabaseService.GetNGProductionAsync(currentproduct.Name);
- Yield = ((double)TotalQuantityToday - (double)NgNumber) / (double)TotalQuantityToday * 100;
- }
- catch (Exception)
- {
- }
- }
- #endregion
- #region 字符判定
- /// <summary>
- /// 判断是否符合当站
- /// </summary>
- /// <param name="data"></param>
- /// <param name="checkData"></param>
- /// <returns></returns>
- private bool CheckCode(string data, string checkData)
- {
- try
- {
- if (data.Length != checkData.Length)
- {
- var len = checkData.Length - data.Length;
- LogHelper.WriteLogMes($"判断是否符合当站失败,字符长度差{len}");
- SendTaskMessage($"判断是否符合当站失败,字符长度差{len}", MessageLevel.Error);
- return false;
- }
- int count = checkData.Length;
- for (int i = 0; i < count; i++)
- {
- if (checkData[i] == '*')//不需要检测的部分
- {
- continue;
- }
- if (data[i] != checkData[i])//有值不一致
- {
- LogHelper.WriteLogMes($"判断是否符合当站失败,第{i}个字符,不一致");
- SendTaskMessage($"判断是否符合当站失败,第{i}个字符,不一致", MessageLevel.Error);
- return false;
- }
- }
- return true;
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogMes($"判断是否符合当站失败,{ex}");
- SendTaskMessage($"判断是否符合当站失败,{ex}", MessageLevel.Error);
- return false;
- }
- }
- #endregion
- #region vm启动检测
- /// <summary>
- /// 杀死所有VM有关进程
- /// </summary>
- public void KillVMProcess()
- {
- KillProcess("VisionMasterServerApp");
- KillProcess("VisionMaster");
- KillProcess("VmModuleProxy.exe");
- KillProcess("vServerApp.exe");
- }
- /// <summary>
- /// 杀死指定进程名的进程
- /// </summary>
- /// <param name="strKillName"></param>
- public void KillProcess(string strKillName)
- {
- foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
- {
- if (p.ProcessName.Contains(strKillName))
- {
- try
- {
- p.Kill();
- p.WaitForExit();
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError(string.Format(Lang.杀死进程0时失败, strKillName), ex);
- }
- }
- }
- }
- #endregion
- #region 拍螺丝数据保存csv
- /// <summary>
- /// 通用方法:将存储XYU的字典导出为规范CSV文件
- /// </summary>
- /// <param name="dataDict">存储XYU的字典</param>
- /// <param name="savePath">CSV文件保存路径</param>
- /// <param name="appendMode">是否追加模式(true=每次运行新增一行,false=覆盖原有文件)</param>
- /// <param name="decimalPlaces">数值保留的小数位数(默认4位,适配工业视觉精度)</param>
- static void ExportDictionaryToCsv(Dictionary<string, double> dataDict, string savePath, bool appendMode = false, int decimalPlaces = 4)
- {
- // 自动创建目录(避免路径不存在报错)
- string directory = Path.GetDirectoryName(savePath);
- if (!Directory.Exists(directory))
- {
- Directory.CreateDirectory(directory);
- }
- // 构建CSV内容
- StringBuilder csvContent = new StringBuilder();
- // 处理表头:仅当文件不存在/非追加模式时,才写入表头
- if (!appendMode || !File.Exists(savePath))
- {
- csvContent.AppendLine(string.Join(",", dataDict.Keys));
- }
- // 处理数据行:按指定小数位数格式化数值
- List<string> formattedValues = new List<string>();
- foreach (var value in dataDict.Values)
- {
- formattedValues.Add(Math.Round(value, decimalPlaces).ToString());
- }
- csvContent.AppendLine(string.Join(",", formattedValues));
- // 写入文件:UTF-8带BOM编码,Excel打开无乱码
- if (appendMode)
- {
- // 追加模式:在文件末尾新增内容
- File.AppendAllText(savePath, csvContent.ToString(), Encoding.UTF8);
- }
- else
- {
- // 覆盖模式:新建/替换文件
- File.WriteAllText(savePath, csvContent.ToString(), Encoding.UTF8);
- }
- }
- public bool ExportDictionaryToCsv1(string rfid, double x, double y, double u)
- {
- try
- {
- DateTime dt = DateTime.Now;
- if (rfid == null || rfid.Count() == 0)
- {
- rfid = dt.ToString("MM-dd-mm");
- }
- string path = $"D:\\视觉检测数据XYU数据\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}\\{rfid}.csv";
- StringBuilder sb = new StringBuilder();
- sb.AppendLine($"SN,X,Y,U");
- sb.AppendLine();
- sb.AppendLine($"{rfid},{x},{y},{u}");
- sb.AppendLine();
- if (!Directory.Exists(Path.GetDirectoryName(path))) //判断文件夹是否
- {
- Directory.CreateDirectory(Path.GetDirectoryName(path)); //创建文件夹
- }
- if (File.Exists(path))
- {
- // 使用 StreamWriter 以追加模式打开文件
- StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
- sw.WriteLine(sb.ToString().TrimEnd(','));
- //sw.WriteLine(sb1.ToString().TrimEnd(','));
- sw.Close();
- sw.Dispose();
- }
- else
- {
- StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
- sw.WriteLine(sb.ToString().TrimEnd(','));
- sw.Close();
- sw.Dispose();
- }
- return true;
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("写入产品记录时出错!", ex);
- return false;
- }
- }
- #endregion
- #region 产品锁付记录进行存储
- /// <summary>
- /// 产品锁付记录进行存储
- /// </summary>
- /// <param name="result">结果</param>
- public void WriteProductLog(List<LockResult> lockResults, string rfid, double ct)
- {
- try
- {
- string result = "";//产品的总结果
- foreach (var item in lockResults)
- {
- result = "OK";
- if (!item.LockPassed)
- {
- result = "NG";
- break;
- }
- }
- DateTime dt = DateTime.Now;
- int number = lockResults.Count;//螺丝数量
- string path = $"D:\\Data\\生产数据\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}.csv";
- StringBuilder sb = new StringBuilder();
- //具体的ct需要优化
- sb.Append($"{dt.ToString("yyyy-MM-dd HH:mm:ss")},{lockResults[0].ProductName},{Math.Round(ct, 3)},{rfid},{result},{lockResults[number - 1].NozzleNumber},{lockResults[number - 1].HeadNumber},");
- foreach (var item in lockResults)
- {
- try
- {
- string res = "";
- if (item.LockPassed)
- {
- res = "Pass";
- }
- else res = "Fail";
- sb.Append($"{res},{item.ResultDetails},{item.LockTorque},{item.TargetTorqueUpperLimit},{item.TargetTorqueLowerLimit},{item.LockTurns},{item.TargetTurnsUpperLimit},{item.TargetTurnsLowerLimit},{item.Pressure},{item.PositionX},{item.PositionY},{item.StartPositionZ},{item.EndPositionZ},{item.LockDescentSpeed},");
- }
- catch (Exception)
- {
- sb.Append($",,,,,,,,,,,,,,");
- }
- }
- //========================
- if (!Directory.Exists(Path.GetDirectoryName(path))) //判断文件夹是否
- {
- Directory.CreateDirectory(Path.GetDirectoryName(path)); //创建文件夹
- }
- if (File.Exists(path))
- {
- // 使用 StreamWriter 以追加模式打开文件
- StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
- sw.WriteLine(sb.ToString().TrimEnd(','));
- sw.Close();
- sw.Dispose();
- }
- else
- {
- StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
- StringBuilder sb1 = new StringBuilder();
- StringBuilder sb_up = new StringBuilder();
- StringBuilder sb_down = new StringBuilder();
- sb1.Append("时间,产品名称,CT,RFID,产品结果,吸嘴数量,披头数量,");
- for (int i = 0; i < number; i++)
- {
- sb1.Append($"螺丝{i + 1}结果,螺丝{i + 1}结果详情,螺丝{i + 1}扭矩,螺丝{i + 1}扭矩上限,螺丝{i + 1}扭矩下限,螺丝{i + 1}圈数,螺丝{i + 1}圈数上限,螺丝{i + 1}圈数下限,螺丝{i + 1}压力值,螺丝{i + 1}锁附X,螺丝{i + 1}锁附Y,螺丝{i + 1}开始位置Z,螺丝{i + 1}结束位置Z,螺丝{i + 1}锁附下降速度,");
- }
- sw.WriteLine(sb1.ToString().TrimEnd(','));
- sw.WriteLine(sb.ToString().TrimEnd(','));
- sw.Close();
- sw.Dispose();
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("写入产品记录时出错!", ex);
- }
- lockResultsAll.Clear();
- }
- /// <summary>
- /// 记录当前工位的锁付结果
- /// </summary>
- /// <param name="stationIndex"></param>
- /// <param name="lockResults"></param>
- /// <param name="productMainSN"></param>
- /// <param name="ct"></param>
- /// <param name="timestamp"></param>
- /// <param name="savePath"></param>
- /// <param name="isSingleLine">是否将所有螺丝的锁付结果一行显示,还是每颗螺丝单独一行显示,默认所有颗螺丝单独一行显示</param>
- /// <returns></returns>
- private bool RecordLockResult(int stationIndex, List<LockResult> lockResults, string productMainSN, double ct, DateTime timestamp, string savePath, bool isSingleLine = true, bool isFirstEnter = true)
- {
- try
- {
- //获取当前工位的配置
- var stationConfig = _configService.GetDeviceInfo(stationIndex);
- if (stationConfig == null) return false;
- //如果保存路径为空,则不保存
- if (string.IsNullOrEmpty(savePath)) return false;
- //如果锁付结果列表为空,则不保存
- if (lockResults == null || lockResults.Count == 0) return false;
- string fullPath = savePath;
- //如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存
- if (File.Exists(savePath) || Path.HasExtension(savePath))
- {
- fullPath = savePath;
- //如果路径不存在,则创建
- // 创建目录
- string directory = Path.GetDirectoryName(fullPath);
- if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
- {
- Directory.CreateDirectory(directory);
- }
- }
- else
- {
- //锁付结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv
- string datePath = timestamp.ToString("yyyy-MM") + "\\";
- string dirPath = Path.Combine(savePath, datePath);
- if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
- string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv";
- fullPath = Path.Combine(dirPath, fileName);
- }
- StringBuilder sb = new StringBuilder();
- if (!File.Exists(fullPath))
- {
- if (isSingleLine)
- {
- //将所有螺丝的锁付结果一行显示,列名格式:时间,产品主SN,CT,工位编号,工位名称,配方名称,配方编号,螺丝编号1,锁付结果1,锁付圈数1,锁付扭矩1,锁付时长1,电批程序编号1,结果详情1,压力值1,扭矩上限1,扭矩下限1,圈数上限1,圈数下限1,电批锁付速度1,锁附X1,锁附Y1,开始位置Z1,结束位置Z1,锁附下降速度1,螺丝供料器编号,...(依次类推直到螺丝编号n)
- sb.Append("时间,产品主SN,CT,工位编号,工位名称,配方名称,配方编号,");
- for (int i = 0; i < lockResults.Count; i++)
- {
- sb.Append($"螺丝编号{i + 1},锁付结果{i + 1},锁付圈数{i + 1},锁付扭矩{i + 1},锁付时长{i + 1},电批程序编号{i + 1},结果详情{i + 1},压力值{i + 1}," +
- $"扭矩上限{i + 1},扭矩下限{i + 1},圈数上限{i + 1},圈数下限{i + 1},电批锁付速度{i + 1},锁附X{i + 1},锁附Y{i + 1},开始位置Z{i + 1},结束位置Z{i + 1},锁附下降速度{i + 1},螺丝供料器编号{i + 1},");
- }
- sb.Append("吸嘴编号,披头编号,操作员姓名");
- }
- else
- {
- sb.Append("时间,产品主SN,CT,工位编号,工位名称,配方名称,配方编号,螺丝编号,锁付结果,锁付圈数,锁付扭矩,锁付时长,电批程序编号,结果详情,压力值," +
- "扭矩上限,扭矩下限,圈数上限,圈数下限,电批锁付速度,锁附X,锁附Y,开始位置Z,结束位置Z,锁附下降速度,螺丝供料器编号,吸嘴编号,披头编号,操作员姓名");
- }
- sb.AppendLine();
- }
- if (isSingleLine)
- {
- //将所有螺丝的锁付结果一行显示,列名格式:时间,产品主SN,CT,工位编号,工位名称,配方名称,配方编号,螺丝编号1,锁付结果1,锁付圈数1,锁付扭矩1,锁付时长1,电批程序编号1,结果详情1,压力值1,扭矩上限1,扭矩下限1,圈数上限1,圈数下限1,电批锁付速度1,锁附X1,锁附Y1,开始位置Z1,结束位置Z1,锁附下降速度1,螺丝供料器编号,...(依次类推直到螺丝编号n)
- sb.Append($"{timestamp:yyyy-MM-dd HH:mm:ss},{productMainSN},{Math.Round(ct, 3)},{stationIndex},{stationConfig.DeviceName},{lockResults[0].ProductName},{lockResults[0].ProductNumber},");
- for (int i = 0; i < lockResults.Count; i++)
- {
- var item = lockResults[i];
- sb.Append($"螺丝{i + 1},{item.LockPassed},{item.LockTurns},{item.LockTorque},{item.LockDuration},{item.ScrewdriverProgramNumber}," +
- $"{item.ResultDetails},{item.Pressure},{item.TargetTorqueUpperLimit},{item.TargetTorqueLowerLimit},{item.TargetTurnsUpperLimit},{item.TargetTurnsLowerLimit},{item.TargetLockSpeed}," +
- $"{item.PositionX},{item.PositionY},{item.StartPositionZ},{item.EndPositionZ},{item.LockDescentSpeed},{item.FeederNumber},");
- }
- sb.Append($"{lockResults[lockResults.Count - 1].NozzleNumber},{lockResults[lockResults.Count - 1].HeadNumber},{lockResults[lockResults.Count - 1].OperatorName}");
- sb.AppendLine();
- }
- else
- {
- foreach (var item in lockResults)
- {
- sb.Append($"{timestamp:yyyy-MM-dd HH:mm:ss},{productMainSN},{Math.Round(ct, 3)},{stationIndex},{stationConfig.DeviceName},{item.ProductName},{item.ProductNumber},{item.Number},{item.LockPassed},{item.LockTurns},{item.LockTorque},{item.LockDuration},{item.ScrewdriverProgramNumber}," +
- $"{item.ResultDetails},{item.Pressure},{item.TargetTorqueUpperLimit},{item.TargetTorqueLowerLimit},{item.TargetTurnsUpperLimit},{item.TargetTurnsLowerLimit},{item.TargetLockSpeed}," +
- $"{item.PositionX},{item.PositionY},{item.StartPositionZ},{item.EndPositionZ},{item.LockDescentSpeed},{item.FeederNumber},{item.NozzleNumber},{item.HeadNumber},");
- sb.AppendLine();
- }
- }
- // 使用 StreamWriter 以追加模式打开文件
- StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8);
- sw.Write(sb.ToString());
- sw.Close();
- sw.Dispose();
- return true;
- }
- catch (Exception ex)
- {
- if (!isFirstEnter)
- return false;
- LogHelper.WriteLogError("记录锁付结果时出错!", ex);
- //我希望在这里生成一个临时文件来保存这次的记录,因为如果本地文件被打开时可能会导致无法写入,如果不保存的话可能会丢失这次的记录,所以我想在这里生成一个临时文件来保存这次的记录
- //生成临时文件的路径,格式为savePath\yyyy-MM\工位编号_yyyy-MM-dd_temp\工位编号_yyyy-MM-dd_HH-mm-ss-fff_temp.csv
- string datePath = timestamp.ToString("yyyy-MM") + "\\";
- string tempDirPath = Path.Combine(savePath, datePath, $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd")}_temp");
- string tempFileName = $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd_HH-mm-ss-fff")}_temp.csv";
- RecordLockResult(stationIndex, lockResults, productMainSN, ct, timestamp, tempFileName, isSingleLine, false);
- return false;
- }
- }
- /// <summary>
- /// 记录其他工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值
- /// </summary>
- /// <param name="stationIndex"></param>
- /// <param name="dataItems"></param>
- /// <param name="productMainSN"></param>
- /// <param name="ct"></param>
- /// <param name="timestamp"></param>
- /// <param name="savePath"></param>
- /// <param name="isFirstEnter"></param>
- /// <returns></returns>
- private bool RecordOtherStationResult(int stationIndex, Dictionary<string, string> dataItems, string productMainSN, double ct, DateTime timestamp, string savePath, bool isFirstEnter = true)
- {
- try
- {
- //获取当前工位的配置
- var stationConfig = _configService.GetDeviceInfo(stationIndex);
- if (stationConfig == null) return false;
- // 获取当前产品
- var currentProduct = _productService.GetCurrentProduct();
- if (currentProduct == null)
- {
- return false;
- }
- //如果保存路径为空,则不保存
- if (string.IsNullOrEmpty(savePath)) return false;
- string fullPath = savePath;
- //如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存
- if (File.Exists(savePath) || Path.HasExtension(savePath))
- {
- fullPath = savePath;
- //如果路径不存在,则创建
- // 创建目录
- string directory = Path.GetDirectoryName(fullPath);
- if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
- {
- Directory.CreateDirectory(directory);
- }
- }
- else
- {
- //结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv
- string datePath = timestamp.ToString("yyyy-MM") + "\\";
- string dirPath = Path.Combine(savePath, datePath);
- if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
- string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv";
- fullPath = Path.Combine(dirPath, fileName);
- }
- StringBuilder sb = new StringBuilder();
- if (!File.Exists(fullPath))
- {
- sb.Append("时间,产品主SN,CT,工位编号,工位名称,配方名称,配方编号,");
- foreach (var item in dataItems)
- {
- sb.Append($"{item.Key},");
- }
- sb.AppendLine();
- }
- sb.Append($"{timestamp:yyyy-MM-dd HH:mm:ss},{productMainSN},{Math.Round(ct, 3)},{stationIndex},{stationConfig.DeviceName},{currentProduct.Name},{currentProduct.NumberCode},");
- foreach (var item in dataItems)
- {
- sb.Append($"{item.Value},");
- }
- sb.AppendLine();
- // 使用 StreamWriter 以追加模式打开文件
- StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8);
- sw.Write(sb.ToString());
- sw.Close();
- sw.Dispose();
- return true;
- }
- catch (Exception ex)
- {
- if (!isFirstEnter)
- {
- return false;
- }
- LogHelper.WriteLogError("记录其他工位结果时出错!", ex);
- //我希望在这里生成一个临时文件来保存这次的记录,因为如果本地文件被打开时可能会导致无法写入,如果不保存的话可能会丢失这次的记录,所以我想在这里生成一个临时文件来保存这次的记录
- //生成临时文件的路径,格式为savePath\yyyy-MM\工位编号_yyyy-MM-dd_temp\工位编号_yyyy-MM-dd_HH-mm-ss-fff_temp.csv
- string datePath = timestamp.ToString("yyyy-MM") + "\\";
- string tempDirPath = Path.Combine(savePath, datePath, $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd")}_temp");
- string tempFileName = $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd_HH-mm-ss-fff")}_temp.csv";
- RecordOtherStationResult(stationIndex, dataItems, productMainSN, ct, timestamp, tempFileName, false);
- return false;
- }
- }
- /// <summary>
- /// 记录工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值
- /// </summary>
- /// <param name="stationIndex"></param>
- /// <param name="dfcs"></param>
- /// <param name="productMainSN"></param>
- /// <param name="ct"></param>
- /// <param name="timestamp"></param>
- /// <param name="savePath"></param>
- /// <param name="isFirstEnter"></param>
- /// <returns></returns>
- private bool RecordStationResult(int stationIndex, IEnumerable<DataFormCtq> dfcs, string productMainSN, double ct, DateTime timestamp, string savePath, bool isFirstEnter = true)
- {
- try
- {
- //获取当前工位的配置
- var stationConfig = _configService.GetDeviceInfo(stationIndex);
- if (stationConfig == null) return false;
- //如果保存路径为空,则不保存
- if (string.IsNullOrEmpty(savePath)) return false;
- string fullPath = savePath;
- //如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存
- if (!File.Exists(savePath) || !Path.HasExtension(savePath))
- {
- fullPath = savePath;
- //如果路径不存在,则创建
- // 创建目录
- string directory = Path.GetDirectoryName(fullPath);
- if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
- {
- Directory.CreateDirectory(directory);
- }
- }
- //结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv
- string datePath = timestamp.ToString("yyyy-MM") + "\\";
- string dirPath = Path.Combine(savePath, datePath);
- if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
- string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv";
- fullPath = Path.Combine(dirPath, fileName);
- StringBuilder sb = new StringBuilder();
- if (!File.Exists(fullPath))
- {
- sb.Append("PPID,Screw_Number,PROCESS_NAME,PROCESS_START_TIME,CTQ_NAME,CTQ_VALUE,CTQ_LSL,CTQ_USL,PROCESS_END_TIME,SUPPLIER_NAME,COMMODITY_TYPE,REVISION,WO#,MFG_LOT#," +
- "MFG_ASSY_LINE,PROCESS_OUTCOME,PROCESS_MACHINE_ID,CTQ_UNIT_OF_MEASURE,ERROR_MESSAGE,PD_ATTR_01,PD_ATTR_02,PD_ATTR_03,PD_ATTR_04,PD_ATTR_05");
- sb.AppendLine();
- }
- if (dfcs == null || dfcs.Count() == 0)
- {
- return false;
- }
- foreach (var dfc in dfcs)
- {
- sb.Append($"{dfc.PPID},{dfc.ScrewNum},{dfc.PROCESS_NAME},{dfc.PROCESS_START_TIME},{dfc.CTQ_NAME},{dfc.CTQ_VALUE:F3},{dfc.CTQ_LSL:F3},{dfc.CTQ_USL:F3},{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},{dfc.PD_ATTR_01},{dfc.PD_ATTR_02},{dfc.PD_ATTR_03},{dfc.PD_ATTR_04},{dfc.PD_ATTR_05}");
- sb.AppendLine();
- }
- // 使用 StreamWriter 以追加模式打开文件
- StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8);
- sw.Write(sb.ToString());
- sw.Close();
- sw.Dispose();
- return true;
- }
- catch (Exception ex)
- {
- if (!isFirstEnter)
- {
- return false;
- }
- LogHelper.WriteLogError("记录其他工位结果时出错!", ex);
- //我希望在这里生成一个临时文件来保存这次的记录,因为如果本地文件被打开时可能会导致无法写入,如果不保存的话可能会丢失这次的记录,所以我想在这里生成一个临时文件来保存这次的记录
- //生成临时文件的路径,格式为savePath\yyyy-MM\工位编号_yyyy-MM-dd_temp\工位编号_yyyy-MM-dd_HH-mm-ss-fff_temp.csv
- string datePath = timestamp.ToString("yyyy-MM") + "\\";
- string tempDirPath = Path.Combine(savePath, datePath, $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd")}_temp");
- string tempFileName = $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd_HH-mm-ss-fff")}_temp.csv";
- RecordStationResult(stationIndex, dfcs, productMainSN, ct, timestamp, tempFileName, false);
- return false;
- }
- }
- #endregion
- #region 写log
- TxtFile mesLog = new TxtFile($"D:\\Data\\Mes记录", "");
- public void MesMessage(string msg)
- {
- mesLog.WriteLine("== " + msg + "\r\n");
- }
- TxtFile infoLog = new TxtFile($"D:\\Data\\运行日志", "");
- public void InfoMessage(string msg)
- {
- infoLog.WriteLine("== " + msg + "\r\n");
- }
- #endregion
- #region 压缩图片文件夹
- /// <summary>
- /// 压缩文件
- /// </summary>
- /// <param name="sourcePath">原路径</param>
- /// <param name="zipname">压缩后文件的名称</param>
- /// <param name="station">mes中的station</param>
- /// <param name="fixid">mes中的fixtureID</param>
- public async void CompressionImage(string sourcePath, string zipname, string station, string fixid)
- {
- string zipPath = "";
- try
- {
- SendTaskMessage($"开始压缩文件", MessageLevel.Info);
- await Task.Run(() =>
- {
- zipPath = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}\\{zipname}.zip";//生成的zip文件路径
- string path = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}";
- if (!Directory.Exists(path))
- {
- Directory.CreateDirectory(path);
- }
- ZipFile.CreateFromDirectory(sourcePath, zipPath);
- });
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError($"压缩文件时出错", ex);
- }
- }
- public async void CompressionSingleCsv(string csvFilePath, string zipname, string station, string fixid)
- {
- string zipPath = "";
- try
- {
- SendTaskMessage("开始压缩CSV文件", MessageLevel.Info);
- await Task.Run(() =>
- {
- if (!File.Exists(csvFilePath))
- {
- LogHelper.WriteLogMes($"CSV文件不存在,不压缩:{csvFilePath}");
- return;
- }
- zipPath = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}\\{zipname}.zip";
- string path = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}";
- if (!Directory.Exists(path))
- {
- Directory.CreateDirectory(path);
- }
- using (FileStream fs = new FileStream(zipPath, FileMode.Create))
- {
- using (ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Create))
- {
- archive.CreateEntryFromFile(csvFilePath, Path.GetFileName(csvFilePath));
- }
- }
- });
- SendTaskMessage("CSV文件压缩完成", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("压缩CSV文件失败", ex);
- }
- }
- #endregion
- /// <summary>
- /// 后台报警刷新显示(适配PLC结构化变量名Bool点位 OPC版)
- /// 完全沿用你原有循环结构、防抖逻辑、UI报警推送规则
- /// </summary>
- public void SendAlarmToUi(OpcUaClientPLC plc)
- {
- PlcExcelLoad loadData = new PlcExcelLoad();
- loadData.LoadData(6);
- // 增加报警状态缓存,防止循环重复刷屏报警
- Dictionary<string, bool> alarmLastState = new Dictionary<string, bool>();
- foreach (var alarm in loadData.AlaemList)
- {
- alarmLastState.Add(alarm.OpcAddress, true);
- }
- Task.Run(() =>
- {
- while (true)
- {
- try
- {
- Thread.Sleep(50);
- foreach (var alarm in loadData.AlaemList)
- {
- // 调用你封装好的OPC读取Bool方法
- bool plcState = plc.ReadBoolNode(alarm.OpcAddress);
- // 上升沿防抖:只有状态从正常→异常(false)变化时,才推送一次报警
- if (!plcState && alarmLastState[alarm.OpcAddress])
- {
- SendTaskMessage($"PLC报警信息:{alarm.Name}", MessageLevel.Error);
- LogHelper.WriteLogPlcWarn($"PLC报警信息:{alarm.Name}");
- alarmLastState[alarm.OpcAddress] = false;
- }
- // 报警复位:状态恢复正常,重置缓存
- else if (plcState && !alarmLastState[alarm.OpcAddress])
- {
- alarmLastState[alarm.OpcAddress] = true;
- }
- }
- }
- catch
- {
- Thread.Sleep(200);
- }
- }
- });
- }
- #endregion
- }
- }
|