syntax-highlighter

Showing posts with label linear motion. Show all posts
Showing posts with label linear motion. Show all posts

Sunday, May 26, 2013

Smooth Feedrate Envelopes for Motion Control, Part II

In the previous post, I derived equations for smooth feedrate control of stepper motors, claiming that by using a smoother feedrate envelope that the motors could be driven faster with less chance of skipping steps and losing position.

In this post, I demonstrate this with a real stepper motor and show that it actually does work: using the envelopes does actually prevent the motors from losing steps.  My test setup is a single NEMA 17 stepper, driven by one of my A4988 driver breakouts, which is controlled by an Arduino sketch running on the Arduino Due.  I'm using half-stepping on the motors, driven by a 200KHz timer interrupt step callback which decides whether or not to step based on the interpolated supplied delays for the start and end of each move.  The move itself approximates a square wave, first accelerating from a slow feedrate, then performing a constant speed portion, then decelerating back to the initial feedrate.

The video below shows the stepper being driven using a constant acceleration profile, which causes the kinks in the feedrate graph in my previous post. You can clearly see it moving around on the table and stalling frequently before it reaches the top speed.


In contrast, here is the result using the third-order cubic feedrate envelope for the same set of moves. The stepper is easily able to handle the top speed and jerks around considerably less on the table.  Of course this comes at a price, a higher pulse-frequency must be used to resolve the acceleration profile.


You can get the code I used for this from following link: https://sites.google.com/site/jamesgregson/tmp/linear_move.zip, it includes a multi-axis DDA implementation suitable for use with timer-interrupts as well as the code for evaluating the feedrate envelopes.

Thursday, May 23, 2013

Smooth Feedrate Envelopes for Motion Control

When running motors it is desirable to run them as smoothly as possible to minimize vibrations and possible missed steps. This is why controllers for 3D printers and CNC machines typically incorporate some notion of acceleration rather than instantly switching from one feedrate to another.  Often this is done with a simple ramp of the feedrate, i.e. using a constant acceleration profile.

As an example, consider a machine starting at feedrate $f_0$ and then performing a very long linear move at a constant feedrate $f_1$. For this example, If $f(t)$ is the machine feedrate over time and $a$ is a constant acceleration, this profile would be defined mathematically as follows:

\begin{equation}
f(t) = \begin{cases}
f_0      & \mbox{if } t < t_0 \\
f_0 + a (t - t_0) \hspace{0.5cm} & \mbox{if } 0 \leq t - t_0 \leq \frac{f_1-f_0}{a} \\
f_1 & \mbox{otherwise}
\end{cases}
\end{equation}

Graphically, here's a plot of the feedrate over time for a move starting at rest at $t=0$ and accelerating up to a feedrate of 2 over one unit of time:


The problem with a constant acceleration profile is that there are sharp kinks in the feedrate plotted over time.  These kinks imply instantaneous changes in acceleration, which in turn imply infinite forces for infinitely short periods of time.  Of course, there is no mechanical way to produce these forces, so what actually happens is the machine overshoots very slightly and averages the forces out over a short time. For low feedrates with a light machine this actually works okay, but for a heavy machine at high-feedrates, the overshoot can be more than a motor step which causes the machine to lose position.  In an open-loop design, once the machine loses position, it never recovers and in all likelihood, the part is ruined.

There are a few ways to address this problem:
  • Use lower feedrates
  • Use higher torque motors
  • Use a closed-loop control scheme, e.g. with encoders on the motors
  • Make the acceleration smooth
The first is clearly not an option because it wastes time and feedrates may be chosen specifically for valid reasons such as minimizing local part heating or reducing machining time.  In an ideal world we'd do the remaining three items, but options two and three are expensive, particularly for hobby gear.  However the fourth option can be tackled in firmware with minimal hardware overhead. 

