Animating a ball in Matlab - matlab

I have a ball with these two equations:
x(t) = v0*cos(α)*t and
y(t) = h + v0*sin(α)*t− 1/2 gt^2 , where t ∈ [0,t final] is the time variable, h is the height, v0 is the initial speed, α is the angle made by v0 with the horizontal, g = 9.8 m/s^2. The floor is at y(x) = 0.
I need to draw a small animation of the ball moving on the plot. I now I should use for, plot, drawnow, but I don't know how to do it.
Can you tell me how to obain this animation?

First, here are some test variables to start with, including the acceleration due to gravity:
g = 9.8; %// m/s^2
v0 = 2; %// m/s
alpha = pi/6; %// Radians
h = 30; %// Start at 30 metres
t_final = 4.5; %// Seconds
t_vector = 0 : 0.01 : t_final;
t_vector in the last line of code creates a vector of points from the initial time of t = 0 up until our ending time in steps of 0.01. With these defined, our job is to go through each of these points in our vector and plot our ball. Next, let's create anonymous functions for each x and y to make our plotting easier:
x = #(t) v0*cos(alpha)*t;
y = #(t) h + v0*sin(alpha)*t - 0.5*g*t.^2;
What you can do next is use a for loop and go through each value of t_vector up until t_final and plot the individual point. You should probably make the point big so we can actually see what the ball looks like:
close all;
figure; hold on;
for t = t_vector
plot(x(t), y(t), 'b.', 'MarkerSize', 16);
axis([0 t_final 0 h]);
pause(0.01);
end
The above code will first close any figures we have open, spawn a new figure and use hold on so that we can call plot multiple times and append points to the graph without it erasing each time. Then, for each point in time, we plot the location on the graph as a blue dot, then make the size of the dot 16. We also make sure that the axis doesn't automatically adjust itself by enforcing that the x values are restricted between t = 0 up to t = t_final. We also restrict the y values from y = 0 up to the initial starting height, which is 30 in my example. At each point, we pause by 0.01 ms so you can see the drawing of the points.
As a bonus, this is what the figure looks like as an animated gif:

Related

How can I make this animation faster on MatLAB

This is the code. I need help making the animation faster.
write the code to make a ball bounce back and forth between to walls. The ball bounces in the form of cos2 (𝜃) where θ goes from 0˚ to 360˚ with a length of 1000.
height of the ball is 28 inches from the center.
distance between the two walls is 30 inches.
radius of the ball is 1 inch
the ball will bounce back and forth 20 times
Code Block:
r = 1;
hmax = 28;
n = 1000;
h = linspace(0,hmax,n);
t = linspace(0,360,n);
k = 0;
pt = 1/6000;
x = zeros(length(h),length(t));
vx = x;
y = x;
vy = y;
a = r+h;
b = r+hmax/2*(cosd(t).^2)+hmax/2;
for i = 1:n
x(i,:) = a(i)+r.*cosd(t);
y(i,:) = b(i)+r.*sind(t);
vx(i,:) = r+r.*cosd(t);
vy(i,:) = r+h.*sind(t);
end
figure(3)
ball_bounce1= plot(x(1:500:end),y(1:500:end),'c','linewidth',3);
axis([-1 31 -1 31])
grid on
while k < 10
if rem(k,2) == 0
for i = 1:n
set(ball_bounce1,'XData',x(i,:),'YData',y(i,:));
pause(pt)
end
end
if k > 10
break
end
end
*Just Something That Might be Useful:
Something that may or may not be interesting to you is using an animated line with a marker representing the ball. This script follows the absolute, abs() of a cosine path. The cosine frequency can also be adjusted by changing 2*pi within the line:
y = Amplitude.*abs(cos(linspace(0,2*pi,Number_Of_Samples))) + Ball_Offset;
This script uses the drawnow to repeateadly draw new points that are queued/added by the addpoints() function.
GIF of Ball Movement (a lot smoother in MATLAB):
Script:
clf;
Animated_Plot = animatedline('MaximumNumPoints',1,'Marker','o','MarkerSize',10);
Amplitude = 28;
Wall_Distance = 30;
Number_Of_Samples = 500;
Ball_Offset = 0.4;
axis([0 Wall_Distance 0 Amplitude+0.2*Amplitude]);
xlabel("Position Between Wall 0 and Wall 30"); ylabel("Amplitude");
title("Ball Movement");
x = linspace(0,Wall_Distance,Number_Of_Samples);
y = Amplitude.*abs(cos(linspace(0,2*pi,Number_Of_Samples))) + Ball_Offset;
%Mirroring and repeating%
x = [x flip(x)];
y = [y flip(y)];
x = repmat(x,1,20);
y = repmat(y,1,20);
for Point = 1: length(x)
addpoints(Animated_Plot, x(Point), y(Point));
drawnow
end
Ran using MATLAB R2019b
Reduce number of vertices of ball. You are drawing 1000 segments to draw a circle, 16 or 32 segments would be enough for that. To do so, you need x and y matrices should be m by n, where m is the number of time slices and n is the number of segments.
Firs step is to define two h and two t vectors, h1 and t1 with m elements, and h2 and t2 with n elements. After doing so, the animation runs pretty smooth here.
And as a side note, I think your movement modelling is wrong. The ball in your code moves like top figure, I believe it should go like the bottom one:

