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.

Sunday, January 4, 2015

Chladni plate

Yet another project to start while others aren't finished!

I'm looking into what it takes to make a Chladni plate.  Toni posted something to FB with bouncing salt, and then Corey and I struck up a conversation considering building one.

Basics of a Chladni plate: back in Ye Olde days, a guy named Chladni messed around with harmonic vibrations of a metal plate, and saw that it made neat patterns.  In those days, he used a violin bow or similar, pulled across the edge of the plate at specific points.  Nowadays, people use electronic vibration generators or wave generators connected to a piece of sheet metal.

Various web sites are out there on instructables and the like.

The link here:
http://www.instructables.com/id/How-to-make-a-Chladi-plate-vibrating-membrane/
shows a way to hook up a speaker, connect it through a "cone" that traps the audio, and then put a membrane over the cone.  So for them, it's kind of like having a speaker connected to the air chamber of a drum, and the drum skin is where the particles bounce around.  That's not quite the same thing as having a plate atop a post, where the vibration energy is focused at one point.
but that's pretty complex, IMHO.  Basically, it it saying "kill a speaker, unwind its magnetic wire, and then wind it up again" which basically turns the speaker into a different magnetic coil.  I couldn't quite grok what the new electromagnet would be driving, though.  The pictures weren't that clear.
This one is more informative, but doesn't have great pictures.
but that's where the project hits at $250 cost.  Not in my budget!There are also some devices one can buy for a pretty penny.  The basis of the machine is the vibration generator, and those will run you $200 or more.  Then you can mount square or circular plates above them for $40 or $50 more.
That would go along with one of these, I think: a vibration generator:
http://www.djb.co.uk/ppm_vibgen.html
There are also devices that can be ordered from Pasco.

So off we go, exploring a DIY approach to this, and perhaps providing better documentation than what I've seen on other sites.

The DIY approach to this is to use an old speaker as the wave generator.  Question one then is: what is a speaker, and why can it work as the wave generator?  I found this link to be informative:
http://www.bcae1.com/speaker.htm

Here are the two speakers I have that could be victims for this project.  The first is a 6" coaxial speaker meant for use in a car stereo system.

This is the speaker with grille assembly:





Looking closer, you can see the tweeter is on a post that goes through the center hole of the woofer's cone.

The main signal wires connect through the woofer cone loosely, and the connection holes are sealed, allowing it to push air with little interference from the wires.  The wires end up connecting through a capacitor, which I assume is used to allow only the high frequency signals to hit the tweeter.



You'll find that you can push gently on the woofer cone, and it springs back.
Push down:
 Lift up:

This movement of the cone is caused by an electromagnet being attracted to or repelled by the speaker's circular magnet at the base.  It springs back into a resting position because of the "spider" which in this case is a webbing material connected to the base of the cone.  The spider is the brown/orange material seen here:

The voice coil and VC Former should be inside there, attached to the spider, and together they move up and down, pushing the cone.

The DIY Chladni plate pages say to cut away the cone, and at least one page says you can cut away the spider, though if you do, I don't quite see how the voice coil + VC Former would go back to a proper resting position.

After they take away the cone (and maybe spider), they attach something like a short tube or cap where the cone had been connected. But if you do that with this coaxial speaker, you'll run into tweeter.