In order to smoothly transition between accelerations we can simply use a different curve to interpolate the feedrates.  The conditions needed are that the feedrates match the desired rates at the beginning and end of the curve and that the slope of the feedrate curves (i.e. the acceleration) is zero at the endpoints.  In between the endpoints we want the curve to be smooth.

The one of the simplest classes of functions that meet these requirements are cubic polynomials.  These are defined by four coefficients $a$, $b$, $c$ and $d$ using the following equation, where $\tau$ is the fraction of the total time spent accelerating:

\begin{equation}
f(\tau) = a \tau^3 + b \tau^2 + c \tau + d
\end{equation}

We now want to solve for the coefficients needed to reproduce the move.  There are four coefficients so we need four equations.  Two come from the requirement that we match the feedrates at the curve endpoints:

\begin{eqnarray}
f(\tau=0) = a 0^3 + b 0^2 + c 0 + d &=& f_0 \\
f(\tau=1) = a 1^3 + b 1^2 + c 1 + d &=& f_1
\end{eqnarray}

From these, we see that $d=f_0$ and $a+b+c=f_1-f_0$. The remaining two equations can be found using the requirements that the slope of the feedrate curve is zero at the endpoints. To enforce these constraints we need the derivative of the cubic function:

\begin{equation}
f'(\tau) = 3 a \tau^2 + 2 b \tau + c
\end{equation}

The constraints can now be enforced by requiring that:

\begin{eqnarray}
f'(\tau=0) = 3 a 0^2 + 2 b 0 + c &=& 0 \\
f'(\tau=1) = 3 a 1^2 + 2 b 1 + c &=& 0 
\end{eqnarray}

These equations make it clear that $c=0$ and $3 a + 2 b = 0$. Combining these with the previous conditions leaves two equations and two unknowns:

\begin{eqnarray}
a + b &=& f_1 - f_0 \\
3 a + 2b &=& 0
\end{eqnarray}

So $a = -\frac{2 b}{3}$ which means that $b = 3 (f_1-f_0)$ and $a = -2 (f_1 - f_0)$. This gives the following equation for the interpolating curve:

\begin{equation}
f(\tau) = -2(f_1-f_0)\tau^3 + 3(f_1-f_0)\tau^2 + f_0
\end{equation}

The only remaining thing is to define $\tau$ in terms of $t$.  This is a simple linear interpolation from the start of the acceleration $t_0$ to the end of the acceleration $t_1=\frac{f_1-f_0}{a}$:

\begin{equation}
\tau = \frac{t-t_0}{t_1-t_0} = \frac{t-t_0}{\frac{f_1-f_0}{a}-t_0}
\end{equation}

Plotting this for the same parameters as before gives a smooth, kink-free curve that considerably reduces the time-rate-of-change of acceleration:


In the post-to-come I will demonstrate applying this to a real stepper motor being driven aggressively.  Although seemingly complicated, for a cost of only a few operations per step, it is possible to switch from the linear acceleration profile to the cubic one derived here and get considerably smoother operation.

Sunday, February 10, 2013

Prototype 5-Axis CNC Board

Since I'm working on some CNC firmware, I thought I needed a test platform.  I didn't want to rip-apart the CNC so I decided to build a new 5-axis board using the new Pololu stepper drivers. These are nice little cheap boards and their advantage over the ubiquitous A4988 drivers is that they don't need cooling up to 1.5A per phase.  This makes things way easier, since those tiny little heatsinks for the A4988 chips are scattered all over my apartment, double-sided tape all linted up so they won't stick, just waiting to be stepped on.  They hurt even more than stepping on a Lego block, little buggers.

Anyway, I figured I should just go to five axes, which would allow me to control the 3D printer eventually (1X, 1Y, 2Z, 1E).  So I built a protoboard test board:


I laid out the board and soldered it up.  It was pretty easy except for having to drill a few extra holes in the power-rails to get the spacing I wanted.  After electrically testing everything I decided not to blow all 5 drivers simultaneously on a meticulously copied wiring error, opting instead for only two.

