So far, we’ve modeled everything in this series as particles. Particles are the simplest way to model something physically, because they only have a location in space and don't have a size or shape. Particles can only translate (move), and can’t rotate.
This article is part of the Physics in Javascript series. If you feel lost reading this article, you may want to read the Gravity and Drag and Spring-Mass-Damper articles.
Just looking for the cool JSFiddle code example?
And while you can do some amazing things just by modeling particles, particles aren't realistic in the real world. Real objects aren't just infinitely small dots. Real objects have a size and shape and most importantly, an orientation. Real objects can rotate. And since most of you are probably interested in game development: you can't get by on particles alone.
Today we're going to begin our discussion of rigid bodies. Rigid bodies have all of the properties of particles: they have a location, they have a linear velocity, and they have a linear acceleration. But because rigid bodies have a shape and size, they also have an orientation (a rotation angle), and are subject not just to forces but also to torques which cause them to rotate. Torques can either be applied to an object directly (in the case of a wheel on a motor, like in a car), or they can appear because a force is applied to an object off-center (like when a football is kicked and tumbles end-over-end).
While rigid bodies are more complicated to model than particles, we’re still able to use familiar concepts and Newton’s laws. We just need to extend them a little bit to deal with rotation and torque.
Translation and Rotation
Let's start by comparing linear motion (translation) to angular motion (rotation). Translation has properties that we’re pretty familiar with by now: position, velocity, acceleration, mass, and force. Rotation is similar, but the variables have been modified slightly to: angle, angular velocity, angular acceleration, moment of inertia, and torque. Let’s introduce these concepts very briefly.Angle
Analogous to “position” for translation, the angle describes the current orientation of a rigid body. If you’re working in two dimensions -- as we are here -- you only need one angle to fully describe an object’s rotation. Typically, angle is denoted by the Greek letter theta: θ. In three dimensions, three angles are required to describe the object’s orientation, and in that case you should use Euler angles. Angle is a dimensionless quantity typically measured in radians or degrees. This is in contrast to the “position” in linear motion, whose dimension is “length”.Concretely: the angle θ is the number of radians or degrees something is rotated by.
Angular Velocity and Angular Acceleration
Like linear velocity, angular velocity describes how much the object’s angle changes in a given time-frame. While “degrees per hour” is an acceptable unit, angular velocity is almost always given in “radians per second”. Since radians are dimensionless, angular velocity has a dimension of inverse time. Typically, the Greek letter omega is used for angular velocity: ω.Similarly, angular acceleration is given in “radians per second squared” or “radians per second, per second”, and is typically denoted by the Greek letter alpha: α.
Torque
Force, in the linear world, is directly responsible for an object’s acceleration. Rotation is no different; in the angular world, torque is responsible for an object's angular acceleration.What’s more, a torque is just a force applied in a special manner: torque is what you get when you apply a force slightly offset from an object’s center of mass. If you were to lay a block on a table and push on it dead-center with your finger, you’d push the block forward without rotating it. If, however, your finger were off to the side of the block, you’d end up both pushing and rotating the block. It’s still the same block, it’s still the same finger. The only thing that has changed is where you applied the force. Since you applied it in such a way that it didn’t go “through” the block’s center of mass, you created a torque and that’s what caused the block to rotate.
A torque, therefore, is just a force multiplied by its (perpendicular) distance from the object’s center of mass (or point of rotation, depending on your physical set-up). Think about using a wrench: the longer the wrench is, the easier it is to turn. That’s because you’re multiplying the force by a larger distance and getting a larger torque as a result (of course, you have to move your hand farther to get the same angle of motion with a longer wrench -- so you end up doing the same amount of work!).
Torque is measured in units of force times distance: newton-meters or pound-feet, and is typically denoted by the Greek letter tau: τ.
Moment of Inertia
The toughest piece of the rotational puzzle to calculate from scratch is the moment of inertia. In linear motion, mass (inertia) is a sort of resistance to changing the object’s motion. A light object is easier to speed up or slow down than a heavy object. Similarly, moment of inertia is a resistance to a change in rotation. But moment of inertia is more complicated than mass, because both the object’s mass and its shape and size need to be considered. A 5 pound hoop is harder to get spinning than a 5 pound disc of the same size, because the hoop has all its mass near the edge.The moment of inertia is given in units of kg * m2 (kilogram times meters squared) and is typically denoted by the capital letter I or J. I like J.
Fortunately, you can just look up the moments of inertia of many common shapes and use those in your calculations. In school we were forced to do those calculations by hand with double or triple integrals. If you’re interested in practicing your calculus, go that route. If not, just use the lookup table.
Equation of Motion and a Pendulum Clock
Newton’s 2nd Law is Fnet = m*a. Modified for rotation, we can write it as τnet = J*α. Notice that, like the linear form of the equation, both τ and α are vectors. Since our example is in 2D -- which means all our rotation happens around the "z" axis -- we can just assume these are scalars for now.Since you’ve certainly read the Gravity and Drag and Spring-Mass-Damper articles, you probably already know what to do with this equation. Figure out the total torque, use that to calculate the acceleration, and then integrate twice to get the angle. The trickiest part is the "figure out the net torque" step, especially if you're uncomfortable with trigonometry. Let’s dive into an example.
I should now point out that -- just like with linear motion -- you can introduce springs and dampers into the mix. The equations are essentially the same as their linear counterparts. If you want a homework assignment, please try adding a damper to this pendulum!
Pendulum Clock
I want to build a simple and elegant animated pendulum clock. Rather than just "fudging" the motion of the pendulum by using sine easing, I want to solve for the physics directly. (Though physics students will recognize that sine actually is the solution to this problem!)The pendulum itself will be modeled as a point mass at the end of a weightless rod. Many physics problems are made with such assumptions: point mass, weightless rod, no friction, etc. It's a good way to make a first pass at what could become a very complicated problem.
Diving right into some code:
var pendulum = {mass: 1, length:500, theta: (Math.PI/2) - 0.05, omega: 0, alpha:0, J:0};
var setup = function() {
pendulum.J = pendulum.mass * pendulum.length * pendulum.length;
...
}
Right off the bat we set up initial conditions for our pendulum. In this case, we've defined θ = 0 to be when the pendulum is pointing horizontally to the right. Many people would choose to define θ = 0 as downwards. It doesn't really matter, as long as you're consistent.
Then we calculate the value of the pendulum's moment of inertia. Our Wikipedia list of moments of inertia tells us that a "point mass m at distance r from the axis of rotation" has a moment of inertia of m*r2, so that's what we use.
Velocity Verlet
I've done a few things differently in this code example. First of all, I've usedrequestAnimFrame()
instead of setInterval()
(see the JSFiddle for the full code; I won't talk about it here). Secondly, instead of using Euler's method of numerical integration, I've used the velocity verlet method.
Euler's method is actually pretty inaccurate as far as numerical integration methods go. I've used it up until now because it's very simple to understand, but it's time to move onwards and upwards. You're ready for it!
The above graphic illustrates where the inaccuracy in Euler's method comes from. Numerical integration is all about calculating the area below a function's curve. Most basic numerical integration techniques draw rectangles underneath the curve and add up their areas (see Riemann sum); this is what we're doing with Euler's method. Unfortunately, this can grossly over- or under-estimate a function especially if that function changes quickly. Making those rectangles thinner (in our case, making the loop delay smaller/faster) can help greatly, but there's still the fact that we're putting the the corner of the rectangle on the curve.
One other integration technique improves accuracy by having the function run through the midpoint of the rectangle, instead of the left or right corner; this is called the midpoint method. There's also the trapezoidal method, which draws trapezoids instead of rectangles. There's also the very accurate Runge-Kutta method, which uses a weighted average of 4 points along the function to calculate the area below the curve.
Here's a nice demonstration of how much better the midpoint method (in green) works compared to Euler's method (blue).
To make a long story short, we'll use the velocity verlet method today. I encourage you to look up the details and try to understand what gives it an advantage over Euler's method!
The Loop
Let's get back to code. In the loop (boring stuff omitted):var loop = function() {
...
/* Velocity Verlet */
/* Calculate current position from last frame's position, velocity, and acceleration */
pendulum.theta += pendulum.omega * deltaT + ( 0.5 * pendulum.alpha * deltaT * deltaT );
/* Calculate forces from current position. */
var T = pendulum.mass * 9.81 * Math.cos(pendulum.theta) * pendulum.length;
/* Current acceleration */
var alpha = T / pendulum.J;
/* Calculate current velocity from last frame's velocity and
average of last frame's acceleration with this frame's acceleration. */
pendulum.omega += 0.5 * (alpha + pendulum.alpha) * deltaT;
/* Update acceleration */
pendulum.alpha = alpha;
var px = width/2 + pendulum.length*Math.cos(pendulum.theta);
var py = 50 + pendulum.length*Math.sin(pendulum.theta);
...
};
The velocity verlet method has us do things "out of order", so to speak. I'll describe the steps in the order I feel is natural, however, starting with torque:
First we calculate the torque on the pendulum. Since gravity pulls downwards at all times, we need to use some trigonometry to get the component of the pendulum's weight that's pulling the pendulum towards the center -- the small portion of the weight pointed perpendicular to the pendulum itself. Because of the fact that we set up the θ = 0 point on the right horizontal, we get this by calculating m * g * cos(θ) -- (where m is the pendulum's mass and g is 9.81 m/s2, the acceleration due to gravity on Earth).
Since we're looking for a torque, we have to multiply that perpendicular force by its distance from the center.
Once we have the torque the next few steps are easy. We calculate the angular acceleration α, and then we implement a piece of velocity verlet to get the angular velocity ω: we use the average of last frame's and this frame's acceleration in the calculation.
Finally, we calculate the angle θ. Notice this time I kept the 0.5 * α * Δt2 in the equation. Up until now I've left that term out -- Δt is pretty small, and squaring it makes it so small it's almost negligible. But let's leave it in here now just as a demonstration!
And that's it for the physics. The next part is a little trigonometry: we have to convert our radius and angle to x- and y-coordinates for the canvas. This is achieved readily with sine and cosine.
As an added bonus, we draw a cute little clock. See the JSFiddle for details.
Results
If you have a formal education in physics, you've probably done this very same pendulum problem by hand. You should notice that our numerical solution agrees very well with the analytical solution. For one, the mass of the pendulum has no effect on the pendulum's period. Only the length matters! Additionally -- without any damping -- the pendulum always returns to its highest points on either side. Feel free to fork the code below and play around.If you like these articles please tell your friends, please sign up for the mailing list below, and consider following me on Twitter. Readers like you following the blog and subscribing to the mailing list gives me the motivation to write these articles -- and potentially an e-book in the future!
You may also like my Machine Learning in Javascript series.