syntax-highlighter

Thursday, April 19, 2012

Simple Command-Line Argument Handling

Much of the code I write is run from the command-line and often has a large number of input parameters.  I quickly got tired of handling command-line arguments and of having to remember the ordering of parameters.

The following code makes this easier by allowing parameters to be specified as key-value pairs.  You then call command_line_get_argument(.), with the desired argument name and type.  It searches through the list of arguments supplied to the program and attempts to read them into the correct type.  If the argument doesn't exist or doesn't convert to the correct type, the function returns false.

e.g.
// some variables declared here...
bool ok = true;
ok &= command_line_get_argument( argc, argv, "-input_file",      ARGUMENT_STRING, input_filename );
ok &= command_line_get_argument( argc, argv, "-output_basename", ARGUMENT_STRING, output_basename );
ok &= command_line_get_argument( argc, argv, "-num_iterations",  ARGUMENT_INT,    &num_iterations );
ok &= command_line_get_argument( argc, argv, "-prior_weight",    ARGUMENT_FLOAT,  &prior_weight );
if( !ok ){
 std::cout << "Usage:" << argv[0] << " [arguments]" << std::endl;
 std::cout << "arguments:" << std::endl;
 std::cout << "\t-input_file       [filename]         REQUIRED - input ground-truth image" << std::endl;
 std::cout << "\t-output_basename  [partial filename] REQUIRED - base name for output files, e.g. 'test01/image0_'" << std::endl;
 std::cout << "\t-num_iterations   [integer]          REQUIRED - number of iterations to perform, each is width*height mutations" << std::endl;
 std::cout << "\t-prior_weight     [real]             REQUIRED - weight for regularizer" << std::endl;
 return 1;
}

The 20 or so lines above replace what was initially closer to one hundred with error checking and ends up being much more readable. The programs are also nicer to work with, since they don't rely on a specific argument order.

The code for this can be downloaded from https://sites.google.com/site/jamesgregson/tmp/command_line_arguments.h. It can be used for whatever you'd like, provided it's attributed as mine.

Sunday, April 8, 2012

Low Cost CNC Machine Part III - 1 1/2 Half-Finished Translation Stages

A continuation of Parts I and II....

I went on a bit of a tear today, building another four of the CNC shaft mounts, plus printing two hex-nut mounts and another motor mount.  As a result I have one nearly completed stage that just needs end-stops added, plus another that's about halfway done and still needs bearing mounts and end-stops.

The newly created hex-nut mounts follow the trend of the shaft and bearing mounts, except that the frame size of the Keling NEMA23s that I'm using don't match that well with shaft centers at 1" height, so the threaded rod ends up a few millimeters above the linear shafts.  Consequently the nut has to be moved a little closer to the carriage to take up the difference.



Nothing really novel here, but having everything mount on standard hole-spacings with standard hardware really makes the design and assembly process easier.

With the hex-nuts in hand, I can now test the stages to see how they perform.  The assembled stage is shown below, with the half-finished stage partially assembled on the carriage.  The extra pillow-block bearings were the ones I'd bought from VXB, I will probably not actually end up using them.  Note that I'm really short on 2" 1/4-20 machine screws, so every mount only has one screw on the clamp side. 


I also tested out a simple anti-backlash nut idea.  It involves backing an additional nut onto a stack of rubber washers.  This is pretty cheap, with adjustable preload and surprisingly enough, seems to stay in place just by friction, although I think a proper mount should probably be designed.  A closeup is below:


For testing I'm using the standard Pololu A4988 drivers, driven by an Arduino Uno.  After some mishaps a few months ago, I fried two of my drivers so I'll have to pick up some new ones. In the photo below you can see the Arduino connected to the 4-axis driver board I've kludged together, connected to the stepper in bipolar parallel, which should give about 180 oz-in of torque.


Early tests showed that even unloaded, it was important to control acceleration of the motors to make sure they didn't skip steps.  I wrote a simple sketch that ramps the step rate up from a low rate where the motors can slam from forward to reverse without stuttering up to a much higher rate, about 2500 steps/sec with no microstepping.  The code is below:

// step pin is #3, direction is pin #2
void setup(){
 Serial.begin(115200); 
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
}

