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;
}
-
-
-
}
-
-
}