Well, nothing beats a real one, but you can't always have it. Simulation is always possible, but you have to follow the laws of physics (or simply ignore them).
Part One: The BasicsFirst of all, the physics of a swing is the same as that describing the good old grandfather clock where a pendulum is used for the time keeping.
But as soon as you start to swing higher and higher, those laws are are getting less and less exact. Experts would tell you you need something called elliptic integrals to describe and calculate the movement of your swing.
Equations like this are really hard to solve, but if you are ready to perform lots of simple caculations, things become quite easy.
These equations are much simpler, buf if you do not understand all of them it does not matter. The only important thing about it is you need to evaluate these eight equations to get just one short movement of the ship, and you have to repeat these steps over and over again. Please note that the new value of the angle phi that you get in equation 8 will be used in equations 1 and 2 when you perform the next step. To observe the results there are many options.
- plot the results on the Serial Plotter of the Arduino IDE
- draw it on a TFT display
- display the position of the ship as a dot on a Neopixel strip (WS2812) in circular shape
- drive a stepper motor that indicates the ship's position
- produce a sound that corresponds to the actual speed of the ship
Once you got it running you can start modifying conditions:
- the mass m of the ship and her passengers. But this does not matter at all, at least as long as it is much less than the mass of the planet you are living on
- the gravity constant. Why not installing a ship swing on the moon or on Jupiter?
- the total energy (potential plus kinetic) you are starting with
- the loss of energy at each swing due to the friction of the pendulum
Mind you: the code given below is written for a swing that overturns. If the total energy is too low, it will not flip over but reverse. That case would need to be treated separately!
Have a happy ride!
The code shown below is for using a 1.8" TFT display. If you are using a different one, some values will probably need to be changed.
/*
Schiffschaukel ohne Daempfung
*/
#include <TFT.h>
#define cs 10
#define dc 9
#define rst 8
TFT tft = TFT(cs, dc, rst);
int w, h, mx, my, r1, r2;
const double m = 1; // irrelevant
const double g = 9.81;
double Wkin, Wpot, Wges, dt, ds,
phi, dPhi, x, y, v, vx, vy;
void setup() {
Serial.begin(9600);
Serial.println(__FILE__);
// Graphik:
tft.begin();
tft.setRotation(0);
w = tft.width();
h = tft.height();
mx = w / 2;
my = h / 2;
r2 = 3;
r1 = mx - r2;
dt = 0.1;
tft.stroke(255, 255, 255);
tft.background(0, 0, 0);
tft.text("Pendel", 0, 0);
// Anfangswerte:
// Naehe oberer Totpunkt
Wges = g * r1 * 1.001;
phi = HALF_PI + 0.001;
}
void loop() {
// altes Bild loeschen:
tft.drawLine(mx, my, mx + x, my - y, 0);
tft.fillCircle(mx + x, my - y, r2, 0);
x = r1 * cos(phi);
y = r1 * sin(phi);
// neue Graphik zeichnen:
tft.fillCircle(mx, my, r2, ST7735_CYAN);
tft.drawLine(mx, my, mx + x, my - y, 34567);
tft.fillCircle(mx + x, my - y, r2, 0x07E0);
tft.drawCircle(mx, my, r1, 0x0101);
//delay(1);
// naechster Schritt:
Wpot = m * g * y;
Wkin = Wges - Wpot;
Serial.print(Wpot);
Serial.print(" ");
Serial.println(Wkin);
if (Wkin < 0) {
Serial.println("Error");
tft.text("Wkin < 0", 0, 10);
while (true);
}
v = sqrt(2 * Wkin / m);
ds = v * dt;
dPhi = ds / r1;
phi = phi - dPhi;
}
Part Two: Any Improvements?Well, it is obvious: that these many calculations need to be done with floating type variables. It is understood that floating point arithmetic takes much longer than integer arithmetic. That is where the new Arduino UNO R4 comes into play. Not only does it run at 48 MHz instead of the UNO R3's 16 MHz, but it also includes an embedded floating point processing unit. So the calculation of the math should be peformed much faster - and it really is. Unfortunately, there is a small problem: if you want to view the results on that 1.8" TFT that I was using, it turns out that the standard library does not support the R4. So, at the end of the day, a new library had to be written, a task you won't complete during your coffee break. And as many users have already reported, you will be penalized for using the SPI protocol. Although the calculations are performed at twice the speed of the R3, the overall speed is only half the speed of the R3.
While the R4 completed three revolutions, the R3 even started the sixth revolution.
The updated code as well as the self-written library can be found in the attachments. The library is anything but perfect. Better not use it for your own projects.
Part Three: Some remarks on Precision of CalculationAs the equations shown above have to be calculated again and again, even small rounding errors will accumulate over the time. The advantage of the UNO R4 is it can really handle floating point number using the double data type which stores decimal numbers with 8 bytes giving about 15 decimal places instead of 4 bytes giving about 7 decimal places. Some of the sine values you also can get by calculating square roots. This code written for the UNO R4 does both and will show you the differences.
/*
https://de.wikipedia.org/wiki/Trigonometrische_Konstante_ausgedr%C3%BCckt_in_reellen_Radikalen
*/
const byte decimals = 17;
void setup() {
Serial.begin(9600);
delay(500);
Serial.println(__FILE__);
Serial.println("winkel\tsinus\t\t\tmit Wurzeln");
for (int winkel = 0;
winkel <= 45;
winkel = winkel + 3)
drucke(winkel);
}
void loop() {}
void drucke(int w) {
double phi = w * TWO_PI / 360;
Serial.print(w);
Serial.print("\t");
Serial.print(sin(phi), decimals);
Serial.print("\t");
Serial.println(wurzel(w, phi), decimals);
}
double wurzel(int w, double winkel) {
switch (w) {
case 0: return 0;
case 15: return sqrt(2 - sqrt(3)) / 2;
case 18: return (sqrt(5) - 1) / 4;
case 24: return (sqrt(3) * (sqrt(5) + 1) - sqrt(2) * sqrt(5 - sqrt(5))) / 8;
case 30: return 0.5;
case 36: return sqrt(2) * sqrt(5 - sqrt(5)) / 4;
case 45: return sqrt(2) / 2;
}
return 0;
}
/*
Werte auf wolframalpha.com:
sin(15) =
0.25881904510252076 23488988376240483283490689013199305138140032073...
sin(45) =
0.70710678118654752 44008443621048490392848359376884740365883398689...
*/
Actually, it must be admitted: the improvements are not really produced by the R4 rather than the C-compiler.
Comments
Please log in or sign up to comment.