The MCU controlling the whole mess is an Arduino Uno.  I have the step pins on PortD and the direction pins on PortB, which allows fast bitwise operations to be used for stepping.  While picking up the stuff for the prototype board I also bought a proto-screw-shield, wanting a more resilient mounting option for the Uno:





I have the early version of my CNC firmware loaded onto the Arduino.  After firing up the serial terminal, I had the thing running!



Not super crazy, but still rewarding nonetheless.

CNC Firmware running on Arduino Uno

In an earlier post I described some prototype CNC firmware that I had gotten running on the Teensy3.0.  The Teensy3.0 is a 32-bit ARM board and is pretty nice, but I wanted to see if the code would also run on an Arduino Uno.  This is a much more restrictive platform; only 2k of ram and 32k of program space.  However, after a bit of porting of the hardware layer, it compiles and seem to run no problem.  Here's a screen-capture from a (brief) session, the pulse-ticks stuff is debugging the motion control module.


Note that this is running the full GCode interpreter, with spec-compliant command sorting and an 8-move lookahead buffer.  The step timer is running off a 2KHz Timer1 interrupt.  I'm hoping to increase this to 8+ KHz, at least on other platforms, which should make smoother motion control possible, but at the moment I'm just happy that my ANSI C + POSIX code that I've developed on on a 64bit quad core machine with 16Gb ram ports easily to an 8bit system with 2k or ram and only interrupts after changing less than 50 hardware-specific lines of code.

I've written the code this way for just this reason; by keeping all the hardware specific stuff isolated in a hardware abstraction layer I'm hoping to make a code base that stands the test of time, from small embedded platforms to boards like the Raspberry Pi, to full-blown PCs.  So far so good, it's running on an 8bit AVR, a 32 bit embedded ARM and a full X86_64 PC.

Wednesday, January 30, 2013

Start of CNC Firmware Running on the Teensy 3.0

I've been intermittently working on some CNC firmware with the goal of getting it to run on everything from an Arduino to a standard PC.  It's a fun project because it's very resource constrained but involves a number of different parts, like GCode parsing, asynchcronous programming, portability and motion control for non-Cartesian machines.

In the interests of portability I've been writing the various components in plain ANSI C (except the comments, I like my double slashes!).  By doing this I expect the code to be portable across a wide variety of platforms, from AVRs to the Propoeller child to ARM to PCs, with minimal effort.

My hopes are that the firmware will conform to the NIST GCode specification as closely as is manageable.  That said, some sacrifices will have to made as the spec calls for around 20k of addressable space for expressions, which exceeds the total RAM of Arduinos and even the Teensy 3.0.  However I hope to get mostly spec-compliant in terms of order of operations, expressions (if not the addressable space) and features.  Where possible I am also allowing the specific capabilities to be determined by preprocessor macros.

I've done a bit of work on the GCode interpreter, getting some test code together that parses GCode expressions (this led to my Mathematical Expression Parser in C) as well as an arbitrary dimension DDA implementation.  To date these have been just simple tests, nothing actually running on real hardware.  I've also done some early tests on doing feedrate optimization and

However today I made some good progress on actually getting some real firmware started.  I got my early GCode interpreter stripped down and abstracted out all the hardware-specific stuff into a hardware layer.  I then wrote the hardware abstraction layer for the Teensy 3.0 version of the Arduino environment and fired up the code, using the following string to test with:


N1229.0(This is a comment)G01x110.0   y330.0 M7 F20.0(MSG: another comment)

And it worked!


The screenshot above shows the GCode interpreter code loaded up in the Arduino environment, the Teensy loader application that programs the Teensy and the serial output of the parser. Note that this is not just reading the commands linearly, it is fully parsing the input, splitting it into distinct commands, sorting the commands by operation precedence (as described in the NIST spec) and finally calling back to the Arduino sketch with each command.