Animating circles, based on ODE-solver output in Matlab [duplicate]

I have a ball with these two equations:
x(t) = v0*cos(α)*t and
y(t) = h + v0*sin(α)*t− 1/2 gt^2 , where t ∈ [0,t final] is the time variable, h is the height, v0 is the initial speed, α is the angle made by v0 with the horizontal, g = 9.8 m/s^2. The floor is at y(x) = 0.
I need to draw a small animation of the ball moving on the plot. I now I should use for, plot, drawnow, but I don't know how to do it.
Can you tell me how to obain this animation?
First, here are some test variables to start with, including the acceleration due to gravity:
g = 9.8; %// m/s^2
v0 = 2; %// m/s
alpha = pi/6; %// Radians
h = 30; %// Start at 30 metres
t_final = 4.5; %// Seconds
t_vector = 0 : 0.01 : t_final;
t_vector in the last line of code creates a vector of points from the initial time of t = 0 up until our ending time in steps of 0.01. With these defined, our job is to go through each of these points in our vector and plot our ball. Next, let's create anonymous functions for each x and y to make our plotting easier:
x = #(t) v0*cos(alpha)*t;
y = #(t) h + v0*sin(alpha)*t - 0.5*g*t.^2;
What you can do next is use a for loop and go through each value of t_vector up until t_final and plot the individual point. You should probably make the point big so we can actually see what the ball looks like:
close all;
figure; hold on;
for t = t_vector
plot(x(t), y(t), 'b.', 'MarkerSize', 16);
axis([0 t_final 0 h]);
pause(0.01);
end
The above code will first close any figures we have open, spawn a new figure and use hold on so that we can call plot multiple times and append points to the graph without it erasing each time. Then, for each point in time, we plot the location on the graph as a blue dot, then make the size of the dot 16. We also make sure that the axis doesn't automatically adjust itself by enforcing that the x values are restricted between t = 0 up to t = t_final. We also restrict the y values from y = 0 up to the initial starting height, which is 30 in my example. At each point, we pause by 0.01 ms so you can see the drawing of the points.
As a bonus, this is what the figure looks like as an animated gif:

matlab: moving circle along a graph and axis equal

