If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

Main content

Trig and forces: the pendulum

Do you remember Newton’s laws of motion from a couple sections back? Back then, we used those laws to calculate the acceleration of an object, so that we could compute and draw its new position in the world. Now, we're going to use those laws to calculate the acceleration of a pendulum, to compute and draw its position along the swing. And as it turns out, we're going to need some help from trigonometry along the way.
A pendulum is a bob suspended from a pivot. Obviously a real-world pendulum would live in a 3D space, but we’re going to look at a simpler scenario, a pendulum in a 2D space—the program canvas.
Diagram of pendulum with angles
In the Forces section, we learned how a force (such as the force of gravity shown in the diagram above) causes an object to accelerate: F=M×A, or A=F/M.
In this case, however, the pendulum bob doesn’t simply fall to the ground, since it is attached by an arm to the pivot point. Instead the bob swings towards its rest position, and we want to compute the acceleration of the bob along the swing. We'll call that its angular acceleration, since the pendulum is accelerating along an arc.
In order to determine the pendulum's angular acceleration, we need to break the force of gravity into components. One component will be along the pendulum arm. We can ignore that component because the arm is always pulling against it, cancelling it out. The other component is perpendicular to the arm. That's the one we care about, because it's pulling the pendulum "sideways", making it swing. Let’s zoom in on the pendulum diagram and visualize those components of the gravity force:
Fg is the total force of gravity downwards. Fp is the force of gravity perpendicular to the arm of the pendulum, pointing in the opposite direction that the pendulum is swinging. Fa is the force of gravity along the arm, which we'll ignore since it won't affect the angular acceleration.
Now how do we calculate Fp? This is where we use our trigonometry. Fg is the hypotenuse of a right triangle, and θ is the angle of the arm. Sine equals opposite over hypotenuse:
sin(θ)=FpFg
Therefore:
Fp=Fgsin(θ)
Great, we now have a simple formula to compute Fp. Now let's circle back to our original question: What is the angular acceleration of the pendulum? Once we find the angular acceleration, we’ll be able to apply our rules of motion to find the new angle for the pendulum.
angular velocity = angular velocity + angular acceleration
angle = angle + angular velocity
Thanks to Newton’s second law, we know that there is a relationship between force and acceleration, namely F=M×A, or A=F/M, and we can use that relationship with the formula above to compute an angular acceleration. See if you can follow this:
Starting with:
perpendicular force = force due to gravity * sine(θ)
Then we divide the right side by mass, to come up with the acceleration, based on Newton's second law:
angular acceleration = (force due to gravity * sine(θ)) / mass
Then we realize we can just divide the force due to gravity by mass, and that's the same thing as acceleration due to gravity, so we'll just substitute that:
angular acceleration = acceleration due to gravity * sine (θ)
Ta-da! We now have a way to calculate the angular acceleration.
We can simplify that even further, since we're ProcessingJS programmers and not physicists. Yes, we know that the acceleration due to gravity on earth is 9.8 meters per second squared. But this number isn’t relevant to us. In our programs, our "gravity" is just an arbitrary number, one that we can use to scale the acceleration to something that feels right.
angular acceleration = gravity * sine(θ)
Amazing. After all that, the formula is so simple. You might be wondering, why bother going through the derivation at all? I mean, learning is great and all, but we could have easily just said, "Hey, the angular acceleration of a pendulum is some constant times the sine of the angle."
This is just another moment in which we remind ourselves that the purpose of the course is not to learn how pendulums swing or gravity works. The point is to think creatively about how things can move about the screen in a computationally based graphics system. The pendulum is just a case study. If you can understand the approach to programming a pendulum, then however you choose to design your onscreen world, you can apply the same techniques.
Of course, we’re not finished yet. We may be happy with our simple, elegant formula, but we still have to apply it in code. This is most definitely a good time to practice our object-oriented programming skills and create a Pendulum object. Let’s think about all the properties we’ve encountered in our pendulum discussion that the object will need to keep track of:
  • arm length
  • angle
  • angular velocity
  • angular acceleration
