Răsfoiți Sursa

支持独立XY模组移动向下相机的全流程校准

本次提交实现了对“独立XY模组移动向下相机”场景的完整支持,包括:
- 新增CameraMount类型MobileDown_IndependentXYPlatform及相关本地化、图片资源;
- CalibrationInfo模型扩展,支持相机运动模组编号与点位;
- 机器人接口与实现类统一增加SafeZ属性,运动逻辑支持自动安全高度;
- 校准与运动流程适配独立XY模组,新增专用工具坐标校准方法;
- 校准界面动态显示模组编号、示教按钮及点位,支持一键采集;
- Drawer机器人手动操作控件切换为PlcRobotManual并适配XYZU_Robot;
- 相关ViewModel、Service、资源等同步适配,提升系统通用性和灵活性。
孝锋 徐 8 luni în urmă
părinte
comite
542d2c90ae
28 a modificat fișierele cu 560 adăugiri și 114 ștergeri
  1. 10 0
      TeamAAS-VM/Core/Robots/EpsonRobot.cs
  2. 10 0
      TeamAAS-VM/Core/Robots/FanucRobot.cs
  3. 10 0
      TeamAAS-VM/Core/Robots/SchneiderRobot.cs
  4. 15 0
      TeamAAS-VM/Core/Robots/XYZU_Robot.cs
  5. 7 0
      TeamAAS-VM/Enums/CameraMount.cs
  6. 5 0
      TeamAAS-VM/Interfaces/IRobot.cs
  7. 19 0
      TeamAAS-VM/Models/Calibration/CalibrationInfo.cs
  8. 10 0
      TeamAAS-VM/Models/Robot/RobotInfo.cs
  9. BIN
      TeamAAS-VM/Resources/Images/MobileDown_IndependentXYPlatform.png
  10. 217 35
      TeamAAS-VM/Services/CameraCalibrationService.cs
  11. 1 0
      TeamAAS-VM/TeamAAS-VP.csproj
  12. 3 0
      TeamAAS-VM/ValueConverter/CameraMountConverter.cs
  13. 38 1
      TeamAAS-VM/ViewModels/Calibration/CalibrationTeachCenterPointViewModel.cs
  14. 6 6
      TeamAAS-VM/ViewModels/Calibration/FixedUpCameraFindP0ViewModel.cs
  15. 11 11
      TeamAAS-VM/ViewModels/Product/CalculateOffsetUViewModel.cs
  16. 30 29
      TeamAAS-VM/ViewModels/Product/PlcPointParamsViewModel.cs
  17. 20 16
      TeamAAS-VM/ViewModels/Product/RobotPointParamsViewModel.cs
  18. 5 5
      TeamAAS-VM/ViewModels/Product/TestProductPageViewModel.cs
  19. 27 0
      TeamAAS-VM/Views/Calibration/CalibrationBasics.xaml
  20. 1 1
      TeamAAS-VM/Views/Calibration/CalibrationCameraParams.xaml
  21. 2 1
      TeamAAS-VM/Views/Calibration/CalibrationCameraParams.xaml.cs
  22. 1 1
      TeamAAS-VM/Views/Calibration/CalibrationEditVision.xaml
  23. 2 1
      TeamAAS-VM/Views/Calibration/CalibrationEditVision.xaml.cs
  24. 78 4
      TeamAAS-VM/Views/Calibration/CalibrationTeachCenterPoint.xaml
  25. 2 1
      TeamAAS-VM/Views/Calibration/CalibrationTeachCenterPoint.xaml.cs
  26. 1 1
      TeamAAS-VM/Views/Calibration/FixedUpCameraFindP0.xaml
  27. 2 1
      TeamAAS-VM/Views/Calibration/FixedUpCameraFindP0.xaml.cs
  28. 27 0
      TeamAAS-VM/Views/SettingView.xaml

+ 10 - 0
TeamAAS-VM/Core/Robots/EpsonRobot.cs

@@ -192,6 +192,16 @@ namespace TeamAAS_VP.Core.Robots
             get { return _CurrentPosition; }
             set { SetProperty(ref _CurrentPosition, value); }
         }
+
+        private double _SafeZ;
+        /// <summary>
+        /// Z轴的安全高度
+        /// </summary>
+        public double SafeZ
+        {
+            get { return _SafeZ; }
+            set { SetProperty(ref _SafeZ, value); }
+        }
         #endregion
 
         #region 事件接收

+ 10 - 0
TeamAAS-VM/Core/Robots/FanucRobot.cs

@@ -196,6 +196,16 @@ namespace TeamAAS_VP.Core.Robots
             get { return _CurrentPosition; }
             set { SetProperty(ref _CurrentPosition, value); }
         }
+
+        private double _SafeZ;
+        /// <summary>
+        /// Z轴的安全高度
+        /// </summary>
+        public double SafeZ
+        {
+            get { return _SafeZ; }
+            set { SetProperty(ref _SafeZ, value); }
+        }
         #endregion
 
         #region 事件接收

+ 10 - 0
TeamAAS-VM/Core/Robots/SchneiderRobot.cs

@@ -191,6 +191,16 @@ namespace TeamAAS_VP.Core.Robots
             get { return _CurrentPosition; }
             set { SetProperty(ref _CurrentPosition, value); }
         }
+
+        private double _SafeZ;
+        /// <summary>
+        /// Z轴的安全高度
+        /// </summary>
+        public double SafeZ
+        {
+            get { return _SafeZ; }
+            set { SetProperty(ref _SafeZ, value); }
+        }
         #endregion
 
         #region 事件接收

+ 15 - 0
TeamAAS-VM/Core/Robots/XYZU_Robot.cs

@@ -47,6 +47,7 @@ namespace TeamAAS_VP.Core.Robots
             Terminator = robot.Terminator;
             DataEncoding = robot.DataEncoding;
             Brand = RobotBrand.XYZ_Platform;
+            SafeZ= robot.SafeZ;
             Plc = pLC;
             Plc.ConnectChangedEvent += Plc_ConnectChangedEvent;
 
@@ -500,6 +501,15 @@ namespace TeamAAS_VP.Core.Robots
             set { SetProperty(ref _Camera4CurrentPosition, value); }
         }
 
+        private double _SafeZ;
+        /// <summary>
+        /// Z轴的安全高度
+        /// </summary>
+        public double SafeZ
+        {
+            get { return _SafeZ; }
+            set { SetProperty(ref _SafeZ, value); }
+        }
         #endregion
 
         #region 连接
@@ -722,6 +732,11 @@ namespace TeamAAS_VP.Core.Robots
                 currentPos.Z = (float)LimZ.Value;
                 if (!Go(currentPos)) return false;
             }
+            else
+            {
+                currentPos.Z = (float)SafeZ;
+                if (!Go(currentPos)) return false;
+            }
             //再XYU轴到位
             currentPos.X = position.X;
             currentPos.Y = position.Y;

+ 7 - 0
TeamAAS-VM/Enums/CameraMount.cs

@@ -51,6 +51,13 @@ namespace TeamAAS_VP.Enums
         [Localization(ResourceName = "CameraMount_MobileDownXYPlatform", ResourceType = typeof(Lang))]
         MobileDown_XYPlatform = 4,
 
+        /// <summary>
+        /// XY模组移动向下
+        /// </summary>
+        [Description("独立XY模组移动向下")]
+        [Localization(ResourceName = "CameraMount_MobileDownIndependentXYPlatform", ResourceType = typeof(Lang))]
+        MobileDown_IndependentXYPlatform = 5,
+
         /// <summary>
         /// 独立相机
         /// </summary>

+ 5 - 0
TeamAAS-VM/Interfaces/IRobot.cs

@@ -76,6 +76,11 @@ namespace TeamAAS_VP.Interfaces
         //当前位置
         RPoint CurrentPosition { get; }
 
+        /// <summary>
+        /// Z轴的安全高度
+        /// </summary>
+        double SafeZ { get; set; }
+
         #endregion
 
         #region 连接通讯

+ 19 - 0
TeamAAS-VM/Models/Calibration/CalibrationInfo.cs

@@ -113,6 +113,16 @@ namespace TeamAAS_VP.Models.Calibration
             set { SetProperty(ref _CameraMount, value); }
         }
 
