Interception! A first project on velocity and calculus.

This lab is an exercise in which we collaboratively work out the problem of intercepting a thrown ball with another projectile. As our first exercise in understanding motion and velocity, we're going to compute the trajectory of a thrown tennis ball from webcam footage of the ball. The footage is shot at 30 fps.

Step 1. Gather data from video.

GetFrame[n_,Dir_] := Module[{firstPNG},
If[Dir == "initframe",
,
firstPNG= FileNames["*.png",{Dir}][[1]];
ImageAdjust[Import[StringReplace[firstPNG,"001" -> StringTake["000" <> ToString[n],-3]]]]]
];

Button["Load data",mydatapath=SystemDialogInput["Directory",ToString[NotebookDirectory[]]]]

nFrames = Length[FileNames["*.png",{mydatapath}]];
Frames = Table[GetFrame[i,mydatapath],{i,1,nFrames}];

RecordedPositions=1;
Data = Table[{0,{0,0}},{i,1,20}];
Manipulate[Frames[[i]],{{pt1,{0,0}},Locator},{{i,1,Dynamic[Button["Record position",Data[[RecordedPositions++]] = {i,pt1}]]},1,Length[Frames],1}]

Data

Data = Select[Data,#[[1]] > 0 &]

DataX = Transpose[{Data[[All,1]],Data[[All,2,1]]}]

DataY = Transpose[{Data[[All,1]],Data[[All,2,2]]}]

Step 2. Plot the fitted data against the actual video to check fit.

XFit = Fit[DataX,{1,t},t]

YFit = Fit[DataY,{1,t,t^2},t]

Show[ListLinePlot[DataX,PlotMarkers->Automatic],Plot[XFit,{t,0,25},Filling->Axis]]

Show[ListLinePlot[DataY,PlotMarkers->Automatic],Plot[YFit,{t,0,25},Filling->Axis]]

FitGraphics = Show[ParametricPlot[{XFit,YFit},{t,0,25},PlotRange->{{0,640},{0,480}},PlotStyle->{Thickness[0.004],Blue,Opacity[1]},AspectRatio->Automatic,Axes->None],ParametricPlot[{XFit,YFit},{t,0,25},PlotRange->{{0,640},{0,480}},PlotStyle->{Thickness[0.01],LightBlue,Opacity[0.5]},AspectRatio->Automatic,Axes->None],ListPlot[Data[[All,2]],PlotMarkers->{Automatic,Small}]]

FitPlot = Rasterize[FitGraphics,Background->None,ImageSize->{640,480}];

FitPoly = InterpolatingPolynomial[Data[[2;;4,2]],x]

ImgPlot = Rasterize[Show[Plot[FitPoly,{x,0,640},PlotRange->{{0,640},{0,480}},PlotStyle->{Thick,Blue},AspectRatio->Automatic,Axes->None],
ListPlot[Data[[1;;4,2]],PlotMarkers->{Automatic,Large}]],Background->None,ImageSize->{640,480}];

Composed = Table[ImageCompose[Frames[[i]],FitPlot],{i,1,Length[Frames]}];

Manipulate[Composed[[i]],{i,1,Length[Composed],1}]

Step 3. Figure out the trajectory of the intercepting projectile.

Suppose we have a launcher located at (640,480) (the lower right corner of the frame) which is capable of launching a projectile at 75 px/frame at an angle of 30 degrees from the horizontal. We want to figure out the correct launch time (in frames) for this projectile to intercept an incoming tennis ball with x coordinate given by

	x(t) = a t + b
	y(t) = c t^2 + d t + e
	
To do this, we need to first figure out the interception projectile's x and y coordinates at time t, assuming that the launch time is t0. Keep in mind that we know the position and velocity of the launch projectile at this time. Let's denote these by 

	X(t) = A t + B
	Y(t) = C t^2 + D t + E

Step 4. Solve for the launch time of the intercepting projectile.

We now need to solve for the launch time which results in an interception of the incoming projectile. Hint: we have a system of 2 simultaneous equations in the unknown parameters launch time (t0) and interception time (t1), and we want to solve them.

Step 5. Plot the launch trajectory on the video to see whether it works!

We now plot the computed launch trajectory on top of the original video to see what happens. Here's an example (which misses):

InterceptX = -50 t + (640 + 50 * 15);
InterceptY = -1.759 t^2 + 83 t - 850;

InterceptionPlot[n_] := Module[{loc},
loc = {InterceptX,InterceptY} /. t-> n;
{ParametricPlot[{InterceptX,InterceptY},{t,0,Length[Frames]},PlotRange->{{0,640},{0,480}},PlotStyle->{Thick,Red},AspectRatio->Automatic,Axes->None],ListPlot[{loc},PlotMarkers->{Automatic,Medium},PlotStyle->Red]}
];

Show[InterceptionPlot[22]]

InterceptComposed = Table[ImageCompose[Composed[[i]],Rasterize[Show[InterceptionPlot[i]],Background->None,ImageSize->{640,480}]],{i,1,Length[Frames]}];

Manipulate[InterceptComposed[[i]],{i,1,Length[InterceptComposed],1}]