diff --git a/trick_sims/SIM_msd/Modified_data/realtime.py b/trick_sims/SIM_msd/Modified_data/realtime.py new file mode 100644 index 00000000..76de2adf --- /dev/null +++ b/trick_sims/SIM_msd/Modified_data/realtime.py @@ -0,0 +1,7 @@ +trick.frame_log_on() +trick.real_time_enable() +trick.exec_set_software_frame(0.1) +trick.itimer_enable() +trick.exec_set_enable_freeze(True) +trick.exec_set_freeze_command(True) +trick.sim_control_panel_set_enabled(True) \ No newline at end of file diff --git a/trick_sims/SIM_msd/README.md b/trick_sims/SIM_msd/README.md new file mode 100644 index 00000000..b546ab88 --- /dev/null +++ b/trick_sims/SIM_msd/README.md @@ -0,0 +1,84 @@ +# SIM_MSD + +SIM\_MSD is a simulator for a mass-spring-damper system. + +![Picture of MSD](./images/MSD0.png) + + The system is described by the equation _mẍ_ + _bẋ_ + _kx_ = _F_, where: + + _m_ is the mass of an object. + + _x_ is the position of the mass. + + _b_ is the damping coefficient. + + _k_ is the spring coefficient. + + _F_ is an external force applied to the mass. + +--- +### Building the Simulation + +In the SIM_MSD directory, execute **trick-CP** to build the simulation executable. When it's complete, you should see: + +``` +=== Simulation make complete === +``` + +Now **cd** into models/Graphics/ and type **make**. This builds the display client for the simulation. + +### Running the Simulation +In the SIM_MSD directory: + +``` +% ./S_main_*.exe RUN_test/input.py +``` + +The following windows should appear: + +![Picture of MSD](./images/MSD2.png) + +![Picture of Control](./images/MSD3.png) + +### Controlling the Simulation +Click **Start** to begin the simulation. + +Click **Reset** to freeze the simulation and reset the position and velocity to +their initial conditions. + +Change **Position** and **Velocity** to adjust the initial conditions for those +attributes. + +Change **Mass**, **Spring Coefficient**, **Damping Coefficient**, and **Applied +Force** to adjust initial conditions _**and**_ also update the sim in real-time. + + + + + + +--- +The following inputs can be set in any of the RUN_*/input.py files to change +the inputs on startup +### Inputs + +Variable | Type | Units | Default Value +---------- |-----------|-------|-------------- +dyn.msd.x_0 | double | m | 5.0 +dyn.msd.v_0 | double | m/s | 0.0 +dyn.msd.b | double | N.s/m | 0.5 +dyn.msd.k | double | N/m | 2.0 +dyn.msd.F | double | N | 5.0 +dyn.msd.m | double | kg | 1.0 + +--- +Some sample input.py files have been created to demonstrate different +mass-spring-damper conditions +### Samples + +Path |Type +------------------------|---------------------------------------------- +RUN_underdamp/input.py |Underdamped Harmonic Oscillator +RUN_critdamp/input.py |Critically Damped Harmonic Oscillator +RUN_overdamp/input.py |Overdamped Harmonic Oscillator +RUN_nodamp/input.py | Simple Harmonic Oscillator (No Damping Force) diff --git a/trick_sims/SIM_msd/RUN_critdamp/input.py b/trick_sims/SIM_msd/RUN_critdamp/input.py new file mode 100644 index 00000000..dbad25fe --- /dev/null +++ b/trick_sims/SIM_msd/RUN_critdamp/input.py @@ -0,0 +1,23 @@ +dyn_integloop.getIntegrator(trick.Runge_Kutta_4, 4) +execfile("Modified_data/realtime.py") + +dyn.msd.b = 2*(2**(0.5)) + +#========================================== +# Start the display VarServer Client +#========================================== +varServerPort = trick.var_server_get_port(); +MsdGui_path = "models/graphics/dist/MsdGui.jar" + +if (os.path.isfile(MsdGui_path)) : + MsdGui_cmd = "java -jar " \ + + MsdGui_path \ + + " " + str(varServerPort) + " &" ; + print(MsdGui_cmd) + os.system( MsdGui_cmd); +else : + print('==================================================================================') + print('MsdGui needs to be built. Please \"cd\" into models/Graphics and type \"make\".') + print('==================================================================================') + +trick.stop(300.0) diff --git a/trick_sims/SIM_msd/RUN_nodamp/input.py b/trick_sims/SIM_msd/RUN_nodamp/input.py new file mode 100644 index 00000000..bbb30c2d --- /dev/null +++ b/trick_sims/SIM_msd/RUN_nodamp/input.py @@ -0,0 +1,23 @@ +dyn_integloop.getIntegrator(trick.Runge_Kutta_4, 4) +execfile("Modified_data/realtime.py") + +dyn.msd.b = 0 + +#========================================== +# Start the display VarServer Client +#========================================== +varServerPort = trick.var_server_get_port(); +MsdGui_path = "models/graphics/dist/MsdGui.jar" + +if (os.path.isfile(MsdGui_path)) : + MsdGui_cmd = "java -jar " \ + + MsdGui_path \ + + " " + str(varServerPort) + " &" ; + print(MsdGui_cmd) + os.system( MsdGui_cmd); +else : + print('==================================================================================') + print('MsdGui needs to be built. Please \"cd\" into models/Graphics and type \"make\".') + print('==================================================================================') + +trick.stop(300.0) diff --git a/trick_sims/SIM_msd/RUN_overdamp/input.py b/trick_sims/SIM_msd/RUN_overdamp/input.py new file mode 100644 index 00000000..9d62bbe3 --- /dev/null +++ b/trick_sims/SIM_msd/RUN_overdamp/input.py @@ -0,0 +1,23 @@ +dyn_integloop.getIntegrator(trick.Runge_Kutta_4, 4) +execfile("Modified_data/realtime.py") + +dyn.msd.b = 4*(2**(0.5)) - 1/2 + +#========================================== +# Start the display VarServer Client +#========================================== +varServerPort = trick.var_server_get_port(); +MsdGui_path = "models/graphics/dist/MsdGui.jar" + +if (os.path.isfile(MsdGui_path)) : + MsdGui_cmd = "java -jar " \ + + MsdGui_path \ + + " " + str(varServerPort) + " &" ; + print(MsdGui_cmd) + os.system( MsdGui_cmd); +else : + print('==================================================================================') + print('MsdGui needs to be built. Please \"cd\" into models/Graphics and type \"make\".') + print('==================================================================================') + +trick.stop(300.0) diff --git a/trick_sims/SIM_msd/RUN_test/input.py b/trick_sims/SIM_msd/RUN_test/input.py new file mode 100644 index 00000000..fb5c80ab --- /dev/null +++ b/trick_sims/SIM_msd/RUN_test/input.py @@ -0,0 +1,21 @@ +dyn_integloop.getIntegrator(trick.Runge_Kutta_4, 4) +execfile("Modified_data/realtime.py") + +#========================================== +# Start the display VarServer Client +#========================================== +varServerPort = trick.var_server_get_port(); +MsdGui_path = "models/graphics/dist/MsdGui.jar" + +if (os.path.isfile(MsdGui_path)) : + MsdGui_cmd = "java -jar " \ + + MsdGui_path \ + + " " + str(varServerPort) + " &" ; + print(MsdGui_cmd) + os.system( MsdGui_cmd); +else : + print('==================================================================================') + print('MsdGui needs to be built. Please \"cd\" into models/Graphics and type \"make\".') + print('==================================================================================') + +trick.stop(300.0) diff --git a/trick_sims/SIM_msd/RUN_underdamp/input.py b/trick_sims/SIM_msd/RUN_underdamp/input.py new file mode 100644 index 00000000..1ced0935 --- /dev/null +++ b/trick_sims/SIM_msd/RUN_underdamp/input.py @@ -0,0 +1,23 @@ +dyn_integloop.getIntegrator(trick.Runge_Kutta_4, 4) +execfile("Modified_data/realtime.py") + +dyn.msd.b = 0.5 + +#========================================== +# Start the display VarServer Client +#========================================== +varServerPort = trick.var_server_get_port(); +MsdGui_path = "models/graphics/dist/MsdGui.jar" + +if (os.path.isfile(MsdGui_path)) : + MsdGui_cmd = "java -jar " \ + + MsdGui_path \ + + " " + str(varServerPort) + " &" ; + print(MsdGui_cmd) + os.system( MsdGui_cmd); +else : + print('==================================================================================') + print('MsdGui needs to be built. Please \"cd\" into models/Graphics and type \"make\".') + print('==================================================================================') + +trick.stop(300.0) diff --git a/trick_sims/SIM_msd/S_define b/trick_sims/SIM_msd/S_define new file mode 100644 index 00000000..3b74619c --- /dev/null +++ b/trick_sims/SIM_msd/S_define @@ -0,0 +1,33 @@ +/************************TRICK HEADER************************* +PURPOSE: + (This S_define works with the RUN_numeric input file) +LIBRARY DEPENDENCIES: + ( + (msd/src/msd_init.cpp) + (msd/src/msd_numeric.cpp) + (msd/src/msd_shutdown.cpp) + (msd/src/msd.cpp) + (msd/src/msd_deriv.cpp) + (msd/src/msd_integ.cpp) + ) +*************************************************************/ + +#include "sim_objects/default_trick_sys.sm" +##include "msd/include/msd_numeric.hh" + + +class MSDSimObject : public Trick::SimObject { + + public: + MSD msd; + + MSDSimObject() { + ("default_data") msd_default_data( msd ) ; + ("initialization") msd_init( msd ) ; + ("derivative") msd.state_deriv(); + ("integration") trick_ret= msd.state_integ(); + } +} ; + +MSDSimObject dyn ; +IntegLoop dyn_integloop (0.01) dyn ; \ No newline at end of file diff --git a/trick_sims/SIM_msd/S_overrides.mk b/trick_sims/SIM_msd/S_overrides.mk new file mode 100644 index 00000000..1b84a37b --- /dev/null +++ b/trick_sims/SIM_msd/S_overrides.mk @@ -0,0 +1,2 @@ +TRICK_CFLAGS += -Imodels +TRICK_CXXFLAGS += -Imodels \ No newline at end of file diff --git a/trick_sims/SIM_msd/images/MSD0.png b/trick_sims/SIM_msd/images/MSD0.png new file mode 100644 index 00000000..11f07ac6 Binary files /dev/null and b/trick_sims/SIM_msd/images/MSD0.png differ diff --git a/trick_sims/SIM_msd/images/MSD1.png b/trick_sims/SIM_msd/images/MSD1.png new file mode 100644 index 00000000..9472a7fe Binary files /dev/null and b/trick_sims/SIM_msd/images/MSD1.png differ diff --git a/trick_sims/SIM_msd/images/MSD2.png b/trick_sims/SIM_msd/images/MSD2.png new file mode 100644 index 00000000..2466e633 Binary files /dev/null and b/trick_sims/SIM_msd/images/MSD2.png differ diff --git a/trick_sims/SIM_msd/images/MSD3.png b/trick_sims/SIM_msd/images/MSD3.png new file mode 100644 index 00000000..fcb1a9d3 Binary files /dev/null and b/trick_sims/SIM_msd/images/MSD3.png differ diff --git a/trick_sims/SIM_msd/models/graphics/MSD/src/MsdController.java b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdController.java new file mode 100644 index 00000000..ebeebe4f --- /dev/null +++ b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdController.java @@ -0,0 +1,200 @@ +/* + * Trick + * 2018 (c) National Aeronautics and Space Administration (NASA) + * Programmers: Scott P. Fennell + */ + + + +import javax.swing.*; +import javax.swing.JTextField; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MsdController extends JFrame { + JTextField positionTextField; + JTextField velocityTextField; + JTextField springTextField; + JTextField dampingTextField; + JTextField forceTextField; + JTextField massTextField; + + ButtonPanel buttonPanel; + JPanel positionPanel; + JPanel labelPanel; + + public void armResetCommand() { + buttonPanel.armResetCommand(); + } + + public void armStartCommand() { + buttonPanel.armStartCommand(); + } + + public boolean getResetCommand() { + return buttonPanel.getResetCommand(); + } + + public boolean getStartCommand() { + return buttonPanel.getStartCommand(); + } + + public MsdController(MsdDisplay display){ + setTitle("Mass-Spring-Damper Control"); + setLayout(new GridLayout(1, 2)); + + buttonPanel = new ButtonPanel(display); + positionPanel = new JPanel(); + labelPanel = new JPanel(); + labelPanel.setAlignmentX(Component.RIGHT_ALIGNMENT); + + positionPanel.setLayout(new GridLayout(13, 1)); + labelPanel.setLayout(new GridLayout(13, 1)); + JPanel framePanel = new JPanel(); + GridLayout layout = new GridLayout(1, 3); + framePanel.setLayout(layout); + + positionTextField = new JTextField(2); + velocityTextField = new JTextField(2); + massTextField = new JTextField(2); + forceTextField = new JTextField(2); + springTextField = new JTextField(2); + dampingTextField = new JTextField(2); + + + + + + + labelPanel.add(new JLabel()); + labelPanel.add(new JLabel("Position: ")); + labelPanel.add(new JLabel()); + labelPanel.add(new JLabel("Velocity: ")); + labelPanel.add(new JLabel()); + labelPanel.add(new JLabel("Mass: ")); + labelPanel.add(new JLabel()); + labelPanel.add(new JLabel("Spring Coefficient: ")); + labelPanel.add(new JLabel()); + labelPanel.add(new JLabel("Damping Coefficient: ")); + labelPanel.add(new JLabel()); + labelPanel.add(new JLabel("Applied Force: ")); + labelPanel.add(new JLabel()); + + positionPanel.add(new JLabel()); + positionPanel.add(positionTextField); + positionPanel.add(new JLabel()); + positionPanel.add(velocityTextField); + positionPanel.add(new JLabel()); + positionPanel.add(massTextField); + positionPanel.add(new JLabel()); + positionPanel.add(springTextField); + positionPanel.add(new JLabel()); + positionPanel.add(dampingTextField); + positionPanel.add(new JLabel()); + positionPanel.add(forceTextField); + positionPanel.add(new JLabel()); + + + for(Component L : labelPanel.getComponents()){ + if(L instanceof JLabel){ + ((JLabel)L).setHorizontalAlignment(JLabel.RIGHT); + } + } + framePanel.add(buttonPanel); + framePanel.add(labelPanel); + framePanel.add(positionPanel); + + add(framePanel); + positionPanel.setSize(positionPanel.getLayout().preferredLayoutSize(positionPanel)); + buttonPanel.setSize(buttonPanel.getPreferredSize()); + setSize(getPreferredSize()); + setLocationByPlatform(true); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + } + + class ButtonPanel extends JPanel implements ActionListener { + + private MsdDisplay msdDisplay; + private boolean startCommand; + private boolean resetCommand; + private JButton startButton, resetButton, zoomOutButton, zoomInButton; + + + public ButtonPanel(MsdDisplay cd) { + msdDisplay = cd; + startCommand = false; + resetCommand = false; + setLayout(new GridLayout(4,1 )); + + startButton = new JButton("Start"); + startButton.addActionListener(this); + startButton.setActionCommand("start"); + startButton.setToolTipText("Start MSD"); + add(startButton); + + resetButton = new JButton("Reset"); + resetButton.addActionListener(this); + resetButton.setActionCommand("reset"); + resetButton.setToolTipText("Reset MSD"); + add(resetButton); + + zoomOutButton = new JButton("\u25b2"); + zoomOutButton.addActionListener(this); + zoomOutButton.setActionCommand("zoomout"); + zoomOutButton.setToolTipText("Zoom in"); + add(zoomOutButton); + + zoomInButton = new JButton("\u25bc"); + zoomInButton.addActionListener(this); + zoomInButton.setActionCommand("zoomin"); + zoomInButton.setToolTipText("Zoom Out"); + add(zoomInButton); + + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + switch (s) { + case "start": + startCommand = true; + break; + case "reset": + resetCommand = true; + + break; + case "zoomin": + msdDisplay.setScale(msdDisplay.getScale() / 2); + break; + case "zoomout": + msdDisplay.setScale(msdDisplay.getScale() * 2); + break; + default: + System.out.println("Unknown Action Command:" + s); + break; + } + } + + public void armResetCommand() { + resetCommand = false; + startButton.setForeground(Color.red); + } + + public void armStartCommand() { + startCommand = false; + startButton.setForeground(Color.gray); + } + + public boolean getResetCommand() { + return resetCommand; + } + + public boolean getStartCommand() { + return startCommand; + } + + } // class ButtonPanel + + +} diff --git a/trick_sims/SIM_msd/models/graphics/MSD/src/MsdDisplay.java b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdDisplay.java new file mode 100644 index 00000000..46aec4d1 --- /dev/null +++ b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdDisplay.java @@ -0,0 +1,50 @@ +/* + * Trick + * 2018 (c) National Aeronautics and Space Administration (NASA) + * Programmers: Scott P. Fennell + */ + + +import javax.swing.*; + + +public class MsdDisplay extends JFrame { + MsdView msdView; + + + + public void setPosition(double value) { + msdView.setPosition(value); + } + + public void setVelocity(double value) { + msdView.setVelocity(value); + } + + public void setScale(int value) { + msdView.setScale(value); + } + + public int getScale() { + return msdView.getScale(); + } + + public void drawMsdView() { + msdView.repaint(); + } + + + + public MsdDisplay(MsdView arena) { + setTitle("Mass-Spring-Damper"); + msdView = arena; + add(msdView); + + + setSize(800, 500); + setLocationByPlatform(true); + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + +} diff --git a/trick_sims/SIM_msd/models/graphics/MSD/src/MsdGui.java b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdGui.java new file mode 100644 index 00000000..bdbff287 --- /dev/null +++ b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdGui.java @@ -0,0 +1,218 @@ +/* + * Trick + * 2018 (c) National Aeronautics and Space Administration (NASA) + * Programmers: Scott P. Fennell + */ + + +import java.awt.*; +import java.io.*; +import java.net.Socket; + +public class MsdGui { + + static BufferedReader in; + static DataOutputStream out; + + public static void connectToServer(String host, int port) throws IOException { + Socket socket = new Socket(host, port); + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); + } + + public static void main(String[] args) throws IOException { + + String host = "localHost"; + int port = 0; + + // ========================================================== + // Handle program arguments. + // ========================================================== + int ii = 0; + while (ii < args.length) { + switch (args[ii]) { + case "-help": + case "--help": { + MsdUtils.printHelpText(); + System.exit(0); + } + break; + default: { + port = (Integer.parseInt(args[ii])); + } + break; + } + ++ii; + } + + if (port == 0) { + System.out.println("No variable server port specified."); + MsdUtils.printHelpText(); + System.exit(0); + } + + boolean go = true; + double dt = 0.01; // Time between updates (seconds). + double pos = 0.0; + double vel = 0.0; + boolean resetCommand; + boolean startCommand; + + + int simMode = 0; + + + int mapScale = 32; // pixels per meter. + + MsdView msdView = new MsdView(mapScale); + MsdDisplay display = new MsdDisplay(msdView); + MsdController controller = new MsdController(display); + display.setVisible(true); + display.drawMsdView(); + controller.setVisible(true); + controller.setLocation(new Point((int)display.getLocationOnScreen().getX() + display.getWidth(), (int)display.getLocationOnScreen().getY())); + controller.setSize(controller.getWidth() + 10, display.getHeight()); + + // Connect to the Trick simulation's variable server + System.out.println("Connecting to: " + host + ":" + port); + connectToServer(host, port); + + out.writeBytes("trick.var_set_client_tag(\"MsdGui\") \n"); + out.flush(); + + // Have the Variable Server send us the simulation mode ONCE. + out.writeBytes("trick.var_add(\"trick_sys.sched.mode\")\n" + + "trick.var_add(\"dyn.msd.x_0\")\n" + + "trick.var_add(\"dyn.msd.v_0\")\n" + + "trick.var_add(\"dyn.msd.m\")\n" + + "trick.var_add(\"dyn.msd.b\")\n" + + "trick.var_add(\"dyn.msd.k\")\n" + + "trick.var_add(\"dyn.msd.F\")\n" + + "trick.var_send() \n" + + "trick.var_clear() \n"); + out.flush(); + + // Read the response and extract the simulation mode. Initialize text fields with initial values. + try { + String line; + String field[]; + line = in.readLine(); + field = line.split("\t"); + simMode = Integer.parseInt(field[1]); + controller.positionTextField.setText(String.format("%.2f", new Double(field[2]))); + controller.velocityTextField.setText(String.format("%.2f", new Double(field[3]))); + controller.massTextField.setText(String.format("%.2f", new Double(field[4]))); + controller.dampingTextField.setText(String.format("%.2f", new Double(field[5]))); + controller.springTextField.setText(String.format("%.2f", new Double(field[6]))); + controller.forceTextField.setText(String.format("%.2f", new Double(field[7]))); + } catch (IOException | NullPointerException e) { + go = false; + } + + // If we're in FREEZE, make ready to start. + if (simMode == TrickSimMode.FREEZE) { + controller.armResetCommand(); + } + + // Configure the Variable Server to cyclically send us the following variables. + // Tell the variable server: + // 1) We want the values of the following variables: + out.writeBytes("trick.var_pause() \n" + + "trick.var_add(\"dyn.msd.x\")\n" + + "trick.var_add(\"dyn.msd.v\")\n" + + "trick.var_add(\"trick_sys.sched.mode\")\n" + + // 2) We want the responses in ASCII: + "trick.var_ascii() \n" + + /* 3) We want debug information: + "trick.var_debug(1) \n" + + */ + // 4) We want values to be updated at the specified rate: + String.format("trick.var_cycle(%.3f)\n", dt) + + // 5) Start sending values as specified. + "trick.var_unpause() \n"); + out.flush(); + + while (go) { + + // Receive and parse periodic data response from the variable server. + try { + String line; + String field[]; + line = in.readLine(); + field = line.split("\t"); + pos = Double.parseDouble(field[1]); + vel = Double.parseDouble(field[2]); + simMode = Integer.parseInt(field[3]); + } catch (IOException | NullPointerException e) { + go = false; + } + // Get inputs from the GUI. + resetCommand = controller.getResetCommand(); + startCommand = controller.getStartCommand(); + + if (simMode == TrickSimMode.FREEZE) { + + controller.armResetCommand(); + resetCommand = false; + if (!controller.positionTextField.getText().isEmpty() && new Double(controller.positionTextField.getText()) >= 0.0) { + display.msdView.hideWall = false; + } + if (!(controller.positionTextField.getText().isEmpty() || + controller.velocityTextField.getText().isEmpty() || + controller.springTextField.getText().isEmpty() || + controller.dampingTextField.getText().isEmpty() || + controller.massTextField.getText().isEmpty() || + controller.forceTextField.getText().isEmpty())) { + + out.writeBytes( + "dyn.msd.x_0 = " + controller.positionTextField.getText() + ";\n" + + "dyn.msd.v_0 = " + controller.velocityTextField.getText() + ";\n" + + "dyn.msd.k = " + controller.springTextField.getText() + ";\n" + + "dyn.msd.b = " + controller.dampingTextField.getText() + ";\n" + + "dyn.msd.m = " + controller.massTextField.getText() + ";\n" + + "dyn.msd.F = " + controller.forceTextField.getText() + ";\n"); + out.writeBytes("dyn.msd.x = dyn.msd.x_0 ;\n"); + out.writeBytes("dyn.msd.v = dyn.msd.v_0 ;\n"); + } + + if (startCommand) { + out.writeBytes(String.format("trick.exec_run();\n")); + + out.flush(); + } + if (resetCommand) { + out.writeBytes(String.format("trick.exec_freeze() ;\n")); + continue; + } + out.flush(); + + } else if (simMode == TrickSimMode.RUN) { + controller.armStartCommand(); + startCommand = false; + if (resetCommand) { + out.writeBytes(String.format("trick.exec_freeze() ;\n")); + out.flush(); + } + if (!(controller.springTextField.getText().isEmpty() || + controller.dampingTextField.getText().isEmpty() || + controller.massTextField.getText().isEmpty() || + controller.forceTextField.getText().isEmpty())) { + out.writeBytes( + "dyn.msd.k = " + controller.springTextField.getText() + ";\n" + + "dyn.msd.b = " + controller.dampingTextField.getText() + ";\n" + + "dyn.msd.m = " + controller.massTextField.getText() + ";\n" + + "dyn.msd.F = " + controller.forceTextField.getText() + ";\n"); + } + } + + // Update the display data. + display.setPosition(pos); + display.setVelocity(vel); + + // Update the scene. + display.drawMsdView(); + + } // while + + } +} diff --git a/trick_sims/SIM_msd/models/graphics/MSD/src/MsdUtils.java b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdUtils.java new file mode 100644 index 00000000..7c8f52ca --- /dev/null +++ b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdUtils.java @@ -0,0 +1,24 @@ +/* + * Trick + * 2018 (c) National Aeronautics and Space Administration (NASA) + * Programmers: Scott P. Fennell + */ + + + +public class MsdUtils { + + public static void printHelpText() { + System.out.println( + "----------------------------------------------------------------------\n" + + "usage: java jar CannonDisplay.jar \n" + + "----------------------------------------------------------------------\n" + ); + } +} + +class TrickSimMode { + public static final int INIT = 0; + public static final int FREEZE = 1; + public static final int RUN = 5; +} \ No newline at end of file diff --git a/trick_sims/SIM_msd/models/graphics/MSD/src/MsdView.java b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdView.java new file mode 100644 index 00000000..8dbdbf80 --- /dev/null +++ b/trick_sims/SIM_msd/models/graphics/MSD/src/MsdView.java @@ -0,0 +1,183 @@ +/* + * Trick + * 2018 (c) National Aeronautics and Space Administration (NASA) + * Programmers: Scott P. Fennell + */ + + + +import javax.swing.*; +import java.awt.*; + +class MsdView extends JPanel { + + private int scale; + private Color massColor; + private Color backgroundColor; + private Color wallColor; + private Color springColor; + private Double position; + private Double velocity; + private Double massRadius; + boolean hideWall = false; + + // Origin of world coordinates in jpanel coordinates. + private int worldOriginX; + private int worldOriginY; + + + /** + * Class constructor. + */ + public MsdView(int mapScale) { + + setScale(mapScale); + + backgroundColor = new Color(200, 200, 255); + springColor = new Color(150, 150, 100); + massColor = new Color(10, 10, 10); + wallColor = new Color(120, 118, 118); + springColor = Color.BLUE; + massRadius = 0.75; + position = 0.0; + velocity = 0.0; + } + + /** + * @param value angle in degrees + */ + public void setPosition(double value) { + position = value; + } + + public void setVelocity(double value) { + velocity = value; + } + + public void setScale(int mapScale) { + if (mapScale < 4) { + scale = 4; + } else if (mapScale > 128) { + scale = 128; + } else { + scale = mapScale; + } + repaint(); + } + + public int getScale() { + return scale; + } + + public void drawCenteredCircle(Graphics2D g, int x, int y, int r) { + x = x - (r / 2); + y = y - (r / 2); + g.fillOval(x, y, r, r); + } + + private void doDrawing(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + rh.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + + int ii, jj; + int width = getWidth(); + int height = getHeight(); + + + worldOriginX = (width / 3); + worldOriginY = (height / 2); + + while (worldOriginX + scale * position > width) { + scale = scale / 2; + } + + // Draw Sky + g2d.setPaint(backgroundColor); + g2d.fillRect(0, 0, width, worldOriginY); + + // Draw mass + g2d.setPaint(massColor); + int bx = (int) (worldOriginX + scale * position); + int by = (int) (worldOriginY); + drawCenteredCircle(g2d, bx, by, (int) (scale * massRadius)); + + // Draw spring + double springPosition; + // reflect spring visual over origin correctly + if(position < massRadius/2 && position > -massRadius/2){ + springPosition = 0.0; + } else if(position < 0){ + springPosition = position + massRadius/2; + } else{ + springPosition = position - massRadius/2; + } + int SCALEFACTOR = 200; + int cycles = 5; + int points = SCALEFACTOR * cycles * 2; + double[] sines = new double[points]; + for (int i = 0; i < points; i++) { + double radians = (Math.PI / SCALEFACTOR) * i; + sines[i] = Math.sin(radians); + } + int maxWidth = (int) (scale * (springPosition /*- massRadius / 2*/)); + double hstep = (double) maxWidth / (double) points; + int maxHeight = (int) (scale); + int[] pts = new int[points]; + for (int i = 0; i < points; i++) { + pts[i] = (int) (sines[i] * maxHeight / 2 * .95 + maxHeight / 2); + } + g2d.setColor(springColor); + for (int i = 1; i < points; i++) { + int x1 = (int) ((i - 1) * hstep); + int x2 = (int) (i * hstep); + int y1 = pts[i - 1]; + int y2 = pts[i]; + g2d.drawLine(x1 + worldOriginX, y1 + height / 2 - scale / 2, x2 + worldOriginX, y2 + height / 2 - scale / 2); + + } + + //Draw wall + if (!hideWall && position >= 0) { + g2d.setPaint(wallColor); + g2d.fillRect(0, 0, worldOriginX, height); + } else { + hideWall = true; + } + + + // Draw range markers. + int tickRange = 50; + if (scale >= 8) tickRange = 20; + if (scale >= 16) tickRange = 10; + if (scale >= 32) tickRange = 5; + if (scale >= 64) tickRange = 1; + + int lower = ((int) ((-worldOriginX) / (scale * tickRange)) + 1) * tickRange; + int upper = ((int) ((width - worldOriginX) / (scale * tickRange)) + 1) * tickRange; + + g2d.setPaint(Color.BLACK); + + for (ii = lower; ii < upper; ii += tickRange) { + int mx = (int) (worldOriginX + scale * ii); + g2d.drawLine(mx, worldOriginY, mx, worldOriginY + 20); + g2d.drawString(String.format("%d", ii), mx, worldOriginY + 15); + } + + g2d.drawString(String.format("SCALE: %d pixels/meter", scale), 20, 20); + g2d.drawString(String.format(" Position (m): %.2f", position), 20, 80); + g2d.drawString(String.format("Velocity (m/s): %.2f", velocity), 20, 120); + + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + doDrawing(g); + } +} \ No newline at end of file diff --git a/trick_sims/SIM_msd/models/graphics/Makefile b/trick_sims/SIM_msd/models/graphics/Makefile new file mode 100644 index 00000000..fe61dffd --- /dev/null +++ b/trick_sims/SIM_msd/models/graphics/Makefile @@ -0,0 +1,36 @@ +SHELL = /bin/sh + +PROJECT_NAME = MsdGui +SRC_DIR = MSD/src +BUILD_DIR = build +CLASSES_DIR = $(BUILD_DIR)/classes +JAR_DIR = dist +MAIN_CLASS = MsdGui + +all: jar + +clean: + rm -rf $(BUILD_DIR) + rm -f manifest + +spotless: clean + rm -rf dist + +$(CLASSES_DIR): + @ mkdir -p $(CLASSES_DIR) + +compile: | $(CLASSES_DIR) + javac -sourcepath $(SRC_DIR) -d $(CLASSES_DIR) $(SRC_DIR)/MsdGui.java + +manifest: + @ echo "Main-Class: $(MAIN_CLASS)" > $@ + +$(JAR_DIR): + @ mkdir -p $(JAR_DIR) + +jar: compile manifest | $(JAR_DIR) + jar cvfm $(JAR_DIR)/$(PROJECT_NAME).jar manifest -C $(CLASSES_DIR) . + @ echo "-------------------------------------------------------------------------------" + @ echo " BUILD COMPLETE" + @ echo "The Java jar file (the Java Executable) is located at: $(JAR_DIR)/$(PROJECT_NAME).jar" + @ echo "-------------------------------------------------------------------------------" diff --git a/trick_sims/SIM_msd/models/msd/include/msd.hh b/trick_sims/SIM_msd/models/msd/include/msd.hh new file mode 100644 index 00000000..832ecf1c --- /dev/null +++ b/trick_sims/SIM_msd/models/msd/include/msd.hh @@ -0,0 +1,48 @@ +/************************TRICK HEADER************************* +PURPOSE: Mass-Spring-Damper class header file . +PROGRAMMERS: + (((Scott P. Fennell) (CACI International Inc.) (January 2018) (Trick Learning Project))) +*************************************************************/ + +#ifndef MSD_H +#define MSD_H + +class MSD { +public: + + double a; /* m/s2 acceleration */ + double v; /* m/s velocity */ + double x; /* m position */ + double m; /* kg mass */; + + double v_0; /* *i m/s initial velocity of the mass (at t = 0) */ + double x_0; /* *i m initial position of the mass (at t = 0) */ + + double b; /* N.s/m damping constant */ + double k; /* N/m spring constant */ + double F; /* N force constant */ + + + + MSD(void); /* not used */ + + MSD(double _m, double _k, double _b, double _F, + double _v_0, double _x_0); + + int state_deriv(void); + int state_integ(void); + + }; + + +#ifdef __cplusplus +extern "C" { +#endif +int msd_default_data(MSD &); +int msd_init(MSD &); +int msd_shutdown(const MSD &); +#ifdef __cplusplus +} +#endif + +#endif /* MSD_H */ \ No newline at end of file diff --git a/trick_sims/SIM_msd/models/msd/include/msd_numeric.hh b/trick_sims/SIM_msd/models/msd/include/msd_numeric.hh new file mode 100644 index 00000000..29093004 --- /dev/null +++ b/trick_sims/SIM_msd/models/msd/include/msd_numeric.hh @@ -0,0 +1,17 @@ +/************************TRICK HEADER************************* +PURPOSE: Msd Numeric model +PROGRAMMERS: + (((Scott P. Fennell) (CACI International Inc.) (January 2018) (Trick Learning Project))) +*************************************************************/ +#ifndef MSD_NUMERIC_H +#define MSD_NUMERIC_H + +#include "msd.hh" + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/trick_sims/SIM_msd/models/msd/src/msd.cpp b/trick_sims/SIM_msd/models/msd/src/msd.cpp new file mode 100644 index 00000000..4c2a3f60 --- /dev/null +++ b/trick_sims/SIM_msd/models/msd/src/msd.cpp @@ -0,0 +1,19 @@ +/************************TRICK HEADER************************* +PURPOSE: MSD is a mass-spring-damper class for a trick sim. +PROGRAMMERS: + (((Scott P. Fennell) (CACI International Inc.) (January 2018) (Trick Learning Project))) +*************************************************************/ +#include +#include "../include/msd_numeric.hh" +#include + +MSD::MSD(double _m, double _k, double _b, double _F, double _v_0, double _x_0) { + m = _m; + k = _k; + b = _b; + F = _F; + v_0 = _v_0; + x_0 = _x_0; +} + +MSD::MSD(void) {/* not used */} \ No newline at end of file diff --git a/trick_sims/SIM_msd/models/msd/src/msd_deriv.cpp b/trick_sims/SIM_msd/models/msd/src/msd_deriv.cpp new file mode 100644 index 00000000..815256ca --- /dev/null +++ b/trick_sims/SIM_msd/models/msd/src/msd_deriv.cpp @@ -0,0 +1,15 @@ +/************************TRICK HEADER************************* + PURPOSE: ( Trick integration ) +PROGRAMMERS: + (((Scott P. Fennell) (CACI International Inc.) (January 2018) (Trick Learning Project))) +*************************************************************/ +#include "../include/msd_numeric.hh" +#include "../include/msd.hh" +#include + +int MSD::state_deriv(void) { + /* system equation for second derivitive */ + a = (F - b*v - k*x)/m; + + return(0); +} \ No newline at end of file diff --git a/trick_sims/SIM_msd/models/msd/src/msd_init.cpp b/trick_sims/SIM_msd/models/msd/src/msd_init.cpp new file mode 100644 index 00000000..627c41ee --- /dev/null +++ b/trick_sims/SIM_msd/models/msd/src/msd_init.cpp @@ -0,0 +1,28 @@ +/************************TRICK HEADER************************* +PURPOSE: Set the initial data values of the MSD +PROGRAMMERS: + (((Scott P. Fennell) (CACI International Inc.) (January 2018) (Trick Learning Project))) +*************************************************************/ + +/* Model Include files */ +#include "../include/msd.hh" + +/* default data job */ +int msd_default_data(MSD &M) { + M = MSD( + 1.0, /* m */ + 2.0, /* k */ + 0.5, /* b */ + 5.0, /* F */ + 0.0, /* v_0 */ + 5.0 /* x_0 */ + + ); + + return 0; +} + +/* initialization job */ +int msd_init(MSD &M) { + return 0; +} diff --git a/trick_sims/SIM_msd/models/msd/src/msd_integ.cpp b/trick_sims/SIM_msd/models/msd/src/msd_integ.cpp new file mode 100644 index 00000000..30566922 --- /dev/null +++ b/trick_sims/SIM_msd/models/msd/src/msd_integ.cpp @@ -0,0 +1,31 @@ +/************************TRICK HEADER************************* + PURPOSE: ( Trick integration ) + PROGRAMMERS: + (((Scott P. Fennell) (CACI International Inc.) (January 2018) (Trick Learning Project))) +*************************************************************/ +#include "../include/msd_numeric.hh" +#include "msd.hh" +#include "trick/Integrator.hh" +#include "trick/integrator_c_intf.h" +#include + +int MSD::state_integ(void) { + int ipass; + load_state( + &x, + &v, + NULL); + + load_deriv( + &v, + &a, + NULL); + + ipass = integrate(); + + unload_state( + &x, + &v, + NULL); + return(ipass); +} \ No newline at end of file diff --git a/trick_sims/SIM_msd/models/msd/src/msd_shutdown.cpp b/trick_sims/SIM_msd/models/msd/src/msd_shutdown.cpp new file mode 100644 index 00000000..48fa22e4 --- /dev/null +++ b/trick_sims/SIM_msd/models/msd/src/msd_shutdown.cpp @@ -0,0 +1,17 @@ +/************************TRICK HEADER************************* +PURPOSE: (Print the final msd state.) +PROGRAMMERS: + (((Scott P. Fennell) (CACI International Inc.) (January 2018) (Trick Learning Project))) +*************************************************************/ +#include "../include/msd.hh" +#include "trick/exec_proto.h" +#include + +int msd_shutdown(const MSD &M) { + printf("========================================\n"); + printf(" MSD State at Shutdown \n"); + printf("pos = [%g], vel = [%g], acc = [%g]\n", + M.x, M.v, M.a); + printf("========================================\n"); + return 0; +} \ No newline at end of file