+        private int _CameraMotionModuleIndex;
+        /// <summary>
+        /// 相机运动模块的编号
+        /// </summary>
+        public int CameraMotionModuleIndex
+        {
+            get { return _CameraMotionModuleIndex; }
+            set { SetProperty(ref _CameraMotionModuleIndex, value); }
+        }
+
         private PickInfo _Pick;
 
         /// <summary>
@@ -327,6 +337,15 @@ namespace TeamAAS_VP.Models.Calibration
             set { SetProperty(ref _DownCameraPoint, value); }
         }
 
+        private RPoint _IndependentDownCameraMotionModulePoint;
+        /// <summary>
+        /// 独立的移动固定向下相机的模组位置
+        /// </summary>
+        public RPoint IndependentDownCameraMotionModulePoint
+        {
+            get { return _IndependentDownCameraMotionModulePoint; }
+            set { SetProperty(ref _IndependentDownCameraMotionModulePoint, value); }
+        }
 
         private ObservableCollection<RobotPixelPoint> _CalibPoints;
 

+ 10 - 0
TeamAAS-VM/Models/Robot/RobotInfo.cs

@@ -114,6 +114,16 @@ namespace TeamAAS_VP.Models
             set { SetProperty(ref _StepDistance, value); }
         }
 
+        private double _SafeZ;
+        /// <summary>
+        /// Z轴的安全高度
+        /// </summary>
+        public double SafeZ
+        {
+            get { return _SafeZ; }
+            set { SetProperty(ref _SafeZ, value); }
+        }
+
         private Guid _PLC;
         /// <summary>
         /// 对应的PLC

BIN
TeamAAS-VM/Resources/Images/MobileDown_IndependentXYPlatform.png


+ 217 - 35
TeamAAS-VM/Services/CameraCalibrationService.cs

@@ -14,6 +14,7 @@ using System.Threading.Tasks;
 using System.Windows;
 using TeamAAS_VP.Controls;
 using TeamAAS_VP.Core;
+using TeamAAS_VP.Core.Robots;
 using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
 using TeamAAS_VP.Models.Calibration;
@@ -62,7 +63,7 @@ namespace TeamAAS_VP.Services
             Matrix<double> RobotCameraRotationMatrix = null;
 
             //移动机器人至待机位置
