ATMDualArmRobot.xaml.cs 17 KB

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