Procházet zdrojové kódy

修复拍一打一的点位逻辑

徐孝锋 před 8 měsíci
rodič
revize
59730ac15f

+ 712 - 0
TeamAAS-VM/Controls/PlcRobotManual.xaml

@@ -0,0 +1,712 @@
+<UserControl x:Class="TeamAAS_VP.Controls.PlcRobotManual"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:local="clr-namespace:TeamAAS_VP.Controls"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:sys="clr-namespace:System;assembly=mscorlib"
+             xmlns:uControl="clr-namespace:TeamAAS_VP.Controls"
+             xmlns:convert="clr-namespace:TeamAAS_VP.ValueConverter"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             mc:Ignorable="d"
+             d:Background="White"
+             d:DataContext="{d:DesignInstance Type=local:PlcRobotManual}"
+             FontFamily="{DynamicResource DefaultFont}">
+    <UserControl.Resources>
+        <convert:JogConverter x:Key="JogConverter" />
+    </UserControl.Resources>
+    <ScrollViewer HorizontalAlignment="Stretch"
+                  VerticalAlignment="Stretch">
+        <Grid HorizontalAlignment="Stretch"
+              VerticalAlignment="Top">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="auto" />
+                <RowDefinition Height="auto" />
+                <RowDefinition Height="auto" />
+            </Grid.RowDefinitions>
+
+            <Grid Grid.Row="0"
+                  Margin="10"
+                  HorizontalAlignment="Center">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto" />
+                    <ColumnDefinition Width="auto" />
+                    <ColumnDefinition Width="auto" />
+                    <ColumnDefinition Width="auto" />
+                </Grid.ColumnDefinitions>
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                </Grid.RowDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="Button"
+                           BasedOn="{StaticResource MaterialDesignRaisedDarkButton}">
+                        <Setter Property="Width"
+                                Value="60" />
+                        <Setter Property="Height"
+                                Value="60" />
+                        <Setter Property="FontSize"
+                                Value="13" />
+                        <Setter Property="Padding"
+                                Value="0" />
+                        <Setter Property="HorizontalAlignment"
+                                Value="Center" />
+                        <Setter Property="VerticalAlignment"
+                                Value="Center" />
+                        <Setter Property="Margin"
+                                Value="2" />
+                        <Setter Property="materialDesign:ButtonAssist.CornerRadius"
+                                Value="10" />
+                    </Style>
+                </Grid.Resources>
+                <StackPanel Grid.ColumnSpan="4"
+                            Grid.Row="0"
+                            Grid.Column="0"
+                            VerticalAlignment="Center"
+                            Orientation="Horizontal">
+                    <Button Content="{lex:Loc 上使能}"
+                            Grid.Row="2"
+                            materialDesign:ButtonAssist.CornerRadius="10"
+                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                            Command="{Binding MotorCommand}"
+                            CommandParameter="True" />
+                    <Button Content="{lex:Loc 下使能}"
+                            Grid.Row="3"
+                            Margin="10"
+                            materialDesign:ButtonAssist.CornerRadius="10"
+                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                            Command="{Binding MotorCommand}"
+                            CommandParameter="False" />
+                    <Button Content="{lex:Loc 复位错误}"
+                            Grid.Row="4"
+                            materialDesign:ButtonAssist.CornerRadius="10"
+                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                            Command="{Binding ResetCommand}" />
+                </StackPanel>
+                <Button Grid.Row="2"
+                        Grid.Column="0"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=X-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowLeftBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-X"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="2"
+                        Grid.Column="2"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=X+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowRightBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+X"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="1"
+                        Grid.Column="1"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Y+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowTopBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+Y"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="3"
+                        Grid.Column="1"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Y-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowBottomBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-Y"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="1"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Z+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowTopBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+Z"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="3"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Z-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowBottomBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-Z"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="4"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=U+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisZRotateCounterclockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+U"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="4"
+                        Grid.Column="0"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=U-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisZRotateClockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-U"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <!--<Button Grid.Row="4"
+                        Grid.Column="1"
+                        Grid.ColumnSpan="2"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=V+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisYRotateCounterclockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+V"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="5"
+                        Grid.Column="1"
+                        Grid.ColumnSpan="2"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=V-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisYRotateClockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-V"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>-->
+                <Button Grid.Row="5"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=W+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisXRotateCounterclockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+W"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="5"
+                        Grid.Column="0"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=W-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisXRotateClockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-W"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <StackPanel Grid.Row="6"
+                            Grid.ColumnSpan="7"
+                            Margin="10,10,0,10"
+                            Grid.Column="0"
+                            VerticalAlignment="Center"
+                            Orientation="Horizontal">
+                    <TextBlock Text="{lex:Loc 步进距离}"
+                               VerticalAlignment="Center" />
+                    <uControl:myNumericUpDowm x:Name="txtDistance"
+                                              MinWidth="100"
+                                              Interval="0.1"
+                                              Minimum="0"
+                                              Maximum="100"
+                                              StringFormat="{}{0:N3} mm"
+                                              Value="{Binding Distance,Mode=TwoWay}"
+                                              Margin="10,0" />
+                </StackPanel>
+                <TextBlock Grid.Row="7"
+                           Grid.ColumnSpan="7"
+                           VerticalAlignment="Center"
+                           Margin="10,0">
+                    <TextBlock.Text>
+                        <MultiBinding StringFormat="{}CurPos X: {0:F3} mm Y: {1:F3} mm Z: {2:F3} mm U: {3:F3} °R: {4:F3} °">
+                            <Binding Path="Robot.CurrentPosition.X" />
+                            <Binding Path="Robot.CurrentPosition.Y" />
+                            <Binding Path="Robot.CurrentPosition.Z" />
+                            <Binding Path="Robot.CurrentPosition.U" />
+                            <Binding Path="Robot.CurrentPosition.W" />
+                        </MultiBinding>
+                    </TextBlock.Text>
+                </TextBlock>
+            </Grid>
+            <!--相机轴控制区域-->
+            <!--<Grid Grid.Row="1"
+                  Margin="10,0,10,10">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="*" />
+                    <RowDefinition Height="*" />
+                </Grid.RowDefinitions>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="Button"
+                           BasedOn="{StaticResource MaterialDesignRaisedDarkButton}">
+                        <Setter Property="MinWidth"
+                                Value="50" />
+                        <Setter Property="MinHeight"
+                                Value="30" />
+                        <Setter Property="FontSize"
+                                Value="13" />
+                        <Setter Property="Padding"
+                                Value="0" />
+                        <Setter Property="HorizontalAlignment"
+                                Value="Center" />
+                        <Setter Property="VerticalAlignment"
+                                Value="Center" />
+                        <Setter Property="materialDesign:ButtonAssist.CornerRadius"
+                                Value="10" />
+                    </Style>
+                </Grid.Resources>
+                --><!--相机2--><!--
+                <Border Grid.Row="0"
+                        Grid.Column="0"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机2轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera2CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera2CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="2"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Margin="2,0"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="2" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,X+" />
+                        <Button Grid.Row="3"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowTopBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,Y+" />
+                        <Button Grid.Row="5"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowBottomBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,Y-" />
+                    </Grid>
+                </Border>
+                --><!--相机4--><!--
+                <Border Grid.Row="0"
+                        Grid.Column="1"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机4轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera4CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera4CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="4"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="4"
+                                    Margin="2,0" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,X+" />
+                        <Button Grid.Row="3"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowTopBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,Y+" />
+                        <Button Grid.Row="5"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowBottomBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,Y-" />
+                    </Grid>
+                </Border>
+                --><!--相机1--><!--
+                <Border Grid.Row="1"
+                        Grid.Column="0"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机1轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera1CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera1CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="1"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="1"
+                                    Margin="2,0" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="1,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="1,X+" />
+                    </Grid>
+                </Border>
+                --><!--相机3--><!--
+                <Border Grid.Row="1"
+                        Grid.Column="1"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机3轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera3CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera3CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="3"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="3"
+                                    Margin="2,0" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="3,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="3,X+" />
+                    </Grid>
+                </Border>
+            </Grid>-->
+
+            <!-- 附加轴列表:绑定到视图模型中的 ExtraAxes 集合(每项假定有 Name、Position) -->
+            <ItemsControl Grid.Row="2"
+                          ItemsSource="{Binding AdditionalAxisList}">
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <Border Padding="6"
+                                Margin="0,2"
+                                Background="{DynamicResource MaterialDesignPaper}">
+                            <DockPanel LastChildFill="False"
+                                       VerticalAlignment="Center">
+                                <StackPanel Orientation="Horizontal"
+                                            DockPanel.Dock="Left"
+                                            VerticalAlignment="Center">
+                                    <TextBlock Text="{Binding Name}"
+                                               Width="140"
+                                               VerticalAlignment="Center" />
+                                    <TextBlock Text="{Binding CurrentPosition, StringFormat='{}{0:F3} mm'}"
+                                               Width="140"
+                                               Margin="10,0"
+                                               VerticalAlignment="Center" />
+                                </StackPanel>
+                                <StackPanel Orientation="Horizontal"
+                                            HorizontalAlignment="Right"
+                                            DockPanel.Dock="Right">
+                                    <Button Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisJogMinusCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}">
+                                        <StackPanel Orientation="Vertical">
+                                            <materialDesign:PackIcon Kind="ArrowLeftBold"
+                                                                     Width="26"
+                                                                     Height="26" />
+                                            <TextBlock Text="-"
+                                                       HorizontalAlignment="Center" />
+                                        </StackPanel>
+                                    </Button>
+                                    <Button Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisJogPlusCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}">
+                                        <StackPanel Orientation="Vertical">
+                                            <materialDesign:PackIcon Kind="ArrowRightBold"
+                                                                     Width="26"
+                                                                     Height="26" />
+                                            <TextBlock Text="+"
+                                                       HorizontalAlignment="Center" />
+                                        </StackPanel>
+                                    </Button>
+                                    <Button Content="上使能"
+                                            Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisMotorOnCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}" />
+                                    <Button Content="下使能"
+                                            Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisMotorOffCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}" />
+                                </StackPanel>
+                            </DockPanel>
+                        </Border>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+
+            <materialDesign:Snackbar Grid.RowSpan="2"
+                                     x:Name="snackbar"
+                                     Opacity="0.9"
+                                     HorizontalContentAlignment="Center"
+                                     VerticalAlignment="Top" />
+        </Grid>
+    </ScrollViewer>
+</UserControl>

+ 581 - 0
TeamAAS-VM/Controls/PlcRobotManual.xaml.cs