Plus we'll also want to specify where the pendulum is hanging from, so we could start with a constructor like this:
var Pendulum  = function(origin, armLength) {
    this.origin = origin;
    this.armLength = armLength;

    this.angle = PI/4;
    this.aVelocity = 0.0;
    this.aAcceleration = 0.0;
};
We’ll also need to write an update() method to update the pendulum’s angle according to our formula…
Pendulum.prototype.update = function() {
    // Arbitrary constant
    var gravity = 0.4;
    // Calculate acceleration
    this.aAcceleration = -1 * gravity * sin(this.angle);
    // Increment velocity
    this.aVelocity += this.aAcceleration;
    // Increment angle
    this.angle += this.aVelocity;    
};
…as well as a display() method to draw the pendulum in the window. This begs the question: “Um, where do we draw the pendulum?” We know the angle and the arm length, but how do we know the x,y (Cartesian!) coordinates for both the pendulum’s pivot point (let’s call it origin) and bob location (let’s call it position)? This may be getting a little tiring, but the answer, yet again, is trigonometry. Let's reference the diagram above.
The origin is just something we make up, as is the arm length. Let’s say we construct our pendulum like so:
var p = new Pendulum(new PVector(100, 10), 125);
We're storing the current angle on the angle property. So relative to the origin, the pendulum’s position is a polar coordinate: (r,angle). And we need it to be Cartesian. Luckily for us, we spent some time in the Angles section deriving the formula for converting from polar to Cartesian. In that section, our angle was relative to the horizontal axis, but here, it's relative to the vertical axis, so we end up using sin() for the x position and cos() for the y position, instead of cos() and sin(), respectively. And so, we can calculate the position relative to the origin using that conversion formula, and then add the origin position to it:
this.position = new PVector(
   this.armLength * sin(this.angle),
   this.armLength * cos(this.angle));
this.position.add(this.origin);
stroke(0, 0, 0);
fill(175, 175, 175);
line(this.origin.x, this.origin.y, this.position.x, this.position.y);
ellipse(this.position.x, this.position.y, 16, 16);
Before we put everything together, there’s one last little detail I neglected to mention. Let’s think about the pendulum arm for a moment. Is it a metal rod? A string? A rubber band? How is it attached to the pivot point? How long is it? What is its mass? Is it a windy day? There are a lot of questions that we could continue to ask that would affect the simulation. We’re living, of course, in a fantasy world, one where the pendulum’s arm is some idealized rod that never bends and the mass of the bob is concentrated in a single, infinitesimally small point.
Nevertheless, even though we don’t want to worry ourselves with all of the questions, we should add one more variable to our calculation of angular acceleration. To keep things simple, in our derivation of the pendulum’s acceleration, we assumed that the length of the pendulum’s arm is 1. In fact, the length of the pendulum’s arm affects the acceleration greatly: the longer the arm, the slower the acceleration. To simulate a pendulum more accurately, we divide by that length, in this case armLength. For a more involved explanation, visit The Simple Pendulum website.
this.aAcceleration = (-1 * gravity / this.armLength) * sin(this.angle);
Finally, a real-world pendulum is going to experience some amount of friction (at the pivot point) and air resistance. With our code as is, the pendulum would swing forever, so to make it more realistic we can use a “damping” trick. I say trick because rather than model the resistance forces with some degree of accuracy (as we did in the Forces section), we can achieve a similar result by simply reducing the angular velocity during each cycle. The following code reduces the velocity by 1% (or multiplies it by 99%) during each frame of animation:
this.aVelocity *= this.damping;
Putting everything together, we have the following example. We've added a bit of functionality to make it easy to drag the bob and drop it from different heights, too. Try it out! 

This "Natural Simulations" course is a derivative of "The Nature of Code" by Daniel Shiffman, used under a Creative Commons Attribution-NonCommercial 3.0 Unported License.

