From 9c8eb0b3488f5bd78f47a5bf4bd233237058ed76 Mon Sep 17 00:00:00 2001 From: Miguel Date: Tue, 14 May 2024 12:04:22 +0200 Subject: [PATCH] Trabajando en la simulacion del Motor con el PLC --- MainViewModel.cs | 5 +- MainWindow.xaml.cs | 47 +++++++---- ObjetosSim/ucVMmotorSim.xaml.cs | 102 +++++++++++++++++++++++- Siemens/PLCControl.xaml.cs | 16 +++- Simulacion/FPhysics.cs | 136 +++++++++++++------------------- 5 files changed, 204 insertions(+), 102 deletions(-) diff --git a/MainViewModel.cs b/MainViewModel.cs index b09dfca..11502eb 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -130,11 +130,13 @@ namespace CtrEditor simulationManager.Debug_DrawInitialBodies(); _timerSimulacion.Start(); + simulationManager.stopwatch.Start(); } private void StopSimulation() { _timerSimulacion.Stop(); + simulationManager.stopwatch.Stop(); } private void OnTickSimulacion(object sender, EventArgs e) @@ -147,7 +149,7 @@ namespace CtrEditor objetoSimulable.UpdateGeometryStep(); } - simulationManager.Step((float)_timerSimulacion.Interval.TotalMilliseconds); + simulationManager.Step(); foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.UpdateControl(); @@ -285,6 +287,7 @@ namespace CtrEditor try { ObjetosSimulables.Clear(); + simulationManager.Clear(); if (_selectedImage != null) { string jsonPath = datosDeTrabajo.ObtenerPathImagenConExtension(_selectedImage, ".json"); diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 06d69fe..948e239 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -19,6 +19,7 @@ using Label = System.Windows.Controls.Label; using MouseEventArgs = System.Windows.Input.MouseEventArgs; using TextBox = System.Windows.Controls.TextBox; using UserControl = System.Windows.Controls.UserControl; +using CheckBox = System.Windows.Controls.CheckBox; //using OpenCvSharp; @@ -416,41 +417,55 @@ namespace CtrEditor foreach (var property in properties) { - if (property.PropertyType == typeof(float) || property.PropertyType == typeof(string)) + var horizontalPanel = new StackPanel { Orientation = Orientation.Horizontal }; + + var label = new Label { Content = property.Name }; + + if (property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int)) { - var label = new Label { Content = property.Name }; var textBox = new TextBox { Width = 200, Margin = new Thickness(0) }; var binding = new Binding(property.Name) { Source = selectedObject, Mode = BindingMode.TwoWay, - UpdateSourceTrigger = UpdateSourceTrigger.LostFocus, // Actualizar solo al perder el foco - //Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"] // Usar el convertidor + UpdateSourceTrigger = UpdateSourceTrigger.LostFocus }; // Aplicar el convertidor solo a propiedades float if (property.PropertyType == typeof(float)) { - textBox.SetBinding(TextBox.TextProperty, binding); - } - else - { - textBox.SetBinding(TextBox.TextProperty, new Binding(property.Name) - { - Source = selectedObject, - Mode = BindingMode.TwoWay, - UpdateSourceTrigger = UpdateSourceTrigger.LostFocus - }); + binding.Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"]; } - PanelEdicion.Children.Add(label); - PanelEdicion.Children.Add(textBox); + textBox.SetBinding(TextBox.TextProperty, binding); + + horizontalPanel.Children.Add(label); + horizontalPanel.Children.Add(textBox); } + else if (property.PropertyType == typeof(bool)) + { + var checkBox = new CheckBox { Margin = new Thickness(5, 0, 0, 0) }; + + var binding = new Binding(property.Name) + { + Source = selectedObject, + Mode = BindingMode.TwoWay + }; + + checkBox.SetBinding(CheckBox.IsCheckedProperty, binding); + + horizontalPanel.Children.Add(label); + horizontalPanel.Children.Add(checkBox); + } + + PanelEdicion.Children.Add(horizontalPanel); } } + + private void MainWindow_Closed(object sender, EventArgs e) { if (DataContext is MainViewModel viewModel) diff --git a/ObjetosSim/ucVMmotorSim.xaml.cs b/ObjetosSim/ucVMmotorSim.xaml.cs index 56e419b..88f3b86 100644 --- a/ObjetosSim/ucVMmotorSim.xaml.cs +++ b/ObjetosSim/ucVMmotorSim.xaml.cs @@ -21,9 +21,25 @@ namespace CtrEditor.ObjetosSim /// /// Interaction logic for ucVMmotorSim.xaml /// + /// + public class VMSimMotor + { + public bool _STATUS_VFD_Ready; + public float STATUS_VFD_ACT_Speed_Hz; + public bool Motor_Running; + public bool STATUS_VFD_Trip; + public bool STATUS_VFD_Warning; + public bool STATUS_VFD_Coasting; + public bool OUT_Run; + public bool OUT_Stop; + public bool OUT_Reversal; + public float OUT_OUT_VFD_REQ_Speed_Hz; + } + + public class osVMmotorSim : osBase { - + // Otros datos y métodos relevantes para la simulación @@ -31,7 +47,12 @@ namespace CtrEditor.ObjetosSim private float _tamano; private float _left; private float _top; - private float _numeroMotor; + private int _numeroMotor; + private float _ratio; + private float _velocidad; + private bool _encendido; + public VMSimMotor motState = new VMSimMotor(); + public float Tamano { @@ -43,7 +64,17 @@ namespace CtrEditor.ObjetosSim } } - public float PLC_NumeroMotor + public bool Encendido + { + get => _encendido; + set + { + _encendido = value; + OnPropertyChanged(nameof(Encendido)); + } + } + + public int PLC_NumeroMotor { get => _numeroMotor; set @@ -88,6 +119,22 @@ namespace CtrEditor.ObjetosSim } } + public float Ratio { + get => _ratio; + set { + _ratio = value; + OnPropertyChanged(nameof(Ratio)); + } + } + + public float Velocidad { + get => _velocidad; + set { + _velocidad = value; + OnPropertyChanged(nameof(Velocidad)); + } + } + public osVMmotorSim() { Tamano = 0.30f; @@ -102,7 +149,49 @@ namespace CtrEditor.ObjetosSim public override void UpdateGeometryStep() { } - public override void UpdatePLC(PLCModel plc) { } + public override void UpdatePLC(PLCModel plc) { + var index = 0; + switch (PLC_NumeroMotor) + { + case < 100: + index = (int)PLC_NumeroMotor-30+300; + break; + } + + motState.OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run"); + motState.OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\""); + motState.OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz"); + + if (Encendido) + { + motState._STATUS_VFD_Ready = true; + motState.Motor_Running = true; + motState.STATUS_VFD_Trip = false; + motState.STATUS_VFD_Warning = false; + motState.STATUS_VFD_Coasting = false; + if (motState.STATUS_VFD_ACT_Speed_Hz < motState.OUT_OUT_VFD_REQ_Speed_Hz) + motState.STATUS_VFD_ACT_Speed_Hz += motState.OUT_OUT_VFD_REQ_Speed_Hz / 375 ; // Simulate Ramp + } else + { + motState._STATUS_VFD_Ready = false; + motState.Motor_Running = false; + motState.STATUS_VFD_Trip = true; + motState.STATUS_VFD_Warning = false; + motState.STATUS_VFD_Coasting = false; + if (motState.STATUS_VFD_ACT_Speed_Hz > 0) + motState.STATUS_VFD_ACT_Speed_Hz -= 1; // Simulate Ramp + } + + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", motState._STATUS_VFD_Ready); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", motState.Motor_Running); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Trip", motState.STATUS_VFD_Trip); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Warning", motState.STATUS_VFD_Warning); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Coasting", motState.STATUS_VFD_Coasting); + + plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz",(int)motState.STATUS_VFD_ACT_Speed_Hz); + + Velocidad = motState.STATUS_VFD_ACT_Speed_Hz/10; + } public override void UpdateControl() { @@ -123,6 +212,11 @@ namespace CtrEditor.ObjetosSim public ucVMmotorSim() { InitializeComponent(); + this.Loaded += OnLoaded; + } + private void OnLoaded(object sender, RoutedEventArgs e) + { + Datos?.ucLoaded(); } public void Resize(float width, float height) { } public void Move(float LeftPixels, float TopPixels) diff --git a/Siemens/PLCControl.xaml.cs b/Siemens/PLCControl.xaml.cs index dc4107a..c1bd50e 100644 --- a/Siemens/PLCControl.xaml.cs +++ b/Siemens/PLCControl.xaml.cs @@ -135,7 +135,7 @@ namespace CtrEditor.Siemens if (PLCInterface.Instance != null) { - CpuTime = PLCInterface.LeerInt16("\"DB HMI\".CPU_Scan_Time")?.ToString() ?? "N/A"; + CpuTime = PLCInterface.LeerTagInt16("\"DB HMI\".CPU_Scan_Time")?.ToString() ?? "N/A"; LastError = PLCInterface.LastError; } } @@ -202,6 +202,18 @@ namespace CtrEditor.Siemens LastError = pTag + ":" + ex.Message; } } + public void EscribirTagInt16(string pTag, int pValue) + { + try + { + Instance?.WriteInt16(pTag,(short) pValue); + } + catch (Exception ex) + { + LastError = pTag + ":" + ex.Message; + } + } + public bool LeerTagBool(string pTag) { try @@ -215,7 +227,7 @@ namespace CtrEditor.Siemens } } - public int? LeerInt16(string pTag) + public int? LeerTagInt16(string pTag) { try { diff --git a/Simulacion/FPhysics.cs b/Simulacion/FPhysics.cs index afaf216..72d2dcf 100644 --- a/Simulacion/FPhysics.cs +++ b/Simulacion/FPhysics.cs @@ -1,31 +1,20 @@ using System; using System.Collections.Generic; -using System.DirectoryServices; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Forms; using System.Windows.Media; using System.Windows.Shapes; -using CtrEditor.Convertidores; -using CtrEditor.ObjetosSim; -using FarseerPhysics.Collision.Shapes; -using FarseerPhysics.Common; using FarseerPhysics.Dynamics; -using FarseerPhysics.Dynamics.Contacts; using FarseerPhysics.Factories; +using FarseerPhysics.Collision.Shapes; using Microsoft.Xna.Framework; -using OpenCvSharp; -using Siemens.Simatic.Simulation.Runtime; -using static System.Windows.Forms.DataFormats; -using Point = System.Windows.Point; +using CtrEditor.Convertidores; +using FarseerPhysics.Common; +using System.Windows; +using System.Diagnostics; namespace CtrEditor.Simulacion { - public class simRectangle { public Body Body { get; private set; } @@ -56,17 +45,16 @@ namespace CtrEditor.Simulacion public void SetDimensions(float width, float height) { - // Primero, elimina el fixture antiguo Body.DestroyFixture(Body.FixtureList[0]); - // Crea un nuevo fixture con las nuevas dimensiones var newShape = new PolygonShape(PolygonTools.CreateRectangle(width / 2, height / 2), 1f); Body.CreateFixture(newShape); } public void Create(float width, float height, Vector2 position, float angle = 0) { - if (Body != null) { + if (Body != null) + { _world.RemoveBody(Body); } Body = BodyFactory.CreateRectangle(_world, width, height, 1f, position); @@ -75,12 +63,8 @@ namespace CtrEditor.Simulacion Body.Rotation = MathHelper.ToRadians(angle); Body.UserData = this; // Importante para la identificación durante la colisión } - - - // Otros métodos según sea necesario, como mover, rotar, etc. } - public class simLine { public Body Body { get; private set; } @@ -109,8 +93,6 @@ namespace CtrEditor.Simulacion } } - - public class simCircle { public Body Body { get; private set; } @@ -129,7 +111,7 @@ namespace CtrEditor.Simulacion public float CenterX { get { return Body.Position.X; } - set { } + set { } } public float CenterY @@ -145,7 +127,8 @@ namespace CtrEditor.Simulacion public float Mass { - get { + get + { if (_mass <= 0) _mass = 1; return _mass; @@ -159,12 +142,12 @@ namespace CtrEditor.Simulacion { _world.RemoveBody(Body); // Remover el cuerpo anterior si existe } - Body = BodyFactory.CreateCircle(_world, _radius, 10f, position); + Body = BodyFactory.CreateCircle(_world, _radius, 1f, position); Body.BodyType = BodyType.Dynamic; // Restablecer manejador de eventos de colisión Body.OnCollision += HandleCollision; - Body.OnSeparation += HandleOnSeparation; + //Body.OnSeparation += HandleOnSeparation; Body.UserData = this; // Importante para la identificación durante la colisión @@ -172,20 +155,14 @@ namespace CtrEditor.Simulacion Body.Friction = 0.5f; // Ajustar según sea necesario para tu simulación // Configurar amortiguamiento - Body.LinearDamping = 0.01f; // Ajustar para controlar la reducción de la velocidad lineal - Body.AngularDamping = 1f; // Ajustar para controlar la reducción de la velocidad angular + Body.LinearDamping = 0f; // Ajustar para controlar la reducción de la velocidad lineal + Body.AngularDamping = 0f; // Ajustar para controlar la reducción de la velocidad angular Body.Restitution = 0.2f; // Baja restitución para menos rebote - Body.IsBullet = true; - } - - private void HandleOnSeparation(Fixture fixtureA, Fixture fixtureB) - { - Body.LinearDamping = 5f; // Ajustar para controlar la reducción de la velocidad lineal + Body.IsBullet = true; } public void SetPosition(float x, float y) { - // Usar el ángulo actual, ya que no es relevante para un círculo en este contexto Body.SetTransform(new Vector2(x, y), Body.Rotation); } @@ -200,38 +177,30 @@ namespace CtrEditor.Simulacion Mass = mass; } - private bool HandleCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact) { if (fixtureB.Body.UserData is simRectangle) { simRectangle conveyor = fixtureB.Body.UserData as simRectangle; - ApplyConveyorEffect(conveyor, fixtureA, contact); - return true; // No aplicar respuestas fisicas + ApplyConveyorEffect(conveyor, fixtureA); + return true; // No aplicar respuestas físicas } - return true; // No aplicar respuestas fisicas + return true; // No aplicar respuestas físicas } - private void ApplyConveyorEffect(simRectangle conveyor, Fixture circleFixture, FarseerPhysics.Dynamics.Contacts.Contact contact) + private void HandleOnSeparation(Fixture fixtureA, Fixture fixtureB) + { + // Aquí puedes restablecer cualquier estado si es necesario al separarse de un simRectangle + } + + private void ApplyConveyorEffect(simRectangle conveyor, Fixture circleFixture) { - // Calcular la velocidad deseada en metros por segundo float speedMetersPerSecond = conveyor.Speed / 60.0f; Vector2 desiredVelocity = new Vector2((float)Math.Cos(conveyor.Body.Rotation), (float)Math.Sin(conveyor.Body.Rotation)) * speedMetersPerSecond; - - // Calcular la fuerza necesaria para alcanzar esa velocidad - Vector2 velocityChange = desiredVelocity - circleFixture.Body.LinearVelocity; - float timeStep = 1.0f / 60.0f; // Asumiendo 60 Hz de tasa de actualización - Vector2 acceleration = velocityChange / timeStep; - Vector2 force = acceleration / Mass; - - // Aplicar la fuerza al círculo - circleFixture.Body.ApplyForce(force); + circleFixture.Body.LinearVelocity = desiredVelocity; } - - } - public class SimulationManagerFP { private World world; @@ -239,16 +208,40 @@ namespace CtrEditor.Simulacion public List circles; public List rectangles; public List lines; + public Stopwatch stopwatch; public Canvas DebugCanvas { get => simulationCanvas; set => simulationCanvas = value; } public SimulationManagerFP() { - world = new World(new Vector2(0,0)); // Vector2.Zero + world = new World(new Vector2(0, 0)); // Vector2.Zero circles = new List(); rectangles = new List(); lines = new List(); + stopwatch = new Stopwatch(); } + + public void Clear() + { + circles.Clear(); + rectangles.Clear(); + lines.Clear(); + world.Clear(); + } + + public void Step() + { + // Detener el cronómetro y obtener el tiempo transcurrido en milisegundos + stopwatch.Stop(); + float elapsedMilliseconds = (float)stopwatch.Elapsed.TotalMilliseconds; + + // Reiniciar el cronómetro para la próxima medición + stopwatch.Restart(); + + // Pasar el tiempo transcurrido al método Step + world.Step(elapsedMilliseconds / 1000.0f); + } + public simCircle AddCircle(float diameter, Vector2 position, float mass) { simCircle circle = new simCircle(world, diameter, position, mass); @@ -256,7 +249,6 @@ namespace CtrEditor.Simulacion return circle; } - public simRectangle AddRectangle(float width, float height, Vector2 position, float angle) { simRectangle rectangle = new simRectangle(world, width, height, position, angle); @@ -271,14 +263,6 @@ namespace CtrEditor.Simulacion return line; } - // Otros métodos para agregar círculos y ejecutar la simulación - - public void Step(float timeStep) - { - world.Step(timeStep/1000.0f); - // Actualiza y gestiona otras lógicas si es necesario - } - public void Debug_DrawInitialBodies() { ClearSimulationShapes(); @@ -334,14 +318,14 @@ namespace CtrEditor.Simulacion EdgeShape edge = fixture.Shape as EdgeShape; Line line = new Line { - X1 = p(edge.Vertex1.X + fixture.Body.Position.X ), // Aplicar escala y posición - Y1 = p(edge.Vertex1.Y + fixture.Body.Position.Y ), - X2 = p(edge.Vertex2.X + fixture.Body.Position.X ), - Y2 = p(edge.Vertex2.Y + fixture.Body.Position.Y ), + X1 = p(edge.Vertex1.X + fixture.Body.Position.X), // Aplicar escala y posición + Y1 = p(edge.Vertex1.Y + fixture.Body.Position.Y), + X2 = p(edge.Vertex2.X + fixture.Body.Position.X), + Y2 = p(edge.Vertex2.Y + fixture.Body.Position.Y), Stroke = Brushes.Black, StrokeThickness = 2 }; - return line; + return line; } private System.Windows.Shapes.Shape DrawCircle(Fixture fixture) @@ -354,8 +338,8 @@ namespace CtrEditor.Simulacion Stroke = Brushes.Black, StrokeThickness = 2 }; - Canvas.SetLeft(ellipse, p(fixture.Body.Position.X - circle.Radius )); - Canvas.SetTop(ellipse, p(fixture.Body.Position.Y - circle.Radius )); + Canvas.SetLeft(ellipse, p(fixture.Body.Position.X - circle.Radius)); + Canvas.SetTop(ellipse, p(fixture.Body.Position.Y - circle.Radius)); return ellipse; } @@ -369,7 +353,6 @@ namespace CtrEditor.Simulacion foreach (Vector2 vertex in polyShape.Vertices) { - // Aplicar la rotación alrededor del origen y luego trasladar float rotatedX = vertex.X * cos - vertex.Y * sin + fixture.Body.Position.X; float rotatedY = vertex.X * sin + vertex.Y * cos + fixture.Body.Position.Y; @@ -378,10 +361,5 @@ namespace CtrEditor.Simulacion return polygon; } - - - } - - }