Instead, let's look at another speaker.  This is from an M-Audio studio speaker system that I found in e-Waste.  It has its own amplifier, which I'm thinking I'll reuse.  There were two problems with the speaker set.  First, its tweeter dome was crushed in.  Second, its volume knob wasn't well constructed and caused an awful, loud scratchy sound as it would be adjusted.  (As it turns out it's a ganged A502 5kOhm potentiometer, so I can probably fix that.)  The picture here shows the volume knob and headphone output circuit removed.


After some disassembly, which included some nasty approaches to removing glued wires, it looks like this.  Word of warning for anyone messing around similarly: this has exposed wiring to its internal 115v transformer.  I'm being safe with this, only working on it unplugged.
The woofer on this one is a plain woofer with no center tweeter post.  (Audio pages will tell you that having separate speakers provides better audio fidelity.)

Here's a picture of the spider in this speaker

and here's a side-by-side comparison of the two speakers.  It's interesting that the M-Audio one has a deeper can, and they're both about the same when comparing the can diameters.



05-JAN-2015
I viewed this video last night:
https://www.youtube.com/watch?v=-Jvosadq2ao
It's a person creating a "vibration speaker".  Basically, he takes a coaxial speaker, turns it upside-down, and then removes the tweeter and puts the tweeter back on top (facing upward).  Then, he replaces the stock woofer cone with a post-and-flange assembly that allows the woofer's voice coil to convey the vibration energy to whatever's underneath.  He puts the whole thing atop a hollow box, which then serves as a cavity for capturing and reflecting the air pressure waves.

There are a several interesting parts about the video.  First, it's relevant.  In essence, he's doing the same thing as what we're trying to do here, connecting a voice coil to a post.

Second, it is interesting that you can remove the tweeter and mess with it, but for us it's not entirely relevant.  It's likely we will not use a coaxial speaker, instead using an old, blown component speaker (or two).

Third, the assembly process is interesting.  He constructs a plexiglass mount point for the rod and flange first, and joins that to the speaker's normal mount points.  He then adds the rod, and glues it down to the cone, which allows the inner part of the cone to act as a bowl where the glue hardens.  Only after the glue is hardened does he remove the cone.  I think it's arguable that that makes things easier, compared to attaching a cylinder to the voice coil assembly, and it's also arguable that it reduces the overall mass that the coil is trying to push.

Yet another similar link for a DIY "Bass Shaker" (which is different than the topper of a Fish Tales pinball machine) but if you watch this, the informative part starts after about 1 min 42 secs into the video.  Before that, it's just silly.
https://www.youtube.com/watch?v=m1GS0uIFVfE

I also love this youtube video both for linguistic reasons and for the high def animations:
https://www.youtube.com/watch?v=DIBDeC3G3_4


Thursday, October 9, 2014

Serial encoder / quadrature from an old printer

I've taken apart various printers to scavenge motors, but often have been intrigued by the serial encoder and quadrature mechanisms inside.  These are quite common in H-P printers, and I've found them in others, too.  Usually there's a disc-type encoder on the drum roller, and a plastic strip-type encoder that runs along the length of the printer head carriage.

I looked around various google DIY pages, and got ideas on how to figure out what's what, but none of them really took me step by step.

So here goes...

Step 1 (lots of effort, can't describe how to do this easily): remove outer casing of a printer so you're left with the basic drum roller carriage.  This one's easier to start with than the linear serial encoder strip one that runs along with the ink carriage.

Here's what you'll see:


If you were to look at that disc's edge under higher power, you'd see that it's actually made up of a bunch of really little lines.

There's a DC motor that controls the little gear at the bottom right.  That drives the belt, which drives another gear assembly at a slower rate, causing the disc with the serial encoder bands to turn.

The fun parts are the disc with the markings on it, and the thing that has 09852 and 9920 written on it.  That assembly has an LED on one side and two light sensors on the other.  As those little lines block or reveal the LED light, the light sensors can see what's happening.

Step 2: Remove the board.  Fortunately, it was one screw with a T8 head.  Try not to scratch up the disc as it's coming off.

T8 wrench head
Lefty loosey
Board is off now
Step 3: Take a look at the board

The board has that cool chip on it, but there's a white shield over the connections.  If you look closely, you'll see a little tab that suggests that the white piece was pressed on and then clicked into place.

So you can pry the U-shaped white part in the middle up, and then slide the whole thing over the tab to remove it.  I used a teeny flat head screwdriver for this, like one of those eyeglass repair kit ones.

And voila (grave accent over "a", do not say "viola"), you can see two wires going up.

Now here I was guessing which side of the chip was the LED and which had the sensors.  Visual inspection on the other side showed a couple of things.  First, the upper part (the one with the 09852/9920 written on it) is thicker.  Second, looking inside the slot, it had a circular opening, whereas the other side appeared flat.  So both those things suggested that the top was the light emitting side, and the lower side was the light-receiving side.

You might also barely notice that two of the board pins connect to the two, revealed upper bars.  I did a continuity check with a multimeter just to make sure I knew which ones connected.  From the perspective of the shot above, the pin closest to the letters "U1", and the middle pin two away from it, were the ones connecting upward.

Continuity check -- multimeter said "beeeeeeep" for this pin and the one two away from it.
Step 4.  Determine LED orientation

I continued on, assuming the two upper leads would connect through an LED.  As such, I could test the diode using my multimeter.  You can find many videos online that describe how to use a multimeter's diode setting to check to see the orientation and voltage drop across a diode.
Set to diode mode

Somewhere around here, I went astray and measured things incorrectly.  My multimeter, when connected "correctly" across the diode, shows a number briefly and then shows "1".  If there is no connection it shows "1" without blinking.  Otherwise, it shows the voltage drop.

I didn't get things right the first time, and thankfully didn't burn out the circuit when I got Vcc and Ground reversed.  Usually that's a Very Bad Idea.

Anyway, let's call the pin nearest the U1 marking 1, and then go 2, 3, and 4 from there.  For this sensor, connecting black to 1, and red to 3, I got that "blink" behavior.  No other combinations (tested across all pin pair combinations in both directions) yielded that.


Step 5.  Look at the opposite side for wiring

Here's what the board looks like when it's flipped upside down.  I was intrigued by the resistor and capacitor but couldn't really figure out what the resistor was for.


With this turned upside-down, the diode pin ordering is reversed, so think of them from top to bottom as 4,3,2,1.

So here in the blog I'm going to cheat and skip around how I messed up in figuring out what this thing was.  More on that later.  But instead of leaving a bad diagram in the blog, I'm supplying the correct diagram here.

 Here's what I eventually figured out. Break out some kind of drawing program (in my case Photoshop Elements), and trace it out and you get this:


It turns out that the resistor R1 on the PCB isn't in the circuit at all.  If I recall, that connected to wires that connected to another assembly at the back of the printer, and those might have connected through to a simple light blockage sensor (optosensor) or physical switch.  Basically, the board's resistor R1 joins up from Vcc to that other wire and probably a physical switch caused it to connect back to the wire I labeled "UNUSED", so it doesn't do anything for me.

At the same time, that meant the LED in the 09852/9920 chip didn't have any resistance protection, at least not from the resistor on the board.  Well, as it turns out based on what I read elsewhere, there's an internal resistor in the sensor itself.

It makes sense that GND and the voltage line are connected via the capacitor C1.  That typically is done to quell ripples in voltage.

That leaves the other two lines coming back from the 09852/9920 chip, and they're directly wired to the original wire bundle.  So I'm assuming those are Sense A and B, which will let me know what's going high and low as the disc turns.

Step 6.  Initial output testing.

I initially wired up 3V and 5V through a 220 ohm resistor to the LED.  As it turns out I got that backwards in early testing, because I didn't know how to read my multimeter.  I thought a constant reading was telling me voltage drop across and indicating that I had proper direction, but that's not how my multimeter works.

Since I got those backwards, there was no way the LED was going to light.  Furthermore, even if I had gotten the wires in the right order, I might have had too much resistance for the circuit to do anything, because I didn't know there was an internal resistor.

Step 7.  Despair

Because I got that all wrong, I gave up for a bit.  I then returned to web searches to see what they might yield, and found this:


http://reprap.org/wiki/Optical_encoders_01
This was my "Aha!" moment.

There were two big clues on that page.  First, they went into some detail explaining how to do diode-setting measurements with my multimeter to try to figure out power and ground, which entailed measuring in diode mode across all pin pairs in both directions, and making a chart.  But more importantly, they said that almost all these kinds of sensor chips run at 5V, and the ones with only 4 pins have a built-in resistor for the LED.

The reprap site recommends fully extracting the chip from its board, and gives suggestions on how to do that.  For my purposes, I wanted to retain the existing board.  Otherwise, it'd be too hard to re-mount and get lined up again.  Through inspection of the board, I'd already determined that I'd disconnected everything else so that was good enough.

So... I re-measured the pins for the chip I have, and eventually determined that the pin closest to the U1 marking is ground, then sense A, then Vcc 5v, then sense B.

Once I had determined the proper direction, I put 5v across the LED and inspected the sensor.  Sure enough, a visible red light could be seen inside!  I wasn't sure if the light would be at a visible wavelength or IR.
I then put the board back where it came from, connected up the multimeter to ground and one of the sense pins, and *slowly* rotated the DC motor.  Sure enough, the output from the sense pin would start wandering around, roughly between 0.5V and 4.5V.  And the output on the other sense pin wasn't the same all the time, which is to be expected.

-------------

Next step: I don't have an oscilloscope handy so I can't tell how clean the voltage signals are for the signal lines.  I'm just going to assume they look ok since I'm just messing around.

I originally got into this project because I'd seen ways in which you could build the remainder of the circuit to figure out direction and count ticks electronically.  There are some diagrams out there that use flip-flops in sequence to buffer up the results, and there are ICs pre-built.   I'm looking at the US Digital LFLS7184-S as examples.  (I also wonder if one of these chips is built onto the printer already somewhere.)  I don't want the Arduino to have to capture interrupts to sum up the number of ticks that have gone by.  I don't trust the clock frequency of the Arduino to measure things accurately.  It'd be much better if that were done electronically, and then the Arduino can dip it and get a summary count.

----
Here are some more pretty pictures.

Disc says that it's 1800 count (I think CT means count) and 200 lines per inch

You can see all the little lines here.
-------------------------
I took apart the carriage board and unsoldered the sensor from it.  I accidentally broke the plastic covering that they use to hold the sensor in place, so if I ever use it again, I'll have to find some way to make sure it stays down.  I think part of the job of the gray covering is to protect wires, but its more important job is to make sure the sensor doesn't bend upward from the PCB.

The carriage board was a multilayer job, so it was hard to tell where the leads were going, and really impossible to know if I could disconnect the sensor from existing circuitry by just cutting leads.  So instead, I had to remove it.

Removal started with desoldering a number of large capacitors that were in the way.  They prevented me from lifting the gray cover off of the sensor, and I wasn't sure if I could just desolder with the plastic in place (for fear of melting the plastic).  In desoldering, I found that it really worked well to add some solder to the existing points first, then solder-sucker it, then clean up with wick.  It came out quite easily after that point.

The pin readings on the carriage sensor were very similar to those on the rotary disc sensor, so I just wired it up the same way and slid the strip through to see if I could get readings from the sense pins, and I could!

End result: I have a rotary sensor and a linear sensor, and more printers that I can mess with beyond that.

So now how do I use it?

I'm tempted to make the linear codestrip and sensor act as some kind of musical instrument, like an electronic slide whistle.  There's gotta be a better use than that, though.  I've seen some YouTube videos that show how you can make an inverted pendulum, too.  But now that I've seen those videos, I know that that's been done.

Why did I do this originally?  To detect when step motors don't actually complete a step.  Using one of these encoders could give me the feedback I want to make sure a step really happened.

Next step remains: build up the rest of the circuitry to actually count the sense A and B signals and accumulate them.

Friday, November 29, 2013

Salvaged H-P printer LCD panel (CM160240) on Arduino using Custom Characters

This is a black & white LCD panel that came out of an H-P printer.

I didn't want to mess with it until I knew that the 44780 LCD would work.

It was mounted to a printed circuit board that had momentary contact switches at various points below the buttons.  On one end, there was a thin, flat cable that had something like 26 pins going out of it.  But the cable that came out to the LCD had only 14 lines.
LCD panel with cable
Close-up view of cable
Cable with 0.1-inch proto board for scale
 Since the cable was at 1mm separation, it was too fine for my soldering ability.  That meant that for me to mess around with the LCD, I'd need some way to break out the cable pins so that I'd get back to 0.1" separation.

I took some digging, searching on the wrong term ("ribbon cable") but I eventually found that the cable is referred to as an FPC (flexible printed circuit) or FFC (flat flex cable / flat flexible cable).

It turned out that there was a nice set of breakout boards available at Newhaven (google "Newhaven ffc adapter"), but they were around $10 each, not including shipping.

Instead, it turned out that Jameco had a little piece that fit a 14-pin, 1mm FFC, for only $0.39 each:
http://www.jameco.com/webapp/wcs/stores/servlet/Product_10001_10001_2144876_-1
The datasheet is at http://www.jameco.com/Jameco/Products/ProdDS/2144876.pdf

I got a couple of those -- always get a backup in case the first one fails!  The way it's set up, it has output pins that are in two rows, seven pins each separated at 2mm, and the pins are offset.  The rows themselves are also 2mm apart.  Since I didn't have any means (yet) to build my own PCB and my own breakout board, nor a way to drill holes at 2mm separation, I bent the rows apart to get more work room, and soldered wires to the pins.  Then, I used heatshrink tubing (from Halted, www.halted.com) for insulation.

The top of the breakout board looks like this:

I filed the holes a little larger so that the wires could be pulled through.  Then, I cut the wires to length and soldered them to push-in headers.  The end result was that all the odd-numbered wires ended up on one side, and the even-numbered ones were on the other side.  The back side of the board is here.  The outermost pins of the headers were soldered just for stability.

Of course with my soldering (non-)skills, I had to check all solder joints for proper connectivity, and make sure I didn't accidentally create any solder bridges.

Then I connected the FFC to it, just to double-check and make sure I knew which pins were which.

But which wires were which?

When I first looked at the LCD on its mount, it wasn't clear what chip was behind it, nor which pins would do what.

My first hint was that it had 14 pins.  Thus I hoped it would obey the same rules as the 44780.

The second hint was a closer inspection of the PCB that held the contact switches.  This is a backlit view of the board with pins in the order 1..14 from left to right.
The thing that stood out was that pin 3 had a thicker trace, and I took that to mean it represented Ground.

The flipside of the board is shown here.  It shows that pin 2 is connected via a capacitor (labeled C1) back to pin 3 (ground), suggesting pin 2 was power.  When I put 5V to pin 2 and ground to pin 3, the board showed a row of black squares.


But still, that didn't tell me anything else about the rest of the LCD pins.  The enable, reset, read-write, contract, and data pins could be in any combination.

I removed the LCD from its plastic mounting to get a closer look.  This took some *very* careful prying.  In retrospect, I might have done well to have applied some heat to loosen up the glue that was keeping it stuck on.  One time, when I was removing the panel in this way, I generated enough static with the plastic housing that it cause a few images to light up on the display, and I was afraid I'd fried it.  So be careful.  I'm not sure if heat is even a good idea, as that might loosen the glue, but damage the panel.


I gently removed the inspection sticker that was on top of the PX16214 identifier, and once outside the mounting, I could also see the DATA IMAGE vendor name.  (Earlier, only the word "IMAGE" was visible.)  Note also on the image above that there are three black bars.  Each of those, I think, is simply a piece of standoff foam with adhesive on it, and that's what kept the LCD panel stuck onto the PCB.

That allowed me to google "data image lcd px16214 p184 s-11" which gave me a single, solitary hit:

LCD mit 14 Pins, aber scheinbar keinem HD44780-kompatiblen ...

www.mikrocontroller.net/topic/187292
Thankfully, I'd gotten a bit of German in high school, and that in combination with knowing how to look for some technical terms let me know that I was on the right path.  Google translate then to help.

The page pointed to this first:
http://www.tstonramp.com/~pddwebacc/cdm/CDM-16214.pdf
and the pins for that are the same as for the 44780, but in reverse order.

However, it still didn't agree with my expectation that pin 3 was ground, and pin 2 was Vcc.

Later, though, in the same mikrocontroller.net web page, it referred to
http://www.optologic.ch/data/CHARACTER_DISPLAYS/PDF/CM160240.PDF

On that page, it showed the pin-shifted positioning that I was after:
pin 3 = Vss (0V)
pin 2 = Vdd (+5V)
pin 1 = Vo (LCD Drive Voltage)
and then it loops around to
pin 14 = RS
pin 13 = RW
pin 12 = E
pins 11..4 = DB0..DB7, respectively

I changed my 44780 sketch to initialize with a 16x2 display, and wired everything together, and it worked -- mostly.  For some reason, doing

lcd.setCursor(0,0);
lcd.print("tankdemo");

would only render the "demo" part to the screen.

I don't know why, but I had to offset all setCursor commands by adding 4 in order for things to line up properly.

The other thing I noticed is that there is no separating pixel row between lines 0 and 1 on the screen, but there still is a dead pixel separating each column.

The end result wiring is a bit of a spaghetti mess.



After I got all that together, I modified the code to allow for some variation to the message displayed on line 0, and messed around with the tank image a bit since this black & white LCD would erase pixels much faster than the 44780.

Here's the resulting code.
#include <LiquidCrystal.h>

// According to CM160240.html
// The pins on the salvaged HP printer's 16x2 LCD display might be
// 1 V0
// 2 Vdd +5v
// 3 Vcc GND
// 4..11 are DB7..DB0, respectively
// 12 EN (H, HL Enable signal)
// 13 RW (H read, L write)
// 14 RS (H data, L command)

// The blue 44780 uses
// 1 = gnd
// 2 = Vcc
// 3 = pot 10k-20k for contrast
// 4 = RS
// 5 = RW
// 6 = EN
// 11 = D4
// 12 = D5
// 13 = D6
// 14 = D7
// Ref. http://www.hacktronics.com/Tutorials/arduino-character-lcd-tutorial.html
// and HD44780 wiring pages

// and I'd used
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
  // RS, EN, DB4, DB5, DB6, DB7
 
// so... I need to wire up pins 14 RS, 12 EN, 7 DB4,6 DB5,5 DB6,4 DB7
// and wire RW to ground
// and consider using 10-20k for contrast on pin 1 (optional?)
// and set 2 to 5v
// and set 3 to 0v
// so ard7 = bd14
//    ard8 = bd12
//    ard9 = bd7
//    ard10 = bd6
//    ard11 = bd5
//    ard12 = bd4
// gnd = bd3
// vcc = bd2
// gnd = RW = bd13


// Board
// 1 = gnd
// 2 = Vcc
// 3 = pot 10k-20k for contrast
// 4 = RS
// 5 = RW
// 6 = EN
// 11 = D4
// 12 = D5
// 13 = D6
// 14 = D7
// Ref. http://www.hacktronics.com/Tutorials/arduino-character-lcd-tutorial.html
// and HD44780 wiring pages

// RW has to be wired low to write, else it remains in "read" mode

byte sprite0[8];
byte sprite1[8];
byte sprite2[8];
byte sprite3[8];

#define XOFFSET 4
#define LCD_CHAR_WIDTH 16
void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(LCD_CHAR_WIDTH, 2);
  lcd.setCursor(XOFFSET,1);
  for (int i=0; i<LCD_CHAR_WIDTH; i++) lcd.write('@');
  memset(sprite0,7,8);
  memset(sprite1,7,8);
  memset(sprite2,7,8);
  memset(sprite3,7,8);
  lcd.setCursor(XOFFSET,1);
//  Serial.begin(9600);
}

// Need eight 32-bit quantities that I can use for shifting bits around.
// The original tank image is in these values.

long tankImg[] = {
  ((long)B000000 << 10) | ((long) B000000 << 5) | B000000 // antenna tip zeroed on HP LCD
 ,((long)B010011 << 10) | ((long) B011110 << 5) | B000000 // turret top
 ,((long)B011111 << 10) | ((long) B011111 << 5) | B011110 // turret mid with barrel
 ,((long)B000111 << 10) | ((long) B011110 << 5) | B000000 // turret base
 ,((long)B001111 << 10) | ((long) B011111 << 5) | B010000 // tread top
 ,((long)B010000 << 10) | ((long) B000000 << 5) | B001000
 ,((long)B010000 << 10) | ((long) B000000 << 5) | B001000
 ,((long)B001111 << 10) | ((long) B011111 << 5) | B010000 // tread bottom, 24 pixels total in tread
};

// tankx is the bitwise position across the screen.
// tankcharx is the character-wise position, thus tankx / 5.
// It can be negative.
// At tankx zero, the tank is on the left of the screen
// so tankImg bytes are broken into four custom chars
// the fourth of which being blank bits
// At tankx one, the tank bits shift a bit to the right
// and if I'm clever, the treads are computed so they "rotate"
// And so on
// Because there are five bits horizontally per custom char
// and the tank treads go every other, I can repeat the original
// tank treads starting at even char positions

#define RESTART_X_POS -15

int tankx = RESTART_X_POS;
int tankcharx;
int tankchary = 1;
int treadx = 0;

#define BITS_PER_CHAR 5

void writeAt(int x, int y, byte b)
{
  if (x >= 0 && x < LCD_CHAR_WIDTH) {
    lcd.setCursor(XOFFSET+x,y);
    lcd.write(b);
  }
}

int msgID = 0;
char *msgs[] = {
   "Tank demo!"
  ,"H-P printer LCD"
  ,"CM160240"
  ,"Thanks to the"
  ,"guys in Germany"
  ,"who wrote up the"
  ,"pin assignments!"
//  1234567890123456
};
#define NUM_MSGS 7
long lastMsgTime = 0;

void loop() {
  if (millis() - lastMsgTime > 2000) {
    lastMsgTime = millis();
    int j;
   
    lcd.setCursor(XOFFSET,0);
    int blanks = (LCD_CHAR_WIDTH - strlen(msgs[msgID]) )  / 2;
    for (j=0; j<blanks; j++) lcd.write(' ');
    lcd.print(msgs[msgID]);
    for (   ; j < LCD_CHAR_WIDTH; j++) {
      lcd.write(' ');
    }
   
    msgID++;
    if (msgID >= NUM_MSGS) {
      msgID = 0;
    }
  }
 
  tankcharx = tankx / BITS_PER_CHAR;
//  Serial.print("tankx = ");
//  Serial.print(tankx);
//  Serial.print("  tankcharx = ");
//  Serial.println(tankcharx);
 
  // Initial rendition, no rotation of treads
  if ((tankx % BITS_PER_CHAR) == 0) {
    // Full shift is on, need to draw a blank where the tank last was
    writeAt(tankcharx-1, tankchary, ' ');
    // Draw the tank's custom characters
    writeAt(tankcharx,   tankchary, 0);
    writeAt(tankcharx+1, tankchary, 1);
    writeAt(tankcharx+2, tankchary, 2);
    writeAt(tankcharx+3, tankchary, 3);
  }
 
  // Compute the bits of the individual custom chars
  int shiftbits = (tankx % BITS_PER_CHAR);
//  Serial.print("shiftbits = ");
//  Serial.println(shiftbits);
  if (shiftbits < 0) { shiftbits += BITS_PER_CHAR; }
  for (int y=0 ; y<8; y++)
  {
    long lval = tankImg[y];
    switch (treadx) {
      case 0:
        switch (y) {
          case 4:
            lval ^= 0x2cb0; break;
          case 7:
            lval ^= 0x2490; break;
        }
        break;
      case 1:
        switch (y) {
          case 4:
            lval ^= 0x1240; break;
//            lval ^= 0x36d0; break; // This setting has fewer pixels on on top
          case 5:
            lval ^= 0x0008; break;
          case 6:
            lval ^= 0x4000; break;
          case 7:
            lval ^= 0x0920; break;
        }
        break;
      case 2:
        switch (y) {
          case 4:
            lval ^= 0x0920; break;
//            lval ^= 0x1b60; break; // This setting has fewer pixels on on top
          case 5:
            lval ^= 0x4000; break;
          case 6:
            lval ^= 0x0008; break;
          case 7:
            lval ^= 0x1240; break;
        }
        break;
    }
   
    long lshifted = lval << (BITS_PER_CHAR-shiftbits);
    sprite0[y] = (byte)((lshifted >> (3*BITS_PER_CHAR)) & B011111);
    sprite1[y] = (byte)((lshifted >> (2*BITS_PER_CHAR)) & B011111);
    sprite2[y] = (byte)((lshifted >> (1*BITS_PER_CHAR)) & B011111);
    sprite3[y] = (byte)((lshifted >> (0*BITS_PER_CHAR)) & B011111);
  } // end computation of the four custom characters' eight lines
 
  // Update the custom chars.  This causes them to be updated
  // immediately on the LCD screen.  I haven't tried rendering
  // in reverse order to see if that makes for any better or worse
  // animation effect.
  lcd.createChar(0, sprite0);
  lcd.createChar(1, sprite1);
  lcd.createChar(2, sprite2);
  lcd.createChar(3, sprite3);
 
  // Move the tank to the next position and reset to the left off screen
  // if it goes far enough off to the right.  Also keep the "tread"
  // offset ticking.
  ++tankx;
  if (tankx >= 5*LCD_CHAR_WIDTH+5) { tankx = RESTART_X_POS; }
 
  ++treadx;
  if (treadx == 3) { treadx = 0; }
 
  // A short delay before we move the tank again.
  // Slower delay = less blur, given the 44780 I have
  // is slow to erase the lit-up pixels.  I like delay(100) milliseconds.
  delay(100);
}



And hopefully blogspot will allow me to post a video here... cross yer fingers...