Sunday, January 17, 2016

"Perpetual motion" / "Perpetuum mobile" laser cutting

"Perpetual motion" / "Perpetuum mobile" laser cutting


I was able to put together -- rather surprisingly quickly -- a Java program that used all the computations in my previous post.  The main design points were:
- use double floating point precision
- use variables for all things I choose (inner radius, "D" length) and all things that could vary physically.
- allow for kerf compensation, given the laser cutter could eat more material than I expect
- allow for variable material thickness
- generate SVG as the output format
- push the output to an output stream, which I later converted to dump data into a known file

Initially, just to check my computations, I'd drawn the pictures on graph paper and used a rule to measure the actual lengths.  I then used Excel to compute everything, and compared against the physical measurements.  Once I was confident in the equations, I transferred them to Java program form.


The main iteration cycle I'd go through would be
- edit the program
- run the program
- load the output SVG file into Firefox, where it would render the results
- iterate

Sometimes, I'd check the output in pure text format using a simple text editor like vim.  That also would allow me to edit some entries to see if different forms of SVG would be better than others.

Initial SVG output

My initial output was very much brute force, generating <polyline> tags with (x,y) pairs in the attributes of the polyline, and I generated all data that way.  Also initially I just wanted the D and qhyp lines.

SVG is a very simple format to use for this.  I had used SVG before, but found it useful to just read up on the info at
http://www.w3schools.com/svg/
From there, I jumped into examples of an SVG Polyline.

Roughly speaking, the initial output looked like this:
<svg>
<polyline points="x0,y0 x1,y1 x2,y2 x3,y3...." style="fill:none;stroke:black;stroke-width:3" />
...
</svg>

The code then would iterate so it was something like this:

... Set the main R, D, and theta variables
... Compute all the other things like A, H, XDL, XDR, Q, qhyp

print "<svg>"
for (int i=0; i<nSegments; i++) {
  angle = theta * i;
  convert angle to radians
  rotate (R,0) through angle using a normal rotation matrix
  rotate (XDL,H) through angle
  print the polyline with points="R,0 XDL,H" as appropriate each time.
}

... Similarly, draw the points from XDL,H to XDL',H' to build the edge walls.
print "</svg>"

The need to transform and scale

After generating the initial output, I found a few things were problematic.  First, the output wasn't visible unless I provide width and height attributes in the initial <svg> tag.  Also, if those values weren't large enough, the drawing would be clipped and the overall window wouldn't let me scroll to see it all.

Second, the output wasn't the right size for me to look at it properly.

I changed the code to generate output like this:
<svg width="800" height="600">
<g transform="translate(400,300)">
<g transform="scale(2.5,2.5)">
... do what I did earlier
</g>
</g>
</svg>

The origin in SVG rendered on screen would be at the top, left corner of the canvas, and Y increases as units move down the screen.  For me, the inverted Y axis didn't make a difference, because mirroring a cut on the laser cutter could be achieved by flipping my material over and running the same cut.  If it matters to you, then you could negate the y scale value, and translate further.

Note that the transformations are applied in inside-out order, so in the example above the scaling happens first, then the translation.

Simplifying the coding using transformations

Once I knew there were SVG native transformation operations, it meant that I wouldn't have to compute the point rotations myself.  Before the code was of the form

for i in 0..(360/theta)-1
{
  compute the x,y points at rotation angle "i*theta"
  print the appropriate svg to draw a line
}

Now the code is

compute the x,y points once at rotation angle 0
for i in 0..(360/theta)-1
{

  print ("<g transform=\"rotate(" + (i*theta) + ")\">");
  draw the shape as if it were at rotation angle zero
  print ("</g>")
}

The need not to scale

Fairly quickly, I found that the scaling operation I was doing would scale everything, including the width of lines.  Anisomorphic scaling (i.e., x scale is not the same as y scale), coupled with the scaling of line widths, resulted in having a unit square turn into a rectangle, but that rectangle would have thick edges on the short sides, and thinner edges on the long sides.

In laser cutting at the TechShop, a hairline edge width is used for cutting, but thick edge widths imply rastering (etching), so having non-uniform edges due to scaling was problematic.