inline void advance_steps( int dir, int steps ){
  int increment  = 4;
  int delay_init = 1000;        // 1/2 initial step delay, in us
  int delay_final = 200;        // 1/2 final step delay, in us
  int delay_curr = delay_init;  // current delay
  
  // compute the end of the ramp up and the start of the ramp down
  int ramp_up   = min( steps/2, (delay_init-delay_final)/increment );
  int ramp_down = max( steps/2, steps-(delay_init-delay_final)/increment );
  
  // set the direction
  digitalWrite( 2, dir );
  
  // start stepping
  int i=0; // step counter
  
  // ramp up
  for( ; i<ramp_up; i++ ){
    digitalWrite( 3, HIGH );
    delayMicroseconds( delay_curr );  
    digitalWrite( 3, LOW );
    delayMicroseconds( delay_curr );
    delay_curr-=increment;
  }
  
  // constant feed-rate
  for( ; i<ramp_down; i++ ){
    digitalWrite( 3, HIGH );
    delayMicroseconds( delay_curr );  
    digitalWrite( 3, LOW );
    delayMicroseconds( delay_curr );    
  }
  
  // ramp down
  for( ; i<steps; i++ ){
    digitalWrite( 3, HIGH );
    delayMicroseconds( delay_curr );
    digitalWrite( 3, LOW );
    delayMicroseconds( delay_curr );
    delay_curr+=increment;
  }
}

void loop(){
  // move carriage one way
  advance_steps( LOW, 15000 );
  
  // then reverse
  advance_steps( HIGH, 15000 );
}

So I tried it out, and it worked! Moves the carriage back and forth like all-get-out.


Pretty cool to see something you've taken from initial idea to built prototype actually perform.  Doesn't hit the 100 mm/s feedrate that I'd like, but I didn't really expect that from the 1/4-20 rod.  With a proper leadscrew it should be no problem to get to that rate.  Yes, that is a T-Pain microphone on the chair in the background.

Next I wanted to see how loaded down the motors were.  To test this I added 16 pounds of freeweights.  It still ran smooth as silk, and after 15 minutes, the Pololu driver was only slightly warm.

I'm really pleased with how this turned out.  The stage is actually pretty quiet, much quieter than I'd expected.  On top of that, it seems to have power to spare even from a 12V supply.  Since the Pololu drivers are rated for up to 35V, I think I should be able to run it at 24V and get even faster feedrates. I haven't checked the accuracy yet, but if the 1/4-20 rod was perfect (Ha!) and there was no backlash (Ha!) then it would have a resolution of 6.4 um/step.  It might be wishful thinking, but I'm hoping to get it to within a few thousands of an inch (0.025-0.05mm).

Next steps are to finish the z-axis and install endstops.  Then I'll make the components for the y-axis and start thinking about a frame.




Wednesday, April 4, 2012

Low Cost CNC Machine Part II - A half-finished translation stage

Following up on my previous post regarding a low-cost cnc machine I have begun the design process and have a half-completed linear stage.  This will form the x-axis for my machine which the z-axis will be mounted to gantry-style.  The y-axis will mount to the machine bed, keeping the total amount of moving metal minimized in the interests of stiffness and acceleration.


Here is the (half-finished) result.  The carriage will run on 8mm linear shafting.  This is pretty light-duty, but cheap and easy for prototyping.  It will probably need to be replaced on the final machine with 12mm or 20mm shafting.  The shaft mounts are made from 1/2"x1.5" bar stock and clamp using one of the two mounting bolts.  This allows the shafts to be removed without totally loosening the mounts.  I started by prototyping on the Makerbot at VHS, and finally got the bar-stock cut at Metal Supermarkets, doing the drilling with the drill-press at VHS.


I have been very happy with my choice of mounting all components with 1/4-20 bolts on 1" centers.  The base stock is 1/4" aluminum plate, with drilled and tapped mounting holes.  It would also be possible, and much more accurate, to use optical breadboards, however these would severely limit the acceleration and feedrates attainable, since they are generally 1/2" thick and twice as heavy.  For now I'm sticking with the 1/4" plate.I



The bearing mounts are 3D printed for now.  They will eventually be made from 1.5" square stock cut in 1" lengths, which is just long enough to hold the LM8UU linear bearings.  The bearing is mounted 1" from the base, following the convention for the shaft-mounts, in order to provide a half-inch of clearance for bolt-heads. I had originally intended to make these out of aluminum, buying the square stock and having it cut, however when I got home I had a terrible surprise:


The prototype mount is shown with the cut aluminum, guess the pieces were cut incorrectly.  In the bag are the other 11 cut pieces that won't fit.  I don't know if it's my mistake or Metal Supermarket's, but either way the pieces are useless to me and I have a lot of them.

I may eventually switch to brass bushings similar to my Shapelock linear bearings to keep the noise down when 3D printing, but will use the LM8UU's until this is actually a problem.  The bearing mounts clamp to the bearings the same way that the shaft-supports do, and as always, mount to the carriage with 1/4-20 bolts on 1" centers.



