Saturday, October 18, 2014

Android/IOIO 3D Laser Scanner



Once you have a 3D printer, it's a logical jump to start thinking about what you can repair with it. I had read articles on simple DIY laser scanners using webcams and a line laser, and decided it would be a fun project to build one and see how well they work.

Rather than using a webcam, I opted to use an Android phone (Galaxy Nexus) that I had as a spare, and an IOIO board that I already owned. I reasoned that the phones had high quality cameras, and that it should allow for higher resolution scanning than a cheap camera. I wrote a simple program on the phone to take the photos and drive a stepper motor to turn a turntable.

I printed this simple printable turntable design and wired up a EasyDriver stepper driver to the recommended stepper motor, wired for .45 degree steps. I found that things tended to slip on the slick turntable surface, so I found a grippy rubbery material similar to shelf lining in the kitchen section.

I placed a line laser on a printed adjustable mount that I designed  and set it at 45 degrees to the camera angle. The line laser from Adafruit makes a nice line.  A phone mount modified from an existing GameClip for the Nexus served as an easy mount for the phone.


I wrote a simple Android app based on the HelloIOIO example application that takes a picture, advances the stepper motor, and takes another. The saved images are processed  by a Python script that tries to identify the center of the laser line, which is surprisingly wide. Treating the center of rotation (the motor shaft) as the origin, it used trigonometry to figure out where the beam as intersected the part and then rotates the resulting points into their position based on how much the turntable has been turned.

This guy has an outstanding explanation of how the math works. I've put the Python script at the end of the blog post in case you are developing something similar.

The resulting point cloud in x,y,z format is loaded into Meshlab. The point cloud is turned into a part with a surface using the method described here.

So. How well does it work? Can I scan parts and then easily run them off on my printer?

It depends entirely on the shape of the object. Here's some examples.



Where the laser line strikes the part, it makes a nice smooth mesh. However, for most parts that are interesting, one area of the part will often shadow another, and detail in that area will be lost. Take a look at the area under the chin of the knight for one example. You also get shadowed areas as the part rotates when one part of the target sticks out a bit. See how the side of the face on the right side of the image below does not show the beam? That's a big chunk of detail that is lost. The mesh gets ugly there, and it would require work in a program like Blender to fix.


I did experiment with two lasers, one of each side of the part, to try to reduce that. I think this is a good approach, but it requires a significantly more precise rig than I made. When I tried to align the resulting two point clouds, I found that the two meshes were slightly different sizes. It appears to require very precise alignment and a stiff setup to keep it all straight if you are doing that. I scrapped this approach - maybe for a later build, but it would be a total redesign.


I also found problems with scanning parts that are glossy or otherwise reflective. The laser beam hits and scatters, rather than making a nice tight beam. Detail in that area is lost, sometimes resulting in the loss of entire faces. I tried scanning a part from a photocopier, and much of it was lost to this.


Finally, parts that were more square than oblong tended not to be illuminated by the beam, and detail was lost. An extreme example is shown in this scan of a wood block, where the entire top was lost.






These issues can be somewhat improved by changing laser angle, laser height, camera distance, etc.  However, it usually involves a tradeoff - you can pick one area to be well illuminated, but at the expense of another. They do work, and they are a very interesting project to play with. If you want to scan in models to do digital sculpting in Blender, as a starting point, they would work well. If the goal is to scan parts for replicating with a minimum of manipulation of the resulting model, it appears to require a more sophisticated approach. Dual beams would help, but you would still have shadowing issues. I think that to really do it right would require scanning the laser up and down while also rotating the part, which significantly complicates the mechanism. 


I enjoyed building it, but the limitations inherent in a single fixed beam are such that most anything I would scan would require extensive work in Blender to to make usable. I may come back to laser scanning at some point, but for now I think I'll just work on improving my skills in CAD. 

If you are going to build a scanner like this, the following things help a lot:

- level the platform you are building on
- level the turntable to avoid "wobbles" in the reconstructed part. I did this by shimming the stepper motor in the turntable mount
- make sure the line laser is at 90 degrees to the turntable surface

A system like David LaserScanner that allows you to scan the beam over the whole surface probably helps a great deal. I may try that at some point, but at this point other projects are calling.

Code for the reconstruction script follows. There is a lot of room for improvement.