Want to join the conversation?

  • blobby green style avatar for user John Preston Cua
    Hi,
    The article seems to jump from giving us the
    sin(theta) = Fp/Fg formula to
    this.aAcceleration = (-1 * gravity / this.armLength) * sin(this.angle);

    I understand that there is a different article that explains why to add the division by this.armLength....

    However, my question now is why add the part where u multiply by -1, when the foundation/basic formula is sin(theta) = Fp/Fg formula to which works out to
    Fg * sin(theta) = Fp or Fp = Fg * sin(theta)

    And in the ProcessingJS world where 0 0 normally starts on the top left of the screen, Fg should be a positive number so that the position will go down as the number gets incremented. By multiplying it by -1, isn't it the reverse of Fg already?

    Thank you....
    (7 votes)
    Default Khan Academy avatar avatar for user
    • old spice man green style avatar for user Bob Lyon
      You are very observant, but the -1 has nothing to do with the default grid layout of the Processing.js canvas.

      This section makes my head explode every time I look at it. It is because the original author abandoned all the previous sections and instead concentrated on angular displacements, angular velocities and angular accelerations as a "simplifying" move. (KA's only fault is republishing it... I vented about this long ago and I agreed that there was no real choice but to keep the original text.)

      A way to look at it goes all the way back to the first picture of this section. The angle is the pendulum's angle relative to the vertical axis (and not the traditional horizontal axis). So angle zero is the resting position. When the angle is positive, the sine of the angle is positive and we want the effects of gravity to "pull" the bob back towards the zero angle, so the -1 is necessary. Similarly, when the angle is negative, its sine is negative and we still want the effects of gravity to "pull" the bob back towards the zero angle, but now that pulling must be positive, so the -1 is necessary. (Clear as mud, right? i tried...)

      Note that the variable gravity is only expressing gravitational effects. With more time and possible confusion, I could make the argument that the gravity variable should always be a negative number, thus obviating the -1.

      The other effects of basing the angle off of the vertical axis is reflected in the display method. There you notice that the X coordinate is computed using the sine of the angle while the Y coordinate uses the cosine. This is bass ackwards from what a casual observer (like you or me) would expect.

      Bonus: Now explain the initialization of the pendulum's angle as computed by the handleDrag method. Do not let your head explode.
      (18 votes)
  • leaf green style avatar for user Vlad Winter
    Regarding the Pendulum Puppet challenge:
    I can't figure out how to get access to Limb1 from Limb2. If there where pointers it would be easy.
    However, when I pass the Limb1 parameter into Limb2 constructor, I just make a new copy of Limb1 and those changes made to Limb2 by the limb2.display function don't get passed into the copy limb2 makes.
    Any suggestions?
    (4 votes)
    Default Khan Academy avatar avatar for user
    • old spice man green style avatar for user Bob Lyon
      I made it so you pass either a PVector object or a Pendulum object as the origin argument to the Pendulum constructor function. Then, within the display method I immediately set a new property, currentOrigin which describes the pivot point of this pendulum using the Javascript instanceof operator:
          if (this.origin instanceof PVector) {
      this.currentOrigin = this.origin;
      } else {
      this.currentOrigin = this.origin.position;
      }
      Then I can use the currentOrigin property knowing it's always the pivot point of the pendulum.
      (14 votes)
  • blobby green style avatar for user CountOfTrouble
    Anyone know the correct formatting to get it to accept the first step?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • male robot hal style avatar for user hideotsubouchi
    This is regarding Challenge: Pendulum puppet step two.

    I have been thinking of this for weeks, I still cannot find an answer.
    Any help will be highly appreciated.

    As pointed out below, by Bob Lyon, the program certainly works well by passing a PVector or a Pendulum object to the origin argument of the Pendulum constructor function.

    However, I think it should also work if either a PVector or a position of another instance (e.g., rightArm1.position) is passed as an origin argument when Pendulum instances are made. Then, in the case that a position of another instance is used, a new position will be calculated based on the position of another instance as the origin.

    I tried this, but even when a position of another instance was used as the origin, the origin is set to x = 0, y = 0, doesn't go anywhere else. I don't understand why.

    I have monitored the positions of limbs (e.g., for rightArm1, text(rightArm1.position, ....) etc ).
    rightArm1.position is certainly getting correct numbers (x = ~250, y = ~185).

    Any help/suggestion will be highly appreciated.
    Thanks for your help in advance!
    (6 votes)
    Default Khan Academy avatar avatar for user
  • winston default style avatar for user octoberX
    In the next challenge:
    I am not able to understand the concept of this code --

    if( this.origin instanceof PVector){
    this.currentOrigin = this.origin;
    }else{
    this.currentOrigin = this.origin.position;
    }

    Please Help !!
    (2 votes)
    Default Khan Academy avatar avatar for user
    • old spice man green style avatar for user Jim E
      Each pendulum (limb) have either a PVector as it's origin or another Pendulum. So we need to know if we just use the origin which is a PVector, or the "parent" Pendulum.position (also a PVector).

      For example see how left arm is created

      Upper arm have a static PVector as it's origin:
      var leftArm1 = new Pendulum(new PVector(width/2-50, 110), limbLength, random(0,360));

      Lower arm is attached to upperArm
      var leftArm2 = new Pendulum(leftArm1, limbLength, random(0,360));
      (5 votes)
  • duskpin ultimate style avatar for user Meagan Browitt
    I'm stuck on Step 2 of the Pendulum challenge. Here is what I have:

    angleMode = "radians";

    var Pendulum = function(origin, armLength) {
    this.origin = origin;
    this.armLength = armLength;
    this.position = new PVector();
    this.angle = 0;

    this.aVelocity = 0.0;
    this.aAcceleration = 0.0;
    this.damping = 0.995;
    this.ballRadius = 25.0;
    this.dragging = false;
    };

    Pendulum.prototype.go = function() {
    this.update();
    this.display();
    };

    Pendulum.prototype.update = function() {
    // As long as we aren't dragging the pendulum, let it swing!
    if (!this.dragging) {
    // Arbitrary constant
    var gravity = 0.4;
    // Calculate acceleration
    this.aAcceleration = (-1 * gravity / this.armLength) * sin(this.angle);
    // Increment velocity
    this.aVelocity += this.aAcceleration;
    // Arbitrary damping
    this.aVelocity *= this.damping;
    // Increment angle
    this.angle += this.aVelocity;
    }
    };

    Pendulum.prototype.display = function() {
    if (this.origin instanceof PVector){
    this.currentOrigin = this.origin;
    } else {
    this.currentOrigin = this.currentOrigin.position;
    }
    this.position = new PVector(
    this.armLength * sin(this.angle),
    this.armLength * cos(this.angle));
    this.position.add(this.currentOrigin);
    stroke(0, 0, 0);
    strokeWeight(3);
    line(this.currentOrigin.x, this.currentOrigin.y, this.position.x, this.position.y);
    fill(224, 194, 134);
    if (this.dragging) {
    fill(143, 110, 44);
    }
    ellipse(this.position.x, this.position.y, this.ballRadius, this.ballRadius);
    };

    var limbLength = 75;
    var leftArm1 = new Pendulum(new PVector(width/2-50, 110));
    var leftArm2 = new Pendulum(leftArm1, limbLength);
    Pendulum.prototype.handleClick = function(mx, my) {
    var d = dist(mx, my, this.position.x, this.position.y);
    if (d < this.ballRadius) {
    this.dragging = true;
    }
    };

    Pendulum.prototype.stopDragging = function() {
    this.aVelocity = 0;
    this.dragging = false;
    };

    Pendulum.prototype.handleDrag = function(mx, my) {
    if (this.dragging) {
    var diff = PVector.sub(this.origin, new PVector(mx, my));
    this.angle = atan2(-1*diff.y, diff.x) - radians(90);
    }
    };

    var limbLength = 75;
    var leftArm1 = new Pendulum(new PVector(width/2-50, 110), limbLength);
    var leftArm2 = new Pendulum(new PVector(width/2-50, 185), limbLength);
    var rightArm1 = new Pendulum(new PVector(width/2+50, 110), limbLength);
    var rightArm2 = new Pendulum(new PVector(width/2+50, 185), limbLength);
    var leftLeg1 = new Pendulum(new PVector(width/2+40, 230), limbLength);
    var leftLeg2 = new Pendulum(new PVector(width/2+40, 305), limbLength);
    var rightLeg1 = new Pendulum(new PVector(width/2-40, 230), limbLength);
    var rightLeg2 = new Pendulum(new PVector(width/2-40, 305), limbLength);

    var limbs = [leftLeg1, leftLeg2,
    rightLeg1, rightLeg2,
    leftArm1, leftArm2,
    rightArm1, rightArm2];

    draw = function() {
    background(255);

    // Draw the body
    strokeWeight(7);
    line(width/2-50, 110, width/2+50, 110);
    line(width/2, 110, width/2, 230);
    line(width/2-40, 230, width/2+40, 230);
    fill(224, 194, 134);
    rect(width/2-25, 39, 50, 64, 30);
    fill(0, 0, 0);
    strokeWeight(0.4);
    ellipse(191,63,20/4,20/4);
    ellipse(209,63,20/4,20/4);
    fill(255, 255, 255);
    ellipse(191,63,3,3);
    ellipse(209,63,3,3);
    fill(224, 194, 134);
    strokeWeight(3);
    line(191,91,209,91);
    for (var i = 0; i < limbs.length; i++){
    limbs[i].go();
    }
    };

    mousePressed = function() {
    for (var i = 0; i < limbs.length; i++){
    limbs[i].handleClick(mouseX, mouseY);
    }
    };

    mouseDragged = function() {
    for (var i = 0; i < limbs.length; i++){
    limbs[i].handleDrag(mouseX, mouseY);
    }
    };

    mouseReleased = function() {
    for (var i = 0; i < limbs.length; i++){
    limbs[i].stopDragging();
    }
    };

    The grader says: make sure you pass the top limbs as arguments to the bottom ones.
    How do I that?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user John Preston Cua
    Hi,
    Im stuck on Step 1 in the Pendulum Puppet Challenge.
    I tried both for loop method and calling each limb one by one and both did not get a pass from the Grader.
    Example of my for loop:
    for(var i = 0; i < limbs.length; i++){
    var limb = limbs[i];
    limb.go();
    }

    What do I have to do to get passed step 1?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user Hani Mereih
    I'm stuck on step 3, although i made the puppet move, but still the grader won't let me pass, please help, please, here is my code;

    var limbLength = 75;
    var leftArm1 = new Pendulum(new PVector(width/2-50, 110), limbLength, this.angle = 2);
    var leftArm2 = new Pendulum(leftArm1, limbLength, this.angle = 2);
    var rightArm1 = new Pendulum(new PVector(width/2+50, 110), limbLength, this.angle = 2);
    var rightArm2 = new Pendulum(rightArm1, limbLength, this.angle = 2);
    var leftLeg1 = new Pendulum(new PVector(width/2+40, 230), limbLength, this.angle = 2/1);
    var leftLeg2 = new Pendulum(leftLeg1, limbLength, this.angle = 2);
    var rightLeg1 = new Pendulum(new PVector(width/2-40, 230), limbLength, this.angle = 2/1);
    var rightLeg2 = new Pendulum(rightLeg1, limbLength, this.angle = 2);

    var limbs = [leftLeg1, leftLeg2,
    rightLeg1, rightLeg2,
    leftArm1, leftArm2,
    rightArm1, rightArm2];
    (2 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user mike.j.cashin
    I cannot get past part 1 of the next challenge (Pendulum puppet). I know I need to use a for loop, and have this as the draw function:

    draw = function() {
    background(255);

    // Draw the body
    strokeWeight(4);
    line(width/2-50, 110, width/2+50, 110);
    line(width/2, 110, width/2, 230);
    line(width/2-40, 230, width/2+40, 230);
    fill(224, 194, 134);
    rect(width/2-25, 39, 50, 64, 30);

    for(var i = 0; i <= limbs.length; i++){
    limbs[i].go();
    }
    };

    All I get, however, is an error message saying "Cannot read property 'go' of undefined."
    I have not changed anything other than what I showed so how do I go forward? I do not see anything wrong and the error does not point to where the problem is.
    (1 vote)
    Default Khan Academy avatar avatar for user
  • winston default style avatar for user Jared O'Leary
    I have the program working; however, the grader is not accepting my answer. Can anyone look at my code and assist? It can be found here: https://www.khanacademy.org/computer-programming/pendulum-puppet-problems/5117497249103872
    (2 votes)
    Default Khan Academy avatar avatar for user
    • aqualine tree style avatar for user Eswag
      You don't need to declare this.currentOrigin or this.even in the constructor. this.even isn't needed. Don't use this.even or anything related to it. Just set the pendulum's position predecessor to the variable name of the same limb1
      (2 votes)