Parsing the string and calling back takes about 250 us (the remaining time taken is up by serial communications) so more than fast enough to fill up a lookahead buffer.  Total RAM used is about 5k, so this won't run on an Uno but does run handily on the Teensy 3.0. Ditto goes for the flash at 33Kb currently. This is pretty hefty compared to other firmware, but I think portability and cleanness makes up for that.

The next steps will be to get the kinematic/motion control stuff fleshed out.  I think I should be able to use by DDA implementation running with the Teensy timers pretty easily.  Then it's just tweaking and adding features...

Saturday, November 3, 2012

Low Cost CNC Part VIII - Built-in electronics

In Part VII, I finally got the CNC cutting, but it was still a bit rough.  Cables ran everywhere, it was powered from a wall-wart and the electronics were sitting next to it on the table.  You can see the setup below:



Since finding the big C-channel piece that makes up the base of the machine, I've always planned to build the electronics into the base to give a nice, compact and clean machine.  I'd been waiting for a power-supply to arrive before doing this, but last week it came so I got to work.

The electronics are currently mounted to a piece of plywood that hooks on a key at one end and has bolt holes to bolt to some 3D printed plastic standoffs.  It fits into the base pretty nicely.


The plywood is a bit of an old shipping box; it had my address on it, hence the black tape.  Undoing two nuts on the right hand side allows the plywood to come loose:


Running approximately left-to-right, you can see the Arduino running GRBL, the three stepper driver carrier boards, a solid-state AC relay for spindle control as well as the power-supply and finally the E-stop button.  All the mains power is wired with 14 gauge household wiring connected with Marretts.  The E-stop button cuts all mains power to the power-supply and relay, thus rapidly immobilizing the machine.  The Arduino is unaffected by the E-stop, being powered from USB.  In this way, the E-stop also functions as an optional operator stop, allowing you to de-energize the machine, reposition it manually or change tools and then start it back up, knowing that it won't starting moving or cutting with your hands in there. 



Looking from the back, the USB socket for the Arduino is accessible, as is the scavenged spindle socket and power cable.  In a subsequent revision I plan to replace these with panel-mount components, but I couldn't locate them locally last week.


It's still a bit ghetto, but quite functional and self-contained at this point.  I intend to finalize the electronics layout and then make a sheet-metal replacement for the plywood with front and back panels and all panel-mount components.  But for the moment, it's working pretty well and I can easily pick it up and move it without rewiring the whole thing.


The other, straightforward, addition was cable drags on all the axes.  This has really helped to clean up the machine, giving me something that looks more like an actual tool than before.  Hopefully I will be able to start using it for projects soon.



Wednesday, October 24, 2012

Low Cost CNC Part VII - It LIVES!!!

So for the last, nearly two years, I've been working on building a low-cost, homemade, 3-axis CNC milling machine.  Today for the first time, I can say that I've done just that, having finally actually cut something.  As far as I know, it's the first milling machine build largely from 3D printed parts.

You can see the entire process, from the beginning, in the previous six posts:  Parts I, II, III, IV, V and VI.


The mill is shown below, along with the 3-axis CNC controller that I've posted about before. 


The spindle is a low-cost Dremel tool, currently attached with a Shapelock bracket.  It will no doubt get replaced with something less awful in the future (I am referring to both the Dremel and bracket, of course).


I have a Rotozip spiral-saw bit in the Dremel tool, to stand in for a proper milling bit.  It's a bit flexible, but more than up to tearing through MDF.


The whole setup is shown above and gives a good sense of scale.  My 3-Axis controller board is in the bottom right, controlled by my laptop.  The CNC itself has around a 6x6x4" working volume, although this is arbitrarily expandable in the X-direction.  The controller board runs GRBL, for which I have written a simple GUI for adjusting settings and jogging the machine. I plan to release the code for this when it stabilizes a bit, since GRBL needs a decent GUI.  I intend to add some basic features, like simple pocket/contour milling.  But for the time being, it's simply a software pendant.