-            await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+            await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             if (cancellationToken.IsCancellationRequested)
             {
                 return (false, null, 0, 0, 0, 0);
@@ -109,7 +110,7 @@ namespace TeamAAS_VP.Services
             RPoint RobotU = calibrationInfo.CenterPoint.Clone();
             RobotU.U += (float)calibrationInfo.Angle;
             //移动机器人中心点
-            await robot.CalibMotionAsync(calibrationInfo.CenterPoint, 0);
+            await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
             if (cancellationToken.IsCancellationRequested)
             {
                 return (false, null, 0, 0, 0, 0);
@@ -118,7 +119,7 @@ namespace TeamAAS_VP.Services
             await robot.CalibOutIOAsync(true);
 
             //机器人U轴旋转
-            await robot.CalibMotionAsync(RobotU, 0);
+            await robot.CalibMotionAsync(RobotU, null);
             if (cancellationToken.IsCancellationRequested)
             {
                 return (false, null, 0, 0, 0, 0);
@@ -127,7 +128,7 @@ namespace TeamAAS_VP.Services
             //关闭吸气
             await robot.CalibOutIOAsync(false);
             //移动机器人至待机位置
-            await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+            await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             if (cancellationToken.IsCancellationRequested)
             {
                 return (false, null, 0, 0, 0, 0);
@@ -149,7 +150,7 @@ namespace TeamAAS_VP.Services
                 double offsety = (P0.Y - curPixel.Y) * pixelScaleY;
                 var pos = RobotCameraRotationMatrix.Inverse() * Vector<double>.Build.Dense(new double[] { offsetx, offsety });
                 //移动机器人取标定块
-                await robot.CalibMotionAsync(RobotU, 0);
+                await robot.CalibMotionAsync(RobotU, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0, 0, 0);
@@ -160,7 +161,7 @@ namespace TeamAAS_VP.Services
                 RobotU.X += (float)pos[0];
                 RobotU.Y += (float)pos[1];
                 //机器人移动
-                await robot.CalibMotionAsync(RobotU, 0);
+                await robot.CalibMotionAsync(RobotU, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0, 0, 0);
@@ -169,7 +170,7 @@ namespace TeamAAS_VP.Services
                 //关闭吸气
                 await robot.CalibOutIOAsync(false);
                 //移动机器人至待机位置
-                await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0, 0, 0);
@@ -187,7 +188,7 @@ namespace TeamAAS_VP.Services
                 if (Math.Abs(offsetx) < 1 && Math.Abs(offsetx) < 1)
                 {
                     //移动机器人取标定块
-                    await robot.CalibMotionAsync(RobotU, 0);
+                    await robot.CalibMotionAsync(RobotU, null);
                     if (cancellationToken.IsCancellationRequested)
                     {
                         return (false, null, 0, 0, 0, 0);
@@ -195,7 +196,7 @@ namespace TeamAAS_VP.Services
                     //打开吸气
                     await robot.CalibOutIOAsync(true);
                     //移动机器人至待机位置
-                    await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                    await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
                     IsFinish = true;
                     break;
                 }
@@ -247,7 +248,7 @@ namespace TeamAAS_VP.Services
             Matrix<double> RobotCameraRotationMatrix = null;
 
             //移动机器人至中心位置
-            await robot.CalibMotionAsync(calibrationInfo.CenterPoint, 0);
+            await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
 
             //计算相机与机器人坐标系的旋转矩阵
             var robotCameraRotationMatrix = await AutoIdentifyRobotCameraRotationMatrix(calibrationInfo, robot, cancellationToken);
@@ -334,7 +335,7 @@ namespace TeamAAS_VP.Services
             Matrix<double> RobotCameraRotationMatrix = null;
 
             //移动机器人至中心位置
-            await robot.CalibMotionAsync(calibrationInfo.CenterPoint, 0);
+            await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
 
             if (calibrationInfo.Pick.PickPlaceModel == Enums.PickPlaceModel.Inhal)
             {
@@ -427,6 +428,161 @@ namespace TeamAAS_VP.Services
             return (true, RobotCameraRotationMatrix, calibrationInfo.Tool.X, calibrationInfo.Tool.Y, pixelScaleX, pixelScaleY);
         }
 
+        /// <summary>
+        /// 独立模组移动向下相机校准工具坐标
+        /// </summary>
+        /// <param name="calibrationInfo"></param>
+        /// <param name="robot"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task<(bool IsSuccess, Matrix<double> RotationMatrix, double ToolX, double ToolY, double PixelScaleX, double PixelScaleY)> CalibrateIndependentXYPlatformMovingDownCameraTool(CalibrationInfo calibrationInfo, IRobot robot, CancellationToken cancellationToken)
+        {
+            double pixelScaleX = 0;
+            double pixelScaleY = 0;
+            Matrix<double> RobotCameraRotationMatrix = null;
+
+            //移动机器人至待机位置
+            await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+
+            if (calibrationInfo.Pick.PickPlaceModel == Enums.PickPlaceModel.Inhal)
+            {
+                //打开吸气
+                await robot.CalibOutIOAsync(true);
+            }
+            else
+            {
+                //张开夹爪
+                //夹爪张开为false,夹爪闭合为True
+                await robot.CalibOutIOAsync(false);
+            }
+
+            //移动独立模组至待机点
+            bool isFinished = await ((XYZU_Robot)robot).WaitCameraMoveFinishedAsync(calibrationInfo.CameraMotionModuleIndex, calibrationInfo.IndependentDownCameraMotionModulePoint);
+            if (!isFinished)
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+
+            var view = new ShowMessage(Lang.提示, Lang.请将校准块放置在吸嘴中心);
+            var result = await DialogHost.Show(view, "CalibToolDialog", null, null, null);
+            if (!((bool)result)) return (false, null, 0, 0, 0, 0);
+            if (calibrationInfo.Pick.PickPlaceModel == Enums.PickPlaceModel.Clamp)
+            {
+                //夹紧夹爪
+                await robot.CalibOutIOAsync(true);
+            }
+
+            //计算相机与机器人坐标系的旋转矩阵
+            var robotCameraRotationMatrix = await AutoIdentifyRobotCameraRotationMatrix(calibrationInfo, robot, cancellationToken);
+            if (!robotCameraRotationMatrix.IsSuccess)
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+            pixelScaleX = robotCameraRotationMatrix.PixelScaleX;
+            pixelScaleY = robotCameraRotationMatrix.PixelScaleY;
+            RobotCameraRotationMatrix = robotCameraRotationMatrix.Item2;
+            //相机拍照并处理图像
+            var photoResult = await CaptureAndProcessCallback();
+            if (!photoResult.IsSuccess)
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+            PointF P0 = new PointF((float)(photoResult.X), (float)(photoResult.Y));
+
+            RPoint RobotU = calibrationInfo.CenterPoint.Clone();
+            RobotU.U += (float)calibrationInfo.Angle;
+            //移动机器人中心点
+            await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+
+            //机器人U轴旋转
+            await robot.CalibMotionAsync(RobotU, null);
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+
+            //相机拍照并处理图像
+            photoResult = await CaptureAndProcessCallback();
+            if (!photoResult.IsSuccess)
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+            PointF curPixel = new PointF((float)(photoResult.X), (float)(photoResult.Y));
+
+            bool IsFinish = false;
+            for (int i = 0; i < 10; i++)
+            {
+                //计算需要移动的偏移量,目的是逼近中心点
+                double offsetx = (P0.X - curPixel.X) * pixelScaleX;
+                double offsety = (P0.Y - curPixel.Y) * pixelScaleY;
+                var pos = RobotCameraRotationMatrix.Inverse() * Vector<double>.Build.Dense(new double[] { offsetx, offsety });
+
+                RobotU.X += (float)pos[0];
+                RobotU.Y += (float)pos[1];
+                //机器人移动
+                await robot.CalibMotionAsync(RobotU, null);
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return (false, null, 0, 0, 0, 0);
+                }
+
+                photoResult = await CaptureAndProcessCallback();
+                if (!photoResult.IsSuccess)
+                {
+                    return (false, null, 0, 0, 0, 0);
+                }
+                curPixel = new PointF((float)(photoResult.X), (float)(photoResult.Y));
+                offsetx = P0.X - curPixel.X;
+                offsety = P0.Y - curPixel.Y;
+                //await Console.Out.WriteLineAsync($"移动后的差异:{offsetx},{offsety}");
+                if (Math.Abs(offsetx) < 1 && Math.Abs(offsetx) < 1)
+                {
+                    //移动机器人至待机位置
+                    await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
+                    IsFinish = true;
+                    break;
+                }
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return (false, null, 0, 0, 0, 0);
+                }
+            }
+
+            if (IsFinish)
+            {
+                Vector<double> p0 = Vector<double>.Build.Dense(new double[] { calibrationInfo.CenterPoint.X, calibrationInfo.CenterPoint.Y });
+                Vector<double> p1 = Vector<double>.Build.Dense(new double[] { RobotU.X, RobotU.Y });
+                ToolCoord toolCoord = new ToolCoord();
+                double u1 = calibrationInfo.CenterPoint.U;
+                double u2 = RobotU.U;
+                if (robot.Brand == Enums.RobotBrand.Schneider)
+                {
+                    u1 *= -1;
+                    u2 *= -1;
+                }
+                toolCoord.ComputeTool(p0, p1, u1, u2);
+                if (calibrationInfo.Tool == null)
+                {
+                    calibrationInfo.Tool = new RobotTool();
+                }
+                calibrationInfo.Tool.X = toolCoord.X;
+                calibrationInfo.Tool.Y = toolCoord.Y;
+                return (true, RobotCameraRotationMatrix, calibrationInfo.Tool.X, calibrationInfo.Tool.Y, pixelScaleX, pixelScaleY);
+            }
+            else
+            {
+                return (false, null, 0, 0, 0, 0);
+            }
+        }
+
         /// <summary>
         /// 通过未标定的相机校准工具坐标。
         /// 当相机内参未知或未可靠标定时,通过已知机器人位姿与图像特征的对应关系反推工具坐标与像素尺度。
@@ -459,6 +615,10 @@ namespace TeamAAS_VP.Services
             {
                 calibresult = await CalibrateJ4MovingDownCameraTool(calibrationInfo, robot, cancellationToken);
             }
+            else if (calibrationInfo.CameraMount == Enums.CameraMount.MobileDown_IndependentXYPlatform)
+            {
+                calibresult = await CalibrateIndependentXYPlatformMovingDownCameraTool(calibrationInfo, robot, cancellationToken);
+            }
             else
             {
                 return (false, null, 0, 0, 0, 0);
@@ -498,7 +658,7 @@ namespace TeamAAS_VP.Services
             //移动机器人至中心点
             if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown && !calibrationInfo.FixedDownCameraNoReturnToHome)
             {
-                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
                 //关闭吸气
                 await robot.CalibOutIOAsync(false);
             }
@@ -517,7 +677,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown && !calibrationInfo.FixedDownCameraNoReturnToHome)
             {
                 //移动机器人至待机位置
-                await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             }
 
             //相机拍照并处理图像
@@ -532,7 +692,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown && !calibrationInfo.FixedDownCameraNoReturnToHome)
             {
                 //移动机器人至P0
-                await robot.CalibMotionAsync(RobotP0, 0);
+                await robot.CalibMotionAsync(RobotP0, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0);
@@ -540,7 +700,7 @@ namespace TeamAAS_VP.Services
                 //打开吸气
                 await robot.CalibOutIOAsync(true);
                 //移动机器人至P1
-                await robot.CalibMotionAsync(RobotP1, 0);
+                await robot.CalibMotionAsync(RobotP1, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0);
@@ -548,7 +708,7 @@ namespace TeamAAS_VP.Services
                 //关闭吸气
                 await robot.CalibOutIOAsync(false);
                 //移动机器人至待机位置
-                await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             }
             else
             {
@@ -573,7 +733,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown && !calibrationInfo.FixedDownCameraNoReturnToHome)
             {
                 //移动机器人至P1
-                await robot.CalibMotionAsync(RobotP1, 0);
+                await robot.CalibMotionAsync(RobotP1, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0);
@@ -581,7 +741,7 @@ namespace TeamAAS_VP.Services
                 //打开吸气
                 await robot.CalibOutIOAsync(true);
                 //移动机器人至P2
-                await robot.CalibMotionAsync(RobotP2, 0);
+                await robot.CalibMotionAsync(RobotP2, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0);
@@ -589,7 +749,7 @@ namespace TeamAAS_VP.Services
                 //关闭吸气
                 await robot.CalibOutIOAsync(false);
                 //移动机器人至待机位置
-                await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             }
             else
             {
@@ -614,7 +774,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown && !calibrationInfo.FixedDownCameraNoReturnToHome)
             {
                 //移动机器人至P2
-                await robot.CalibMotionAsync(RobotP2, 0);
+                await robot.CalibMotionAsync(RobotP2, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0);
@@ -622,7 +782,7 @@ namespace TeamAAS_VP.Services
                 //打开吸气
                 await robot.CalibOutIOAsync(true);
                 //移动机器人至P0
-                await robot.CalibMotionAsync(RobotP0, 0);
+                await robot.CalibMotionAsync(RobotP0, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, 0, 0);
@@ -630,7 +790,7 @@ namespace TeamAAS_VP.Services
                 //关闭吸气
                 await robot.CalibOutIOAsync(false);
                 //移动机器人至待机位置
-                await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             }
             else
             {
@@ -773,7 +933,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo == null) return (false, null, null, null);
             if (robot == null || !robot.IsConnected) return (false, null, null, null);
 
-            
+
             //发送校准的参数
             await robot.CalibParameAsync(calibrationInfo.Pick, calibrationInfo.Speed, calibrationInfo.Accel, calibrationInfo.Power, calibrationInfo.WaitSuction, calibrationInfo.WaitBlow);
 
@@ -782,7 +942,7 @@ namespace TeamAAS_VP.Services
             {
 
                 //移动机器人至中心位置
-                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, null, null);
@@ -808,14 +968,15 @@ namespace TeamAAS_VP.Services
 
                 calibrationInfo.RobotCameraRotationMatrix = robotCameraRotationMatrix.RotationMatrix.ToArray();
             }
-            else if (calibrationInfo.CameraMount== Enums.CameraMount.MobileDown_XYPlatform)
+            else if (calibrationInfo.CameraMount == Enums.CameraMount.MobileDown_XYPlatform)
             {
                 //移动机器人至中心位置
-                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, null, null);
                 }
