An Electronic Lead Screw controller using a Teensy 4.1

Nice progress. For software testing one might want a knob adjustable rate, but a sweep is useful.

I was looking at the Spindle Encoder. The one I have appears to have Open Collector outputs, so perhaps strong pullups to 3.3V could be used, avoiding a level shifter altogether. Might be worth testing. With proper cabling and grounding it might not be necessary to go to receivers or differential signaling.
I'm just getting used to this Teensy. So playing around with creating a hopefully known frequency sweep. That way I could know how many counts I am supposed to have, which is good for testing. A easy spinning pot would also be good for testing more random changes, along with a reversal switch.

You inspired me to take a look at the encoder. My Omron E6B2-CWZ6C has open collector outputs! However, I have to power the encoder with 5V-24VDC. So I could power the encoder with my 24V supply, but use pull ups to the Teensy 3.3V supply. I'm guessing a value of 100 ohms would be ok for the pull up. The Omron will sink 35mA max. (3.3-0.4)/100 = 29mA, which is good enough. Jury is still out whether there will be signal integrity issues... For at least the cheapo stepper driver, I can use some 2n2222 transistors. I may use bus drivers to drive the transistors, but I will start out with a direct drive of the transistor when everything is local to my bench.

Starting to look at the quadrature decoder now... Doesn't look as hard, but, you know how that goes... Might use the little stepper to drive the Omron and to read out it's position. Of course the shafts are the wrong size, but that is fixable.

Need another terminal block adapter for my second Teensy, and will make a plate to bolt down both Teensy's. Right now there's nothing to restrain anything and my scope probes can drag the whole assembly off the desk! Things will only get worse when more things get plugged together.
 
I would select pullups for 10-15 mA rather than the full current. 2N2222's should do fine. Blue masking tape to keep cables from pulling experiments off the bench. :)

For decoding I like to use a small lookup table. Feed it with the present and previous A and B bits, so a 16 element table. The outputs from the lookup table can be tailored to make the overall code most efficient. Up and down counts in separate bits, or a count/direction in two bits, or zero when the encoder didn't move. You can also get error counts from a third bit if the state transition is not a legal one. Only one bit should change from previous to present inputs. Counting the errors measures noise or insufficient computing performance. There are lots of ways to do quadrature decoding. Using the built in quadrature hardware is more complicated and at the end of the day doesn't really save anything or provide anything extra at these low rates. I want the code to trigger on each edge and generate a pulse to the stepper with as little latency and variation as practical. For the most part we don't even care about the direction once it gets moving and things are going the right way.

I implemented a rotary knob with a Teensy 2 using this lookup table technique and you could not spin the knob fast enough to generate errors. That one was using pin change interrupts on the two inputs and sending the resulting knob position over USB. The encoder had 512 edges per rotation. That CPU clock was 37 times slower than the Teensy 4.1, and it had zero problems doing several knobs at once.
 
Last edited:
I would select pullups for 10-15 mA rather than the full current. 2N2222's should do fine.

For decoding I like to use a small lookup table. Feed it with the present and previous A and B bits, so a 16 element table. The outputs from the lookup table can be tailored to make the overall code most efficient. Up and down counts in separate bits, or a count/direction in two bits, or zero when the encoder didn't move. You can also get error counts from a third bit if the state transition is not a legal one. Only one bit should change from previous to present inputs. Counting the errors measures noise or insufficient computing performance. There are lots of ways to do quadrature decoding. Using the built in quadrature hardware is more complicated and at the end of the day doesn't really save anything or provide anything extra at these low rates. I want the code to trigger on each edge and generate a pulse to the stepper with as little latency and variation as practical. For the most part we don't even care about the direction once it gets moving and things are going the right way.

I implemented a rotary knob with a Teensy 2 using this lookup table technique and you could not spin the knob fast enough to generate errors. That one was using pin change interrupts on the two inputs and sending the resulting knob position over USB. The encoder had 512 edges per rotation. That CPU clock was 37 times slower than the Teensy 4.1, and it had zero problems doing several knobs at once.
Yes, maybe 270-330 ohms is better to start out with.

Think I am going to try using the hardware quadrature decoder in the Teensy 4.1 QuadEncoder library using interrupts. It looks really simple to use. I do need to read up on how they deal with over and underflow. It looks like in the code they detect it, but don't do anything. That's not so good. For a 100 KHz encoder waveform (max of encoder) rollover 32 bits, is in 11.9 hours, or much less if running forward then reverse. Could be seconds! I suppose if one sets the position counter to the middle, then won't overflow for 5.9 hours, continuously on in the same direction, which is a long time on a lathe. The PJRC forum has been really responsive on helping out, been great for working through understanding the libraries. Think I will ping the PJRC forum for ideas on this. Still 5.9 hours of continuous high speed spindle time is a lot for a hobbiest.
 