Also, having scaling meant that I would have to reverse the scale computation for elements where I had a known, required final value, such as the width of a hairline.

Once I knew that out, I took out the <g transform="scale(x,y)"> operations.  Instead, I'd have to generate the SVG output using full size coordinates.

File format versions

Once I had a basic drawing in place, I took it to the TechShop and loaded it up in CorelDraw.

In the past, I've had problems loading SVG into CorelDraw.  The primary problem appears to be around curves or splines that are closed, where earlier versions of CorelDraw would not handle them properly, and would send closing vectors off to Never Never Land.

For this SVG, however, I was drawing very simple primitives, and I could load it directly in.

I did find that some computers had different versions of CorelDraw installed, and if I would load .svg, convert to .cdr, and save, it might not be readable in an earlier software installation version (CorelDraw 5 can't read CorelDraw 7 output).  To get around that, while I still hadn't ironed out my .svg output, I could export from CorelDraw 7 in .pdf, and load that into CorelDraw 5.

Pixels? Points?  What are SVG units?

There were two things I wanted to check when loading my SVG file into CorelDraw.  The first problem was units.  Since my SVG file was output with simple commands like <polyline points="100,200 200,200">, it wasn't clear exactly how those would measure out to become physical values in real world units.

A second problem that arose, still related to units, was that the concept of a "hairline" line width is what determines whether or not the Epilog laser cutter will cut as vectors, or etch as rastering.  CorelDraw doesn't explicitly show the line width in millimeters when it's set to "hairline".

My initial path here was to take a value like "100" SVG units, and compare against what was being shown in CorelDraw in millimeters.  I'd generate the SVG and load the file into Corel Draw.  Then, I'd set the ruler units (Ruler Settings option menu, then set units to millimeters) and click on an object to see how big it was.

Since the code was generating lines at angles, I had to find a generated line or rectangle that was at a multiple of 90 degrees.  Once I knew the SVG value and its corresponding CorelDraw millimeters value, I got what I thought was an SVG-to-mm ratio.  As it turns out, though, that was a mistake.  It seems that default units are "pixels", and the ratio might vary from one computer to the next.  I'm not sure, but it's definitely better to use real units and not rely on "pixels".

I also looked up the definition of "hairline" online, and it ends up being 0.00762 cm or 0.0762mm.  So, with my errant unit conversion ratio, I generated some SVG values for the "stroke-width" attribute, loaded in CorelDraw, saw "hairline" in the interface, and was happy but inaccurate.

D board, Q boards, tabs, intersections

The walls could be plain, rectangular boards, glued down to the base. But in laser cutting tradition, I chose to cut tabs and slots for them to plug into.

Here's the first sketch I had for what I'd want the boards to look like.  It's not really correct, because each D wall hits the next D wall.  But it shows the kinds of tabs to think about.

The D boards would have one tab sticking into the base.  I would choose where that tab would go, and opted to put it some percentage distance down the length of D.  I arbitrarily chose the tab length to be 20% the size of D itself, and messed around with the placement percentage to get it to hit somewhere along the RestD section of D (not along nor intersecting Base).

At the top of D, where it hits the outer edge, the board actually intersects with two Q boards at the same time.  The drawing under the Kerf heading below shows what they'd be shaped like.  The thought was to create each board in this way:
- The tabs would be 1/6th of the wall height.  Each board would have two tabs where needed.
- The D board outer tabs would be the "middle" tabs.
- One end of Q would have the "upper" tabs, and the other end would have the "lower" tabs.

This is a top-down sketch of the D boards hitting each other (labeled "Intersection point"), and at the outer edge, a D board hitting two Q boards.

Kerf

Since I'd be cutting tabs and slots, I might have to compensate for kerf, which basically meant I'd have to cut less from the slots, and more around the tabs.  The laser cutter burns away a small amount of material, much like a table saw would cut about the width of a saw blade.  While the laser is much more precise, the amount of material removed is not zero.

This is a drawing of what the kerf compensation cut lines would look like.
The red lines show what the actual object would look like, and black lines indicate where the laser cuts would be.  Material between black and red represent the kerf.

The top part really should just be "MThick" (material thickness), not "MThick + 1/2K".  The idea here is that I can draw these parts with simple x,y changes, so the code would say something like this:
print the polyline tag;
print x + "," + y + " ";
y += 2*T;
print x + "," + y + " ";
x += materialThickness;
print x + "," + y + " ";
etc.
print close polyline tag;

The bearing

At the center of the base circle, I wanted to press in a regular inline skate bearing.  I had several laying around still from the JGRO project that started, but stalled.  The outer diameter of one measured at 22.01mm, quite accurate for what the internet declared to be 22mm OD.

To add the circle at the middle of my drawing, I wanted to cut a 22mm circle, minus half kerf on both sides.  That would mean having a circle whose diameter was 22mm minus 1 kerf (radius is 11mm - half kerf).  In SVG, that would come out looking like this:
<g transform="translate(x,y)">
<circle x="somex" y="somey" r="someradius" style="fill:none;stroke:black;stroke-width:3" />

</g>

and, since I was treating the whole page origin as the center of the circle, I could use the default x,y values and just draw it like this:

<g transform="translate(x,y)">
<circle r="someradius" style="fill:none;stroke:black;stroke-width:3" />

</g>

Test cuts

Concerned about the fit of the tabs to each other, tab fit within slots, and bearing fit within circle, I did some test cuts of each.

The first test cuts are the five figures on the left side of the board.

For my "D board" test cuts, since I was dealing with a smaller piece of scrap and didn't want to waste material, I used CorelDraw to trim off a few nodes, and made two of them.

The first problem, and pretty much a showstopper for everything, was that the bearing circle came out at 21mm, far too small for the bearing to press in.  I wasn't sure if the error was caused by an incorrect kerf setting, or because of the SVG-to-mm conversion ratio I was using.

I also took the two D boards, and put their tabs against each other.  If cut correctly, they would have a smooth surface going across, but they didn't.  Instead, there was a bump up, suggesting the resulting tabs were ending up being too large.  That meant my kerf compensation value was too large (I'm on the outer edge, so cutting too far away from where I want the resulting edge to be), or my units were wrong, or both.

