Homework3: Constrained Dynamics
Summary:
Implement dynamics with a simple constraint.
Assignment text:
(25pt) Problem A: A Bead on a Wire
Simulate the motion of a particle and visualize the result.
The particle is defined in a Cartesian coordinate system p=(x,y), and it
is constrained by a unit circle centered at the origin. Use the initial
position (0, 1), the initial velocity (0, 0), and gravitational force (0,-mg).
Constants are give as m=1Kg, and g=9.8m/sec2. |
What I did:
I have created a small program.
download the
program (you need to put qt-mt230nc.dll in
the same directory)
It requires Windows (2000?), openGL, GLVU
(to compile), and the QT runtime dll (included).
You can view the source
code. All the simulation code is contained in the main.cpp. The other
files are used for the user interface.
I chose to use the Lagrange’s equations
of motion, which is overkill for this circle case -- but still very easy.
The concept is to express the state of
the system in a natural manner, and then convert it to the "real world".
For a bead on a circle, the position can be stored as a single parameter
a
which indicates the angle.
Converting to world co-ordinates x,
y
is easy, just trigonometry. (See math below.) Then, the Jacobin matrix
J is solved. This matrix is built from the partial derivatives shown. Additionally,
the time derivative of J is found (J-dot).
The equation of motion is then shown. Notice
that I have moved the Mass matrix M over to the force f side
of the equation.
Then, some simple math and simplification
provides us with a solution for the acceleration of the angle variable
(a-dot-dot).
Finally, this system can be integrated
with Euler's method. The relevant code is shown below:
//simulation variables
static Stopwatch timer;
struct _circle
{
float theta;
float thetaVelocity;
Vec3f worldForces;
float mass;
} circle;
Vec3f gravity;
void initObjects(void)
{
timer.Start();
circle.theta = 3.1415/2;
gravity.Set(0, -9.8, 0);
}
void simulation(void)
{
static float time_simulated = 0;
float time_now = timer.GetTime();
float time_passed = time_now - time_simulated;
circle.mass = pControlPanel->FloatSpinBox_mass->doubleValue();
circle.worldForces.Set(0,0,0);
circle.worldForces += circle.mass * gravity;
float force_amount = pControlPanel->FloatSpinBox_force->doubleValue();
if (pControlPanel->PushButton_Force_Left->isDown()
)
circle.worldForces += Vec3f(-force_amount,0,0);
if (pControlPanel->PushButton_Force_Up->isDown()
)
circle.worldForces += Vec3f(0,force_amount,0);
if (pControlPanel->PushButton_Force_Right->isDown())
circle.worldForces += Vec3f(force_amount,0,0);
float timestep = pControlPanel->SpinBox_TimeStep->value()
/ (float)1000;
float dampening = 1-pControlPanel->FloatSpinBox_dampening->doubleValue();
int i=0;
while ((time_simulated < time_now) &&
(timestep > 0))
{
float acceleration =
- circle.worldForces.x/circle.mass*sin(circle.theta)
+ circle.worldForces.y/circle.mass*cos(circle.theta);
circle.theta += circle.thetaVelocity
* timestep;
circle.thetaVelocity += acceleration
* timestep;
circle.thetaVelocity *= dampening;
time_simulated += timestep;
i++;
}
}
Analysis:
The system performs very well, and is very
stable. The constraint can never be broken. Some dampening is required.
|