So with everything set up, it was time to start cutting.  I attached my 3D printed iPhone mount to the XY table, started the Dremel, pressed record and began jogging the machine.  The result is pure awesomeness, for me anyway.



I had either the cutting depth or the feedrate too high for the spindle speed, since the bit began 'climbing', rounding the edges of the square when the feedrate was high.


But guess what? I don't care! 'Cause the CNC that I started nearly two years ago, which has been my preferred hobby while simultaneously being intensely frustrating has finally, finally, cut something. Praise Jebus!

Obviously there's refinement to be had.  For one thing, the ~10 mm long square sides should actually be one inch.  And I should make sure that the axes are actually square (I'd be shocked if they are).  Also I want to package the electronics in the base extrusion, provide a proper power-supply, perhaps some heat-sinks on the stepper drivers and maybe attach a real spindle.  And then there's ballscrews/belts.

But that's for later.  For the time being, my CNC actually cut something.

To my knowledge, this is also the first milling machine built substantially with 3D printed parts.  I hope in the not-to-distant future to get the feedrates up to the point of being able to 3D print with the mill itself. I also intend to build a tapping attachment to tap the holes used in the aluminum plates, which is -really- time-consuming and error-prone. This would make the machine as much of a RepRap as most 3D printers are, but considerably more solid.  But that's for later.

Monday, October 15, 2012

Low-Cost CNC Part VI - The Z-Axis

Following up on Parts I, II, III, IV, and V, the machine gets a Z-Axis!
 
With the addition of a Z-Axis the machine is starting to really come together.  The main supporting column is a 4x4" square extrusion with 1/4" walls, mounted at 30 degrees.  I'm hoping this will be stiff enough to be mounted cantilevered.  It mostly passes the 'grab-and-pull' test, but I can feel it deflect a bit when I yank on it.  Hopefully the forces during machining will be low enough for this to not be an issue.


I used two Newport 360-30 angle brackets to build the main support.  These normally retail for about $110 USD, but I was able to pick them up used for $38 each.  Here's a detailed shot of the lower mount.


This still makes them the most expensive part of the machine, but even with them, I think the mechanics could be built for about $100 per axis, including motors.  I looked at a number of options for the supporting column, including welding a custom bracket, but all quotes came back at $300+.  This cost less than $100 (including the column) and is pretty stiff. Plus I can re-use the brackets later.



I still need to tweak dimensions a bit.  As can be seen in the photo above, the Z-Axis is a bit low and doesn't provide much clearance over the XY table.  I will probably add a spacer on the angle mount and drill/tap a few new holes to get a bit more clearance.  I'm only shooting for about three extra inches.  This should give the final machine a few inches of working depth, including perhaps a small vise on the table and a cutter.  I may also flip the Z-Axis around and mount the plate rather than the carriage to the supporting column, which will give a bit more clearance but has other tradeoffs.


Sunday, September 16, 2012

Low Cost CNC Part V - A Redesign

I've been working on a homemade CNC now for quite some time.  My goal for the project was to produce something modular, where shaft-mounts, motor mounts and bearings were entirely separate parts using a standardized mounting pattern.  This would allow the machines to be put together like Legos and has a lot of advantages, like the ability to mix and match drive options, e.g. in the image below, one axis is screw-driver while the other is belt-driven.



I still think this concept has merit, however the part designs that I ended up using made for bulky and not particularly stiff machines. In the photo above, the top of the XY table is close to six inches from the base plate and the machine itself has considerable give.  Even worse, I didn't build enough slop into the designs to accommodate tolerances for manually built mounting plates, so it was actually quite difficult to get all the pieces to play nice.

