Student Center
Collision of Billiard Balls
In this exercise, we use MATLAB and Simulink to model the movement of billiard balls.
Two billiard balls are lying at rest on a billiards table, which measures 8 feet by 4 feet. The figure below shows the initial position of each billiard ball:

Figure 1: Billiard table illustrates position of two billiard balls.
At time t = 0, the cue ball (white ball) is hit directly toward the red ball and has an initial velocity of 0.5 ft/s. The cue ball elastically collides with the red ball. The red ball travels directly toward the upper-right corner of the table, and the cue ball travels at an angle of -45 degrees to the horizontal. Assume that the balls do not slow down due to friction. Where is each ball located at t = 12 seconds?
Solving the problem:
This problem consists of three separate parts:
- The cue ball is hit and travels toward the red ball.
- The cue ball and the red ball collide.
- The cue ball and the red ball travel off in different directions.
Let’s model this problem one part at a time:
Part 1: The cue ball is hit and travels toward the red ball.
We know the cue ball’s initial velocity and initial position. We can get the position of the cue ball using a Constant block and an Integrator block.
- Insert a Constant block (from the Sources library) into the model. Label this block as v0 and enter an initial velocity of 0.5.
- Next we need to get the position of the cue ball. So let’s insert an Integrator block (from the Continuous library) into the model, and connect the v0 block to the Integrator block.
- Double-click the Integrator block and set the Initial condition as 1. (The cue ball starts at x = 1, and we are assuming the left edge of the table is x = 0.)
-
Send the value of the position of the cue ball to the workspace using a To Workspace block (Sinks library). Name this variable xA.
Our model now looks like this:
Figure 2: Model of cue ball position.
Part 2: The cue ball and the red ball collide.
We know the direction of the balls after the collision, but we do not know their velocities. To find this information, we will use the Conservation of Momentum principle, which states that the momentum of the system before impact must be the same as the momentum of the system after impact, as long as no external forces are acting on the system. Here are the two simultaneous equations that we need to solve:
-
mAv0 = mAvAcos( θA ) + mBvBcos( θB )
-
0 = mAvAsin(θA) + mBvBsin(θB)
Because mA = mB, these equations can be simplified:
-
v0 = vAcos( θA ) + vBcos( θB )
-
0 = vAsin(θA) + vBsin(θB)
Now, we could solve these equations using Simulink. However, the model would look rather complicated because it would involve algebraic loops.
A better solution is to use MATLAB to solve this problem, because MATLAB excels at solving systems of linear equations. We can use MATLAB directly within Simulink using the Embedded MATLAB Function block.
- First, we need to tell Simulink when to model the collision. Insert an If block and an If-Action Subsystem block into the model (Ports & Subsystems library).
- Branch off the cue ball position signal by right-clicking the signal. Then connect the signal to the input of the If block.
- Double-click the If block and uncheck “Show else condition”.
- Enter the following as the If expression: (u1 >= 3.7) & (u1 <= 3.75). This ensures that the collision calculations are made when the cue ball impacts the red ball. (This happens when the center of the cue ball is at x = 3.7 ft since the radius of each ball is approximately 0.15 ft.)
- Connect the output of the If block to the if port of the If-Action Subsystem block.
- Double-click the If-Action Subsystem block and insert an Embedded MATLAB Function block (User-Defined Functions library) into the system.
- Double-click the Embedded MATLAB Function block and use the following code to solve the system of linear equations:
- Insert three Inports (Sources library) and four Outports (Sinks library) into the If-Action Subsystem block. Label the three Inports as v0, angleA, angleB and the four Outports as vAx, vAy, vBx, vBy.
- Go back to the main model and insert two Constant blocks. Label them angleA and angleB. Enter -45*(pi/180) for angleA, and atan(0.5) for angleB.
- Connect v0, angleA, and angleB to the corresponding inports of the If Action Subsystem block. Our model now looks like this:
function [vAx,vAy,vBx,vBy] = fcn(v0, angleA, angleB)
A = [cos(angleA) cos(angleB); sin(angleA) sin(angleB)];
B = [v0; 0];
x = inv(A)*B;
vAx = x(1)*cos(angleA);
vAy = x(1)*sin(angleA);
vBx = x(2)*cos(angleB);
vBy = x(2)*sin(angleB);
Main Model

