So I got the bug, and finally decided to move forward with an ELS for my 55year old Craftsman 6" lathe. I've had it in the back of my mind for many years, as I just can't stand changing gears. A few similar threads here gave me the confidence to move forward. My concern has always been whether or not a stepper motor with its' discrete step sizes would provide the precision needed. Looks like at least a few folks have made it work. I was never concerned about the design, as in a previous life (I'm a retired EE), I worked in telecom as a hardware engineer, designing embedded processor boards and the associated firmware to run them. That should give you an idea of how far back that goes, as now a days, the hardware and firmware are handled by different groups/individuals. Since I was the guy that understood hardware and software, after a few years and projects, I ended up running the engineering department.
Enough about me, I've used the PI Pico to build a few projects, and I'm fascinated with the onboard programmable state machines (PIO). It's amazing how much you can get out of a handful instructions. The instruction space is limited to 32 instructions, but again, there's a lot you can do with it.
Jump ahead to the spoiler... I've got it working, and can machine common ANSI and Metric threads, and set feed rates from .0005 to well, anything I want, but have arbitrarily feed limited to .0625.
So what's the theory?
first, a major requirement for my method to work...
1) The feed rate must be such that there are always more encoder pulses than stepper steps. In other words, over any interval, there can never be more than one step between encoder pulses. To make this happen, you have to set the gearing of the encoder and stepper based on the greatest feed per revolution you want to support. I selected 5TPI as my maximum.
I decided to see If I could use the state machine to map the rotary encoder phase(s) into stepper pulses. After writing a few simulations I decided it was definitely doable if I could stuff the needed code into 32 instructions. My simulations proved that if you assume the encoder and stepper are perfectly aligned at count 0, meaning step 0 (call it S0) is at the perfect position for encoder pulse 0 (call it E0), that for standard ANSI and Metric threads, there are a finite number of encoder pulses such that at some count Sn, once again the stepper is perfectly aligned (well within .1% of a step size) with an encoder pulse En (see paragraph and pic below). This alignment that occurs at Sn is a point at which I can loop back to the beginning of my algorithm. Between pulse 0 and pulse n, I calculate the next step feed value, and when it lands between two encoder pulses, I create a step at the pulse the step rounds up or down to. I pic is worth a thousand words.
In the pic below, the top line represents encoder pulses, and the bottom line stepper pulses. The circled encoder pulses are positions where I decide to step the stepper motor. Notice that the encoder pulse selected (circled) is the pulse closest to the stepper's actual value. The position error is the difference between the circled encoder position and the actual stepper position, but it's so small, it's negligible. The error is less than half an encoder pulse, and for my case with stepper pulse resolution of .000156" (.0625 feed screw pitch / 400 steps per feed screw rev), the error is much less than the stepper resolution. Also notice that at the last step, the encoder position matches up with the stepper position. This is important because at this point, I can loop back and start from the beginning. This is the case I mentioned above that for ANSI and Metric threads I can find this point
My idea was to use a bitmap that had a one to one correspondence with encoder pulses. Once a feed has been specified, I'd calculate the bitmap (circled encoder positions above), and write it to a buffer that would be DMA'd to the state machine. The state machine would be triggered by the rotary encoder and for every trigger pulse it would load in the next bit in the bitmap, which would indicate whether or not a stepper pulse was needed.
So that's the basis for the design... In subsequent posts (if anyone is interested), I'll go into the state machine code and how I setup the DMA to keep the state machine fed.
Enough about me, I've used the PI Pico to build a few projects, and I'm fascinated with the onboard programmable state machines (PIO). It's amazing how much you can get out of a handful instructions. The instruction space is limited to 32 instructions, but again, there's a lot you can do with it.
Jump ahead to the spoiler... I've got it working, and can machine common ANSI and Metric threads, and set feed rates from .0005 to well, anything I want, but have arbitrarily feed limited to .0625.
So what's the theory?
first, a major requirement for my method to work...
1) The feed rate must be such that there are always more encoder pulses than stepper steps. In other words, over any interval, there can never be more than one step between encoder pulses. To make this happen, you have to set the gearing of the encoder and stepper based on the greatest feed per revolution you want to support. I selected 5TPI as my maximum.
I decided to see If I could use the state machine to map the rotary encoder phase(s) into stepper pulses. After writing a few simulations I decided it was definitely doable if I could stuff the needed code into 32 instructions. My simulations proved that if you assume the encoder and stepper are perfectly aligned at count 0, meaning step 0 (call it S0) is at the perfect position for encoder pulse 0 (call it E0), that for standard ANSI and Metric threads, there are a finite number of encoder pulses such that at some count Sn, once again the stepper is perfectly aligned (well within .1% of a step size) with an encoder pulse En (see paragraph and pic below). This alignment that occurs at Sn is a point at which I can loop back to the beginning of my algorithm. Between pulse 0 and pulse n, I calculate the next step feed value, and when it lands between two encoder pulses, I create a step at the pulse the step rounds up or down to. I pic is worth a thousand words.
In the pic below, the top line represents encoder pulses, and the bottom line stepper pulses. The circled encoder pulses are positions where I decide to step the stepper motor. Notice that the encoder pulse selected (circled) is the pulse closest to the stepper's actual value. The position error is the difference between the circled encoder position and the actual stepper position, but it's so small, it's negligible. The error is less than half an encoder pulse, and for my case with stepper pulse resolution of .000156" (.0625 feed screw pitch / 400 steps per feed screw rev), the error is much less than the stepper resolution. Also notice that at the last step, the encoder position matches up with the stepper position. This is important because at this point, I can loop back and start from the beginning. This is the case I mentioned above that for ANSI and Metric threads I can find this point
My idea was to use a bitmap that had a one to one correspondence with encoder pulses. Once a feed has been specified, I'd calculate the bitmap (circled encoder positions above), and write it to a buffer that would be DMA'd to the state machine. The state machine would be triggered by the rotary encoder and for every trigger pulse it would load in the next bit in the bitmap, which would indicate whether or not a stepper pulse was needed.
So that's the basis for the design... In subsequent posts (if anyone is interested), I'll go into the state machine code and how I setup the DMA to keep the state machine fed.