#!C:\WinPython-64bit-2.7.5.3\python-2.7.5.amd64\python

from Tkinter import *
from PIL import Image
import math

thresholdBrightness = 600;
centerLine = 1368;
leftBound = 362
rightBound = 2287
upperBound = 996
lowerBound = 1368

def findBrightestToRight(im, y):
 rowBrightestPosition = 0
 rowBrightestValue = 0
 global centerLine
 leftEdge = -1
 rightEdge = -1
 pix = im.load()


 if y > lowerBound:
  return -1

 if y < upperBound:
  return -1

 
 for x in range(centerLine,rightBound,2):
  pixel = pix[x,y] #get rgb value of current pixel
  pixelBrightness = pixel[0] + pixel[1] + pixel[2]
  if pixelBrightness > rowBrightestValue:
   rowBrightestValue = pixelBrightness
   rowBrightestPosition = x


 if rowBrightestValue > thresholdBrightness:
  return rowBrightestPosition
 else:
  return -1

#todo: handle return of -1 properly

print("Starting...")


maxSteps = 0;
yPixelsPerMM = 1.00
xPixelsPerMM = 1.00
thetaDegrees = 27.0 #angle formed by laser line to camera
thetaRadians = math.radians(thetaDegrees)
rotationAngleDegrees = 0;
rotationAngleRadians = 0;
degreesPerStep = .45
result = ""

numberOfFiles = 800;


thetaRadians = math.radians(thetaDegrees)

#make blank files
f = open('scannerOutput1.asc', 'w')
f.close()


for currentFile in range(0,numberOfFiles):
 print "Processing file " + str(currentFile) 
 filename = str(currentFile) + ".jpg"
 im = Image.open(filename) 
 imageWidth = im.size[0]
 imageHeight = im.size[1]
  
 rotationAngleRadians = math.radians(rotationAngleDegrees)
 print rotationAngleDegrees
 result1 = ""
 
 
 for y in range(0,imageHeight):
  
  rowBrightestPosition = findBrightestToRight(im, y)
  #print y
  ##invert y
  yPosition = ((imageHeight * 1.00) - y) * yPixelsPerMM;   #this will need to be scaled
  
  xPosition = ((rowBrightestPosition - centerLine)/(math.sin(thetaRadians))) * xPixelsPerMM; 
  zPosition = 0.00; 
 
  ##we need to rotate the x,y,0 position to it's final position based on stepper motor angle
  ##rotate about y axis to proper position according to current part rotation angle
  rotationAngleRadians = math.radians(rotationAngleDegrees)
  zRotated = (zPosition * math.cos(rotationAngleRadians)) - (xPosition * math.sin(rotationAngleRadians));
  xRotated = (zPosition * math.sin(rotationAngleRadians)) + (xPosition * math.cos(rotationAngleRadians));
  yRotated = yPosition;
 
  if rowBrightestPosition != -1:
   result1 =result1 + str(xRotated) + "," + str(yRotated) + "," + str(zRotated) + "\r\n";

 rotationAngleDegrees = rotationAngleDegrees + degreesPerStep
 f = open('scannerOutput1.asc', 'a')
 f.write(result1)
 f.close()

 
print "Done."

Thursday, July 31, 2014

Failed attempts to get HC-SR04 sonar module working underwater



Over the last few months I've been looking at building a sonar sensor for underwater robotics. I've been mostly focused on learning some basic signal processing to detect the echos. As documented in a previous post, I've gotten it working in air on a PC using the sound card, and have also recently gotten a TI-Launchpad based version working in air. (More on that later).

However, since the HC-SR04 is so inexpensive and works so well in the air, I could not resist trying to make it work in water. It would be cheaper, easier, and use less power if I could make it work.



Previous reading on making hydrophones indicated that simply dunking a microphone in a film canister full of mineral oil would effectively couple it to the water around it, and let you hear the sounds in the water. That's what I intend to do with the Launchpad based digital sonar. Since mineral oil is non-conductive, I figured it was worth a try to seal a HC-SR04 in a container of mineral oil and see what it did.

The HC-SR04 emits a short pulse of ultrasound and then waits for the first echo. It then outputs a pulse with a length corresponding to the time it took to hear it. From that, you can calculate the distance to the target.