Hello and pardon me if my english is a bit rusty. I'm trying to create a circle that moves along a parametric function (coordinates are stored in vectors). I have written a function for drawing the circle and I know that you can use the axis equal command in matlab in order to create a circle shape and avoid an ellipse. My problem is that when I do this the figure window becomes very wide relative to the plotted graph. Any input is appreciated.
MAIN CODE:
t = linspace(0,3);
x = 30*cos(pi/4)/2*(1-exp(-0.5*t));
y = (30*sin(pi/4)/2 + 9.81/0.5^2)*(1-exp(0.5*t)) - 9.81*t/0.5;
for i = 1:length(t)
plot(x,y)
axis equal
hold on
cirkel(x(i),y(i),1,1,'r') % argument #3 is the radius #4 is 1 for fill
hold off
pause(0.01)
end
CIRCLE CODE:
function cirkel(x,y,r,f,c)
angle = linspace(0, 2*pi, 360);
xp = x + r*cos(angle);
yp = y + r*sin(angle);
plot(x,y)
if f == 1 && nargin == 5
fill(xp,yp,c)
end
When you call axis equal it makes one unit of the x axis be the same size as one unit of the y axis. You are seeing what you are because your y values span a much larger range than the x values.
One way to deal with this would be to query the aspect ratio and x/y limits of the current axes as shown in the second part of this answer. However, an easier approach is rather than using fill to plot your circle, you could instead use scatter with a circular marker which will be circular regardless of the aspect ratio of your axes.
t = linspace(0,3);
x = 30*cos(pi/4)/2*(1-exp(-0.5*t));
y = (30*sin(pi/4)/2 + 9.81/0.5^2)*(1-exp(0.5*t)) - 9.81*t/0.5;
% Plot the entire curve
hplot = plot(x, y);
hold on;
% Create a scatter plot where the area of the marker is 50. Store the handle to the plot
% in the variable hscatter so we can update the position inside of the loop
hscatter = scatter(x(1), y(1), 50, 'r', 'MarkerFaceColor', 'r');
for k = 1:length(t)
% Update the location of the scatter plot
set(hscatter, 'XData', x(k), ... % Set the X Position of the circle to x(k)
'YData', y(k)) % Set the Y Position of the circle to y(k)
% Refresh the plot
drawnow
end
As a side note, it is best to update existing plot objects rather than creating new ones.
If you want the small dot to appear circular, and you want to have a reasonable domain (x-axis extent), try this:
function cirkel(x,y,r,f,c)
angle = linspace(0, 2*pi, 360);
xp = x + 0.04*r*cos(angle); %% adding scale factor of 0.04 to make it appear circular
yp = y + r*sin(angle);
plot(x,y)
if f == 1 && nargin == 5
fill(xp,yp,c)
end
Note the addition of the scale factor in the computation of xp. If you want to automate this, you can add another parameter to cirkel(), let's call it s, that contains the scale factor. You can calculate the scale factor in your script by computing the ratio of the range to the domain (y extent divided by x extent).

Hough Transform: Converted polar coordinates back to Cartesian, but still can't plot them

