Main content
Computer programming
Course: Computer programming > Unit 5
Lesson 7: Oscillations- Oscillation amplitude and period
- Challenge: Rainbow slinky
- Oscillation with angular velocity
- Challenge: Spaceship ride
- Waves
- Challenge: Many waves
- Trig and forces: the pendulum
- Challenge: Pendulum puppet
- Spring forces
- Project: Curling, crawling, circling creatures
© 2023 Khan AcademyTerms of usePrivacy PolicyCookie Notice
Spring forces
In the beginning of this section, we looked at modeling simple harmonic motion by mapping the sine wave to a pixel range, and had you model a bob on a spring using that sine wave. While using the
sin()
function is a quick-and-dirty, one-line-of-code way of getting something up and running, it won’t do if what we really want is to have a bob hanging from a spring in a two-dimensional space that responds to other forces in the environment (wind, gravity, etc.) To accomplish a simulation like this (one that is identical to the pendulum example, only now the arm is a springy connection), we need to model the forces of a spring using PVector
.The force of a spring is calculated according to Hooke’s law, named for Robert Hooke, a British physicist who developed the formula in 1660. Hooke originally stated the law in Latin: "Ut tensio, sic vis," or “As the extension, so the force.” Let’s think of it this way:
The force of the spring is directly proportional to the extension of the spring.
In other words, if you pull on the bob a lot, the force will be strong; if you pull on the bob a little, the force will be weak. Mathematically, the law is stated as follows:
k
is constant and its value will ultimately scale the force. Is the spring highly elastic or quite rigid?x
refers to the displacement of the spring, i.e. the difference between the current length and the rest length. The rest length is defined as the length of the spring in a state of equilibrium.
Now remember, force is a vector, so we need to calculate both magnitude and direction. Let’s look at one more diagram of the spring and label all the givens we might have in a program.
Let’s establish the following three starting variables as shown in the diagram above, with some reasonable values.
var anchor = new PVector(100, 10);
var bob = new PVector(110, 100);
var restLength = 20;
First, let’s use Hooke’s law to calculate the magnitude of the force. We need to know
k
and x
. k
is easy; it’s just a constant, so let’s make something up.var k = 0.1;
x
is perhaps a bit more difficult. We need to know the “difference between the current length and the rest length.” The rest length is defined as the variable restLength
. What’s the current length? The distance between the anchor and the bob. And how can we calculate that distance? How about the magnitude of a vector that points from the anchor to the bob? (Note that this is exactly the same process we employed when calculating distance in the Gravitational Attraction section.)var dir = PVector.sub(bob, anchor);
var currentLength = dir.mag();
var x = currentLength - restLength;
Now that we’ve sorted out the elements necessary for the magnitude of the force
(-1 * k * x)
, we need to figure out the direction, a unit vector pointing in the direction of the force. The good news is that we already have this vector. Right? Just a moment ago we thought to ourselves: “How we can calculate that distance? How about the magnitude of a vector that points from the anchor to the bob?” Well, that same vector is the direction of the force!In the diagram above, we can see that if we stretch the spring beyond its rest length, there should be a force pulling it back towards the anchor. And if it shrinks below its rest length, the force should push it away from the anchor. This reversal of direction is accounted for in the formula with the -1. And so all we need to do is normalize the
PVector
we used for the distance calculation! Let’s take a look at the code and rename that PVector
variable as “force.”var k = 0.01;
var force = PVector.sub(bob, anchor);
var currentLength = force.mag();
var x = currentLength - restLength;
// Direction of spring force, a unit vector
force.normalize();
// Putting it together: direction and magnitude!
force.mult(-1 * k * x);
Now that we have the algorithm worked out for computing the spring force vector, the question remains: what object-oriented programming structure should we use? This, again, is one of those situations in which there is no “correct” answer. There are several possibilities; which one we choose depends on the program’s goals and one’s own personal coding style. Still, since we’ve been working all along with a
Mover
object, let’s keep going with this same framework. Let’s think of our Mover
object as the spring’s “bob.” The bob needs location, velocity, and acceleration vectors to move about the screen. Perfect—we’ve got that already! And perhaps the bob experiences a gravity force via the applyForce()
method. Just one more step—we need to apply the spring force:var bob = new Bob();
draw = function() {
// Our “make-up-a-gravity force”
var gravity = new PVector(0, 1);
bob.applyForce(gravity);
// We need to also calculate and apply a spring force!
var spring = ????
bob.applyForce(spring);
// Our standard update() and display() methods
bob.update();
bob.display();
};
draw()
loop. But thinking ahead to when you might have multiple bobs and multiple spring connections, it makes a good deal of sense to write an additional object, a Spring
object. As shown in the diagram above, the Bob
object keeps track of the movements of the bob; the Spring
object keeps track of the spring’s anchor and its rest length and calculates the spring force on the bob.This allows us to write this lovely code to tie them together:
var bob = new Bob();
var spring = new Spring();
draw = function() {
// Our “make-up-a-gravity force”
var gravity = new PVector(0, 1);
bob.applyForce(gravity);
// Spring.connect() will take care of
// computing and applying the spring force
spring.connect(bob);
// Our standard update() and display() methods
bob.update();
bob.display();
};
You may notice here that this is quite similar to what we did in the Gravity section with an attractor. There, we said something like:
var force = attractor.calculateAttraction(mover);
mover.applyForce(force);
The analogous situation here with a spring would be:
var force = spring.calculateForce(bob);
bob.applyForce(force);
Nevertheless, in this example, all we did was:
spring.connect(bob);
What gives? Why don’t we need to call
applyForce()
on the bob? The answer is, of course, that we do need to call applyForce()
on the bob. Only instead of doing it in draw()
, we’re just demonstrating that a perfectly reasonable (and sometimes preferable) alternative is to ask the connect()
method to internally handle calling applyForce()
on the bob.Spring.prototype.connect(bob) {
var force = /* some fancy calculations */;
bob.applyForce(force);
};
Why do it one way with the
Attractor
object and another way with the Spring
object? When we were first learning about forces, it was a bit clearer to show all the forces being applied in the main draw()
loop, and hopefully this helped you learn about force accumulation. Now that we’re more comfortable with that, perhaps it’s simpler to embed some of the details inside the objects themselves.Let's put it all together, in the program embedded below. We've added a few things: (1) the
Bob
object includes functions for mouse interactivity so that the bob can be dragged around the window, and (2) the Spring
object includes a function to constrain the connection’s length between a minimum and a maximum.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?
- If I use notepad++ to compile the code, how to display it using canvas?(1 vote)
- Notepad++ will not compile your code, compilation is done in the browser that is showing the HTML page. Notepad++ is a text editor, it creates text files, which can be HTML, or plain text files.
Go here, and paste the code into Notepad++ and save it as; TEMPLATE.HTM
https://www.khanacademy.org/computer-programming/webpage-template/5413012314390528
Then launch the file in your browser.(6 votes)
- Still what is meant by the extension of the spring?(2 votes)
- When you pull on a spring, you extend it. When you push a spring, you compress it. Compression and extension are opposites.(2 votes)
- The exlanation of the connect function is not clear and also what is b?(2 votes)
- What specifically are you having trouble with?
b
is the parameter passed into theconnect
function that is the bob passed in.(2 votes)
- I get confused when springs and strings are asked and I am not able to figure out where the spring applies the force.(2 votes)
- On line 130: line(0,0, v3.x, v3.y);
What is the purpose of this?(2 votes) - I have a doubt about the handleDrag method. in the handleClick it defines :
this.dragOffset.x = this.position.x-mx;
this.dragOffset.y = this.position.y-my;
And in the handleDrag it does :
this.position.x = mx + this.dragOffset.x;
this.position.y = my + this.dragOffset.y;
But if you solve these equations, you will find :
this.position.x= this.position.x;
and this.position.y= this.position.y;
How it's works ?? I can't understand :/
thank you(2 votes)- Well, handle click happens before handle drag then handle drag continues until it's not being dragged. So, in other words it starts with the click, so dragOffset = this.position-m then the drag happens and if m is different, then it moves this.position to the new m. So, in other words this.position = m is the result.(1 vote)
- Where do you find maxLength?(1 vote)
- Line 135:
The maximum length is 200.spring.constrainLength(bob, 30, 200);
(3 votes)
- this.dragOffset = new PVector();
this.dragging = false;.
so what is basically " dragOffset" ?(3 votes)- In the instance shown, "dragOffset" is a variable which holds the difference, or offset of the mouse position and the object(bob) position.(2 votes)
- b.position = PVector.add(this.anchor, dir);
What does this do? does it change the original value of b.position? how are the x and y changed?(1 vote)b.position
becomes the sum of thethis.anchor
vector and thedir
vector.
It does not change the original values ofb.position
. Instead it replaces the entire vector object.(2 votes)
- On the pendulum puppet challenge, there is a hint:
Pendulum.prototype.display = function() {
if () {
this.currentOrigin = ;
} else {
this.currentOrigin = ;
}
};
var leftArm1 = new Pendulum(new PVector(width/2-50, 110), limbLength);
var leftArm2 = new Pendulum(leftArm1, limbLength);
and in the instructions, it says
"...we suggest letting the first argument of Pendulum be either a PVector or another Pendulum, and acting accordingly. "
I feel like some more information or similar example code would have helped. The concept seems clear, but if the lingo and sequencing was a polished brass key , I'm hoping a bent rusty nail can align the tumblers.(1 vote)