I then ran a second test cut with a bunch of circles of varying diameter.  Once I figured out the "right" size of a circle for my bearing, I could use that as my target for the generated SVG.  Here, CorelDraw provided a nice accelerator.

To draw circles in CorelDraw, you can choose the ellipse tool, and hold Shift while dragging to ensure the result is circular.  Then, you can select your circle (click on its edge) and hit ctrl+D to duplicate the circle.  After that, drag the new circle to a new location, and CorelDraw will remember the offset.  From there, you just hit ctrl+D again and again, and each newly duplicated circle will be offset the way you chose.

What I didn't know but learned in this exercise is that CorelDraw also will auto-adjust dimensions when you hit ctrl+D.  So what I did was:
- create circle
- using the dimensions pane, change width to 22mm and height to 22mm.
- select the circle
- hit ctrl+D to duplicate
- move the new circle to a nearby, non-overlapping location to the right of the original
- using the dimensions pane, change size to 21.95mm
- hit ctrl+D again and again
In the end, I had six circles ranging from 22mm to 21.75mm.  I just cut them all out, and tried each one with the bearing to see which woud fit best.
Because I put them too close to each other, I did a third test cut with 21.85mm and 21.8mm diameters, but with a lot of material between.  I still came out with 21.85mm being a nice, snug fit.

For the bearing hole, I also added two additional washer-style circles to be cut out.  Those were just in case the material was so thin that the bearing wouldn't have enough to grab onto.  With thin material, I'd just stack the washers over and concentric with the bearing hole, and that would provide enough thickness for a good seating of the bearing.

Reconsidering kerf compensation

The bearing circle diameter value of 21.85mm for a 22mm physical object suggested that the kerf value was actually 0.15mm, and that would translate to a very small fraction of an inch (0.005905512 inches)..  I had been assuming a 1/32" kerf, though, which would be 0.03125, about five times as large.

