An Electronic Leadscrew Controller using a Pi Pico

I haven’t researched this much. But I think there is a strong counter argument to be made on the cost/complexity issue. The classic implementation is going overboard on encoder resolution, driving a high interrupt rate, creating a lot of overhead in servicing a frequent interrupt, to give a reasonable fidelity to step timing. This runs into upper limits on encoder vs rpm.

Currently the classic algorithm is fire off a step if justified at the current encoder pulse. Change he algorithm slightly, to determine if a step is warranted before the next encoder pulse. If so interpolate at what estimated time that step should occur.

Measuring the time interval between two encoder pulses is trivial if you use a microcontroller with input event timing capture hardware. Subtraction with attention to timer wraps. At a cursory glance, the pico doesn’t qualify, but the teensy does. Simplistically just use the previous interval as a predictor of the next interval.

PLLs and etc etc are way overkill.

If you can interpolate timing to 1/10 of the encoder interval then you could use an encoder with one tenth the resolution, and thereby reduce the pulse rate on the encoder by a factor of 10. Realistically you can get 1 uS (1MHz) clocking easily, but even a 10uS capture clock resolution is sufficient.

Could you then use a 512 pulse/turn encoder to the same effect as the 4096? There is a lower bound on this as the acceleration/deceleration of the spindle becomes problematic. But for a reasonable spindle mass it would be interesting to measure/calculate an upper bound on speed changes over 1/512 of a revolution, that is still less than 1 degree. I doubt it going to be more variation than the 2 out of 3 pulses in the above, although that is an extreme case. The point is both schemes have timing error. pulse - pulse -skip can be modeled as a timing error. Can I use a 512 pulse encoder with timing interpolation and beat that error, even in the presence of acceleration? TBD but I would guess it could.

At 1000rpm, 512 pulse per rev is 117 us/pulse if my late night math is correct. So a 10uS capture clock resolution would still give a factor of 10 improvement on the (virtual) encoder resolution, performance of a 4096 pulse encoder with 1/10 the interrupt rate for the simple cost of waiting for a timer. If that timer is interrupt based (vs spin wait) that doubles the number of interrupts so we get 1/5th rather than 1/10th the interrupt rate.

Normally I would look at the desired delay and spin wait vs schedule a delay timer depending on what is more efficient.

No where in this does the complexity approach justifying an FPGA if a micro with event timing capture is used. Note I picked 512 as that is actually 1/8 of 4096, makes dividing the interval a simple matter of bit shifting. If I use a 512 pulse encoder with timing resolution justifying 16 virtual pulses (really 15+1Real) then I have a virtual 8192 pulse encoder, and beat the 4096 pulse encoder‘s effective resolution, at a much lower processor load. I’m now at skip-skip-pulse-skip-skip-pulse for what was the previous 2 out of 3. Less peak strain on your spring (maybe less chance of a loststep if using a cheap stepper?) Then, could I deal with higher RPMs where the classic system would die sooner on the higher interrupt rate?
 
Last edited:
I'm actually not planning to use interrupts much if at all. The Pico realtime core has nothing else to do. It has plenty of performance available to manage 4096 edges. It could handle quite a lot more. I already have this encoder, and many others do as well. They are readily available. Many ELS designs use it, so it is a good component to use in case one changes to another design. There's a 2,000 line variant of this model with 8,000 ppr if you want more resolution. I don't think a Pico core would have any trouble keeping up with it.

The 4096 ppr encoder is resolving the spindle to 5.3 arc minutes and this is suggesting that's not precise enough so we need to subdivide that with timers to relocate some of the microstep motor pulses by up to half a microstep. What drives this requirement?

