Faster Speed Needed for Homing Function

Hi,
I am running Mega 2560 with Easy Driver @ 1600 microsteps to achieve 8mm / revolution of a screw jack. The screw jack is used for positioning a wire anywhere from 0mm to 800mm.

I need a homing function during setup to insure the position of the screw jack returns to zero. I have this running. My problem is that, when moving toward the home position of 0, the speed is WAY to slow.

Can anyone suggest a better method than this...

// Start Homing procedure of Stepper Motor at startup

// NOTE: While HOMING, need faster speed

while (digitalRead(home_switch)) {  // Do this until the switch is activated   
  
  digitalWrite(A1, LOW); // Direction Pin
  digitalWrite(A0, HIGH);// Step
  digitalWrite(A0, LOW); // Step
 
}

// NOTE: While ZEROING, need slower speed... below code is OK


while (!digitalRead(home_switch)) { // Do this until the switch is not activated

  digitalWrite(A1, HIGH); // Direction Pin
  digitalWrite(A0, HIGH); // Step
  digitalWrite(A0, LOW);  // Step

}

The current code moves 2 centimeters / minute. If the position on start was at 80 cm, it would take 40 minutes to home this!!!

The first digitalWrite in each loop is invariant. Moving those two lines out of each loop will increase the speed by 33%.

Hi,
Sorry for the lack of reference.. I made a change to the code to show what the pins are doing.
Yet, even if the code is still wrong, 33% would be like the time it takes to whip an egg with the overall goal to bake a cake

BTW... I'm using the AccelStepper Library.

As Coding Badly suggest, first remove the direction from the while loop.

You can replace the digitalWrite() with direct port manipulation. You can toggle a pin by writing to the input register. Pin Analog 0 is on register F, bit 0.

//digitalWrite(A0, HIGH);// Step
  // digitalWrite(A0, LOW); // Step
 PINF |= 1;

EDIT: You can also replace the digitalRead() of the home switch in the while() with the direct port reading.

PINF |= 1;
Address      Name
-----------  ----
0x0F (0x2F)  PINF
  1. I/O registers within the address range $00 - $1F are directly bit-accessible using the SBI and CBI instructions. In these registers, the value of single bits can be checked by using the SBIS and SBIC instructions.

Whew! You got lucky.

However, the OUT instruction is one clock cycle instead of two so, depending on how the optimizer behaves, this could be faster...

PINF = 1;

This code switches off all other bits in PINF, that is probably not intended.

Hey guys,

Appreciate the input, but you've gone way over my head on this. And it looks like you guys are debating who is right here.

Anyway, I tried commenting my code and adding the direct port code by Cattledog

  //digitalWrite(A0, HIGH);// Step
  // digitalWrite(A0, LOW); // Step
 PINF |= 1;

And things just started making a humming sound. tried also with PINF = 1; Still humming sound. Reverted back to my original code... humming sound. Couple of reboots and all is back to 'slow' normal

Also, I'm not really sure this would solve the problem (2cm / minute for 80 cm = 40 minutes to home from max position).

When using stepper.runToNewPosition(), which is obviously 'blocking', during normal execution of the program, I get some nice acceleration and speed. But because it is blocking, I can't use this for the homing function. Can you recommend some other method/function that a noob can wrap his head around which would help here. :slight_smile:

Thanks

Whandall:
This code switches off all other bits in PINF, that is probably not intended.

The "whew" in my post is because the compiler optimizes @cattledog's snippet to a bit-set instruction. So, in this particular case (PINF / m2560 processor) either works.

