CalibToolViewModel.cs 33 KB

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