I've been very impressed with Paul and his libraries, they have been of high quality and well supported. It's one of the excellent things about the Teensy.

Perhaps whenever the spindle is not turning, just reset the quadrature counter to midrange. You can make your code handle over/underflow easily enough, but it is something that requires testing and is somewhat unnecessary. In any case you want an interrupt on each change of count, and figuring out what is going on with the counter is pretty much the same magnitude of code as figuring out the quadrature.

With this encoder the 100 khz corresponds to just shy of 6000 rpm, my lathe tops out at 2,000 so it would take even longer to over-range. Your code should be running fast enough to see each count, so it only has to worry about zero or one count in either direction. The value of the register itself is not really useful. The code just has to decide whether to send a pulse to the stepper or not, and the best ways to do this in a precise way and avoid all the rare overflow issues are to use the fractional gear ratio directly, essentially overflowing for each stepper pulse. Then instead of an overflow being a rare event that is hard to test for, the overflows happen constantly and frequently and hence are easy to test for and get right. It only requires add/subtract/compare, never a division so is very fast and doesn't have precision issues to worry about.
 
I've been very impressed with Paul and his libraries, they have been of high quality and well supported. It's one of the excellent things about the Teensy.

Perhaps whenever the spindle is not turning, just reset the quadrature counter to midrange. You can make your code handle over/underflow easily enough, but it is something that requires testing and is somewhat unnecessary. In any case you want an interrupt on each change of count, and figuring out what is going on with the counter is pretty much the same magnitude of code as figuring out the quadrature.

With this encoder the 100 khz corresponds to just shy of 6000 rpm, my lathe tops out at 2,000 so it would take even longer to over-range. Your code should be running fast enough to see each count, so it only has to worry about zero or one count in either direction. The value of the register itself is not really useful. The code just has to decide whether to send a pulse to the stepper or not, and the best ways to do this in a precise way and avoid all the rare overflow issues are to use the fractional gear ratio directly, essentially overflowing for each stepper pulse. Then instead of an overflow being a rare event that is hard to test for, the overflows happen constantly and frequently and hence are easy to test for and get right. It only requires add/subtract/compare, never a division so is very fast and doesn't have precision issues to worry about.
It seems you have thought about this before. I'm coming in cold, attempting to learn as I go. Not quite sure I am grasping your last paragraph, but I'll think about it and mull it over.

It doesn't seem too difficult to force over or underflow to test it. Just preset the counter to near the top and go forward and detect the overflow flag. Set a bit in the ISR to know it happened. Use the state of the bit in your calcs. Likewise for the underflow. Set position count near zero, go in reverse... Is there more to it than that?

At the speeds I'd want to run in my lathe, practically speaking, would take a long, long time to over-range. And as you said, if the spindle wasn't turning for a while, one could change the position register to mid range. Of course there's a handful of other things to do, but it's sort of an initialization process, or perhaps a re-initialization.
 
One can approach this problem from several different directions. Accumulating the rotary encoder in a register and calculating the corresponding position of the leadscrew as many have done is the CNC approach. Necessary if you are building a CNC. Of course if one is doing that then perhaps just install LinuxCNC or similar and be done with it, they've done a better job already there.

If we approach this as an electronic gearbox we don't need absolute position at all. We just need encoder events feeding a gear ratio generating a pulse train to drive the leadscrew/feed motor controller. I actually covered a simple algorithm for that earlier in the thread. Essentially it's a differential approach rather than an integral approach. For example if we want a pulse ratio of 1/2 the algorithm needs to output a motor pulse every other spindle encoder pulse. The actual shaft ratio will also include the ratio of microsteps to spindle encoder steps, but in the end the ratio is just an integer fraction between input and output pulses that the algorithm implements. For each encoder pulse it does an add, and a compare, when it overflows a subtract and an output pulse is generated. It is super simple. And about as exact as we can get, and no feedback loops are required. It's essentially a code version of gears implementing a ratio between encoder and motor pulses. It's fairly simple integer fraction arithmetic. No need for floating point. No multiplication or division in it's simple difference form.