However, for the reason I stated (reply #4) and because relying on an optimization that may not always happen is a fool's errand I agree with you that a simple assignment is the correct choice.

gufinov:
But because it is blocking, I can't use this for the homing function.

I can't help but notice that you mentioned that important detail rather late in this thread. This is your moment to add any additional pertinent details. At least if you want any more assistance from me.

gufinov:
And things just started making a humming sound. tried also with PINF = 1; Still humming sound. Reverted back to my original code‚Ķ humming sound. Couple of reboots and all is back to ‚Äėslow‚Äô normal

The snippet of code in your Original Post

while (digitalRead(home_switch)) {  // Do this until the switch is activated  
  
  digitalWrite(A1, LOW); // Direction Pin
  digitalWrite(A0, HIGH);// Step
  digitalWrite(A0, LOW); // Step
 
}

should produce steps at a very high rate I suspect several thousand per second. Maybe in fact it is too fast for the motor.

You need to write a short complete program to learn what works and what doesn’t. Then you can post the complete program which will make it much easier to help.

…R
Stepper Motor Basics
Simple Stepper Code

Fellas,

I apologize if you felt like I led you down the wrong path or left too much detail out. A friend, who is a good programmer (unlike me), once stated that when asking for help, don't throw in all the code if it really isn't needed. Provide your intentions and keep it simple. I thought I did that.

So anyway, the problem seems to have been in the lack of any delay between steps. Thanks @Robin2 for pointing me to your 'Simple Stepper Program'. I had actually read this and other articles of yours just a week or so ago. I used that program today, modified to my needs for the switch, and all was well. So I looked back at my code and realized that the delays were missing - argh!

So here is the whole code. But I gotta warn you.. there really isn't much here. I did add a bunch of comments to help with understanding... but likely way more than necessary.

// SHORT TERM GOAL (this exercise): Homing Switch Test
// END GOAL: run a linear actuator with available travel distance between 0 - 800 mm and exact positioning down to any 1 mm within that range
// REASON FOR TEST
// When equipment is shutdown, or loss of power, on bootup, the position of the linear actuator (screw jack) is unknown. Calculating distances would not be possible.
// HARDWARE
// Arduino mega2560
// 4 wire bi-polar stepper with Easy Driver running 1600 steps per revolution and a direct connection to a screw jack via coupler
// 1 Meter screw jack : 1 revolution = 8 mm linear travel : effective range 0-800mm 
 
// PHASE 1: On Setup, run stepper in a negative direction and try to achieve a high rate of linear travel speed from any given point, returning the actuator to the home switch
// upon reaching limit of travel (to home), switch will close, causing the motor to reverse direction (move forward)
// Upon moving forward and releasing the microswitch, the motor will stop and position can be set to 0

// NOTE: This is only one (1) of many potential ways to move the motor.... looking for the best, and potentially the fastest option. 

#include  "AccelStepper.h" // AccelStepper Library

// AccelStepper Setup
AccelStepper stepper(1, A0, A1);  // 1 = Driver
                                  // Arduino A0 connected to STEP pin 'Easy Driver'
                                  // Arduino A1 connected to DIR pin 'Easy Driver'
                  
// Setting up the Microswitch for homing

#define home_switch 9 // Pin 9 connected to MicroSwitch N.O. position and common to GND


  
void setup(void) {


// Setup the Microswitch Pin Mode
  pinMode(home_switch, INPUT_PULLUP);

  
// Start Homing procedure of Stepper Motor at startup

  digitalWrite(A1, LOW);      // (LOW = anti-clockwise / HIGH = clockwise)
  
  while (digitalRead(home_switch)) {  // while the switch is not activated, move the motor
    
  digitalWrite(A0, HIGH);      // Step pin High
  digitalWrite(A0, LOW);     // Step pin Low 
  delay(1);
  }

  digitalWrite(A1, HIGH);    // (LOW = anti-clockwise / HIGH = clockwise)
  
  while (!digitalRead(home_switch)) { // while the switch is activated, move the motor
    
  digitalWrite(A0, HIGH);      // Step pin High
  digitalWrite(A0, LOW);     // Step pin Low
  delay(10);
  }
}

void loop(){
  // nothing yet
}

A friend, who is a good programmer (unlike me), once stated that when asking for help, don’t throw in all the code if it really isn’t needed. Provide your intentions and keep it simple. I thought I did that.

If you don’t know what is causing your problem then how do you know what code is needed ?

The stickies at the top of this forum describe the best way to ask a programming question. One of the suggestions when the problem is part of a large program is to write a small program that demonstrates the problem. Doing this often reveals the real problem and solution and is sound advice.

This approach was suggested by Robin in reply #9

@UKHeliBob,

I know you guys get a lot of beginners in here and it can be frustrating trying to help someone with a lack of experience. I didn't come here to cause problems and I certainly don't want to ruffle the feathers of the Masters, and judging from your experience and posts, that would include you. I followed all advice presented and used some of my own thinking on what might be adequate. On top of that, I did exactly as Robin2 asked. I provided my complete short program code and took the time to comment on what I was ultimately trying to achieve. And I certainly didn't ask anyone to do the hard work for me. I am simply looking for enlightenment. So I'm not sure why you jumped in here just to offer criticism - but I'm ok with it. Though I do think it's only fair that I get to explain my position a bit.

I believed the original snippet of code and context was sufficient to understand the goal - move a motor backwards until it hits a switch, move it forward till it opens the switch, but do it faster than the code presented. There really isn't much more to it. And if you look at my original post and then the full code, you will realize this is definitely the case. I simply removed the pin setups and the include for the accelstepper library and concentrated on the actual movement of the motor. Crazy how the simplest of things are so easily overlooked.

Based on my lack of experience with Arduino and steppers, I actually thought that little snippet was correct and was simply wondering if there was a better way to achieve faster speed. With all of the functions available in AccelStepper, and I don't know how many other libraries, I just thought someone would throw a function out there. Jumping into port mapping went over my head so I was simply trying to keep things simple.

This reference and comment helped tremendously!....

Robin2:
The snippet of code in your Original Post

while (digitalRead(home_switch)) {  // Do this until the switch is activated  

digitalWrite(A1, LOW); // Direction Pin
 digitalWrite(A0, HIGH);// Step
 digitalWrite(A0, LOW); // Step

}



should produce steps at a very high rate I suspect several thousand per second. Maybe in fact it is too fast for the motor.

That and the link to an example led me down the path to a fix, rather than a new method/function. At this point, I realized something must be actually wrong.


Now about that port mapping thing... I am interested in a little understanding.
How would you achieve motor function with direct pin access? Does it need to toggle high and low?...

a figurative loop {
PINF |= 1;
PINF |= 0;
delay(1);
} // repeat

What would have been the correct code to achieve a simple rotation (forward and backwards) of a stepper using this porting method?

Thank you all for the advice, assistance, and yes - the criticism. I can only do better from here on :slight_smile:

PINF = 1;  // toggle bit
PINF = 1;  // toggle bit
delayMicroseconds(1000);

I feel combining a very fast method of bit manipulation with a delay is... strange.

Whandall:

PINF = 1;  // toggle bit

PINF = 1;  // toggle bit
delayMicroseconds(1000);



I feel combining a very fast method of bit manipulation with a delay is... strange.

Hi @Whandall,

I am confused by the comment which follows your code because, from the arduino reference, there doesn't appear to be much difference between delay() and delayMicroseconds();

Did you mean you would not use either? Or you prefer to use delayMicroseconds() over delay(). In my sample I used delay(1) == 1 microsecond whereas you put delaymicroseconds(1000) == 1 second.

Also, does PINF = 1; perform a high low toggle in 1 instance? Or is it a literal toggle that autoswitches from its current state, thus requiring 2 instances as you coded, like this...

PINF = 1; // toggles 'lets say to HIGH'
PINF = 1; // toggles to opposite of previous
// and is a delay() or delaymicroseconds() required?

and pending your answers, I will assume something like this (following) would work as a change to my existing code:

while (digitalRead(home_switch)) {
PINF = 1;
PINF = 1;
delaymicrosends(3);
}

Also, does the #1 in PINF = 1; represent the position of the Analog 1 pin (A1) to the Atmega 2560 microchip.. and thus PINF = 0; would represent Analog Pin 0 (A0)

my reference to this last question: https://www.arduino.cc/en/uploads/Hacking/PinMap2560big.png

In all digital values you have an uncertainty of one LSB.

So a delay(1) will delay between 65 ns and 1000 ¬Ķs, delayMicroseconds(1000) will delay between 900 and 1000 ¬Ķs.

Writing a bit in a PINx register toggles the output with a single instruction.

Whandall:
In all digital values you have an uncertainty of one LSB.

So a delay(1) will delay between 65 ns and 1000 ¬Ķs, delayMicroseconds(1000) will delay between 900 and 1000 ¬Ķs.

Writing a bit in a PINx register toggles the output with a single instruction.

So just to clarify..

1 . you would or would not use a delay/delayMicroseconds (at least in reference to my existing setup) (yes/no)

2 - within a loop, you only need 1 execution of PINF = 1; to get a HIGH and LOW toggle and thus stepper movement (true/false)

3 - the '1' in PINF = 1; represents the Pin position on the 2560 microchip?

Thanks for the education :slight_smile:

For accurate delays below 5 ms I would use delayMicroseconds, normally I do not use delays.

Each write to the PINx toggles, for one step you need both low an high phases, so two toggles.
Whether it takes one ore two loop rounds per step does not really matter, does it?
You get a higher frequency if you have more toggles in a row, but the stepper will give up long before.

Again, extra fast bit manipulations in combination with delays are a waste of effort,
it does not matter, the stepper is so much slower, you can savely use digitalWrite().

Which pin resides in what register and in what position is documented in the datasheet and the pin mapping of the Arduino.
Finding out this information at runtime from an arbitrary pin makes digitalWrite() as slow as it is.
You can have a look at the source of that routine.

Whandall:

PINF = 1;  // toggle bit

PINF = 1;  // toggle bit
delayMicroseconds(1000);



I feel combining a very fast method of bit manipulation with a delay is... strange.

I am addressing this comment to @gufinov rather than to @Whandall - I just used the easy quote.

The advice to use PINF etc was provided because (based on your description) people thought you needed more speed when in fact you needed less speed - a longer interval between pulses.

Using digitalWrite() and micros() or millis() to manage the timing of your steps will be fine - as in the second example in my link.

...R
Edit to add "digitalWrite and"

@Robin2 and @Whandall

Thank you both again. I sincerely appreciate the quality of your explanations and the time you've taken to present them. The information has been very helpful.

Cheers!