The motor-mount breaks from the mold a bit.  I will probably make the final mounts from angle or C-channel, but for now just have the 3D printed part.  This fits a NEMA23 stepper very nicely, but is not particularly stiff.  The stiffness is not so big a concern, since I will be adding support bearing to keep the threaded rod in tension, which should handle any axial stresses, however I'm worried that the less than rugged mount might break during repeated trips to VHS in my bicycle paniers.

All that remains to finish the prototype stage is to get a piece of plate for the carriage, print the (already designed) lead-screw support bearings and lead-nut mount and drill/tap about a dozen holes.  The result should be a reasonably stiff, reasonably accurate linear stage.  If all goes well, I can then look into sourcing reasonably priced leadscrews, since the stand-in 1/4-20 rod I'm using won't allow the 100 mm/s feeds I'm looking for.  Currently I can only achieve about 30 RPS (~38mm/s) with the steppers, which needs quite gradual acceleration. Switching to a 1/4", 2- or 3- start leadscrew would give me the feeds I'm looking for, but sourcing these in Vancouver is troublesome.

Low Cost CNC Machine Part I

I am currently in the midst of trying to build a low-cost 3-axis CNC milling machine.  I have no basis for making one, I don't even have a project in mind that needs one; I just want one, and specifically one that I've made myself.  This means that I will invariably (a) spend way more time/money building it than needed if I just ordered one, (b) will probably end up with a sub-par machine and (c) will be heartbroken when it has to be taken apart because it is absolutely deafening when running. Oh well.

I've seen a number of DIY machines online, and while I find them interesting, none really do it for me.  I would like to end up with a mill that can handle a variety of materials: wood, plastic, protoboard and ideally, aluminum.  Milling hard materials at sensible feedrates will require a stiff machine, so plywood and MDF framed machines are out, as are (in my opinion) belt and chain drives since they can be backdriven.

Beyond having just a plain CNC, I would also like the ability to add an extruder head to make a 3D extuder.  This means that the feedrates must be reasonably fast; based on the Makerbot at the Vancouver Hack Space, (VHS). I would like feedrates of about 50 mm/s, with a maximum feed of over 100 mm/s so the motors aren't running full-out all the time and so the machine has decent acceleration which will keep it responsive.  This means that I will also need a fairly light machine, which is completely at odds with the stiffness requirement.  Beyond that, I would like to be able to build the machine with a minimum of machining, in order to keep costs down.

Nevertheless I plunge ahead.  Compromising between the stiffness and lightness requirements, I have decided to make the machine from aluminum.  To give maximum flexibility in the design and to maximize component reuse when the design inevitably changes, I have decided to make all frame components from stock sections of aluminum, i.e. bar and plate stock.  These have good tolerances (relatively speaking) to begin with and nice factory edges from which to reference other features.  I've further decided that all components should mount with 1/4-20 UNC bolts on 1" centers.  These bolts are cheap in a wide range of lengths, and using this spacing allows me to prototype on the optical table at the lab.  This will mean a lot of tapping, but it's time I learned how to tap anyway.  The frame components themselves will be drilled with 5/16" holes to allow a sloppy fit, which will allow minor offsets and angular misalignments to be corrected before tightening everything down.

I've also decided to take advantage of my excellent access to the Makerbot at VHS to prototype the various parts before machining them from aluminum.  As conceived, everything can be made with a cutoff saw (which Metal Supermarkets has, at 1$ per cut) and a drill-press (which the hackspace has).  However the machining is a time-consuming and error-prone process for me, so having a design without interference or other gotchas will cut down on frustration.

That's all for now....

Hex-Meshing Paper Published!

Quite delayed in posting this, but my paper, All-Hex Mesh Generation via Volumetric PolyCube Deformation (joint work with Alla Sheffer and Eugene Zhange) was published in SGP2011! This paper dealt with how to automatically generate a lego-like PolyCube version of an object that could then be meshed with hexahedral elements (distorted cubes).  This is a very difficult problem with big application in industry, although this paper is just a stepping stone in the road to automatic all-hex mesh generation.


The image above shows a PolyCube automatically generated from the geometry that is hex-meshed on the right.  Only hexahedral elements are present in the output mesh and the minimum element quality is often very high, although this is not guaranteed by the method.

Uniform Grid Interpolation in 1D, 2D and 3D

Recently I had need for code to interpolate data stored on regular grids in 1D, 2D and 3D.  This code is straightforward but time-consuming to write and I often find myself re-implementing it for each project that I work on.

