Measure.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. //时间:20200610
  2. //作者:郝爽
  3. //功能:测量线程
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using SmartSEMControl;
  10. using MeasureData;
  11. namespace MeasureThread
  12. {
  13. public enum ImageMode
  14. {
  15. FIB,
  16. SEM
  17. }
  18. //层间通讯数据包
  19. public struct ST_MSTMsg
  20. {
  21. //线程状态
  22. public struct STMThreadStatus
  23. {
  24. public int iMThreadStatus;
  25. public string cMsrStartTime;
  26. public string cMsrEndTime;
  27. };
  28. //切孔状态
  29. public struct STMSampleStatus
  30. {
  31. public int iMeasureSampleStatus;
  32. public string cSampleName;
  33. };
  34. public STMThreadStatus STMThreadStu;
  35. public STMSampleStatus STMSampleStu;
  36. };
  37. public class Measure
  38. {
  39. public delegate void ProgressEventHandler(ST_MSTMsg msg);
  40. public event ProgressEventHandler ProgressEvent;
  41. //全局只有一个fatorySEM
  42. static FactoryHardware factorySEM = FactoryHardware.Instance;
  43. ISEMControl iSEM = factorySEM.ISEM;
  44. const String ImageName1 = @"ImageSEM600X.tif"; //传给客户,作水平校正
  45. const String ImageName2 = @"ImageFIB600X1.tif";//传给客户,找到切割点
  46. const String ImageName3 = @"ImageFIB600X2.tif";
  47. const String ImageName4 = @"ImageSEM300X.tif";//传给客户,找到已经切割点
  48. const String ImageName5 = @"ImageSEM6000X.tif";//传给客户,水平校正
  49. const String ImageName6 = @"ImageSEMMag.tif";//传给客户,测量层高
  50. const float fMin = (float)0.0000002; //单位是米
  51. //测量文件
  52. private MeasureFile m_measureFile;
  53. public MeasureFile MeasureFile
  54. {
  55. get { return this.m_measureFile; }
  56. set { this.m_measureFile = value; }
  57. }
  58. //测量的切割孔
  59. private List<MeasureData.CutHole> m_cutHoles;
  60. public List<MeasureData.CutHole> cutHoles
  61. {
  62. get { return this.m_cutHoles; }
  63. set { this.m_cutHoles = value; }
  64. }
  65. //工作文件夹
  66. private string m_WorkingFolder;
  67. public string WorkingFolder
  68. {
  69. get { return this.m_WorkingFolder; }
  70. set { this.m_WorkingFolder = value; }
  71. }
  72. //线程状态
  73. private ThreadStatus m_ThreadStatus;
  74. public ThreadStatus TStatus
  75. {
  76. get { return this.m_ThreadStatus; }
  77. set { this.m_ThreadStatus = value; }
  78. }
  79. //测量参数
  80. private MeasureParam m_MsParam;
  81. public MeasureParam MeasParam
  82. {
  83. get { return this.m_MsParam; }
  84. set { this.m_MsParam = value; }
  85. }
  86. //构造函数
  87. public Measure()
  88. {
  89. Init();
  90. }
  91. private void Init()
  92. {
  93. MeasParam = new MeasureParam();
  94. TStatus = new ThreadStatus();
  95. cutHoles = new List<MeasureData.CutHole>();
  96. }
  97. //初始化测量业务, 读测量文件,判断是否有可测试的切孔
  98. public bool InitMeas(MeasureFile a_measureFile)
  99. {
  100. m_measureFile = a_measureFile;
  101. List<CutHole> listHoles = m_measureFile.ListCutHole;
  102. foreach (CutHole h in listHoles )
  103. {
  104. if (h.SWITCH == true)
  105. {
  106. m_cutHoles.Add(h);
  107. }
  108. }
  109. if(m_cutHoles.Count == 0)
  110. return false;
  111. this.m_MsParam = m_measureFile.MParam;
  112. return true;
  113. }
  114. //测量流程
  115. public void DoMeasure()
  116. {
  117. //创建线程的测量状态的更新
  118. this.TStatus.ComputeTime(THREAD_TIME_TYPE.START);
  119. //将这个开始时间传递给主界面
  120. //检查硬件连接是否正常
  121. if (!ConnectHardware())
  122. {
  123. this.TStatus.ComputeTime(THREAD_TIME_TYPE.STOPPED);
  124. return;
  125. }
  126. //设置工作文件夹
  127. if (!SetWorkingFolderStr())
  128. {
  129. this.TStatus.ComputeTime(THREAD_TIME_TYPE.STOPPED);
  130. return;
  131. }
  132. float[] firstPosition;
  133. for (int i = 0; i < m_cutHoles.Count; i++)
  134. {
  135. if (i == 0)
  136. {
  137. firstPosition = iSEM.GetStagePosition();
  138. }
  139. else
  140. {
  141. }
  142. }
  143. //第一个孔的测试
  144. FirstHole();
  145. //非第一个孔的测试
  146. OtherHole();
  147. }
  148. //检查硬件连接是否正常
  149. public bool ConnectHardware()
  150. {
  151. //返回硬件的连接状态
  152. return iSEM.ConnectStatus();
  153. }
  154. //设置工作文件夹
  155. public bool SetWorkingFolderStr()
  156. {
  157. //获取工作文件路径
  158. string pathName = m_measureFile.FilePath;
  159. //判断工作文件路径是否为空或无效
  160. if (string.IsNullOrEmpty(pathName))
  161. {
  162. return false;
  163. }
  164. //文件未保存
  165. else if (pathName.CompareTo(MeasureFile.UNTITLED_FILE_NAME) == 0)
  166. {
  167. return false;
  168. }
  169. //获取工作文件所在文件夹
  170. string folder = System.IO.Path.GetDirectoryName(pathName);
  171. if (string.IsNullOrEmpty(folder))
  172. {
  173. return false;
  174. }
  175. WorkingFolder += @"\\";
  176. return false;
  177. }
  178. //第一个孔的测试过程
  179. public bool FirstHole()
  180. {
  181. MeasureData.CutHole firstHole = m_cutHoles[0];
  182. //12.根据样品类型参数确定是否需要PT沉积,控制PT针插入
  183. //if (firstHole.PT == true)
  184. //{
  185. // if (!iSEM.InsertPT())
  186. // {
  187. // return false;
  188. // }
  189. //}
  190. //13.自动定位切割
  191. {
  192. //1.控制SEM放大600X
  193. if (!iSEM.SetMagnification(600))
  194. {
  195. return false;
  196. }
  197. //2.控制SEM自动对焦、亮度、对比度
  198. if (!MeasParam.FocusMode)
  199. {
  200. //弹出手动对焦的窗口
  201. }
  202. else
  203. {
  204. //调用自动对焦模块
  205. }
  206. //3.设置SEM进行角度补偿54度
  207. if (!TiltCorrection(54))
  208. {
  209. return false;
  210. }
  211. //4.控制SEM拍照
  212. //5.保存照片
  213. {
  214. //1. 创建目录,已经完成
  215. //2. 设置图片名称
  216. //3. 保存图片1
  217. String fileName1 = WorkingFolder + ImageName1;
  218. if (!GetImage(ImageMode.SEM, fileName1))
  219. {
  220. return false;
  221. }
  222. }
  223. //6.设置FIB拍照参数——扫描时间、束流等
  224. //7.控制FIB自动亮度、对比度
  225. //8.控制FIB拍照
  226. //9.保存照片
  227. {
  228. //1. 设置图片名称
  229. //2. 保存图片2
  230. String fileName2 = WorkingFolder + ImageName2;
  231. if (!GetImage(ImageMode.FIB, fileName2))
  232. {
  233. return false;
  234. }
  235. }
  236. //10.将照片传给客户,返回梯形位置坐标,及样品类型参数(是否需要PT沉积,PT坐标位置,PT宽度、PT高度、梯形上、下边及深度、扫描时间、束流、样品放大倍数1、样品放大倍数2等切割参数)
  237. //11.自动工具样品类型参数确定是否需要PT沉积
  238. {
  239. //1. 根据客户PT沉积坐标控制FIB调整到中心位置
  240. //2. 验证移动准确性:获取当前FIB中心位置坐标,与客户返回坐标对比,验证是否一定正确
  241. //3. 根据坐标进行PT沉积
  242. }
  243. //模拟为客户返回的坐标值
  244. float x0 = 0, y0 = 0;
  245. //12.根据梯形坐标控制FIB调整到中心位置
  246. if (!iSEM.MoveStageXY(x0, y0))
  247. {
  248. return false;
  249. }
  250. //13.验证移动准确性:获取当前FIB中心位置坐标,与客户返回坐标对比,验证是否移动正确
  251. float x1 = iSEM.GetStageAtX();
  252. float y1 = iSEM.GetStageAtY();
  253. if (Math.Abs(x0 - x1) > fMin && Math.Abs(y0 - y1) > fMin)
  254. {
  255. return false;
  256. }
  257. //14.保存样品1第1号孔中心位置6轴坐标1 XYZMRT到数据库,保存客户返回值信息到数据库
  258. float[] firstPosition = iSEM.GetStagePosition();
  259. }
  260. //14.自动控制FIB切割
  261. {
  262. //1.根据参数设置FIB草率时间(使图清晰),设置梯形上下边及深度、设置束流
  263. //2.控制FIB进行切割
  264. //3.控制FIB拍照600X
  265. //4.保存图片
  266. {
  267. //1.设置图片名称
  268. //2.保存图片3
  269. String fileName3 = WorkingFolder + ImageName3;
  270. if (!GetImage(ImageMode.FIB, fileName3))
  271. {
  272. return false;
  273. }
  274. }
  275. //5.验证切割准确性:与切割前对比,如果对比误差大,则停止自动执行,进行报警
  276. //6.设置FIB解冻:先读取状态,如果冻结状态则进行解冻
  277. }
  278. //15.根据样品类型决定是否撤出PT针
  279. //if (firstHole.PT == false)
  280. //{
  281. // if (!iSEM.OutputPT())
  282. // {
  283. // return false;
  284. // }
  285. //}
  286. //16.自动调整SEM找到切割位置
  287. {
  288. //1.控制SEM放大到300倍
  289. if (!iSEM.SetMagnification(300))
  290. {
  291. return false;
  292. }
  293. //2.控制SEM自动对焦、亮度、对比度-接口
  294. if (!MeasParam.FocusMode)
  295. {
  296. //弹出手动对焦的窗口
  297. }
  298. else
  299. {
  300. //调用自动对焦模块
  301. }
  302. //3.控制SEM拍照
  303. String fileName4 = WorkingFolder + ImageName4;
  304. if (!GetImage(ImageMode.SEM, fileName4))
  305. {
  306. return false;
  307. }
  308. //4.将照片传给客户,获取偏移坐标,以及偏移角度
  309. float x4 = 0, y4 = 0;
  310. float angle = 0;
  311. //5.根据坐标控制SEM移动到切孔位置,居中
  312. if (!iSEM.MoveStageXY(x4, y4))
  313. {
  314. return false;
  315. }
  316. if (!iSEM.SetScanRotation(angle))
  317. {
  318. return false;
  319. }
  320. //6.验证移动准确性:获取当前SEM中心位置坐标,与客户返回坐标对比,验证是否移动正确
  321. float x5 = iSEM.GetStageAtX();
  322. float y5 = iSEM.GetStageAtY();
  323. if (Math.Abs(x5 - x4) > fMin && Math.Abs(y5 - y4) > fMin)
  324. {
  325. return false;
  326. }
  327. }
  328. //17.自动控制SEM拍截面照
  329. {
  330. //1.控制SEM放大到指定参数大小范围,6000x
  331. if (!iSEM.SetMagnification(6000))
  332. {
  333. return false;
  334. }
  335. //2.控制SEM自动对焦、消像散、亮度、对比度
  336. if (!MeasParam.FocusMode)
  337. {
  338. //弹出手动对焦的窗口
  339. }
  340. else
  341. {
  342. //调用自动对焦模块
  343. }
  344. //3.设置SEM角度补偿cos36度
  345. if (!TiltCorrection(36))
  346. {
  347. return false;
  348. }
  349. //4.控制SEM拍照
  350. //5.保存照片4
  351. String fileName5 = WorkingFolder + ImageName5;
  352. if (!GetImage(ImageMode.SEM, fileName5))
  353. {
  354. return false;
  355. }
  356. //6.将照片传给客户,获取偏移坐标
  357. float x6 = 0, y6 = 0;
  358. float angle1 = 0;
  359. float mage = 10000;
  360. //7.根据坐标控制SEM移动到分析位置
  361. if (!iSEM.MoveStageXY(x6, y6))
  362. {
  363. return false;
  364. }
  365. //8.验证移动准确性:获取当前SEM中心位置坐标,与客户返回坐标对比,验证是否移动正确
  366. float x7 = iSEM.GetStageAtX();
  367. float y7 = iSEM.GetStageAtY();
  368. if (Math.Abs(x6 - x7) > fMin && Math.Abs(y6 - y7) > fMin)
  369. {
  370. return false;
  371. }
  372. //9.控制SEM平行校正,并记录校正前初始值
  373. float foldAnagle = iSEM.GetScanRotation();
  374. if (foldAnagle == float.NaN)
  375. {
  376. return false;
  377. }
  378. if (!iSEM.SetScanRotation(angle1))
  379. {
  380. return false;
  381. }
  382. //10.控制SEM放大到指定参数大小范围
  383. if (!iSEM.SetMagnification(mage))
  384. {
  385. return false;
  386. }
  387. //11.控制SEM自动对焦、消像散、亮度、对比度
  388. if (!MeasParam.FocusMode)
  389. {
  390. //弹出手动对焦的窗口
  391. }
  392. else
  393. {
  394. //调用自动对焦模块
  395. }
  396. //12.控制SEM对分析位置拍照
  397. String fileName6 = WorkingFolder + ImageName6;
  398. if (!GetImage(ImageMode.SEM, fileName6))
  399. {
  400. return false;
  401. }
  402. //13.保存照片
  403. //14.控制SEM取消电子束校正,回到初始值
  404. if (!iSEM.SetScanRotation(foldAnagle))
  405. {
  406. return false;
  407. }
  408. }
  409. //18.自动层高分析
  410. {
  411. //1.获取SEM Pixel Size给客户传入参数
  412. if (iSEM.GetPixelSize() == float.NaN)
  413. {
  414. return false;
  415. }
  416. //2.将照片传给客户,客户进行层高分析(返回分析后的图像、相对坐标、分辨率、各层编号以及各层对应的层高数据),如果客户自行出分析报告则无需返回数据
  417. }
  418. //19.自动能谱分析
  419. {
  420. //1. 确定能谱位置
  421. //2. 控制牛津打能谱
  422. //3. 能谱分析——面扫+线扫描
  423. }
  424. return true;
  425. }
  426. //非第一个孔的测试过程
  427. public void OtherHole()
  428. {
  429. for (int i = 1; i < m_cutHoles.Count; i++)
  430. {
  431. CutHole currentHole = m_cutHoles[i];
  432. //1. 初始化
  433. {
  434. //1. 设置FIB解冻:先读取状态,如果冻结则进行解冻
  435. //读取图像冻结状态
  436. float ffrozen = iSEM.GetImageFrozen();
  437. if (ffrozen == float.NaN)
  438. {
  439. return;
  440. }
  441. //2. 调节样品1号孔的样品台6轴坐标
  442. //3. 将样品1号孔坐标2存入数据库
  443. //4. 控制样品台T轴归0,R轴变为坐标1、Z/M轴作为坐标2保存不变
  444. if (!iSEM.SetStageGotoT(0))
  445. {
  446. return;
  447. }
  448. //5. 获取光镜2号孔XY坐标
  449. //6. 根据光镜坐标控制样品台移动
  450. //7. 控制样品台,调整T轴54度、M/Z/R轴不变
  451. }
  452. //2. 定位切割
  453. {
  454. //1. 拉直操作
  455. {
  456. //1.1 控制SEM进行拍照
  457. //1.2 图片传给客户,返回偏移角度
  458. //1.3 根据返回角度,控制样品台转动
  459. }
  460. //2. 与1号孔13步相同
  461. }
  462. //3. 以后步骤与1号孔以后步骤一致
  463. }
  464. }
  465. //角度补偿
  466. public bool TiltCorrection(float a_fAngle)
  467. {
  468. //记录原来电镜的状态
  469. bool bTilt = false;
  470. float fOldTilt = iSEM.GetTiltCorrection();
  471. if (fOldTilt == float.NaN)
  472. {
  473. return false;
  474. }
  475. else if (fOldTilt == 1)
  476. {
  477. bTilt = true;
  478. }
  479. else if (fOldTilt == 0)
  480. {
  481. bTilt = false;
  482. }
  483. float fOldAngle = iSEM.GetTiltAngle();
  484. if (fOldAngle == float.NaN)
  485. {
  486. return false;
  487. }
  488. //开启校正
  489. if (!iSEM.SetTiltCorrectionOn())
  490. {
  491. return false;
  492. }
  493. //设置校正角度
  494. if (!iSEM.SetTiltAngle(fOldAngle))
  495. {
  496. return false;
  497. }
  498. //恢复原始状态
  499. if (!iSEM.SetTiltAngle(a_fAngle))
  500. {
  501. return false;
  502. }
  503. if (bTilt)
  504. {
  505. if (!iSEM.SetTiltCorrectionOn())
  506. {
  507. return false;
  508. }
  509. }
  510. else
  511. {
  512. if (!iSEM.SetTiltCorrectionOff())
  513. {
  514. return false;
  515. }
  516. }
  517. return true;
  518. }
  519. //拍图
  520. public bool GetImage(ImageMode a_mode, String a_fileName)
  521. {
  522. //1. 图像解冻
  523. float foldFrozen = iSEM.GetImageFrozen();
  524. if (foldFrozen == float.NaN)
  525. {
  526. return false;
  527. }
  528. if (!iSEM.ImageLive())
  529. {
  530. return false;
  531. }
  532. //2. 确认图像模式
  533. if (ImageMode.SEM == a_mode)
  534. {
  535. if (!iSEM.CmdFIBModeSEM())
  536. {
  537. return false;
  538. }
  539. }
  540. else if (ImageMode.FIB == a_mode)
  541. {
  542. if (!iSEM.CmdFIBModeFIB())
  543. {
  544. return false;
  545. }
  546. }
  547. else
  548. {
  549. return false;
  550. }
  551. //3. 获取分辨率
  552. int[] ImageSize = iSEM.GetImageStore();
  553. if (ImageSize[0] == 0 || ImageSize[1] == 0)
  554. {
  555. return false;
  556. }
  557. short width = (short)ImageSize[0];
  558. short height = (short)ImageSize[1];
  559. //4. 抓图
  560. if (!iSEM.GrabImage(a_fileName, 0, 0, width, height, 0))
  561. {
  562. return false;
  563. }
  564. //5. 恢复初始状态
  565. if (foldFrozen == 0)
  566. {
  567. if (!iSEM.ImageLive())
  568. {
  569. return false;
  570. }
  571. }
  572. else if (foldFrozen == 1)
  573. {
  574. if (!iSEM.ImageFrozen())
  575. {
  576. return false;
  577. }
  578. }
  579. return true;
  580. }
  581. }
  582. }