Friday, April 12, 2013
ARM motion controller Pt1
I picked up a cheap LPC1768 dev board from EBAY, <$40 for a 100MHz ARM processor with a 2.8 inch 320x240 touch screen, with the intention of using it as a printer driver.
A couple of weekends ago I stuck a pololu 4988 stepper driver in a breadboard, ran a few wires, connected a stepper and plugged the step pin into one of the GPIO outputs. A couple of hours later I was running the motor off the board at speeds upwards of 1000RPM, all in all a promising test.
So the next task is writing a real motion controller, now I could just port one of the many existing reprap firmwares from arduino, or even have gone back to the original source and just ported GRBL, but where is the fun in that. For me half the reason for doing it is to better understand the what works and the limitations, and the core of a motion controller isn't actually all that complicated.
First thing I needed to do was be able to coordinate motors so that multiple axis would move together at a requested velocity.
My initial thought on implementing this was to use the RIT timer on the LPC which fires an interrupt when it reaches a comparator value.
Basically you compute the velocity for the move
And from that compute the number of ticks for each axis
You then just figure out which axis moves next, and set the comparator to that value. at the end of that interrupt you repeat the process and update the comparator appropriately.
This has the advantage of only firing the interrupt when a step on an axis is needed, and the precision of the output is basically limited to a few timer clock pulse, given the clock is running at 25MHz that's pretty damn good precision.
So I built a simple event based system and wrote the code to set up movement across multiple axis. There were two issues.
The first was that as the Cortex-M3 which the LPC1768 is based on doesn't have hardware floating point, so I made the decision to do everything as fixed point, In attempting to retain as much precision as possible I ended up with a 64 by 64 bit divide (which is probably 200+ cycles) in the setup code. This on it's own I could have lived with and I could have probably done some things like breaking down long moves to remove it.
The second issue came up when I finally thought about implementing acceleration, every time a step is taken you have to determine when the next step should be, with constant velocity this is trivially just an add of the interval you calculated above, with acceleration you basically have to solve
for t for every step of every axis, accumulating error as you do so.
OK so we can make this work but is there a better approach?
Yes, but I'll leave it for the next entry.