This has some advantages and disadvantages. It's really easy to use and process the data. However, you only get one data point - you only hear one echo. The digital sonar approach gives you all the echoes back, not just one, with relative intensity information, like this:



I figured that the HC-SR04 must be waiting a small amount of time after sending the initial pulse to prevent it from triggering on the ringing of the sending transducer. If I could get the pulse out of the pill bottle before that window, it should work.

I first got the HC-SR04 working in air with a Stellaris Launchpad. I then sealed up the HC-SR04 in a medicine container full of mineral oil.






Results:
The module worked in the oil, but didn't return data that I could correlate in any useful way with distance to target.

With the sensor out of the water, it repeatedly returned a very small value (100 or so).

With the sensor in the water, it alternated between sending an extremely small value (~50) and a very large one (600,000+). It did this pretty much regardless of what it was pointed at, and quite regularly. 50, 600000, 50, 600000, 50..... I'm not sure what was happening, exactly.

I've decided to give up on this approach and return to the Stellaris Launchpad-based digital signal processing approach. That will give me a lot more information since I can look at all the echoes graphically. Bummer. It would have been really cool if it worked.

Tuesday, May 13, 2014

Adding a Heated Print Bed to the Printrbot Simple (Plywood Bed Edition)



After struggling with warping on larger prints, I decided to try adding a heated bed to my Simple. I am delighted with the results. It has completely eliminated the warping problem and allows me to print at full speed.

Here's what I used. As usual, you use information from the internet at your own risk, and if you are not comfortable with things like voltage and current ratings, get help from someone who is. Electricity at the current levels involved here are a modest fire hazard if adequate safeguards are not in place.

1) MakerFarm 4.5x6" Heated Bed  with Prewired Thermistor



I could have individually bought the high temp wire and sleeving and assembled it, but the price difference was very small.

2)  3/16"x 4 x 5 Borosilicate Glass from McMaster Carr

Borosilicate glass is less likely to break when warmed and cooled. I figured the thicker stuff would be less likely to break when I pried things off the bed.

3) A solid state relay to control the bed. The Printrboard has an output that can directly drive a heated bed this size, but there are reports that the Molex connector isn't up to the task and can overheat. Additionally, a short on the bed could damage the Printrboard. The Printrboard is an expensive piece of hardware, so I chose to isolate it from the bed.

Update: I added a heat sink to the SSR. It got fairly hot during long prints, even running at 50% of it's rated current capacity. The heat sink helped a great deal.



In this configuration, the relay is the only load driven by the PrintrBoard's heat bed output. The relay has to be driven by the 12V output, and be able to switch enough DC current and voltage to run the bed with a margin of safety.  Also be aware that the control outputs on the solid state relay have a polarity that must be observed. There is good information on wiring up the SSR here. Be aware that unlike typical magnetic relays, SSRs have a polarity on both the driven side and the load side.

4) A large 12V power supply I already own. The power supply that comes with the Simple is not sized to run a heated bed. Since I was using a relay it was easy to power the bed from another supply. Some people are using a modified ATX computer supply, or 12V supplies are available in a variety of capacities. MakerFarm says the bed alone can draw up to 8 amps.

5) 4 medium sized binder paper clips to hold the heated bed and glass to the plywood bed.

6) Permatex Ultra Copper high temperature silicone sealant to secure the thermistor to the heat bed.

An interesting note on the relay: I first chose a mechanical relay. It turns out that the Printrboard's firmware is set up to run a fast PID loop  which is well suited to run semiconductors. It causes a mechanical relay to chatter several times per second. Changing it to a mode more suitable for a mechanical relay requires recompiling and flashing the Printrboard firmware. That's a lot of work, and carries a bit of risk, so I chose to buy the solid state relay.

The first part of the process was to secure the thermistor to the underside of the heated bed. I placed the thermistor where I wanted it, taped the wires to hold it in place, and then put a blob of Permatex Ultra Copper over it to hold it down. I was careful not to put any Permatex between the thermistor and bed.



Next, I marked the plywood bed of my printer for cutouts so that the heated bed would fit flush on it. That required cutouts for the bed wires and the thermistor. The circular cutout for the thermistor was done with a Forstner bit. The small cutouts for the wires was done with a hobby knife.


