Overview
This worksheet extends the Momentum worksheet from straight lines to the plane, and from describing collisions to calculating them the way a game physics engine does. It introduces the centre of mass of a system, the coefficient of restitution that controls how bouncy a collision is, and a single impulse formula that resolves any two-body collision in one step.
It ends with a C++ console program that resolves collisions between pairs of bodies and checks that momentum comes out the same as it went in.
Learning Objectives
By the end of this lab you will be able to:
- Calculate the impulse from a changing force using the area under a force-time graph
- Locate the centre of mass of a system of particles and explain why internal forces cannot change its velocity
- Derive and apply the formulas for an elastic collision in one dimension
- Define the coefficient of restitution and use it to describe collisions between perfectly elastic and perfectly inelastic
- Apply conservation of momentum component by component to collisions in two dimensions
- Use the impulse-based collision response formula to calculate velocities after a collision along a contact normal
- Implement impulse-based collision response in a console program and verify that momentum is conserved
Concept
In the Momentum worksheet, impulse was force multiplied by contact time. Real contact forces are not constant. They rise from zero, peak, and fall back as two objects squash together and spring apart. The impulse is the area under the force-time graph, whatever its shape. A physics engine usually does not know the shape at all. It skips straight to the total impulse needed to stop the objects moving into each other, and applies it in a single step.
For a group of objects there is a single point that moves as if all the mass were concentrated there and all the external forces acted on it. This is the centre of mass. Internal forces, such as the forces during a collision between members of the group, cannot change its velocity. That is conservation of momentum seen from a different angle.
Real collisions sit somewhere between perfectly bouncy and perfectly sticky. The coefficient of restitution, , measures where. It compares how fast two objects separate after a collision with how fast they approached. In two dimensions, a frictionless collision only affects the part of each velocity along the line through the point of contact, the contact normal. The part sliding along the surface carries on unchanged. Put those ideas together and you get one formula for the impulse that resolves any collision between two bodies.
Tasks
Task 1 - Impulse from a force-time graph
Hook
A baseball bat is in contact with the ball for about one thousandth of a second. During that time the force rises from nothing to a peak and falls away again. With a force that changes so quickly, how can you work out what it does to the ball?
Intuition
Split the contact time into many tiny slices. In each slice the force is nearly constant, so the impulse in that slice is force times a tiny time, a thin rectangle of area. Adding all the slices gives the total area under the curve. Whatever the shape, the area is the impulse, and the impulse is the change in momentum.
Reshape the force curve below. A tall narrow pulse and a low wide pulse can have exactly the same area and give the ball exactly the same change in velocity.
Formalise
The integral sign means "add up the area under". The average force is the impulse spread evenly over the contact time.
Worked example
A 0.145 kg baseball arrives at 40 m/s and leaves at 45 m/s in the opposite direction. Contact lasts 1 ms.
- Change in momentum. Taking the outgoing direction as positive, .
- Average force. .
- Peak force for a triangular pulse. A triangle's area is half its base times its height, so the same area needs a peak of twice the average, about 24 600 N.
Your turn
A triangular force pulse peaks at 2000 N and lasts 0.01 s. Its impulse is N s.
A force rises steadily from 0 to 500 N over 2 ms, stays at 500 N for 6 ms, then falls to 0 over 2 ms. The impulse is N s.
That impulse acts on a 0.5 kg ball at rest. Its final speed is m/s.
Two force-time graphs have the same area. One is tall and narrow, the other low and wide. Which statement is true?
Why do engines rarely calculate the force during a collision?
Task 2 - Centre of mass
Hook
A firework rocket explodes at the top of its flight, sending fragments in every direction. Is there anything about the fragments as a group that still follows the rocket's original curved path?
Intuition
The centre of mass is the mass-weighted average position of a system. For two equal masses it is halfway between them. If one is heavier, it is closer to the heavier one. Its velocity is the total momentum divided by the total mass. Because internal forces cannot change total momentum, they cannot change the centre of mass's velocity either. The fragments of the firework fly apart, but their centre of mass carries on along the parabola the rocket was following, until the first fragment hits the ground.
Formalise
Worked example
- Two masses. 2 kg at and 3 kg at . , closer to the heavier mass.
- Skaters pushing apart. 40 kg and 80 kg skaters start at rest. Total momentum is zero, so . After pushing apart they move in opposite directions, but the point between them, two thirds of the way toward the heavier skater, stays exactly where it was.
Your turn
A 4 kg mass sits at x = 1 m and a 1 kg mass at x = 6 m. The centre of mass is at x = m.
Three particles: 1 kg at (0, 0), 2 kg at (3, 0) and 1 kg at (0, 4). The centre of mass is at (, ).
A 2 kg ball moves at 6 m/s toward a 4 kg ball at rest. The centre of mass moves at m/s, before and after they collide.
A firework explodes in mid-air. Ignoring air resistance, what path does the centre of mass of the fragments follow?
In a game, two objects inside a closed system collide. Which statement is always true if the engine conserves momentum?
Task 3 - Elastic collisions in one dimension
Hook
In a Newton's cradle, one steel ball swings in, stops dead, and the ball at the far end swings out at the same speed. Why does the incoming ball stop, rather than bouncing back or carrying on?
Intuition
An elastic collision conserves both momentum and kinetic energy. Writing out both conservation laws for two objects gives two equations in the two unknown final velocities. Solving them leads to a useful fact. In an elastic collision the relative velocity reverses. The speed at which the objects approach equals the speed at which they separate. Combining that with conservation of momentum gives the final velocities directly.
Formalise
From and .
| Special case | Result |
|---|---|
| Equal masses | They swap velocities. A moving ball hitting an identical still ball stops dead, and the still one moves off at the original speed. |
| Light object hits a very heavy still object | The light object bounces back at almost its original speed. The heavy object barely moves. |
| Heavy object hits a very light still object | The heavy object carries on almost unchanged. The light object shoots off at nearly twice the heavy object's speed. |
Worked example
A 1 kg cart at 6 m/s hits a stationary 2 kg cart elastically.
- First cart. . It bounces back.
- Second cart. .
- Check momentum. Before 6, after . Check kinetic energy. Before 18 J, after .
Your turn
A 3 kg ball at 2 m/s collides elastically head-on with a 1 kg ball moving at -2 m/s. Afterward the 3 kg ball moves at m/s and the 1 kg ball at m/s.
A 2 kg puck at 5 m/s hits an identical stationary puck elastically. The first puck ends at m/s and the second at m/s.
In Newton's cradle, why does the incoming ball stop?
A ping-pong ball bounces off a stationary bowling ball elastically. What happens?
What is true of the relative velocity in a perfectly elastic collision?
Task 4 - Coefficient of restitution
Hook
Drop a tennis ball and a lump of clay from the same height. The tennis ball bounces back up to about half its height. The clay does not bounce at all. How can a game describe both with one number?
Intuition
The coefficient of restitution is the ratio of separation speed to approach speed. For a perfectly elastic collision . For a perfectly inelastic, sticky collision . Real materials sit in between. For a ball bouncing on a fixed floor, the ball leaves at times the speed it arrived at. Since height depends on speed squared, each bounce reaches of the previous height.
Change below and drop the ball.
Formalise
With for velocities before and for after, and for a ball on a fixed floor.
Worked example
A ball dropped from 2 m bounces to 1.28 m.
- Height ratio. .
- Coefficient. .
- Next bounce. .
In a game engine, is usually a property set on each material, often called bounciness or restitution. When two materials meet, the engine combines their values, commonly by taking the larger, the smaller or the average.
Your turn
A ball dropped from 1.5 m bounces to 0.96 m. Its coefficient of restitution is .
A ball hits a floor at 5 m/s with e = 0.6. It leaves the floor at m/s.
A ball with e = 0.8 is dropped from 2 m. After its third bounce it reaches m, to 3 significant figures.
Explain why a value of e greater than 1 would break conservation of energy for a ball bouncing on a fixed floor.
Task 5 - Collisions in two dimensions
Hook
In pool, the cue ball strikes another ball off centre and the two balls fly apart at an angle. How do you predict both directions?
Intuition
At the instant of contact, the only force between two smooth balls acts along the line joining their centres, the contact normal. So split each velocity into a part along the normal and a part along the tangent. The tangent parts are untouched. The normal parts behave exactly like a one-dimensional collision. Recombine the parts and you have the final velocities.
Game engines go one step further and fold all of that into a single impulse along the normal, calculated from the closing speed, the restitution and the two masses. Move the offset slider below to go from a head-on hit to a glancing blow. With equal masses and , notice the angle between the two outgoing velocities.
Formalise
With the unit normal pointing from A to B. If the closing speed is positive the bodies are already separating and no impulse is applied.
Worked example
Body A, 2 kg at 3 m/s, meets body B, 1 kg at -1 m/s, head on along x, so . Take .
- Closing speed. . Negative, so they are approaching.
- Impulse. .
- New velocities. , .
- Checks. Momentum before , after . Separation speed .
Your turn
Two 1 kg discs, A moving at (3, 0) m/s and B at rest, touch with contact normal . Take .
The closing speed along the normal is m/s and the impulse is N s.
After the collision, A moves at (, ) m/s.
After the collision, B moves at (, ) m/s.
In the exercise above, what is the angle between the two final velocities?
In a frictionless 2D collision, which part of each velocity is unchanged?
Task 6 - Impulse-based collision response in code
Collision response in a physics engine happens in two stages. Collision detection finds which bodies are touching and the contact normal between them. Collision response then changes their velocities. This task builds the response stage for circular bodies using the impulse formula from Task 5.
Create a new Console App (C++) project named CollisionResponse and replace its source file with the skeleton below, saved as CollisionResponse.cpp. Every scenario in main places two discs of radius 0.5 m exactly touching, so detection is already done.
- Calculate the contact normal
n, the vector froma.positiontob.positiondivided by its length. - Calculate the closing speed as the dot product of
b.velocity - a.velocitywithn. - If the closing speed is positive,
returnstraight away. - Calculate the impulse magnitude
j. - Subtract
n * (j / a.mass)froma.velocityand addn * (j / b.mass)tob.velocity.
Success condition: in every scenario the momentum before matches the momentum after. Equal masses head on swap velocities. The glancing blow gives (1.08, -1.44) and (1.92, 1.44), matching your answers to Task 5. The worked example gives 1 and 3 m/s. The already separating pair is left unchanged.
#include <cmath>
#include <iomanip>
#include <iostream>
#include <string>
struct Vec2
{
double x;
double y;
};
Vec2 operator+(Vec2 a, Vec2 b) { return { a.x + b.x, a.y + b.y }; }
Vec2 operator-(Vec2 a, Vec2 b) { return { a.x - b.x, a.y - b.y }; }
Vec2 operator*(Vec2 a, double s) { return { a.x * s, a.y * s }; }
double dot(Vec2 a, Vec2 b) { return a.x * b.x + a.y * b.y; }
double length(Vec2 a) { return std::sqrt(dot(a, a)); }
struct Body
{
double mass;
Vec2 position;
Vec2 velocity;
};
Vec2 momentum(const Body& a, const Body& b)
{
return a.velocity * a.mass + b.velocity * b.mass;
}
double kineticEnergy(const Body& a, const Body& b)
{
return 0.5 * a.mass * dot(a.velocity, a.velocity)
+ 0.5 * b.mass * dot(b.velocity, b.velocity);
}
void resolveCollision(Body& a, Body& b, double e)
{
// TODO: the contact normal n is the unit vector from a's centre to b's
// TODO: the closing speed is the relative velocity (b minus a) along n
// TODO: if that value is positive the bodies are already moving apart,
// so return without changing anything
// TODO: impulse magnitude j = -(1 + e) * closing / (1 / ma + 1 / mb)
// TODO: push a back along n by j / ma and b forward along n by j / mb
}
void runScenario(const std::string& name, Body a, Body b, double e)
{
Vec2 pBefore = momentum(a, b);
double keBefore = kineticEnergy(a, b);
resolveCollision(a, b, e);
Vec2 pAfter = momentum(a, b);
std::cout << name << " (e = " << e << ")\n";
std::cout << " A after (" << a.velocity.x << ", " << a.velocity.y << ")\n";
std::cout << " B after (" << b.velocity.x << ", " << b.velocity.y << ")\n";
std::cout << " momentum before (" << pBefore.x << ", " << pBefore.y << ")"
<< " after (" << pAfter.x << ", " << pAfter.y << ")\n";
std::cout << " kinetic energy before " << keBefore << " J"
<< " after " << kineticEnergy(a, b) << " J\n\n";
}
int main()
{
std::cout << std::fixed << std::setprecision(3);
// Each pair of discs has radius 0.5 m and is placed exactly touching
runScenario("Head-on, equal masses",
{ 1.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { 0.0, 0.0 } }, 1.0);
runScenario("Head-on, heavy hits light",
{ 4.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { 0.0, 0.0 } }, 1.0);
runScenario("Glancing blow, equal masses",
{ 1.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 0.8, 0.6 }, { 0.0, 0.0 } }, 1.0);
runScenario("Worked example from Task 5",
{ 2.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { -1.0, 0.0 } }, 0.5);
runScenario("Already separating",
{ 1.0, { 0.0, 0.0 }, { -1.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { 1.0, 0.0 } }, 1.0);
return 0;
}
Why does the response need to return early when the bodies are already separating?
Solution
Try the tasks above before revealing the solution.