CalibToolViewModel.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. using Cognex.VisionPro;
  2. using Cognex.VisionPro.ToolBlock;
  3. using MaterialDesignThemes.Wpf;
  4. using MathNet.Numerics;
  5. using MathNet.Numerics.LinearAlgebra;
  6. using NPOI.SS.Formula.Functions;
  7. using OpenCvSharp;
  8. using Prism.Commands;
  9. using Prism.Events;
  10. using Prism.Ioc;
  11. using Prism.Mvvm;
  12. using Prism.Regions;
  13. using Prism.Services.Dialogs;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Drawing;
  17. using System.Linq;
  18. using System.Reflection.Metadata;
  19. using System.Text;
  20. using System.Threading.Tasks;
  21. using System.Windows;
  22. using System.Windows.Media.Media3D;
  23. using Team.FFFeederService.Interfaces;
  24. using TeamAAS_VP.Controls;
  25. using TeamAAS_VP.Core;
  26. using TeamAAS_VP.Events;
  27. using TeamAAS_VP.Interfaces;
  28. using TeamAAS_VP.Models;
  29. using TeamAAS_VP;
  30. using static OpenCvSharp.LineIterator;
  31. using TeamAAS_VP.Resources.Languages;
  32. namespace TeamAAS_VP.ViewModels.Calibration
  33. {
  34. public class CalibToolViewModel : BindableBase, IDialogAware
  35. {
  36. IRegionManager _regionManager;
  37. IRegionNavigationService _regionNavigationService;
  38. IContainerProvider _container;
  39. IDialogService _dialogService;
  40. IEventAggregator _eventAggregator;
  41. #region 属性
  42. private ICogImage _Image;
  43. public ICogImage Image
  44. {
  45. get { return _Image; }
  46. set { SetProperty(ref _Image, value); }
  47. }
  48. private Cognex.VisionPro.CogGraphicCollection _Graphic;
  49. public Cognex.VisionPro.CogGraphicCollection Graphic
  50. {
  51. get { return _Graphic; }
  52. set { SetProperty(ref _Graphic, value); }
  53. }
  54. private CalibrationInfo _SelectCalibration;
  55. public CalibrationInfo SelectCalibration
  56. {
  57. get { return _SelectCalibration; }
  58. set { SetProperty(ref _SelectCalibration, value); }
  59. }
  60. public string Title=> "校准工具坐标";
  61. private double _Angle = 180;
  62. /// <summary>
  63. /// 机器人移动的范围U
  64. /// </summary>
  65. public double Angle
  66. {
  67. get { return _Angle; }
  68. set { SetProperty(ref _Angle, value); }
  69. }
  70. public RobotTool Tool { get; set; }
  71. /// <summary>
  72. /// 机器人与相机之间的旋转矩阵
  73. /// </summary>
  74. public Matrix<double> RobotCameraRotationMatrix { get; set; }
  75. public Management management { get; set; }
  76. public RobotService robotService { get; set; }
  77. public IRobot Robot { get; set; }
  78. public IVoiceCoilMotorFeeder Feeder { get; set; }
  79. private bool _IsRunning=true;
  80. public bool IsRunning
  81. {
  82. get { return _IsRunning; }
  83. set { SetProperty(ref _IsRunning,value); }
  84. }
  85. private ICamera _Camera;
  86. public ICamera Camera
  87. {
  88. get { return _Camera; }
  89. set { SetProperty(ref _Camera, value); }
  90. }
  91. #endregion
  92. #region 命令
  93. private DelegateCommand _ConfirmCommand;
  94. public DelegateCommand ConfirmCommand =>
  95. _ConfirmCommand ?? (_ConfirmCommand = new DelegateCommand(ExecuteConfirmCommand).ObservesCanExecute(() => IsRunning));
  96. private DelegateCommand _CancelCommand;
  97. public DelegateCommand CancelCommand =>
  98. _CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand).ObservesCanExecute(() => IsRunning));
  99. private DelegateCommand _StartCalibCommand;
  100. public DelegateCommand StartCalibCommand =>
  101. _StartCalibCommand ?? (_StartCalibCommand = new DelegateCommand(ExecuteStartCalibCommand).ObservesCanExecute(()=> IsRunning));
  102. #endregion
  103. #region 事件
  104. public event Action<IDialogResult> RequestClose;
  105. #endregion
  106. public CalibToolViewModel(IRegionManager regionManager, IEventAggregator ea, IRegionNavigationService regionNavigationService, IContainerProvider container, IDialogService dialogService)
  107. {
  108. _regionManager = regionManager;
  109. _regionNavigationService = regionNavigationService;
  110. _container = container;
  111. _dialogService = dialogService;
  112. _eventAggregator = ea;
  113. }
  114. #region 方法
  115. /// <summary>
  116. /// 确定
  117. /// </summary>
  118. void ExecuteConfirmCommand()
  119. {
  120. if (Tool==null)
  121. {
  122. return;
  123. }
  124. IDialogParameters parameters = new DialogParameters();
  125. parameters.Add("Tool", Tool);
  126. parameters.Add("RobotCameraRotationMatrix", RobotCameraRotationMatrix);
  127. parameters.Add("Angle", Angle);
  128. RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters));
  129. }
  130. /// <summary>
  131. /// 取消
  132. /// </summary>
  133. void ExecuteCancelCommand()
  134. {
  135. IDialogParameters parameters = new DialogParameters();
  136. parameters.Add("Tool", Tool);
  137. RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel, parameters));
  138. }
  139. /// <summary>
  140. /// 开始校准
  141. /// </summary>
  142. async void ExecuteStartCalibCommand()
  143. {
  144. if (SelectCalibration == null) return;
  145. if (Robot == null || !Robot.IsConnected) return;
  146. Robot.Timeout = 600000;
  147. try
  148. {
  149. if (Angle == 0)
  150. Angle = 10;
  151. var view = new ShowMessage(Lang.Tool校准, Lang.是否开始自动校准工具坐标);
  152. //show the dialog
  153. var result = await DialogHost.Show(view, "CalibToolDialog", null, null, null);
  154. if (!((bool)result)) return;
  155. IsRunning = false;
  156. //发送校准的参数
  157. await Robot.CalibParameAsync(SelectCalibration.Pick, SelectCalibration.Speed, SelectCalibration.Accel, SelectCalibration.Power, SelectCalibration.WaitSuction, SelectCalibration.WaitBlow);
  158. Tuple<bool, Matrix<double>, double, double> calibresult=new Tuple<bool, Matrix<double>, double, double>(false,null,0,0);
  159. if (SelectCalibration.CameraMount == Enums.CameraMount.FixedDown)
  160. {
  161. calibresult = await CalibToolForFixedDown();
  162. }
  163. else if (SelectCalibration.CameraMount == Enums.CameraMount.FixedUp)
  164. {
  165. calibresult = await CalibToolForFixedUp();
  166. }
  167. else if (SelectCalibration.CameraMount == Enums.CameraMount.MobileJ4)
  168. {
  169. calibresult = await CalibToolForMobileJ4();
  170. }
  171. else
  172. {
  173. view = new ShowMessage(Lang.Tool校准, Lang.暂不支持此安装方式的相机, false);
  174. result = await DialogHost.Show(view, "CalibToolDialog", null, null, null);
  175. return;
  176. }
  177. if (calibresult.Item1)
  178. {
  179. if (Tool==null)
  180. {
  181. Tool = new RobotTool();
  182. }
  183. Tool.X = calibresult.Item3;
  184. Tool.Y = calibresult.Item4;
  185. RobotCameraRotationMatrix = calibresult.Item2;
  186. //MessageBox.Show("校准完成");
  187. view = new ShowMessage(Lang.Tool校准, Lang.校准完成, false);
  188. await DialogHost.Show(view, "CalibToolDialog", null, null, null);
  189. IDialogParameters parameters = new DialogParameters();
  190. parameters.Add("Tool", Tool);
  191. parameters.Add("RobotCameraRotationMatrix", RobotCameraRotationMatrix);
  192. RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters));
  193. }
  194. else
  195. {
  196. view = new ShowMessage(Lang.Tool校准, Lang.校准失败, false);
  197. //show the dialog
  198. await DialogHost.Show(view, "CalibToolDialog", null, null, null);
  199. }
  200. IsRunning = true;
  201. }
  202. catch (Exception ex)
  203. {
  204. IsRunning = true;
  205. LogHelper.WriteLogError("相机校准-校准验证界面示加载时出错!", ex);
  206. //MessageBox.Show(ex.Message);
  207. var view = new ShowMessage(Lang.Tool校准, $"{ex.Message}", false);
  208. //show the dialog
  209. var result = await DialogHost.Show(view, "CalibToolDialog", null, null, null);
  210. }
  211. }
  212. public bool CanCloseDialog()
  213. {
  214. return true;
  215. }
  216. public void OnDialogClosed()
  217. {
  218. }
  219. public void OnDialogOpened(IDialogParameters parameters)
  220. {
  221. SelectCalibration = _container.Resolve<CalibrationHomeViewModel>().SelectCalibration;
  222. management = _container.Resolve<Management>();
  223. robotService = management.RobotService;
  224. if (SelectCalibration != null)
  225. {
  226. Camera = management.CameraService.GetCamera(SelectCalibration.CameraID);
  227. Robot = robotService.GetRobot(SelectCalibration.RobotId);
  228. if (SelectCalibration.FeederId!=Guid.Empty)
  229. {
  230. Feeder = management.FeederService.GetFeeder(SelectCalibration.FeederId);
  231. }
  232. Angle = SelectCalibration.Angle;
  233. }
  234. }
  235. /// <summary>
  236. /// 移动机器人3个点计算旋转矩阵
  237. /// </summary>
  238. /// <returns>(旋转矩阵,PixelScaleX,PixelScaleY)</returns>
  239. private async Task<Tuple<Matrix<double>,double,double>> MoveRobotThreePointComputCroodTrans(RPoint rPoint, float distance)
  240. {
  241. //-------------------------------------------P0-----------------------------------
  242. //移动机器人至中心点
  243. if (SelectCalibration.CameraMount == Enums.CameraMount.FixedDown)
  244. {
  245. await Robot.CalibMotionAsync(rPoint, 0);
  246. //关闭吸气
  247. await Robot.CalibOutIOAsync(false);
  248. }
  249. else
  250. {
  251. await Robot.CalibMotionAsync(rPoint, rPoint.Z);
  252. }
  253. RPoint RobotP0= await Robot.GetRobotPosAsync();
  254. RPoint RobotP1 = RobotP0.Clone();
  255. RPoint RobotP2 = RobotP0.Clone();
  256. RobotP1.X += distance;
  257. RobotP2.Y += distance;
  258. if (SelectCalibration.CameraMount == Enums.CameraMount.FixedDown)
  259. {
  260. //移动机器人至待机位置
  261. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  262. }
  263. var P0=Photo();
  264. //-------------------------------------------P1-----------------------------------
  265. if (SelectCalibration.CameraMount == Enums.CameraMount.FixedDown)
  266. {
  267. //移动机器人至P0
  268. await Robot.CalibMotionAsync(RobotP0, 0);
  269. //打开吸气
  270. await Robot.CalibOutIOAsync(true);
  271. //移动机器人至P1
  272. await Robot.CalibMotionAsync(RobotP1, 0);
  273. //关闭吸气
  274. await Robot.CalibOutIOAsync(false);
  275. //移动机器人至待机位置
  276. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  277. }
  278. else
  279. {
  280. //移动机器人至P1
  281. await Robot.CalibMotionAsync(RobotP1, RobotP1.Z);
  282. }
  283. var P1 = Photo();
  284. //-------------------------------------------P2-----------------------------------
  285. if (SelectCalibration.CameraMount == Enums.CameraMount.FixedDown)
  286. {
  287. //移动机器人至P1
  288. await Robot.CalibMotionAsync(RobotP1, 0);
  289. //打开吸气
  290. await Robot.CalibOutIOAsync(true);
  291. //移动机器人至P2
  292. await Robot.CalibMotionAsync(RobotP2, 0);
  293. //关闭吸气
  294. await Robot.CalibOutIOAsync(false);
  295. //移动机器人至待机位置
  296. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  297. }
  298. else
  299. {
  300. //移动机器人至P2
  301. await Robot.CalibMotionAsync(RobotP2, RobotP2.Z);
  302. }
  303. var P2 = Photo();
  304. //-------------------------------------------P0--------------------------------------
  305. if (SelectCalibration.CameraMount == Enums.CameraMount.FixedDown)
  306. {
  307. //移动机器人至P2
  308. await Robot.CalibMotionAsync(RobotP2, 0);
  309. //打开吸气
  310. await Robot.CalibOutIOAsync(true);
  311. //移动机器人至P0
  312. await Robot.CalibMotionAsync(RobotP0, 0);
  313. //关闭吸气
  314. await Robot.CalibOutIOAsync(false);
  315. //移动机器人至待机位置
  316. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  317. }
  318. else
  319. {
  320. //移动机器人至P0
  321. await Robot.CalibMotionAsync(RobotP0, RobotP0.Z);
  322. }
  323. //-----------------------------------------计算旋转矩阵------------------------------
  324. Matrix<double> M= ComputRotationMatrix(P0, P1, P2);
  325. //Theta = Acos(M11)
  326. //相机与机器人坐标系角度:Theta * 180 / PI
  327. //-----------------------------------------计算像素和毫米比例-----------------------
  328. Vector<double> P11= Vector<double>.Build.Dense(new double[] { distance, 0 });
  329. Vector<double> P21 = Vector<double>.Build.Dense(new double[] { P1.X, P1.Y }) - Vector<double>.Build.Dense(new double[] { P0.X, P0.Y });
  330. double PixelScaleX = Math.Abs((M * P11)[0] / P21[0]); //mm/pixel
  331. double PixelScaleY = Math.Abs((M * P11)[1] / P21[1]); //mm/pixel
  332. return new Tuple<Matrix<double>, double, double>(M, PixelScaleX, PixelScaleY);
  333. }
  334. /// <summary>
  335. /// 计算旋转矩阵
  336. /// </summary>
  337. /// <param name="P0"></param>
  338. /// <param name="P1"></param>
  339. /// <param name="P2"></param>
  340. /// <returns></returns>
  341. private Matrix<double> ComputRotationMatrix(PointF P0, PointF P1, PointF P2)
  342. {
  343. Vector<double> Point0 = Vector<double>.Build.Dense(new double[] { (double)P0.X, (double)P0.Y });
  344. Vector<double> Point1 = Vector<double>.Build.Dense(new double[] { (double)P1.X, (double)P1.Y });
  345. Vector<double> Point2 = Vector<double>.Build.Dense(new double[] { (double)P2.X, (double)P2.Y });
  346. //2.计算坐标系的基向量:
  347. Vector<double> E1 = (Point1 - Point0) / (Point1 - Point0).L2Norm();
  348. Vector<double> E2 = (Point2 - Point0 - E1.DotProduct(Point2 - Point0) * E1) / (Point2 - Point0 - E1.DotProduct(Point2 - Point0) * E1).L2Norm();
  349. //3.计算旋转矩阵:我们可以使用基向量组成的矩阵作为旋转矩阵。具体地,我们可以将基向量 e1 和 e2 分别作为新坐标系下的 $x$ 和 $y$ 轴,然后组成一个矩阵,再对这个矩阵求逆即可得到旋转矩阵。代码实现:
  350. // Compute rotation matrix
  351. Matrix<double> R = Matrix<double>.Build.DenseOfColumnVectors(E1, E2);
  352. return R;
  353. }
  354. /// <summary>
  355. /// 相机拍照
  356. /// </summary>
  357. /// <returns></returns>
  358. /// <exception cref="Exception"></exception>
  359. private PointF Photo()
  360. {
  361. if (Feeder != null)
  362. {
  363. Feeder.OpenLight();
  364. Feeder.SetLightTimeOut((ushort)SelectCalibration.Brightness);
  365. }
  366. Task.Delay(200).Wait();
  367. //采集图像
  368. if (Camera != null)
  369. {
  370. SelectCalibration.ToolBlock.Inputs["InputImage"].Value = Camera.Grab();
  371. Image = (ICogImage)SelectCalibration.ToolBlock.Inputs["InputImage"].Value;
  372. }
  373. Graphic = null;
  374. SelectCalibration.ToolBlock.Run();
  375. CogToolBlockTerminalCollection outputCollection = SelectCalibration.ToolBlock.Outputs;
  376. Graphic = outputCollection["Graphic"].Value as CogGraphicCollection;
  377. bool Found = (bool)(outputCollection["Found"].Value);
  378. if (Found)
  379. {
  380. var strpoints = outputCollection["Point"].Value.ToString();
  381. string[] items = strpoints.Split(',');
  382. return new PointF(float.Parse(items[0]), float.Parse(items[1]));
  383. }
  384. else
  385. {
  386. throw new Exception(Lang.拍照失败);
  387. }
  388. }
  389. /// <summary>
  390. /// 固定向下相机校准工具坐标
  391. /// </summary>
  392. /// <returns>(结果,旋转矩阵,Tool.X,Tool.Y)</returns>
  393. private async Task<Tuple<bool,Matrix<double>, double, double>> CalibToolForFixedDown()
  394. {
  395. //移动机器人至待机位置
  396. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  397. if (SelectCalibration.Pick.PickPlaceModel == Enums.PickPlaceModel.Inhal)
  398. {
  399. //打开吸气
  400. await Robot.CalibOutIOAsync(true);
  401. }
  402. else
  403. {
  404. //张开夹爪
  405. //夹爪张开为false,夹爪闭合为True
  406. await Robot.CalibOutIOAsync(false);
  407. }
  408. var view = new ShowMessage(Lang.提示, Lang.请将校准块放置在吸嘴中心);
  409. var result = await DialogHost.Show(view, "CalibToolDialog", null, null, null);
  410. if (!((bool)result)) { IsRunning = true; return new Tuple<bool, Matrix<double>, double, double>(false,null,0,0); }
  411. if (SelectCalibration.Pick.PickPlaceModel == Enums.PickPlaceModel.Clamp)
  412. {
  413. //夹紧夹爪
  414. await Robot.CalibOutIOAsync(true);
  415. }
  416. //计算相机与机器人坐标系的旋转矩阵
  417. var rst = await MoveRobotThreePointComputCroodTrans(SelectCalibration.CenterPoint, ((float)SelectCalibration.Height) / 3);
  418. SelectCalibration.PixelScaleX = rst.Item2;
  419. SelectCalibration.PixelScaleY = rst.Item3;
  420. var P0 = Photo(); //拍照获取中点像素坐标
  421. RPoint RobotU = SelectCalibration.CenterPoint.Clone();
  422. RobotU.U += (float)Angle;
  423. //移动机器人中心点
  424. await Robot.CalibMotionAsync(SelectCalibration.CenterPoint, 0);
  425. //打开吸气
  426. await Robot.CalibOutIOAsync(true);
  427. //机器人U轴旋转
  428. await Robot.CalibMotionAsync(RobotU, 0);
  429. //关闭吸气
  430. await Robot.CalibOutIOAsync(false);
  431. //移动机器人至待机位置
  432. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  433. var curPixel = Photo();
  434. bool IsFinish = false;
  435. for (int i = 0; i < 10; i++)
  436. {
  437. //计算需要移动的偏移量,目的是逼近中心点
  438. double offsetx = (P0.X - curPixel.X) * rst.Item2;
  439. double offsety = (P0.Y - curPixel.Y) * rst.Item3;
  440. var pos = rst.Item1.Inverse() * Vector<double>.Build.Dense(new double[] { offsetx, offsety });
  441. //移动机器人取标定块
  442. await Robot.CalibMotionAsync(RobotU, 0);
  443. //打开吸气
  444. await Robot.CalibOutIOAsync(true);
  445. RobotU.X += (float)pos[0];
  446. RobotU.Y += (float)pos[1];
  447. //机器人移动
  448. await Robot.CalibMotionAsync(RobotU, 0);
  449. //关闭吸气
  450. await Robot.CalibOutIOAsync(false);
  451. //移动机器人至待机位置
  452. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  453. curPixel = Photo();
  454. offsetx = P0.X - curPixel.X;
  455. offsety = P0.Y - curPixel.Y;
  456. //await Console.Out.WriteLineAsync($"移动后的差异:{offsetx},{offsety}");
  457. if (Math.Abs(offsetx) < 1 && Math.Abs(offsetx) < 1)
  458. {
  459. //移动机器人取标定块
  460. await Robot.CalibMotionAsync(RobotU, 0);
  461. //打开吸气
  462. await Robot.CalibOutIOAsync(true);
  463. //移动机器人至待机位置
  464. await Robot.CalibMotionAsync(SelectCalibration.HomePoint, 0);
  465. IsFinish = true;
  466. break;
  467. }
  468. }
  469. if (IsFinish)
  470. {
  471. Vector<double> p0 = Vector<double>.Build.Dense(new double[] { SelectCalibration.CenterPoint.X, SelectCalibration.CenterPoint.Y });
  472. Vector<double> p1 = Vector<double>.Build.Dense(new double[] { RobotU.X, RobotU.Y });
  473. ToolCoord toolCoord = new ToolCoord();
  474. double u1 = SelectCalibration.CenterPoint.U;
  475. double u2 = RobotU.U;
  476. if (Robot.Brand == Enums.RobotBrand.Schneider)
  477. {
  478. u1 *= -1;
  479. u2 *= -1;
  480. }
  481. toolCoord.ComputeTool(p0, p1, u1, u2);
  482. if (Tool == null)
  483. {
  484. Tool = new RobotTool();
  485. }
  486. Tool.X = toolCoord.X;
  487. Tool.Y = toolCoord.Y;
  488. RobotCameraRotationMatrix = rst.Item1;
  489. return new Tuple<bool, Matrix<double>, double, double>(true, RobotCameraRotationMatrix, Tool.X, Tool.Y);
  490. }
  491. else
  492. {
  493. return new Tuple<bool, Matrix<double>, double, double>(false, null,0,0);
  494. }
  495. }
  496. /// <summary>
  497. /// 固定向上相机校准工具坐标
  498. /// </summary>
  499. /// <returns>(结果,旋转矩阵,Tool.X,Tool.Y)</returns>
  500. private async Task<Tuple<bool, Matrix<double>, double, double>> CalibToolForFixedUp()
  501. {
  502. //移动机器人至中心位置
  503. await Robot.CalibMotionAsync(SelectCalibration.CenterPoint, 0);
  504. if (SelectCalibration.Pick.PickPlaceModel == Enums.PickPlaceModel.Inhal)
  505. {
  506. //打开吸气
  507. await Robot.CalibOutIOAsync(true);
  508. }
  509. else
  510. {
  511. //张开夹爪
  512. await Robot.CalibOutIOAsync(false);
  513. }
  514. var view = new ShowMessage(Lang.提示, Lang.请将校准块放置在吸嘴中心);
  515. var result = await DialogHost.Show(view, "CalibToolDialog", null, null, null);
  516. if (!((bool)result)) { IsRunning = true; return new Tuple<bool, Matrix<double>, double, double>(false,null,0,0); }
  517. if (SelectCalibration.Pick.PickPlaceModel == Enums.PickPlaceModel.Clamp)
  518. {
  519. //夹紧夹爪
  520. await Robot.CalibOutIOAsync(true);
  521. }
  522. //计算相机与机器人坐标系的旋转矩阵
  523. var rst = await MoveRobotThreePointComputCroodTrans(SelectCalibration.CenterPoint, ((float)SelectCalibration.Height) / 3);
  524. SelectCalibration.PixelScaleX = rst.Item2;
  525. SelectCalibration.PixelScaleY = rst.Item3;
  526. var imagecenter = Camera.Grab();
  527. PointF P0 = new PointF((float)(imagecenter.Width/2), (float)(imagecenter.Height / 2)); //中心点像素坐标
  528. //先找相机中心点,校准中心点坐标
  529. bool IsFinish = false;
  530. var curPixel = Photo();
  531. var curpos = Robot.GetRobotPos();
  532. for (int i = 0; i < 10; i++)
  533. {
  534. //计算需要移动的偏移量,目的是逼近中心点
  535. double offsetx = (P0.X - curPixel.X) * rst.Item2;
  536. double offsety = (P0.Y - curPixel.Y) * rst.Item3;
  537. var pos = rst.Item1.Inverse() * Vector<double>.Build.Dense(new double[] { offsetx, offsety });
  538. curpos.X += (float)pos[0];
  539. curpos.Y += (float)pos[1];
  540. //机器人移动
  541. await Robot.CalibMotionAsync(curpos, curpos.Z);
  542. curPixel = Photo();
  543. offsetx = P0.X - curPixel.X;
  544. offsety = P0.Y - curPixel.Y;
  545. //await Console.Out.WriteLineAsync($"移动后的差异:{offsetx},{offsety}");
  546. if (Math.Abs(offsetx) < 1 && Math.Abs(offsetx) < 1)
  547. {
  548. IsFinish = true;
  549. break;
  550. }
  551. }
  552. if (IsFinish==true)
  553. {
  554. SelectCalibration.CenterPoint= Robot.GetRobotPos();
  555. }
  556. else
  557. {
  558. return new Tuple<bool, Matrix<double>, double, double>(false, null, 0, 0);
  559. }
  560. RPoint RobotU = SelectCalibration.CenterPoint.Clone();
  561. RobotU.U += (float)Angle;
  562. //机器人U轴旋转
  563. await Robot.CalibMotionAsync(RobotU, RobotU.Z);
  564. curPixel = Photo();
  565. IsFinish = false;
  566. for (int i = 0; i < 10; i++)
  567. {
  568. //计算需要移动的偏移量,目的是逼近中心点
  569. double offsetx = (P0.X - curPixel.X) * rst.Item2;
  570. double offsety = (P0.Y - curPixel.Y) * rst.Item3;
  571. var pos = rst.Item1.Inverse() * Vector<double>.Build.Dense(new double[] { offsetx, offsety });
  572. RobotU.X += (float)pos[0];
  573. RobotU.Y += (float)pos[1];
  574. //机器人移动
  575. await Robot.CalibMotionAsync(RobotU, 0);
  576. curPixel = Photo();
  577. offsetx = P0.X - curPixel.X;
  578. offsety = P0.Y - curPixel.Y;
  579. //await Console.Out.WriteLineAsync($"移动后的差异:{offsetx},{offsety}");
  580. if (Math.Abs(offsetx) < 1 && Math.Abs(offsetx) < 1)
  581. {
  582. IsFinish = true;
  583. break;
  584. }
  585. }
  586. if (IsFinish)
  587. {
  588. Vector<double> p0 = Vector<double>.Build.Dense(new double[] { SelectCalibration.CenterPoint.X, SelectCalibration.CenterPoint.Y });
  589. Vector<double> p1 = Vector<double>.Build.Dense(new double[] { RobotU.X, RobotU.Y });
  590. ToolCoord toolCoord = new ToolCoord();
  591. double u1 = SelectCalibration.CenterPoint.U;
  592. double u2 = RobotU.U;
  593. if (Robot.Brand== Enums.RobotBrand.Schneider)
  594. {
  595. u1 *= -1;
  596. u2 *= -1;
  597. }
  598. toolCoord.ComputeTool(p0, p1, u1, u2);
  599. if (Tool == null)
  600. {
  601. Tool = new RobotTool();
  602. }
  603. /*double toolx= toolCoord.X;
  604. if (Robot.Brand == Enums.RobotBrand.Schneider)
  605. {
  606. toolx *= -1;
  607. }*/
  608. Tool.X = toolCoord.X;
  609. Tool.Y = toolCoord.Y;
  610. RobotCameraRotationMatrix = rst.Item1;
  611. return new Tuple<bool, Matrix<double>, double, double>(true, RobotCameraRotationMatrix, Tool.X, Tool.Y);
  612. }
  613. else
  614. {
  615. return new Tuple<bool, Matrix<double>, double, double>(false, null, 0, 0);
  616. }
  617. }
  618. /// <summary>
  619. /// J4移动机器人校准工具坐标
  620. /// </summary>
  621. /// <returns>(结果,旋转矩阵,Tool.X,Tool.Y)</returns>
  622. private async Task<Tuple<bool, Matrix<double>, double, double>> CalibToolForMobileJ4()
  623. {
  624. //移动机器人至中心位置
  625. await Robot.CalibMotionAsync(SelectCalibration.CenterPoint, 0);
  626. //计算相机与机器人坐标系的旋转矩阵
  627. var rst = await MoveRobotThreePointComputCroodTrans(SelectCalibration.CenterPoint, ((float)SelectCalibration.Height) / 3);
  628. SelectCalibration.PixelScaleX = rst.Item2;
  629. SelectCalibration.PixelScaleY = rst.Item3;
  630. var imagecenter = Camera.Grab();
  631. PointF P0 = new PointF((float)(imagecenter.Width / 2), (float)(imagecenter.Height / 2)); //中心点像素坐标
  632. //先找相机中心点,校准中心点坐标
  633. bool IsFinish = false;
  634. var curPixel = Photo();
  635. var curpos = Robot.GetRobotPos();
  636. for (int i = 0; i < 10; i++)
  637. {
  638. //计算需要移动的偏移量,目的是逼近中心点
  639. double offsetx = (P0.X - curPixel.X) * rst.Item2;
  640. double offsety = (P0.Y - curPixel.Y) * rst.Item3;
  641. var pos = rst.Item1.Inverse() * Vector<double>.Build.Dense(new double[] { offsetx, offsety });
  642. curpos.X += (float)pos[0];
  643. curpos.Y += (float)pos[1];
  644. //机器人移动
  645. await Robot.CalibMotionAsync(curpos, curpos.Z);
  646. curPixel = Photo();
  647. offsetx = P0.X - curPixel.X;
  648. offsety = P0.Y - curPixel.Y;
  649. //await Console.Out.WriteLineAsync($"移动后的差异:{offsetx},{offsety}");
  650. if (Math.Abs(offsetx) < 1 && Math.Abs(offsetx) < 1)
  651. {
  652. IsFinish = true;
  653. break;
  654. }
  655. }
  656. if (IsFinish == true)
  657. {
  658. SelectCalibration.CenterPoint = Robot.GetRobotPos();
  659. }
  660. else
  661. {
  662. return new Tuple<bool, Matrix<double>, double, double>(false, null, 0, 0);
  663. }
  664. RPoint RobotU = SelectCalibration.CenterPoint.Clone();
  665. RobotU.U += (float)Angle;
  666. //机器人U轴旋转
  667. await Robot.CalibMotionAsync(RobotU, RobotU.Z);
  668. //计算相机与机器人坐标系的旋转矩阵
  669. var rst1 = await MoveRobotThreePointComputCroodTrans(RobotU, 1);
  670. curPixel = Photo();
  671. IsFinish = false;
  672. for (int i = 0; i < 10; i++)
  673. {
  674. //计算需要移动的偏移量,目的是逼近中心点
  675. double offsetx = (P0.X - curPixel.X) * rst1.Item2;
  676. double offsety = (P0.Y - curPixel.Y) * rst1.Item3;
  677. var pos = rst1.Item1.Inverse() * Vector<double>.Build.Dense(new double[] { offsetx, offsety });
  678. RobotU.X += (float)pos[0];
  679. RobotU.Y += (float)pos[1];
  680. //机器人移动
  681. await Robot.CalibMotionAsync(RobotU, RobotU.Z);
  682. curPixel = Photo();
  683. offsetx = P0.X - curPixel.X;
  684. offsety = P0.Y - curPixel.Y;
  685. //await Console.Out.WriteLineAsync($"移动后的差异:{offsetx},{offsety}");
  686. if (Math.Abs(offsetx) < 1 && Math.Abs(offsetx) < 1)
  687. {
  688. IsFinish = true;
  689. break;
  690. }
  691. }
  692. if (IsFinish)
  693. {
  694. Vector<double> p0 = Vector<double>.Build.Dense(new double[] { SelectCalibration.CenterPoint.X, SelectCalibration.CenterPoint.Y });
  695. Vector<double> p1 = Vector<double>.Build.Dense(new double[] { RobotU.X, RobotU.Y });
  696. ToolCoord toolCoord = new ToolCoord();
  697. double u1 = SelectCalibration.CenterPoint.U;
  698. double u2 = RobotU.U;
  699. if (Robot.Brand == Enums.RobotBrand.Schneider)
  700. {
  701. u1 *= -1;
  702. u2 *= -1;
  703. }
  704. toolCoord.ComputeTool(p0, p1, u1, u2);
  705. if (Tool == null)
  706. {
  707. Tool = new RobotTool();
  708. }
  709. Tool.X = toolCoord.X;
  710. Tool.Y = toolCoord.Y;
  711. RobotCameraRotationMatrix = rst.Item1;
  712. return new Tuple<bool, Matrix<double>, double, double>(true, RobotCameraRotationMatrix, Tool.X, Tool.Y);
  713. }
  714. else
  715. {
  716. return new Tuple<bool, Matrix<double>, double, double>(false, null, 0, 0);
  717. }
  718. }
  719. #endregion
  720. }
  721. }