+
                 //计算相机与机器人坐标系的旋转矩阵
                 var robotCameraRotationMatrix = await AutoIdentifyRobotCameraRotationMatrix(calibrationInfo, robot, cancellationToken);
                 if (!robotCameraRotationMatrix.IsSuccess)
@@ -834,6 +995,15 @@ namespace TeamAAS_VP.Services
 
                 calibrationInfo.RobotCameraRotationMatrix = robotCameraRotationMatrix.RotationMatrix.ToArray();
             }
+            else if (calibrationInfo.CameraMount == Enums.CameraMount.MobileDown_IndependentXYPlatform)
+            {
+                //移动独立模组至待机点
+                bool isFinished = await ((XYZU_Robot)robot).WaitCameraMoveFinishedAsync(calibrationInfo.CameraMotionModuleIndex, calibrationInfo.IndependentDownCameraMotionModulePoint);
+                if (!isFinished)
+                {
+                    return (false, null, null, null);
+                }
+            }
 
             double IntervalX = calibrationInfo.Width / 2;
             double IntervalY = calibrationInfo.Height / 2;
@@ -1002,7 +1172,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo.CameraMount == Enums.CameraMount.MobileJ4)
             {
                 //移动机器人至中心位置
-                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.CenterPoint, null);
                 if (cancellationToken.IsCancellationRequested)
                 {
                     return (false, null, null, null);
@@ -1028,7 +1198,7 @@ namespace TeamAAS_VP.Services
                 //移动机器人至i
                 if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown)
                 {
-                    await robot.CalibMotionAsync(rPoints[i], 0);
+                    await robot.CalibMotionAsync(rPoints[i], null);
                     if (cancellationToken.IsCancellationRequested)
                     {
                         return (false, null, null, null);
@@ -1036,7 +1206,7 @@ namespace TeamAAS_VP.Services
                     //关闭吸气
                     await robot.CalibOutIOAsync(false);
                     //移动机器人至待机位置
-                    await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                    await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
                 }
                 else
                 {
@@ -1059,7 +1229,7 @@ namespace TeamAAS_VP.Services
                 if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown)
                 {
                     //移动机器人至i
-                    await robot.CalibMotionAsync(rPoints[i], 0);
+                    await robot.CalibMotionAsync(rPoints[i], null);
                     if (cancellationToken.IsCancellationRequested)
                     {
                         return (false, null, null, null);
@@ -1082,7 +1252,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown)
             {
                 //移动机器人至待机位置
-                await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             }
 
             if (cancellationToken.IsCancellationRequested)
@@ -1327,7 +1497,7 @@ namespace TeamAAS_VP.Services
                 if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown)
                 {
                     //移动机器人至i
-                    await robot.CalibMotionAsync(rPoints[i], 0);
+                    await robot.CalibMotionAsync(rPoints[i], null);
                     if (cancellationToken.IsCancellationRequested)
                     {
                         return (false, null);
@@ -1335,7 +1505,7 @@ namespace TeamAAS_VP.Services
                     //关闭吸气
                     await robot.CalibOutIOAsync(false);
                     //移动机器人至待机位置
-                    await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                    await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
                 }
                 else
                 {
@@ -1361,7 +1531,7 @@ namespace TeamAAS_VP.Services
                 if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown)
                 {
                     //移动机器人至i
-                    await robot.CalibMotionAsync(rPoints[i], 0);
+                    await robot.CalibMotionAsync(rPoints[i], null);
                     //打开吸气
                     await robot.CalibOutIOAsync(true);
                 }
@@ -1375,7 +1545,7 @@ namespace TeamAAS_VP.Services
             if (calibrationInfo.CameraMount == Enums.CameraMount.FixedDown)
             {
                 //移动机器人至待机位置
-                await robot.CalibMotionAsync(calibrationInfo.HomePoint, 0);
+                await robot.CalibMotionAsync(calibrationInfo.HomePoint, null);
             }
 
             //RMS(均方根值) 标定偏差
@@ -1484,6 +1654,18 @@ namespace TeamAAS_VP.Services
             return (true, calibrationTestResult);
         }
 
+        /// <summary>
+        /// 独立模组相机计算独立模组步进坐标系与绝对坐标系的刚体变换矩阵
+        /// </summary>
+        /// <param name="markPoint"></param>
+        /// <param name="calibPoints"></param>
+        /// <returns></returns>
+        public (bool IsSuccess, double[,] TransformationMatrix) CalculateIndependentCameraRigidTransformationMatrix(CalibrationInfo calibrationInfo, IRobot robot, CancellationToken cancellationToken)
+        {
+            //模组移动Mark至相机中心点,此时Mark的绝对坐标是:P0,步进坐标:P1
+
+        }
+
         public void Dispose()
         {
             GC.SuppressFinalize(this);

+ 1 - 0
TeamAAS-VM/TeamAAS-VP.csproj

@@ -1575,6 +1575,7 @@
   </ItemGroup>
   <ItemGroup>
     <Content Include="Resources\ddraw.dll" />
+    <Resource Include="Resources\Images\MobileDown_IndependentXYPlatform.png" />
     <Content Include="Resources\SciCamera.Net.dll" />
     <Resource Include="Resources\Images\MobileDown.png" />
     <Content Include="Resources\GxIAPINET.dll" />

+ 3 - 0
TeamAAS-VM/ValueConverter/CameraMountConverter.cs

@@ -39,6 +39,9 @@ namespace TeamAAS_VP.ValueConverter
                 case CameraMount.MobileDown_XYPlatform:
                     imageName = "MobileDown.png";
                     break;
+                case CameraMount.MobileDown_IndependentXYPlatform:
+                    imageName = "MobileDown_IndependentXYPlatform.png";
+                    break;
                 default:
                     break;
             }

+ 38 - 1
TeamAAS-VM/ViewModels/Calibration/CalibrationTeachCenterPointViewModel.cs

@@ -14,6 +14,7 @@ using System.Windows;
 using Team.FFFeederService.Interfaces;
 using TeamAAS_VP;
 using TeamAAS_VP.Core;
+using TeamAAS_VP.Core.Robots;
 using TeamAAS_VP.Events;
 using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
@@ -105,6 +106,10 @@ namespace TeamAAS_VP.ViewModels.Calibration
         public DelegateCommand MoveCenterCommand =>
             _MoveCenterCommand ?? (_MoveCenterCommand = new DelegateCommand(ExecuteMoveCenterCommand));
 
+        private DelegateCommand _TechIndependentDownCameraMotionModulePointCommand;
+        public DelegateCommand TechIndependentDownCameraMotionModulePointCommand =>
+            _TechIndependentDownCameraMotionModulePointCommand ?? (_TechIndependentDownCameraMotionModulePointCommand = new DelegateCommand(ExecuteTechIndependentDownCameraMotionModulePointCommand));
+
         
         #endregion
 
@@ -311,7 +316,7 @@ namespace TeamAAS_VP.ViewModels.Calibration
                 }
 
 
-                await Robot.CalibMotionAsync(SelectCalibration.CenterPoint,0);
+                await Robot.CalibMotionAsync(SelectCalibration.CenterPoint,null);
                 
                 LogHelper.WriteLogInfo($"相机校准-移动机器人至中心点界面示教待机点");
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = $"成功! X:{SelectCalibration.CenterPoint.X} Y:{SelectCalibration.CenterPoint.Y}  Z:{SelectCalibration.CenterPoint.Z}", Duration = 1 });
@@ -322,6 +327,38 @@ namespace TeamAAS_VP.ViewModels.Calibration
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
             }
         }
+
+        /// <summary>
+        /// 示教独立XY模组移动点
+        /// </summary>
+        async void ExecuteTechIndependentDownCameraMotionModulePointCommand()
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                var curpos = await ((XYZU_Robot)Robot).GetCameraPosAsync(SelectCalibration.CameraMotionModuleIndex);
+                if (SelectCalibration.IndependentDownCameraMotionModulePoint == null)
+                {
+                    SelectCalibration.IndependentDownCameraMotionModulePoint = new RPoint();
+                }
+                SelectCalibration.IndependentDownCameraMotionModulePoint.X = curpos.X;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.Y = curpos.Y;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.Z = curpos.Z;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.U = curpos.U;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.V = curpos.V;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.W = curpos.W;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.Hand = curpos.Hand;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.Local = curpos.Local;
+                SelectCalibration.IndependentDownCameraMotionModulePoint.Tool = curpos.Tool;
+                LogHelper.WriteLogInfo($"相机校准-示教独立XY模组移动点:X:{SelectCalibration.IndependentDownCameraMotionModulePoint.X} Y:{SelectCalibration.IndependentDownCameraMotionModulePoint.Y}  Z:{SelectCalibration.IndependentDownCameraMotionModulePoint.Z} ");
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = $"成功! X:{SelectCalibration.IndependentDownCameraMotionModulePoint.X} Y:{SelectCalibration.IndependentDownCameraMotionModulePoint.Y}  Z:{SelectCalibration.IndependentDownCameraMotionModulePoint.Z}", Duration = 1 });
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("相机校准-示教独立XY模组移动点时出错!", ex);
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
+            }
+        }
         #endregion
 
         #region 继承