The linked header file includes templated interpolation routines for 1D, 2D and 3D interpolation on uniformly gridded data with linear, cosine and cubic (Catmull-Rom) interpolants.  It is fully documented with DOXYGEN and provides a simple fairly consistent API.  The code works by interpolating values that are passed in either as individual values or as arrays allowing it to work with arbitrarily defined grids and also optionally returns the weights associated with each value.  I have used the code to implement

The following code snippet taken from one of the 2D test functions shows the use of the API. In all API functions, points are ordered lexographically by axis, i.e. p[0] = [x, y], p[1] = [x+1, y], p[2] = [x, y+1], p[3] = [x+1, y+1].

/**
 @brief test function for the 2D linear interpolation routines, currently just
 checks that the methods are consistent, i.e. that they all produce the same
 output for the same input
 @return true if test passes false otherwise
*/
static bool interpolation_test_lerp_2D(){
 const double t0=0.325f, t1=0.675, v[] = { 1.0, 2.0, 2.0, 5.0 };
 double o0, o1, o2, o3, w[4];
 bool result = true;
 
 // check that API functions are consistent
 o0 = interpolation_lerp_2D( v[0], v[1], v[2], v[3], t0, t1 );
 o1 = interpolation_lerp_2D( v[0], v[1], v[2], v[3], t0, t1, w[0], w[1], w[2], w[3] );
 o2 = interpolation_lerp_2D( v, t0, t1 );
 o3 = interpolation_lerp_2D( v, t0, t1, w );
 result &= fabs(o0-o1) < 1e-9 && fabs(o0-o2) < 1e-9 && fabs(o0-o3) < 1e-9;
 
 // check that input values are reproduced
 result &= fabs( interpolation_lerp_2D( v[0], v[1], v[2], v[3], 0.0, 0.0 )-v[0] ) < 1e-9; 
 result &= fabs( interpolation_lerp_2D( v[0], v[1], v[2], v[3], 1.0, 0.0 )-v[1] ) < 1e-9;
 result &= fabs( interpolation_lerp_2D( v[0], v[1], v[2], v[3], 0.0, 1.0 )-v[2] ) < 1e-9;
 result &= fabs( interpolation_lerp_2D( v[0], v[1], v[2], v[3], 1.0, 1.0 )-v[3] ) < 1e-9; 

 return result;
}

The code is freely available for all purposes and can be downloaded below:

https://sites.google.com/site/jamesgregson/tmp/interpolation.h

Please contact me if you find bugs, questions or find the code useful.

Friday, March 23, 2012

Shapelock Linear Bearings

It's pretty difficult to get reasonably priced linear-bearings in Canada, due to the markup that Canadian distributors apply and shipping/export fees when importing from the US.  In spite of this, I ordered a set of shaft supports and pillow-block linear bearings from VXB via Amazon.  The shaft-supports are okay, but the bearings are deafening when they move.  For a CNC mill this would be fine, since the cutting noises will probably drown out the bearing noise.  However I'd like to be able to swap out the spindle for a plastic extruder to make a 3D printer that I can use in my apartment.

So I set about trying to make quiet, modestly accurate linear bearings from scratch, using only handtools.  Here are the results:


The body of the bearing is made from Shapelock, with a brass tube insert for the contact surface.  They're not the most accurate, with about 4 thou (0.1mm) of play, but they're dirt cheap and pretty easy to make if you're patient.  Higher accuracy is possible if you can find brass-tubing with an ID that matches the OD of your linear shaft.  In my case, the best I could find for 8mm linear shaft was 11/32" OD brass tubing with an ID of 8.1mm.

I decided to use the existing shaft supports as forms.  I started by sliding the brass bushing over the shaft and clamping one shaft support on either side.  I then used a clamp to hold two corner brackets against the shaft supports.  The aluminum sheet underneath is not necessary, but conducts heat well and does not stick to the Shapelock (unlike my counter-tops), which I've found makes the process faster and easier.


After that I heated up the Shapelock and started cramming it in from the top and bottom, cooling it in the sink under running water afterwards.  Be sure to add more material than you need, since you can always cut off excess.


After remove the clamp and prying off the corner brackets, the result had a lot of flashing:



After cutting the excess away with a box-cutter, I had the final parts.  Now all that is left is to drill mounting holes.


These bearings run much more quietly on the 8mm shafting than the LM8UU pillow-blocks that I ordered.  They don't bind much when torque is applied and run much more smoothly than the pillow-blocks, at least with low-load.  The pillow-blocks can hang vertically on the shafting without moving, while these lighter bearings will start to slide if the shaft is tilted by about 15 degrees.

Unfortunately they have more play than the pillowblocks, this is largely from using 11/32" OD brass-tubing which has an ID of slightly more than 8mm.  Finding 8mm ID tubing should fix this however.