Modeling a Spinning Sprinkler

Subtitle: “You don’t really understand something until you model it”

Here is the video. It’s great. Watch it.

The basic idea is to predict the path of water that is shot from a spinning sprinkler. In the first case, the water is shot straight out of the spinning pipe. The second case is a little bit trickier with the water shot towards the center of the sprinkler. OK, it’s not actually a sprinkler.

Of course, once a drop of water leaves the sprinkler, it will only have the gravitational force acting on it. So, if you view this from the top—a drop of water should travel in a straight line with a constant velocity. But there is a problem that makes this difficult to predict. It’s that we don’t see the path of one drop of water, we see the path of a water stream.

A water stream is a collection of water drops. Even though one drop might travel in a straight line, the next drop will be “launched” at a different location with a different velocity. This makes it look weird.

OK, so let’s get to a model. I’m going to go over the steps to build this model in VPython.

Build a bar

Don’t try to do everything at once. Let’s just make a spinning bar—I’ll add water balls later. Here is what that spinning bar looks like.

And here is the code (along with a link to the code – https://trinket.io/glowscript/d6545ddfca

Let me go over some of the important parts of this code.

  • The bar is an object of type “box”—this is a prebuilt object in VPython. It has two important attributes. The position (pos) is the location of the center of the box. The size is the vector with length, width, and height.
  • I added a ball so you can see the center (it’s not needed).
  • The variable “omega” is the angular velocity of the rotation. You can change this if you like.
  • The variable “theta” is the angular position of the bar—this is used for something later.
  • In the loop, the rate(100) tells the code to not do any more than 100 loops per second. Since I have a time step of 0.01 seconds, this means 100 loop would take one second—it would run in “real time”.
  • Don’t worry about line 16 (update theta)—at least not for now.
  • Line 18 is the important part. There is a rotate function in Vpython. You need to pick the angle (in this case it’s dtheta which is the angular velocity times the time step), the axis of rotation (the z-axis) and the origin of rotation (the origin).

But it works.

Add a single water

The next step is to add a single ball of water to the end of the sprinkler bar. It’s not going to do anything except to “ride around”. Here’s what that looks like. It’s really the same thing except with that ball of water.

Here is the code—https://trinket.io/glowscript/14e1ecbb7d. Let me just point out the important parts.

If I know the angular position of the sprinkler, I can find the vector from the center of the sprinkler to the end of the sprinkler. It looks like this:

\vec{r} = \left(\frac{L}{2}\right) <\cos\theta,\sin\theta,0>

For each iteration of the loop, I can calculate theta and then use that to calculate “r”. This r is now the new vector position of the ball.

List of balls

Now for the magic. Lists are your friend. I feel like I could write a whole post on just lists—but I want to get right to the good stuff.

In short, a list is a group of things in python. Let me start with an example program.

balls=[]
x=-5
dx=1

while x<3:
  balls=balls+[x]
  x=x+dx

print("balls = ",balls)
print("balls 3 = ",balls[2])

Here are some notes on this code.

  • balls = [] makes an empty list. The name of this list is balls.
  • In the loop, I add a new x value to the list and then update x.
  • At the end, I print the list of balls and the 3rd item in the list (the first item would be balls[0]).

Here’s the output.

But wait! You don’t just have to make a list of numbers. I can make a list with objects too. Check out this version of the code.

balls=[]
x=-5
dx=1

while x<3:
  balls=balls+[sphere(pos=vector(x,0,0), radius=0.1,color=color.cyan)]
  x=x+dx


print("balls 3 position = ",balls[2].pos)

Here is the output.

Boom. Check that out. It’s 8 balls—but in just one list. You can even print out the position of one of the balls (you can’t print the whole list because a sphere() isn’t printable).

Water balls in a list

OK, I think we are ready. Oh, you might not be ready—maybe you need some more practice with lists. Just start playing around and see what happens. Anyway, here is the plan.

  • Make a list of water balls (actually two lists—one for each side).
  • Start the time (t = 0) and a time step of dt.
  • Set a ball time counter. If the time gets to some specified value, then create a ball and add it to the list (both lists).
  • When you create a water ball, set its properties: mass, size, add a trail…oh, and initial velocity. Yup. You can do that.
  • Now let stuff run. I will need to go through each ball list and update the water ball positions, but that’s not too difficult.

Let’s just get to the code. Here it is (also on trinket.io)

GlowScript 2.9 VPython

#Length of sprinkler - just leave this
L=0.1
stick=box(pos=vector(0,0,0), size=vector(L,.05*L,.05*L),color=color.yellow)
cent=sphere(pos=vector(0,0,0), radius=0.03*L, color=color.red)


#CHANGE THIS - rotation rate of sprinkler
omega=2*pi/2


theta=0

#CHANGE THIS to -1 to make balls shoot IN
a=1 

t=0
dt=0.01

#this is just a spacer to make the scene look nice
space=sphere(pos=vector(4*L,0,0),radius=0.001)


#water stuff
water=[]
water2=[]
vwater=.3
tint=0 #this is the "clock" for shooting water

#CHANGE THIS - this is the water ball production rate
f=15 #water per second rate that balls are made


while t<10:
  rate(100)
  r=(L/2)*vector(cos(theta),sin(theta),0)
  r2=-r
  

  if tint>=1/f:
    
    water=water+[sphere(pos=r,radius=0.04*L, color=color.cyan, v=(-1*cross(r,vector(0,0,omega))+a*vwater*r.hat),
    make_trail=False)]
    water2=water2 +[sphere(pos=r2,radius=0.04*L, color=color.cyan, v=(-1*cross(r2,vector(0,0,omega))+a*vwater*r2.hat),
    make_trail=False)]
    tint=0
  for ball in water:
    ball.pos=ball.pos+ball.v*dt
    if ball.pos.mag>3*L:
      ball.v=vector(0,0,0)
      ball.visible=False
      del ball
  for ball2 in water2:
    ball2.pos=ball2.pos+ball2.v*dt
    if ball2.pos.mag>3*L:
      ball2.v=vector(0,0,0)
      ball2.visible=False
      del ball2  
    
  theta=theta+omega*dt
  
  stick.rotate(angle=dt*omega,axis=vector(0,0,1), origin=vector(0,0,0))
  t=t+dt
  tint=tint+dt

This is what the output looks like. Actually, this is an animation for the case of the water shooting inward (since I already had the gif).

Now for some comments on the code.

  • When the water ball gets a certain distance away (I think I set it to 3*L), I change the water ball velocity to vector(0,0,0) and then I make it invisible. Otherwise the view would just keep expanding and it would look weird.
  • I don’t have any other important comments, but I can’t have a one bullet list.

I think that’s good enough. Hope that helps.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s