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