Once I was able to test fit the bed and it sat flat, I placed the glass over it and secured it with the office binder clips. I had to remove the steel arms that you pinch to open the jaws of the clips.

I then found that the full width clips limited my print area a bit - the head would smack one when it went home. I used a bench grinder to cut them in half.



I then reset the Z home level - this is critical, since the hot end will crash into the glass if you don't. You do lose a bit of Z printing height, the thickness of the glass + PCB. 

I got good results heating the bed to 55C, with blue tape on the glass. Prints come out perfectly flat and are hard to get off the bed. A friend tells me hairspray works well on the heated glass on his Rostock Max and the parts come off the bed more easily, so I intend to try that soon.


I have been extremely pleased with this so far - it resolved my warping issue entirely, allows me to print at normal speeds, and in theory, I should be able to print ABS now. Total cost was around $65, since I had the power supply already.

Tuesday, April 8, 2014

Troubleshooting And Fixing Extruder Jams On The Printrbot SImple



I am in the process of printing off parts for a friend's Kossel. The lower frame mounts are the largest parts, and are near the limits of what a Simple can print. It proved rather challenging to print them reliably and without warping.

My printer lives in a basement that stays at about 58 degrees F. I am using Zen Toolworks PLA which seems to work best at around 210 C. To keep warps to a minimum I print inside a plastic enclosure, which raises the temps about 15 degrees, onto blue tape cleaned with alcohol, and I have to print SLOW. 10 mm per second is the travel rate for the perimeters and infill. Even with that, I have to print on a 8 layer raft to get large parts to print without appreciable curling at the edges.

God, I want a heated print bed. But that will be the subject of another post...

So anyway. With these settings, the lower vertex of a Kossel takes 11 hours to print. I was fine with that - I'm in no real hurry and want the best print I can make. However, printing that long introduces it's own issues. I experienced consistent filament stoppages at about 1.5-2 hours, after which the printer would continue to go through the motions and leave nothing behind.

So I tried the obvious stuff. I cleaned and adjusted the extruder. I levelled the bed. Twice. I tore down the extruder and cleaned up the internal edges to reduce friction. Still no go. Jammed at about the same point.

I then read about extruder motor temperature - that a hot motor can transfer enough heat to the filament to soften it before it goes into the extruder. My motor was indeed running hot to the touch. I dialed back the current on the Printrboard until it was just warm to the touch and wasn't skipping. I excitedly started a print and went to bed.

I woke up to another filament jam. There was some swearing, and a bunch of wasted plastic.

What finally fixed it was removing the 40 mm fan from it's normal place blowing on the extruder and tacking it with CA glue to the side of the extruder, blowing into the chamber that the filament passes through on it's way to the hot end. After all, I was not using the fan anyway, since my layers were so slow.

I turned on the fan 100% full blast in software, and started the print in the middle of the day. Five hours in, the extruder motor was cool to the touch, below body temperature, and no jams. I have since completed two back to back 11 hour prints. It's fixed.

If you have a Printrbot Simple that is regularly jamming the filament, I encourage you to put a cooling fan on the extruder. The difference was immediate and remarkable. If your extruder motor even feels a little warm, it can start to soften PLA on long prints.

After the Kossel parts are done, I intend to make this mount for a more dignified fix:

40mm Diameter Fan mount for Printrbot siple with a wooden extruder



Saturday, March 15, 2014

Reducing Warped Prints With The Printrbot Simple


Update: I eliminated the warping issue by installing a heated bed. Details here.

I was recently pondering extending the X axis on my Simple, using the extensible X axis brackets. I decided to try printing a small, simple project enclosure first, since I had really only printed fairly tall things with small bases. The only previous print I had tried that was fairly wide was an 808 camera mount for a friend's drone and it had warped badly. I had been able to straighten it by softening it under some really hot water, but I wanted to understand how big a problem it was.



I printed a box, and it came out looking like this. Ouch. Off to do some research.

Warping is caused by uneven cooling of the part. Objects longer in one direction than the other tend to do it more, and it's worse as you add layers. ABS apparently does it a whole lot more than the PLA my Simple uses, but I wanted to figure out how to fix it. A very good Makerbot blog post describes some common solutions, and variations of them worked for me.

I print in my unheated basement, which runs a pretty constant 58 degrees F. I think this contributes greatly to the problem.