So I have already implemented every part of a Hough Transform on my own, except for actually plotting the lines back onto the original image.
I can set up my array of data that I have like this.
points | theta | rho
-------|-------|----
[246,0] -90 -246
[128,0] -90 -128
[9,0] -90 -9
[0,9] 0 9
[0,128] 0 128
[0,246] 0 246
The points are the points that were converted from the peaks in Polar Coordinates. So now I need to draw all six of these lines and I have had no luck.
Edit
So I tried to change my code based off suggestions. This is what I came up with.
function help(img, outfile, peaks, rho, theta)
imshow(img);
x0 = 1;
xend = size(img,2);
peaks_len=length(peaks);
for i=1:peaks_len
peak=peaks(i,:);
r_ind=peak(1);
t_ind=peak(2);
r=rho(r_ind);
th=theta(t_ind);
%display([r,th,peak]);
%// if a vertical line, then draw a vertical line centered at x = r
% display([r, th]);
if (th == 0)
display('th=0');
display([1, size(img,1)]);
line([r r], [1 size(img,1)], 'Color', 'green');
else
%// Compute starting y coordinate
y0 = abs((-cosd(th)/sind(th))*x0 + (r / sind(th)))+11;%-25;
%// Compute ending y coordinate
yend = abs((-cosd(th)/sind(th))*xend + (r / sind(th)))+11;%-25;
display('y');
display([y0, yend]);
display('x');
display([x0 xend]);
%// Draw the line
line([x0 xend], [y0 yend], 'Color', 'green');
end
end
end
I had to change from r==0 to th==0 because th=0 would give NAN errors when r was not 0.
Based off the peaks, I then used that to get the data I needed to then calculate some values... but for some reason this isn't plotting well.
If you notice the + 11 for both y values. I had to do that to get the lines to be where they need to. I have a feeling something else went wrong.
I did change it so that my Rho values are all now positive.
If you recall from the parameterization of the Hough space, the direct relation between rho,theta to x,y is:
rho = x*cos(theta) + y*sin(theta)
Bear in mind that x,y represent the column and row location respectively. In addition, the origin is defined at the top-left corner of the image. Now that you want to plot the equation of the line, you have your rho and theta. Simply re-arrange the equation so that you can solve for an equation of the line of the form y = mx + b:
As such , simply loop over each rho and theta you have and draw a line that starts from the origin at x = 0 up to the limit of your image x = width-1. However, because MATLAB is 1-indexed, we need to go from x = 1 to x = width. Supposing that your rho and theta are stored in separate arrays of the same lengths and you have your edge image stored in im, you can do something like this:
imshow(im); %// Show the image
hold on; %// Hold so we can draw lines
numLines = numel(rho); %// or numel(theta);
%// These are constant and never change
x0 = 1;
xend = size(im,2); %// Get the width of the image
%// For each rho,theta pair...
for idx = 1 : numLines
r = rho(idx); th = theta(idx); %// Get rho and theta
%// Compute starting y coordinate
y0 = (-cosd(th)/sind(th))*x0 + (r / sind(th)); %// Note theta in degrees to respect your convention
%// Compute ending y coordinate
yend = (-cosd(th)/sind(th))*xend + (r / sind(th));
%// Draw the line
line([x0 xend], [y0 yend], 'Color', 'blue');
end
The above code is pretty simple. First, show the image using imshow in MATLAB. Next, use hold on so we can draw our lines in the image that will go on top of the image. Next, we calculate how many rho,theta pairs there are, and then we define the two x coordinates to be 1 and width as we will use these to determine where the starting and ending y coordinates are, given these x coordinates. Next, for each rho,theta pair we have, determine the corresponding y coordinates, then use line to draw a line from the starting and ending (x,y) coordinates in blue. We repeat this until we run out of lines.
Don't be alarmed if the y coordinates that are produced go out of bounds in the image. line will be intelligent enough to simply cap the result.
When theta = 0
The above code works assuming that you have no vertical lines detected in the Hough Transform, or when theta = 0. If theta = 0 (like in your case), this means that we have a vertical line which would thus produce an infinite slope and our formulation of y = mx + b is invalid. Should theta = 0, the equation of the line becomes x = rho. As such, you will need an additional if statement inside your loop that will detect this:
imshow(im); %// Show the image
hold on; %// Hold so we can draw lines
numLines = numel(rho); %// or numel(theta);
%// These are constant and never change
x0 = 1;
xend = size(im,2); %// Get the width of the image
%// For each rho,theta pair...
for idx = 1 : numLines
r = rho(idx); th = theta(idx); %// Get rho and theta
%// if a vertical line, then draw a vertical line centered at x = r
if (th == 0)
line([r r], [1 size(im,1)], 'Color', 'blue');
else
%// Compute starting y coordinate
y0 = (-cosd(th)/sind(th))*x0 + (r / sind(th)); %// Note theta in degrees to respect your convention
%// Compute ending y coordinate
yend = (-cosd(th)/sind(th))*xend + (r / sind(th));
%// Draw the line
line([x0 xend], [y0 yend], 'Color', 'blue');
end
end
In order to draw the vertical line, I need to know how high the image is so that we can draw a vertical line from the top of the image (y = 1) down to the bottom of the image (y = height) which is anchored at x = rho. As such, the above code should now properly handle any line, as well as the degenerate case when the slope is infinite. Therefore, this second version of the code is what you're after.
Good luck!

Animation process in Matlab

I am just learning how to use Matlab. The problem is animating simple 2D plots. In trying to animate a line from (0,0) to (0, 10) connecting them in an animation I have this so far:
x = 0;
p = plot(x, y, 'o', 'EraseMode', 'none'); % p is the handle, for later manipulations
axis equal
for k = 0:1:10 % the idea here is to have k go from 0 to 10 and set y to that value
y = k;
set(p,'XData', x, 'YData', y) % then this adds another point based on that new y
drawnow
end
The problem is, when this is run, is that it only plots the first point. Any help appreciated.
You should draw a line define by two points, and then at each iteration update the y value of the second point:
h = plot([0 0],[0 0]); %// draw line initially
axis([-1 1 0 10]) %// freeze axis to see how the line grows
for k = 0:.1:10
set(h,'YData',[0 k]) %// update second y value
drawnow
end
MATLAB introduced a new way of animating lines, starting with version R2014b, called animatedLine.
Here's how you can use it to draw the vertical line in your question.
x = 0;
h = animatedline();
set(gca,'ylim',[0 10],'xlim',[-5 5],'box','on');
for y=0:0.0001:10;
addpoints(h,x,y);
drawnow update
end
Adjust the step size (0.001 in this example) to increase or decrease your animation speed as necessary. To get a set frames per second you will want to look into a timer callback instead.