Just to put some numbers on it. 4096 edges, 2/3 fraction is 2730 pulses per rotation, 8 microsteps, 200 steps per rotation makes 1.706 leadscrew rotations per spindle rotation, at 12 TPI one spindle rotation moves the carriage 0.142 inches for about a 7 tpi thread, each microstep moves it 0.0000521". So we're basically talking about moving these 0.00005" steps back and forth in time (really spindle rotation) by fractions of 5.3 arc minutes compared to the spindle rotation because the simple algorithm doesn't inherently subdivide the 5.3 arc minute intervals. In the case of this example, we would essentially move one of the two pulses by half of 5.3 arc minutes, so a change of 2.7 arc minutes of one edge, then the two pulses would be equally spaced with earlier and later pulses. Will the mechanical system respond any differently? A useful error estimation requires including the mechanical system's filtering effects to see if there is actually a meaningful difference. One of the problems with developing a new algorithm is doing the modelling to understand the performance details.

Microsteps aren't steps, they are adjustments in the motor current magnitudes. A real step is changing direction of currents in the coils. There's no physical spring, just the magnetic forces pulling the rotor to positions in between the full steps.

My plan is to take known-to-work encoders, motors, drivers and algorithms and implement them on a readily available and inexpensive Pi Pico which has hardware which appears to be quite well suited to the simple algorithm. Keep risk low and the parts inexpensive. If the Pico doesn't work out it is easy enough to swap to some other microcontroller (or algorithm), most of the cost is in the other components. So far I haven't seen evidence that there is a problem with this approach. Clearly some folks want to do more or follow a different path, and that's fine. We can get more complicated if there is a reason to do so. I'm not convinced there is a reason to start there. This reminds me of the Analog Vinyl vs CD Digital arguments.

This weekend I was thinking it might be fun to do a test that uses MicroPython and PIO rather than the second core for the realtime. I think it may be possible to do the simple algorithm in the Pico PIO state machine processor. I'll have to study the PIO further. It would essentially be running the algorithm on hardware. Since MicroPython can talk to these state machines it might be worth an experiment or two. One could probably use the PIO to implement or support timer designs as well. The PIO clocks at 133 MHz, and if the state set is small it will cycle quickly.

The PIO is pretty limited in features, I don't (at this point) see how to implement the full control algorithms in it, but it is perfect for generating stepper motor pulses with the proper timing - set the direction output, generate the step pulse edges with the proper timing required. Better than a conventional timer.

What I'd really like to see is one core running MicroPython, one core running C++ plus the PIO state machines available. That would give a nice balance of performance, ease of programming and real time capability. I haven't seen this done yet but it is probably coming soon for the Pico.
 
Last edited:
RP2040 Pico Timers

64 bit counter 1 uS time since boot, won't overflow for thousands of years
race free reading latch
four alarms on low 32 bits of counter, trigger interrupts, dma, PIO, etc

Other Timer Resources on RP2040

The system timer is intended to provide a global timebase for software. RP2040 has a number of other programmable counter resources which can provide regular interrupts, or trigger DMA transfers.
• The PWM (Section 4.5) contains 8× 16-bit programmable counters, which run at up to system speed, can generate interrupts, and can be continuously reprogrammed via the DMA, or trigger DMA transfers to other peripherals.
• 8× PIO state machines (Chapter 3) can count 32-bit values at system speed, and generate interrupts.
• The DMA (Section 2.5) has four internal pacing timers, which trigger transfers at regular intervals.
• Each Cortex-M0+ core (Section 2.4) has a standard 24-bit SysTick timer, counting either the microsecond tick (Section 4.7.2) or the system clock.
 
Last edited:
Alan,
You started out asking for general interest. I have tried to engage with my ideas and thoughts. I am reading some implicit messaging, so I may be totally misunderstanding, but the tone of your comments are at odds with collaborating (and approach lecturing), as you have basically said you have a plan and are set on that. I don't see any merit to continuing such a discussion, I have my own ideas as well. Nothing wrong with either side of that, but no reason to try to collaborate in light of that. I will bow out of any further discussion on your thread. Good luck with your plans.
 