The Printrbot Simple is a very cool piece of machinery, but you do sacrifice some features to have a lower cost. One of the biggest ones is a heated print bed, which most people indicate solve the problem completely in PLA and is necessary in ABS. There is not yet a kit for the Printrbot Simple to add one.

Here's what worked well for me:

1) Clean your blue tape on the bed with rubbing alcohol after you apply it, and then don't touch it. This removes wax and oils that your skin leaves behind that prevent sticking.

2) Turn on "Brim" in Slic3r, maybe 5mm around. This increases the surface area adhering your part to the bed, reducing the odds it will curl off the bed.

These two things alone helped a lot, but I still had a small amount of curling.

3) Want it to really stick? Tell Slic3r to print a "raft" of perhaps 5-8 layers. This works very well but requires you to cut or sand the raft off your part. The raft is sacrificial support material that warps instead of your part. This worked, but would be a hassle, so I kept tinkering. Here's what the raft material looked like:



But hey, it's a lot flatter. I'll keep it in mind for parts I can't print flat any other way. A lot of guys on the forums sneer at rafts, saying the are obsolete, no one uses them, they are old school. Those guys have printed heat beds. My Simple does not. So if I need to print a raft occasionally, so be it.

4) Make a "slow" saved settings for Slic3r that you use when you want to minimize warps. I set it to print at 10 mm/sec, 1/3 the speed the Printrbot usually prints at. Sure, it takes a while. I value print quality over speed.

5) If your printer is in a chilly environment, you might consider enclosing it. I found that simply parking a large cardboard box over the printer, with a hole cut for the filament to enter, caused the air in the box to rise 20 degrees F to 80F. With that, my warping went away entirely with no raft. I did use a 5mm brim.



It stuck to the bed so well I had to use a putty knife to pry it off. Victory. I think that the box causes the print to stay at a more even temperature, reduces the temperature delta from the bottom of the print to the top layers, and causes the whole thing to cool more evenly.

Please consider the risk of fire if you choose to enclose your printer. I used the cardboard as an experiment only, and will be replacing it with something more fire resistant. Your safety is your own responsibility.


Monday, February 17, 2014

More fun with the Printrbot Simple, and an easy spool solution




I have spent some time calibrating my Printrbot Simple, and am having excellent results. It took some experimentation and a good set of calipers and about a dozen little test prints, but I think it's there. :-)

I found that though the X/Y/Z steps per mm were right on, I was overextruding by about 8%. This didn't show up when I measured the amount of filament being moved - in fact, with the stock settings, it appeared that I should be under-extruding. But the symptoms were consistent - my prints were about .3mm too big in all directions on the external dimensions, and holes and slots were printing too small. Dialing back my extrusion multiplier to .9250 did the trick - prints are smooth and fit together.

I also switched filaments to Zen Toolworks PLA in white, and I am very pleased. I found that in my cool basement I had to run it at 210C to get good layer adhesion, but once I figured out that, man, it's nice.




I found a simple way to hang a filament spool, which eliminates tangles on long prints. I had a wide hook designed for hanging things on garage walls that was the right size. I had binding until I removed the rubber coating, exposing the steel. Works great.




Sunday, February 2, 2014

Estimating Cost of 3D Prints in PLA



When I first decided to get a 3D printer, I had no real understanding of what it cost to operate. It's useful to be able to know what a part costs before you print it.

It turns out this is pretty easy. Repetier Host (and probably anything that uses Slic3r as the slicing tool) will output the length of filament, as well as the volume, that the print will consume. For example, the print below shows that it will need 3.5 cubic centimeters of PLA plastic to complete.



An internet search shows that the density of PLA plastic is 1.25 grams per cubic centimeter. A 2 kilogram (2000 gram) spool of PLA costs about $30.

Now we can set up a simple ratio:

1000 grams/$30.00 = 1.25 grams/ (dollars per cubic centimeter)

Dollars per cubic centimeter = 0.0375, or just shy of 4 cents. So the above sample print, at 3.5 cubic centimeters, would cost about (4 x 3.5) = 14 cents.

If your design does not require printed support scaffolding, you can also easily calculate what it will weigh. This is useful for robotics and RC models. 3.5 cubic centimeters x 1.25 grams per cubic centimeter is about 4.4 grams.