+ 6 - 6
TeamAAS-VM/ViewModels/Calibration/FixedUpCameraFindP0ViewModel.cs

@@ -369,7 +369,7 @@ namespace TeamAAS_VP.ViewModels.Calibration
                 // 1.移动至标定块放置位置,取标定块
 
                 //移动机器人至下相机位置
-                bool isSuccess = await Robot.CalibMotionAsync(SelectCalibration.PutPoint, 0);
+                bool isSuccess = await Robot.CalibMotionAsync(SelectCalibration.PutPoint, null);
                 if (!isSuccess)
                 {
                     MessageBox.Show("移动至移动至标定块放置位置,取标定块失败!");
@@ -380,7 +380,7 @@ namespace TeamAAS_VP.ViewModels.Calibration
                 await Task.Delay(300);
 
                 // 2.移动至下相机位置,拍照,计算P0点
-                isSuccess = await Robot.CalibMotionAsync(SelectCalibration.DownCameraPoint, 0);
+                isSuccess = await Robot.CalibMotionAsync(SelectCalibration.DownCameraPoint, null);
                 if (!isSuccess)
                 {
                     MessageBox.Show("移动至下相机位置失败!");
@@ -417,7 +417,7 @@ namespace TeamAAS_VP.ViewModels.Calibration
                 }
 
                 // 3.移动至标定块放置位置,放下标定块
-                isSuccess = await Robot.CalibMotionAsync(SelectCalibration.PutPoint, 0);
+                isSuccess = await Robot.CalibMotionAsync(SelectCalibration.PutPoint, null);
                 if (isSuccess)
                 {
                     //关闭吸气
@@ -434,7 +434,7 @@ namespace TeamAAS_VP.ViewModels.Calibration
                 // 4.Z轴上升安全高度
                 RPoint safePoint = SelectCalibration.PutPoint.Clone();
                 safePoint.Z = 0;
-                isSuccess = await Robot.CalibMotionAsync(safePoint, 0);
+                isSuccess = await Robot.CalibMotionAsync(safePoint, null);
                 if (!isSuccess)
                 {
                     MessageBox.Show("Z轴上升至安全高度失败!");
@@ -467,7 +467,7 @@ namespace TeamAAS_VP.ViewModels.Calibration
                     return;
                 }
                 //移动机器人至下相机位置
-                bool isSuccess = await Robot.CalibMotionAsync(SelectCalibration.DownCameraPoint, 0);
+                bool isSuccess = await Robot.CalibMotionAsync(SelectCalibration.DownCameraPoint, null);
                 if (isSuccess)
                 {
                     MessageBox.Show("移动至下相机位置成功!");
@@ -521,7 +521,7 @@ namespace TeamAAS_VP.ViewModels.Calibration
                     return;
                 }
                 //移动机器人至标定块放位置
-                bool isSuccess = await Robot.CalibMotionAsync(SelectCalibration.PutPoint, 0);
+                bool isSuccess = await Robot.CalibMotionAsync(SelectCalibration.PutPoint, null);
                 if (isSuccess)
                 {
                     MessageBox.Show("移动至标定块放位置成功!");

+ 11 - 11
TeamAAS-VM/ViewModels/Product/CalculateOffsetUViewModel.cs

@@ -291,7 +291,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 var pos = ToolInfo.Place.Clone();
                 //pos.Z = 0;
                 //移动机器人至待机位置
-                await Robot.CalibMotionAsync(pos, 0);
+                await Robot.CalibMotionAsync(pos, null);
 
                 //打开吸气
                 await Robot.CalibOutIOAsync(true);
@@ -303,7 +303,7 @@ namespace TeamAAS_VP.ViewModels.Product
 
 
                 //移动机器人至放料位置
-                await Robot.CalibMotionAsync(ToolInfo.Place, 0);
+                await Robot.CalibMotionAsync(ToolInfo.Place, null);
 
                 await Task.Delay(300);
 
@@ -316,13 +316,13 @@ namespace TeamAAS_VP.ViewModels.Product
                 if (calib.CameraMount== Enums.CameraMount.FixedDown && SelectProcedure.FeederId!= Guid.Empty)
                 {
                     //移动机器人至取料位置
-                    await Robot.CalibMotionAsync(ToolInfo.Pick, 0);
+                    await Robot.CalibMotionAsync(ToolInfo.Pick, null);
                     //关闭吸气
                     await Robot.CalibOutIOAsync(false);
                     await Task.Delay(300);
 
                     //移动机器人至待机位置
-                    await Robot.CalibMotionAsync(pos, 0);
+                    await Robot.CalibMotionAsync(pos, null);
 
                     var campos = await Photo();
 
@@ -331,18 +331,18 @@ namespace TeamAAS_VP.ViewModels.Product
                     var posPick = ToolInfo.Pick.Clone();
                     posPick.U += 10;
                     //移动机器人至取料位置
-                    await Robot.CalibMotionAsync(ToolInfo.Pick, 0);
+                    await Robot.CalibMotionAsync(ToolInfo.Pick, null);
                     //打开吸气
                     await Robot.CalibOutIOAsync(true);
                     await Task.Delay(300);
                     //机器人旋转角度
-                    await Robot.CalibMotionAsync(posPick, 0);
+                    await Robot.CalibMotionAsync(posPick, null);
                     //关闭吸气
                     await Robot.CalibOutIOAsync(false);
                     await Task.Delay(300);
 
                     //移动机器人至待机位置
-                    await Robot.CalibMotionAsync(pos, 0);
+                    await Robot.CalibMotionAsync(pos, null);
 
                     var campos1 = await Photo();
 
@@ -375,18 +375,18 @@ namespace TeamAAS_VP.ViewModels.Product
                     ToolInfo.OffsetZ = ToolInfo.Pick.Z;
 
                     //机器人旋转角度
-                    await Robot.CalibMotionAsync(posPick, 0);
+                    await Robot.CalibMotionAsync(posPick, null);
                     //打开吸气
                     await Robot.CalibOutIOAsync(true);
                     await Task.Delay(300);
                     //移动机器人至待机位置
-                    await Robot.CalibMotionAsync(pos, 0);
+                    await Robot.CalibMotionAsync(pos, null);
                 }
                 //目前只考虑到固定向上相机计算工具坐标
                 else
                 {
                     //移动机器人至取料位置
-                    await Robot.CalibMotionAsync(ToolInfo.Pick, 0);
+                    await Robot.CalibMotionAsync(ToolInfo.Pick, null);
                     var campos = await Photo();
 
                     //-------------------------------------------------------------------------------------------
@@ -394,7 +394,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     var posPick = ToolInfo.Pick.Clone();
                     posPick.U += 10;
                     //机器人旋转角度
-                    await Robot.CalibMotionAsync(posPick, 0);
+                    await Robot.CalibMotionAsync(posPick, null);
                     var campos1 = await Photo();
 
                     if (campos1.Item3 - campos.Item3 > 0)

+ 30 - 29
TeamAAS-VM/ViewModels/Product/PlcPointParamsViewModel.cs

@@ -593,7 +593,7 @@ namespace TeamAAS_VP.ViewModels.Product
                         await Robot.GoAsync(point);
                         break;
                     case MotionCommand.Jump:
-                        await Robot.JumpAsync(point, 0);
+                        await Robot.JumpAsync(point, null);
                         break;
                     case MotionCommand.Move:
                         await Robot.MoveAsync(point);
@@ -1083,7 +1083,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     U = SelectedPoint.U_Position,
                     V = SelectedPoint.R_Position,
                 };
-                await Robot.CalibMotionAsync(rpoint, 0);
+                await Robot.CalibMotionAsync(rpoint, null);
 
                 await Robot.CalibParameAsync(new PickInfo() { Inhal = Inhal, Blow = 1 }, 20, 20, true, 200, 200);
                 //打开吸真空
@@ -1092,7 +1092,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 await Task.Delay(500);
 
                 rpoint.Z = 0;
-                await Robot.CalibMotionAsync(rpoint, 0);
+                await Robot.CalibMotionAsync(rpoint, null);
 
                 if (DialogHost.IsDialogOpen("RootDialog"))
                 {
@@ -1151,7 +1151,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     U = SelectedPoint.U_Position,
                     V = SelectedPoint.R_Position,
                 };
-                await Robot.CalibMotionAsync(rpoint, 0);
+                await Robot.CalibMotionAsync(rpoint, null);
                 await Task.Delay(200);
 
                 //获取固定向上相机1的流程
@@ -1261,7 +1261,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     U = Points[0].U_Position,
                     V = Points[0].R_Position,
                 };
-                await Robot.CalibMotionAsync(rpoint, 0);
+                await Robot.CalibMotionAsync(rpoint, null);
                 await Task.Delay(200);
 
                 //获取移动向下相机1的流程
@@ -1303,7 +1303,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     U = Points[1].U_Position,
                     V = Points[1].R_Position,
                 };
-                await Robot.CalibMotionAsync(rpoint, 0);
+                await Robot.CalibMotionAsync(rpoint, null);
                 await Task.Delay(200);
 
                 //获取移动向下相机1的流程
@@ -1412,7 +1412,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     U = (float)angle,
                     V = SelectedPoint.R_Position,
                 };