If Action Subsystem

Figure 3: Main model and If Action Subsystem model.
Part 3: The cue ball and the red ball travel in different directions.
Now that we know the velocity of each ball, we can find the position of each ball and output these values to the workspace.
- Insert four Integrator blocks into the model and connect the four output ports of the If Action Subsystem to the four input ports of the Integrator blocks.
- Set the initial value of the vAx Integrator block to 3.7.
- Set the initial value of the vBx Integrator block to 4.
- Insert three To Workspace blocks into the model and connect the vAy, vBx, and vBy Integrator blocks to these To Workspace blocks. Label the variables as yA, xB, and yB, respectively.
- The value of xA is a little trickier. Before impact, we want to output the value of xA as the signal from the first v0 Integrator block. However, after impact, this signal no longer represents the value of xA; xA is now the integral of the output signal of the If Action Subsystem. We will insert a Switch block (Signal Routing library) into our model to switch between these two signals.
- The second port is the control port. We input the signal from the v0 Integrator block into the control port.
- Double-click the Switch block, set the Criteria to u2 >= Threshold, and the Threshold to 3.7.
- The signal that is input into the first input port of the Switch block will get passed when xA >= 3.7. We want the output signal from the If Action Subsystem to be this signal (the value of xA after impact). So we connect this signal to the first input port of the Switch block.
- The signal that is input into the third input port of the Switch block will get passed when
xA < 3.7. We want the output signal from the v0 Integrator block to be this signal (the value of xA before impact). So connect this signal to the third input port of the Switch block. - Delete the previous signal that was connected to the xA To Workspace block. Connect the output port of the Switch block to the xA To Workspace block. Our model now looks like this:

Figure 4: Complete system model.
Finally, we can answer our original question – where is each ball located at t = 12 seconds?
In the Simulation -> Configuration Parameters menu, select a fixed step solver with a fixed step time of 0.1 seconds and a stop time of 15 seconds. Now we can run the model.
We know the position of the ball at 0.1-second increments. To find the value of xA, yA, xB, or yB at these increments of time, type the following at the MATLAB prompt:
output = [tout xA yA xB yB]
Examine the table to find the positions of the balls at all increments of time.
BONUS: To visualize the collision after the model has finished executing, insert the following code in the Stop callback function of the model (Go to File> Model Properties and choose the Callbacks tab):
%Draw the billiards table
i = 1;
diam = 12;
hold on;
axis([0 8 -2 2])
set(gca,'Color','g','xcolor','g','ycolor','g','PlotBoxAspectRatio',[1 0.5 1],'xtick',[],'ytick',[])
plot([0 0 4 4 8 8],[2 -2 2 -2 2 -2],'o', 'MarkerEdgeColor','k', 'MarkerFaceColor','k','MarkerSize',diam+2);
%Plot the position of each ball as a marker.
h(1) = plot(xA(1),yA(1),'o', 'MarkerEdgeColor','w', 'MarkerFaceColor','w','MarkerSize',diam);
h(2) = plot(xB(1),yB(1),'o', 'MarkerEdgeColor','r', 'MarkerFaceColor','r','MarkerSize',diam);
i=2;
while i <= length(xA)
delete(h(1));delete(h(2))
h(1) = plot(xA(i),yA(i),'o', 'MarkerEdgeColor','w', 'MarkerFaceColor','w','MarkerSize',diam);
h(2) = plot(xB(i),yB(i),'o', 'MarkerEdgeColor','r', 'MarkerFaceColor','r','MarkerSize',diam);
pause(0.01)
i = i+1;
end
Store