Last edited:
@AlanB any code, or progress to share? Or still in planning mode? Planning is good, but unless you are a wizard, (I am not such a person) sometimes you just have to start at the problem and pick away at it, bit by bit. Basically, that's what I did with my version of ELS. Still planning parts of the system, but, plodding away at the bits (software modules) that need to be done and refining as I go along.
 
Alan,
You started out asking for general interest. I have tried to engage with my ideas and thoughts. I am reading some implicit messaging, so I may be totally misunderstanding, but the tone of your comments are at odds with collaborating (and approach lecturing), as you have basically said you have a plan and are set on that. I don't see any merit to continuing such a discussion, I have my own ideas as well. Nothing wrong with either side of that, but no reason to try to collaborate in light of that. I will bow out of any further discussion on your thread. Good luck with your plans.

I think you have raised some valid questions and made some interesting suggestions to the discussion. I probably push back more than I should, I don't mean anything personal by it. My plans are certainly not crystallized but I think it is important to start with something simple before contemplating adding complexity that we don't know is needed. Use calculations or measurements to demonstrate the requirement driving any increase in complexity. So far I've been unable to find that here. That could mean I just have not gone far enough down the learning curve yet, but I would think others would have already documented that requirement somewhere. So far I haven't found it. Make it as simple as possible, but no simpler, as it is said. :)

I like to follow the KISS design principle. Simple and solid. So it might be a bit early in the process for me to add timing enhancements to the simple fractional approach or consider a totally timing based approach. I can see a number of ways to do it, some that may be practical and some that are computationally too expensive, but for me they represent as-yet unjustified complexity and I haven't worked through them in any detail. I would be much more interested if we could find a reason to do it.

On one project we were not allowed to use steppers because they drove resonances in the mechanical system. The imperfect pulse timing is not the only issue, the steppers themselves have nonlinear torque ripple and the microsteps aren't exact all of which adds to the problem. But the lathe leadscrew systems aren't as sensitive to issues in the drive compared to a telescope. So we can apparently get away with a fair amount of imperfection in the drive. If we can't then we probably need to scrap the stepper and go for the servomotor.

I'm reminded of the story where the Russian manager of nuclear material refining is so proud when they find that the American refined material is slightly less pure than theirs. The advising German physicist points out that the Americans make it precisely good enough to do the job, and don't waste resources making it any better. :)

Anyway, I'm motivated to make something that works with minimum complexity, at least to begin with. One of my flaws. Honed from a career of working with physicists who often wanted things that were not practical to make, there are always tradeoffs...

@AlanB any code, or progress to share? Or still in planning mode? Planning is good, but unless you are a wizard, (I am not such a person) sometimes you just have to start at the problem and pick away at it, bit by bit. Basically, that's what I did with my version of ELS. Still planning parts of the system, but, plodding away at the bits (software modules) that need to be done and refining as I go along.

It looks like you are having a lot of fun with your breadboard, and making great progress. You are way ahead of me in the code department at this point. I'm learning from your experiments. My schedule is pretty full at the moment so I've done only a little study and thinking on the hardware. The Pico PIO is so different from the usual I/O programming that I need to spend some time on it to understand what it is even good for and what it might do for the ELS. I just returned from spending some days camping in the desert and had some quality time practicing with my drone. Another project that I spend too little time on...

I've got a few breadboards on my desk already so I'll have to shelve something or tear something apart to make space for this. I like to think about things for awhile before diving in. Except for those times we dive in first and ask questions later. I haven't quite committed this project to hardware yet. But talking about it here keeps it in mind and makes it more likely that it will move forward. I do enjoy the new PM-1228 lathe, even without an ELS. :)

Alan B
 
