AtmRobot.xaml.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. using MECF.Framework.Common.CommonData;
  2. using OpenSEMI.ClientBase;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.ComponentModel;
  6. using System.Linq;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Animation;
  12. using VirgoUI.Controls.Common;
  13. namespace VirgoUI.Client.Models.Controls
  14. {
  15. /// <summary>
  16. /// AtmRobot.xaml 的交互逻辑
  17. /// </summary>
  18. public partial class AtmRobot : UserControl, INotifyPropertyChanged
  19. {
  20. private int moveTime = 300;
  21. private const int AnimationTimeout = 3000; // ms
  22. private string CurrentPosition
  23. {
  24. get; set;
  25. }
  26. private RobotAction CurrentAction
  27. {
  28. get; set;
  29. }
  30. public int MoveTime
  31. {
  32. get => moveTime;
  33. set
  34. {
  35. moveTime = value;
  36. }
  37. }
  38. // Using a DependencyProperty as the backing store for RotateAngel. This enables animation, styling, binding, etc...
  39. public static readonly DependencyProperty RotateAngleProperty =
  40. DependencyProperty.Register("RotateAngel", typeof(int), typeof(AtmRobot), new PropertyMetadata(0));
  41. public int TranslateX
  42. {
  43. get { return (int)GetValue(TranslateXProperty); }
  44. set { SetValue(TranslateXProperty, value); }
  45. }
  46. // Using a DependencyProperty as the backing store for TranslateX. This enables animation, styling, binding, etc...
  47. public static readonly DependencyProperty TranslateXProperty =
  48. DependencyProperty.Register("TranslateX", typeof(int), typeof(AtmRobot), new PropertyMetadata(0));
  49. public WaferInfo Wafer1
  50. {
  51. get { return ( WaferInfo)GetValue(Wafer1Property); }
  52. set { SetValue(Wafer1Property, value); }
  53. }
  54. // Using a DependencyProperty as the backing store for Wafer1. This enables animation, styling, binding, etc...
  55. public static readonly DependencyProperty Wafer1Property =
  56. DependencyProperty.Register("Wafer1", typeof( WaferInfo), typeof(AtmRobot), new PropertyMetadata(null));
  57. public WaferInfo Wafer2
  58. {
  59. get { return ( WaferInfo)GetValue(Wafer2Property); }
  60. set { SetValue(Wafer2Property, value); }
  61. }
  62. // Using a DependencyProperty as the backing store for Wafer2. This enables animation, styling, binding, etc...
  63. public static readonly DependencyProperty Wafer2Property =
  64. DependencyProperty.Register("Wafer2", typeof( WaferInfo), typeof(AtmRobot), new PropertyMetadata(null));
  65. public string Station
  66. {
  67. get { return (string)GetValue(StationProperty); }
  68. set { SetValue(StationProperty, value); }
  69. }
  70. // Using a DependencyProperty as the backing store for Station. This enables animation, styling, binding, etc...
  71. public static readonly DependencyProperty StationProperty =
  72. DependencyProperty.Register("Station", typeof(string), typeof(AtmRobot), new PropertyMetadata("Robot"));
  73. public RobotMoveInfo RobotMoveInfo
  74. {
  75. get { return (RobotMoveInfo)GetValue(RobotMoveInfoProperty); }
  76. set { SetValue(RobotMoveInfoProperty, value); }
  77. }
  78. public static readonly DependencyProperty RobotMoveInfoProperty =
  79. DependencyProperty.Register("RobotMoveInfo", typeof(RobotMoveInfo), typeof(AtmRobot), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
  80. public bool WaferPresentA
  81. {
  82. get { return (bool)GetValue(WaferPresentAProperty); }
  83. set { SetValue(WaferPresentAProperty, value); }
  84. }
  85. // Using a DependencyProperty as the backing store for WaferPresent. This enables animation, styling, binding, etc...
  86. public static readonly DependencyProperty WaferPresentAProperty =
  87. DependencyProperty.Register("WaferPresentA", typeof(bool), typeof(AtmRobot), new PropertyMetadata(false));
  88. public bool WaferPresentB
  89. {
  90. get { return (bool)GetValue(WaferPresentBProperty); }
  91. set { SetValue(WaferPresentBProperty, value); }
  92. }
  93. // Using a DependencyProperty as the backing store for WaferPresent. This enables animation, styling, binding, etc...
  94. public static readonly DependencyProperty WaferPresentBProperty =
  95. DependencyProperty.Register("WaferPresentB", typeof(bool), typeof(AtmRobot), new PropertyMetadata(false));
  96. public ICommand CreateDeleteWaferCommand
  97. {
  98. get { return (ICommand)GetValue(CreateDeleteWaferCommandProperty); }
  99. set { SetValue(CreateDeleteWaferCommandProperty, value); }
  100. }
  101. // Using a DependencyProperty as the backing store for CreateDeleteWaferCommand. This enables animation, styling, binding, etc...
  102. public static readonly DependencyProperty CreateDeleteWaferCommandProperty =
  103. DependencyProperty.Register("CreateDeleteWaferCommand", typeof(ICommand), typeof(AtmRobot), new PropertyMetadata(null));
  104. public ICommand MoveWaferCommand
  105. {
  106. get { return (ICommand)GetValue(MoveWaferCommandProperty); }
  107. set { SetValue(MoveWaferCommandProperty, value); }
  108. }
  109. // Using a DependencyProperty as the backing store for MoveWaferCommand. This enables animation, styling, binding, etc...
  110. public static readonly DependencyProperty MoveWaferCommandProperty =
  111. DependencyProperty.Register("MoveWaferCommand", typeof(ICommand), typeof(AtmRobot), new PropertyMetadata(null));
  112. public Dictionary<string, StationPosition> StationPosition
  113. {
  114. get { return (Dictionary<string, StationPosition>)GetValue(StationPositionProperty); }
  115. set { SetValue(StationPositionProperty, value); }
  116. }
  117. // Using a DependencyProperty as the backing store for StationPosition. This enables animation, styling, binding, etc...
  118. public static readonly DependencyProperty StationPositionProperty =
  119. DependencyProperty.Register("StationPosition", typeof(Dictionary<string, StationPosition>), typeof(AtmRobot), new PropertyMetadata(null, StationPositionChangedCallback));
  120. private List<MenuItem> menu;
  121. public event PropertyChangedEventHandler PropertyChanged;
  122. public List<MenuItem> Menu
  123. {
  124. get
  125. {
  126. return menu;
  127. }
  128. set
  129. {
  130. menu = value;
  131. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Menu"));
  132. }
  133. }
  134. private ICommand MoveCommand
  135. {
  136. get; set;
  137. }
  138. private void MoveTo(object target)
  139. {
  140. MoveRobot((RobotMoveInfo)target);
  141. }
  142. public AtmRobot()
  143. {
  144. InitializeComponent();
  145. root.DataContext = this;
  146. CurrentPosition = "ArmA.System";
  147. MoveCommand = new RelayCommand(MoveTo);
  148. StationPosition = new Dictionary<string, StationPosition>
  149. {
  150. { "ArmA.System",new StationPosition()
  151. {
  152. StartPosition= new RobotPosition()
  153. {
  154. X=0,
  155. Root=145,
  156. Arm= 240,
  157. Hand=244
  158. },
  159. EndPosition= new RobotPosition()
  160. {
  161. Root=145,
  162. Arm= 240,
  163. Hand=244
  164. }
  165. }
  166. },
  167. { "ArmB.System",new StationPosition()
  168. {
  169. StartPosition= new RobotPosition()
  170. {
  171. X=0,
  172. Root=035,
  173. Arm= 120,
  174. Hand=474
  175. },
  176. EndPosition= new RobotPosition()
  177. {
  178. Root=035,
  179. Arm= 120,
  180. Hand=474
  181. }
  182. }
  183. },
  184. { "ArmA.LP1",new StationPosition()
  185. {
  186. StartPosition= new RobotPosition()
  187. {
  188. X=0,
  189. Root=145,
  190. Arm= 240,
  191. Hand=244
  192. },
  193. EndPosition= new RobotPosition()
  194. {
  195. Root=133,
  196. Arm=278,
  197. Hand=38
  198. }
  199. }
  200. },
  201. { "ArmB.LP1",new StationPosition()
  202. {
  203. StartPosition= new RobotPosition()
  204. {
  205. X=0,
  206. Root=035,
  207. Arm= 120,
  208. Hand=474
  209. },
  210. EndPosition= new RobotPosition()
  211. {
  212. Root=58,
  213. Arm=82,
  214. Hand=310
  215. }
  216. }
  217. } ,
  218. { "ArmA.Cooling1",new StationPosition()
  219. {
  220. StartPosition= new RobotPosition()
  221. {
  222. X=0,
  223. Root=145,
  224. Arm= 240,
  225. Hand=244
  226. },
  227. EndPosition= new RobotPosition()
  228. {
  229. Root=172,
  230. Arm=271,
  231. Hand=97
  232. }
  233. }
  234. },
  235. { "ArmB.Cooling1",new StationPosition()
  236. {
  237. StartPosition= new RobotPosition()
  238. {
  239. X=0,
  240. Root=035,
  241. Arm= 120,
  242. Hand=474
  243. },
  244. EndPosition= new RobotPosition()
  245. {
  246. Root=177,
  247. Arm=282,
  248. Hand=83
  249. }
  250. }
  251. },
  252. { "ArmA.PMA",new StationPosition()
  253. {
  254. StartPosition= new RobotPosition()
  255. {
  256. X=0,
  257. Root=145,
  258. Arm= 240,
  259. Hand=244
  260. },
  261. EndPosition= new RobotPosition()
  262. {
  263. Root=233,
  264. Arm=77,
  265. Hand=-37
  266. }
  267. }
  268. },
  269. { "ArmB.PMA",new StationPosition()
  270. {
  271. StartPosition= new RobotPosition()
  272. {
  273. X=0,
  274. Root=035,
  275. Arm= 120,
  276. Hand=474
  277. },
  278. EndPosition= new RobotPosition()
  279. {
  280. Root=-63,
  281. Arm=-65,
  282. Hand=40
  283. }
  284. }
  285. },
  286. };
  287. canvas1.Rotate(145);
  288. canvas2.Rotate(240);
  289. canvas3.Rotate(244);
  290. canvas21.Rotate(035);
  291. canvas22.Rotate(120);
  292. canvas23.Rotate(474);
  293. }
  294. static void StationPositionChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  295. {
  296. var self = (AtmRobot)d;
  297. var positions = (Dictionary<string, StationPosition>)e.NewValue;
  298. var menus = new List<MenuItem>();
  299. foreach (var position in positions)
  300. {
  301. var m = new MenuItem() { Header = position.Key };
  302. Enum.TryParse<RobotArm>(position.Key.Split('.')[0], out RobotArm arm);
  303. m.Items.Add(new MenuItem() { Header = "Pick", Command = self.MoveCommand, CommandParameter = new RobotMoveInfo() { BladeTarget = position.Key, Action = RobotAction.Picking, ArmTarget = arm } });
  304. m.Items.Add(new MenuItem() { Header = "Place", Command = self.MoveCommand, CommandParameter = new RobotMoveInfo() { BladeTarget = position.Key, Action = RobotAction.Placing, ArmTarget = arm } });
  305. m.Items.Add(new MenuItem() { Header = "Move", Command = self.MoveCommand, CommandParameter = new RobotMoveInfo() { BladeTarget = position.Key, Action = RobotAction.Moving, ArmTarget = arm } });
  306. menus.Add(m);
  307. }
  308. self.Menu = menus;
  309. self.MoveTo(new RobotMoveInfo() { BladeTarget = positions.First().Key, Action = RobotAction.None });
  310. }
  311. protected override void OnRender(DrawingContext drawingContext)
  312. {
  313. base.OnRender(drawingContext);
  314. if (DesignerProperties.GetIsInDesignMode(this))
  315. {
  316. return;
  317. }
  318. if (RobotMoveInfo != null)
  319. {
  320. var needMove = CurrentPosition != RobotMoveInfo.BladeTarget || CurrentAction != RobotMoveInfo.Action;
  321. needMove= needMove && (RobotMoveInfo.Action != RobotAction.Retracting) ;
  322. if (needMove)
  323. {
  324. LogMsg($" RobotMoveInfo, action:{RobotMoveInfo.Action} armTarget:{RobotMoveInfo.ArmTarget} bladeTarget:{RobotMoveInfo.BladeTarget}");
  325. Invoke(() => MoveRobot(RobotMoveInfo));
  326. CurrentAction = RobotMoveInfo.Action;
  327. CurrentPosition = RobotMoveInfo.BladeTarget;
  328. }
  329. }
  330. }
  331. private void Invoke(Action action)
  332. {
  333. Dispatcher.Invoke(action);
  334. }
  335. private void LogMsg(string msg)
  336. {
  337. var source = "ATM Robot";
  338. Console.WriteLine("{0} {1}", source, msg);
  339. }
  340. private void MoveRobot(RobotMoveInfo moveInfo)
  341. {
  342. canvas1.Stop();
  343. canvas2.Stop();
  344. canvas3.Stop();
  345. canvas21.Stop();
  346. canvas22.Stop();
  347. canvas23.Stop();
  348. var target = moveInfo.BladeTarget;
  349. var arm = moveInfo.ArmTarget;
  350. MoveToStart(arm, CurrentPosition
  351. ,
  352. () => TranslateTo(target, () => MoveToStart(arm, target, () =>
  353. {
  354. if (moveInfo.Action != RobotAction.Moving)
  355. {
  356. MoveToEnd(arm, target, () => UpdateWafer(moveInfo));
  357. }
  358. })));
  359. }
  360. private void RotateTo(string station, Action onComplete = null)
  361. {
  362. var position = StationPosition[station];
  363. LogMsg($"Rotate to {position.StartPosition.X}");
  364. container.Rotate((int)position.StartPosition.X, true, MoveTime, 0, 0, onComplete);
  365. }
  366. private void TranslateTo(string station, Action onComplete = null)
  367. {
  368. var position = StationPosition[station];
  369. LogMsg($"Translate to {position.StartPosition.Z}");
  370. Translate(StationPosition[CurrentPosition].StartPosition.Z, position.StartPosition.Z, onComplete);
  371. }
  372. private void MoveToStart(RobotArm arm, string station, Action onComplete = null)
  373. {
  374. LogMsg($"{arm} Move to start {station}");
  375. StationPosition positionA = station.Contains("ArmA") ? StationPosition[station] : StationPosition[station.Replace("ArmB", "ArmA")];
  376. StationPosition positionB = station.Contains("ArmB") ? StationPosition[station] : StationPosition[station.Replace("ArmA", "ArmB")];
  377. var storyboard = new Storyboard();
  378. storyboard.Completed += (s, e) => onComplete?.Invoke();
  379. var needRotate = new List<bool>();
  380. needRotate.Add(canvas1.Rotate(storyboard, positionA.StartPosition.Root, true, MoveTime));
  381. needRotate.Add(canvas2.Rotate(storyboard, positionA.StartPosition.Arm, true, MoveTime));
  382. needRotate.Add(canvas3.Rotate(storyboard, positionA.StartPosition.Hand, true, MoveTime));
  383. needRotate.Add(canvas21.Rotate(storyboard, positionB.StartPosition.Root, true, MoveTime));
  384. needRotate.Add(canvas22.Rotate(storyboard, positionB.StartPosition.Arm, true, MoveTime));
  385. needRotate.Add(canvas23.Rotate(storyboard, positionB.StartPosition.Hand, true, MoveTime));
  386. if (needRotate.Any(x => x))
  387. {
  388. storyboard.Begin();
  389. }
  390. else
  391. {
  392. onComplete?.Invoke();
  393. }
  394. CurrentPosition = station;
  395. }
  396. private void MoveToEnd(RobotArm arm, string station, Action onComplete = null)
  397. {
  398. LogMsg($"{arm} move to end {station}");
  399. var position = StationPosition[station];
  400. var storyboard = new Storyboard();
  401. storyboard.Completed += (s, e) => onComplete?.Invoke();
  402. var needRotate = new List<bool>();
  403. if (arm == RobotArm.ArmA || arm == RobotArm.Both)
  404. {
  405. needRotate.Add(canvas1.Rotate(storyboard, position.EndPosition.Root, true, MoveTime));
  406. needRotate.Add(canvas2.Rotate(storyboard, position.EndPosition.Arm, true, MoveTime));
  407. needRotate.Add(canvas3.Rotate(storyboard, position.EndPosition.Hand, true, MoveTime));
  408. }
  409. if (arm == RobotArm.ArmB || arm == RobotArm.Both)
  410. {
  411. needRotate.Add(canvas21.Rotate(storyboard, position.EndPosition.Root, true, MoveTime));
  412. needRotate.Add(canvas22.Rotate(storyboard, position.EndPosition.Arm, true, MoveTime));
  413. needRotate.Add(canvas23.Rotate(storyboard, position.EndPosition.Hand, true, MoveTime));
  414. }
  415. if (needRotate.Any(x => x))
  416. {
  417. storyboard.Begin();
  418. }
  419. else
  420. {
  421. onComplete?.Invoke();
  422. }
  423. CurrentPosition = station;
  424. }
  425. private void UpdateWafer(RobotMoveInfo moveInfo)
  426. {
  427. var waferPresent = false;
  428. switch (moveInfo.Action)
  429. {
  430. case RobotAction.None:
  431. case RobotAction.Moving:
  432. return;
  433. case RobotAction.Picking:
  434. waferPresent = true;
  435. break;
  436. case RobotAction.Placing:
  437. waferPresent = false;
  438. break;
  439. default:
  440. break;
  441. }
  442. switch (moveInfo.ArmTarget)
  443. {
  444. case RobotArm.ArmA:
  445. WaferPresentA = waferPresent;
  446. break;
  447. case RobotArm.ArmB:
  448. WaferPresentB = waferPresent;
  449. break;
  450. case RobotArm.Both:
  451. WaferPresentA = waferPresent;
  452. WaferPresentB = waferPresent;
  453. break;
  454. default:
  455. break;
  456. }
  457. }
  458. private void Translate(int start, int target, Action onComplete = null)
  459. {
  460. AnimationHelper.TranslateX(root, start, target, MoveTime, onComplete);
  461. }
  462. }
  463. }