I've since redesigned the machine to use more compact mounts, merged the shaft and motor supports into a single axis-end part and moved to half-inch shafting.  The switch to larger shafting results in a much stiffer machine, but unfortunately does require bushing style bearings.  Using the combined axis ends simplifies alignment, but unfortunately precludes belt drives.  I've also switched to Nema 17 steppers from Nema 23s, which leads to a more compact overall machine.  Surprisingly they don't seem to have much affect on the overall machine speed.  This makes for a much cleaner design:


Like the old parts, the new parts are 3D printed, but this time on my recently acquired RepRap.  The meshes were parametrically generated using my Python contructive solid geometry library, which is becoming quite usable.  This serves for prototypes, but final parts could be machines from plastic or aluminum.  The fixed-end for the leadscrew uses the same axis-end as the motor side, but with some bearing plates and Nylin nuts to take the axial loads:


After switching to acetal linear bushings, the bearings mounts can be made much more compact, reducing the height of the XY table from about six inches to a shade over 3.  These seem to run nicely on plain hardware store shafting, although hardened precision linear shafting would obviously be stiffer and smoother than cold-rolled bar stock.


Overall the machine is looking much cleaner.  I've decided to go with a knee-mill style machine rather than a gantry arrangement.  This means an XY table horizontally with a third axis mounted vertically. I bought a massive piece of aluminum channel to serve as the base of the machine, 10"x3"x20".  This provides a sturdy mount, and the controller and power-supply can be mounted to the underside.  Here's the thing midway through the build process yesterday:


And here's the finished-except-for-limit-switches XY table mounted to the channel.  The green duct tape is just there to stop it from gouging up my coffee table when I move it.  I will also probably replace the top cheese-plate with a thicker piece of flat-bar that's had all the holes drilled and tapped; I can't tell you how much I'm looking forward to doing that.


The mount for the Z-axis will be attached at the near-end of the machine.  I still have to design and build that mount, as well as print out the parts for the third axis.

After assembly, I simply had to try it out, missing limit switches or not.  I hooked it up to my 3-axis controller board with the Pololu A4988 carrier board carriers. The Arduino is flashed with GRBL, and wired to the carrier boards, which are in turn wired to the steppers.  I need to find some extra heatsinks for the X and Y axes, along with some thermal tape or epoxy, but they seem to run cool enough for testing anyway.


Here is it running, the first time I've gotten one of these CNC projects using actual GCode.  The leadscrew for the Y-axis is a bit loose in the fixed-end bearings, causing the knocking sounds, I have to look into the alignment, but otherwise it's working pretty well.  Speed is about one inch per second.


Next up will be designing a mount for the Z-axis.  I'm quite happy with the current set of printed parts and will probably continue to use them.

Friday, August 10, 2012

3-Axis CNC Controller

In a previous post, I showed the single axis stepper driver boards that I sent out to be made by OSH Park. These seemed to be electrically fine, although it was tricky to properly test without the connectors and other components.  After a quick order from DigiKey, I had the bits I needed.


I'm pleased to say that these work as expected, allowing the microstep mode to be chosen by DIP switch, breaking out all inputs and outputs with screw terminals, and providing the connections needed for high and low limit switches.  I've assembled three of these and screwed them to a piece of MDF to serve as the basis for a 3-Axis CNC controller board based on an Arduino Uno and GRBL.






The start of this board is shown above. Before it's complete I need to add the power connections for the high-power side, along with the limit switches.  I have the GRBL firmware flashed onto the Arduino and have connected a few motors to this setup and everything works great!


Shown below is a closeup of the boards.  The screw terminals in the front connect the limit switches for the high and low endstops.  These have pulldown resistors and are connected to two of the screw-terminal positions on the logic side of the board (the two un-wired stops).  The remaining pulldown resistors are connected to the microstep selection pins, which are set by the red DIP switch.  On the right side of the board are the motor connections (the 4-position terminal block) and the motor power connections (the two position terminals).  All connections are with 3.5mm terminal blocks, which actually meet the power requirements for multi-amp 24V operation.  They also allow multiple connections to be made which allows the daisy-chain type wiring shown above.  The low-power side also has these connections since even though they are not needed it's nice to only need one screwdriver to do the wiring.