Left confused by the 5x factor, I just gave up on the kerf computation completely.  I dropped the kerf variable down to zero, and re-cut some D and Q boards.  After doing that, they slotted into each other quite nicely, with no noticeable step created at the top or bottom when joining the three boards together.

I also tried pushing the zero-kerf boards into the rebuilt-with-zero-kerf slots, and they fit somewhat snugly, so I went with it.

That left me just trying to figure out how to make sure my circle would come out as 21.85mm, because I still didn't have real physical units expressed in my .svg output.

SVG real world coordinates, and style sheets

So how do you figure out how to tell CorelDraw how to draw things in real world coordinates?

Turns out it's pretty easy.  But here's how I backed into it.

I started by creating a brand new file in CorelDraw, and saving it as SVG.  The file that was created showed me a few things.

First, the unit type is declared in the opening <svg> statement, where the width and height are stated.  So at the opening of my file, I really want something like this:
<svg width="800mm" height="600mm">


From that point onward, all unit measurements are assumed to be in that unit type, and they are not declared with their own unit type.

So, to get the bearing circle, I would just have to say this after having set up the millimeter unit type at the start of the file in the <svg> tag:
<circle r="21.85" style="fill:none;stroke:black;stroke-width:3" />


Even the viewBox declaration within the same <svg> tag is stated without a unit type.

I also noticed that the CorelDraw SVG output file made its XML format clear, and made use of stylesheets.  The starting portion looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve"  width="610mm" height="457mm" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 610 457"

xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.str0 {stroke:black;stroke-width:0.0762}
.str3 {stroke:black;stroke-width:1}
.strred {stroke:red;stroke-width:0.1}
.strnocutblue {stroke:blue;stroke-width:1}
.fil0 {fill:none}
]]>
</style>
</defs>


This made it so that I could declare my hairline stroke width once, and refer to it later using a declaration like this:
<circle r="21.85" class="fil0 str0" />

Some decorative swirls

To get a more interesting center, and also leave the base with less mass, I wanted some sun rays radiating out from the center.  I tried some simple crescents at first, but they weren't very interesting, and plain sine curves would cut across each other at the 180 degree point.

Fortunately, MY was home from college and able to whip up a quick formula.
<insert formula here>

Full rendering

I adjusted the code to use stylesheets and millimeter units, and re-ran the code.  I left some areas of the code such that I'd have to change them before each run, particularly the choices of whether to render the base, and/or the D boards, and/or the Q boards.  This is a drawing of the D boards and the base.  (Apologies to anyone with contrast vision problems, but the hairline stroke-width makes things very faint.)


I then took the output to Corel Draw, created a new Broad Sheet document, and copied the objects from SVG into the new page.  The material width and height sometimes wasn't exactly 24"x18", depending on what scraps I had, so it was important to lay the objects out according to actual dimensions.

I also duplicated the bearing washers, and had to manually duplicate the inner circle, and used Corel Draw's alignment functions to keep things centered up for them.

The edited Broad Sheet in Corel Draw 5 looked like this:
 I cut that on 5mm ply, and that's when I ran into the tab collision problem.  More on that later.


Monday, January 11, 2016

"Perpetual" motion - based on "perpetuum motion" video

"Perpetuum Motion" laser cut design

11-JAN-2016

Sadly, I've let my Techshop membership expire, but in a flurry of last-minute building before it went away, I got intrigued by "perpetual motion" machines that are depicted on youtube, and got in my head that I wanted to build one.

Ready for some good ol' geometry and trig?

The video

The starting point is to see the video at YouTube.  Search on "Perpetuum Mobile HD".

About 2m35s into it, you'll see a drawing attributed to Edward Somerset, and resulting machine that someone built.  I thought to make the whole thing, laser cut, but before doing that, I'd have to figure out the geometry and trig around it.

The same drawing is attributed as "Jacob Leupold’s Overbalanced Wheel" at http://jamesminshall.com/sustainability/energy-generation/perpetual-motion-generators/, though I personally find that page a bit overreaching in its claims.

I also started down the path of making one more like the "six orange segments cut out of a circle" in the first image of that page, which was easier to draw and cut, but building the "dumbbell" weights that slide along it proved to be too challenging for the scale I'd used.

