Measure.cs 20 KB

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