| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204 |
- using Cognex.VisionPro.ToolBlock;
- using Cognex.VisionPro;
- using MathNet.Numerics.LinearAlgebra;
- using MathNet.Numerics.RootFinding;
- using NPOI.SS.Formula.Functions;
- using NPOI.Util;
- using OpenCvSharp;
- using OpenCvSharp.Flann;
- using Prism.Events;
- using Prism.Ioc;
- using Prism.Mvvm;
- using Prism.Regions;
- using Prism.Services.Dialogs;
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.IO;
- using System.Linq;
- using System.Net.Sockets;
- using System.Security.Cryptography;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Documents;
- using System.Windows.Interop;
- using System.Windows.Media;
- using System.Windows.Media.Media3D;
- using Team.FFFeederService;
- using Team.FFFeederService.Interfaces;
- using TeamAAS_VP.Data;
- using TeamAAS_VP.Enums;
- using TeamAAS_VP.Events;
- using TeamAAS_VP.Models;
- using TeamAAS_VP.ViewModels.Home;
- using TeamAAS_VP;
- using TouchSocket.Core;
- using TouchSocket.Sockets;
- using static MaterialDesignThemes.Wpf.Theme.ToolBar;
- using System.ComponentModel;
- using System.Collections;
- using System.Reflection.Metadata;
- using TeamAAS_VP.Resources.Languages;
- using TeamAAS_VP.Core.PLCs;
- using TeamAAS_VP.Interfaces;
- using Opc.Ua;
- using TeamAAS_VP.Core.Robots;
- using TeamAAS_VP.Core.RFID;
- using TeamAAS_VP.Controls;
- using TeamAAS_VP.Core.Sfis;
- namespace TeamAAS_VP.Core
- {
- public class Management : BindableBase
- {
- /// <summary>EthernetIP 底栏状态项固定 Id(与设备 Id 无关)</summary>
- public static readonly Guid EthernetIpStatusId = new Guid("E4E10000-0001-4000-8000-000000000001");
- #region 字段
- IRegionManager _regionManager;
- IEventAggregator _eventAggregator;
- IContainerProvider _container;
- System.Threading.Timer cTtimer;
- System.Threading.Timer yieldtimer;
- private bool IsStart = false;
- private DateTime StartTime = DateTime.Now;
- #endregion
- #region 属性
- /// <summary>
- /// 当前用户
- /// </summary>
- public User CurrentUser { get; set; } = new User() { UserName = "操作员", UserPassword = "", IsRemember = false, userPart = Enums.UserPart.Operator, CreateTime = DateTime.Now };
- /// <summary>
- /// 设备参数
- /// </summary>
- public DeviceConfiguration DeviceConfig { get; set; } = new DeviceConfiguration();
- private Language _CurrentLanguage = Language.ChineseSimplified;
- /// <summary>
- /// 当前软件使用的语言
- /// </summary>
- public Language CurrentLanguage
- {
- get { return _CurrentLanguage; }
- set { SetProperty(ref _CurrentLanguage, value); }
- }
- private ObservableCollection<ShowRender> _Renders;
- /// <summary>
- /// 显示界面
- /// </summary>
- public ObservableCollection<ShowRender> Renders
- {
- get { return _Renders; }
- set { SetProperty(ref _Renders, value); }
- }
- private Dictionary<Guid, Thread> _plcTrigger = new Dictionary<Guid, Thread>();
- /// <summary>
- /// 当前plc触发监控
- /// </summary>
- public Dictionary<Guid, Thread> PlcTrigger { get => _plcTrigger; set => _plcTrigger = value; }
- private ObservableCollection<ProductModel> _Products;
- /// <summary>
- /// 产品列表
- /// </summary>
- public ObservableCollection<ProductModel> Products
- {
- get { return _Products; }
- set { SetProperty(ref _Products, value); }
- }
- private ProductModel _CurrentProduct;
- /// <summary>
- /// 当前产品
- /// </summary>
- public ProductModel CurrentProduct
- {
- get { return _CurrentProduct; }
- set { SetProperty(ref _CurrentProduct, value); }
- }
- public FeederService FeederService { get; set; }
- public RobotService RobotService { get; set; }
- public CameraService CameraService { get; set; }
- public PlcService PlcService { get; set; }
- public BgCommunicate BgCommunicate { get; private set; }
- public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; }
- private CancellationTokenSource _handshakeCts;
- private Task _handshakeTask;
- private CancellationTokenSource _heartbeatCts;
- private Task _heartbeatTask;
- private CancellationTokenSource _sfisSignalCts;
- private Task _sfisSignalTask;
- private SfisWorkflowService _sfisWorkflow;
- private RFIDTagData _lastRfidTag;
- private readonly object _sync = new object();
- public SIG350RFIDClient BgEipCommunicate { get; private set; }
- private CancellationTokenSource _mcReconnectCts;
- private Task _mcReconnectTask;
- private readonly object _mcReconnectSync = new object();
- private DateTime _mcLastReconnectAttempt = DateTime.MinValue;
- private const int McReconnectIntervalMs = 3000;
- private Action<string> _mcPlcLogHandler;
- private volatile bool _mcMonitorLoopsStarted;
- public ModbusTcpMasterCommunicate ModbusTcpMasterCommunicate { get; private set; }
- /// <summary>
- /// Modbus TCP 主站配置(连接电批等设备)
- /// </summary>
- public ModbusTcpMasterConfig ModbusTcpMasterConfig { get; set; } = new ModbusTcpMasterConfig();
- private ObservableCollection<StatusInfo> _Status = new ObservableCollection<StatusInfo>();
- /// <summary>
- /// 状态栏集合
- /// </summary>
- public ObservableCollection<StatusInfo> Status
- {
- get { return _Status; }
- set { SetProperty(ref _Status, value); }
- }
- private TimeSpan _CT;
- public TimeSpan CT
- {
- get { return _CT; }
- set { SetProperty(ref _CT, 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); }
- }
- public Dictionary<string, object> BackupObject { get; set; } = new Dictionary<string, object>();
- #endregion
- #region 命令
- #endregion
- #region 事件
- #endregion
- public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container)
- {
- _regionManager = regionManager;
- _eventAggregator = ea;
- _container = container;
- cTtimer = new Timer(DoCycleTime, null, 5000, 100);
- yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
- Renders = new ObservableCollection<ShowRender>();
- }
- #region 配置参数读写操作
- /// <summary>
- /// 读取配置参数
- /// </summary>
- public void ReadConfig()
- {
- ReadCamerasDeviceConfig();
- ReadRobotsDeviceConfig();
- ReadFeedersDeviceConfig();
- ReadPlcDeviceConfig();
- ReadBgTcpIpDeviceConfig();
- ReadBgModbusTcpDeviceConfig();
- ReadModbusTcpMasterDeviceConfig();
- ReadBgEthernetIPDeviceConfig();
- ReadBgSfisDeviceConfig();
- }
- /// <summary>
- /// 读取相机设备配置参数
- /// </summary>
- public void ReadCamerasDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.CamerasConfigurationPath))
- {
- DeviceConfig.Cameras = FileHelper.ReadJsonFile<ObservableCollection<CameraInfo>>(FilePath.CamerasConfigurationPath);
- }
- else
- {
- DeviceConfig.Cameras = new ObservableCollection<CameraInfo>();
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.Robots = new ObservableCollection<RobotInfo>();
- LogHelper.WriteLogError("加载相机配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存相机设备配置参数
- /// </summary>
- public void SaveCamerasDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.Cameras, FilePath.CamerasConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存相机配置参数至文件时出错!", ex);
- }
- }
- /// <summary>
- /// 读取机器人设备配置参数
- /// </summary>
- public void ReadRobotsDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.RobotsConfigurationPath))
- {
- DeviceConfig.Robots = FileHelper.ReadJsonFile<ObservableCollection<RobotInfo>>(FilePath.RobotsConfigurationPath);
- }
- else
- {
- DeviceConfig.Robots = new ObservableCollection<RobotInfo>();
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.Robots = new ObservableCollection<RobotInfo>();
- LogHelper.WriteLogError("加载机器人配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存机器人设备配置参数
- /// </summary>
- public void SaveRobotsDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.Robots, FilePath.RobotsConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存机器人配置参数至文件时出错!", ex);
- }
- }
- /// <summary>
- /// 读取Feeder设备配置参数
- /// </summary>
- public void ReadFeedersDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.FeedersConfigurationPath))
- {
- DeviceConfig.Feeders = FileHelper.ReadJsonFile<ObservableCollection<FeederInfo>>(FilePath.FeedersConfigurationPath);
- }
- else
- {
- DeviceConfig.Feeders = new ObservableCollection<FeederInfo>();
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.Feeders = new ObservableCollection<FeederInfo>();
- LogHelper.WriteLogError("加载Feeder配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存Feeder设备配置参数
- /// </summary>
- public void SaveFeederDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.Feeders, FilePath.FeedersConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存Feeder配置参数至文件时出错!", ex);
- }
- }
- /// <summary>
- /// 读取PLC设备配置参数
- /// </summary>
- public void ReadPlcDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.PlcConfigurationPath))
- {
- DeviceConfig.Plcs = FileHelper.ReadJsonFile<ObservableCollection<PlcInfo>>(FilePath.PlcConfigurationPath);
- }
- else
- {
- DeviceConfig.Plcs = new ObservableCollection<PlcInfo>();
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.Plcs = new ObservableCollection<PlcInfo>();
- LogHelper.WriteLogError("加载PLC配置文件时出错!", ex);
- }
- TryMigrateLegacyMcConfig();
- }
- private void TryMigrateLegacyMcConfig()
- {
- if (DeviceConfig.Plcs.Any(p => p.CommunicationType == CommunicationType.Mitsubishi_MC))
- return;
- try
- {
- if (!File.Exists(FilePath.BgMCToPcCommunicatePath))
- return;
- var legacy = FileHelper.ReadJsonFile<MCToPCInfo>(FilePath.BgMCToPcCommunicatePath);
- if (legacy == null)
- return;
- var mcPlc = new PlcInfo
- {
- Id = Guid.NewGuid(),
- Name = "Mitsubishi MC",
- CommunicationType = CommunicationType.Mitsubishi_MC
- };
- mcPlc.ApplyMcInfo(legacy);
- DeviceConfig.Plcs.Add(mcPlc);
- SavePlcDeviceConfig();
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("迁移旧版 MC 配置至 PLC 列表时出错!", ex);
- }
- }
- /// <summary>
- /// 保存PLC设备配置参数
- /// </summary>
- public void SavePlcDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.Plcs, FilePath.PlcConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存PLC配置参数至文件时出错!", ex);
- }
- }
- /// <summary>
- /// 读取语言配置参数
- /// </summary>
- public void ReadLanguageDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.LanguageConfigurationPath))
- {
- CurrentLanguage = FileHelper.ReadJsonFile<Language>(FilePath.LanguageConfigurationPath);
- }
- else
- {
- CurrentLanguage = Language.ChineseSimplified;
- }
- }
- catch (Exception ex)
- {
- CurrentLanguage = Language.ChineseSimplified;
- LogHelper.WriteLogError("加载Language配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存语言配置参数
- /// </summary>
- public void SaveLanguageDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(CurrentLanguage, FilePath.LanguageConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存Language配置参数至文件时出错!", ex);
- }
- }
- /// <summary>
- /// 读取后台TCPIP通讯配置参数
- /// </summary>
- public void ReadBgTcpIpDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.BgTcpIpConfigurationPath))
- {
- DeviceConfig.BgCommunicate = FileHelper.ReadJsonFile<BgTcpIP>(FilePath.BgTcpIpConfigurationPath);
- }
- else
- {
- DeviceConfig.BgCommunicate = new BgTcpIP();
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.BgCommunicate = new BgTcpIP();
- LogHelper.WriteLogError("加载后台TCPIP通讯配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存后台TCPIP通讯配置参数
- /// </summary>
- public void SaveBgTcpIpDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.BgCommunicate, FilePath.BgTcpIpConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存后台TCPIP通讯配置参数至文件时出错!", ex);
- }
- }
- /// <summary>
- /// 读取后台ModbusTcp通讯配置参数
- /// </summary>
- public void ReadBgModbusTcpDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.BgModbusTcpConfigurationPath))
- {
- DeviceConfig.BgModbusCommunicate = FileHelper.ReadJsonFile<BgModbusTcp>(FilePath.BgModbusTcpConfigurationPath);
- }
- else
- {
- DeviceConfig.BgModbusCommunicate = new BgModbusTcp();
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.BgModbusCommunicate = new BgModbusTcp();
- LogHelper.WriteLogError("加载后台Modbus TCP通讯配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存后台ModbusTcp通讯配置参数
- /// </summary>
- public void SaveBgModbusTcpDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.BgModbusCommunicate, FilePath.BgModbusTcpConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存后台ModbusTcp通讯配置参数至文件时出错!", ex);
- }
- }
- /// <summary>
- /// 读取后台EthernetIP通讯配置参数
- /// </summary>
- public void ReadBgEthernetIPDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.BgEthernetIPCommunicatePath))
- {
- DeviceConfig.BgEthernetIPCommunicate = FileHelper.ReadJsonFile<BgEthernetIP>(FilePath.BgEthernetIPCommunicatePath);
-
- }
- else
- {
- DeviceConfig.BgEthernetIPCommunicate = new BgEthernetIP();
- FileHelper.WriteJsonFile(DeviceConfig.BgEthernetIPCommunicate, FilePath.BgEthernetIPCommunicatePath);
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.BgEthernetIPCommunicate = new BgEthernetIP();
- LogHelper.WriteLogError("加载后台Eip通讯配置文件时出错!", ex);
- }
- }
- public void ReadBgSfisDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.BgSfisCommunicatePath))
- {
- DeviceConfig.BgSfisCommunicate = FileHelper.ReadJsonFile<BgSfisConfig>(FilePath.BgSfisCommunicatePath);
- }
- else
- {
- DeviceConfig.BgSfisCommunicate = new BgSfisConfig();
- FileHelper.WriteJsonFile(DeviceConfig.BgSfisCommunicate, FilePath.BgSfisCommunicatePath);
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.BgSfisCommunicate = new BgSfisConfig();
- LogHelper.WriteLogError("加载 SFIS 配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存EIP配置
- /// </summary>
- public void SaveBgEthernetIPDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.BgEthernetIPCommunicate, FilePath.BgEthernetIPCommunicatePath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存后台Eip通讯配置参数至文件时出错!", ex);
- }
- }
- public void SaveBgSfisDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(DeviceConfig.BgSfisCommunicate, FilePath.BgSfisCommunicatePath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存 SFIS 配置参数至文件时出错!", ex);
- }
- }
- #endregion
- #region 初始化硬件模块
- /// <summary>
- /// 初始化视觉
- /// </summary>
- public Tuple<bool, string> InitVision()
- {
- try
- {
- return new Tuple<bool, string>(true, "");
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("初始化VM视觉方式时出错!", ex);
- return new Tuple<bool, string>(false, ex.Message);
- }
- }
- /// <summary>
- /// 初始化Feeder
- /// </summary>
- /// <returns></returns>
- public async Task<Tuple<bool, string>> InitFeeders()
- {
- FeederService = new FeederService();
- StringBuilder sb = new StringBuilder();
- foreach (var item in DeviceConfig.Feeders)
- {
- FeederService.CreateFeeder(item.Id, item.IP, item.Port, item.FeederBrand);
- Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- try
- {
- FeederService.GetFeeder(item.Id).FeederConnectedEvent += Management_FeederConnectedEvent;
- FeederService.GetFeeder(item.Id).FeederDisconnectedEvent += Management_FeederDisconnectedEvent;
- await FeederService.GetFeeder(item.Id).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 new Tuple<bool, string>(true, "");
- }
- else
- {
- return new Tuple<bool, string>(false, sb.ToString());
- }
- }
- /// <summary>
- /// 初始化机器人
- /// </summary>
- /// <returns></returns>
- public async Task<Tuple<bool, string>> InitRobots()
- {
- RobotService = new RobotService();
- StringBuilder sb = new StringBuilder();
- foreach (var item in DeviceConfig.Robots)
- {
- RobotService.CreateRobot(item.Id, item);
- if (item.RobotBrand == RobotBrand.XYZ_Platform || item.RobotBrand == RobotBrand.XYZU_Platform)
- {
- RobotService.GetRobot(item.Id).TrggerChangeEvent += Management_TrggerChangeEvent;
- continue;
- }
- try
- {
- Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- RobotService.GetRobot(item.Id).ReceivedEvent += Management_ReceivedEvent;
- RobotService.GetRobot(item.Id).SendEvent += Management_SendEvent;
- RobotService.GetRobot(item.Id).ConnectedEvent += Management_ConnectedEvent;
- RobotService.GetRobot(item.Id).DisconnectedEvent += Management_DisconnectedEvent;
- await RobotService.GetRobot(item.Id).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 new Tuple<bool, string>(true, "");
- }
- else
- {
- return new Tuple<bool, string>(false, sb.ToString());
- }
- }
- /// <summary>
- /// 初始化PLC
- /// </summary>
- /// <returns></returns>
- public async Task<Tuple<bool, string>> InitPlc()
- {
- PlcService = new PlcService();
- StringBuilder sb = new StringBuilder();
- foreach (var item in DeviceConfig.Plcs)
- {
- try
- {
- if (!PlcService.CreatePlc(item.Id, item))
- {
- sb.AppendLine($"{item.Name}: 不支持的 PLC 通讯类型 [{item.CommunicationType}]");
- continue;
- }
- var plc = PlcService.GetPlc(item.Id);
- if (plc == null)
- {
- sb.AppendLine($"{item.Name}: 创建 PLC 失败");
- continue;
- }
- Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- plc.ConnectChangedEvent += Management_PlcConnectChangedEvent;
- await plc.ConnectAsync();
- }
- catch (Exception ex)
- {
- sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]");
- SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm);
- }
- }
- if (sb.Length == 0)
- {
- return new Tuple<bool, string>(true, "");
- }
- else
- {
- return new Tuple<bool, string>(false, sb.ToString());
- }
- }
- /// <summary>
- /// 初始化相机
- /// </summary>
- /// <returns></returns>
- public Task<Tuple<bool, string>> InitCameras()
- {
- CameraService = new CameraService();
- StringBuilder sb = new StringBuilder();
- foreach (var item in DeviceConfig.Cameras)
- {
- try
- {
- Renders.Add(new ShowRender() { Id = item.Id, CameraName = item.CameraName });
- CameraService.CreateCamera(item.Id, item);
- Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
- CameraService.GetCamera(item.Id).CameraConnectChangedEvent += Management_CameraConnectChangedEvent;
- if (CameraService.GetCamera(item.Id).OpenDevice())
- {
- SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug);
- }
- else
- {
- SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
- sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!");
- }
- }
- 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 Task.FromResult(new Tuple<bool, string>(true, ""));
- }
- else
- {
- return Task.FromResult(new Tuple<bool, string>(false, sb.ToString()));
- }
- }
- /// <summary>
- /// 初始化后台TCP服务器通讯
- /// </summary>
- public void InitBgTcp()
- {
- try
- {
- BgCommunicate = new BgCommunicate(DeviceConfig.BgCommunicate);
- BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent;
- BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent;
- BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent;
- BgCommunicate.SendEvent += BgCommunicate_SendEvent;
- BgCommunicate.StartListening();
- SendTaskMessage($"{Lang.已开启监听端口}:{DeviceConfig.BgCommunicate.Port}", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- SendTaskMessage($"{Lang.未开启监听端口}:{DeviceConfig.BgCommunicate.Port}", MessageLevel.Error);
- LogHelper.WriteLogError("开启后台服务器通讯时出错!", ex);
- }
- }
- /// <summary>
- /// 初始化后台ModbusTCP从站
- /// </summary>
- public void InitModbusTcp()
- {
- try
- {
- BgModbusTcpCommunicate = new BgModbusTcpCommunicate(DeviceConfig.BgModbusCommunicate);
- if (DeviceConfig.BgModbusCommunicate.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("开启后台Modbus TCP通讯时出错!", ex);
- }
- }
- /// <summary>
- /// 读取 Modbus TCP 主站配置
- /// </summary>
- public void ReadModbusTcpMasterDeviceConfig()
- {
- try
- {
- if (File.Exists(FilePath.ModbusTcpMasterConfigurationPath))
- {
- ModbusTcpMasterConfig = FileHelper.ReadJsonFile<ModbusTcpMasterConfig>(FilePath.ModbusTcpMasterConfigurationPath);
- }
- else
- {
- ModbusTcpMasterConfig = new ModbusTcpMasterConfig();
- }
- }
- catch (Exception ex)
- {
- ModbusTcpMasterConfig = new ModbusTcpMasterConfig();
- LogHelper.WriteLogError("加载 Modbus TCP 主站配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存 Modbus TCP 主站配置
- /// </summary>
- public void SaveModbusTcpMasterDeviceConfig()
- {
- try
- {
- FileHelper.WriteJsonFile(ModbusTcpMasterConfig, FilePath.ModbusTcpMasterConfigurationPath);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("保存 Modbus TCP 主站配置时出错!", ex);
- }
- }
-
- /// <summary>
- /// 初始化 Modbus TCP 主站(轮询电批/扭矩控制器)
- /// </summary>
- public void InitModbusTcpMaster()
- {
- try
- {
- ModbusTcpMasterCommunicate?.Stop();
- ModbusTcpMasterCommunicate = new ModbusTcpMasterCommunicate(ModbusTcpMasterConfig, _eventAggregator);
- if (!ModbusTcpMasterConfig.IsEnabled)
- {
- return;
- }
- ModbusTcpMasterCommunicate.Start();
- SendTaskMessage($"Start Modbus Tcp Master:{ModbusTcpMasterConfig.IP}:{ModbusTcpMasterConfig.Port}:{ModbusTcpMasterConfig.SlaveID}", MessageLevel.Debug);
- }
- catch (Exception ex)
- {
- SendTaskMessage($"No Start Modbus Tcp Master:{ex.Message}", MessageLevel.Alarm);
- LogHelper.WriteLogError("开启 Modbus TCP 主站通讯时出错!", ex);
- }
- }
- /// <summary>
- /// 初始化 EthernetIP
- /// </summary>
- public void InitEthernetIP()
- {
- try
- {
- EnsureEthernetIpStatusEntry();
- DisposeRfidClient();
- BgEipCommunicate = new SIG350RFIDClient(DeviceConfig.BgEthernetIPCommunicate);
- BgEipCommunicate.BeforeStartRfidReading = ApplyEthernetIpRfidConfiguration;
- BgEipCommunicate.OnLog += BgEipCommunicate_OnLog;
- BgEipCommunicate.OnTagDataReceived += RfidClient_OnTagDataReceived;
- BgEipCommunicate.OnConnectReceive += Management_EipConnectChangedEvent;
- if (!DeviceConfig.BgEthernetIPCommunicate.IsEnabled)
- {
- UpdateEthernetIpStatus(false);
- return;
- }
- if (BgEipCommunicate.Connect())
- {
- UpdateEthernetIpStatus(true);
- SendTaskMessage($"EthernetIP:{DeviceConfig.BgEthernetIPCommunicate.IP}", MessageLevel.Debug);
- StartEthernetIpRfidIO();
- }
- else
- {
- UpdateEthernetIpStatus(false);
- // Connect 失败时会触发 OnConnectReceive(false),内部自动重连
- }
- }
- catch (Exception ex)
- {
- UpdateEthernetIpStatus(false);
- SendTaskMessage($"EthernetIP err:{ex.Message}", MessageLevel.Alarm);
- LogHelper.WriteLogError("开启 EthernetIP通讯时出错!", ex);
- }
- }
- private void EnsureEthernetIpStatusEntry()
- {
- if (Status.Any(s => s.ID == EthernetIpStatusId))
- return;
- App.Current.Dispatcher.Invoke(() =>
- {
- if (!Status.Any(s => s.ID == EthernetIpStatusId))
- {
- Status.Add(new StatusInfo(
- EthernetIpStatusId,
- $"{Lang.EthernetIP}{Lang.未连接}",
- new SolidColorBrush(Colors.Red)));
- }
- });
- }
- private void UpdateEthernetIpStatus(bool isConnected)
- {
- var sta = Status.FirstOrDefault(s => s.ID == EthernetIpStatusId);
- if (sta == null)
- return;
- App.Current.Dispatcher.Invoke(() =>
- {
- if (isConnected)
- {
- sta.Message = $"{Lang.EthernetIP}{Lang.已连接}";
- sta.Background = new SolidColorBrush(Colors.Green);
- }
- else
- {
- sta.Message = $"{Lang.EthernetIP}{Lang.未连接}";
- sta.Background = new SolidColorBrush(Colors.Red);
- }
- });
- }
- private void Management_EipConnectChangedEvent(bool isConnected)
- {
- if (isConnected)
- {
- SendTaskMessage($"{Lang.EthernetIP}{Lang.已连接}!", MessageLevel.Debug);
- TryStartHandshakeAfterEipReady();
- }
- else
- {
- SendTaskMessage($"{Lang.EthernetIP}{Lang.断开连接}!", MessageLevel.Error);
- }
- UpdateEthernetIpStatus(isConnected);
- }
- /// <summary>配置 RFID 端口(1..N)并固定为 UID 读模式。</summary>
- private void ApplyEthernetIpRfidConfiguration()
- {
- if (BgEipCommunicate == null || !BgEipCommunicate.IsConnected)
- return;
- var eipConfig = DeviceConfig.BgEthernetIPCommunicate;
- var ports = eipConfig.GetEnabledPortNumbers();
- BgEipCommunicate.ConfigureRFIDPorts(ports, PortMode.IOLAutostart);
- BgEipCommunicate.ConfigureReadOptions(eipConfig.ToRfh5xxReadOptions());
- SendTaskMessage($"RFID 已配置端口 1–{eipConfig.RfidPortCount},读 UID", MessageLevel.Debug);
- }
- private void StartEthernetIpRfidIO()
- {
- if (BgEipCommunicate == null || !BgEipCommunicate.IsConnected)
- return;
- try
- {
- ApplyEthernetIpRfidConfiguration();
- }
- catch (Exception ex)
- {
- SendTaskMessage("RFID 端口配置失败: " + ex.Message, MessageLevel.Alarm);
- LogHelper.WriteLogError("RFID 端口配置失败", ex);
- }
- BgEipCommunicate.StartRFIDReading(DeviceConfig.BgEthernetIPCommunicate.CycleTime);
- TryStartHandshakeAfterEipReady();
- }
- /// <summary>EIP 就绪后尝试启动 Ready 握手;MC 未连接则跳过,由 MC 重连循环补启。</summary>
- private void TryStartHandshakeAfterEipReady()
- {
- var mcPlc = GetMcPlcInfo();
- if (mcPlc == null)
- return;
- var client = GetMcPlcClient();
- if (client == null || !client.IsConnected)
- return;
- TryStartHandshakeLoop(mcPlc);
- }
- /// <summary>
- /// 初始化三菱 MC PLC:自动连接、心跳、Ready 握手、SFIS 信号监听
- /// </summary>
- public void InitMcCommunicate()
- {
- var mcPlc = GetMcPlcInfo();
- if (mcPlc == null)
- {
- SendTaskMessage("未配置三菱 MC PLC,跳过 MC 通讯初始化", MessageLevel.Debug);
- return;
- }
- try
- {
- StopMcCommunicateLoops();
- var mcWrapper = PlcService?.GetPlc(mcPlc.Id) as MitsubishiMcPLC;
- if (mcWrapper == null)
- {
- SendTaskMessage("MC PLC 未通过 PlcService 创建,请检查 PLC 配置", MessageLevel.Alarm);
- return;
- }
- var client = mcWrapper.Client;
- if (_mcPlcLogHandler == null)
- _mcPlcLogHandler = msg => SendTaskMessage($"PLC {msg}", MessageLevel.Info);
- client.OnLog -= _mcPlcLogHandler;
- client.OnLog += _mcPlcLogHandler;
- client.ConnectionLost -= McPlcConnectionLost;
- client.ConnectionLost += McPlcConnectionLost;
- if (!client.IsConnected)
- {
- mcWrapper.Connect();
- }
- if (!client.IsConnected)
- {
- SendTaskMessage("PLC 连接失败,将自动重连", MessageLevel.Alarm);
- StartMcReconnectLoop();
- return;
- }
- SendTaskMessage("PLC TCP 连接成功,正在测试 MC 读写...", MessageLevel.Info);
- string testDev = string.IsNullOrWhiteSpace(mcPlc.PlcDataStartDevice) ? "D110" : mcPlc.PlcDataStartDevice.Trim();
- if (testDev == "0")
- testDev = "D110";
- if (!client.TestCommunication(testDev))
- {
- SendTaskMessage("MC 通讯测试失败,请检查:二进制3E、端口、允许RUN中写入", MessageLevel.Alarm);
- }
- else
- {
- SendTaskMessage("连接成功,MC 字通讯正常", MessageLevel.Info);
- }
- string bitTestDev = ResolveBitTestDevice(mcPlc);
- if (bitTestDev != null)
- {
- if (!client.TestBitCommunication(bitTestDev))
- SendTaskMessage("MC 位通讯测试失败,请检查 OK/NG 位地址及 RUN 中写入", MessageLevel.Alarm);
- }
- else
- {
- SendTaskMessage("MC 位通讯测试跳过:请配置读OK或读NG位地址", MessageLevel.Debug);
- }
- client.ResetHeartbeatState();
- EnsureMcCommunicateLoopsRunning(mcPlc, client);
- StartMcReconnectLoop();
- }
- catch (Exception ex)
- {
- SendTaskMessage("PLC 连接失败: " + ex.Message, MessageLevel.Alarm);
- LogHelper.WriteLogError("PLC 连接失败", ex);
- StopMcCommunicateLoops();
- }
- }
- private void McPlcConnectionLost()
- {
- _mcMonitorLoopsStarted = false;
- SendTaskMessage("MC PLC 连接中断", MessageLevel.Alarm);
- }
- /// <summary>MC 连接可用时确保心跳 / SFIS / Ready 握手循环已启动。</summary>
- private void EnsureMcCommunicateLoopsRunning(PlcInfo mcPlc, MitsubishiPLC client)
- {
- if (mcPlc == null || client == null || !client.IsConnected)
- return;
- client.ResetHeartbeatState();
- StartHeartbeatLoop(mcPlc);
- StartSfisSignalLoop();
- TryStartHandshakeLoop(mcPlc);
- _mcMonitorLoopsStarted = true;
- }
- private void TryStartHandshakeLoop(PlcInfo mcPlc)
- {
- if (mcPlc == null || !mcPlc.PlcForwardEnabled || !CanStartHandshake(mcPlc))
- return;
- StartHandshakeLoop();
- }
- private PlcInfo GetMcPlcInfo()
- {
- return DeviceConfig?.Plcs?.FirstOrDefault(p => p.CommunicationType == CommunicationType.Mitsubishi_MC);
- }
- private MitsubishiPLC GetMcPlcClient()
- {
- var mcInfo = GetMcPlcInfo();
- if (mcInfo == null || PlcService == null)
- return null;
- return (PlcService.GetPlc(mcInfo.Id) as MitsubishiMcPLC)?.Client;
- }
- private bool CanStartHandshake(PlcInfo mcPlc)
- {
- if (BgEipCommunicate == null || !BgEipCommunicate.IsConnected || !BgEipCommunicate.IsIOModeActive)
- return false;
- var mapping = mcPlc.ToPlcMapping();
- return MitsubishiPLC.IsDeviceEnabled(mapping.ReadyBitDevice)
- && MitsubishiPLC.IsDeviceEnabled(mapping.PortDevice)
- && MitsubishiPLC.IsDeviceEnabled(mapping.DataStartDevice);
- }
- private string ResolveBitTestDevice(PlcInfo mcPlc)
- {
- if (mcPlc == null) return null;
- if (MitsubishiPLC.IsDeviceEnabled(mcPlc.PlcOkBitDevice))
- return mcPlc.PlcOkBitDevice.Trim();
- if (MitsubishiPLC.IsDeviceEnabled(mcPlc.PlcNgBitDevice))
- return mcPlc.PlcNgBitDevice.Trim();
- return null;
- }
- private void StopMcCommunicateLoops()
- {
- try
- {
- _mcMonitorLoopsStarted = false;
- StopMcReconnectLoop();
- StopHandshakeLoop();
- StopHeartbeatLoop();
- StopSfisSignalLoop();
- ResetSfisWorkflow();
- }
- catch { /* ignore */ }
- }
- private void StartMcReconnectLoop()
- {
- StopMcReconnectLoop();
- _mcReconnectCts = new CancellationTokenSource();
- var token = _mcReconnectCts.Token;
- _mcReconnectTask = Task.Run(() => McReconnectLoop(token), token);
- }
- private void StopMcReconnectLoop()
- {
- try
- {
- if (_mcReconnectCts != null)
- {
- _mcReconnectCts.Cancel();
- try
- {
- if (_mcReconnectTask != null)
- _mcReconnectTask.Wait(2000);
- }
- catch (AggregateException) { /* ignore */ }
- _mcReconnectCts.Dispose();
- }
- }
- catch { /* ignore */ }
- finally
- {
- _mcReconnectCts = null;
- _mcReconnectTask = null;
- }
- }
- private void McReconnectLoop(CancellationToken token)
- {
- int attempt = 0;
- while (!token.IsCancellationRequested)
- {
- try
- {
- var mcPlc = GetMcPlcInfo();
- if (mcPlc == null)
- {
- Thread.Sleep(1000);
- continue;
- }
- var mcWrapper = PlcService?.GetPlc(mcPlc.Id) as MitsubishiMcPLC;
- var client = mcWrapper?.Client;
- if (client == null)
- {
- Thread.Sleep(1000);
- continue;
- }
- if (client.IsConnected)
- {
- if (!_mcMonitorLoopsStarted)
- EnsureMcCommunicateLoopsRunning(mcPlc, client);
- attempt = 0;
- Thread.Sleep(500);
- continue;
- }
- if ((DateTime.UtcNow - _mcLastReconnectAttempt).TotalMilliseconds < McReconnectIntervalMs)
- {
- Thread.Sleep(500);
- continue;
- }
- _mcLastReconnectAttempt = DateTime.UtcNow;
- attempt++;
- SendTaskMessage($"MC PLC 连接断开,正在重连(第 {attempt} 次)...", MessageLevel.Info);
- bool connected;
- lock (_mcReconnectSync)
- {
- if (client.IsConnected)
- {
- connected = true;
- }
- else
- {
- mcWrapper.Connect();
- connected = client.IsConnected;
- }
- }
- if (connected)
- {
- EnsureMcCommunicateLoopsRunning(mcPlc, client);
- SendTaskMessage("MC PLC 重连成功", MessageLevel.Info);
- attempt = 0;
- }
- else
- {
- SendTaskMessage("MC PLC 重连失败,将继续重试", MessageLevel.Alarm);
- }
- }
- catch (Exception ex)
- {
- if (token.IsCancellationRequested)
- break;
- LogHelper.WriteLogError("MC 重连循环异常", ex);
- Thread.Sleep(McReconnectIntervalMs);
- }
- }
- }
- private void StartHeartbeatLoop(PlcInfo mcPlc)
- {
- StopHeartbeatLoop();
- if (mcPlc == null) return;
- string device = mcPlc.PlcHeartbeatDevice;
- if (!MitsubishiPLC.IsDeviceEnabled(device))
- return;
- PlcHeartbeatKind kind;
- try
- {
- kind = MitsubishiPLC.ResolveHeartbeatKind(device);
- }
- catch (Exception ex)
- {
- SendTaskMessage("PLC 心跳地址无效", MessageLevel.Alarm);
- LogHelper.WriteLogError("PLC 心跳地址无效", ex);
- return;
- }
- if (kind == PlcHeartbeatKind.Disabled)
- return;
- int intervalMs = Math.Max(200, mcPlc.PlcHeartbeatIntervalMs);
- _heartbeatCts = new CancellationTokenSource();
- var token = _heartbeatCts.Token;
- _heartbeatTask = Task.Run(() => HeartbeatLoop(token, device.Trim(), intervalMs), token);
- SendTaskMessage("PLC 已启动心跳 " + device.Trim()
- + (kind == PlcHeartbeatKind.Bit ? "(位翻转)" : "(字递增)")
- + " 间隔=" + intervalMs + "ms", MessageLevel.Info);
- }
- private void StopHeartbeatLoop()
- {
- try
- {
- if (_heartbeatCts != null)
- {
- _heartbeatCts.Cancel();
- try
- {
- if (_heartbeatTask != null)
- _heartbeatTask.Wait(2000);
- }
- catch (AggregateException) { /* ignore */ }
- _heartbeatCts.Dispose();
- }
- }
- catch { /* ignore */ }
- finally
- {
- _heartbeatCts = null;
- _heartbeatTask = null;
- }
- }
- private void HeartbeatLoop(CancellationToken token, string device, int intervalMs)
- {
- while (!token.IsCancellationRequested)
- {
- try
- {
- MitsubishiPLC plc;
- lock (_sync)
- plc = GetMcPlcClient();
- if (plc == null || !plc.IsConnected)
- {
- Thread.Sleep(100);
- continue;
- }
- plc.PulseHeartbeat(device);
- }
- catch (Exception ex)
- {
- if (!token.IsCancellationRequested)
- {
- SendTaskMessage("心跳异常: " + ex.Message, MessageLevel.Alarm);
- LogHelper.WriteLogError("心跳异常", ex);
- }
- }
- Thread.Sleep(intervalMs);
- }
- }
- private void StartHandshakeLoop()
- {
- StopHandshakeLoop();
- _handshakeCts = new CancellationTokenSource();
- var token = _handshakeCts.Token;
- _handshakeTask = Task.Run(() => HandshakeLoop(token), token);
- SendTaskMessage("已启动 Ready 握手循环", MessageLevel.Info);
- }
- private void HandshakeLoop(CancellationToken token)
- {
- bool lastReady = false;
- while (!token.IsCancellationRequested)
- {
- try
- {
- MitsubishiPLC plc;
- SIG350RFIDClient rfid;
- lock (_sync)
- {
- plc = GetMcPlcClient();
- rfid = BgEipCommunicate;
- }
- if (plc == null || !plc.IsConnected || rfid == null || !rfid.IsConnected || !rfid.IsIOModeActive)
- {
- Thread.Sleep(50);
- continue;
- }
- PlcRfidMapping mapping = SnapshotMapping();
- if (!MitsubishiPLC.IsDeviceEnabled(mapping.ReadyBitDevice))
- {
- Thread.Sleep(100);
- continue;
- }
- bool ready = plc.ReadReadyBit(mapping);
- if (ready && !lastReady)
- {
- SendTaskMessage("PLC 检测到 Ready=ON,开始读卡", MessageLevel.Info);
- ProcessReadyRequest(plc, rfid, mapping, token);
- while (!token.IsCancellationRequested)
- {
- if (!plc.IsConnected)
- break;
- if (!plc.ReadReadyBit(mapping))
- break;
- Thread.Sleep(20);
- }
- if (!token.IsCancellationRequested && plc.IsConnected)
- {
- plc.ClearReceiveBit(mapping);
- SendTaskMessage("PLC Ready=OFF,已清除 Receive", MessageLevel.Info);
- }
- lastReady = false;
- continue;
- }
- lastReady = ready;
- Thread.Sleep(20);
- }
- catch (Exception ex)
- {
- if (token.IsCancellationRequested)
- break;
- SendTaskMessage("PLC 握手异常", MessageLevel.Alarm);
- LogHelper.WriteLogError("PLC 握手异常", ex);
- Thread.Sleep(100);
- lastReady = false;
- }
- }
- }
- private PlcRfidMapping SnapshotMapping()
- {
- lock (_sync)
- {
- var mcPlc = GetMcPlcInfo();
- return mcPlc?.ToPlcMapping() ?? new PlcRfidMapping();
- }
- }
- private void ProcessReadyRequest(MitsubishiPLC plc, SIG350RFIDClient rfid, PlcRfidMapping mapping, CancellationToken token)
- {
- int port;
- try
- {
- port = plc.ReadRequestPort(mapping);
- }
- catch (Exception ex)
- {
- SendTaskMessage("PLC 读端口号失败", MessageLevel.Alarm);
- LogHelper.WriteLogError("PLC 读端口号失败", ex);
- try { plc.WriteReadFailure(mapping); } catch { /* ignore */ }
- return;
- }
- SendTaskMessage("PLC 请求端口 " + port, MessageLevel.Info);
- if (port < 1 || port > 8)
- {
- SendTaskMessage("端口号无效: " + port, MessageLevel.Alarm);
- try { plc.WriteReadFailure(mapping); } catch { /* ignore */ }
- return;
- }
- if (token.IsCancellationRequested)
- return;
- RFIDTagData tag = null;
- try
- {
- int timeout = mapping.ReadTimeoutMs > 0 ? mapping.ReadTimeoutMs : 2000;
- var readOpts = DeviceConfig.BgEthernetIPCommunicate.ToRfh5xxReadOptions();
- tag = rfid.ReadRFIDTag(port, timeout, readOpts);
- }
- catch (Exception ex)
- {
- SendTaskMessage("RFID 读卡异常", MessageLevel.Alarm);
- LogHelper.WriteLogError("RFID 读卡异常", ex);
- }
- if (tag != null && tag.Data != null && tag.Data.Length > 0)
- {
- lock (_sync)
- _lastRfidTag = CloneTag(tag);
- try
- {
- plc.WriteReadSuccess(mapping, tag);
- }
- catch (Exception ex)
- {
- SendTaskMessage("RFID 写 OK/数据失败", MessageLevel.Alarm);
- LogHelper.WriteLogError("RFID 写 OK/数据失败", ex);
- }
- }
- else
- {
- SendTaskMessage("RFID 端口 " + port + " 未读到标签", MessageLevel.Alarm);
- try { plc.WriteReadFailure(mapping); }
- catch (Exception ex)
- {
- SendTaskMessage("RFID 写 NG 失败", MessageLevel.Alarm);
- LogHelper.WriteLogError("RFID 写 NG 失败", ex);
- }
- }
- }
- private bool SnapshotSfisEnabled()
- {
- lock (_sync)
- return DeviceConfig.BgSfisCommunicate?.IsEnabled == true;
- }
- private SfisConfig SnapshotSfisConfig()
- {
- lock (_sync)
- return DeviceConfig.BgSfisCommunicate?.ToSfisConfig() ?? new SfisConfig();
- }
- private PlcSfisFeedback SnapshotSfisPlcFeedback()
- {
- lock (_sync)
- return DeviceConfig.BgSfisCommunicate?.ToPlcSfisFeedback() ?? new PlcSfisFeedback();
- }
- private SfisWorkflowService CreateSfisWorkflow()
- {
- var workflow = new SfisWorkflowService(SnapshotSfisConfig());
- workflow.OnLog += msg => SendTaskMessage("SFIS " + msg, MessageLevel.Info);
- return workflow;
- }
- private SfisWorkflowService GetOrCreateSfisWorkflow()
- {
- lock (_sync)
- {
- if (_sfisWorkflow != null)
- return _sfisWorkflow;
- }
- var workflow = CreateSfisWorkflow();
- lock (_sync)
- {
- if (_sfisWorkflow == null)
- _sfisWorkflow = workflow;
- else
- {
- try { workflow.Dispose(); }
- catch { /* ignore */ }
- }
- return _sfisWorkflow;
- }
- }
- private void ResetSfisWorkflow()
- {
- lock (_sync)
- {
- if (_sfisWorkflow != null)
- {
- try { _sfisWorkflow.Dispose(); }
- catch { /* ignore */ }
- _sfisWorkflow = null;
- }
- }
- }
- private void StartSfisSignalLoop()
- {
- StopSfisSignalLoop();
- var sfis = DeviceConfig.BgSfisCommunicate;
- if (sfis == null || !sfis.IsEnabled)
- return;
- bool passReady = sfis.PassEnabled && MitsubishiPLC.IsDeviceEnabled(sfis.PlcSfisPassSignalDevice);
- bool uploadReady = sfis.UploadEnabled && MitsubishiPLC.IsDeviceEnabled(sfis.PlcSfisUploadSignalDevice);
- if (!passReady && !uploadReady)
- return;
- _sfisSignalCts = new CancellationTokenSource();
- var token = _sfisSignalCts.Token;
- _sfisSignalTask = Task.Run(() => SfisSignalLoop(token), token);
- SendTaskMessage("SFIS 已启动信号监听"
- + (passReady ? " 过站=" + sfis.PlcSfisPassSignalDevice.Trim() : string.Empty)
- + (uploadReady ? " 上传=" + sfis.PlcSfisUploadSignalDevice.Trim() : string.Empty), MessageLevel.Info);
- }
- private void StopSfisSignalLoop()
- {
- try
- {
- if (_sfisSignalCts != null)
- {
- _sfisSignalCts.Cancel();
- try
- {
- if (_sfisSignalTask != null)
- _sfisSignalTask.Wait(2000);
- }
- catch (AggregateException) { /* ignore */ }
- _sfisSignalCts.Dispose();
- }
- }
- catch { /* ignore */ }
- finally
- {
- _sfisSignalCts = null;
- _sfisSignalTask = null;
- }
- }
- private void SfisSignalLoop(CancellationToken token)
- {
- bool lastPass = false;
- bool lastUpload = false;
- while (!token.IsCancellationRequested)
- {
- try
- {
- if (!SnapshotSfisEnabled())
- {
- lastPass = false;
- lastUpload = false;
- Thread.Sleep(200);
- continue;
- }
- MitsubishiPLC plc;
- lock (_sync)
- plc = GetMcPlcClient();
- if (plc == null || !plc.IsConnected)
- {
- Thread.Sleep(100);
- continue;
- }
- var sfis = DeviceConfig.BgSfisCommunicate;
- bool passEnabled = sfis.PassEnabled;
- bool uploadEnabled = sfis.UploadEnabled;
- string passDev = sfis.PlcSfisPassSignalDevice;
- string uploadDev = sfis.PlcSfisUploadSignalDevice;
- bool passOn = passEnabled && MitsubishiPLC.IsDeviceEnabled(passDev) && plc.ReadBit(passDev);
- bool uploadOn = uploadEnabled && MitsubishiPLC.IsDeviceEnabled(uploadDev) && plc.ReadBit(uploadDev);
- if (passEnabled && passOn && !lastPass)
- {
- SendTaskMessage("SFIS 过站信号上升沿 " + passDev.Trim(), MessageLevel.Info);
- RunSfisOnSignal(plc, runPass: true, runUpload: false);
- }
- else if (passEnabled && !passOn && lastPass)
- {
- try
- {
- plc.ClearSfisReceiveBit(SnapshotSfisPlcFeedback(), isPassStation: true);
- SendTaskMessage("过站信号 OFF,已清除 Receive", MessageLevel.Info);
- }
- catch (Exception ex)
- {
- SendTaskMessage("清除过站 Receive 失败: " + ex.Message, MessageLevel.Alarm);
- }
- }
- if (uploadEnabled && uploadOn && !lastUpload)
- {
- SendTaskMessage("SFIS 上传信号上升沿 " + uploadDev.Trim(), MessageLevel.Info);
- RunSfisOnSignal(plc, runPass: false, runUpload: true);
- }
- else if (uploadEnabled && !uploadOn && lastUpload)
- {
- try
- {
- plc.ClearSfisReceiveBit(SnapshotSfisPlcFeedback(), isPassStation: false);
- SendTaskMessage("上传信号 OFF,已清除 Receive", MessageLevel.Info);
- }
- catch (Exception ex)
- {
- SendTaskMessage("清除上传 Receive 失败: " + ex.Message, MessageLevel.Alarm);
- }
- }
- lastPass = passOn;
- lastUpload = uploadOn;
- Thread.Sleep(50);
- }
- catch (Exception ex)
- {
- if (token.IsCancellationRequested)
- break;
- SendTaskMessage("SFIS 信号监听异常: " + ex.Message, MessageLevel.Alarm);
- Thread.Sleep(200);
- lastPass = false;
- lastUpload = false;
- }
- }
- }
- private struct SfisRunPlan
- {
- public bool RunPass;
- public bool RunUpload;
- }
- private void RunSfisOnSignal(MitsubishiPLC plc, bool runPass, bool runUpload)
- {
- bool isPassStation = runPass;
- PlcSfisFeedback feedback = SnapshotSfisPlcFeedback();
- bool success = false;
- try
- {
- RFIDTagData tag = TryLoadTagForSfis(plc);
- if (tag == null)
- {
- SendTaskMessage("SFIS 无可用 RFID 数据,写 PLC NG", MessageLevel.Alarm);
- WriteSfisPlcResult(plc, feedback, isPassStation, false);
- return;
- }
- success = TryRunSfisWorkflow(tag, new SfisRunPlan { RunPass = runPass, RunUpload = runUpload });
- }
- catch (Exception ex)
- {
- SendTaskMessage("SFIS 流程异常: " + ex.Message, MessageLevel.Alarm);
- success = false;
- }
- WriteSfisPlcResult(plc, feedback, isPassStation, success);
- }
- private void WriteSfisPlcResult(MitsubishiPLC plc, PlcSfisFeedback feedback, bool isPassStation, bool success)
- {
- try
- {
- plc.WriteSfisResult(feedback, isPassStation, success);
- }
- catch (Exception ex)
- {
- SendTaskMessage((isPassStation ? "过站" : "上传") + " 回写失败: " + ex.Message, MessageLevel.Alarm);
- }
- }
- private RFIDTagData TryLoadTagForSfis(MitsubishiPLC plc)
- {
- PlcRfidMapping mapping = SnapshotMapping();
- var readOpts = DeviceConfig.BgEthernetIPCommunicate.ToRfh5xxReadOptions();
- if (MitsubishiPLC.IsDeviceEnabled(mapping.DataStartDevice))
- {
- try
- {
- byte[] data = plc.ReadDeviceBytes(mapping.DataStartDevice, mapping.MaxDataBytes);
- data = TrimTrailingZeros(data);
- if (data.Length > 0)
- {
- int port = 0;
- if (MitsubishiPLC.IsDeviceEnabled(mapping.PortDevice))
- port = plc.ReadRequestPort(mapping);
- return new RFIDTagData
- {
- Port = port,
- Data = data,
- Timestamp = DateTime.Now,
- PayloadKind = readOpts.Kind
- };
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage("SFIS 从 PLC 读取 RFID 数据失败: " + ex.Message, MessageLevel.Alarm);
- }
- }
- lock (_sync)
- {
- if (_lastRfidTag != null && _lastRfidTag.Data != null && _lastRfidTag.Data.Length > 0)
- return CloneTag(_lastRfidTag);
- }
- return null;
- }
- private static RFIDTagData CloneTag(RFIDTagData tag)
- {
- return new RFIDTagData
- {
- Port = tag.Port,
- Data = (byte[])tag.Data.Clone(),
- Timestamp = tag.Timestamp,
- Quality = tag.Quality,
- PayloadKind = tag.PayloadKind
- };
- }
- private static byte[] TrimTrailingZeros(byte[] data)
- {
- if (data == null || data.Length == 0)
- return new byte[0];
- int len = data.Length;
- while (len > 0 && data[len - 1] == 0)
- len--;
- if (len == data.Length)
- return data;
- var trimmed = new byte[len];
- Array.Copy(data, trimmed, len);
- return trimmed;
- }
- private bool TryRunSfisWorkflow(RFIDTagData tag, SfisRunPlan plan)
- {
- try
- {
- var config = SnapshotSfisConfig();
- var context = SfisRfidMapper.FromRfidTag(tag, config);
- var result = GetOrCreateSfisWorkflow().ProcessUnit(context, plan.RunPass, plan.RunUpload);
- PrintSfisResult(result);
- return result.Success;
- }
- catch (ArgumentException ex)
- {
- SendTaskMessage("SFIS 数据无效: " + ex.Message, MessageLevel.Alarm);
- return false;
- }
- catch (Exception ex)
- {
- SendTaskMessage("SFIS 流程异常: " + ex.Message, MessageLevel.Alarm);
- return false;
- }
- }
- private void PrintSfisResult(SfisWorkflowResult result)
- {
- if (result == null)
- return;
- SendTaskMessage(result.Success
- ? "SFIS 流程成功 ISN=" + result.Isn
- : "SFIS 流程失败 ISN=" + result.Isn + " => " + result.ErrorMessage, MessageLevel.Info);
- if (result.Steps == null)
- return;
- foreach (var step in result.Steps)
- {
- string msg = step.Response != null ? step.Response.Message : string.Empty;
- int code = step.Response != null ? step.Response.ReturnCode : -1;
- SendTaskMessage("SFIS " + step.StepName + ": P_RET=" + code + " " + msg, MessageLevel.Debug);
- }
- }
- private void BgEipCommunicate_OnLog(string obj)
- {
- SendTaskMessage(obj, MessageLevel.Info);
- }
- /// <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($"开启脚本时出错:{item}", ex);
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("读取本地脚本文件列表时出错", ex);
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("开启后台脚本时出错!", ex);
- }
- }
- #endregion
- #region 产品操作
- /// <summary>
- /// 加载所有产品
- /// </summary>
- public void LoadAllProducts()
- {
- Products = new ObservableCollection<ProductModel>();
- try
- {
- if (File.Exists(FilePath.ProductsPath + "//ProductList.cfg"))
- {
- Dictionary<Guid, string> list = FileHelper.ReadJsonFile<Dictionary<Guid, string>>(FilePath.ProductsPath + "//ProductList.cfg");
- foreach (var item in list)
- {
- Products.Add(FileHelper.ReadJsonFile<ProductModel>(FilePath.ProductsPath + "//" + item.Value + "//" + item.Value + ".cfg"));
- //for (int i = 0; i < Products[Products.Count - 1].CameraProcedures.Count; i++)
- //{
- // for (int j = 0; j < Products[Products.Count - 1].CameraProcedures[i].ProcedureModels.Count; j++)
- // {
- // string prcPath = FilePath.ProductsPath + "//" + item.Value + "//" + Products[Products.Count - 1].CameraProcedures[i].Camera + "//" + Products[Products.Count - 1].CameraProcedures[i].ProcedureModels[j].Name + ".prc";
- // Products[Products.Count - 1].CameraProcedures[i].ProcedureModels[j].Procedure = VmProcedure.Load(prcPath);
- // }
- //}
- }
- SendTaskMessage($"{Lang.所有产品加载完成}!", MessageLevel.Debug);
- }
- else
- {
- SendTaskMessage($"{Lang.无产品}!", MessageLevel.Alarm);
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- LogHelper.WriteLogError("加载所有产品时出错!", ex);
- }
- }
- /// <summary>
- /// 加载产品
- /// </summary>
- public void LoadProducts(ProductModel product)
- {
- var prd = Products.FirstOrDefault(x => x.ID == product.ID);
- if (prd == null)
- {
- return;
- }
- try
- {
- //清除上一个产品的相机拍照数据
- feederCurentBlobArea = new Dictionary<Guid, Dictionary<Guid, double>>();
- LastPointsForFeeder = new Dictionary<Guid, List<Vector<double>>>();
- PointCollection = new Dictionary<Guid, Dictionary<string, Queue<string>>>();
- for (int i = 0; i < prd.CameraProcedures.Count; i++)
- {
- for (int j = 0; j < prd.CameraProcedures[i].ProcedureModels.Count; j++)
- {
- string prcPath = FilePath.ProductsPath + "//" + prd.Name + "//" + prd.CameraProcedures[i].Camera + "//" + prd.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
- prd.CameraProcedures[i].ProcedureModels[j].ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
- }
- }
- //设置Feeder的光源亮度及Feeder的振动参数
- prd.IsLoad = true;
- foreach (var item in Products)
- {
- if (item.ID != prd.ID)
- {
- item.IsLoad = false;
- }
- }
- CurrentProduct = prd;
- Dictionary<Guid, List<NodeId>> keyValuePairs = new Dictionary<Guid, List<NodeId>>();
- Dictionary<Guid, ObservableCollection<ProcedureOutputOpcAdr>> keyValuePairsT = new Dictionary<Guid, ObservableCollection<ProcedureOutputOpcAdr>>();
- foreach (var item in prd.CameraProcedures)
- {
- foreach (var itemT in item.ProcedureModels)
- {
- IRobot robot = RobotService.GetRobot(itemT.RobotId);
- if (robot != null && robot.Brand == RobotBrand.XYZ_Platform)
- {
- if (keyValuePairs.ContainsKey(itemT.Id))
- {
- keyValuePairs[itemT.Id].Add(itemT.TriggerCommand);
- }
- else
- {
- keyValuePairs.Add(itemT.Id, new List<NodeId> { itemT.TriggerCommand });
- }
- if (!keyValuePairsT.ContainsKey(itemT.Id))
- {
- keyValuePairsT.Add(itemT.Id, itemT.ProcedureOutputsOpcAdrs);
- }
- }
- }
- }
- Guid[] Threadkeys = PlcTrigger.Keys.ToArray();
- Thread[] ThreadValues = PlcTrigger.Values.ToArray();
- for (int i = 0; i < PlcTrigger.Count; i++)
- {
- var procedure = prd.CameraProcedures.FirstOrDefault(p => p.ProcedureModels?.FirstOrDefault(f => f.Id == Threadkeys[i]) != null);
- Guid guid = procedure.ProcedureModels.FirstOrDefault(f => f.Id == Threadkeys[i]).RobotId;
- XYZ_Platform robot = RobotService.GetRobot(guid) as XYZ_Platform;
- robot.IsTrigger = false;
- ThreadValues[i].Abort();
- }
- PlcTrigger.Clear();
- Guid[] keys = keyValuePairs.Keys.ToArray();
- List<NodeId>[] values = keyValuePairs.Values.ToArray();
- for (int i = 0; i < keyValuePairs?.Count; i++)
- {
- var procedure = prd.CameraProcedures.FirstOrDefault(p =>
- p.ProcedureModels?.FirstOrDefault(f => f.Id == keys[i]) != null);
- Guid guid = procedure.ProcedureModels.FirstOrDefault(f => f.Id == keys[i]).RobotId;
- XYZ_Platform robot = RobotService.GetRobot(guid) as XYZ_Platform;
- robot.IsTrigger = false;
- if (keyValuePairsT.ContainsKey(keys[i]))
- {
- List<ProcedureOutputOpcAdr> ProcedureOutputOpcAdrs = new List<ProcedureOutputOpcAdr>();
- var saas = keyValuePairsT[keys[i]];
- for (int j = 0; j < keyValuePairsT[keys[i]]?.Count; j++)
- {
- ProcedureOutputOpcAdrs.Add(keyValuePairsT[keys[i]][j]);
- }
- robot.IsTrigger = true;
- Thread thread = robot.CreateThreadToTrigger(values[i].ToArray(), ProcedureOutputOpcAdrs);
- PlcTrigger.Add(keys[i], thread);
- }
- }
- DatabaseHelper.UpdateProductDatabase(product);
- SendTaskMessage(Lang.产品加载完成.Replace("{0}", CurrentProduct.Name), MessageLevel.Debug);
- App.Current.Dispatcher.Invoke(() =>
- {
- _eventAggregator.GetEvent<ProductChangedNotification>().Publish(CurrentProduct);
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.产品加载完成.Replace("{0}", CurrentProduct.Name), Duration = 1 });
- });
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- LogHelper.WriteLogError($"加载产品[{prd.Name}]时出错!", ex);
- }
- }
- /// <summary>
- /// 保存产品
- /// </summary>
- /// <param name="product"></param>
- public void SaveProducts(ProductModel product)
- {
- try
- {
- product.DateTime = DateTime.Now;
- var prod = Products.FirstOrDefault(item => item.ID == product.ID);
- if (prod != null)
- {
- prod = product;
- }
- else
- {
- product.IsCreate = false;
- Products.Add(product);
- }
- Dictionary<Guid, string> list = new Dictionary<Guid, string>();
- foreach (var item in Products)
- {
- list.Add(item.ID, item.Name);
- }
- FileHelper.WriteJsonFile(list, FilePath.ProductsPath + "//ProductList.cfg");
- FileHelper.WriteJsonFile(product, FilePath.ProductsPath + "//" + product.Name + "//" + product.Name + ".cfg");
- foreach (var item in product.CameraProcedures)
- {
- foreach (var item1 in item.ProcedureModels)
- {
- string prcPath = FilePath.ProductsPath + "//" + product.Name + "//" + item.Camera + "//" + item1.Name + ".vpp";
- if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
- {
- Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
- }
- if (item1.ToolBlock != null)
- {
- CogSerializer.SaveObjectToFile(item1.ToolBlock, prcPath);
- //item1.ToolBlock= CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
- }
- else
- {
- if (File.Exists(prcPath))
- {
- item1.ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
- }
- else
- {
- item1.ToolBlock = CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
- }
- }
- }
- }
- DatabaseHelper.UpdateProductDatabase(product);
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
- LogHelper.WriteLogError("保存产品时出错!", ex);
- }
- }
- /// <summary>
- /// 保存产品
- /// </summary>
- public void SaveProducts()
- {
- Dictionary<Guid, string> list = new Dictionary<Guid, string>();
- foreach (var item in Products)
- {
- list.Add(item.ID, item.Name);
- }
- FileHelper.WriteJsonFile(list, FilePath.ProductsPath + "//ProductList.cfg");
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
- }
- /// <summary>
- /// 保存产品模板
- /// </summary>
- /// <param name="product"></param>
- public void SaveProductTemplate(ProductModel product)
- {
- try
- {
- product.DateTime = DateTime.Now;
- var prod = Products.FirstOrDefault(item => item.ID == product.ID);
- if (prod != null)
- {
- prod = product;
- }
- else
- {
- product.IsCreate = false;
- }
- FileHelper.WriteJsonFile(product, FilePath.ProductTemplatePath + "//" + product.Name + "//" + product.Name + ".cfg");
- foreach (var item in product.CameraProcedures)
- {
- foreach (var item1 in item.ProcedureModels)
- {
- string prcPath = FilePath.ProductTemplatePath + "//" + product.Name + "//" + item.Camera + "//" + item1.Name + ".vpp";
- if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
- {
- Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
- }
- if (item1.ToolBlock != null)
- {
- CogSerializer.SaveObjectToFile(item1.ToolBlock, prcPath);
- //item1.ToolBlock= CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
- }
- else
- {
- if (File.Exists(prcPath))
- {
- item1.ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
- }
- else
- {
- item1.ToolBlock = CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
- }
- }
- }
- }
- DatabaseHelper.UpdateProductDatabase(product);
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
- LogHelper.WriteLogError("保存产品模板时出错!", ex);
- }
- }
- /// <summary>
- /// 复制产品
- /// </summary>
- /// <param name="product"></param>
- /// <param name="newName"></param>
- public ProductModel CopyProduct(ProductModel product, string newName)
- {
- var p = product.Clone();
- p.Name = newName;
- p.ID = Guid.NewGuid();
- p.DateTime = DateTime.Now;
- for (int i = 0; i < p.CameraProcedures.Count; i++)
- {
- for (int j = 0; j < p.CameraProcedures[i].ProcedureModels.Count; j++)
- {
- string sorPath = FilePath.ProductsPath + "//" + ((ProductModel)product).Name + "//" + p.CameraProcedures[i].Camera + "//" + ((ProductModel)product).CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
- string procname = p.CameraProcedures[i].ProcedureModels[j].Name.Split('-')[2];
- procname = $"{p.Name}-{p.CameraProcedures[i].Camera}-{procname}";
- p.CameraProcedures[i].ProcedureModels[j].Name = procname;
- string prcPath = FilePath.ProductsPath + "//" + p.Name + "//" + p.CameraProcedures[i].Camera + "//" + p.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
- if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
- {
- Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
- }
- if (File.Exists(sorPath))
- {
- File.Copy(sorPath, prcPath, true);
- if (p.CameraProcedures[i].ProcedureModels[j].ToolBlock == null)
- {
- p.CameraProcedures[i].ProcedureModels[j].ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
- }
- }
- }
- }
- Products.Add(p);
- SaveProducts(p);
- return p;
- }
- /// <summary>
- /// 重新命名产品
- /// </summary>
- /// <param name="product"></param>
- /// <param name="newName"></param>
- public void RenameProduct(ProductModel product, string newName)
- {
- string oldname = product.Name;
- //更改产品名称
- product.Name = newName;
- //遍历所有的相机流程,更改相机流程的名称
- for (int i = 0; i < product.CameraProcedures.Count; i++)
- {
- for (int j = 0; j < product.CameraProcedures[i].ProcedureModels.Count; j++)
- {
- //旧路径
- string sorPath = FilePath.ProductsPath + "//" + oldname + "//" + product.CameraProcedures[0].Camera + "//" + product.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
- string procname = product.CameraProcedures[i].ProcedureModels[j].Name.Split('-')[2];
- procname = $"{product.Name}-{product.CameraProcedures[i].Camera}-{procname}";
- product.CameraProcedures[i].ProcedureModels[j].Name = procname;
- //新路径
- string prcPath = FilePath.ProductsPath + "//" + product.Name + "//" + product.CameraProcedures[0].Camera + "//" + product.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
- if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
- {
- Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
- }
- if (File.Exists(sorPath))
- {
- File.Copy(sorPath, prcPath, true);
- File.Delete(sorPath);
- }
- }
- string prcPath1 = FilePath.ProductsPath + "//" + oldname + "//" + product.CameraProcedures[0].Camera;
- if (Directory.Exists(prcPath1))
- {
- Directory.Delete(prcPath1);
- }
- }
- //更改产品数据库
- string src = FilePath.ProductsPath + "//" + oldname + "//" + oldname + ".db";
- string dsc = FilePath.ProductsPath + "//" + product.Name + "//" + product.Name + ".db";
- if (File.Exists(src))
- {
- File.Copy(src, dsc, true);
- File.Delete(src);
- }
- //更改数据库中有关的产品名称
- DatabaseHelper.RevampProductName(product, oldname);
- SaveProducts(product);
- //删除旧产品路径
- string sorPath1 = FilePath.ProductsPath + "//" + oldname + "//" + oldname + ".cfg";
- if (File.Exists(sorPath1))
- {
- File.Delete(sorPath1);
- }
- sorPath1 = FilePath.ProductsPath + "//" + oldname;
- if (Directory.Exists(sorPath1))
- {
- Directory.Delete(sorPath1);
- }
- }
- /// <summary>
- /// 移除产品
- /// </summary>
- /// <param name="product"></param>
- public void RemoveProduct(ProductModel product)
- {
- var prod = Products.FirstOrDefault(p => p.ID == product.ID);
- if (prod != null)
- {
- Products.Remove(prod);
- SaveProducts();
- }
- }
- #endregion
- #region 相机校准操作
- /// <summary>
- /// 加载所有校准
- /// </summary>
- public void LoadAllCalibration()
- {
- try
- {
- if (File.Exists(FilePath.CalibrationPath + "//CalibrationList.cfg"))
- {
- DeviceConfig.Calibrations = new ObservableCollection<CalibrationInfo>();
- Dictionary<Guid, string> list = FileHelper.ReadJsonFile<Dictionary<Guid, string>>(FilePath.CalibrationPath + "//CalibrationList.cfg");
- foreach (var item in list)
- {
- DeviceConfig.Calibrations.Add(FileHelper.ReadJsonFile<CalibrationInfo>(FilePath.CalibrationPath + "//" + item.Value + "//" + item.Value + ".cfg"));
- }
- SendTaskMessage(Lang.校准加载完成, MessageLevel.Debug);
- }
- else
- {
- SendTaskMessage(Lang.无校准, MessageLevel.Alarm);
- }
- }
- catch (Exception ex)
- {
- DeviceConfig.Calibrations = new ObservableCollection<CalibrationInfo>();
- LogHelper.WriteLogError("加载校准配置文件时出错!", ex);
- }
- }
- /// <summary>
- /// 保存校准
- /// </summary>
- /// <param name="calibration"></param>
- public void SaveCalibration(CalibrationInfo calibration)
- {
- try
- {
- calibration.DateTime = DateTime.Now;
- var calib = DeviceConfig.Calibrations.FirstOrDefault(item => item.Id == calibration.Id);
- if (calib != null)
- {
- calib = calibration;
- }
- else
- {
- calibration.IsCreate = false;
- DeviceConfig.Calibrations.Add(calibration);
- }
- Dictionary<Guid, string> list = new Dictionary<Guid, string>();
- foreach (var item in DeviceConfig.Calibrations)
- {
- list.Add(item.Id, item.Name);
- }
- FileHelper.WriteJsonFile(list, FilePath.CalibrationPath + "//CalibrationList.cfg");
- FileHelper.WriteJsonFile(calibration, FilePath.CalibrationPath + "//" + calibration.Name + "//" + calibration.Name + ".cfg");
- if (calibration.ToolBlock != null)
- {
- string prcPath = FilePath.CalibrationPath + "//" + calibration.Name + "//" + calibration.Name + ".vpp";
- if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
- {
- Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
- }
- CogSerializer.SaveObjectToFile(calibration.ToolBlock, prcPath);
- }
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
- LogHelper.WriteLogError("保存校准时出错!", ex);
- }
- }
- /// <summary>
- /// 移除校准
- /// </summary>
- /// <param name=""></param>
- public void RemoveCalibration(CalibrationInfo calibration)
- {
- var calib = DeviceConfig.Calibrations.FirstOrDefault(p => p.Id == calibration.Id);
- if (calib != null)
- {
- DeviceConfig.Calibrations.Remove(calib);
- Dictionary<Guid, string> list = new Dictionary<Guid, string>();
- foreach (var item in DeviceConfig.Calibrations)
- {
- list.Add(item.Id, item.Name);
- }
- FileHelper.WriteJsonFile(list, FilePath.CalibrationPath + "//CalibrationList.cfg");
- _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
- }
- }
- #endregion
- #region Feeder清料动作
- /// <summary>
- /// 加载Feeder清料动作
- /// </summary>
- public Dictionary<Guid, ObservableCollection<FeederClearWork>> LoadFeedersClearTask()
- {
- Dictionary<Guid, ObservableCollection<FeederClearWork>> FeedersClearWork = new Dictionary<Guid, ObservableCollection<FeederClearWork>>();
- try
- {
- if (File.Exists(FilePath.FeedersClearTaskPath))
- {
- FeedersClearWork = FileHelper.ReadJsonFile<Dictionary<Guid, ObservableCollection<FeederClearWork>>>(FilePath.FeedersClearTaskPath);
- }
- return FeedersClearWork;
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("加载Feeder清料动作配置文件时出错!", ex);
- return FeedersClearWork;
- }
- }
- /// <summary>
- /// 保存Feeder清料动作
- /// </summary>
- public void SaveFeedersClearTask(Dictionary<Guid, ObservableCollection<FeederClearWork>> FeedersClearWork)
- {
- FileHelper.WriteJsonFile(FeedersClearWork, FilePath.FeedersClearTaskPath);
- }
- /// <summary>
- /// 执行Feeder清料
- /// </summary>
- /// <param name="FeederId"></param>
- /// <param name="feederClearWork"></param>
- /// <returns></returns>
- public async Task ExecuteFeederClear(Guid FeederId, FeederClearWork feederClearWork, CancellationToken cancellationToken)
- {
- IVoiceCoilMotorFeeder Feeder = FeederService.GetFeeder(FeederId);
- if (!Feeder.IsConnected)
- {
- return;
- }
- for (int i = 0; i < feederClearWork.ClearCount; i++)
- {
- //1.Feeder振动之前,打开挡板
- await Feeder.OutputAsync((int)feederClearWork.BeforeOutput + 1, 0);
- await Task.Delay(200);
- //2.执行配置的Feeder振动任务
- for (int j = 0; j < feederClearWork.VibrationCount; j++)
- {
- await ExecuteFeederWorks(Feeder, feederClearWork.FeederWorks, true);
- //如果料仓停止了,则打开料仓运动
- if (!await Feeder.GetOutputStatusAsync())
- {
- await Feeder.OutputAsync((int)feederClearWork.BeforeOutput + 1, 0);
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- await Feeder.StopOutputAsync();
- return;
- }
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- await Feeder.StopOutputAsync();
- return;
- }
- //3.Feeder振动之后,关闭挡板
- await Feeder.StopOutputAsync();
- await Task.Delay(300);
- }
- //3.Feeder振动之后,关闭挡板
- await Feeder.StopOutputAsync();
- await Task.Delay(300);
- }
- #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);
- var r = DeviceConfig.Robots.FirstOrDefault(ro => ro.Id == robotid);
- //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
- var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding());
- SendTaskMessage($"{r.RobotName}Received:{buffer}", MessageLevel.Info);
- var _ = Task.Run(async () =>
- {
- try
- {
- await ExecuteRemoteCommand(buffer, async result =>
- {
- if (result.Item1)
- {
- try
- {
- if (result.Item2.Length > 1)
- {
- foreach (var item in result.Item2)
- {
- if (robot.ConnectType == TCPConnectType.Client)
- {
- if (robot.IsConnected)
- {
- await robot.SendAsync($"{item}");
- }
- }
- else
- {
- var cient = (ITcpSessionClient)arg2;
- if (cient.Online)
- {
- await robot.SendAsync(cient, $"{item}");
- }
- }
- await Task.Delay(10);
- }
- }
- else
- {
- if (robot.ConnectType == TCPConnectType.Client)
- {
- if (robot.IsConnected)
- {
- await robot.SendAsync($"{result.Item2[0]}");
- }
- }
- else
- {
- var cient = (ITcpSessionClient)arg2;
- if (cient.Online)
- {
- await robot.SendAsync(cient, $"{result.Item2[0]}");
- }
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("TCP发送数据时出错!", ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- }
- }, RobotTCPCollection[robotid].Token);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- });
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- }
- /// <summary>
- /// 机器人XY模组执行命令
- /// </summary>
- /// <param name="arg1"></param>
- /// <param name="arg2"></param>
- /// <exception cref="NotImplementedException"></exception>
- private async void Management_TrggerChangeEvent(Guid arg1, object arg2, List<ProcedureOutputOpcAdr> arg3)
- {
- if (!RobotTCPCollection.ContainsKey(arg1))
- RobotTCPCollection.Add(arg1, new CancellationTokenSource());
- else
- {
- if (RobotTCPCollection[arg1].IsCancellationRequested)
- {
- RobotTCPCollection[arg1] = new CancellationTokenSource();
- }
- }
- var robot = await RobotService.GetRobotAsync(arg1) as XYZ_Platform;
- var r = DeviceConfig.Robots.FirstOrDefault(ro => ro.Id == arg1);
- SendTaskMessage($"{r.RobotName}Received:{arg2}", MessageLevel.Info);
- var _ = Task.Run(async () =>
- {
- try
- {
- await ExecuteRemoteCommand(arg2.ToString(), async result =>
- {
- if (result.Item1)
- {
- try
- {
- string[] adrs = new string[arg3.Count];
- object[] values = new object[arg3.Count];
- values[0] = false;
- values[1] = false;
- string[] results = result.Item2[0].Split(',');
- for (int i = 0; i < arg3.Count; i++)
- {
- if (i == 0)
- {
- if (results[1] == "OK")
- {
- adrs[i] = arg3[i].Name;
- values[i] = true;
- adrs[i + 1] = arg3[i + 1].Name;
- values[i + 1] = false;
- }
- else
- {
- adrs[i] = arg3[i].Name;
- values[i] = false;
- adrs[i + 1] = arg3[i + 1].Name;
- values[i + 1] = true;
- }
- i += 1;
- continue;
- }
- if (i < arg3.Count - 1)
- {
- adrs[i] = arg3[i].Name;
- if (i < results.Length)
- {
- float res = 0f;
- if (float.TryParse(results[i], out res))
- {
- values[i] = results[i];
- }
- else
- {
- values[i] = res;
- }
- }
- else
- {
- values[i] = 0f;
- }
- }
- }
- adrs[adrs.Length - 1] = arg3[arg3.Count - 1].Name;
- values[values.Length - 1] = true;
- robot.Plc.OpcUaClient.WriteNodes(adrs, values);
- await Task.Delay(10);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("回复plc发送数据时出错!", ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- }
- }, RobotTCPCollection[arg1].Token);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("处理XYZ机器人接收的命令时出错!", ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- });
- }
- #region 处理命令
- /// <summary>
- /// 执行命令
- /// </summary>
- /// <param name="command"></param>
- public async Task ExecuteRemoteCommand(string command, Action<Tuple<bool, string[]>> callback, CancellationToken cancellationToken)
- {
- string[] commandItem = command.Split(',');
- if (CurrentProduct == null)
- {
- if (commandItem[0] == "GetProductName")
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { $"{commandItem[0]},null" }));
- return;
- }
- }
- ProcedureModel procedure = null;
- foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
- {
- procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == commandItem[0]);
- if (procedure != null) break;
- }
- if (procedure != null)
- {
- //相机拍照
- await RunProcedure(procedure, commandItem, rst =>
- {
- if (rst.Item1)
- {
- if (rst.Item2.Length > 1)
- {
- List<string> buffers = new List<string>();
- foreach (var item in rst.Item2)
- {
- buffers.Add($"{commandItem[0]},{item}");
- }
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, buffers.ToArray()));
- }
- else
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2[0]}" }));
- }
- }
- else
- {
- callback.Invoke(rst);
- }
- }, cancellationToken);
- return;
- }
- switch (commandItem[0])
- {
- case "LoadProduct":
- await LoadProduct(commandItem[1], rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetProductName":
- await GetCurrentProductName(rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetProductID":
- await GetCurrentProductID(rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetSpeed":
- await GetCurrentProductSpeed(rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetAllRobotPoints":
- await GetAllRobotPoints(rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetRobotPointsCount":
- await GetRobotPointsCount(rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetRobotPoint":
- await GetRobotPoint(int.Parse(commandItem[1]), rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetPalletsCount":
- await GetPalletsCount(rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetAllPallets":
- await GetAllPallet(rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetPallet":
- await GetPallet(commandItem[1], rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetPalletPoint":
- await GetPalletPoint(commandItem[1], int.Parse(commandItem[2]), rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetToolCount":
- await GetToolCount(commandItem[1], rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetTool":
- await GetTool(commandItem[1], int.Parse(commandItem[2]), rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "GetProcedureParam":
- await GetProcedureParam(commandItem[1], rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "CycleTime":
- ExecuteCycleTime(commandItem[1], rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "Record":
- AddProductionRecords(commandItem[1], rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- break;
- case "Err":
- SendTaskMessage(commandItem[1], MessageLevel.Error);
- DatabaseHelper.AppendAlarm(commandItem[1]);
- break;
- case "Info":
- SendTaskMessage(commandItem[1], MessageLevel.Info);
- break;
- case "GetGlobalParam":
- if (commandItem.Length == 2)
- {
- GetGlobalParam(commandItem[1], -1, rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- }
- else if (commandItem.Length == 3)
- {
- GetGlobalParam(commandItem[1], int.Parse(commandItem[2]), rst =>
- {
- callback.Invoke(new Tuple<bool, string[]>(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
- });
- }
- break;
- }
- }
- /// <summary>
- /// 运行流程
- /// </summary>
- /// <param name="procedure">流程对象</param>
- /// <param name="items">触发命令</param>
- /// <param name="callback">回调函数</param>
- /// <param name="cancellationToken">取消任务</param>
- /// <returns></returns>
- public async Task RunProcedure(ProcedureModel procedure, string[] items, Action<Tuple<bool, string[]>> callback, CancellationToken cancellationToken)
- {
- string path = FilePath.ProductsPath + "//" + CurrentProduct.Name + "//" + procedure.CameraName + "//" + procedure.Name + ".cs";
- string script = "";
- if (File.Exists(path))
- {
- try
- {
- script = FileHelper.ReadFile(path);
- SendTaskMessage(Lang.执行视觉处理脚本, MessageLevel.Debug);
- var rst1 = await ScriptHelper.ExecuteVisionScriptingAsync(script, _regionManager, _eventAggregator, _container, procedure, items, rst =>
- {
- callback.Invoke(rst);
- });
- if (!rst1.Item1)
- {
- SendTaskMessage(Lang.视觉处理脚本出错, MessageLevel.Error);
- callback.Invoke(new Tuple<bool, string[]>(false, new string[] { "ScriptError" }));
- foreach (var item in rst1.Item2)
- {
- SendTaskMessage(item, MessageLevel.Error);
- }
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- LogHelper.WriteLogError("执行视觉处理脚本时出错!", ex);
- callback.Invoke(new Tuple<bool, string[]>(false, new string[] { "ScriptError" }));
- }
- }
- else
- {
- //正常执行模块,每次拍照,会返回所有的结果数据
- IVoiceCoilMotorFeeder Feeder = null;
- if (procedure.FeederId != Guid.Empty)
- {
- Feeder = this.FeederService.GetFeeder(procedure.FeederId);
- await RunProcedureFeeder(Feeder, procedure, items, rst =>
- {
- callback.Invoke(rst);
- }, cancellationToken);
- }
- else
- {
- RunProcedureOther(procedure, items, rst =>
- {
- callback.Invoke(rst);
- }, cancellationToken);
- }
- }
- }
- /// <summary>
- /// Feeder当前Blob的面积,产品-流程-面积
- /// </summary>
- public Dictionary<Guid, Dictionary<Guid, double>> feederCurentBlobArea = new Dictionary<Guid, Dictionary<Guid, double>>();
- /// <summary>
- /// 最后一次feeder拍照出来的点位,流程-点数据
- /// </summary>
- public Dictionary<Guid, List<Vector<double>>> LastPointsForFeeder = new Dictionary<Guid, List<Vector<double>>>();
- /// <summary>
- /// 每次拍照得到的点位数据集合,每个流程中包含多个结果输出项,每个结果项中包含多个点位,流程-输出集合-点位队列
- /// </summary>
- public Dictionary<Guid, Dictionary<string, Queue<string>>> PointCollection = new Dictionary<Guid, Dictionary<string, Queue<string>>>();
- /// <summary>
- /// Feeder相机引导模式
- /// </summary>
- /// <param name="Feeder">feeder</param>
- /// <param name="procedure">流程对象</param>
- /// <param name="items">触发命令</param>
- /// <param name="callback">回调函数</param>
- /// <returns></returns>
- public async Task RunProcedureFeeder(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, string[] items, Action<Tuple<bool, string[]>> callback, CancellationToken cancellationToken)
- {
- //是否检测上次的点位,相同点位排除
- bool IsCheckLastPoints = false;
- bool IsSingleResultModel = false;
- int InputVibration = 0;
- int GetPosCount = 1;
- Dictionary<string, string> InputTerminal = null; //触发命令传入的输入终端
- if (items.Length >= 2 && string.Equals(items[1], "GetPos"))
- {
- //Camera1,GetPos,PosCount,CheckLastPoints
- if (items.Length >= 4 && string.Equals(items[3], "CheckLastPoints"))
- {
- IsCheckLastPoints = true;
- GetPosCount = int.Parse(items[2]);
- }
- ////Camera1,GetPos,CheckLastPoints
- else if (items.Length >= 3 && string.Equals(items[2], "CheckLastPoints"))
- {
- IsCheckLastPoints = true;
- GetPosCount = 1;
- }
- else if (items.Length >= 3 && int.TryParse(items[2], out GetPosCount))
- {
- }
- else
- {
- GetPosCount = 1;
- }
- if (GetPosCount <= 0)
- {
- GetPosCount = 1;
- }
- //进入一次拍照后,,点位数据保存在软件里面,机器人每次跟软件获取一个或者两个点位
- ////获取点位数据
- if (!PointCollection.ContainsKey(procedure.Id))
- {
- PointCollection.Add(procedure.Id, new Dictionary<string, Queue<string>>());
- }
- IsSingleResultModel = true;
- }
- else if (items.Length >= 2 && string.Equals(items[1], "ClearPos"))
- {
- //进入一次拍照后,,点位数据保存在软件里面,机器人每次跟软件获取一个或者两个点位
- ////清除所有点位数据
- if (!PointCollection.ContainsKey(procedure.Id))
- {
- PointCollection.Add(procedure.Id, new Dictionary<string, Queue<string>>());
- }
- PointCollection[procedure.Id].Clear();
- IsSingleResultModel = true;
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { "ClearPos" }));
- return;
- }
- else if (items.Length >= 2 && string.Equals(items[1], "CheckLastPoints"))
- {
- IsCheckLastPoints = true;
- }
- else if (items.Length >= 2 && string.Equals(items[1], "Vibration"))
- {
- //先振后拍
- InputVibration = 1;
- }
- else if (items.Length >= 2 && string.Equals(items[1], "NoVibration"))
- {
- //先拍再决定是否要不要振
- InputVibration = 2;
- }
- else if (items.Length >= 2 && string.Equals(items[1], "SetVisionToolInputs"))
- {
- InputTerminal = new Dictionary<string, string>();
- //触发命令传入的输入终端
- for (int i = 2; i < items.Length; i += 2)
- {
- if (!string.IsNullOrEmpty(items[i]) && items.Length >= i + 2)
- {
- InputTerminal.Add(items[i].Trim(), items[i + 1].Trim());
- }
- }
- if (InputTerminal.Count <= 0)
- {
- InputTerminal = null;
- }
- }
- //如果还没有结果项目,则触发拍照,获取结果
- if (IsSingleResultModel && PointCollection[procedure.Id].Count > 0)
- {
- //遍历所有的结果项
- foreach (var item in PointCollection[procedure.Id])
- {
- //如果结果的数量大于等于可获取的点位数量,则直接返回点位数据
- if (item.Value != null && item.Value.Count >= GetPosCount)
- {
- List<string> poslist = new List<string>();
- for (int i = 0; i < GetPosCount; i++)
- {
- poslist.Add(item.Value.Dequeue());
- }
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { $"OK,{item.Key},{string.Join(",", poslist)}" }));
- SendTaskMessage($"{item.Key}{Lang.剩余点位数量}:{item.Value.Count}", MessageLevel.Debug);
- return;
- }
- }
- }
- if (IsSingleResultModel)
- {
- PointCollection[procedure.Id].Clear();
- }
- await ExecuteFeederForPhotoBefore(Feeder, procedure, InputVibration, cancellationToken);
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- await Feeder.CloseLightAsync();
- return;
- }
- DateTime nowtime = DateTime.Now;
- //多次拍照
- for (int i = 0; i < procedure.FeederFailLimit; i++)
- {
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- await Feeder.CloseLightAsync();
- return;
- }
- SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
- string photoresult = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection);
- if (!string.IsNullOrEmpty(photoresult))
- {
- //多次拍照,如果拍照次数到达上限,直接返回结果
- if (i == procedure.FeederFailLimit - 1)
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { $"NG,{photoresult}" }));
- return;
- }
- else
- {
- continue;
- }
- }
- var BlobTotalArea = (double)outputCollection["BlobTotalArea"].Value;
- //记录当前的blob面积
- Dictionary<Guid, double> tuple;
- if (feederCurentBlobArea.TryGetValue(CurrentProduct.ID, out tuple))
- {
- //如流程当前已经存在此流程的记录
- if (tuple.ContainsKey(procedure.Id))
- {
- tuple[procedure.Id] = BlobTotalArea;
- }
- else
- {
- tuple.Add(procedure.Id, BlobTotalArea);
- }
- }
- else
- {
- feederCurentBlobArea.Add(CurrentProduct.ID, new Dictionary<Guid, double>());
- feederCurentBlobArea[CurrentProduct.ID].Add(procedure.Id, BlobTotalArea);
- }
- if (!outputCollection.Contains("Found"))
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { "NG,NoOut[Found]" }));
- return;
- }
- bool Found = (bool)(outputCollection["Found"].Value);
- //拍照OK
- if (Found)
- {
- SendTaskMessage(Lang.拍照OK, MessageLevel.Debug);
- if (procedure.ProcedureOutputs == null)
- {
- SendTaskMessage(Lang.视觉流程未配置输出项, MessageLevel.Alarm);
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { "NG,NotOutputs" }));
- return;
- }
- var ResultCollection = GetVisionOutput(procedure, outputCollection, items);
- if (!ResultCollection.Item1)
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { ResultCollection.Item2 }));
- return;
- }
- List<string> SendResults = new List<string>();
- //将本次点位结果记录至最后一次
- if (!LastPointsForFeeder.ContainsKey(Feeder.Id))
- {
- LastPointsForFeeder.Add(Feeder.Id, new List<Vector<double>>());
- }
- int PosNum = 0;
- bool ishavepoint = false;
- List<Vector<double>> pointBuffer = new List<Vector<double>>();
- foreach (var result in ResultCollection.Item3)
- {
- //是点位数据时
- if (result.Value.Item1)
- {
- ishavepoint = true;
- //值不为空时
- if (result.Value.Item2 != null)
- {
- List<string> points = new List<string>();
- foreach (var pos in (List<Vector<double>>)(result.Value.Item2))
- {
- pointBuffer.Add(pos);
- //判断是否有重复的点位,防止机器人重复取同一个物料,陷入死循环
- if (IsCheckLastPoints)
- {
- if (LastPointsForFeeder.ContainsKey(Feeder.Id))
- {
- var repeated = LastPointsForFeeder[Feeder.Id].FirstOrDefault(p => Math.Abs(p[0] - pos[0]) < 1 && Math.Abs(p[1] - pos[1]) < 1);
- if (repeated != null) continue;
- }
- }
- if (IsSingleResultModel)
- {
- PosNum++;
- //如果当前是软件点位队列存储模式,则,将所有数据存储在队列中
- if (!PointCollection[procedure.Id].ContainsKey(result.Key))
- {
- PointCollection[procedure.Id].Add(result.Key, new Queue<string>());
- }
- PointCollection[procedure.Id][result.Key].Enqueue($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
- }
- else
- {
- //根据当前点位数量决定是否继续输出点位。
- PosNum++;
- if (PosNum >= procedure.OutputPointCountMax)
- {
- points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
- break;
- }
- else
- {
- points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
- }
- }
- }
- if (IsSingleResultModel)
- {
- //如果当前是软件点位队列存储模式,则,将所有数据存储在队列中
- if (!PointCollection[procedure.Id].ContainsKey(result.Key))
- {
- PointCollection[procedure.Id].Add(result.Key, new Queue<string>());
- }
- SendTaskMessage($"{result.Key}{Lang.可用的点位个数}:{PointCollection[procedure.Id][result.Key].Count}", MessageLevel.Debug);
- }
- else
- {
- if (points.Count == 0)
- {
- SendResults.Add($"0");
- break;
- }
- else
- {
- SendResults.Add($"{points.Count},{string.Join(",", points)}");
- }
- }
- }
- else
- {
- SendResults.Add($"0");
- }
- }
- //其他输出数据时
- else
- {
- if (result.Value.Item2 != null)
- {
- SendResults.Add((string)result.Value.Item2);
- }
- else
- {
- SendResults.Add($"null");
- }
- }
- }
- //将本次点位结果记录至最后一次
- LastPointsForFeeder[Feeder.Id] = pointBuffer;
- if (ishavepoint && PosNum <= 0)
- {
- //存在点位输出项,但是点位数量为0
- await ExecuteFeederForPhotoLater(Feeder, procedure, BlobTotalArea, cancellationToken);
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- await Feeder.CloseLightAsync();
- return;
- }
- continue;
- }
- if (Feeder != null)
- {
- await Feeder.CloseLightAsync();
- }
- if (IsSingleResultModel)
- {
- //遍历所有的结果项
- foreach (var item in PointCollection[procedure.Id])
- {
- //如果结果的数量大于等于可获取的点位数量,则直接返回点位数据
- if (item.Value != null && item.Value.Count >= GetPosCount)
- {
- List<string> poslist = new List<string>();
- for (int j = 0; j < GetPosCount; j++)
- {
- poslist.Add(item.Value.Dequeue());
- }
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { $"OK,{item.Key},{string.Join(",", poslist)}" }));
- SendTaskMessage($"{item.Key}{Lang.剩余点位数量}:{item.Value.Count}", MessageLevel.Debug);
- return;
- }
- }
- }
- else
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { $"OK,{string.Join(";", SendResults)}" }));
- }
- return;
- }
- //拍照NG
- else
- {
- SendTaskMessage(Lang.拍照NG, MessageLevel.Error);
- await ExecuteFeederForPhotoLater(Feeder, procedure, BlobTotalArea, cancellationToken);
- continue;
- }
- }
- SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { "NG,NoFind" }));
- }
- /// <summary>
- /// 相机拍照,其他模式
- /// </summary>
- /// <param name="procedure"></param>
- /// <param name="items"></param>
- /// <param name="callback"></param>
- public void RunProcedureOther(ProcedureModel procedure, string[] items, Action<Tuple<bool, string[]>> callback, CancellationToken cancellationToken)
- {
- DateTime nowtime = DateTime.Now;
- Dictionary<string, string> InputTerminal = null; //触发命令传入的输入终端
- if (items.Length >= 2 && string.Equals(items[1], "SetVisionToolInputs"))
- {
- InputTerminal = new Dictionary<string, string>();
- //触发命令传入的输入终端
- for (int i = 2; i < items.Length; i += 2)
- {
- if (!string.IsNullOrEmpty(items[i]) && items.Length >= i + 2)
- {
- InputTerminal.Add(items[i].Trim(), items[i + 1].Trim());
- }
- }
- if (InputTerminal.Count <= 0)
- {
- InputTerminal = null;
- }
- }
- for (int i = 0; i < procedure.FeederFailLimit; i++)
- {
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- return;
- }
- SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
- string photoresult = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection);
- if (!string.IsNullOrEmpty(photoresult))
- {
- //多次拍照,如果拍照次数到达上限,直接返回结果
- if (i == procedure.FeederFailLimit - 1)
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { $"NG,{photoresult}" }));
- return;
- }
- else
- {
- continue;
- }
- }
- if (!outputCollection.Contains("Found"))
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { "NG,NoOut[Found]" }));
- return;
- }
- bool Found = (bool)(outputCollection["Found"].Value);
- //拍照OK
- if (Found)
- {
- SendTaskMessage(Lang.拍照OK, MessageLevel.Debug);
- if (procedure.ProcedureOutputs == null)
- {
- SendTaskMessage(Lang.视觉流程未配置输出项, MessageLevel.Alarm);
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { "NG,NotOutputs" }));
- return;
- }
- var ResultCollection = GetVisionOutput(procedure, outputCollection, items);
- if (!ResultCollection.Item1)
- {
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { ResultCollection.Item2 }));
- return;
- }
- List<string> SendResults = new List<string>();
- int PosNum = 0;
- bool ishavepoint = false;
- foreach (var result in ResultCollection.Item3)
- {
- //是点位数据时
- if (result.Value.Item1)
- {
- ishavepoint = true;
- //值不为空时
- if (result.Value.Item2 != null)
- {
- List<string> points = new List<string>();
- foreach (var pos in (List<Vector<double>>)(result.Value.Item2))
- {
- //根据当前点位数量决定是否继续输出点位。
- PosNum++;
- if (PosNum >= procedure.OutputPointCountMax)
- {
- points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
- break;
- }
- else
- {
- points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
- }
- }
- if (points.Count == 0)
- {
- SendResults.Add($"0");
- break;
- }
- else
- {
- SendResults.Add($"{points.Count},{string.Join(",", points)}");
- }
- }
- else
- {
- SendResults.Add($"0");
- }
- }
- //其他输出数据时
- else
- {
- if (result.Value.Item2 != null)
- {
- SendResults.Add((string)result.Value.Item2);
- }
- else
- {
- SendResults.Add($"null");
- }
- }
- }
- if (ishavepoint && PosNum <= 0)
- {
- continue;
- }
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { $"OK,{string.Join(";", SendResults)}" }));
- return;
- }
- //拍照NG
- else
- {
- SendTaskMessage(Lang.拍照NG, MessageLevel.Error);
- continue;
- }
- }
- SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
- callback.Invoke(new Tuple<bool, string[]>(true, new string[] { "NG,NoFind" }));
- }
- #region 相机拍照
- /// <summary>
- /// 执行相机拍照
- /// </summary>
- /// <param name="procedure"></param>
- /// <param name="outputCollection"></param>
- /// <returns></returns>
- public string ExecutePhoto(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection)
- {
- try
- {
- //采集图像
- var camera = CameraService.GetCamera(procedure.CameraId);
- bool succed = camera.SetExposureTime(procedure.ExposureTime);
- if (!succed)
- {
- SendTaskMessage($"相机曝光设置失败!", MessageLevel.Error);
- }
- succed = camera.SetGain(procedure.Gain);
- if (!succed)
- {
- SendTaskMessage($"相机增益设置失败!", MessageLevel.Error);
- }
- DateTime nowtime = DateTime.Now;
- LogHelper.WriteLogInfo("开始采集图像");
- var image = camera.Grab();
- if (image == null)
- {
- SendTaskMessage(Lang.图像采集失败, MessageLevel.Error);
- outputCollection = null;
- return "CameraError";
- }
- procedure.ToolBlock.Inputs["InputImage"].Value = image;
- LogHelper.WriteLogInfo($"采集图像完成;用时:{(DateTime.Now - nowtime).Milliseconds}ms");
- if (InputTerminal != null)
- {
- LogHelper.WriteLogInfo($"为ToolBlock传入输入终端");
- foreach (var item in InputTerminal)
- {
- if (procedure.ToolBlock.Inputs.Contains(item.Key))
- {
- LogHelper.WriteLogInfo($"传入[{item.Key}]={item.Value}");
- procedure.ToolBlock.Inputs[item.Key].Value = item.Value;
- }
- else
- {
- LogHelper.WriteLogInfo($"创建并传入[{item.Key}]={item.Value}");
- procedure.ToolBlock.Inputs.Add(new CogToolBlockTerminal(item.Key, item.Value));
- }
- }
- }
- //运行视觉工具
- LogHelper.WriteLogInfo("开始运行视觉工具");
- procedure.ToolBlock.Run();
- if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
- {
- SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
- outputCollection = procedure.ToolBlock.Outputs;
- ICogRecord record = null;
- foreach (CogToolBlockTerminal item in outputCollection)
- {
- if (item.Value is ICogRecord)
- record = item.Value as ICogRecord;
- }
- _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
- {
- CameraName = procedure.CameraName,
- Id = procedure.CameraId,
- Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
- Graphic = outputCollection["Graphic"].Value as CogGraphicCollection,
- Record = record,
- Result = (bool)(outputCollection["Found"].Value),
- IsShow = true,
- IsSaveImage = procedure.IsSaveImage,
- SaveImageModel = procedure.SaveImageModel,
- SaveImagePathModel = procedure.SaveImagePathModel,
- SavePath = procedure.SavePath,
- IsCompress = procedure.IsCompress,
- });
- DatabaseHelper.AddCameraRecords(CurrentProduct.Name, procedure.Name, outputCollection);
- return string.Empty;
- }
- else
- {
- SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Error);
- SendTaskMessage(procedure.ToolBlock.RunStatus.Message, MessageLevel.Error);
- outputCollection = null;
- _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
- {
- CameraName = procedure.CameraName,
- Id = procedure.CameraId,
- Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
- Graphic = new CogGraphicCollection(),
- Result = false,
- IsShow = true,
- IsSaveImage = procedure.IsSaveImage,
- SaveImageModel = procedure.SaveImageModel,
- SaveImagePathModel = procedure.SaveImagePathModel,
- SavePath = procedure.SavePath
- });
- DatabaseHelper.AddCameraRecords(CurrentProduct.Name, procedure.Name, outputCollection);
- return "ToolBlockError";
- }
- }
- catch (Exception ex)
- {
- SendTaskMessage(ex.Message, MessageLevel.Error);
- LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错!", ex);
- outputCollection = null;
- return "Error";
- }
- }
- /// <summary>
- /// 校准转换
- /// </summary>
- /// <param name="calib"></param>
- /// <param name="x"></param>
- /// <param name="y"></param>
- /// <param name="angle"></param>
- /// <returns></returns>
- public Vector<double> TransformPoint(CalibrationInfo calib, double x, double y, double angle, string[] items, out string message, RobotBrand robotBrand = RobotBrand.Default)
- {
- //得到校准矩阵
- Matrix<double> matrix = Matrix<double>.Build.DenseOfArray(calib.AffineTransformationMaterial);
- if (calib.CameraMount == CameraMount.FixedDown || calib.CameraMount == CameraMount.MobileJ2 || calib.CameraMount == CameraMount.MobileJ4)
- {
- angle *= -1;
- }
- //将像素坐标转换成机器人坐标
- var rpos = matrix * Vector<double>.Build.Dense(new double[] { x, y, 1 });
- if (calib.CameraMount == Enums.CameraMount.MobileJ4)
- {
- if (items.Length < 4)
- {
- SendTaskMessage(Lang.J4移动相机校准转换条件错误, MessageLevel.Alarm);
- message = "NG,DataError";
- return null;
- }
- //像素直接转换成mm时的点位
- double Robot_X, Robot_Y;
- Robot_X = rpos[0];
- Robot_Y = rpos[1];
- //机器人当前TOOL 0下的坐标
- double curpos_x = 0, curpos_y = 0, curpos_u = 0;
- curpos_x = double.Parse(items[1]);
- curpos_y = double.Parse(items[2]);
- curpos_u = double.Parse(items[3]);
- //得到旋转矩阵
- double angle1 = Math.PI * (curpos_u - calib.MarkPoint.U) / 180;
- // 创建T矩阵
- Matrix<double> rotationMatrix = Matrix<double>.Build.DenseOfArray(new double[,]
- {
- { Math.Cos(angle1), -Math.Sin(angle1) },
- { Math.Sin(angle1), Math.Cos(angle1) }
- });
- Vector<double> p3 = Vector<double>.Build.Dense(new double[] { Robot_X - calib.CalibPoints[0].Robot.X, Robot_Y - calib.CalibPoints[0].Robot.Y });
- Vector<double> phere = Vector<double>.Build.Dense(new double[] { curpos_x, curpos_y });
- var cc = rotationMatrix * p3 + phere;
- rpos = Vector<double>.Build.Dense(new double[] { cc[0], cc[1] });
- }
- else if (calib.CameraMount == Enums.CameraMount.MobileDown_XYPlatform)
- {
- if (items.Length < 4)
- {
- SendTaskMessage(Lang.移动相机校准转换条件错误, MessageLevel.Alarm);
- message = "NG,DataError";
- return null;
- }
- //像素直接转换成mm时的点位
- double Robot_X, Robot_Y;
- Robot_X = rpos[0];
- Robot_Y = rpos[1];
- //模组当前TOOL 0下的坐标(相当于模组吸嘴坐标)
- double curpos_x = 0, curpos_y = 0, curpos_u = 0;
- curpos_x = double.Parse(items[1]);
- curpos_y = double.Parse(items[2]);
- curpos_u = double.Parse(items[3]);
- //得到旋转矩阵
- //double angle1 = Math.PI * (curpos_u - calib.MarkPoint.U) / 180;
- double angle1 = 0;
- // 创建T矩阵
- Matrix<double> rotationMatrix = Matrix<double>.Build.DenseOfArray(new double[,]
- {
- { Math.Cos(angle1), -Math.Sin(angle1) },
- { Math.Sin(angle1), Math.Cos(angle1) }
- });
- Vector<double> p3 = Vector<double>.Build.Dense(new double[] { Robot_X - calib.CalibPoints[0].Robot.X, Robot_Y - calib.CalibPoints[0].Robot.Y });
- Vector<double> phere = Vector<double>.Build.Dense(new double[] { curpos_x, curpos_y });
- var cc = rotationMatrix * p3 + phere;
- rpos = Vector<double>.Build.Dense(new double[] { cc[0], cc[1] });//Mark点在tool0下的的坐标
- }
- else
- {
- //当需要直接转换工具坐标时
- if (items.Length == 4 && double.TryParse(items[1], out double curposX) && double.TryParse(items[2], out double curposY) && double.TryParse(items[3], out double curposU))
- {
- //根据机器人当前的点位计算工具坐标
- ToolCoord tool = new ToolCoord();
- if (robotBrand == RobotBrand.Schneider)
- {
- curposU *= -1;
- }
- tool.ComputeTool(curposX, curposY, curposU, rpos[0], rpos[1]);
- rpos = Vector<double>.Build.Dense(new double[] { tool.X, tool.Y });
- }
- }
- message = string.Empty;
- return Vector<double>.Build.Dense(new double[] { rpos[0], rpos[1], angle });
- }
- /// <summary>
- /// 获取需要输出项
- /// </summary>
- /// <param name="procedure"></param>
- /// <param name="outputCollection"></param>
- /// <param name="IsCheckLastPoints"></param>
- /// <returns>是否成功,错误返回内容,<项的名称,<是否是点位数据,值>></returns>
- public Tuple<bool, string, Dictionary<string, Tuple<bool, object>>> GetVisionOutput(ProcedureModel procedure, CogToolBlockTerminalCollection outputCollection, string[] items)
- {
- RobotBrand robotBrand = RobotBrand.Default;
- var robot = DeviceConfig.Robots.FirstOrDefault(r => r.Id == procedure.RobotId);
- if (robot != null)
- {
- robotBrand = robot.RobotBrand;
- }
- List<string> SendResults = new List<string>();
- //<输出项的名称,<是否点位,每项输出集合值>>
- Dictionary<string, Tuple<bool, object>> ResultCollection = new Dictionary<string, Tuple<bool, object>>();
- foreach (var output in procedure.ProcedureOutputs) //遍历配置的所有需要输出项
- {
- //根据输出类型进行区分输出
- if (output.ValueType == typeof(string))
- {
- //需要点位转换时,进行点位提取
- if (output.IsPointTran)
- {
- if (outputCollection[output.Name].Value == null || string.IsNullOrEmpty(outputCollection[output.Name].Value.ToString()))
- {
- //如果需要输出的项的值为空,即点位数据为空,则输出点位的个数为0
- ResultCollection.Add(output.Name, new Tuple<bool, object>(true, null));
- continue;
- }
- string[] strpoints = outputCollection[output.Name].Value.ToString().Split(";");
- List<Vector<double>> currentPointsForFeeder = new List<Vector<double>>();
- int index = 0;
- //获取相机校准
- var calib = DeviceConfig.Calibrations.FirstOrDefault(cal => cal.Id == procedure.CalibrationId);
- if (calib == null)
- {
- SendTaskMessage(Lang.J4移动相机校准转换条件错误1, MessageLevel.Alarm);
- return new Tuple<bool, string, Dictionary<string, Tuple<bool, object>>>(false, "NG,NotCalibrations", null);
- }
- List<string> SendDtat = new List<string>();
- List<string> points = new List<string>();
- //遍历所有的输出点位
- foreach (var pos in strpoints)
- {
- //转换点位-像素转换成机器人绝对坐标
- var rpos = TransformPoint(calib, double.Parse(pos.Split(',')[0]), double.Parse(pos.Split(',')[1]), double.Parse(pos.Split(',')[2]), items, out string message, robotBrand);
- if (rpos == null)
- {
- return new Tuple<bool, string, Dictionary<string, Tuple<bool, object>>>(false, message, null);
- }
- currentPointsForFeeder.Add(rpos);
- }
- ResultCollection[output.Name] = new Tuple<bool, object>(true, currentPointsForFeeder);
- }
- //直接输出字符串
- else
- {
- if (outputCollection[output.Name].Value == null || string.IsNullOrEmpty(outputCollection[output.Name].Value.ToString()))
- {
- ResultCollection.Add(output.Name, new Tuple<bool, object>(false, null));
- continue;
- }
- ResultCollection[output.Name] = new Tuple<bool, object>(false, outputCollection[output.Name].Value.ToString());
- }
- }
- else
- {
- if (outputCollection[output.Name].Value == null)
- {
- ResultCollection.Add(output.Name, new Tuple<bool, object>(false, null));
- }
- else
- {
- ResultCollection[output.Name] = new Tuple<bool, object>(false, outputCollection[output.Name].Value.ToString());
- }
- }
- }
- return new Tuple<bool, string, Dictionary<string, Tuple<bool, object>>>(true, string.Empty, ResultCollection);
- }
- /// <summary>
- /// Feeder拍照前,执行Feeder
- /// </summary>
- /// <param name="Feeder"></param>
- /// <param name="procedure"></param>
- /// <returns></returns>
- public async Task ExecuteFeederForPhotoBefore(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, int CompulsoryVibration, CancellationToken cancellationToken)
- {
- if (Feeder.FeederBrand == FeederBrand.AFAG)
- {
- await Feeder.SetLightValueAsync((ushort)procedure.LightValue);
- }
- else
- {
- //Feeder光源亮度设置
- if (procedure.LightValue > 3)
- {
- var light = await Feeder.GetLightBrightnessAsync();
- if (procedure.LightValue != light)
- {
- await Feeder.SetLightValueAsync((ushort)procedure.LightValue);
- }
- //打开光源
- await Feeder.OpenLightAsync();
- }
- }
- if (CompulsoryVibration == 2)
- {
- return;
- }
- //先振后拍时
- if (procedure.VibrationModel == VibrationModel.VibrationPhoto || CompulsoryVibration == 1)
- {
- if (procedure.FeederWorks != null && procedure.FeederWorks.FeederWorkList != null)
- {
- bool flog = false;
- Dictionary<Guid, double> tuple;
- if (feederCurentBlobArea.TryGetValue(CurrentProduct.ID, out tuple))
- {
- //首先判断是否是当前流程
- if (tuple.TryGetValue(procedure.Id, out double minArea))
- {
- //如果上次的Blob面积小于设定的最小值,则触发供料
- if (minArea <= procedure.MinArea)
- {
- flog = true;
- SendTaskMessage(Lang.执行料仓供料, MessageLevel.Info);
- await ExecuteFeederStockWorks(Feeder, procedure.FeederStockWorks, cancellationToken);
- await Task.Delay(procedure.WaitFeederStop);
- SendTaskMessage(Lang.料仓供料结束, MessageLevel.Info);
- }
- }
- }
- if (!flog)
- {
- //执行配置的Feeder振动任务
- await ExecuteFeederWorks(Feeder, procedure.FeederWorks, cancellationToken, false);
- }
- await Task.Delay(procedure.WaitFeederStop);
- }
- }
- else
- {
- if (procedure.LightValue > 3)
- {
- await Task.Delay(procedure.WaitPhoto);
- }
- Dictionary<Guid, double> tuple;
- if (feederCurentBlobArea.TryGetValue(CurrentProduct.ID, out tuple))
- {
- //首先判断是否是当前流程
- if (tuple.TryGetValue(procedure.Id, out double minArea))
- {
- //如果上次的Blob面积小于设定的最小值,则触发供料
- if (minArea <= procedure.MinArea)
- {
- SendTaskMessage(Lang.执行料仓供料, MessageLevel.Info);
- await ExecuteFeederStockWorks(Feeder, procedure.FeederStockWorks, cancellationToken);
- await Task.Delay(procedure.WaitFeederStop);
- SendTaskMessage(Lang.料仓供料结束, MessageLevel.Info);
- //执行配置的Feeder振动任务
- /*foreach (var feederwork in procedure.FeederWorks.FeederWorkList)
- {
- if (feederwork.Function == VibrationFunction.Delay)
- {
- await Task.Delay(feederwork.Duration);
- }
- else
- {
- await Feeder.StartAction((int)feederwork.Function, feederwork.Duration);
- await Task.Delay(feederwork.Duration);
- }
- }*/
- await Task.Delay(procedure.WaitFeederStop);
- }
- }
- }
- }
- }
- /// <summary>
- /// Feeder拍照后,执行Feeder
- /// </summary>
- /// <param name="Feeder"></param>
- /// <param name="procedure"></param>
- /// <param name="curentBlobArea"></param>
- /// <returns></returns>
- public async Task ExecuteFeederForPhotoLater(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, double curentBlobArea, CancellationToken cancellationToken)
- {
- //根据斑点面积决定是否料仓供料
- if (curentBlobArea <= procedure.MinArea)
- {
- SendTaskMessage(Lang.执行料仓供料, MessageLevel.Info);
- await ExecuteFeederStockWorks(Feeder, procedure.FeederStockWorks, cancellationToken);
- await Task.Delay(procedure.WaitFeederStop);
- SendTaskMessage(Lang.料仓供料结束, MessageLevel.Info);
- }
- else
- {
- if (procedure.FeederWorks != null && procedure.FeederWorks.FeederWorkList != null)
- {
- SendTaskMessage(Lang.执行Feeder振动, MessageLevel.Info);
- //执行配置的Feeder振动任务
- await ExecuteFeederWorks(Feeder, procedure.FeederWorks, cancellationToken);
- await Task.Delay(procedure.WaitFeederStop);
- SendTaskMessage(Lang.Feeder振动结束, MessageLevel.Info);
- }
- }
- }
- #endregion
- /// <summary>
- /// 加载产品
- /// </summary>
- /// <param name="name"></param>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task LoadProduct(string name, Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- ProductModel product = null;
- product = Products.FirstOrDefault(p => p.Name == name);
- if (product == null)
- {
- if (int.TryParse(name, out int ProductNumber))
- {
- product = Products.FirstOrDefault(p => p.NumberCode == ProductNumber);
- }
- else
- {
- callback.Invoke(new Tuple<bool, string>(true, "NG,NoProduct"));
- return;
- }
- }
- LoadProducts(product);
- callback.Invoke(new Tuple<bool, string>(true, "OK"));
- });
- }
- /// <summary>
- /// 获取当前产品名称
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetCurrentProductName(Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, "null"));
- return;
- }
- callback.Invoke(new Tuple<bool, string>(true, CurrentProduct.Name));
- });
- }
- /// <summary>
- /// 获取当前产品ID
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetCurrentProductID(Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, "null"));
- return;
- }
- callback.Invoke(new Tuple<bool, string>(true, CurrentProduct.ID.ToString()));
- });
- }
- /// <summary>
- /// 获取速度
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetCurrentProductSpeed(Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null)
- {
- return;
- }
- int power = CurrentProduct.Power ? 1 : 0;
- int IsUserUpCamera = CurrentProduct.IsUserUpCamera ? 1 : 0;
- callback.Invoke(new Tuple<bool, string>(true, $"{CurrentProduct.Speed},{CurrentProduct.Accel},{CurrentProduct.Speeds},{CurrentProduct.Accels},{power},{IsUserUpCamera}"));
- });
- }
- /// <summary>
- /// 获取所有的机器人点位
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetAllRobotPoints(Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- StringBuilder sb = new StringBuilder();
- foreach (var item in CurrentProduct.RobotPoint.Points)
- {
- sb.Append($"{item.Number},{item.X.ToString("F3")},{item.Y.ToString("F3")},{item.Z.ToString("F3")},{item.U.ToString("F3")},{item.V.ToString("F3")},{item.W.ToString("F3")},{(int)item.Hand},{item.Local},{item.Tool},{item.RobotId.ToString()},");
- }
- callback.Invoke(new Tuple<bool, string>(true, $"{sb.ToString().TrimEnd(',')}"));
- });
- }
- /// <summary>
- /// 获取机器人点位数量
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetRobotPointsCount(Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- if (CurrentProduct.RobotPoint.Points == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"0"));
- }
- else
- {
- callback.Invoke(new Tuple<bool, string>(true, $"{CurrentProduct.RobotPoint.Points.Count}"));
- }
- });
- }
- /// <summary>
- /// 获取指定编号机器人点位
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetRobotPoint(int number, Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- var pos = CurrentProduct.RobotPoint.Points.FirstOrDefault(p => p.Number == number);
- if (pos == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"null"));
- }
- else
- {
- callback.Invoke(new Tuple<bool, string>(true, $"{pos.Number},{pos.X.ToString("F3")},{pos.Y.ToString("F3")},{pos.Z.ToString("F3")},{pos.U.ToString("F3")},{pos.V.ToString("F3")},{pos.W.ToString("F3")},{(int)pos.Hand},{pos.Local},{pos.Tool},{pos.RobotId.ToString()}"));
- }
- });
- }
- /// <summary>
- /// 获取托盘数量
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetPalletsCount(Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- if (CurrentProduct.RobotPoint.Pallets == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"0"));
- }
- else
- {
- callback.Invoke(new Tuple<bool, string>(true, $"{CurrentProduct.RobotPoint.Pallets.Count}"));
- }
- });
- }
- /// <summary>
- /// 获取所有的托盘
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetAllPallet(Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- StringBuilder sb = new StringBuilder();
- foreach (var item in CurrentProduct.RobotPoint.Pallets)
- {
- sb.Append($"{item.Name},{item.Row},{item.Column},{(int)item.Arrangement},{item.P0.X.ToString("F3")},{item.P0.Y.ToString("F3")},{item.P0.Z.ToString("F3")},{item.P0.U.ToString("F3")},{item.P0.V.ToString("F3")},{item.P0.W.ToString("F3")},{(int)item.P0.Hand},{item.P0.Local},{item.P0.Tool}," +
- $"{item.P1.X.ToString("F3")},{item.P1.Y.ToString("F3")},{item.P1.Z.ToString("F3")},{item.P1.U.ToString("F3")},{item.P1.V.ToString("F3")},{item.P1.W.ToString("F3")},{(int)item.P1.Hand},{item.P1.Local},{item.P1.Tool}," +
- $"{item.P2.X.ToString("F3")},{item.P2.Y.ToString("F3")},{item.P2.Z.ToString("F3")},{item.P2.U.ToString("F3")},{item.P2.V.ToString("F3")},{item.P2.W.ToString("F3")},{(int)item.P2.Hand},{item.P0.Local},{item.P2.Tool},");
- }
- callback.Invoke(new Tuple<bool, string>(true, $"{sb.ToString().TrimEnd(',')}"));
- });
- }
- /// <summary>
- /// 获取指定名称的托盘
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetPallet(string name, Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- var pallet = CurrentProduct.RobotPoint.Pallets.FirstOrDefault(p => p.Name == name);
- if (pallet == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"null"));
- }
- else
- {
- callback.Invoke(new Tuple<bool, string>(true, $"{pallet.Name},{pallet.Row},{pallet.Column},{(int)pallet.Arrangement},{pallet.P0.X.ToString("F3")},{pallet.P0.Y.ToString("F3")},{pallet.P0.Z.ToString("F3")},{pallet.P0.U.ToString("F3")},{pallet.P0.V.ToString("F3")},{pallet.P0.W.ToString("F3")},{(int)pallet.P0.Hand},{pallet.P0.Local},{pallet.P0.Tool}," +
- $"{pallet.P1.X.ToString("F3")},{pallet.P1.Y.ToString("F3")},{pallet.P1.Z.ToString("F3")},{pallet.P1.U.ToString("F3")},{pallet.P1.V.ToString("F3")},{pallet.P1.W.ToString("F3")},{(int)pallet.P1.Hand},{pallet.P1.Local},{pallet.P1.Tool}," +
- $"{pallet.P2.X.ToString("F3")},{pallet.P2.Y.ToString("F3")},{pallet.P2.Z.ToString("F3")},{pallet.P2.U.ToString("F3")},{pallet.P2.V.ToString("F3")},{pallet.P2.W.ToString("F3")},{(int)pallet.P2.Hand},{pallet.P0.Local},{pallet.P2.Tool}"));
- }
- });
- }
- /// <summary>
- /// 获取夹具末端执行器数量
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetToolCount(string command, Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.CameraProcedures == null)
- {
- return;
- }
- ProcedureModel procedure = null;
- foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
- {
- procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == command);
- if (procedure != null) break;
- }
- if (procedure == null || procedure.ToolInfo == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"0"));
- return;
- }
- callback.Invoke(new Tuple<bool, string>(true, $"{procedure.ToolInfo.Count}"));
- });
- }
- /// <summary>
- /// 获取指定编号的夹具末端执行器参数
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetTool(string command, int index, Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.CameraProcedures == null)
- {
- return;
- }
- ProcedureModel procedure = null;
- foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
- {
- procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == command);
- if (procedure != null) break;
- }
- if (procedure == null || procedure.ToolInfo == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"null"));
- return;
- }
- var tool = procedure.ToolInfo[index];
- callback.Invoke(new Tuple<bool, string>(true, $"{tool.Tool.Number},{tool.Tool.X.ToString("F3")},{tool.Tool.Y.ToString("F3")},{tool.OffsetX.ToString("F3")},{tool.OffsetY.ToString("F3")},{tool.OffsetZ.ToString("F3")},{tool.OffsetU.ToString("F3")}"));
- });
- }
- /// <summary>
- /// 获取流程参数
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetProcedureParam(string command, Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- ProcedureModel procedure = null;
- foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
- {
- procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == command);
- if (procedure != null) break;
- }
- if (procedure == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"null"));
- return;
- }
- callback.Invoke(new Tuple<bool, string>(true, $"{procedure.WaitSuction},{procedure.WaitBlow},{procedure.WaitPhoto}"));
- });
- }
- /// <summary>
- /// 获取指定名称托盘的指定编号的点坐标
- /// </summary>
- /// <param name="callback"></param>
- /// <returns></returns>
- private Task GetPalletPoint(string name, int index, Action<Tuple<bool, string>> callback)
- {
- return Task.Run(() =>
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- var pallet = CurrentProduct.RobotPoint.Pallets.FirstOrDefault(p => p.Name == name);
- if (pallet == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"null"));
- }
- else
- {
- PalletTool palletTool = new PalletTool(pallet);
- StringBuilder sb = new StringBuilder();
- callback.Invoke(new Tuple<bool, string>(true, $"{pallet.Name},{palletTool.Points.Count()},{index},{palletTool.Points[index].X.ToString("F3")},{palletTool.Points[index].Y.ToString("F3")},{palletTool.Points[index].Z.ToString("F3")}," +
- $"{palletTool.Points[index].U.ToString("F3")},{palletTool.Points[index].V.ToString("F3")},{palletTool.Points[index].W.ToString("F3")},{(int)(palletTool.Points[index].Hand)},{palletTool.Points[index].Local},{palletTool.Points[index].Tool}"));
- }
- });
- }
- /// <summary>
- /// 执行Feeder振动集合
- /// </summary>
- /// <param name="feeder"></param>
- /// <param name="works"></param>
- /// <returns></returns>
- public async Task ExecuteFeederWorks(IVoiceCoilMotorFeeder feeder, FeederWorks works, CancellationToken cancellationToken, bool isUpdateParame = true)
- {
- //执行配置的Feeder振动任务
- if (feeder.FeederBrand == FeederBrand.AFAG)
- {
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.ConfigIndex < 0)
- {
- continue;
- }
- if (feederwork.ConfigIndex == 0)
- {
- await Task.Delay(feederwork.Duration);
- }
- else
- {
- ((AfagFeeder)feeder).LoadConfiguration(feederwork.ConfigIndex);
- ((AfagFeeder)feeder).SetIntensity(feederwork.Intensity);
- ((AfagFeeder)feeder).SetDirection(feederwork.Direction);
- await Task.Delay(feederwork.Duration);
- ((AfagFeeder)feeder).SetIntensity(0);
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- return;
- }
- }
- }
- else
- {
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.Function == VibrationFunction.Delay)
- {
- await Task.Delay(feederwork.Duration);
- }
- else
- {
- if (feederwork.SingleAction != null && isUpdateParame)
- {
- await feeder.SetShakeParametersAsync((int)feederwork.Function, feederwork.SingleAction);
- }
- await feeder.StartAction((int)feederwork.Function, feederwork.Duration);
- await Task.Delay(feederwork.Duration);
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- return;
- }
- }
- }
- }
- /// <summary>
- /// 执行Feeder振动集合
- /// </summary>
- /// <param name="feeder"></param>
- /// <param name="works"></param>
- /// <returns></returns>
- public async Task ExecuteFeederWorks(IVoiceCoilMotorFeeder feeder, FeederWorks works, bool isUpdateParame = true)
- {
- //执行配置的Feeder振动任务
- if (feeder.FeederBrand == FeederBrand.AFAG)
- {
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.ConfigIndex < 0)
- {
- continue;
- }
- if (feederwork.ConfigIndex == 0)
- {
- await Task.Delay(feederwork.Duration);
- }
- else
- {
- ((AfagFeeder)feeder).LoadConfiguration(feederwork.ConfigIndex);
- ((AfagFeeder)feeder).SetIntensity(feederwork.Intensity);
- ((AfagFeeder)feeder).SetDirection(feederwork.Direction);
- await Task.Delay(feederwork.Duration);
- ((AfagFeeder)feeder).SetIntensity(0);
- }
- }
- }
- else
- {
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.Function == VibrationFunction.Delay)
- {
- await Task.Delay(feederwork.Duration);
- }
- else
- {
- if (feederwork.SingleAction != null && isUpdateParame)
- {
- await feeder.SetShakeParametersAsync((int)feederwork.Function, feederwork.SingleAction);
- }
- await feeder.StartAction((int)feederwork.Function, feederwork.Duration);
- await Task.Delay(feederwork.Duration);
- }
- }
- }
- }
- /// <summary>
- /// 执行Feeder料仓供料及振动集合
- /// </summary>
- /// <param name="feeder"></param>
- /// <param name="works"></param>
- /// <returns></returns>
- public async Task ExecuteFeederStockWorks(IVoiceCoilMotorFeeder feeder, FeederStockWorks works, bool isUpdateParame = true)
- {
- List<Task> tasks = new List<Task>();
- if (feeder.FeederBrand == FeederBrand.AFAG)
- {
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederStockWorkList != null)
- {
- //执行配置的料仓振动任务
- foreach (var stockwork in works.FeederStockWorkList)
- {
- if (stockwork.RegisterIndex == 0)
- {
- Task.Delay(stockwork.Duration).Wait();
- }
- else if (stockwork.RegisterIndex == 1)
- {
- if (BgModbusTcpCommunicate != null)
- {
- BgModbusTcpCommunicate.Slave.DataStore.HoldingRegisters[stockwork.Address] = 1;
- Thread.Sleep(stockwork.Duration);
- BgModbusTcpCommunicate.Slave.DataStore.HoldingRegisters[stockwork.Address] = 0;
- }
- }
- }
- }
- }));
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederWorkList != null)
- {
- //执行配置的Feeder振动任务
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.ConfigIndex < 0)
- {
- continue;
- }
- if (feederwork.ConfigIndex == 0)
- {
- Thread.Sleep(feederwork.Duration);
- }
- else
- {
- ((AfagFeeder)feeder).LoadConfiguration(feederwork.ConfigIndex);
- ((AfagFeeder)feeder).SetIntensity(feederwork.Intensity);
- ((AfagFeeder)feeder).SetDirection(feederwork.Direction);
- Thread.Sleep(feederwork.Duration);
- ((AfagFeeder)feeder).SetIntensity(0);
- }
- }
- }
- }));
- }
- else
- {
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederStockWorkList != null)
- {
- //执行配置的料仓振动任务
- foreach (var stockwork in works.FeederStockWorkList)
- {
- if (stockwork.Function == VibrationFunction.Delay)
- {
- Task.Delay(stockwork.Duration).Wait();
- }
- else
- {
- feeder.OutputAsync(((int)stockwork.Function) + 1, stockwork.Duration).Wait();
- Thread.Sleep(stockwork.Duration);
- }
- }
- }
- }));
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederWorkList != null)
- {
- //执行配置的Feeder振动任务
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.Function == VibrationFunction.Delay)
- {
- Task.Delay(feederwork.Duration).Wait();
- }
- else
- {
- if (feederwork.SingleAction != null && isUpdateParame)
- {
- feeder.SetShakeParameters((int)feederwork.Function, feederwork.SingleAction);
- }
- feeder.StartAction((int)feederwork.Function, feederwork.Duration).Wait();
- Thread.Sleep(feederwork.Duration);
- }
- }
- }
- }));
- }
- await Task.WhenAll(tasks);
- }
- /// <summary>
- /// 执行Feeder料仓供料及振动集合
- /// </summary>
- /// <param name="feeder"></param>
- /// <param name="works"></param>
- /// <returns></returns>
- public async Task ExecuteFeederStockWorks(IVoiceCoilMotorFeeder feeder, FeederStockWorks works, CancellationToken cancellationToken, bool isUpdateParame = true)
- {
- List<Task> tasks = new List<Task>();
- if (feeder.FeederBrand == FeederBrand.AFAG)
- {
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederStockWorkList != null)
- {
- //执行配置的料仓振动任务
- foreach (var stockwork in works.FeederStockWorkList)
- {
- if (stockwork.RegisterIndex == 0)
- {
- LogHelper.WriteLogDebug($"开启延时:{stockwork.Duration}ms");
- Thread.Sleep(stockwork.Duration);
- LogHelper.WriteLogDebug($"延时结束");
- }
- else if (stockwork.RegisterIndex == 1)
- {
- if (BgModbusTcpCommunicate != null)
- {
- LogHelper.WriteLogDebug($"料仓开始震动:{stockwork.Duration}ms");
- BgModbusTcpCommunicate.Slave.DataStore.HoldingRegisters[stockwork.Address] = 1;
- Thread.Sleep(stockwork.Duration);
- BgModbusTcpCommunicate.Slave.DataStore.HoldingRegisters[stockwork.Address] = 0;
- LogHelper.WriteLogDebug($"料仓停止震动:{stockwork.Duration}ms");
- }
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- return;
- }
- }
- }
- }));
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederWorkList != null)
- {
- //执行配置的Feeder振动任务
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.ConfigIndex < 0)
- {
- continue;
- }
- if (feederwork.ConfigIndex == 0)
- {
- Thread.Sleep(feederwork.Duration);
- }
- else
- {
- ((AfagFeeder)feeder).LoadConfiguration(feederwork.ConfigIndex);
- ((AfagFeeder)feeder).SetIntensity(feederwork.Intensity);
- ((AfagFeeder)feeder).SetDirection(feederwork.Direction);
- Thread.Sleep(feederwork.Duration);
- ((AfagFeeder)feeder).SetIntensity(0);
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- return;
- }
- }
- }
- }));
- }
- else
- {
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederStockWorkList != null)
- {
- //执行配置的料仓振动任务
- foreach (var stockwork in works.FeederStockWorkList)
- {
- if (stockwork.Function == VibrationFunction.Delay)
- {
- Task.Delay(stockwork.Duration).Wait();
- }
- else
- {
- feeder.OutputAsync(((int)stockwork.Function) + 1, stockwork.Duration).Wait();
- Thread.Sleep(stockwork.Duration);
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- return;
- }
- }
- }
- }));
- tasks.Add(Task.Run(() =>
- {
- if (works != null && works.FeederWorkList != null)
- {
- //执行配置的Feeder振动任务
- foreach (var feederwork in works.FeederWorkList)
- {
- if (feederwork.Function == VibrationFunction.Delay)
- {
- Task.Delay(feederwork.Duration).Wait();
- }
- else
- {
- if (feederwork.SingleAction != null && isUpdateParame)
- {
- feeder.SetShakeParameters((int)feederwork.Function, feederwork.SingleAction);
- }
- feeder.StartAction((int)feederwork.Function, feederwork.Duration).Wait();
- Thread.Sleep(feederwork.Duration);
- }
- if (cancellationToken != null && cancellationToken.IsCancellationRequested)
- {
- return;
- }
- }
- }
- }));
- }
- await Task.WhenAll(tasks);
- }
- /// <summary>
- /// 执行计时器
- /// </summary>
- /// <param name="state"></param>
- /// <param name="callback"></param>
- public void ExecuteCycleTime(string state, Action<Tuple<bool, string>> callback)
- {
- if (int.Parse(state) == 1)
- {
- IsStart = true;
- StartTime = DateTime.Now;
- callback.Invoke(new Tuple<bool, string>(true, $"1"));
- }
- else
- {
- IsStart = false;
- callback.Invoke(new Tuple<bool, string>(true, $"0"));
- }
- }
- /// <summary>
- /// 生产计数
- /// </summary>
- /// <param name="_Content"></param>
- /// <param name="callback"></param>
- public void AddProductionRecords(string _Content, Action<Tuple<bool, string>> callback)
- {
- DatabaseHelper.AddProductProductionRecords(CurrentProduct.Name, _Content);
- callback.Invoke(new Tuple<bool, string>(true, _Content));
- }
- /// <summary>
- /// 获取产品的全局参数
- /// </summary>
- /// <param name="ParamName"></param>
- /// <param name="index"></param>
- /// <param name="callback"></param>
- public void GetGlobalParam(string ParamName, int index, Action<Tuple<bool, string>> callback)
- {
- if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
- {
- return;
- }
- var pos = CurrentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == ParamName);
- if (pos == null)
- {
- callback.Invoke(new Tuple<bool, string>(true, $"null"));
- }
- else
- {
- switch (index)
- {
- case 1:
- callback.Invoke(new Tuple<bool, string>(true, $"{pos.Name},{pos.Param1}"));
- break;
- case 2:
- callback.Invoke(new Tuple<bool, string>(true, $"{pos.Name},{pos.Param2}"));
- break;
- case 3:
- callback.Invoke(new Tuple<bool, string>(true, $"{pos.Name},{pos.Param3}"));
- break;
- case 4:
- callback.Invoke(new Tuple<bool, string>(true, $"{pos.Name},{pos.Param4}"));
- break;
- default:
- callback.Invoke(new Tuple<bool, string>(true, $"{pos.Name},{pos.Param1},{pos.Param2},{pos.Param3},{pos.Param4}"));
- break;
- }
- }
- }
- #endregion
- #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 = DeviceConfig.Robots.FirstOrDefault(ro => ro.Id == robotid);
- SendTaskMessage($"{r.RobotName}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 = DeviceConfig.Robots.FirstOrDefault(ro => ro.Id == robotid);
- if (r.ConnectType == TCPConnectType.Server)
- {
- ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
- SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
- var robot = this.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 = DeviceConfig.Robots.FirstOrDefault(ro => ro.Id == robotid);
- if (r.ConnectType == TCPConnectType.Server)
- {
- ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
- SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
- var robot = this.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="arg1"></param>
- /// <param name="arg2"></param>
- /// <param name="arg3"></param>
- /// <exception cref="NotImplementedException"></exception>
- private void Management_FeederDisconnectedEvent(Guid feederid, ITcpClient arg2, ClosedEventArgs arg3)
- {
- var f = DeviceConfig.Feeders.FirstOrDefault(ro => ro.Id == feederid);
- var sta = Status.FirstOrDefault(s => s.ID == feederid);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{f.FeederName}{Lang.未连接}";
- sta.Background = new SolidColorBrush(Colors.Red);
- }));
- SendTaskMessage($"{f.FeederName}{Lang.断开连接}!", MessageLevel.Error);
- }
- /// <summary>
- /// Feeder连接成功时
- /// </summary>
- /// <param name="arg1"></param>
- /// <param name="arg2"></param>
- /// <param name="arg3"></param>
- /// <exception cref="NotImplementedException"></exception>
- private void Management_FeederConnectedEvent(Guid feederid, ITcpClient arg2, ConnectedEventArgs arg3)
- {
- var f = DeviceConfig.Feeders.FirstOrDefault(ro => ro.Id == feederid);
- var sta = Status.FirstOrDefault(s => s.ID == feederid);
- App.Current.Dispatcher.Invoke(new
- Action(() =>
- {
- sta.Message = $"{f.FeederName}{Lang.已连接}";
- sta.Background = new SolidColorBrush(Colors.Green);
- }));
- SendTaskMessage($"{f.FeederName}{Lang.已连接}!", MessageLevel.Debug);
- }
- /// <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 = DeviceConfig.Cameras.FirstOrDefault(c => c.Id == 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 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);
- }));
- }
- 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);
- }));
- }
- }
- #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);
- Task.Run(async () =>
- {
- try
- {
- await ExecuteRemoteCommand(msg, async result =>
- {
- try
- {
- if (!client.Online)
- {
- return;
- }
- if (result.Item1)
- {
- if (result.Item2.Length > 1)
- {
- foreach (var item in result.Item2)
- {
- await BgCommunicate.SendAsync(client, $"{item}");
- await Task.Delay(10);
- }
- }
- else
- {
- await BgCommunicate.SendAsync(client, $"{result.Item2[0]}");
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("后台TCP发送数据时出错!", ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- }, BgCommunicateollection[client.Id].Token);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("处理后台服务器接收的命令时出错!", ex);
- SendTaskMessage(ex.Message, MessageLevel.Alarm);
- }
- });
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogError("处理后台服务器接收的命令时出错!", 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);
- }
- #endregion
- #region Eip
- private void DisposeRfidClient()
- {
- try
- {
- if (BgEipCommunicate != null)
- {
- BgEipCommunicate.OnTagDataReceived -= RfidClient_OnTagDataReceived;
- BgEipCommunicate.OnConnectReceive -= Management_EipConnectChangedEvent;
- BgEipCommunicate.Dispose();
- }
- UpdateEthernetIpStatus(false);
- }
- catch { /* ignore */ }
- finally
- {
- BgEipCommunicate = null;
-
- }
- }
- private void RfidClient_OnTagDataReceived(object sender, RFIDTagDataEventArgs e)
- {
- if (e == null || e.Tags == null || e.Tags.Count == 0)
- return;
- foreach (var tag in e.Tags)
- {
- lock (_sync)
- _lastRfidTag = CloneTag(tag);
- SendTaskMessage("RFID 端口" + tag.Port + " Hex=" + tag.ToHexString(), MessageLevel.Debug);
- }
- }
- private void StopHandshakeLoop()
- {
- try
- {
- if (_handshakeCts != null)
- {
- _handshakeCts.Cancel();
- try
- {
- if (_handshakeTask != null)
- _handshakeTask.Wait(2000);
- }
- catch (AggregateException) { /* ignore */ }
- _handshakeCts.Dispose();
- }
- }
- catch { /* ignore */ }
- finally
- {
- _handshakeCts = null;
- _handshakeTask = null;
- }
- }
- #endregion
- #region 方法
- private void SendTaskMessage(string msg, MessageLevel level)
- {
- _eventAggregator.GetEvent<TaskMessageNotification>().Publish(new Models.MessageStruct() { Message = msg, level = level });
- }
- private void DoCycleTime(object state)
- {
- if (IsStart)
- {
- App.Current.Dispatcher.Invoke(new Action(() =>
- {
- CT = DateTime.Now - StartTime;
- }));
- }
- }
- private void DoYieldTime(object state)
- {
- if (CurrentProduct == null) return;
- TotalQuantity = DatabaseHelper.GetTotalQuantity(CurrentProduct.Name);
- TotalQuantityToday = DatabaseHelper.GetTotalQuantityToday(CurrentProduct.Name);
- CurrentUPH = DatabaseHelper.GetUPH(CurrentProduct.Name);
- }
- #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($"杀死进程:{strKillName}时失败!", ex);
- }
- }
- }
- }
- #endregion
- #endregion
- }
- }
|