Creado Encoder Lineal. Corregido error de inicio de tiempo en simulacion. Creado Frame Plate para que se muevan los objetos con un encoder lineal. Agregado a los transportes la actualizacion de geometrias en caso de que sean movidos por la interfaz.
This commit is contained in:
parent
353b4b99e6
commit
9f41401e40
|
@ -75,14 +75,14 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aether.Physics2D" Version="2.1.0" />
|
||||
<PackageReference Include="ClosedXML" Version="0.104.0-preview2" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="ClosedXML" Version="0.104.2" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Emgu.CV" Version="4.9.0.5494" />
|
||||
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.9.0.5494" />
|
||||
<PackageReference Include="Emgu.CV.UI" Version="4.9.0.5494" />
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.6.0" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc2" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.122" />
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.6.1" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc4.5" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||
<PackageReference Include="Tesseract" Version="5.2.0" />
|
||||
|
|
|
@ -704,6 +704,7 @@ namespace CtrEditor
|
|||
Debug_SimulacionCreado = true;
|
||||
|
||||
_timerSimulacion.Start();
|
||||
simulationManager.Start();
|
||||
}
|
||||
|
||||
private void StopSimulation()
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucFramePlate"
|
||||
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:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osFramePlate Color_Titulo="Black" Alto_Titulo="0.1" Color="WhiteSmoke" />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Viewbox Grid.Row="0" Height="{Binding Alto_Titulo, Converter={StaticResource MeterToPixelConverter}}">
|
||||
<Label Content="{Binding Titulo}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold"
|
||||
Foreground="{Binding Color_Titulo, Converter={StaticResource ColorToBrushConverter}}" />
|
||||
</Viewbox>
|
||||
<Rectangle Grid.Row="1" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}" Stroke="Blue"
|
||||
StrokeThickness="0.2" />
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,153 @@
|
|||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.FuncionesBase;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using Newtonsoft.Json;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using Color = System.Windows.Media.Color;
|
||||
using Colors = System.Windows.Media.Colors;
|
||||
using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucFramePlate.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class osFramePlate : osBase, IosBase
|
||||
{
|
||||
[JsonIgnore]
|
||||
public float offsetY;
|
||||
[JsonIgnore]
|
||||
public float offsetX;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Frame Plate";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
Color color;
|
||||
[ObservableProperty]
|
||||
Color color_Titulo;
|
||||
|
||||
[ObservableProperty]
|
||||
string titulo;
|
||||
[ObservableProperty]
|
||||
public float alto_Titulo;
|
||||
|
||||
// Encoder
|
||||
[ObservableProperty]
|
||||
[property: Description("This is a link to a Encoder for X.")]
|
||||
[property: Category("Encoders:")]
|
||||
[property: ItemsSource(typeof(osBaseItemsSource<osEncoderMotorLineal>))]
|
||||
private string encoder_X;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("K Pulses per meter for Moving")]
|
||||
[property: Category("Encoders:")]
|
||||
public float k_encoder_X;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("X in meter offset Left. Position when the encoder is 0")]
|
||||
[property: Category("Encoders:")]
|
||||
public float offset_encoder_X;
|
||||
|
||||
[JsonIgnore]
|
||||
private osEncoderMotorLineal EncoderX;
|
||||
|
||||
[JsonIgnore]
|
||||
private float EncoderXValue;
|
||||
|
||||
partial void OnEncoder_XChanged(string value)
|
||||
{
|
||||
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||
{
|
||||
EncoderX = (osEncoderMotorLineal)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osEncoderMotorLineal && s.Nombre == value), null);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
if (EncoderX == null)
|
||||
return;
|
||||
if (K_encoder_X == 0)
|
||||
return;
|
||||
if (EncoderXValue != EncoderX.Valor_Actual)
|
||||
Left = (EncoderX.Valor_Actual / k_encoder_X) + offset_encoder_X;
|
||||
EncoderXValue = EncoderX.Valor_Actual;
|
||||
}
|
||||
|
||||
public override void TopChanging(float oldValue, float newValue)
|
||||
{
|
||||
offsetY = newValue - oldValue;
|
||||
}
|
||||
public override void LeftChanging(float oldValue, float newValue)
|
||||
{
|
||||
offsetX = newValue - oldValue;
|
||||
}
|
||||
|
||||
public osFramePlate()
|
||||
{
|
||||
Ancho = 0.5f;
|
||||
Alto = 0.5f;
|
||||
Alto_Titulo = 0.2f;
|
||||
Color = Colors.WhiteSmoke;
|
||||
Titulo = "Frame";
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
base.ucLoaded();
|
||||
// El UserControl se ha cargado
|
||||
OnEncoder_XChanged(Encoder_X);
|
||||
}
|
||||
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
base.ucUnLoaded();
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucFramePlate : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucFramePlate()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += OnLoaded;
|
||||
this.Unloaded += OnUnloaded;
|
||||
}
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucLoaded();
|
||||
}
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucUnLoaded();
|
||||
}
|
||||
public void Highlight(bool State) { }
|
||||
public ZIndexEnum ZIndex()
|
||||
{
|
||||
return ZIndexEnum.Decorativos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -99,6 +99,7 @@ namespace CtrEditor.ObjetosSim
|
|||
Diametro = 0.10f;
|
||||
Mass = 1;
|
||||
ColorButton_oculto = Brushes.Gray;
|
||||
Preserve_Outside_Transport = true;
|
||||
}
|
||||
|
||||
public void UpdateAfterMove()
|
||||
|
|
|
@ -35,6 +35,10 @@ namespace CtrEditor.ObjetosSim
|
|||
[ObservableProperty]
|
||||
private float offsetTopSalida;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("The bottle will be destroyed if fall outside transport.")]
|
||||
[property: Category("Enable to Run:")]
|
||||
private bool preserve_Outside_Transport;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("PLC tag for consense to run. 1 => always")]
|
||||
|
@ -103,6 +107,7 @@ namespace CtrEditor.ObjetosSim
|
|||
Botellas_hora = 10000;
|
||||
Filtro_consenso_ON_s = 1;
|
||||
Filtro_consenso_OFF_s = 0.1f;
|
||||
Preserve_Outside_Transport = false;
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||
|
@ -144,6 +149,8 @@ namespace CtrEditor.ObjetosSim
|
|||
// No hay botellas, se puede crear una nueva directamente
|
||||
var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||
((osBotella)nuevaBotella).Diametro = Diametro_botella;
|
||||
((osBotella)nuevaBotella).Preserve_Outside_Transport = Preserve_Outside_Transport;
|
||||
((osBotella)nuevaBotella).AutoCreated = true;
|
||||
nuevaBotella.AutoCreated = true;
|
||||
UltimaBotella = (osBotella)nuevaBotella;
|
||||
BotellaCreada = true;
|
||||
|
@ -158,6 +165,7 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
osBotella nuevaBotella = (osBotella)_mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||
nuevaBotella.Diametro = Diametro_botella;
|
||||
((osBotella)nuevaBotella).Preserve_Outside_Transport = Preserve_Outside_Transport;
|
||||
nuevaBotella.AutoCreated = true;
|
||||
UltimaBotella = nuevaBotella;
|
||||
BotellaCreada = true;
|
||||
|
|
|
@ -110,6 +110,11 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
}
|
||||
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float frictionCoefficient;
|
||||
[ObservableProperty]
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
</VisualBrush.Transform>
|
||||
<VisualBrush.Visual>
|
||||
<Canvas>
|
||||
<Rectangle Fill="#FFBFBFBF" Width="10" Height="10"/>
|
||||
<Rectangle Fill="LightGray" Width="10" Height="10" Canvas.Left="10"/>
|
||||
<Rectangle Fill="LightGray" Width="10" Height="10" />
|
||||
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10" />
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
|
@ -55,7 +55,7 @@
|
|||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stretch="Uniform">
|
||||
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" FontSize="18" Opacity="0.5"/>
|
||||
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" FontSize="18" Opacity="0.9"/>
|
||||
</Viewbox>
|
||||
</Canvas>
|
||||
|
||||
|
|
|
@ -135,6 +135,10 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
}
|
||||
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public osTransporteGuias()
|
||||
{
|
||||
|
|
|
@ -227,6 +227,11 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
}
|
||||
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
|
||||
public osTransporteGuiasUnion()
|
||||
{
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
</VisualBrush.Transform>
|
||||
<VisualBrush.Visual>
|
||||
<Canvas>
|
||||
<Rectangle Fill="Gray" Width="10" Height="10"/>
|
||||
<Rectangle Fill="DarkGray" Width="10" Height="10" Canvas.Left="10"/>
|
||||
<Rectangle Fill="LightGray" Width="10" Height="10"/>
|
||||
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10"/>
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
|
@ -28,14 +28,25 @@
|
|||
<vm:osTransporteTTop Ancho="2"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Canvas>
|
||||
<Rectangle x:Name="Transporte"
|
||||
<Canvas RenderTransformOrigin="0,0">
|
||||
<Canvas.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform />
|
||||
<SkewTransform />
|
||||
<RotateTransform Angle="{Binding Angulo}" />
|
||||
<TranslateTransform />
|
||||
</TransformGroup>
|
||||
</Canvas.RenderTransform>
|
||||
<Rectangle x:Name="Transporte"
|
||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Fill="{StaticResource BeltBrush}">
|
||||
<Rectangle.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Angulo}"/>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<Viewbox Canvas.Top="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Stretch="Uniform">
|
||||
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold"
|
||||
FontSize="18" Opacity="0.9" />
|
||||
</Viewbox>
|
||||
</Canvas>
|
||||
</UserControl>
|
|
@ -116,6 +116,11 @@ namespace CtrEditor.ObjetosSim
|
|||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public osTransporteTTop()
|
||||
{
|
||||
Ancho = 1;
|
||||
|
|
|
@ -86,6 +86,10 @@ namespace CtrEditor.ObjetosSim
|
|||
[ObservableProperty]
|
||||
public float velocidad;
|
||||
|
||||
[ObservableProperty]
|
||||
public bool sentido_contrario;
|
||||
|
||||
|
||||
partial void OnVelocidadChanged(float value)
|
||||
{
|
||||
if (value > 0)
|
||||
|
@ -113,6 +117,7 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
motState.UpdatePLC(plc, this, elapsedMilliseconds);
|
||||
Velocidad = (Proporcional_Speed / 100) * (motState.STATUS_VFD_ACT_Speed_Hz / 10);
|
||||
Sentido_contrario = motState.OUT_Reversal;
|
||||
}
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucEncoderMotor"
|
||||
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:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osEncoderMotor />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid Width="50" Height="50">
|
||||
<Ellipse Fill="{Binding Color_oculto}" Stroke="DarkGray" StrokeThickness="2" Width="30" Height="30" />
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,160 @@
|
|||
// EncoderMotorViewModel.cs
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Windows.Media;
|
||||
using System.ComponentModel;
|
||||
using LibS7Adv;
|
||||
using System.Diagnostics;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using CtrEditor.FuncionesBase;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
public partial class osEncoderMotor : osBase, IosBase
|
||||
{
|
||||
private osBase Motor = null;
|
||||
private Stopwatch Stopwatch = new Stopwatch();
|
||||
private double stopwatch_last = 0;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Encoder Motor";
|
||||
}
|
||||
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private Brush color_oculto;
|
||||
|
||||
[ObservableProperty]
|
||||
public float velocidadActual;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Pulsos por vuelta del encoder")]
|
||||
[property: Category("Encoder Config:")]
|
||||
public float pulsos_Por_Vuelta;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Ratio de giros por 50Hz")]
|
||||
[property: Category("Encoder Config:")]
|
||||
public float ratio_Giros_50hz;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Valor actual del encoder")]
|
||||
[property: Category("Encoder Status:")]
|
||||
public float valor_Actual;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Link to Motor")]
|
||||
[property: Category("PLC link:")]
|
||||
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||
string id_Motor;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Tag para escribir el valor del encoder")]
|
||||
[property: Category("PLC link:")]
|
||||
string tag_Valor;
|
||||
|
||||
partial void OnId_MotorChanged(string value)
|
||||
{
|
||||
if (Motor != null)
|
||||
Motor.PropertyChanged -= OnMotorPropertyChanged;
|
||||
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||
{
|
||||
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
|
||||
if (Motor != null)
|
||||
Motor.PropertyChanged += OnMotorPropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||
{
|
||||
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||
}
|
||||
}
|
||||
|
||||
public osEncoderMotor()
|
||||
{
|
||||
Pulsos_Por_Vuelta = 360; // Por defecto, un pulso por grado
|
||||
Ratio_Giros_50hz = 1; // Por defecto, 1 giro por cada 50Hz
|
||||
Color_oculto = Brushes.Gray;
|
||||
Stopwatch.Start();
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
if (Motor != null && Motor is osVMmotorSim motor)
|
||||
{
|
||||
VelocidadActual = motor.Velocidad;
|
||||
|
||||
// Calcular giros por segundo basado en la velocidad actual
|
||||
// velocidad * ratio_giros_50hz / 100 nos da los giros por segundo a esa velocidad
|
||||
float girosPorSegundo = (VelocidadActual * Ratio_Giros_50hz) / 100f;
|
||||
|
||||
// Considerar el sentido de giro
|
||||
if (motor.Sentido_contrario)
|
||||
girosPorSegundo = -girosPorSegundo;
|
||||
|
||||
// Calcular incremento de pulsos para este ciclo
|
||||
float segundosTranscurridos = elapsedMilliseconds / 1000f;
|
||||
float incrementoPulsos = girosPorSegundo * Pulsos_Por_Vuelta * segundosTranscurridos;
|
||||
|
||||
// Actualizar valor del encoder
|
||||
Valor_Actual = (Valor_Actual + incrementoPulsos) % Pulsos_Por_Vuelta;
|
||||
if (Valor_Actual < 0) Valor_Actual += Pulsos_Por_Vuelta;
|
||||
|
||||
// Actualizar color basado en si está girando
|
||||
Color_oculto = Math.Abs(girosPorSegundo) > 0.01f ? Brushes.LightGreen : Brushes.Gray;
|
||||
|
||||
// Escribir valor al PLC si hay tag configurado
|
||||
if (!string.IsNullOrEmpty(Tag_Valor))
|
||||
{
|
||||
EscribirWordTagScaled(Tag_Valor, Valor_Actual, 0, Pulsos_Por_Vuelta, 0, 27648);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
base.ucLoaded();
|
||||
OnId_MotorChanged(Id_Motor);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucEncoderMotor : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucEncoderMotor()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += OnLoaded;
|
||||
this.Unloaded += OnUnloaded;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucLoaded();
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucUnLoaded();
|
||||
}
|
||||
|
||||
public void Highlight(bool State) { }
|
||||
|
||||
public ZIndexEnum ZIndex()
|
||||
{
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucEncoderMotorLineal"
|
||||
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:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osEncoderMotorLineal />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid Width="50" Height="50">
|
||||
<Ellipse Fill="{Binding Color_oculto}" Stroke="DarkGray" StrokeThickness="2" Width="30" Height="30" />
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,152 @@
|
|||
// EncoderMotorLinealViewModel.cs
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Windows.Media;
|
||||
using System.ComponentModel;
|
||||
using LibS7Adv;
|
||||
using System.Diagnostics;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using CtrEditor.FuncionesBase;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
public partial class osEncoderMotorLineal : osBase, IosBase
|
||||
{
|
||||
private osBase Motor = null;
|
||||
private Stopwatch Stopwatch = new Stopwatch();
|
||||
private double stopwatch_last = 0;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Encoder Motor Lineal";
|
||||
}
|
||||
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private Brush color_oculto;
|
||||
|
||||
[ObservableProperty]
|
||||
public float velocidadActual;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Pulsos por Hz por segundo : K")]
|
||||
[property: Category("Encoder Config:")]
|
||||
public float pulsos_Por_Hz;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Valor actual del encoder")]
|
||||
[property: Category("Encoder Status:")]
|
||||
public float valor_Actual;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Link to Motor")]
|
||||
[property: Category("PLC link:")]
|
||||
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||
string id_Motor;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Description("Tag para escribir el valor del encoder")]
|
||||
[property: Category("PLC link:")]
|
||||
string tag_Valor;
|
||||
|
||||
partial void OnId_MotorChanged(string value)
|
||||
{
|
||||
if (Motor != null)
|
||||
Motor.PropertyChanged -= OnMotorPropertyChanged;
|
||||
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||
{
|
||||
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
|
||||
if (Motor != null)
|
||||
Motor.PropertyChanged += OnMotorPropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||
{
|
||||
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||
}
|
||||
}
|
||||
|
||||
public osEncoderMotorLineal()
|
||||
{
|
||||
Pulsos_Por_Hz = 3000; // Por defecto, un pulso por grado
|
||||
Color_oculto = Brushes.Gray;
|
||||
Stopwatch.Start();
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
if (Motor != null && Motor is osVMmotorSim motor)
|
||||
{
|
||||
VelocidadActual = motor.Velocidad;
|
||||
|
||||
// Calcular giros por segundo basado en la velocidad actual
|
||||
float pulsosPorHz = (VelocidadActual * Pulsos_Por_Hz) / 100f;
|
||||
|
||||
// Considerar el sentido de giro
|
||||
if (motor.Sentido_contrario)
|
||||
pulsosPorHz = -pulsosPorHz;
|
||||
|
||||
// Calcular incremento de pulsos para este ciclo
|
||||
float segundosTranscurridos = elapsedMilliseconds / 1000f;
|
||||
float incrementoPulsos = pulsosPorHz * segundosTranscurridos;
|
||||
|
||||
// Actualizar valor del encoder
|
||||
Valor_Actual = (Valor_Actual + incrementoPulsos);
|
||||
|
||||
// Actualizar color basado en si está girando
|
||||
Color_oculto = Math.Abs(pulsosPorHz) > 0.01f ? Brushes.LightGreen : Brushes.Gray;
|
||||
|
||||
// Escribir valor al PLC si hay tag configurado
|
||||
if (!string.IsNullOrEmpty(Tag_Valor))
|
||||
{
|
||||
EscribirDINTTag(tag_Valor, (int)Valor_Actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
base.ucLoaded();
|
||||
OnId_MotorChanged(Id_Motor);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucEncoderMotorLineal : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucEncoderMotorLineal()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += OnLoaded;
|
||||
this.Unloaded += OnUnloaded;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucLoaded();
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucUnLoaded();
|
||||
}
|
||||
|
||||
public void Highlight(bool State) { }
|
||||
|
||||
public ZIndexEnum ZIndex()
|
||||
{
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,12 +53,26 @@ namespace CtrEditor.ObjetosSim
|
|||
b = VisualRepresentation;
|
||||
c = simulationManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract partial class osBase : ObservableObject
|
||||
{
|
||||
public virtual string Nombre { get; set; } = "osBase";
|
||||
|
||||
public osBase()
|
||||
{
|
||||
if (float.IsNaN(Left))
|
||||
{
|
||||
Left = 0;
|
||||
}
|
||||
|
||||
if (float.IsNaN(Top))
|
||||
{
|
||||
Top = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private Storyboard _storyboard;
|
||||
[JsonIgnore]
|
||||
|
@ -210,7 +224,7 @@ namespace CtrEditor.ObjetosSim
|
|||
Id = new UniqueId().ObtenerNuevaID();
|
||||
}
|
||||
|
||||
// Group
|
||||
// Group as FacePlate
|
||||
[ObservableProperty]
|
||||
[property: Description("This is a link to a faceplate. It works like an anchor.")]
|
||||
[property: Category("Group:")]
|
||||
|
@ -253,6 +267,56 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
}
|
||||
|
||||
// Group as FacePlate
|
||||
[ObservableProperty]
|
||||
[property: Description("This is a link to a FromPlate that moves automatically. It works like an anchor.")]
|
||||
[property: Category("Group:")]
|
||||
[property: ItemsSource(typeof(osBaseItemsSource<osFramePlate>))]
|
||||
private string group_FramePanel;
|
||||
|
||||
[JsonIgnore]
|
||||
private osFramePlate FramePlate;
|
||||
[JsonIgnore]
|
||||
private bool isUpdatingFromFramePlate = false;
|
||||
|
||||
partial void OnGroup_FramePanelChanged(string value)
|
||||
{
|
||||
if (FramePlate != null)
|
||||
FramePlate.PropertyChanged -= OnFramePlatePropertyChanged;
|
||||
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||
{
|
||||
FramePlate = (osFramePlate)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osFramePlate && s.Nombre == value), null);
|
||||
if (FramePlate != null)
|
||||
FramePlate.PropertyChanged += OnFramePlatePropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFramePlatePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (!isUpdatingFromFramePlate)
|
||||
{
|
||||
isUpdatingFromFramePlate = true;
|
||||
|
||||
if (e.PropertyName == nameof(osFramePlate.Nombre))
|
||||
Group_Panel = ((osFramePlate)sender).Nombre;
|
||||
|
||||
if (e.PropertyName == nameof(osFramePlate.Top))
|
||||
{
|
||||
Top += ((osFramePlate)sender).offsetY;
|
||||
OnMoveResizeRotate();
|
||||
}
|
||||
|
||||
if (e.PropertyName == nameof(osFramePlate.Left))
|
||||
{
|
||||
Left += ((osFramePlate)sender).offsetX;
|
||||
OnMoveResizeRotate();
|
||||
}
|
||||
|
||||
isUpdatingFromFramePlate = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ShowPreviewWindow(Stream imageStream)
|
||||
{
|
||||
// Create a new window for preview
|
||||
|
@ -535,6 +599,7 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
ActualizarLeftTop();
|
||||
OnGroup_PanelChanged(Group_Panel); // Establece el link y se suscribe a los eventos
|
||||
OnGroup_FramePanelChanged(Group_FramePanel); // Establece el link y se suscribe a los eventos
|
||||
Show_On_This_Page = Show_On_This_Page; // Update data
|
||||
}
|
||||
|
||||
|
@ -687,6 +752,17 @@ namespace CtrEditor.ObjetosSim
|
|||
_plc.EscribirBool(Tag, Value);
|
||||
}
|
||||
|
||||
public void EscribirDINTTag(string Tag, float Value)
|
||||
{
|
||||
if (_plc == null) return;
|
||||
if (!string.IsNullOrEmpty(Tag))
|
||||
{
|
||||
SDataValue plcData = new SDataValue();
|
||||
plcData.Int32 = (int)Value;
|
||||
_plc.EscribirTag(Tag, plcData);
|
||||
}
|
||||
}
|
||||
|
||||
public void EscribirWordTagScaled(string Tag, float Value, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max)
|
||||
{
|
||||
if (_plc == null) return;
|
||||
|
|
|
@ -726,6 +726,12 @@ namespace CtrEditor.Simulacion
|
|||
// ******************************************************************************************************************************************
|
||||
// ******************************************************************************************************************************************
|
||||
|
||||
public void Start()
|
||||
{
|
||||
stopwatch.Start();
|
||||
stopwatch_last = stopwatch.Elapsed.TotalMilliseconds;
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
||||
|
|
Loading…
Reference in New Issue