Measure.cs 20 KB

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