The calculations

At the heart of the overbalanced wheel were a couple of variables up to anyone to choose.

The initial drawing looks sort of like this (drawn in Corel Draw 5).  This is a mirror image of what many online images/videos depict.  Laid out this way, it would rotate counter-clockwise.  I choose this representation since it makes the angle calculation visualization a bit less taxing.
Wheel geometry, 12 segments, 30-degree theta, R=5, D=8
 In this form, I see there being three degrees of freedom.  First is the R, the radius of the inner circle.  Next is what I call D, the length of the longer walls that rach the outside wall.  Finally, there is the number of segments -- in this case 12 -- and that determines theta, the angle of rotation from one R to the next (and therefore also about the origin, from one D to the next).

Definitions of R and D

Enlarged, we have this:
Labeling of theta, R, D

Calculating the outer circle radius

I want to compute the radius from the origin to the outside edge.  I chose A to be the angle (180-theta)/2, and D is the hypotenuse of that triangle.  The height from the horizontal to the first edge point (what I call d0) is H, and H = D*sin(A).

I then split R into two parts: XDL and XDR, and XDR is H*sin(A).  Therefore
A = (180-theta)/2
H = D*sin(A)
XDR = D*cos(A)
XDL = R-XDR
d0 = (XDL, H)
( AKA,d0x = XDL, d0y = H)
 Q = sqrt(XDL*XDL + H*H)
Labeling of A, H, XDL, XDR, Q, and d0


Where D meets the next D

The next intersection that's interesting is the one where the second R intersects our first D.  Thought of another way, that's where one D meets the next D.  I call that point (x1,y1) on the drawing below.  That can be found a number of ways.  The simple solution is
x1 = R*cos(theta)
y1 = R*sin(theta)
Then, based on similar triangles, we can find the ratio of distances to see where it lands, percentage-wise, along the length of D.  So, Base is to D as y1 is to H
Base/D = y1/H
Base = D*y1/H

"Base" also is the base length of the isosceles triangle formed by theta, so it can be computed that way, too.

Labels for Base, RestD, (x1,y1), qhyp

Calculating the distance between outer edge points

The last point that's interesting is (d1x, d1y).  This I chose to do using a normal rotation matrix, since all the edge points rotate by theta, just as all the other points on the wheel.

The simple rotation matrix approach says
x' = x*cos(theta) - y*sin(theta)
y' = x*sin(theta) + y*cos(theta)
(Ref. https://en.wikipedia.org/wiki/Rotation_matrix)

Thus
d1x = d0x*cos(theta) - d0y*sin(theta)
d1y = d0y*sin(theta) + d0y*cos(theta)

And the outer edge wall length (for some reason I called this "qhyp") is
qhyp = sqrt((d1x-d0x)^2 + (d1y-d0y)^2)

In retrospect, now that I draw it, I realize that the computation of qhyp could be much easier, because it's the base of a larger isosceles triange, still with theta as the top angle, and common leg lengths of Q.  Half the triangle base is Q*cos(A), and therefore qhyp = 2*Q*cos(A).

Or, for those of you who like the more obscure functions, qhyp == 2Q / sec(A).



Having qhyp lets me make each of the 1..nSegments outer walls.  The original video shows an outer wall more like the floor of a crude bridge, where individual narrow planks are placed at the edges of a circle of radius Q.  For my design, instead, I'm intending to cut a slightly larger circle, and have tab holes that hold the nSegments outer walls in place.

Knowing all the computations, I can create a program that generates all the lines and points and angles, and have it draw a laser-cuttable pattern for me, just to show where all the walls would go.

The intent is to create a disc with tab holes to cut out, so each wall could be put in at the right points.  Then, the walls of some given wallHeight could be constructed with knowledge of D (the inner edge walls), and qhyp (the outer edge walls).  The tabs and tab hole lengths would be some fraction of each wall length, but the tab hole width would have to be variable, based on the thickness of the measured material being cut.

And yeah, I already did write the program to do this, and have some notes on SVG generation and laser cutting experimentation to share, but I'll cover those topics in a later post.