Friday, December 28, 2012

Two animation scripts - and why Movimentum is still necessary

Here is a small tool chain to create animations for mechanical explanations. And here is an explanation of the compiler that creates ImageMagick (or other) calls from animation scripts.

Is there still a need to complete the Movimentum project (which is getting more and more complex)?

Well, there is! Let me explain this with two very simple mechanisms,
  • the "Scotch yoke mechanism" and
  • the simple crank (mechanism)
which also serve as examples of animation scripts in my "tiny animation language." Here are diagrams of both:

Scotch-yoke mechanism

Crank mechanism

Getting these mechanisms to turn their wheels will also be a short tutorial about how to write animation scripts.

Scotch-yoke is easy


Let us start is the animation for Scotch-yoke. Here is the result of what we'll develop:



The "model" for this gear is easy. We overlay three pieces:
  • the fixed blue block (file Block.PNG),
  • the turning red wheel (file Wheel.PNG), and
  • the orange slider (file Slider.PNG).

The blue block is always at the same place:

  Block.PNG -geometry +0+0 -composite

The wheel is simply rotated by some angle !A (whose actual values will be set later). The center of the rotation must be found by inspecting the image with some graphics viewer that can show coordinates:

  ( Wheel.PNG -distort SRT "619,265,!A" ) -geometry +0+0 -composite

Finally, we have to move the slider by some x distance. This distance must vary like a sine wave. My little language can create sine waves only for vector variables, therefore we define such a variable %S, but use only its x component:

  Slider.PNG -geometry +%S:x+0 -composite

Overlaying these parts yields the following call to convert—the result is written to f_*.PNG:

$ ... convert -size 824x528 xc:white \
  Block.PNG -geometry +0+0 -composite \
  ( Wheel.PNG -distort SRT "619,265,!A" ) -geometry +0+0 -composite \
  Slider.PNG -geometry +%S:x+0 -composite \
  f_!T.PNG

When I created this animation the first time, I used 825x529 as size. The libx264 codec, however, complained that width and height were not even, so I changed them to 824x528—and it worked!
What about the variables' values?

Increasing !A is easy. We choose a rotation of 5 degrees per frame, starting at 0:

  !A 0 5 360

Moving %S is a little awkward. Here is one(!) way of doing it: %S starts at x coordinate 0 (because this is the initial shift of the slider), and has the same y as the rotation center of the wheel. Moreoever, we want to rotate it about some point which we call %C. Therefore, we have

  %S 0 0 %C 5

Now, we need to place %C. As the %S anchor of the slider is at its left end (the red circle), %C must be the rotation center of that end. Therefore, its coordinates are not (619,0)—the center of the wheel—, but (R,0), where R is the pixel radius of the wheel. Measuring this in some graphics program, I found R=118, and so the coordinates for %C are:

  %C 118 0 0 0

How many frames should we produce? 360 divided by 5 is 72, so 72 frames make one revolution. Two rotations would be fine, so we create 150 frames. Thus, our animation script is:

  !T 10000 1 .

  !A 0 5 360
  %C 118 0 0 0
  %S 0 0 %C 5
  $ 150 convert -size 824x528 xc:white \
    Block.PNG -geometry +0+0 -composite \
    ( Wheel.PNG -distort SRT "619,265,!A" ) -geometry +0+0 -composite \
    Slider.PNG -geometry +%S:x+0 -composite \
    e\f_!T.png

... and this is exactly what produces the animation shown above!

Actually, I like to start animations without any movement; and then accelerate the mechanism. Here is a script that does this:

!T 20000 1 .

# We start with 12 frames with increments of 0 degrees, i.e., nothing moves:
!A 0 0 360
%C 118 0 0 0
%S 0 0 %C 0
$ 12 convert -size 824x528 xc:white \
  Block.PNG -geometry +0+0 -composite \
  ( Wheel.PNG -distort SRT "619,265,!A" ) -geometry +0+0 -composite \
  Slider.PNG -geometry +%S:x+0 -composite \
  e\f_!T.png

# Next, we set the increment to 1 degrees for 4 frames ...
!A . 1 .
%S . . %C 1
$ 4

# ... then to 2 ...
!A . 2 .
%S . . %C 2
$ 4

# ... then to 3 ...
!A . 3 .
%S . . %C 3
$ 4

# ... then to 4:
!A . 4 .
%S . . %C 4
$ 4