Last edited:
I am taking a simple approach to the problem. The basic algorithm is "dumb as dirt" and I like that. That makes it trivial to debug. No fancy footwork, just counting. Not computationally complex. I only care about spindle position, spindle velocity (to make sure the stepper can keep up) and stepper steps, and practically little else. All my "hard core code" is under 200 LOC. Some state machine stuff at maybe 100 LOC. The display and user interface stuff is about 600 LOC, and growing. I started coding 20 days ago, after I received the first Teensy. Been an interesting learning curve.

Some day, I too would like to integrate in my DRO position to thread to a stop AND be able to pick up the metric thread again, but that is low priority at the moment. I want to eliminate gear changing, as it is messy and slightly time consuming. That process reduces my enjoyment in the shop and takes away from the creative moment. I intend for my ELS to do both feeding and threading without changing the gearbox. If I find that changing the gearbox really is necessary, it will be begrudgingly added in, depending on how much trouble it is.

A super fancy system would be nice but, my reality is I'd be perfectly satisfied with not touching greasy gears again for threading or feeding. Basically that aligns with Mr. Clough's approach. KISS. I haven't copied anything from him code wise, primarily since his source code isn't all that well documented. His videos are instructive and well done, but his actual source code documentation is minimal.

So far, my outlay has been pretty small, a toy stepper motor, driver, and power supply, a rotary encoder, a 3.2" touch display, a couple of Teensy 4.1 processors, and a home built driver buffer board. This hardware has allowed me to do some interesting development and refine some concepts that were fuzzy to me. Certainly has made me believe that the effort is worth pursuing. At this point, it is very likely that I will have a working system, before TI delivers any more Launchpad F280049C boards. Getting ready to buy a NEMA 24 stepper set up.

It would be great if you got started. At some point, you just have to dive in. I dove in, got a bit over my head for a bit, but I can report the water is great!
 
I am taking a simple approach to the problem. The basic algorithm is "dumb as dirt" and I like that. That makes it trivial to debug. No fancy footwork, just counting. Not computationally complex. I only care about spindle position, spindle velocity (to make sure the stepper can keep up) and stepper steps, and practically little else. All my "hard core code" is under 200 LOC. Some state machine stuff at maybe 100 LOC. The display and user interface stuff is about 600 LOC, and growing. I started coding 20 days ago, after I received the first Teensy. Been an interesting learning curve.

Some day, I too would like to integrate in my DRO position to thread to a stop AND be able to pick up the metric thread again, but that is low priority at the moment. I want to eliminate gear changing, as it is messy and slightly time consuming. That process reduces my enjoyment in the shop and takes away from the creative moment. I intend for my ELS to do both feeding and threading without changing the gearbox. If I find that changing the gearbox really is necessary, it will be begrudgingly added in, depending on how much trouble it is.

A super fancy system would be nice but, my reality is I'd be perfectly satisfied with not touching greasy gears again for threading or feeding. Basically that aligns with Mr. Clough's approach. KISS. I haven't copied anything from him code wise, primarily since his source code isn't all that well documented. His videos are instructive and well done, but his actual source code documentation is minimal.

So far, my outlay has been pretty small, a toy stepper motor, driver, and power supply, a rotary encoder, a 3.2" touch display, a couple of Teensy 4.1 processors, and a home built driver buffer board. This hardware has allowed me to do some interesting development and refine some concepts that were fuzzy to me. Certainly has made me believe that the effort is worth pursuing. At this point, it is very likely that I will have a working system, before TI delivers any more Launchpad F280049C boards. Getting ready to buy a NEMA 24 stepper set up.

It would be great if you got started. At some point, you just have to dive in. I dove in, got a bit over my head for a bit, but I can report the water is great!

Your approach sounds perfect.

I'm wondering what you mean by possibly needing to change the gearbox for feeding? Perhaps you mean what I was talking about - supporting more than one gearbox setting. I doubt that will be necessary. It's something I've not seen anyone need to do. I want to do it for experimenting and testing, not because I think it will be necessary. It is also simple to do, once the actual ratios are known. It doesn't change the control algorithm. That reminds me. I want to use the DRO to map out the ratios precisely. I've already noticed that the manual is apparently off on feed rates. I suspect they got the threading numbers right. I'll measure them with the DRO and spindle turns counter that I have and see.
 