-                await Robot.CalibMotionAsync(rpoint, 0);
+                await Robot.CalibMotionAsync(rpoint, null);
                 if (DialogHost.IsDialogOpen("RootDialog"))
                 {
                     DialogHost.Close("RootDialog");
@@ -1588,7 +1588,7 @@ namespace TeamAAS_VP.ViewModels.Product
                             break;
                     }
                 }
-                if(pn==null)
+                if (pn == null)
                 {
                     return;
                 }
@@ -1596,7 +1596,7 @@ namespace TeamAAS_VP.ViewModels.Product
 
                 // 1.Z轴上升到安全高度
                 curpos.Z = 0;
-                bool isSuccess = await Robot.CalibMotionAsync(curpos, 0);
+                bool isSuccess = await Robot.CalibMotionAsync(curpos, null);
                 if (!isSuccess)
                 {
                     _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "机器人移动失败!", Duration = 1 });
@@ -1616,7 +1616,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 curpos.Y = pn.Y_Position;
                 curpos.Z = pn.Z_Position_Start;
                 curpos.U = pn.U_Position;
-                isSuccess = await Robot.CalibMotionAsync(curpos, 0);
+                isSuccess = await Robot.CalibMotionAsync(curpos, null);
                 if (!isSuccess)
                 {
                     _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "机器人移动失败!", Duration = 1 });
@@ -1738,20 +1738,21 @@ namespace TeamAAS_VP.ViewModels.Product
                     for (int i = 0; i < points.Length; i++)
                     {
                         //如果当前的取料点数量小于等于i,则新增一个取料点
-                        if(SelectProduct.PickPoints.Count<=i)
+                        if (SelectProduct.PickPoints.Count <= i)
                         {
-                            SelectProduct.PickPoints.Add(new PlcPoint() 
-                            { Number=i+1,
-                                X_Position= points[i].X_Position ,
-                                X_Velocity=100,
-                                Y_Position= points[i].Y_Position ,
-                                Y_Velocity=100,
-                                Z_Position_Start= points[i].Z_Position_Start,
-                                Z_Velocity_Start=100,
-                            U_Position= points[i].U_Position,
-                            U_Velocity=100,
-                            Z_Position_Stop= points[i].Z_Position_Stop,
-                            Z_Velocity_Stop=100,
+                            SelectProduct.PickPoints.Add(new PlcPoint()
+                            {
+                                Number = i + 1,
+                                X_Position = points[i].X_Position,
+                                X_Velocity = 100,
+                                Y_Position = points[i].Y_Position,
+                                Y_Velocity = 100,
+                                Z_Position_Start = points[i].Z_Position_Start,
+                                Z_Velocity_Start = 100,
+                                U_Position = points[i].U_Position,
+                                U_Velocity = 100,
+                                Z_Position_Stop = points[i].Z_Position_Stop,
+                                Z_Velocity_Stop = 100,
                             });
                         }
                         else
@@ -1789,15 +1790,15 @@ namespace TeamAAS_VP.ViewModels.Product
                             {
                                 Number = index + 1,
                                 X_Position = points[i].X_Position,
-                                X_Velocity=100,
+                                X_Velocity = 100,
                                 Y_Position = points[i].Y_Position,
-                                Y_Velocity=100,
+                                Y_Velocity = 100,
                                 Z_Position_Start = points[i].Z_Position_Start,
-                                Z_Velocity_Start=100,
+                                Z_Velocity_Start = 100,
                                 U_Position = points[i].U_Position,
-                                U_Velocity=100,
+                                U_Velocity = 100,
                                 Z_Position_Stop = points[i].Z_Position_Stop,
-                                Z_Velocity_Stop=100,
+                                Z_Velocity_Stop = 100,
                             });
                         }
                         else
@@ -1873,7 +1874,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     }
                 }
                 CameraList = new ObservableCollection<CameraInfo>(_configService.GetAllCameras());
-                Pallet1 = new PalletEx() { Row = 4, Column = 2 ,P1=new PlcPoint(),P0=new PlcPoint(),P2=new PlcPoint()};
+                Pallet1 = new PalletEx() { Row = 4, Column = 2, P1 = new PlcPoint(), P0 = new PlcPoint(), P2 = new PlcPoint() };
                 Pallet2 = new PalletEx() { Row = 4, Column = 2, P1 = new PlcPoint(), P0 = new PlcPoint(), P2 = new PlcPoint() };
 
             }

+ 20 - 16
TeamAAS-VM/ViewModels/Product/RobotPointParamsViewModel.cs

@@ -51,7 +51,8 @@ namespace TeamAAS_VP.ViewModels.Product
         public RobotPointStore SelectedRobot
         {
             get { return _SelectedRobot; }
-            set {
+            set
+            {
                 if (SetProperty(ref _SelectedRobot, value))
                 {
                     try
@@ -82,7 +83,7 @@ namespace TeamAAS_VP.ViewModels.Product
         public RPoint SelectPoint
         {
             get { return _SelectPoint; }
-            set { SetProperty(ref _SelectPoint,value); }
+            set { SetProperty(ref _SelectPoint, value); }
         }
 
         private RPoint _selectedPointInDataGrid;
@@ -97,7 +98,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 }
                 // 可以同步到 SelectPoint 属性
                 SelectPoint = value;
-                
+
             }
         }
 
@@ -113,7 +114,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 }
                 // 可以同步到 SelectPoint 属性
                 SelectPoint = value;
-                
+
             }
         }
 
@@ -124,7 +125,7 @@ namespace TeamAAS_VP.ViewModels.Product
         public MotionCommand SelectMotionCommand
         {
             get { return _SelectMotionCommand; }
-            set { SetProperty(ref _SelectMotionCommand,value); }
+            set { SetProperty(ref _SelectMotionCommand, value); }
         }
 
         public Management management { get; set; }
@@ -137,7 +138,7 @@ namespace TeamAAS_VP.ViewModels.Product
             set
             {
                 SetProperty(ref _Robot, value);
-                
+
             }
         }
 
@@ -164,7 +165,7 @@ namespace TeamAAS_VP.ViewModels.Product
             }
         }
 
-        private ObservableCollection<int> _Tools = new ObservableCollection<int>(new int[] {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});
+        private ObservableCollection<int> _Tools = new ObservableCollection<int>(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });
         /// <summary>
         /// 机器人Tool集合
         /// </summary>