I'm quite pleased with my first attempt at getting a board made.  It worked first try, the quality of the boards is excellent and I think these drivers can form the basis of a good many other projects.

Friday, July 27, 2012

A4988 Single Axis Carrier Board

I recently ordered some simple boards from OSH Park.  These are single-axis versions of my 3-axis carrier board for the Pololu A4988 stepper carriers and (will) include pulldown resistors for the microstepping pins (which can be set using DIP switches), as well power and pull-down resistors for high- and low-limit switches.  All connections are made using 3.5mm screw terminals and the boards have mounting holes for more permanent installation.  They also feature a diode for reverse voltage protection on the logic supply (but not on the motor supply).



A quick test seems to indicate that the boards are electrically sound, although I have yet to fully populate one and test it fully.  If they work properly, I plan to fix a silkscreen error where the logic supply voltage and ground connections are unlabeled.  I also plan to break out the enable pin on the driver and the large capacitor across the motor supply suggested by the Pololu site.  When I'm content with how the boards work, I'll release the Eagle files.

Saturday, May 26, 2012

Python Involute Spur Gear Script

It's pretty difficult to find reasonably priced gears around and even if you can find them, they're often not exactly what you want. Finding a gear with the right number of teeth, width, pressure-angle and bore is often not possible.

To this end I have written a python script for generating involute gears. Other scripts are available, an OpenSCAD script thingiverse for example, however i) I like to do things myself, from scratch and ii) I'd prefer my setup work with a more mainstream programming language. The source-code is available at the bottom of this post.

The script generates involute spur gears, with pressure angles up to about 30 degrees. I hope to extend it to include racks and internal gears eventually, but it is quite useful now. Output is in SVG for easy editing in graphic-design/laser-cutting or DXF for use with OpenSCAD. I am currently working on a CGAL-based constructive solid geometry module for python that will allow CSG operations to be performed by python scripts. This would allow fully parameteric CSG design to be done in an open, mainstream language.

I've generated some examples using the following script:
# import the gears script
from gears import *

pa = 14.5   # pressure angle, in degrees
P  = 24     # pitch, teeth per unit distance

# generate three gears
ax, ay = gears_make_gear( pa, 12, P )
bx, by = gears_make_gear( pa, 24, P )
cx, cy = gears_make_gear( pa, 48, P )
dx, dy = gears_make_gear( 30.0, 8, P )

# write them out as svg files, scaled uniformly by 150 and 300
gears_svg_out( ax, ay, 'section_a.svg', 150 )
gears_svg_out( bx, by, 'section_b.svg', 150 )
gears_svg_out( cx, cy, 'section_c.svg', 150 )
gears_svg_out( dx, dy, 'section_d.svg', 300 )


The output is below:



14.5 degree pressure angle, 12 teeth




14.5 degree pressure angle, 24 teeth




14.5 degree pressure angle, 48 teeth




30 degree pressure angle, 8 teeth


Since I haven't finished the CGAL CSG python CSG library, I've been calling OpenSCAD from the command-line via python to generate actual gears. I 3D printed some of these on the Vancouver Hackspace (VHS) Makerbot, with reasonably good results:



These parts will eventually be used as part of a 1:4 drive for the leadscrews for my CNC. Currently I have ample torque, but cannot spin the motors fast enough to get fast rapid traversals. With a 1:4 drive, I will hopefully be able to drive the machine quite quickly.



Sourcecode for the script can be downloaded from: http://sites.google.com/site/jamesgregson/tmp/gears.py. Use it for whatever you'd like, but please don't redistribute it.

Saturday, April 21, 2012

Low Cost CNC Part IV - Cheeseplates and belt-drives