@@ -0,0 +1,581 @@
+using Prism.Commands;
+using Prism.Ioc;
+using Prism.Mvvm;
+using Prism.Unity;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using TeamAAS_VP.Core.PLCs;
+using TeamAAS_VP.Core.Robots;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Resources.Languages;
+
+namespace TeamAAS_VP.Controls
+{
+    /// <summary>
+    /// PlcRobotManual.xaml 的交互逻辑
+    /// </summary>
+    public partial class PlcRobotManual : UserControl, INotifyPropertyChanged
+    {
+        IConfigService _configService;
+        public PlcRobotManual()
+        {
+            InitializeComponent();
+            DataContext = this;
+        }
+
+        #region 属性
+
+
+        private ObservableCollection<AxisExtended> _AdditionalAxisList;
+        public ObservableCollection<AxisExtended> AdditionalAxisList
+        {
+            get { return _AdditionalAxisList; }
+            set { SetProperty(ref _AdditionalAxisList, value); }
+        }
+
+        private XYZU_Robot _Robot;
+
+        public XYZU_Robot Robot
+        {
+            get { return _Robot; }
+            set
+            {
+                SetProperty(ref _Robot, value);
+                try
+                {
+                    if (value != null)
+                    {
+                        if (_configService == null)
+                            _configService = ((PrismApplication)(App.Current)).Container.Resolve<IConfigService>();
+                        this.Distance = _configService.GetRobotStepDistance(value.Id);
+                    }
+                }
+                catch (Exception)
+                {
+
+                }
+            }
+        }
+
+        private double _Distance = 1;
+
+        public double Distance
+        {
+            get { return _Distance; }
+            set
+            {
+                SetProperty(ref _Distance, value);
+                try
+                {
+                    if (Robot == null)
+                    {
+                        return;
+                    }
+                    if (_configService == null)
+                        _configService = ((PrismApplication)(App.Current)).Container.Resolve<IConfigService>();
+                    _configService.UpdateRobotStepDistance(Robot.Id, value);
+                }
+                catch (Exception)
+                {
+
+                }
+            }
+        }
+        #endregion
+
+        #region 命令
+
+        private DelegateCommand<string> _MotorCommand;
+        public DelegateCommand<string> MotorCommand =>
+            _MotorCommand ?? (_MotorCommand = new DelegateCommand<string>(ExecuteMotorCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+
+
+        private DelegateCommand _ResetCommand;
+        public DelegateCommand ResetCommand =>
+            _ResetCommand ?? (_ResetCommand = new DelegateCommand(ExecuteResetCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+
+
+        private DelegateCommand<object> _JogCommand;
+        public DelegateCommand<object> JogCommand =>
+            _JogCommand ?? (_JogCommand = new DelegateCommand<object>(ExecuteJogCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        //附加轴,轴点动+命令
+        private DelegateCommand<object> _AdditionalAxisJogPlusCommand;
+        public DelegateCommand<object> AdditionalAxisJogPlusCommand =>
+            _AdditionalAxisJogPlusCommand ?? (_AdditionalAxisJogPlusCommand = new DelegateCommand<object>(ExecuteAdditionalAxisJogPlusCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        //附加轴,轴点动-命令
+        private DelegateCommand<object> _AdditionalAxisJogMinusCommand;
+        public DelegateCommand<object> AdditionalAxisJogMinusCommand =>
+            _AdditionalAxisJogMinusCommand ?? (_AdditionalAxisJogMinusCommand = new DelegateCommand<object>(ExecuteAdditionalAxisJogMinusCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        private DelegateCommand<object> _AdditionalAxisMotorOnCommand;
+        public DelegateCommand<object> AdditionalAxisMotorOnCommand =>
+            _AdditionalAxisMotorOnCommand ?? (_AdditionalAxisMotorOnCommand = new DelegateCommand<object>(ExecuteAdditionalAxisMotorOnCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        private DelegateCommand<object> _AdditionalAxisMotorOffCommand;
+        public DelegateCommand<object> AdditionalAxisMotorOffCommand =>
+            _AdditionalAxisMotorOffCommand ?? (_AdditionalAxisMotorOffCommand = new DelegateCommand<object>(ExecuteAdditionalAxisMotorOffCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        //private DelegateCommand<string> _CameraAxisModerOnCommand;
+        //public DelegateCommand<string> CameraAxisModerOnCommand =>
+        //    _CameraAxisModerOnCommand ?? (_CameraAxisModerOnCommand = new DelegateCommand<string>(ExecuteCameraAxisModerOnCommand));
+
+        //private DelegateCommand<string> _CameraAxisModerOffCommand;
+        //public DelegateCommand<string> CameraAxisModerOffCommand =>
+        //    _CameraAxisModerOffCommand ?? (_CameraAxisModerOffCommand = new DelegateCommand<string>(ExecuteCameraAxisModerOffCommand));
+
+        //private DelegateCommand<string> _CameraAxisJogCommand;
+        //public DelegateCommand<string> CameraAxisJogCommand =>
+        //    _CameraAxisJogCommand ?? (_CameraAxisJogCommand = new DelegateCommand<string>(ExecuteCameraAxisJogCommand));
+        #endregion
+
+        #region 事件
+
+        #endregion
+
+        #region 方法
+
+        private void ShowMsg(string msg)
+        {
+            if (snackbar.MessageQueue == null)
+            {
+                snackbar.MessageQueue = new MaterialDesignThemes.Wpf.SnackbarMessageQueue();
+            }
+            snackbar.MessageQueue.Clear();
+            snackbar.MessageQueue?.Enqueue(
+                msg,
+                null,
+                null,
+                null,
+                false,
+                true,
+                TimeSpan.FromSeconds(0.4));
+        }
+
+        /// <summary>
+        /// 电机
+        /// </summary>
+        /// <param name="obj"></param>
+        private async void ExecuteMotorCommand(string obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                await Robot.MotorAsync(Convert.ToBoolean(obj));
+                ShowMsg($"{Lang.完成}!");
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("机器人点击操作时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 重置
+        /// </summary>
+        private async void ExecuteResetCommand()
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                await Robot.ResetAsync();
+
+                ShowMsg($"{Lang.完成}!");
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("重置机器人时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 点动
+        /// </summary>
+        /// <param name="obj"></param>
+        private async void ExecuteJogCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                var items = ((string)obj).Split(':');
+                //如果移动距离大于10mm,则提示用户确认
+                double distance = double.Parse(items[1]);
+                if (Math.Abs(distance) >= 10)
+                {
+                    if (MessageBox.Show($"确认要点动距离 {distance} mm 吗?", "确认点动", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                    {
+                        return;
+                    }
+                }
+                Robot.Timeout = 6000000;
+                switch (items[0])
+                {
+                    case "X+":
+                        await Robot.JogAsync("X", distance);
+                        break;
+                    case "X-":
+                        await Robot.JogAsync("X", -distance);
+                        break;
+                    case "Y+":
+                        await Robot.JogAsync("Y", distance);
+                        break;
+                    case "Y-":
+                        await Robot.JogAsync("Y", -distance);
+                        break;
+                    case "Z+":
+                        await Robot.JogAsync("Z", distance);
+                        break;
+                    case "Z-":
+                        await Robot.JogAsync("Z", -distance);
+                        break;
+                    case "U+":
+                        await Robot.JogAsync("U", distance);
+                        break;
+                    case "U-":
+                        await Robot.JogAsync("U", -distance);
+                        break;
+                    case "V+":
+                        await Robot.JogAsync("V", distance);
+                        break;
+                    case "V-":
+                        await Robot.JogAsync("V", -distance);
+                        break;
+                    case "W+":
+                        await Robot.JogAsync("W", distance);
+                        break;
+                    case "W-":
+                        await Robot.JogAsync("W", -distance);
+                        break;
+                    default:
+                        break;
+                }
+                Robot.Timeout = 5000;
+
+
+                ShowMsg($"{Lang.完成}!");
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("机器点动时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        private bool CanExecute
+        {
+            get
+            {
+                if (Robot != null)
+                {
+                    return Robot.CanExecute;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 附加轴+点动
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisJogPlusCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    //如果移动距离大于10mm,则提示用户确认
+                    if (Math.Abs(Distance) >= 10)
+                    {
+                        if (MessageBox.Show($"确认要点动距离 {Distance} mm 吗?", "确认点动", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                        {
+                            return;
+                        }
+                    }
+                    await Robot.AdditionalAxisJogAsync(axis.Name, Distance);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴点动+时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 附加轴-点动
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisJogMinusCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    //如果移动距离大于10mm,则提示用户确认
+                    if (Math.Abs(Distance) >= 10)
+                    {
+                        if (MessageBox.Show($"确认要点动距离 {Distance} mm 吗?", "确认点动", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                        {
+                            return;
+                        }
+                    }
+                    await Robot.AdditionalAxisJogNegAsync(axis.Name, Distance);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴点动-时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 附加轴上使能
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisMotorOffCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    await Robot.AdditionalAxisMotorAsync(axis.Name, true);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴上使能时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 附加轴下使能
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisMotorOnCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    await Robot.AdditionalAxisMotorAsync(axis.Name, true);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴下使能时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        #region 相机控制
+        ///// <summary>
+        ///// 轴电机下使能操作
+        ///// </summary>
+        ///// <param name="parameter"></param>
+        //async void ExecuteCameraAxisModerOffCommand(string parameter)
+        //{
+        //    try
+        //    {
+        //        int cameraIndex = int.Parse(parameter);
+        //        var isSuccess = await Robot.CameraMotorAsync(cameraIndex, false);
+        //        if (isSuccess)
+        //        {
+        //            ShowMsg($"{Lang.完成}!");
+        //        }
+        //        else
+        //        {
+        //            ShowMsg("相机轴下使能失败!");
+        //        }
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        LogHelper.WriteLogError("相机轴下使能时出错!", ex);
+        //        ShowMsg(ex.Message);
+        //    }
+        //}
+
+        ///// <summary>
+        ///// 轴电机上使能操作
+        ///// </summary>
+        ///// <param name="parameter"></param>
+        //async void ExecuteCameraAxisModerOnCommand(string parameter)
+        //{
+        //    try
+        //    {
+        //        int cameraIndex = int.Parse(parameter);
+        //        var isSuccess = await Robot.CameraMotorAsync(cameraIndex, true);
+        //        if (isSuccess)
+        //        {
+        //            ShowMsg($"{Lang.完成}!");
+        //        }
+        //        else
+        //        {
+        //            ShowMsg("相机轴上使能失败!");
+        //        }
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        LogHelper.WriteLogError("相机轴上使能时出错!", ex);
+        //        ShowMsg(ex.Message);
+        //    }
+        //}
+
+        ///// <summary>
+        ///// 相机轴点动命令
+        ///// </summary>
+        ///// <param name="parameter"></param>
+        //async void ExecuteCameraAxisJogCommand(string parameter)
+        //{
+        //    try
+        //    {
+        //        int cameraIndex = int.Parse(parameter.Split(',')[0]);
+        //        double jogDistance = Distance;
+        //        string axisName = "";
+        //        switch (parameter.Split(',')[1])
+        //        {
+        //            case "X+":
+        //                jogDistance = Distance;
+        //                axisName = "X";
+        //                break;
+        //            case "X-":
+        //                jogDistance = -Distance;
+        //                axisName = "X";
+        //                break;
+        //            case "Y+":
+        //                jogDistance = Distance;
+        //                axisName = "Y";
+        //                break;
+        //            case "Y-":
+        //                jogDistance = -Distance;
+        //                axisName = "Y";
+        //                break;
+        //            default:
+        //                break;
+        //        }
+        //        bool isSuccess = await Robot.CameraJogAsync(cameraIndex, axisName, jogDistance);
+        //        if (isSuccess)
+        //        {
+        //            ShowMsg($"{Lang.完成}!");
+        //        }
+        //        else
+        //        {
+        //            ShowMsg("相机轴点动失败!");
+        //        }
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        LogHelper.WriteLogError("相机轴点动时出错!", ex);
+        //        ShowMsg(ex.Message);
+        //    }
+        //}
+        #endregion
+
+        #endregion
+
+        #region 属性通知
+        /// <summary>
+        /// Occurs when a property value changes.
+        /// </summary>
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        /// <summary>
+        /// Checks if a property already matches a desired value. Sets the property and
+        /// notifies listeners only when necessary.
+        /// </summary>
+        /// <typeparam name="T">Type of the property.</typeparam>
+        /// <param name="storage">Reference to a property with both getter and setter.</param>
+        /// <param name="value">Desired value for the property.</param>
+        /// <param name="propertyName">Name of the property used to notify listeners. This
+        /// value is optional and can be provided automatically when invoked from compilers that
+        /// support CallerMemberName.</param>
+        /// <returns>True if the value was changed, false if the existing value matched the
+        /// desired value.</returns>
+        protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
+        {
+            if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
+
+            storage = value;
+            RaisePropertyChanged(propertyName);
+
+            return true;
+        }
+
+        /// <summary>
+        /// Checks if a property already matches a desired value. Sets the property and
+        /// notifies listeners only when necessary.
+        /// </summary>
+        /// <typeparam name="T">Type of the property.</typeparam>
+        /// <param name="storage">Reference to a property with both getter and setter.</param>
+        /// <param name="value">Desired value for the property.</param>
+        /// <param name="propertyName">Name of the property used to notify listeners. This
+        /// value is optional and can be provided automatically when invoked from compilers that
+        /// support CallerMemberName.</param>
+        /// <param name="onChanged">Action that is called after the property value has been changed.</param>
+        /// <returns>True if the value was changed, false if the existing value matched the
+        /// desired value.</returns>
+        protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
+        {
+            if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
+
+            storage = value;
+            onChanged?.Invoke();
+            RaisePropertyChanged(propertyName);
+
+            return true;
+        }
+
+        /// <summary>
+        /// Raises this object's PropertyChanged event.
+        /// </summary>
+        /// <param name="propertyName">Name of the property used to notify listeners. This
+        /// value is optional and can be provided automatically when invoked from compilers
+        /// that support <see cref="CallerMemberNameAttribute"/>.</param>
+        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
+        }
+
+        /// <summary>
+        /// Raises this object's PropertyChanged event.
+        /// </summary>
+        /// <param name="args">The PropertyChangedEventArgs</param>
+        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
+        {
+            PropertyChanged?.Invoke(this, args);
+        }
+        #endregion
+    }
+}

+ 9 - 1
TeamAAS-VM/Core/Management.cs

@@ -1807,9 +1807,17 @@ namespace TeamAAS_VP.Core
                             //拍1打1 
                             if (systemConfig.WorkMode == 1)
                             {
-                                var point = currentProduct.ScrewPoints[positionIndex].Clone();
+                                var point=currentProduct.ScrewPoints.FirstOrDefault(p=>p.Number== positionIndex);
+                                if (point==null)
+                                {
+                                    SendTaskMessage($"点:{positionIndex}不存在", MessageLevel.Info);
+                                    await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
+                                    return;
+                                }
+                                point = point.Clone();
                                 point.X_Position = UpCameraPutResults[1].X + DowmCameraResults[1].X;
                                 point.Y_Position = UpCameraPutResults[1].Y + DowmCameraResults[1].Y;
+                                SendTaskMessage($"点:{positionIndex},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
                                 await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
                             }
                             //拍1打所有

+ 414 - 0
TeamAAS-VM/Core/RectangleCenterCalculator.cs

@@ -0,0 +1,414 @@
+using MathNet.Numerics.LinearAlgebra;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TeamAAS_VP.Core
+{
+    /// <summary>
+    /// 提供多种方法用于计算由四个角点定义的矩形中心点、长轴角度以及相关矩形参数的辅助类。
+    /// 角点顺序约定:左上(0) → 右上(1) → 右下(2) → 左下(3)
+    /// 长轴方向:从左上角(0)指向右上角(1)
+    /// 角度范围:[-180, 180) 度,0°指向X轴正方向,逆时针为正
+    /// </summary>
+    public class RectangleCenterCalculator
+    {
+        /// <summary>
+        /// 矩形中心及方向信息的综合结果
+        /// </summary>
+        public class RectangleResult
+        {
+            /// <summary>
+            /// 矩形中心点坐标
+            /// </summary>
+            public Vector<double> Center { get; set; }
+
+            /// <summary>
+            /// 矩形长轴方向向量(从左上指向右上的单位向量)
+            /// </summary>
+            public Vector<double> MajorAxis { get; set; }
+
+            /// <summary>
+            /// 矩形短轴方向向量(单位向量)
+            /// </summary>
+            public Vector<double> MinorAxis { get; set; }
+
+            /// <summary>
+            /// 矩形长度(沿长轴方向,左上到右上的距离)
+            /// </summary>
+            public double Length { get; set; }
+
+            /// <summary>
+            /// 矩形宽度(沿短轴方向)
+            /// </summary>
+            public double Width { get; set; }
+
+            /// <summary>
+            /// 长轴方向角度[-180, 180)度
+            /// 从左上指向右上的向量在XY平面的投影角度
+            /// 0° = 指向X轴正方向,正角度逆时针,负角度顺时针
+            /// </summary>
+            public double MajorAxisAngle { get; set; }
+
+            /// <summary>
+            /// 四个角点的坐标(保持输入顺序)
+            /// </summary>
+            public List<Vector<double>> Corners { get; set; }
+
+            /// <summary>
+            /// 左上角点坐标
+            /// </summary>
+            public Vector<double> TopLeft => Corners != null && Corners.Count >= 1 ? Corners[0] : null;
+
+            /// <summary>
+            /// 右上角点坐标
+            /// </summary>
+            public Vector<double> TopRight => Corners != null && Corners.Count >= 2 ? Corners[1] : null;
+
+            /// <summary>
+            /// 右下角点坐标
+            /// </summary>
+            public Vector<double> BottomRight => Corners != null && Corners.Count >= 3 ? Corners[2] : null;
+
+            /// <summary>
+            /// 左下角点坐标
+            /// </summary>
+            public Vector<double> BottomLeft => Corners != null && Corners.Count >= 4 ? Corners[3] : null;
+
+            /// <summary>
+            /// 矩形的面积
+            /// </summary>
+            public double Area { get; set; }
+
+            /// <summary>
+            /// 拟合误差(均方根误差)
+            /// </summary>
+            public double FitError { get; set; }
+        }
+
+        /// <summary>
+        /// 验证角点顺序并进行必要的调整
+        /// 确保顺序为:左上 → 右上 → 右下 → 左下
+        /// </summary>
+        private static List<Vector<double>> ValidateAndOrderCorners(List<Vector<double>> corners)
+        {
+            if (corners == null || corners.Count != 4)
+                throw new ArgumentException("需要4个角点");
+
+            // 这里可以添加自动排序逻辑,但既然您已知顺序,直接返回
+            // 如果未来需要自动排序,可以使用以下逻辑:
+            // 1. 找到最左边的两个点作为左边界
+            // 2. 根据Y坐标区分左上和左下
+            // 3. 计算中心点,确定其他点位置
+
+            return corners; // 假设输入已经按正确顺序
+        }
+
+        /// <summary>
+        /// 计算从左上指向右上的长轴方向角度
+        /// </summary>
+        private static double CalculateMajorAxisAngle(Vector<double> topLeft, Vector<double> topRight)
+        {
+            // 计算方向向量(从左上指向右上)
+            Vector<double> direction = topRight - topLeft;
+
+            // 只考虑XY平面上的投影
+            double x = direction[0];
+            double y = direction[1];
+
+            // 使用Math.Atan2计算角度(弧度)
+            double angleRad = Math.Atan2(y, x);
+
+            // 转换为度,得到有符号角度 [-180, 180)
+            double angleDeg = angleRad * 180.0 / Math.PI;
+
+            // Math.Atan2的结果已经是[-180, 180],但确保一下边界
+            if (angleDeg >= 180.0)
+                angleDeg -= 360.0;
+            else if (angleDeg < -180.0)
+                angleDeg += 360.0;
+
+            return angleDeg;
+        }
+
+        /// <summary>
+        /// 使用最小二乘法思想计算最优矩形中心点及相关参数(对外统一入口)
+        /// 推荐使用改进的PCA方法,因为它能利用所有点信息进行优化
+        /// </summary>
+        public static RectangleResult CalculateOptimalCenter(List<Vector<double>> corners)
+        {
+            // 验证和调整角点顺序
+            var orderedCorners = ValidateAndOrderCorners(corners);
+
+            // 使用改进的PCA方法(考虑已知顺序)
+            return CalculateByPCAWithKnownOrder(orderedCorners);
+        }
+
+        /// <summary>
+        /// 方法1:基于已知角点顺序的直接计算(最准确)
+        /// 直接使用左上和右上点计算长轴,然后计算其他参数
+        /// </summary>
+        public static RectangleResult CalculateByDirectMethod(List<Vector<double>> corners)
+        {
+            var orderedCorners = ValidateAndOrderCorners(corners);
+
+            var topLeft = orderedCorners[0];
+            var topRight = orderedCorners[1];
+            var bottomRight = orderedCorners[2];
+            var bottomLeft = orderedCorners[3];
+
+            // 计算长轴(从左上指向右上)
+            Vector<double> majorAxis = (topRight - topLeft).Normalize(2);
+
+            // 计算短轴(从左上指向左下)
+            Vector<double> minorAxis = (bottomLeft - topLeft).Normalize(2);
+
+            // 确保短轴与长轴垂直(处理非正交情况)
+            minorAxis = (minorAxis - majorAxis * minorAxis.DotProduct(majorAxis)).Normalize(2);
+
+            // 计算中心点(四个角点的平均)
+            var center = Vector<double>.Build.DenseOfEnumerable(
+                Enumerable.Range(0, 3)
+                    .Select(i => orderedCorners.Select(c => c[i]).Average()));
+
+            // 计算长度和宽度
+            double length = Distance(topLeft, topRight);
+            double width = Distance(topLeft, bottomLeft);
+
+            // 计算长轴角度
+            double angle = CalculateMajorAxisAngle(topLeft, topRight);
+
+            // 计算拟合误差
+            double fitError = CalculateFitErrorDirect(center, majorAxis, minorAxis, length, width, orderedCorners);
+
+            return new RectangleResult
+            {
+                Center = center,
+                MajorAxis = majorAxis,
+                MinorAxis = minorAxis,
+                Length = length,
+                Width = width,
+                MajorAxisAngle = angle,
+                Corners = orderedCorners,
+                Area = length * width,
+                FitError = fitError
+            };
+        }
+
+        /// <summary>
+        /// 方法2:使用PCA但考虑已知角点顺序(推荐)
+        /// 结合PCA的鲁棒性和已知顺序的准确性
+        /// </summary>
+        public static RectangleResult CalculateByPCAWithKnownOrder(List<Vector<double>> corners)
+        {
+            var orderedCorners = ValidateAndOrderCorners(corners);
+
+            // 步骤1:使用所有点进行PCA得到初步估计
+            var matrix = Matrix<double>.Build.DenseOfRows(orderedCorners);
+            var mean = Vector<double>.Build.DenseOfEnumerable(
+                Enumerable.Range(0, 3).Select(i => matrix.Column(i).Average()));
+
+            var centered = matrix.Clone();
+            for (int i = 0; i < 4; i++)
+            {
+                centered.SetRow(i, centered.Row(i) - mean);
+            }
+
+            var covariance = centered.Transpose() * centered / 3.0;
+            var evd = covariance.Evd();
+
+            // 获取特征向量
+            var eigenvectors = evd.EigenVectors;
+
+            // 步骤2:使用已知顺序确定长轴方向
+            var topLeft = orderedCorners[0];
+            var topRight = orderedCorners[1];
+
+            // 计算实际的长轴方向(从左上指向右上)
+            Vector<double> actualMajorDirection = (topRight - topLeft).Normalize(2);
+
+            // 从PCA的特征向量中找到最接近实际方向的那个
+            Vector<double> bestAxis = eigenvectors.Column(0);
+            double bestSimilarity = Math.Abs(actualMajorDirection.DotProduct(bestAxis));
+
+            for (int i = 1; i < 3; i++)
+            {
+                var axis = eigenvectors.Column(i);
+                double similarity = Math.Abs(actualMajorDirection.DotProduct(axis));
+                if (similarity > bestSimilarity)
+                {
+                    bestSimilarity = similarity;
+                    bestAxis = axis;
+                }
+            }
+
+            // 确保PCA轴的方向与实际方向一致(点积为正)
+            Vector<double> majorAxis = bestAxis;
+            if (actualMajorDirection.DotProduct(majorAxis) < 0)
+            {
+                majorAxis = -majorAxis;
+            }
+
+            // 计算短轴(与长轴垂直)
+            Vector<double> minorAxis = CalculatePerpendicularAxis(majorAxis);
+
+            // 将点投影到轴上计算中心、长度和宽度
+            var projMajor = orderedCorners.Select(p => (p - mean).DotProduct(majorAxis)).ToList();
+            var projMinor = orderedCorners.Select(p => (p - mean).DotProduct(minorAxis)).ToList();
+
+            double centerMajor = (projMajor.Min() + projMajor.Max()) / 2.0;
+            double centerMinor = (projMinor.Min() + projMinor.Max()) / 2.0;
+            var center = mean + majorAxis * centerMajor + minorAxis * centerMinor;
+
+            double length = Math.Abs(projMajor.Max() - projMajor.Min());
+            double width = Math.Abs(projMinor.Max() - projMinor.Min());
+
+            // 计算长轴角度(使用实际的左上-右上方向)
+            double angle = CalculateMajorAxisAngle(topLeft, topRight);
+
+            // 计算拟合误差
+            double fitError = CalculateFitError(center, majorAxis, minorAxis, length, width, orderedCorners);
+
+            return new RectangleResult
+            {
+                Center = center,
+                MajorAxis = majorAxis,
+                MinorAxis = minorAxis,
+                Length = length,
+                Width = width,
+                MajorAxisAngle = angle,
+                Corners = orderedCorners,
+                Area = length * width,
+                FitError = fitError
+            };
+        }
+
+        /// <summary>
+        /// 方法3:对角线优化方法(考虑已知顺序)
+        /// </summary>
+        public static RectangleResult CalculateByDiagonalOptimization(List<Vector<double>> corners)
+        {
+            var orderedCorners = ValidateAndOrderCorners(corners);
+            var topLeft = orderedCorners[0];
+            var topRight = orderedCorners[1];
+
+            // 直接使用已知顺序计算长轴角度
+            double angle = CalculateMajorAxisAngle(topLeft, topRight);
+
+            // 计算长轴方向向量
+            Vector<double> majorAxis = (topRight - topLeft).Normalize(2);
+            Vector<double> minorAxis = CalculatePerpendicularAxis(majorAxis);
+
+            // 使用所有对角线组合计算最佳中心
+            var diagonalCombinations = new[]
+            {
+            (orderedCorners[0], orderedCorners[2]), // 左上-右下
+            (orderedCorners[1], orderedCorners[3])  // 右上-左下
+        };
+
+            var centers = diagonalCombinations.Select(p => (p.Item1 + p.Item2) / 2.0).ToList();
+            var center = (centers[0] + centers[1]) / 2.0;
+
+            // 计算长度和宽度
+            double length = Distance(topLeft, topRight);
+            double width = Distance(topLeft, orderedCorners[3]); // 左上-左下
+
+            // 计算拟合误差
+            double fitError = CalculateFitError(center, majorAxis, minorAxis, length, width, orderedCorners);
+
+            return new RectangleResult
+            {
+                Center = center,
+                MajorAxis = majorAxis,
+                MinorAxis = minorAxis,
+                Length = length,
+                Width = width,
+                MajorAxisAngle = angle,
+                Corners = orderedCorners,
+                Area = length * width,
+                FitError = fitError
+            };
+        }
+
+        /// <summary>
+        /// 辅助方法:计算与给定向量垂直的单位向量
+        /// </summary>
+        private static Vector<double> CalculatePerpendicularAxis(Vector<double> axis)
+        {
+            // 找一个不与axis共线的向量
+            Vector<double> temp;
+            if (Math.Abs(axis[0]) < 0.9)
+                temp = Vector<double>.Build.Dense(new[] { 1.0, 0.0, 0.0 });
+            else
+                temp = Vector<double>.Build.Dense(new[] { 0.0, 1.0, 0.0 });
+
+            var perpendicular = temp - axis * temp.DotProduct(axis);
+            return perpendicular.Normalize(2);
+        }
+
+        /// <summary>
+        /// 辅助方法:计算两点距离
+        /// </summary>
+        private static double Distance(Vector<double> a, Vector<double> b)
+        {
+            return (a - b).L2Norm();
+        }
+
+        /// <summary>
+        /// 辅助方法:计算拟合误差
+        /// </summary>
+        private static double CalculateFitError(Vector<double> center, Vector<double> majorAxis,Vector<double> minorAxis, double length, double width, List<Vector<double>> corners)
+        {
+            // 生成理想矩形的四个角点
+            var idealCorners = new List<Vector<double>>
+        {
+            center + majorAxis * (length / 2) + minorAxis * (width / 2),   // 右上
+            center + majorAxis * (length / 2) - minorAxis * (width / 2),   // 右下
+            center - majorAxis * (length / 2) - minorAxis * (width / 2),   // 左下
+            center - majorAxis * (length / 2) + minorAxis * (width / 2)    // 左上
+        };
+
+            // 注意:理想角点顺序可能与输入不同,需要重新排序匹配
+            // 这里简单计算所有对应点的最小距离和
+            double sumSquared = 0;
+            for (int i = 0; i < 4; i++)
+            {
+                // 找到最近的理想角点
+                double minDist = double.MaxValue;
+                foreach (var ideal in idealCorners)
+                {
+                    double dist = Distance(corners[i], ideal);
+                    if (dist < minDist) minDist = dist;
+                }
+                sumSquared += minDist * minDist;
+            }
+
+            return Math.Sqrt(sumSquared / 4);
+        }
+
+        /// <summary>
+        /// 直接计算方法的拟合误差
+        /// </summary>
+        private static double CalculateFitErrorDirect(Vector<double> center, Vector<double> majorAxis,Vector<double> minorAxis, double length, double width, List<Vector<double>> corners)
+        {
+            // 对于直接方法,我们知道每个角点的理想位置
+            var idealCorners = new List<Vector<double>>
+        {
+            center - majorAxis * (length / 2) + minorAxis * (width / 2),  // 左上
+            center + majorAxis * (length / 2) + minorAxis * (width / 2),  // 右上
+            center + majorAxis * (length / 2) - minorAxis * (width / 2),  // 右下
+            center - majorAxis * (length / 2) - minorAxis * (width / 2)   // 左下
+        };
+
+            double sumSquared = 0;
+            for (int i = 0; i < 4; i++)
+            {
+                sumSquared += Math.Pow(Distance(corners[i], idealCorners[i]), 2);
+            }
+
+            return Math.Sqrt(sumSquared / 4);
+        }
+    }
+}

+ 1 - 1
TeamAAS-VM/Models/PLC/PlcAddressConfig.cs

@@ -979,7 +979,7 @@ namespace TeamAAS_VP.Models.PLC
             In_MesCheck.Description = Lang.Mes交互1获取过站信息当站是否生产2上传本站数据;
 
             In_Result = Ensure(In_Result);
-            In_Result.Address = "ns=4;s=DB_Communication|ToPC.Mes[{0}].Result";
+            In_Result.Address = "ns=4;s=DB_Communication|ToPC.Mes[0].Product_Status";
             In_Result.DataType = "int16";
             In_Result.Description = "产品的最终结果,1:OK; 2:NG";
 

+ 2 - 2
TeamAAS-VM/Properties/AssemblyInfo.cs

@@ -51,5 +51,5 @@ using System.Windows;
 //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
 //通过使用 "*",如下所示:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.2.0.6")]
-[assembly: AssemblyFileVersion("1.2.0.6")]
+[assembly: AssemblyVersion("1.2.0.7")]
+[assembly: AssemblyFileVersion("1.2.0.7")]

binární
TeamAAS-VM/Resources/Images/MobileDown_IndependentXYPlatform.png


+ 317 - 0
TeamAAS-VM/ViewModels/Calibration/CalibIndependentCameraViewModel.cs

@@ -0,0 +1,317 @@
+using Cognex.VisionPro;
+using Cognex.VisionPro.ToolBlock;
+using MathNet.Numerics.LinearAlgebra;
+using Prism.Commands;
+using Prism.Events;
+using Prism.Ioc;
+using Prism.Mvvm;
+using Prism.Regions;
+using Prism.Services.Dialogs;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using Team.FFFeederService.Interfaces;
+using TeamAAS_VP.Core;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models.Calibration;
+using TeamAAS_VP.Models.Robot;
+using TeamAAS_VP.Resources.Languages;
+
+namespace TeamAAS_VP.ViewModels.Calibration
+{
+    public class CalibIndependentCameraViewModel : BindableBase, IConfirmNavigationRequest
+    {
+        IRegionManager _regionManager;
+        IRegionNavigationService _regionNavigationService;
+        IContainerProvider _container;
+        IDialogService _dialogService;
+        IEventAggregator _eventAggregator;
+        IRobotService _robotService;
+        IFeederService _feederService;
+        ICameraService _cameraService;
+        ISystemDatabaseService _systemDatabaseService;
+        ICameraCalibrationService _cameraCalibrationService;
+        private CancellationTokenSource _cts;
+        #region 属性
+        private ICogImage _Image;
+
+        public ICogImage Image
+        {
+            get { return _Image; }
+            set { SetProperty(ref _Image, value); }
+        }
+
+        private Cognex.VisionPro.CogGraphicCollection _Graphic;
+
+        public Cognex.VisionPro.CogGraphicCollection Graphic
+        {
+            get { return _Graphic; }
+            set { SetProperty(ref _Graphic, value); }
+        }
+
+        private CalibrationInfo _SelectCalibration;
+
+        public CalibrationInfo SelectCalibration
+        {
+            get { return _SelectCalibration; }
+            set { SetProperty(ref _SelectCalibration, value); }
+        }
+
+        public Management management { get; set; }
+        public IRobot Robot { get; set; }
+
+        private bool _IsRunning = true;
+
+        public bool IsRunning
+        {
+            get { return _IsRunning; }
+            set { SetProperty(ref _IsRunning, value); }
+        }
+
+        private ICamera _Camera;
+
+        public ICamera Camera
+        {
+            get { return _Camera; }
+            set { SetProperty(ref _Camera, value); }
+        }
+        #endregion
+
+        #region 命令
+        private DelegateCommand _NextCommand;
+        public DelegateCommand NextCommand =>
+            _NextCommand ?? (_NextCommand = new DelegateCommand(ExecuteNextCommand).ObservesCanExecute(() => IsRunning));
+
+        private DelegateCommand _BackCommand;
+        public DelegateCommand BackCommand =>
+            _BackCommand ?? (_BackCommand = new DelegateCommand(ExecuteBackCommand).ObservesCanExecute(() => IsRunning));
+
+        private DelegateCommand _StartCalibCommand;
+        public DelegateCommand StartCalibCommand =>
+            _StartCalibCommand ?? (_StartCalibCommand = new DelegateCommand(ExecuteStartCalibCommand).ObservesCanExecute(() => IsRunning));
+
+        #endregion
+
+        #region 事件
+
+        #endregion
+
+        public CalibIndependentCameraViewModel(IRegionManager regionManager, IEventAggregator ea, IRegionNavigationService regionNavigationService, IContainerProvider container, IDialogService dialogService,
+            IRobotService robotService, IFeederService feederService, ICameraService cameraService, ISystemDatabaseService systemDatabaseService, ICameraCalibrationService cameraCalibrationService)
+        {
+            _regionManager = regionManager;
+            _regionNavigationService = regionNavigationService;
+            _container = container;
+            _dialogService = dialogService;
+            _robotService = robotService;
+            _eventAggregator = ea;
+            _feederService = feederService;
+            _cameraService = cameraService;
+            _systemDatabaseService = systemDatabaseService;
+            _cameraCalibrationService = cameraCalibrationService;
+        }
+
+        #region 方法
+
+        /// <summary>
+        /// 开始校准
+        /// </summary>
+        async void ExecuteStartCalibCommand()
+        {
+            //try
+            //{
+            //    //弹窗提示是否开始独立移动相机刚体变换校准
+            //    MessageBoxResult msgResult = MessageBox.Show("是否开始独立移动相机位置校准", Lang.自动校准, MessageBoxButton.YesNo, MessageBoxImage.Question);
+            //    if (msgResult != MessageBoxResult.Yes)
+            //    {
+            //        return;
+            //    }
+
+            //    IsRunning = false;
+            //    _cts = new CancellationTokenSource();
+            //    (bool IsSuccess, double[,] RotationMatrix, double[,] TranslationMatrix) = await _cameraCalibrationService.CalculateIndependentCameraRigidTransformationMatrix(SelectCalibration, Robot, _cts.Token);
+            //    if (!IsSuccess)
+            //    {
+            //        MessageBox.Show("独立移动相机位置校准失败", $"{Lang.自动校准}", MessageBoxButton.OK, MessageBoxImage.Warning);
+            //        return;
+            //    }
+            //    SelectCalibration.IndependentDownCameraMotionModuleRotationMatrix = RotationMatrix;
+            //    SelectCalibration.IndependentDownCameraMotionModuleTranslationMatrix = TranslationMatrix;
+            //    //NavigationParameters param = new NavigationParameters();
+            //    //param.Add("SelectCalibration", SelectCalibration);
+            //    //_regionManager.RequestNavigate("CalibrationRegionContext", "CalibrationAuto", param);
+
+            //}
+            //catch (Exception ex)
+            //{
+            //    LogHelper.WriteLogError("独立移动相机位置校准时出错!", ex);
+            //    MessageBox.Show(ex.Message);
+            //}
+            //finally
+            //{
+            //    try
+            //    {
+            //        if (_cts != null && !_cts.IsCancellationRequested)
+            //            _cts.Cancel();
+            //        _cts?.Dispose();
+            //        _cts = null;
+            //    }
+            //    catch (Exception)
+            //    {
+
+            //    }
+            //    IsRunning = true;
+            //}
+        }
+
+        /// <summary>
+        /// 下一步
+        /// </summary>
+        void ExecuteNextCommand()
+        {
+            NavigationParameters param = new NavigationParameters();
+            param.Add("SelectCalibration", SelectCalibration);
+            _regionManager.RequestNavigate("CalibrationRegionContext", "CalibrationAuto", param);
+        }
+
+        /// <summary>
+        /// 上一步
+        /// </summary>
+        void ExecuteBackCommand()
+        {
+            NavigationParameters param = new NavigationParameters();
+            param.Add("SelectCalibration", SelectCalibration);
+
+            _regionManager.RequestNavigate("CalibrationRegionContext", "CalibrationSelectTool", param);
+        }
+
+        /// <summary>
+        /// 相机拍照
+        /// </summary>
+        /// <returns></returns>
+        private async Task<(bool IsSuccess, double X, double Y, double U, int ImageWidth, int ImageHeight)> CaptureAndProcess()
+        {
+            await Task.Delay(200);
+            //采集图像
+            if (Camera != null)
+            {
+                ICogImage image = Camera.Grab();
+                if (SelectCalibration.IsDistortionCorrection && SelectCalibration.CalibCheckerboardTool != null)
+                {
+                    SelectCalibration.CalibCheckerboardTool.InputImage = image;
+                    SelectCalibration.CalibCheckerboardTool.Run();
+                    image = SelectCalibration.CalibCheckerboardTool.OutputImage;
+                }
+                SelectCalibration.ToolBlock.Inputs["InputImage"].Value = image;
+
+            }
+            App.Current.Dispatcher.Invoke(() =>
+            {
+                Graphic = null;
+                Image = (ICogImage)SelectCalibration.ToolBlock.Inputs["InputImage"].Value;
+            });
+
+            SelectCalibration.ToolBlock.Run();
+            CogToolBlockTerminalCollection outputCollection = SelectCalibration.ToolBlock.Outputs;
+            App.Current.Dispatcher.Invoke(() =>
+            {
+                Graphic = outputCollection["Graphic"].Value as CogGraphicCollection;
+            });
+
+            bool Found = (bool)(outputCollection["Found"].Value);
+            if (Found)
+            {
+                var strpoints = outputCollection["Point"].Value.ToString();
+                string[] items = strpoints.Split(',');
+                double x = double.Parse(items[0]);
+                double y = double.Parse(items[1]);
+                return (true, x, y, 0, Image.Width, Image.Height);
+            }
+            else
+            {
+                return (false, 0, 0, 0, Image.Width, Image.Height);
+            }
+        }
+
+        #endregion
+
+        #region 继承
+        /// <summary>
+        /// 确认导航请求时调用。此方法允许您在导航之前执行一些操作。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <param name="continuationCallback"></param>
+        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
+        {
+            continuationCallback(true);
+        }
+
+        /// <summary>
+        /// 接收导航请求时调用。传入导航参数,包含有关导航目标的信息。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <exception cref="NotImplementedException"></exception>
+        public async void OnNavigatedTo(NavigationContext navigationContext)
+        {
+            SelectCalibration = navigationContext.Parameters.GetValue<CalibrationInfo>("SelectCalibration");
+            if (SelectCalibration != null)
+            {
+                Robot = _robotService.GetRobot(SelectCalibration.RobotId);
+            }
+            Camera = _cameraService.GetCamera(SelectCalibration.CameraID);
+            _cameraCalibrationService.CaptureAndProcessCallback = null;
+            _cameraCalibrationService.CaptureAndProcessCallback = CaptureAndProcess;
+            if (_systemDatabaseService.GetCurrentUser().userPart == Enums.UserPart.Operator)
+            {
+                IsAllowEdit = false;
+            }
+            else
+            {
+                IsAllowEdit = true;
+            }
+        }
+
+        /// <summary>
+        /// 是否允许导航到此视图模型。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <returns></returns>
+        public bool IsNavigationTarget(NavigationContext navigationContext)
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// 导航离开此视图模型时调用。您可以在此处执行清理操作或保存状态。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        public void OnNavigatedFrom(NavigationContext navigationContext)
+        {
+            _cameraCalibrationService.CaptureAndProcessCallback = null;
+        }
+        #endregion
+
+        private bool _IsAllowEdit = false;
+
+        public bool IsAllowEdit
+        {
+            get { return _IsAllowEdit; }
+            set { SetProperty(ref _IsAllowEdit, value); }
+        }
+
+        private void LoginChange(Models.User user)
+        {
+            if (user.userPart == Enums.UserPart.Operator)
+            {
+                IsAllowEdit = false;
+            }
+            else
+            {
+                IsAllowEdit = true;
+            }
+        }
+    }
+}

+ 261 - 0
TeamAAS-VM/ViewModels/Calibration/CalibrationDistortionViewModel.cs

@@ -0,0 +1,261 @@
+using Cognex.VisionPro;
+using Cognex.VisionPro.CalibFix;
+using Cognex.VisionPro.ToolBlock;
+using Prism.Commands;
+using Prism.Events;
+using Prism.Ioc;
+using Prism.Mvvm;
+using Prism.Regions;
+using Prism.Services.Dialogs;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using Team.FFFeederService.Interfaces;
+using TeamAAS_VP.Core;
+using TeamAAS_VP.Events;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models.Calibration;
+
+namespace TeamAAS_VP.ViewModels.Calibration
+{
+    public class CalibrationDistortionViewModel : BindableBase, IConfirmNavigationRequest
+    {
+        IRegionManager _regionManager;
+        IRegionNavigationService _regionNavigationService;
+        IContainerProvider _container;
+        IDialogService _dialogService;
+        IEventAggregator _eventAggregator;
+        IConfigService _configService;
+        IRobotService _robotService;
+        ICameraService _cameraService;
+        IFeederService _feederService;
+        ISystemDatabaseService _systemDatabaseService;
+
+        #region 属性
+
+        private CogCalibCheckerboardEditV2 _CalibCheckerboardEdit;
+
+        public CogCalibCheckerboardEditV2 CalibCheckerboardEdit
+        {
+            get { return _CalibCheckerboardEdit; }
+            set { SetProperty(ref _CalibCheckerboardEdit, value); }
+        }
+
+
+        private CalibrationInfo _SelectCalibration;
+
+        public CalibrationInfo SelectCalibration
+        {
+            get { return _SelectCalibration; }
+            set { SetProperty(ref _SelectCalibration, value); }
+        }
+
+        private ICamera _Camera;
+
+        public ICamera Camera
+        {
+            get { return _Camera; }
+            set { SetProperty(ref _Camera, value); }
+        }
+        #endregion
+
+        #region 命令
+        private DelegateCommand _LoadedCommand;
+        public DelegateCommand LoadedCommand =>
+            _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));
+        private DelegateCommand _NextCommand;
+        public DelegateCommand NextCommand =>
+            _NextCommand ?? (_NextCommand = new DelegateCommand(ExecuteNextCommand));
+
+        private DelegateCommand _BackCommand;
+        public DelegateCommand BackCommand =>
+            _BackCommand ?? (_BackCommand = new DelegateCommand(ExecuteBackCommand));
+
+        private DelegateCommand _RunCommand;
+        public DelegateCommand RunCommand =>
+            _RunCommand ?? (_RunCommand = new DelegateCommand(ExecuteRunCommand));
+        #endregion
+
+        #region 事件
+
+        #endregion
+
+        public CalibrationDistortionViewModel(IRegionManager regionManager, IEventAggregator ea, IRegionNavigationService regionNavigationService, IContainerProvider container, IDialogService dialogService,
+            IConfigService configService, IRobotService robotService, ICameraService cameraService, IFeederService feederService, ISystemDatabaseService systemDatabaseService)
+        {
+            _regionManager = regionManager;
+            _regionNavigationService = regionNavigationService;
+            _container = container;
+            _dialogService = dialogService;
+            _eventAggregator = ea;
+            _configService = configService;
+            _robotService = robotService;
+            _cameraService = cameraService;
+            _feederService = feederService;
+            _systemDatabaseService = systemDatabaseService;
+        }
+
+        #region 方法
+        void ExecuteLoadedCommand()
+        {
+            try
+            {
+                if (_systemDatabaseService.GetCurrentUser().userPart == Enums.UserPart.Operator)
+                {
+                    IsAllowEdit = false;
+                }
+                else
+                {
+                    IsAllowEdit = true;
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 下一步
+        /// </summary>
+        void ExecuteNextCommand()
+        {
+            try
+            {
+                string calibToolPath = FilePath.CalibrationPath + "//" + SelectCalibration.Name + "//" + "CalibCheckerboard.vpp";
+                if (!Directory.Exists(Path.GetDirectoryName(calibToolPath)))
+                {
+                    Directory.CreateDirectory(Path.GetDirectoryName(calibToolPath));
+                }
+                SelectCalibration.CalibCheckerboardTool = CalibCheckerboardEdit.Subject;
+                //保存校准工具
+                CogSerializer.SaveObjectToFile(CalibCheckerboardEdit.Subject, calibToolPath);
+                
+                NavigationParameters param = new NavigationParameters();
+                param.Add("SelectCalibration", SelectCalibration);
+                _regionManager.RequestNavigate("CalibrationRegionContext", "CalibrationEditVision", param);
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("相机校准-畸变校准工具界面点击下一步时出错!", ex);
+                MessageBox.Show(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 上一步
+        /// </summary>
+        void ExecuteBackCommand()
+        {
+            try
+            {
+                NavigationParameters param = new NavigationParameters();
+                param.Add("SelectCalibration", SelectCalibration);
+                _regionManager.RequestNavigate("CalibrationRegionContext", "CalibrationCameraParams", param);
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("相机校准-畸变校准工具界面点击上一步时出错!", ex);
+                MessageBox.Show(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 运行
+        /// </summary>
+        void ExecuteRunCommand()
+        {
+            try
+            {
+                SelectCalibration.CalibCheckerboardTool = CalibCheckerboardEdit.Subject;
+                CalibCheckerboardEdit.Subject.InputImage = Camera.Grab();
+                CalibCheckerboardEdit.Subject.Run();
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("相机校准-畸变校准时出错", ex);
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
+            }
+        }
+        #endregion
+
+        #region 继承
+        /// <summary>
+        /// 确认导航请求时调用。此方法允许您在导航之前执行一些操作。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <param name="continuationCallback"></param>
+        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
+        {
+            continuationCallback(true);
+        }
+
+        /// <summary>
+        /// 接收导航请求时调用。传入导航参数,包含有关导航目标的信息。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <exception cref="NotImplementedException"></exception>
+        public async void OnNavigatedTo(NavigationContext navigationContext)
+        {
+            SelectCalibration = navigationContext.Parameters.GetValue<CalibrationInfo>("SelectCalibration");
+            if (CalibCheckerboardEdit != null)
+            {
+                //先判断校准文件夹下是否存在校准工具VPP文件,存在则加载,不存在则新建一个工具
+                string calibToolPath = FilePath.CalibrationPath + "//" + SelectCalibration.Name + "//" + "CalibCheckerboard.vpp";
+                if (System.IO.File.Exists(calibToolPath))
+                {
+                    SelectCalibration.CalibCheckerboardTool = CogSerializer.LoadObjectFromFile(calibToolPath) as CogCalibCheckerboardTool;
+                    CalibCheckerboardEdit.Subject = SelectCalibration.CalibCheckerboardTool;
+                }
+                else
+                {
+                    SelectCalibration.CalibCheckerboardTool = new CogCalibCheckerboardTool();
+                    CalibCheckerboardEdit.Subject = SelectCalibration.CalibCheckerboardTool;
+                }
+            }
+            Camera = _cameraService.GetCamera(SelectCalibration.CameraID);
+        }
+
+        /// <summary>
+        /// 是否允许导航到此视图模型。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <returns></returns>
+        public bool IsNavigationTarget(NavigationContext navigationContext)
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// 导航离开此视图模型时调用。您可以在此处执行清理操作或保存状态。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        public void OnNavigatedFrom(NavigationContext navigationContext)
+        {
+
+        }
+        #endregion
+
+        private bool _IsAllowEdit = false;
+
+        public bool IsAllowEdit
+        {
+            get { return _IsAllowEdit; }
+            set { SetProperty(ref _IsAllowEdit, value); }
+        }
+
+        private void LoginChange(Models.User user)
+        {
+            if (user.userPart == Enums.UserPart.Operator)
+            {
+                IsAllowEdit = false;
+            }
+            else
+            {
+                IsAllowEdit = true;
+            }
+        }
+    }
+}

+ 568 - 0
TeamAAS-VM/ViewModels/DebugMod/PlcRobotManualStepViewModel.cs

@@ -0,0 +1,568 @@
+using Prism.Commands;
+using Prism.Events;
+using Prism.Ioc;
+using Prism.Mvvm;
+using Prism.Regions;
+using Prism.Unity;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows;
+using TeamAAS_VP.Core.Robots;
+using TeamAAS_VP.Events;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Resources.Languages;
+
+namespace TeamAAS_VP.ViewModels.DebugMod
+{
+    public class PlcRobotManualStepViewModel : BindableBase, IConfirmNavigationRequest
+    {
+        IContainerProvider _container;
+        IEventAggregator _eventAggregator;
+        IRobotService _robotService;
+        ISystemDatabaseService _systemDatabaseService;
+        IConfigService _configService;
+        public PlcRobotManualStepViewModel(IContainerProvider container, IEventAggregator ea, IRobotService robotService, ISystemDatabaseService systemDatabaseService, IConfigService configService)
+        {
+            _container = container;
+            _eventAggregator = ea;
+            _robotService = robotService;
+            _systemDatabaseService = systemDatabaseService;
+            _configService = configService;
+            //订阅权限登录事件
+            _eventAggregator.GetEvent<UserLoginNotification>().Subscribe(LoginChange);
+        }
+
+        #region 属性
+
+        private ObservableCollection<AxisExtended> _AdditionalAxisList;
+        public ObservableCollection<AxisExtended> AdditionalAxisList
+        {
+            get { return _AdditionalAxisList; }
+            set { SetProperty(ref _AdditionalAxisList, value); }
+        }
+
+        private XYZU_Robot _Robot;
+
+        public XYZU_Robot Robot
+        {
+            get { return _Robot; }
+            set
+            {
+                SetProperty(ref _Robot, value);
+                try
+                {
+                    if (value != null)
+                    {
+                        this.Distance = _configService.GetRobotStepDistance(value.Id);
+                    }
+                }
+                catch (Exception)
+                {
+
+                }
+            }
+        }
+
+        private double _Distance = 1;
+
+        public double Distance
+        {
+            get { return _Distance; }
+            set
+            {
+                SetProperty(ref _Distance, value);
+                try
+                {
+                    if (Robot == null)
+                    {
+                        return;
+                    }
+                    if (_configService == null)
+                        _configService = ((PrismApplication)(App.Current)).Container.Resolve<IConfigService>();
+                    _configService.UpdateRobotStepDistance(Robot.Id, value);
+                }
+                catch (Exception)
+                {
+
+                }
+            }
+        }
+        #endregion
+
+        #region 命令
+
+        private DelegateCommand<string> _MotorCommand;
+        public DelegateCommand<string> MotorCommand =>
+            _MotorCommand ?? (_MotorCommand = new DelegateCommand<string>(ExecuteMotorCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+
+
+        private DelegateCommand _ResetCommand;
+        public DelegateCommand ResetCommand =>
+            _ResetCommand ?? (_ResetCommand = new DelegateCommand(ExecuteResetCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+
+
+        private DelegateCommand<object> _JogCommand;
+        public DelegateCommand<object> JogCommand =>
+            _JogCommand ?? (_JogCommand = new DelegateCommand<object>(ExecuteJogCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        //附加轴,轴点动+命令
+        private DelegateCommand<object> _AdditionalAxisJogPlusCommand;
+        public DelegateCommand<object> AdditionalAxisJogPlusCommand =>
+            _AdditionalAxisJogPlusCommand ?? (_AdditionalAxisJogPlusCommand = new DelegateCommand<object>(ExecuteAdditionalAxisJogPlusCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        //附加轴,轴点动-命令
+        private DelegateCommand<object> _AdditionalAxisJogMinusCommand;
+        public DelegateCommand<object> AdditionalAxisJogMinusCommand =>
+            _AdditionalAxisJogMinusCommand ?? (_AdditionalAxisJogMinusCommand = new DelegateCommand<object>(ExecuteAdditionalAxisJogMinusCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        private DelegateCommand<object> _AdditionalAxisMotorOnCommand;
+        public DelegateCommand<object> AdditionalAxisMotorOnCommand =>
+            _AdditionalAxisMotorOnCommand ?? (_AdditionalAxisMotorOnCommand = new DelegateCommand<object>(ExecuteAdditionalAxisMotorOnCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        private DelegateCommand<object> _AdditionalAxisMotorOffCommand;
+        public DelegateCommand<object> AdditionalAxisMotorOffCommand =>
+            _AdditionalAxisMotorOffCommand ?? (_AdditionalAxisMotorOffCommand = new DelegateCommand<object>(ExecuteAdditionalAxisMotorOffCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute));
+
+        //private DelegateCommand<string> _CameraAxisModerOnCommand;
+        //public DelegateCommand<string> CameraAxisModerOnCommand =>
+        //    _CameraAxisModerOnCommand ?? (_CameraAxisModerOnCommand = new DelegateCommand<string>(ExecuteCameraAxisModerOnCommand));
+
+        //private DelegateCommand<string> _CameraAxisModerOffCommand;
+        //public DelegateCommand<string> CameraAxisModerOffCommand =>
+        //    _CameraAxisModerOffCommand ?? (_CameraAxisModerOffCommand = new DelegateCommand<string>(ExecuteCameraAxisModerOffCommand));
+
+        //private DelegateCommand<string> _CameraAxisJogCommand;
+        //public DelegateCommand<string> CameraAxisJogCommand =>
+        //    _CameraAxisJogCommand ?? (_CameraAxisJogCommand = new DelegateCommand<string>(ExecuteCameraAxisJogCommand));
+
+
+        #endregion
+
+        #region 事件
+
+        #endregion
+
+        #region 方法
+
+        private void ShowMsg(string msg)
+        {
+            _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = $"{Lang.成功}!", Duration = 0.4 });
+        }
+
+        /// <summary>
+        /// 电机
+        /// </summary>
+        /// <param name="obj"></param>
+        private async void ExecuteMotorCommand(string obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                await Robot.MotorAsync(Convert.ToBoolean(obj));
+                ShowMsg($"{Lang.完成}!");
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("机器人点击操作时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 重置
+        /// </summary>
+        private async void ExecuteResetCommand()
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                await Robot.ResetAsync();
+
+                ShowMsg($"{Lang.完成}!");
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("重置机器人时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 点动
+        /// </summary>
+        /// <param name="obj"></param>
+        private async void ExecuteJogCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                var items = ((string)obj).Split(':');
+                //如果移动距离大于10mm,则提示用户确认
+                double distance = double.Parse(items[1]);
+                if (Math.Abs(distance) >= 10)
+                {
+                    if (MessageBox.Show($"确认要点动距离 {distance} mm 吗?", "确认点动", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                    {
+                        return;
+                    }
+                }
+                Robot.Timeout = 6000000;
+                switch (items[0])
+                {
+                    case "X+":
+                        await Robot.JogAsync("X", distance);
+                        break;
+                    case "X-":
+                        await Robot.JogAsync("X", -distance);
+                        break;
+                    case "Y+":
+                        await Robot.JogAsync("Y", distance);
+                        break;
+                    case "Y-":
+                        await Robot.JogAsync("Y", -distance);
+                        break;
+                    case "Z+":
+                        await Robot.JogAsync("Z", distance);
+                        break;
+                    case "Z-":
+                        await Robot.JogAsync("Z", -distance);
+                        break;
+                    case "U+":
+                        await Robot.JogAsync("U", distance);
+                        break;
+                    case "U-":
+                        await Robot.JogAsync("U", -distance);
+                        break;
+                    case "V+":
+                        await Robot.JogAsync("V", distance);
+                        break;
+                    case "V-":
+                        await Robot.JogAsync("V", -distance);
+                        break;
+                    case "W+":
+                        await Robot.JogAsync("W", distance);
+                        break;
+                    case "W-":
+                        await Robot.JogAsync("W", -distance);
+                        break;
+                    default:
+                        break;
+                }
+                Robot.Timeout = 5000;
+
+
+                ShowMsg($"{Lang.完成}!");
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("机器点动时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        private bool CanExecute
+        {
+            get
+            {
+                if (Robot != null)
+                {
+                    return Robot.CanExecute;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 附加轴+点动
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisJogPlusCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    //如果移动距离大于10mm,则提示用户确认
+                    if (Math.Abs(Distance) >= 10)
+                    {
+                        if (MessageBox.Show($"确认要点动距离 {Distance} mm 吗?", "确认点动", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                        {
+                            return;
+                        }
+                    }
+                    await Robot.AdditionalAxisJogAsync(axis.Name, Distance);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴点动+时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 附加轴-点动
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisJogMinusCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    //如果移动距离大于10mm,则提示用户确认
+                    if (Math.Abs(Distance) >= 10)
+                    {
+                        if (MessageBox.Show($"确认要点动距离 {Distance} mm 吗?", "确认点动", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                        {
+                            return;
+                        }
+                    }
+                    await Robot.AdditionalAxisJogNegAsync(axis.Name, Distance);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴点动-时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 附加轴下使能
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisMotorOffCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    await Robot.AdditionalAxisMotorAsync(axis.Name, false);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴上使能时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 附加轴上使能
+        /// </summary>
+        /// <param name="obj"></param>
+        async void ExecuteAdditionalAxisMotorOnCommand(object obj)
+        {
+            if (Robot == null || !Robot.IsConnected) return;
+            try
+            {
+                if (obj is AxisExtended axis)
+                {
+                    await Robot.AdditionalAxisMotorAsync(axis.Name, true);
+                    ShowMsg($"{Lang.完成}!");
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("附加轴下使能时出错!", ex);
+                ShowMsg(ex.Message);
+            }
+        }
+
+        #region 相机控制
+        ///// <summary>
+        ///// 轴电机下使能操作
+        ///// </summary>
+        ///// <param name="parameter"></param>
+        //async void ExecuteCameraAxisModerOffCommand(string parameter)
+        //{
+        //    try
+        //    {
+        //        int cameraIndex = int.Parse(parameter);
+        //        var isSuccess = await Robot.CameraMotorAsync(cameraIndex, false);
+        //        if (isSuccess)
+        //        {
+        //            ShowMsg($"{Lang.完成}!");
+        //        }
+        //        else
+        //        {
+        //            ShowMsg("相机轴下使能失败!");
+        //        }
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        LogHelper.WriteLogError("相机轴下使能时出错!", ex);
+        //        ShowMsg(ex.Message);
+        //    }
+        //}
+
+        ///// <summary>
+        ///// 轴电机上使能操作
+        ///// </summary>
+        ///// <param name="parameter"></param>
+        //async void ExecuteCameraAxisModerOnCommand(string parameter)
+        //{
+        //    try
+        //    {
+        //        int cameraIndex = int.Parse(parameter);
+        //        var isSuccess =await Robot.CameraMotorAsync(cameraIndex, true);
+        //        if (isSuccess)
+        //        {
+        //            ShowMsg($"{Lang.完成}!");
+        //        }
+        //        else
+        //        {
+        //            ShowMsg("相机轴上使能失败!");
+        //        }
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        LogHelper.WriteLogError("相机轴上使能时出错!", ex);
+        //        ShowMsg(ex.Message);
+        //    }
+        //}
+
+        ///// <summary>
+        ///// 相机轴点动命令
+        ///// </summary>
+        ///// <param name="parameter"></param>
+        //async void ExecuteCameraAxisJogCommand(string parameter)
+        //{
+        //    try
+        //    {
+        //        int cameraIndex = int.Parse(parameter.Split(',')[0]);
+        //        double jogDistance = Distance;
+        //        string axisName = "";
+        //        switch (parameter.Split(',')[1])
+        //        {
+        //            case "X+":
+        //                jogDistance = Distance;
+        //                axisName = "X";
+        //                break;
+        //            case "X-":
+        //                jogDistance = -Distance;
+        //                axisName = "X";
+        //                break;
+        //            case "Y+":
+        //                jogDistance = Distance;
+        //                axisName = "Y";
+        //                break;
+        //            case "Y-":
+        //                jogDistance = -Distance;
+        //                axisName = "Y";
+        //                break;
+        //            default:
+        //                break;
+        //        }
+        //        bool isSuccess = await Robot.CameraJogAsync(cameraIndex, axisName, jogDistance);
+        //        if (isSuccess)
+        //        {
+        //            ShowMsg($"{Lang.完成}!");
+        //        }
+        //        else
+        //        {
+        //            ShowMsg("相机轴点动失败!");
+        //        }
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        LogHelper.WriteLogError("相机轴点动时出错!", ex);
+        //        ShowMsg(ex.Message);
+        //    }
+        //}
+        #endregion
+
+        #endregion
+
+        #region 继承
+        /// <summary>
+        /// 确认导航请求时调用。此方法允许您在导航之前执行一些操作。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <param name="continuationCallback"></param>
+        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
+        {
+            continuationCallback(true);
+        }
+
+        /// <summary>
+        /// 接收导航请求时调用。传入导航参数,包含有关导航目标的信息。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <exception cref="NotImplementedException"></exception>
+        public async void OnNavigatedTo(NavigationContext navigationContext)
+        {
+            var robotInfo = navigationContext.Parameters["RobotInfo"] as Models.RobotInfo;
+            if (robotInfo != null)
+            {
+                Robot = _robotService.GetRobot(robotInfo.Id) as XYZU_Robot;
+                AdditionalAxisList = Robot.AdditionalAxisList;
+                Robot.EnterDebugMode = true;
+            }
+
+            if (_systemDatabaseService.GetCurrentUser().userPart == Enums.UserPart.Operator)
+            {
+                IsAllowEdit = false;
+            }
+            else
+            {
+                IsAllowEdit = true;
+            }
+        }
+
+        /// <summary>
+        /// 是否允许导航到此视图模型。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        /// <returns></returns>
+        public bool IsNavigationTarget(NavigationContext navigationContext)
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// 导航离开此视图模型时调用。您可以在此处执行清理操作或保存状态。
+        /// </summary>
+        /// <param name="navigationContext"></param>
+        public void OnNavigatedFrom(NavigationContext navigationContext)
+        {
+            if (Robot != null)
+                Robot.EnterDebugMode = false;
+        }
+        #endregion
+
+        private bool _IsAllowEdit = false;
+
+        public bool IsAllowEdit
+        {
+            get { return _IsAllowEdit; }
+            set { SetProperty(ref _IsAllowEdit, value); }
+        }
+
+        private void LoginChange(Models.User user)
+        {
+            if (user.userPart == Enums.UserPart.Operator)
+            {
+                IsAllowEdit = false;
+            }
+            else
+            {
+                IsAllowEdit = true;
+            }
+        }
+    }
+}

+ 123 - 0
TeamAAS-VM/Views/Calibration/CalibIndependentCamera.xaml

@@ -0,0 +1,123 @@
+<UserControl x:Class="TeamAAS_VP.Views.Calibration.CalibIndependentCamera"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             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:wf="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
+             xmlns:vp="clr-namespace:Cognex.VisionPro;assembly=Cognex.VisionPro.Controls"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Calibration"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:CalibIndependentCameraViewModel}"
+             d:Height="600"
+             d:Width="1024"
+             d:Background="White"
+             FontFamily="{DynamicResource DefaultFont}">
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="auto" />
+        </Grid.RowDefinitions>
+        <Button Grid.Row="0"
+                Content="{materialDesign:PackIcon Kind=ArrowLeftCircle}"
+                Width="50"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Top"
+                ToolTip="{lex:Loc 返回}"
+                Style="{StaticResource MaterialDesignIconButton}"
+                Command="{Binding BackCommand}" />
+        <StackPanel Grid.Row="0"
+                    Orientation="Horizontal"
+                    Margin="50,0"
+                    VerticalAlignment="Center">
+            <materialDesign:PackIcon Kind="CrosshairsGps"
+                                     Width="30"
+                                     Height="30" />
+            <TextBlock Text="{Binding SelectCalibration.Name,Converter={StaticResource StringFormatConverter},ConverterParameter=' [{0}] '}"
+                       VerticalAlignment="Center"
+                       TextTrimming="CharacterEllipsis" />
+            <TextBlock Text="- 独立移动相机校准"
+                       VerticalAlignment="Center"
+                       TextTrimming="CharacterEllipsis" />
+        </StackPanel>
+
+        <Grid Grid.Row="1"
+              IsEnabled="{Binding IsAllowEdit}">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="*" />
+                <RowDefinition Height="auto" />
+            </Grid.RowDefinitions>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="auto"
+                                  MinWidth="300" />
+            </Grid.ColumnDefinitions>
+            <wf:WindowsFormsHost Grid.Column="0">
+                <vp:CogRecordDisplay x:Name="display" />
+            </wf:WindowsFormsHost>
+            <StackPanel Grid.Row="0"
+                        Grid.Column="1"
+                        Orientation="Vertical" VerticalAlignment="Center">
+                <StackPanel Orientation="Horizontal">
+                    <TextBlock Text="独立模组X方向移动的距离:"
+                               VerticalAlignment="Center"
+                               Margin="0,0,5,0" />
+                    <mah:NumericUpDown Grid.Row="6"
+                                       Grid.Column="1"
+                                       Maximum="600"
+                                       Minimum="-600"
+                                       Interval="1"
+                                       MinHeight="30"
+                                       Margin="5,10"
+                                       MinWidth="120"
+                                       StringFormat="{}{0:N3} mm"
+                                       materialDesign:HintAssist.HelperText="移动距离"
+                                       Value="{Binding SelectCalibration.IndependentDownCameraMotionModuleMoveX,Mode=TwoWay}" />
+                    
+                    <TextBlock Text="mm"
+                               VerticalAlignment="Center"
+                               Margin="0,0,5,0" />
+                </StackPanel>
+                <Button
+                        MinWidth="150"
+                        Margin="10,10"
+                        HorizontalAlignment="Center"
+                        VerticalAlignment="Center"
+                        materialDesign:ButtonAssist.CornerRadius="10"
+                        Style="{StaticResource MaterialDesignRaisedButton}"
+                        Command="{Binding StartCalibCommand}">
+                    <StackPanel Orientation="Horizontal">
+                        <materialDesign:PackIcon Kind="AutomaticStart" />
+                        <TextBlock Text="开始校准"
+                                   Margin="5,0" />
+                    </StackPanel>
+                </Button>
+            </StackPanel>
+        </Grid>
+
+        <StackPanel Grid.Row="2"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Center"
+                    VerticalAlignment="Center"
+                    Margin="20">
+            <Button Content="{lex:Loc 下一步}"
+                    IsEnabled="{Binding IsAllowEdit}"
+                    MinWidth="150"
+                    Margin="10,0"
+                    HorizontalAlignment="Center"
+                    VerticalAlignment="Center"
+                    materialDesign:ButtonAssist.CornerRadius="10"
+                    Style="{StaticResource MaterialDesignRaisedButton}"
+                    Command="{Binding NextCommand}" />
+        </StackPanel>
+    </Grid>
+</UserControl>

+ 73 - 0
TeamAAS-VM/Views/Calibration/CalibIndependentCamera.xaml.cs

@@ -0,0 +1,73 @@
+using Cognex.VisionPro;
+using Cognex.VisionPro.Dimensioning;
+using System;
+using System.Windows.Controls;
+using TeamAAS_VP.ViewModels.Calibration;
+
+namespace TeamAAS_VP.Views.Calibration
+{
+    /// <summary>
+    /// Interaction logic for CalibIndependentCamera
+    /// </summary>
+    public partial class CalibIndependentCamera : UserControl
+    {
+
+        //CalibIndependentCameraViewModel VM;
+        public CalibIndependentCamera()
+        {
+            InitializeComponent();
+            //VM = DataContext as CalibIndependentCameraViewModel;
+            //VM.PropertyChanged += VM_PropertyChanged;
+            //this.display.VerticalScrollBar = false;
+            //this.display.HorizontalScrollBar = false;
+            //this.display.AutoFit = true;
+            //this.display.BackColor = System.Drawing.SystemColors.ActiveCaption;
+        }
+
+        //private int _imageWidth;
+        //private int _imageHeight;
+        //private void VM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+        //{
+        //    try
+        //    {
+        //        if (e.PropertyName == "Image")
+        //        {
+        //            this.display.Image = VM.Image;
+        //            //图像中心点坐标
+        //            _imageWidth = this.display.Image.Width;
+        //            _imageHeight = this.display.Image.Height;
+        //        }
+        //        else if (e.PropertyName == "Graphic")
+        //        {
+        //            this.display.StaticGraphics.Clear();
+        //            CogGraphicCollection graphic = new CogGraphicCollection();
+        //            CogCreateLineTool line1 = new CogCreateLineTool();
+        //            CogCreateLineTool line2 = new CogCreateLineTool();
+        //            line1.InputImage = this.display.Image;
+        //            line2.InputImage = this.display.Image;
+        //            line1.Line.X = _imageWidth / 2;
+        //            line1.Line.Y = _imageHeight / 2;
+        //            line1.Line.Rotation = 0;
+        //            line2.Line.X = _imageWidth / 2;
+        //            line2.Line.Y = _imageHeight / 2;
+        //            line2.Line.Rotation = Math.PI / 180 * 90;
+        //            line1.Run();
+        //            line2.Run();
+        //            graphic.Add(line1.GetOutputLine());
+        //            graphic.Add(line2.GetOutputLine());
+        //            this.display.StaticGraphics.Clear();
+        //            this.display.StaticGraphics.AddList(graphic, "");
+        //            if (VM.Graphic != null)
+        //            {
+        //                this.display.StaticGraphics.AddList(VM.Graphic, "");
+        //            }
+
+        //        }
+        //    }
+        //    catch (System.Exception)
+        //    {
+
+        //    }
+        //}
+    }
+}

+ 98 - 0
TeamAAS-VM/Views/Calibration/CalibrationDistortion.xaml

@@ -0,0 +1,98 @@
+<UserControl x:Class="TeamAAS_VP.Views.Calibration.CalibrationDistortion"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:wf="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
+             xmlns:vp="clr-namespace:Cognex.VisionPro.CalibFix;assembly=Cognex.VisionPro.CalibFix.Controls"
+             xmlns:uControl="clr-namespace:TeamAAS_VP.Controls"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Calibration"
+             xmlns:convert="clr-namespace:TeamAAS_VP.ValueConverter"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:CalibrationDistortionViewModel}"
+             d:Height="600"
+             d:Width="1024"
+             d:Background="White"
+             FontFamily="{DynamicResource DefaultFont}">
+    <b:Interaction.Triggers>
+        <b:EventTrigger EventName="Loaded">
+            <b:InvokeCommandAction Command="{Binding LoadedCommand}" />
+        </b:EventTrigger>
+    </b:Interaction.Triggers>
+    
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="auto" />
+        </Grid.RowDefinitions>
+        <Button Grid.Row="0"
+                Content="{materialDesign:PackIcon Kind=ArrowLeftCircle}"
+                Width="50"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Top"
+                ToolTip="{lex:Loc 返回}"
+                Style="{StaticResource MaterialDesignIconButton}"
+                Command="{Binding BackCommand}" />
+        <StackPanel Grid.Row="0"
+                    Orientation="Horizontal"
+                    Margin="50,0"
+                    VerticalAlignment="Center">
+            <materialDesign:PackIcon Kind="CrosshairsGps"
+                                     Width="30"
+                                     Height="30" />
+            <TextBlock Text="{Binding SelectCalibration.Name,Converter={StaticResource StringFormatConverter},ConverterParameter=' [{0}] '}"
+                       VerticalAlignment="Center" />
+            <TextBlock Text="- 图像畸变校准"
+                       VerticalAlignment="Center" />
+        </StackPanel>
+
+        <materialDesign:DrawerHost Grid.Row="1"
+                                   IsEnabled="{Binding IsAllowEdit}"
+                                   OpenMode="Standard"
+                                   x:Name="DrawerHost">
+            <materialDesign:DrawerHost.RightDrawerContent>
+                <uControl:PlcRobotManual x:Name="robotManual" />
+            </materialDesign:DrawerHost.RightDrawerContent>
+
+            <Grid>
+                <wf:WindowsFormsHost Grid.Column="0"
+                                     Margin="0,0,0,35">
+                    <vp:CogCalibCheckerboardEditV2 x:Name="CalibCheckerboardEditV2" />
+                </wf:WindowsFormsHost>
+                <Button Content="{lex:Loc 运行流程}"
+                        Width="100"
+                        HorizontalAlignment="Left"
+                        VerticalAlignment="Bottom"
+                        Margin="5,3"
+                        Command="{Binding RunCommand}" />
+            </Grid>
+
+
+        </materialDesign:DrawerHost>
+
+        <StackPanel Grid.Row="2"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Center"
+                    VerticalAlignment="Center"
+                    Margin="20">
+            <Button Content="{lex:Loc 下一步}"
+                    IsEnabled="{Binding IsAllowEdit}"
+                    MinWidth="150"
+                    Margin="10,0"
+                    HorizontalAlignment="Center"
+                    VerticalAlignment="Center"
+                    materialDesign:ButtonAssist.CornerRadius="10"
+                    Style="{StaticResource MaterialDesignRaisedButton}"
+                    Command="{Binding NextCommand}" />
+        </StackPanel>
+    </Grid>
+</UserControl>

+ 18 - 0
TeamAAS-VM/Views/Calibration/CalibrationDistortion.xaml.cs

@@ -0,0 +1,18 @@
+using System.Windows.Controls;
+using TeamAAS_VP.Core.Robots;
+using TeamAAS_VP.ViewModels.Calibration;
+
+namespace TeamAAS_VP.Views.Calibration
+{
+    /// <summary>
+    /// Interaction logic for CalibrationDistortion
+    /// </summary>
+    public partial class CalibrationDistortion : UserControl
+    {
+        public CalibrationDistortion()
+        {
+            InitializeComponent();
+            ((CalibrationDistortionViewModel)DataContext).CalibCheckerboardEdit = this.CalibCheckerboardEditV2;
+        }
+    }
+}

+ 752 - 0
TeamAAS-VM/Views/DebugMod/PlcRobotManualStep.xaml

@@ -0,0 +1,752 @@
+<UserControl x:Class="TeamAAS_VP.Views.DebugMod.PlcRobotManualStep"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.DebugMod"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:sys="clr-namespace:System;assembly=mscorlib"
+             xmlns:uControl="clr-namespace:TeamAAS_VP.Controls"
+             xmlns:convert="clr-namespace:TeamAAS_VP.ValueConverter"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             mc:Ignorable="d"
+             d:Background="White"
+             d:DataContext="{d:DesignInstance Type=vm:PlcRobotManualStepViewModel}"
+             FontFamily="{DynamicResource DefaultFont}">
+    <UserControl.Resources>
+        <convert:JogConverter x:Key="JogConverter" />
+    </UserControl.Resources>
+    <ScrollViewer HorizontalAlignment="Stretch"
+                  VerticalAlignment="Stretch">
+        <Grid HorizontalAlignment="Stretch"
+              VerticalAlignment="Top"
+              IsEnabled="{Binding IsAllowEdit}">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="auto" />
+                <RowDefinition Height="auto" />
+                <RowDefinition Height="auto" />
+            </Grid.RowDefinitions>
+
+            <Grid Grid.Row="0"
+                  Margin="10"
+                  HorizontalAlignment="Center">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto" />
+                    <ColumnDefinition Width="auto" />
+                    <ColumnDefinition Width="auto" />
+                    <ColumnDefinition Width="auto" />
+                </Grid.ColumnDefinitions>
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                </Grid.RowDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="Button"
+                           BasedOn="{StaticResource MaterialDesignRaisedDarkButton}">
+                        <Setter Property="Width"
+                                Value="60" />
+                        <Setter Property="Height"
+                                Value="60" />
+                        <Setter Property="FontSize"
+                                Value="13" />
+                        <Setter Property="Padding"
+                                Value="0" />
+                        <Setter Property="HorizontalAlignment"
+                                Value="Center" />
+                        <Setter Property="VerticalAlignment"
+                                Value="Center" />
+                        <Setter Property="Margin"
+                                Value="2" />
+                        <Setter Property="materialDesign:ButtonAssist.CornerRadius"
+                                Value="10" />
+                    </Style>
+                </Grid.Resources>
+                <StackPanel Grid.ColumnSpan="4"
+                            Grid.Row="0"
+                            Grid.Column="0"
+                            VerticalAlignment="Center"
+                            Orientation="Horizontal">
+                    <Button Content="{lex:Loc 上使能}"
+                            Grid.Row="2"
+                            materialDesign:ButtonAssist.CornerRadius="10"
+                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                            Command="{Binding MotorCommand}"
+                            CommandParameter="True" />
+                    <Button Content="{lex:Loc 下使能}"
+                            Grid.Row="3"
+                            Margin="10"
+                            materialDesign:ButtonAssist.CornerRadius="10"
+                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                            Command="{Binding MotorCommand}"
+                            CommandParameter="False" />
+                    <Button Content="{lex:Loc 复位错误}"
+                            Grid.Row="4"
+                            materialDesign:ButtonAssist.CornerRadius="10"
+                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                            Command="{Binding ResetCommand}" />
+                </StackPanel>
+                <Button Grid.Row="2"
+                        Grid.Column="0"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=X-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowLeftBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-X"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="2"
+                        Grid.Column="2"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=X+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowRightBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+X"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="1"
+                        Grid.Column="1"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Y+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowTopBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+Y"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="3"
+                        Grid.Column="1"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Y-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowBottomBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-Y"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="1"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Z+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowTopBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+Z"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="3"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=Z-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="ArrowBottomBold"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-Z"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="4"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=U+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisZRotateCounterclockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+U"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="4"
+                        Grid.Column="0"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=U-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisZRotateClockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-U"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <!--<Button Grid.Row="4"
+                        Grid.Column="1"
+                        Grid.ColumnSpan="2"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=V+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisYRotateCounterclockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+V"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="5"
+                        Grid.Column="1"
+                        Grid.ColumnSpan="2"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=V-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisYRotateClockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-V"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>-->
+                <Button Grid.Row="5"
+                        Grid.Column="3"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=W+}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisXRotateCounterclockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="+W"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <Button Grid.Row="5"
+                        Grid.Column="0"
+                        Command="{Binding JogCommand}"
+                        CommandParameter="{Binding ElementName=txtDistance,Path=Value,Converter={StaticResource JogConverter}, ConverterParameter=W-}">
+                    <StackPanel Orientation="Vertical">
+                        <materialDesign:PackIcon Kind="AxisXRotateClockwise"
+                                                 Width="26"
+                                                 Height="26" />
+                        <TextBlock Text="-W"
+                                   HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+                <StackPanel Grid.Row="6"
+                            Grid.ColumnSpan="7"
+                            Margin="10,10,0,10"
+                            Grid.Column="0"
+                            VerticalAlignment="Center"
+                            Orientation="Horizontal">
+                    <TextBlock Text="{lex:Loc 步进距离}"
+                               VerticalAlignment="Center" />
+                    <uControl:myNumericUpDowm x:Name="txtDistance"
+                                              MinWidth="100"
+                                              Interval="0.1"
+                                              Minimum="0"
+                                              Maximum="100"
+                                              StringFormat="{}{0:N3} mm"
+                                              Value="{Binding Distance,Mode=TwoWay}"
+                                              Margin="10,0" />
+                </StackPanel>
+                <TextBlock Grid.Row="7"
+                           Grid.ColumnSpan="7"
+                           VerticalAlignment="Center"
+                           Margin="10,0">
+                    <TextBlock.Text>
+                        <MultiBinding StringFormat="{}CurPos X: {0:F3} mm Y: {1:F3} mm Z: {2:F3} mm U: {3:F3} °R: {4:F3} °">
+                            <Binding Path="Robot.CurrentPosition.X" />
+                            <Binding Path="Robot.CurrentPosition.Y" />
+                            <Binding Path="Robot.CurrentPosition.Z" />
+                            <Binding Path="Robot.CurrentPosition.U" />
+                            <Binding Path="Robot.CurrentPosition.W" />
+                        </MultiBinding>
+                    </TextBlock.Text>
+                </TextBlock>
+            </Grid>
+
+            <!--相机轴控制区域-->
+            <!--<Grid Grid.Row="1"
+                  Margin="10,0,10,10">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="*" />
+                    <RowDefinition Height="*" />
+                </Grid.RowDefinitions>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="Button"
+                           BasedOn="{StaticResource MaterialDesignRaisedDarkButton}">
+                        <Setter Property="MinWidth"
+                                Value="50" />
+                        <Setter Property="MinHeight"
+                                Value="30" />
+                        <Setter Property="FontSize"
+                                Value="13" />
+                        <Setter Property="Padding"
+                                Value="0" />
+                        <Setter Property="HorizontalAlignment"
+                                Value="Center" />
+                        <Setter Property="VerticalAlignment"
+                                Value="Center" />
+                        <Setter Property="materialDesign:ButtonAssist.CornerRadius"
+                                Value="10" />
+                    </Style>
+                </Grid.Resources>
+                -->
+            <!--相机2-->
+            <!--
+                <Border Grid.Row="0"
+                        Grid.Column="0"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机2轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera2CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera2CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="2"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Margin="2,0"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="2" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,X+" />
+                        <Button Grid.Row="3"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowTopBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,Y+" />
+                        <Button Grid.Row="5"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowBottomBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="2,Y-" />
+                    </Grid>
+                </Border>
+                -->
+            <!--相机4-->
+            <!--
+                <Border Grid.Row="0"
+                        Grid.Column="1"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机4轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera4CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera4CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="4"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="4"
+                                    Margin="2,0" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,X+" />
+                        <Button Grid.Row="3"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowTopBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,Y+" />
+                        <Button Grid.Row="5"
+                                Grid.Column="1"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowBottomBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="4,Y-" />
+                    </Grid>
+                </Border>
+                -->
+            <!--相机1-->
+            <!--
+                <Border Grid.Row="1"
+                        Grid.Column="0"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机1轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera1CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera1CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="1"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="1"
+                                    Margin="2,0" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="1,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="1,X+" />
+                    </Grid>
+                </Border>
+                -->
+            <!--相机3-->
+            <!--
+                <Border Grid.Row="1"
+                        Grid.Column="1"
+                        HorizontalAlignment="Stretch"
+                        BorderBrush="LightGray"
+                        BorderThickness="1"
+                        CornerRadius="10"
+                        Margin="2">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                            <RowDefinition Height="auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <TextBlock Grid.Row="0"
+                                   Grid.ColumnSpan="3"
+                                   Text="相机3轴控制"
+                                   FontWeight="Bold"
+                                   FontSize="14"
+                                   HorizontalAlignment="Center" />
+                        <TextBlock Grid.Row="1"
+                                   Grid.ColumnSpan="3"
+                                   VerticalAlignment="Center"
+                                   Margin="10,0">
+                            <TextBlock.Text>
+                                <MultiBinding StringFormat="{}X: {0:F3} mm Y: {1:F3} mm">
+                                    <Binding Path="Robot.Camera3CurrentPosition.X" />
+                                    <Binding Path="Robot.Camera3CurrentPosition.Y" />
+                                </MultiBinding>
+                            </TextBlock.Text>
+                        </TextBlock>
+                        <StackPanel Grid.Row="2"
+                                    Grid.ColumnSpan="3"
+                                    Orientation="Horizontal"
+                                    HorizontalAlignment="Center">
+                            <Button Content="{lex:Loc 上使能}"
+                                    Command="{Binding CameraAxisModerOnCommand}"
+                                    CommandParameter="3"
+                                    Margin="2,0" />
+                            <Button Content="{lex:Loc 下使能}"
+                                    Command="{Binding CameraAxisModerOffCommand}"
+                                    CommandParameter="3"
+                                    Margin="2,0" />
+                        </StackPanel>
+                        <Button Grid.Row="4"
+                                Grid.Column="0"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowLeftBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="3,X-" />
+                        <Button Grid.Row="4"
+                                Grid.Column="2"
+                                MinHeight="30"
+                                MinWidth="40"
+                                Width="40"
+                                Height="30"
+                                Content="{materialDesign:PackIcon ArrowRightBold}"
+                                Command="{Binding CameraAxisJogCommand}"
+                                CommandParameter="3,X+" />
+                    </Grid>
+                </Border>
+            </Grid>-->
+
+            <!-- 附加轴列表:绑定到视图模型中的 ExtraAxes 集合(每项假定有 Name、Position) -->
+            <ItemsControl Grid.Row="2"
+                          ItemsSource="{Binding AdditionalAxisList}">
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <Border Padding="6"
+                                Margin="0,2"
+                                Background="{DynamicResource MaterialDesignPaper}">
+                            <DockPanel LastChildFill="False"
+                                       VerticalAlignment="Center">
+                                <StackPanel Orientation="Horizontal"
+                                            DockPanel.Dock="Left"
+                                            VerticalAlignment="Center">
+                                    <TextBlock Text="{Binding Index}"
+                                               FontWeight="Bold"
+                                               VerticalAlignment="Center" />
+                                    <TextBlock Text="{Binding Name}"
+                                               FontWeight="Bold"
+                                               Margin="2,0"
+                                               VerticalAlignment="Center" />
+
+                                    <TextBlock Text="当前位置:"
+                                               Margin="30,0"
+                                               VerticalAlignment="Center" />
+                                    <TextBlock Text="{Binding CurrentPosition, StringFormat='{}{0:F3} mm'}"
+                                               Width="140"
+                                               VerticalAlignment="Center" />
+                                </StackPanel>
+                                <StackPanel Orientation="Horizontal"
+                                            HorizontalAlignment="Right"
+                                            DockPanel.Dock="Right">
+                                    <StackPanel.Resources>
+                                        <Style TargetType="Button"
+                                               BasedOn="{StaticResource MaterialDesignRaisedDarkButton}">
+                                            <Setter Property="Width"
+                                                    Value="60" />
+                                            <Setter Property="Height"
+                                                    Value="60" />
+                                            <Setter Property="FontSize"
+                                                    Value="13" />
+                                            <Setter Property="Padding"
+                                                    Value="0" />
+                                            <Setter Property="HorizontalAlignment"
+                                                    Value="Center" />
+                                            <Setter Property="VerticalAlignment"
+                                                    Value="Center" />
+                                            <Setter Property="Margin"
+                                                    Value="2" />
+                                            <Setter Property="materialDesign:ButtonAssist.CornerRadius"
+                                                    Value="10" />
+                                        </Style>
+                                    </StackPanel.Resources>
+                                    <Button Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisJogMinusCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}">
+                                        <StackPanel Orientation="Vertical">
+                                            <materialDesign:PackIcon Kind="ArrowLeftBold"
+                                                                     Width="26"
+                                                                     Height="26" />
+                                            <TextBlock Text="-"
+                                                       HorizontalAlignment="Center" />
+                                        </StackPanel>
+                                    </Button>
+                                    <Button Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisJogPlusCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}">
+                                        <StackPanel Orientation="Vertical">
+                                            <materialDesign:PackIcon Kind="ArrowRightBold"
+                                                                     Width="26"
+                                                                     Height="26" />
+                                            <TextBlock Text="+"
+                                                       HorizontalAlignment="Center" />
+                                        </StackPanel>
+                                    </Button>
+                                    <Button Content="上使能"
+                                            Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisMotorOnCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}" />
+                                    <Button Content="下使能"
+                                            Width="60"
+                                            Height="36"
+                                            Margin="6,0"
+                                            Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                            Command="{Binding DataContext.AdditionalAxisMotorOffCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
+                                            CommandParameter="{Binding}" />
+                                </StackPanel>
+                            </DockPanel>
+                        </Border>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+
+            <materialDesign:Snackbar Grid.RowSpan="2"
+                                     x:Name="snackbar"
+                                     Opacity="0.9"
+                                     HorizontalContentAlignment="Center"
+                                     VerticalAlignment="Top" />
+        </Grid>
+    </ScrollViewer>
+</UserControl>

+ 15 - 0
TeamAAS-VM/Views/DebugMod/PlcRobotManualStep.xaml.cs

@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace TeamAAS_VP.Views.DebugMod
+{
+    /// <summary>
+    /// Interaction logic for PlcRobotManualStep
+    /// </summary>
+    public partial class PlcRobotManualStep : UserControl
+    {
+        public PlcRobotManualStep()
+        {
+            InitializeComponent();
+        }
+    }
+}