If you want to add CNC functions like machining to a shoulder, etc, then you need to accumulate the position for comparing, which of course could also be done easily enough in addition. But to implement just the gearing ratio the position accumulation isn't really needed.

It's not hard to test the wraparound once, but if you retest at every code modification it gets old quickly. If it isn't needed, why do it?

Lots of ways to do this, as you know. Enjoy the journey, whatever path you choose. The hard part is mounting the I/O on the lathe. The code and UI is the fun part. :)
 
Last edited:
Got some transistors! Built up a driver board. Have to laugh, it is a 2.2K resistor to the base of the transistor, and a transistor x 3 for the ENA, DIR and PUL signals. Checked the basic design on the Teensy to make sure it would drive it.

Seeing the teeny terminal blocks on my Teensy breakout board has made me want some for the driver board. It will make it a lot easier to wire up! Ordered some 2 pin, 3 pin and 6 pin mini terminal blocks. These guys have 2mm screws on them, they are small, since they are at 0.1" spacing. They fit perfectly into 0.1" perf board.

Also assembled and soldered a terminal block board for the second Teensy. Last night modeled some of the pieces in FreeCAD so I can make a plate for all of this stuff to attach to. The wires are stiff enough that they push the lightweight boards and NEMA 11 motor around.

Had a little bit of excitement when I hooked up my radar project and the Teensy. When I attached the battery to the radar there was a loud pop of something blowing up. Found a little darkened spot on the board. Needless to say, I hastened to disconnect the battery, a 6V 4.5AH sealed lead acid. So much haste that I yanked the wire out of the crimp terminal.

After my heart stopped racing, I then connected a spare M4 board and confirmed that I could run two different instances of Arduino, and two different processors, one in each instance. That will make some things easier. I want Teensy #1 to be the stimulus for Teensy #2.

So it seems I need to check if my radar is dead, or a supply bit the dust. Fooey. A tantalum capacitor exploded. I've heard of them popping before when reverse biased. Pretty sure it was put in right. It is at a 16V tantalum on a 6V supply. 2x derating. Maybe I should get a 25V cap. The half of the case where the polarity marking would be has blown up so I don't have any additional information. Guess I'll replace it and see if anything else is INOP. Not what I was expecting! It's only the second capacitor explosion I've witnessed. First was a PC power supply electrolytic exploding - that was loud and totally unexpected. This was a much smaller pop, but equally unexpected. I honestly think this was coincidence, have well over 100 hours of operation time on this radar board stack.
PXL_20220509_192312470.jpgPXL_20220509_192342331.jpg
Replaced the cap. My radar is operational again. Glad it was just a crappy component. Output of an A(440Hz) tuning fork. Right on the money!
PXL_20220509_200928656.jpg
Ok, back to Teensy's and driver boards.
PXL_20220509_202107816.jpg
I used the low temp solder paste (and a hot air gun) to attach the PSRAM and ethernet connector (6 pin) on the backside of Teensy#2. Melt point is supposedly 137C. The low temp lead free solder paste is also nice to lower the melt point of standard lead free solder when you need to do rework. Just apply some paste and the lead free solders mix and melt at a lower temp. This helps a lot especially if you are using solder wick to clean out the through holes. Kind of a do it yourself ChipQuik.
 
Got the Omron rotary encoder hooked up and am running using the HW quadrature encoder in the Teensy. There's a few things I don't understand just yet, but it is somewhat encouraging. Need to wire in my stepper motor/driver/stepper driver board. It seems the shaft coupler supplied for the encoder is 6mm to 6mm. My NEMA 11 stepper has a 5mm shaft. Is there a simple thing I can do to connect them together? Make a 6mm rod, drill it out to 5mm and slit it? Probably a good idea to use a collet for this.
 
those stepper drivers are garbage. fine for testing but they are really not worth the trouble of wiring up. I had good luck with the stepperonline "1-CL57Y-24HE40" on my lathe. the newer open loop drivers are also good, "DM542Y"
I uderstand both the motor and driver are not very good. They are only for me to get my feet wet. Don't have much outlay into it at this point. I was looking at the 4Nm NEMA 24 stepper at steppersonline. That driver seems familiar as well. I didn't want to sink a lot of cash into something that I couldn't get going. This minimizes my cost exposure.

I'm still not quite sure I will get everything to work. Been a steep learning curve so far. Once I get the basic framework figured out, I will get a bit more serious about real hardware, and even user interfaces. I don't even have the basic system figured out in my head yet. Once I figure that out, it will become much easier for me.
 
Back
Top