Last edited:
Your approach sounds perfect.

I'm wondering what you mean by possibly needing to change the gearbox for feeding? Perhaps you mean what I was talking about - supporting more than one gearbox setting. I doubt that will be necessary. It's something I've not seen anyone need to do. I want to do it for experimenting and testing, not because I think it will be necessary. It is also simple to do, once the formula and ratios are known. That reminds me. I want to use the DRO to map out the ratios precisely. I've already noticed that the manual is apparently off on feed rates. I suspect they got the threading numbers right. I'll measure them with the DRO and spindle turns counter that I have and see.
I was referring to your supporting more than one gear box setting. I actually don't know my gb ratios and would have to measure them. So, in this case, the muse is insufficient for me to be stirred to measure it. Once I install the Encoder, should be easier to measure, but that moment hasn't come.

Have lots of stuff still to do on this project still, so I am focusing on the essential tasks first. Coming up with an easy but safe way for the operator to start the machine with the correct parameters is currently on the top of my list.
 
One reason that one might want to support multiple gearbox settings with the ELS is to be able to optimize the tradeoffs between maximum spindle speed, ELS motor speed, torque, and effective step sizes. I agree that it is not something that ELS systems generally do, at least I've not seen any that did in terms of putting it into the user interface. They pick one setting and do everything with that. I do note that Clough changed his gearbox setting when he changed motors due to the torque/speed capability of the new motor. Many folks have fiddled with the drive ratio during initial testing to find the compromise they wanted by changing the belt ratio between the motor and gearbox input.

I'm in the situation where I have a lathe that has a 15 speed gearbox. It's enough to cover most imperial ratios but still has a lot of change gears to cover a few imperial pitches and many metric pitches. It doesn't cover everything so folks have figured out how to 3D print a few more change gears and get more ratios. I can print more gears but I want to avoid the change gear mess. So it can clearly benefit from an ELS.

This lathe also inherently has three speeds with one gearbox setting - threading, feeding and cross feeding all have separate engagement controls and gear ratios from one gearbox setting. So it essentially has 45 speeds. So this needs to be in the user interface anyway. Probably best to display all three all the time. In both imperial and metric units. The display design will be interesting.

There's also a 3 year warranty on this new machine so I'm extra motivated to avoid modifying it. I want a bolt-on, removable ELS.

So what I'm planning is to have the user interface take an input for the gearbox ratio setting - A1 through C5. I'm planning to use a rotary encoder knob for the user interface, so one can step through them by rotating a knob. As the ratios are selected the display will show max spindle speed and effective step sizes for each setting. If a high ratio is selected the ELS motor's max speed may be reached before the spindle reaches full speed. There are a lot of tradeoffs going on here - motor torque vs speed, torque multiplication in the gearing, the fractional ratio is changing so the averaging in the pulses vs mechanical system is also changing, etc. If one is threading at low speed, a low max spindle speed is acceptable and smaller effective step sizes are desirable. If one is feeding (higher spindle speeds are likely) so it may not be and the larger inherent gearing ratio in the feed system makes step sizes smaller already. I'd like the operator to be able to choose the gear ratio within the gearbox's settings to use for the job.

The ratio doesn't change the algorithm or the equations, it just changes the fraction. It doesn't add complexity to the control algorithm. It does add complexity to the user interface. It's a complexity inherent in the lathe.

What I expect will happen in real life is that a compromise gearbox setting will be chosen and that setting will be used 95% of the time. But now and then it might be useful to have the flexibility. During testing one can push the system to see if the ELS motor errors out, and select appropriate max RPM for the user interface advisory display.

Plans are subject to change. :)
 
Back
Top