import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
Simulation of a double pendulum with simple forward Euler integration.
@author <michels@cs.stanford.edu>
public class DoublePendulum extends Applet implements ActionListener, Runnable {
double theta1S = 1.6, dtheta1S = 0;
double theta2S = 1.8, dtheta2S = 0;
double theta1, dtheta1, ddtheta1;
double theta2, dtheta2, ddtheta2;
double theta1a, dtheta1a, ddtheta1a, theta2a, dtheta2a, ddtheta2a;
double x1, y1, x2, y2;
int x1c, y1c, x2c, y2c;
double dt = 0.005, t = -dt;
double g = 9.81;
double l1, l2, l;
double m1, m2, m;
public void dataUpdate() {
t = t + dt;
ddtheta1 = (-1 / (l1 * (m - Math.pow(Math.cos(theta1 - theta2), 2)))) * (g * (m * Math.sin(theta1) - Math.sin(theta2) * Math.cos(theta1 - theta2)) + Math.sin(theta1 - theta2) * (l1 * Math.pow(dtheta1, 2) * Math.cos(theta1 - theta2) + l2 * Math.pow(dtheta2, 2)));
ddtheta2 = -l * ddtheta1 * Math.cos(theta1 - theta2) + l * Math.pow(dtheta1, 2) * Math.sin(theta1 - theta2) - (g / l2) * Math.sin(theta2);
dtheta1a = dtheta1;
dtheta2a = dtheta2;
theta1a = theta1;
theta2a = theta2;
dtheta1 = dtheta1a + ddtheta1 * dt;
dtheta2 = dtheta2a + ddtheta2 * dt;
theta1 = theta1a + dtheta1 * dt;
theta2 = theta2a + dtheta2 * dt;
x1 = l1 * Math.sin(theta1);
y1 = l1 * Math.cos(theta1);
x2 = x1 + l2 * Math.sin(theta2);
y2 = y1 + l2 * Math.cos(theta2);
x1c = (int) (100 * x1) + 450;
y1c = (int) (100 * y1) + 300;
x2c = (int) (100 * x2) + 450;
y2c = (int) (100 * y2) + 300;
}
public void paint(Graphics g) {
g.setColor(Color.black);
text("t = " + String.valueOf(Math.round(t * 10.) / 10.) + "s", 20, 20, 12, g);
g.fillOval(446, 296, 8, 8);
g.drawLine(450, 300, x1c, y1c);
g.drawLine(x1c, y1c, x2c, y2c);
g.setColor(Color.red);
g.fillOval(x1c - (int) (12 * m1), y1c - (int) (12 * m1),
(int) (24 * m1), (int) (24 * m1));
g.setColor(Color.blue);
g.fillOval(x2c - (int) (12 * m2), y2c - (int) (12 * m2),
(int) (24 * m2), (int) (24 * m2));
}
void text(String txt, int x, int y, int s, Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Font f = new Font("Sans Serif", Font.LAYOUT_LEFT_TO_RIGHT, s);
FontMetrics fm = getFontMetrics(f);
LineMetrics lm = fm.getLineMetrics(txt, g);
g2d.setFont(f);
g2d.drawString(txt, x, y);
}
private Image bufferingImage;
private Graphics bufferingGraphics;
public void update(Graphics g) {
int width = 900, height = 600;
if (bufferingImage == null) {
bufferingImage = createImage(width, height);
bufferingGraphics = bufferingImage.getGraphics();
}
bufferingGraphics.setColor(getBackground());
bufferingGraphics.fillRect(0, 0, width, height);
paint(bufferingGraphics);
g.drawImage(bufferingImage, 0, 0, this);
}
Thread runner;
boolean started = false;
Runner-Start.
public void startSim() {
runner = new Thread(this);
runner.start();
}
public void pauseSim() {
runner.stop();
}
public void stopSim() {
try {
runner.stop();
} catch (Exception oops) {
}
loadInput();
t = -dt;
dataUpdate();
repaint();
}
public void run() {
while (true) {
repaint();
dataUpdate();
try {
Thread.sleep((int) (dt * 900));
} catch (InterruptedException e) {
}
}
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == btnSP) {
if (started) {
pauseSim();
} else {
startSim();
}
started = !started;
} else if (e.getSource() == btnST) {
stopSim();
if (started) {
started = !started;
}
}
}
Button btnSP, btnST;
TextField txtM1 = new TextField("1.0");
TextField txtM2 = new TextField("1.0");
TextField txtL1 = new TextField("1.0");
TextField txtL2 = new TextField("1.0");
TextField txtTheta1 = new TextField("1.6");
TextField txtTheta2 = new TextField("1.8");
TextField txtDTheta1 = new TextField("0.0");
TextField txtDTheta2 = new TextField("0.0");
public void init() {
setLayout(new BorderLayout());
Panel myPanel = new Panel();
myPanel.setLayout(new GridLayout(2, 9));
Label laM1 = new Label("m1 =");
Label laM2 = new Label("m2 =");
Label laL1 = new Label("l1 =");
Label laL2 = new Label("l2 =");
Label laTheta1 = new Label("θ1(0) =");
Label laTheta2 = new Label("θ2(0) =");
Label laDTheta1 = new Label("dθ1(0) =");
Label laDTheta2 = new Label("dθ2(0) =");
btnSP = new Button("Run/Stop");
btnST = new Button("Initialize");
add(myPanel, BorderLayout.SOUTH);
myPanel.add(laM1);
myPanel.add(txtM1);
myPanel.add(laL1);
myPanel.add(txtL1);
myPanel.add(laTheta1);
myPanel.add(txtTheta1);
myPanel.add(laDTheta1);
myPanel.add(txtDTheta1);
myPanel.add(btnSP);
myPanel.add(laM2);
myPanel.add(txtM2);
myPanel.add(laL2);
myPanel.add(txtL2);
myPanel.add(laTheta2);
myPanel.add(txtTheta2);
myPanel.add(laDTheta2);
myPanel.add(txtDTheta2);
myPanel.add(btnST);
btnSP.addActionListener(this);
btnST.addActionListener(this);
loadInput();
dataUpdate();
}
public void loadInput() {
m1 = new Double(txtM1.getText());
m2 = new Double(txtM2.getText());
l1 = new Double(txtL1.getText());
l2 = new Double(txtL2.getText());
theta1 = new Double(txtTheta1.getText());
theta2 = new Double(txtTheta2.getText());
dtheta1 = new Double(txtDTheta1.getText());
dtheta2 = new Double(txtDTheta2.getText());
l = l1 / l2;
m = (m1 + m2) / m2;
}
}