@@ -181,10 +182,12 @@ namespace TeamAAS_VP.ViewModels.Product
         public int SelectTool
         {
             get { return _SelectTool; }
-            set { SetProperty(ref _SelectTool, value); 
+            set
+            {
+                SetProperty(ref _SelectTool, value);
                 if (value >= 0)
                 {
-                    if (Robot!=null && Robot.IsConnected)
+                    if (Robot != null && Robot.IsConnected)
                     {
                         try
                         {
@@ -227,7 +230,7 @@ namespace TeamAAS_VP.ViewModels.Product
 
         private DelegateCommand<object> _ExecuteMotion;
         public DelegateCommand<object> ExecuteMotion =>
-            _ExecuteMotion ?? (_ExecuteMotion = new DelegateCommand<object>(ExecuteExecuteMotion).ObservesCanExecute(() => CanExecute).ObservesProperty(()=>Robot).ObservesProperty(()=>Robot.CanExecute));
+            _ExecuteMotion ?? (_ExecuteMotion = new DelegateCommand<object>(ExecuteExecuteMotion).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
 
         private DelegateCommand<object> _JogCommand;
         public DelegateCommand<object> JogCommand =>
@@ -257,7 +260,7 @@ namespace TeamAAS_VP.ViewModels.Product
         public DelegateCommand RobotSelectedChangedCommand =>
             _RobotSelectedChangedCommand ?? (_RobotSelectedChangedCommand = new DelegateCommand(ExecuteRobotSelectedChangedCommand));
 
-        
+
         #endregion
 
         #region 事件
@@ -312,7 +315,8 @@ namespace TeamAAS_VP.ViewModels.Product
                 DialogParameters dialogParameters = new DialogParameters();
                 dialogParameters.Add("SelectProduct", SelectProduct);
                 dialogParameters.Add("SelectedRobot", SelectedRobot);
-                _dialogService.Show("PalletManage", dialogParameters, rst => {
+                _dialogService.Show("PalletManage", dialogParameters, rst =>
+                {
                     //对话框关闭之后的回调函数,可以在这解析结果。
                     ButtonResult result1 = rst.Result;
 
@@ -415,7 +419,7 @@ namespace TeamAAS_VP.ViewModels.Product
                         await Robot.GoAsync(point);
                         break;
                     case MotionCommand.Jump:
-                        await Robot.JumpAsync(point, 0);
+                        await Robot.JumpAsync(point, null);
                         break;
                     case MotionCommand.Move:
                         await Robot.MoveAsync(point);
@@ -430,7 +434,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
             }
         }
-        
+
         /// <summary>
         /// 示教点位
         /// </summary>
@@ -616,14 +620,14 @@ namespace TeamAAS_VP.ViewModels.Product
             {
                 SelectProduct = navigationContext.Parameters.GetValue<ProductModel>("SelectProduct");
 
-                if (SelectProduct.RobotPoint.Robots.Count>0)
+                if (SelectProduct.RobotPoint.Robots.Count > 0)
                 {
                     SelectedRobot = SelectProduct.RobotPoint.Robots.FirstOrDefault();
                     Robot = _robotService.GetRobot(SelectedRobot.Id);
                     SelectedPointInDataGrid = SelectedRobot.Points.FirstOrDefault();
                     SelectedPointInComboBox = SelectedPointInDataGrid;
                 }
-                
+
 
                 if (Robot != null && Robot.IsConnected)
                 {

+ 5 - 5
TeamAAS-VM/ViewModels/Product/TestProductPageViewModel.cs

@@ -394,7 +394,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 var pos = SelectPoint.Clone();
                 //pos.Z = 0;
                 //移动机器人至待机位置
-                await Robot.CalibMotionAsync(pos, 0);
+                await Robot.CalibMotionAsync(pos, null);
                 //打开光源
                 await Feeder.OpenLightAsync();
                 await Feeder.SetLightValueAsync((ushort)SelectProcedure.LightValue);
@@ -409,7 +409,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 await Task.Delay(300);
 
                 //移动机器人至待机位置
-                await Robot.CalibMotionAsync(pos, 0);
+                await Robot.CalibMotionAsync(pos, null);
 
                 var campos = await Photo(SelectProcedure, Camera);
 
@@ -432,12 +432,12 @@ namespace TeamAAS_VP.ViewModels.Product
                 Target.Tool = 2;
 
                 //取料
-                await Robot.CalibMotionAsync(Target, 0);
+                await Robot.CalibMotionAsync(Target, null);
                 await Task.Delay(200);
                 await Robot.CalibOutIOAsync(true);
 
                 //移动机器人至待机位置
-                await Robot.CalibMotionAsync(pos, 0);
+                await Robot.CalibMotionAsync(pos, null);
 
                 //打开光源
                 await Feeder.CloseLightAsync();
@@ -484,7 +484,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 var pos = SelectPoint1.Clone();
                 //pos.Z = 0;
                 //移动机器人至待机位置
-                await Robot1.CalibMotionAsync(pos, 0);
+                await Robot1.CalibMotionAsync(pos, null);
 
                 var calib = _calibrationService.GetAllCalibrations().FirstOrDefault(cal => cal.Id == SelectProcedure1.CalibrationId);
                 if (calib == null)

+ 27 - 0
TeamAAS-VM/Views/Calibration/CalibrationBasics.xaml

@@ -4,6 +4,7 @@
              xmlns:prism="http://prismlibrary.com/"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
              xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
              xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
              xmlns:sys="clr-namespace:System;assembly=mscorlib"
@@ -204,6 +205,32 @@
                         <localbehaviors:ComboBoxSelectionBehavior UserSelectionCommand="{Binding SelectCameraMountChangedCommand}" />
                     </b:Interaction.Behaviors>
                 </ComboBox>
+                <mah:NumericUpDown Grid.Row="3"
+                                   Grid.Column="1"
+                                   HorizontalAlignment="Right"
+                                   Margin="0,0,-65,0"
+                                   Width="50"
+                                   Height="30"
+                                   Minimum="0"
+                                   Interval="1"
+                                   Maximum="4"
+                                   d:Visibility="Visible"
+                                   Value="{Binding SelectCalibration.CameraMotionModuleIndex,Mode=TwoWay}"
+                                   ToolTip="相机运动模组编号">
+                    <mah:NumericUpDown.Style>
+                        <Style TargetType="mah:NumericUpDown">
+                            <Setter Property="Visibility"
+                                    Value="Collapsed" />
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding SelectCalibration.CameraMount}"
+                                             Value="{x:Static enums:CameraMount.MobileDown_IndependentXYPlatform}">
+                                    <Setter Property="Visibility"
+                                            Value="Visible" />
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </mah:NumericUpDown.Style>
+                </mah:NumericUpDown>
 
                 <TextBlock Text="{lex:Loc 取料方式,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}"
                            Grid.Row="4"

+ 1 - 1
TeamAAS-VM/Views/Calibration/CalibrationCameraParams.xaml

@@ -64,7 +64,7 @@
                                    d:IsRightDrawerOpen="true"
                                    x:Name="DrawerHost">
             <materialDesign:DrawerHost.RightDrawerContent>
-                <uControl:RobotManual x:Name="robotManual" />
+                <uControl:PlcRobotManual x:Name="robotManual" />
             </materialDesign:DrawerHost.RightDrawerContent>
 
             <Grid>

+ 2 - 1
TeamAAS-VM/Views/Calibration/CalibrationCameraParams.xaml.cs

@@ -1,4 +1,5 @@
 using System.Windows.Controls;
+using TeamAAS_VP.Core.Robots;
 using TeamAAS_VP.ViewModels.Calibration;
 using TeamAAS_VP.ViewModels.Product;
 
@@ -23,7 +24,7 @@ namespace TeamAAS_VP.Views.Calibration
         {
             if (e.PropertyName=="Robot")
             {
-                this.robotManual.Robot = VM.Robot;
+                this.robotManual.Robot = VM.Robot as XYZU_Robot;
             }
             else if (e.PropertyName == "Image")
             {

+ 1 - 1
TeamAAS-VM/Views/Calibration/CalibrationEditVision.xaml

@@ -62,7 +62,7 @@
                                    OpenMode="Standard"
                                    x:Name="DrawerHost">
             <materialDesign:DrawerHost.RightDrawerContent>
-                <uControl:RobotManual x:Name="robotManual" />
+                <uControl:PlcRobotManual x:Name="robotManual" />
             </materialDesign:DrawerHost.RightDrawerContent>
 
             <Grid>

+ 2 - 1
TeamAAS-VM/Views/Calibration/CalibrationEditVision.xaml.cs

@@ -1,4 +1,5 @@
 using System.Windows.Controls;
+using TeamAAS_VP.Core.Robots;
 using TeamAAS_VP.ViewModels.Calibration;
 
 namespace TeamAAS_VP.Views.Calibration
@@ -22,7 +23,7 @@ namespace TeamAAS_VP.Views.Calibration
         {
             if (e.PropertyName=="Robot")
             {
-                this.robotManual.Robot = VM.Robot;
+                this.robotManual.Robot = VM.Robot as XYZU_Robot;
             }
         }
     }

+ 78 - 4
TeamAAS-VM/Views/Calibration/CalibrationTeachCenterPoint.xaml

@@ -65,7 +65,7 @@
                                    OpenMode="Modal"
                                    x:Name="DrawerHost">
             <materialDesign:DrawerHost.RightDrawerContent>
-                <uControl:RobotManual x:Name="robotManual" />
+                <uControl:PlcRobotManual x:Name="robotManual" />
             </materialDesign:DrawerHost.RightDrawerContent>
             <Grid VerticalAlignment="Center"
                   HorizontalAlignment="Center"
@@ -82,14 +82,14 @@
                     <RowDefinition Height="auto" />
                     <RowDefinition Height="auto" />
                     <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
                 </Grid.RowDefinitions>
                 <Grid.ColumnDefinitions>
                     <ColumnDefinition Width="auto"
                                       MinWidth="100" />
                     <ColumnDefinition Width="*"
                                       MinWidth="200" />
-                    <ColumnDefinition Width="auto"
-                                      />
+                    <ColumnDefinition Width="auto" />
                 </Grid.ColumnDefinitions>
                 <Grid.Resources>
                     <Style TargetType="TextBlock">
@@ -270,7 +270,81 @@
                                    materialDesign:HintAssist.Hint="{lex:Loc 图像Y方向}"
                                    materialDesign:HintAssist.HelperText="{lex:Loc 图像Y方向}"
                                    Value="{Binding SelectCalibration.Height,Mode=TwoWay}" />
-                <StackPanel Grid.Row="8"
+
+                <TextBlock Text="相机移动模组位置:"
+                           FontWeight="Bold"
+                           Grid.Row="8"
+                           Grid.Column="0"
+                           VerticalAlignment="Center"
+                           d:Visibility="Visible">
+                    <TextBlock.Style>
+                        <Style TargetType="TextBlock">
+                            <Setter Property="Visibility"
+                                    Value="Collapsed" />
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding SelectCalibration.CameraMount}"
+                                             Value="{x:Static enums:CameraMount.MobileDown_IndependentXYPlatform}">
+                                    <Setter Property="Visibility"
+                                            Value="Visible" />
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </TextBlock.Style>
+                </TextBlock>
+                <Button Content="{lex:Loc 示教}"
+                        Grid.Row="8"
+                        Grid.Column="1"
+                        MinWidth="150"
+                        Margin="10,10"
+                        HorizontalAlignment="Center"
+                        VerticalAlignment="Center"
+                        materialDesign:ButtonAssist.CornerRadius="10"
+                        Command="{Binding TechIndependentDownCameraMotionModulePointCommand}"
+                        d:Visibility="Visible">
+                    <Button.Style>
+                        <Style TargetType="Button"
+                               BasedOn="{StaticResource MaterialDesignRaisedButton}">
+                            <Setter Property="Visibility"
+                                    Value="Collapsed" />
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding SelectCalibration.CameraMount}"
+                                             Value="{x:Static enums:CameraMount.MobileDown_IndependentXYPlatform}">
+                                    <Setter Property="Visibility"
+                                            Value="Visible" />
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </Button.Style>
+                </Button>
+                <TextBlock Grid.Row="9"
+                           Grid.ColumnSpan="3"
+                           d:Visibility="Visible">
+                    <TextBlock.Text>
+                        <MultiBinding StringFormat="{}X:{0:F3} mm Y:{1:F3} mm">
+                            <Binding Path="SelectCalibration.IndependentDownCameraMotionModulePoint.X"
+                                     TargetNullValue="0.000"
+                                     FallbackValue="0.000" />
+                            <Binding Path="SelectCalibration.IndependentDownCameraMotionModulePoint.Y"
+                                     TargetNullValue="0.000"
+                                     FallbackValue="0.000" />
+                        </MultiBinding>
+                    </TextBlock.Text>
+                    <TextBlock.Style>
+                        <Style TargetType="TextBlock">
+                            <Setter Property="Visibility"
+                                    Value="Collapsed" />
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding SelectCalibration.CameraMount}"
+                                             Value="{x:Static enums:CameraMount.MobileDown_IndependentXYPlatform}">
+                                    <Setter Property="Visibility"
+                                            Value="Visible" />
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </TextBlock.Style>
+                </TextBlock>
+
+                <StackPanel Grid.Row="10"
                             Grid.ColumnSpan="2"
                             Orientation="Horizontal"
                             HorizontalAlignment="Center">

+ 2 - 1
TeamAAS-VM/Views/Calibration/CalibrationTeachCenterPoint.xaml.cs

@@ -1,4 +1,5 @@
 using System.Windows.Controls;
+using TeamAAS_VP.Core.Robots;
 using TeamAAS_VP.ViewModels.Calibration;
 
 namespace TeamAAS_VP.Views.Calibration
@@ -20,7 +21,7 @@ namespace TeamAAS_VP.Views.Calibration
         {
             if (e.PropertyName== "Robot")
             {
-                this.robotManual.Robot = VM.Robot;
+                this.robotManual.Robot = VM.Robot as XYZU_Robot;
             }
         }
     }

+ 1 - 1
TeamAAS-VM/Views/Calibration/FixedUpCameraFindP0.xaml

@@ -64,7 +64,7 @@
                                    OpenMode="Standard"
                                    x:Name="DrawerHost">
             <materialDesign:DrawerHost.RightDrawerContent>
-                <uControl:RobotManual x:Name="robotManual" />
+                <uControl:PlcRobotManual x:Name="robotManual" />
             </materialDesign:DrawerHost.RightDrawerContent>
 
             <Grid>

+ 2 - 1
TeamAAS-VM/Views/Calibration/FixedUpCameraFindP0.xaml.cs

@@ -1,4 +1,5 @@
 using System.Windows.Controls;
+using TeamAAS_VP.Core.Robots;
 using TeamAAS_VP.ViewModels.Calibration;
 
 namespace TeamAAS_VP.Views.Calibration
@@ -20,7 +21,7 @@ namespace TeamAAS_VP.Views.Calibration
         {
             if (e.PropertyName == "Robot")
             {
-                this.robotManual.Robot = VM.Robot;
+                this.robotManual.Robot = VM.Robot as XYZU_Robot;
             }
         }
     }

+ 27 - 0
TeamAAS-VM/Views/SettingView.xaml

@@ -354,6 +354,7 @@
                                 <RowDefinition />
                                 <RowDefinition />
                                 <RowDefinition />
+                                <RowDefinition />
                             </Grid.RowDefinitions>
                             <Grid.ColumnDefinitions>
                                 <ColumnDefinition Width="auto" />
@@ -540,6 +541,32 @@
                                       HorizontalAlignment="Left"
                                       VerticalAlignment="Center"
                                       Visibility="{Binding SelectRobot.RobotBrand,Converter={StaticResource RobotBrandToVisibiltyConverter}}" />
+                            <!--Z轴的安全高度-->
+                            <TextBlock Grid.Row="8"
+                                       Grid.Column="0"
+                                       Text="Z轴的安全高度: "
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       FontSize="{DynamicResource Font.Size.Body3}"
+                                       HorizontalAlignment="Right"
+                                       VerticalAlignment="Center"/>
+                            <TextBox Text="{Binding SelectRobot.SafeZ,Mode=TwoWay}"
+                                      Grid.Row="8"
+                                      Grid.Column="1"
+                                      Margin="10,0"
+                                      Width="{Binding ElementName=txt_Id,Path=ActualWidth}"
+                                      MinWidth="80"
+                                      FontSize="{DynamicResource Font.Size.Body3}"
+                                      HorizontalContentAlignment="Center"
+                                      HorizontalAlignment="Left"
+                                      VerticalAlignment="Center"
+                                      />
+                            <TextBlock Grid.Row="8"
+                                       Grid.Column="1"
+                                       Text="mm"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       FontSize="{DynamicResource Font.Size.Body3}"
+                                       HorizontalAlignment="Right"
+                                       VerticalAlignment="Center" Margin="0,0,-20,0"/>
                             <!--PLC-->
                             <TextBlock Grid.Row="3"
                                        Grid.Column="0"