# Then, we run with increments of 5 degrees for 150 frames.
!A . 5 .
%S . . %C 5
$ 150

# For deceleration, we reduce the increments to 3 for 4 frames ...
!A . 3 .
%S . . %C 3
$ 4

# ... then to 1 ...
!A . 1 .
%S . . %C 1
$ 4

# Finally, we end with 12 frames without movement:
!A . 0 .
%S . . %C 0
$ 12

And here is the result:



So far so good. But what about the crank?

The crank is difficult


We place the block and the wheel as before:

  Block.PNG -geometry +0+0 -composite
  ( Wheel.PNG -distort SRT "619,265,!A" ) -geometry +0+0 -composite

The driving rod must turn at its right end; and moreover, it must change its angle. In my script language, we need something like

  ( Rod.PNG -distort SRT "619,265,!R" ) -geometry +%S:x+%S:y -composite

where !R is the rod's angle. We can reuse %S from the Scotch-yoke mechanism ... I won't explain why, just try it out. Leaving !R at zero for the moment, we get a crank with "flying rod":

  !T 30000 1 .

  !R 0 0 360
  !A 0 5 360
  %C 118 0 0 0
  %S 0 0 %C 5
  $ 50 convert -size 824x528 xc:white \
    Block.PNG -geometry +0+0 -composite \
    ( Wheel.PNG -distort SRT "619,265,!A" ) -geometry +0+0 -composite \
    ( Rod.PNG -distort SRT "501,265,!R" ) -geometry +%S:x+%S:y -composite \
    e\f_!T.png

But what can we do about the rod's angle? Well—nothing. The "piston motion equations" for the crank mechanism are not simple linear or rotational formulas. Here is the equation for x in the "angle domain":


I could add functionality for this equation (and maybe I will, if I create the third animation with a crank). But of course there will be another linkage which still cannot be computed; and if I add that, there will be one more, and so on. Movimentum, on the other hand, as a general equation solver should solve almost all equations for mechanical linkages, without any need to patch the animation compiler.

What can we do right now? We can interpolate. Let us divide the circle into eight segments, each of which has 72/8 = 9 frames. At the end of the first segment, the right end of the rod will be 0.707r above the center line. The angle in the last frame must be asin(0.707 · r / d), where r is the radius of the crank and d the length of the rod. In our case, we find an angle of asin(0.707 · 118 / 447) = 10.75°. If we distribute this evenly over the 9 frames, we find an angle of 1.19° per frame. So we try the following:

!T 40000 1 .

!R 0 -1.19 360
!A 0 5 360
%C 118 0 0 0
%S 0 0 %C 5
$ 9

# stop at end
!R . 0 .
!A . 0 .
%S . . %C 0
$ 10




That looks almost acceptable. Ok, the left end goes a little bit up and down—but we'll leave it at that.

At the end of the next octant, the angle is asin(118 / 447) = 15.3°. We have to distribute 15.3° – 10.75° over 9 frames, which gives us 0.51° per frame for that octant:

!T 50000 1 .

!R 0 -1.19 360
!A 0 5 360
%C 118 0 0 0
%S 0 0 %C 5
$ 9

!R . -0.51 .
$ 9

# stop at end
!R . 0 .
!A . 0 .
%S . . %C 0
$ 10


For the next octants, we can copy the results which gives us the following animation:

!T 60000 1 .

!R 0 -1.19 360
!A 0 5 360
%C 118 0 0 0
%S 0 0 %C 5
$ 9

!R . -0.51 .
$ 9

!R . 0.51 .
$ 9

!R . 1.19 .
$ 18

!R . 0.51 .
$ 9

!R . -0.51 .
$ 9

!R . -1.19 .
$ 9

# stop at end
!R . 0 .
!A . 0 .
%S . . %C 0
$ 10



Mhm—not as good as needed. Of course, subdividing the circle in more segments is possible—but becomes more and more cumbersome. So, maybe a new version of an animation language would be helpful if cranks appear at more and more places.

I hope that this short introduction to my tool chain for simple mechaincal animations has been interesting. Of course, there is much more capable software around (ImageMagick itself can do some animation, then there's Flash programming, modern 3D CAD tools and what-have-you), but for me, it was fun to develop this tooling with a 100-line compiler, some existing command-line tools, and a simple CAD software at the front end!

No comments:

Post a Comment