Stepper motor synchronization

Hi folks,

I am fairly new to Arduino and I have a project that I am working on where I could use some assistance.

My project is to achieve very basic lathe leadscrew synchronization with the spindle. I'm aware of some other solutions such as ELS but I want to learn how to do this while using the resources that are available to me without having to buy into a third party solution. I'n not really interested in a full CNC option either.

I have the core components which include the Arduino, a large stepper motor (200 step/rev), appropriate stepper driver (step and direction type), timing pulleys and timing belt to drive the leadscrew, and a mechanism to provide pulses based on spindle revolution, etc... I have not built the spindle 'timing disc' yet but the concept is to fix a slotted disc to the spindle and use a photodiode to send a 5 volt pulse every time the slot(s) pass through the photodiode. Alternately a hall-effect sensor with one or multiple magnets on the disc could be another option.

I have done a bunch of research and have been looking for some code examples however I have not been able to find something similar to my requirements.

I am having a hard time figuring out the logic of how to synchronize the stepper with the spindle based on the spindle timing disc.

Here are some of the specs:

Stepper Motor (1/16 micro-stepping): 3200 steps/rev
Spindle timing disc: 1 pulse per rev (for the sake of simplicity)
Stepper to Leadscrew ratio: 1.25
NOTE: Stepper has a 15 tooth timing pulley and lathe leadscrew has a 12 tooth timing pulley.
Leadscrew: 8 TPI (3/4" acme thread)
Lathe Carriage feed based on a single spindle revolution: 0.0167"
NOTE: Eventually I will code this so that I can manually set different carriage feed rates but for the sake of this discussion, a single feed rate is sufficient.

I think these are all of the numbers that would be required in order to do the calculations. I'm having a hard time trying to figure out the formulas and I am hoping that someone here can help me to figure out the formulas and logic to make this work.

Here is the concept:

I need to be able to rotate the leadscrew so that between each pulse (rising edge) from the spindle timing disc, the lathe carriage will move a total of 0.0167 inches.

The lathe spindle will be spinning at a variable RPM. The RPM will only vary slightly based on the load. The spindle / timing disc will provide 1 pulse per revolution of the spindle. For the sake of calculations, lets use a constant RPM and say that for each spindle revolution, it takes 1.66 seconds (or 100 RPM).

My thought is that I would need to start a timer to capture the milliseconds between each pulse from the spindle. for the sake of calculations, lets just say that the spindle speed is constant and there is 1660 milliseconds between pulses

Then I would need to calculate the number of steps (X steps) required to move the carriage 0.0167".

The last part would be to figure out how to step the motor X steps over 1660 milliseconds.

Does this sounds about right? Any suggestions on how to calculate the required number of steps and then how to drive X number of steps over a given time period? Math isn't my forte so I am having troubles trying to figure out what the formula would look like.

Any help with this would be super!

Welcome to the Forum.

You have a long post that seems to conclude with a very simple problem.

The number of steps needed to match a single rotation of your spindle is something that is primarily determined by the geometry of the lathe. You can figure that out with a spreasheet.

If you conclude that for a particular screw pitch you need 1 revolution of the screw for every revolution of the spindle you will need 3200 steps (at 1/16 microstepping). If the spindle turns i revolution in 1660 millisecs or 1660000 microsecs that means 518 or 519 µsecs between steps (about 1900 steps per second). (Please check my maths carefully).

It may be better to measure time in microsecs for your application.

I think that rate of pulses would be achievable with code like in the second example in Simple Stepper Program. It uses digitalWrite() which is a slow instruction and port manipulation would be much faster if it is needed.

One thing you should consider (with the aid of your spreadsheet) is how accurately integer maths will give you the range of step-intervals that are necessary to keep step with the spindle. My guess is that if you use unsigned long integers (max value 2^32-1) you should be able to achieve satisfactory numbers. I don't think floating-point calculations would be significantly better - they are very slow and they have to be reduced to integers for actual use.

...R
Stepper Motor Basics

Hi Robin,

Thank for the reply. I was trying to figure out how to step a stepper motor X number of steps over a specified amount of time. I didn't clue in that what I needed to do this was to calculate the delay between steps (in millisec or microsec). So again, I appreciate you taking to time to read into my project and offer up some advice!

I have started building out a spreadsheet to get the required delay between steps based on different variables (Feed rate, Spindle RPM, Gear Ratio, Stepper microstepping, and leadscrew pitch).

Also, I have been reading your reply and "I think" there was a mistake. I'm trying to verify that I have the right numbers / formulas so let me break down what I have so far. If we use the example you went through.....
For an 8 TPI lead screw pitch, 1 revolution of the lead screw for every revolution of the spindle. 3200 steps needed for 1 revolution of the lead screw.
Now..... For this example, we said that the spindle is running at 100 RPM which actually translates to 0.6 seconds per revolution or 600000 microseconds per revolution (I think you calculated revs per microsecond, which was 1.6 revs per second or 1660000 microseconds, instead of the amount of time required for a single revolution of the spindle).
Using 600000 microseconds, and 3200 steps, this works out to 187.5 microseconds between steps.

To apply this to Arduino code, do you think that I could use pulseIn to capture the time between spindle rotations? And then use that time as the High and Low delay for the stepper?
Do you think i might need to use interrupts?

Here is a basic proof of concept:

void setup()
{
  pinMode(8, OUTPUT);  //Stepper Direction
  pinMode(9, OUTPUT);  //Step 
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  pinMode(3,INPUT);    //Spindle Rev pulse
  
}

void loop()
{
  unsigned long spindlerev = pulseIn(3,LOW) + pulseIn(3,HIGH);
  unsigned long stepdelay = spindlerev / 2;
  digitalWrite(9, HIGH);
  delay(stepdelay);
  digitalWrite(9, LOW);
  delay(stepdelay);
}

No, you can't use pulseIn() because it locks up your Arduino totally while it's waiting for the pulse to finish.

This is a good example where interrupts are necessary. Unfortunately for you interrupts are a mind-bending topic and it's not easy to get it programmed correctly. However, this does seem to be a pretty simple example for interrupts. Use one of the dedicated hardware interrupt pins - INT0 or INT1, which is Arduino pins 2 or 3 (on the UNO.) Setting up a simple interrupt to record the value of micros() when interrupted is actually pretty easy.

You do really need to have a slotted disc. The RPM can vary significantly within a single revolution. Making that disc with sufficient accuracy is also an issue.

You may need to read up on "phase locked loop" design. Basically, you want your stepper frequency to be matched "in phase" to the spindle and if it finds that it has fallen behind, it needs to send extra steps to catch up. Rather than trying to calculate the frequency based on time-between-triggers, think of each trigger as a request for "1000 more steps please." Then modify the frequency of the output to catch up or fall back.

there is a yahoo form that started in jan of 2006. wow, that seems so long ago,

John D did the work and created the ELS for all of us who did not have all the change gears or a lathe.

I would offer that your stepper would be better with a 2:1 pulley than the proposed 0.8 : 1 ratio. 15 drive and 12 driven is only. 0.8 and not 1.25. it is typical to have the drive screw smaller, often much smaller than the driven pulley.

a typical feed might be 0,002 in per revolution
you know the ACME screw pitch, you can calculate steps per revolution

The only thing you have to calculate is timing between pulses.

I'm glad I warned you about my maths :slight_smile:
Producing pulses as close as every 187 µsecs does not leave much time for the Arduino to do other things. Perhaps 1/8 microstepping would be sufficient.

This code

  digitalWrite(9, HIGH);
  delay(stepdelay);
  digitalWrite(9, LOW);
  delay(stepdelay);

would be better as

  digitalWrite(9, HIGH);
  delay(pulseWidth);      // only needs to be about 10 µsecs
  digitalWrite(9, LOW);
  delay(stepdelay);

as it puts all the step time into one place and makes it easier to manipulate - especially for short values.

Also, don't use delay() - see the second example in Simple Stepper Program

For very fast pulse rates you will probably need to abandom digitalWrite() in favour of port manipulation. Personally I would do a lot of experimenting to see if I could get by with fewer microsteps.

Using an interrupt to capture each rotation of the spindle should be straightforward. Assuming the sensor creates a pulse each time which can be detected by the INT0 pin (pin 2 on an Uno).

In setup() you can have

attachInterrupt(0, spindleDetect, RISING);

and your ISR code could be

void spindleDetect() {
   spindleMicros = micros();
   spindleDetectFlag = true;
}

Then your code in loop() can watch out for

 if (spindleDetectFlag == true) {
        spindleDetectFlag = false;
        prevSpindleMicros = newSpindleMicros;
        noInterrupts();
           newSpindleMicros = spindleMicros;
        interrupts();
        spindleRevMicros = newSpindleMicros - prevSpindleMicros;
   }

Use unsigned long for the different variables, except spindleDetectFlag which should be boolean.

...R

Hi guys,

Thanks for the comments and advice! This is really helping me bring this project to life. I have finished most of the mechanical work on the lathe and I will be moving onto the electronics very soon. I believe the last mechanical piece is to fabricate the spindle timing disc. I do have a lathe and a mill so I can build this disc very accurately.

Any recommendations for the slot on the timing disc (eg. should I machine a small slot or should I machine it so that for each spindle revolution, there will be a 50% duty cycle?). Or does it even matter? I guess all I really need to detect is the transition from low to high once per revolution. Let me know what you think and if you have any recommendations.

NOTE: I have re-machined the bores of the timing pulleys that I have so I now have the 12 tooth pulley on the drive side (attached to the stepper motor) and the 15 tooth timing pulley attached to the driven side (attached to the leadscrew). I believe this gives me the 1.25:1 ratio. I would probably be better off having a 2:1 ratio but I am working with what I have....

I have completed the spreadsheet to calculate the delayed between steps. when i plug in some real world numbers, this is what I get for the delay between steps:
Stepper steps per rev (1/16 microstepping): 3200
Leadscrew TPI: 8
Spindle RPM: 400
Spindle Timing (Micros per revolution): 150000
Carriage Feed rate (inches per spindle rev): 0.0024
Gear Ratio (motor to leadscrew): 1.25:1

With the above defined, here are the corresponding values:

0.0192 Leadscrew revolutions per 1 spindle revolution.
49.152 steps to rotate leadscrew 0.0192 revolution (includes gear ratio).
Delay between Steps: 3051.7578 microseconds.

That's a much more reasonable delay between steps, even at 1/16 micro stepping. If I was to switch to 1/2 micro stepping, I would be looking at a delay of 24414.0625 microseconds.

Robin - Thanks for providing some example code for how I might be able to handle the timing via interrupts. I have been trying to step through this, since I am not experienced with Arduino or programming and I think I understand what this does. Can you please confirm or correct the below description...

Each time the signal from the photo-interrupter transitions from low to high an interrupt occurs and micros(), which is the amount of time since the program started, is stored into a variable, via the ISR.
Then within the loop, we check to see if the interrupt occurred, via a flag, and if the interrupt did occur, we move the micros() value to prevSpindleMicros and then store the new micros() value into newSpindleMicros. However if the interrupt hasn't occurred, carry on executing other code.
At that point we calculate the amount of time between spindle revolutions by subtracting newSpindleMicros from prevSpindleMicros.

Observations.... The first time this code is executed and goes through the loop, the initial value within prevSpindleMicros and newSpindleMicros will be 0. So the first calculation of spindleRevMicros will actually be the time since the program started opposed to the time between revolutions.
Then when the second interrupt happens, the old micros() value gets moved into prevSpindleMicros and newSpindleMicros get the new micros() value from the ISR. At that point we can subtract the new from the old to get the true amount of time, in microseconds for 1 spindle revolution. Essentially the loop has to happen twice before we get a proper value.

Does this sound right?

Again, thanks everyone for the suggestions and examples and please let me know if I have interpreted this code correctly and if you have any suggestions about the timing disc.

Be aware that timing will, in practice, have to be done using integers (whole numbers).

Your interpretation seems to be correct and you are correct about the need to ignore the first interval. However I imagine the machine will have been running for some minutes before you start trying to cut a thread.

If you have only one "hole" in the timing disk I doubt if it matters how it is made. If there are multiple holes the gaps between them should all be the same.

A dark disc with a bit of white paint may be sufficient.

...R