I started by making some cheese-plate, aka optical breadboards.  You can buy these--and they will be far more accurate than I can make--but they are expensive.  This is probably because they are precision ground, anodized and 1/2 inch thick.  Half-inch plates are too heavy for this application, so I set about making some from 1/4 inch plate.

I scored out a grid pattern and then center-punched the intersections.  Actually I center-punched them twice, once with a very fine punch and then again with a much larger punch.  I've found this results in better-centered holes.  I also purchased a 1/4-20 tap-drill.  This simultaneously drills and taps a hole and, when used in a drill-press, dramatically speeds the process of making these plates up, as well as results in more accurate holes.  You can see the grid of center-punched holes and tap-drill below:


It's kind of weird using these with a drill press.  First you have to lower the spindle to drill into the material, until the threads begin to catch.  At this point it pulls the spindle down at the correct speed, you basically have to just stay out of the way.  However it is critical to get the stop of the drill-press set at the right location, particularly with the 1/4 inch plate, since the tap-drill is only intended for thinner plate stock.  If the stop is set too low, it will drag the countersink portion of the bit most of the way through the plate, leaving almost no thread.  Too high and it will presumably either strip the hole or break the bit, since the drill-press will stop while the threaded portion of the bit is still in the plate.

After a few false-starts, I had it down and started cranking out the holes:


The tap-drill was a life-saver.  Previously each hole would take about 5 minutes by the time center-punching, clamping, drilling and hand-tapping was done.  With the tap-drill it is closer to one or two, and the results are way more accurate.  A catch is that with the non-reversing spindle of the VHS drill-press it is necessary to unscrew the spindle manually.  This is a bit of a workout for the wrists, but less so than tapping by hand.  A tap-head could fix this but costs more than I care to spend.

After a bit over an hour, I had my first cheese-plate:


Then I made another one.  Then added a few rows of holes to the existing plate I'd been using as a base for the first stage.

Following up on the previous post, I've printed out fixed-end bearing blocks for the leadscrews.  These support axial loads on the leadscrew and take the load off (flimsy) motor mount.  I also tested the completed stage at 30V, hoping to reach the 100 mm/s that I'd set as a target.  I was able to reach about 40 mm/s, far short of what I'd hoped.  Switching to a proper leadscrew would fix this, however would fly in the face of 'low-cost'.  I'm pretty sure that the current feedrates are more than any spindle I plan to use can handle, however they're way too low for 3D printing.

This is where the beauty of the design-concept comes in.  With all part mounting on 1" centered, 1/4-20 holes, it is trivial to modify the machine design just by unbolting the parts and shifting them around. So I rotated the motor and fixed-support by 90 degrees and shifted some of the linear bearings a bit and added some timing pulleys.  The end result was this:


The bottom axis is belt-driven, while the top-axis is still screw-driven. All the parts are common, except a few spacers that I pressed into service as clamps for the belt so I could tension it correctly. You can see the setup below:


The fixed-end screw supports were used to hold the timing pulley opposite the motor.  The picture below shows the support with the top-axis screw sticking through.  Backing nuts onto the bearings locks the axial position of the screw.  It currently uses 608 (i.e. skateboard) bearings but should be modified to use angular contact bearings:


So how fast is it?  Much faster.  Like, a lot faster.  It's not quite what I'd wanted (a design that handled everything), but I'll settle for a set of parts that can be CNC or 3D printer with only a wrench and some re-jiggering separating them.  And what's more, it's still pretty beefy.  I loaded up the stage with (in addition to the top-axis), 16 lbs (i.e. all) of my girlfriend's free-weights.  It had no problem flinging them back and forth, shaking my coffee table vigorously in the process.


That's all for now.  I'll probably convert the other long-axis to belt-drive since I think I'm more likely to get the full machine up and running as a 3D printer rather than as a CNC, at least in the initial stages.

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....

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.