Help me modify this "Simple Stepper Progam"

Hi all, would anyone be interested In helping modify this code? First off, I did read the "Planning and Implementing an Arduino Program" written by Robin2 and did start to put together a program, then I noticed Robin2's "Simple Stepper Program" is very similar to my needs and much simpler then what i had created, so I thought it might be more practical just to adjust from his code.

Essentially I would like the clockwise button (buttonCW) to turn the motor at 9 RPM. I would like the counter clockwise button (buttonCCW) to spin at a faster arbitrary speed. (Whatever speed my battery voltage can support)
I would also like to add a home and limit switch to the device.

What I am using this for is a barndoor tracker. Basically when the motor runs CW at 9RPM the device will slowly move to track the sky. When the device reaches the end of it's mechanical limits it hits the "rewind limit switch" and this slews the motor counter clockwise until the device hits the "home"" limit switch. If all goes well the device is running again at 9RPM clockwise after it hits the home limit.

In theory I guess the whole operation could be controlled by just 2 limit switches, however I would like to have a couple of buttons to add control. Example at times I may need to rewind the device early, or perhaps pause the device.
In reality I suppose the "Rewind limit switch" and "Rewind" button could actuality be the same thing ie: 2 parallel switches wired to one pin on the Arduino.

I will be using the UNO, Pololu DRV8834 Low-Voltage Stepper Motor Driver Carrier, NEMA 17 200 step motor and 11.1v (10.8v) Lithium battery packs.

I would like to use 1/32 micro-stepping as well.

Anyhow I think that covers it, any help would be appreciated.

// testing a stepper motor with a Pololu A4988 driver board or equivalent

// this version uses millis() to manage timing rather than delay()
// and the movement is determined by a pair of momentary push switches
// press one and it turns CW, press the other and it turns CCW

byte directionPin = 9;
byte stepPin = 8;

byte buttonCWpin = 10;
byte buttonCCWpin = 11;

boolean buttonCWpressed = false;
boolean buttonCCWpressed = false;

byte ledPin = 13;

unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long millisBetweenSteps = 25; // milliseconds

void setup() {

  Serial.begin(9600);
  Serial.println("Starting Stepper Demo with millis()");

  pinMode(directionPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  
  pinMode(buttonCWpin, INPUT_PULLUP);
  pinMode(buttonCCWpin, INPUT_PULLUP);
  
}

void loop() {
	
	curMillis = millis();
	readButtons();
	actOnButtons();
	
}

void readButtons() {
	
	buttonCCWpressed = false;
	buttonCWpressed = false;
	
	if (digitalRead(buttonCWpin) == LOW) {
		buttonCWpressed = true;
	}
	if (digitalRead(buttonCCWpin) == LOW) {
		buttonCCWpressed = true;
	}
}

void actOnButtons() {
	if (buttonCWpressed == true) {
		digitalWrite(directionPin, LOW);
		singleStep();
	}
	if (buttonCCWpressed == true) {
		digitalWrite(directionPin, HIGH);
		singleStep();
	}
}

void singleStep() {
	if (curMillis - prevStepMillis >= millisBetweenSteps) {
		prevStepMillis += millisBetweenSteps;
		digitalWrite(stepPin, HIGH);
		digitalWrite(stepPin, LOW);
	}
}

Number_5:
Essentially I would like the clockwise button (buttonCW) to turn the motor at 9 RPM. I would like the counter clockwise button (buttonCCW) to spin at a faster arbitrary speed. (Whatever speed my battery voltage can support)
I would also like to add a home and limit switch to the device.

All that is perfectly feasible but it pretty much amounts to asking someone to write the program for you. If that is what you want then ask in the Gigs and Collaborations section and be prepared to pay.

If you want to do it yourself we will certainly try to help, but you need to do most of the work

Break it down into small pieces.
Start by getting the CW button to move the motor at a different speed from the CCW button. (I am assuming you only want the motor to move while the button is pressed).

Have you looked at Stepper Motor Basics. if you want a stepper to move quickly you need a high voltage.

I presume you have checked that the current required by the motor can be comfortably supplied by the driver?

...R

Robin2:
All that is perfectly feasible but it pretty much amounts to asking someone to write the program for you. If that is what you want then ask in the Gigs and Collaborations section and be prepared to pay.

If you want to do it yourself we will certainly try to help, but you need to do most of the work

I followed your advice and started to write my code when I came across a conflict. I was unable to understand why you used "byte" while in a similar example program somebody else uses "#define". I tried asking a simple question as to the difference in this application and did not get a simple relevant answer that applies to the context of what I was doing. Ergo I was stumped from the start, I learn better when I understand the implications of my actions.

Robin2:
Break it down into small pieces.
Start by getting the CW button to move the motor at a different speed from the CCW button. (I am assuming you only want the motor to move while the button is pressed).

I would like the motor to keep moving CW once the button is pressed. The device can be stopped by hitting the button again, or when the device hits the limit switch I would like it to stop, then rewind to a "home" limit switch.

The Driver board is actually still in the mail, I hope to have it tonight or tomorrow, then I am going to actually try your example etc.

Robin2:
Have you looked at Stepper Motor Basics. if you want a stepper to move quickly you need a high voltage.

Yes, I have read that, thanks. The important feature of this machine is that it spins the motor CW at a steady 9 RPM. The "high speed" rewind CCW feature does not have a required speed, just whatever I can get with my voltage and equipment, perhaps through trial and error.
The motor is a ~2.4V 1.7A Bipolar stepper being powered with a chopper driver board and 10.8V 5200mAh LiPoly battery.

Robin2:
I presume you have checked that the current required by the motor can be comfortably supplied by the driver?...R

Yes, I have a 1.7A motor that I pan on running at 1.5A or a little lower with the Pololu DRV8834.

It's nice to know I have you on board. When my driver board gets here I will start on getting the motor to spin at 2 different speeds first.

Much appreciated.

Cheers.

Functionally it does not matter whether you use #define or create a byte variable. #define does not use up any memory space for storing the variable.

Don't start different Threads about the same project. Keep all your questions in one place so everyone has access to all the information and does not have to wonder if the question has already been answered somewhere else. I think I saw the #define question but I did not associate it with this Thread or remember who had asked the question. Also I thought your question was whether to use pin 9 or pin 9 and that it had been answered. (Unless I am all mixed up)

I would like the motor to keep moving CW once the button is pressed. The device can be stopped by hitting the button again

Then you need to arrange for pressing the button (i.e. when the button changes from not-pressed to pressed) to change a variable (known as a state variable) - perhaps call it runClockwise. Then the code for moving the motor can cause it to move clockwise if (runClockwise == true)

Later on you can make the code in your limit switch function turn that variable to false which would override the present setting but would not prevent another button press from getting it going again (obviously once the limit switch is clear).

...R

Number_5:
The motor is a ~2.4V 1.7A Bipolar stepper being powered with a chopper driver board and 10.8V 5200mAh LiPoly battery.

Yes, I have a 1.7A motor that I pan on running at 1.5A or a little lower with the Pololu DRV8834.

Absolute max for DRV8834 is 11.8V, 3S LiPo battery is nominally 11.1V, upto 13V fully charged. Spot
a problem?

Use the DRV8825?

Robin2:
Functionally it does not matter whether you use #define or create a byte variable. #define does not use up any memory space for storing the variable.

OK, awesome.

Robin2:
Don't start different Threads about the same project. Keep all your questions in one place so everyone has access to all the information and does not have to wonder if the question has already been answered somewhere else. I think I saw the #define question but I did not associate it with this Thread or remember who had asked the question. Also I thought your question was whether to use pin 9 or pin 9 and that it had been answered. (Unless I am all mixed up)

My apologies, it was attempt to address specific question in an attempt through the problem, duly noted I will keep everything here.

Robin2:
Then you need to arrange for pressing the button (i.e. when the button changes from not-pressed to pressed) to change a variable (known as a state variable) - perhaps call it runClockwise. Then the code for moving the motor can cause it to move clockwise if (runClockwise == true)

OK cool, this will give me some direction to work with, much appreciated.

Robin2:
Later on you can make the code in your limit switch function turn that variable to false which would override the present setting but would not prevent another button press from getting it going again (obviously once the limit switch is clear).

...R

That sounds like a plan, I will report here in a day or so after I try it out.

Cheers.

MarkT:
Absolute max for DRV8834 is 11.8V, 3S LiPo battery is nominally 11.1V, upto 13V fully charged. Spot
a problem?

Use the DRV8825?

I am counting on the nominal voltage of the LiPo pack to be 10.8V. The DRV8834 seems more appropriate for my 2.4V motor and enables me to still use LiPo batteries that I have on hand, albiet with now low-voltage protection for now. (The DRV8825 is for 8.5V to 45 V)

Battery pack will be more like 3 x 4.1V or 4.2V when fully charged unless it has a stepdown converter in it.
3.6V is more of a discharged state.

CrossRoads:
Battery pack will be more like 3 x 4.1V or 4.2V when fully charged unless it has a stepdown converter in it.
3.6V is more of a discharged state.

It is a difficult answer because I originally purchased had a constant voltage L/R type driver and was advised to get a constant current driver, rightly so for the type of motor I have, as I now understand.

I chose the DRV8834 because it is more or less compatible with the motor I already had on had, which was a gift. This motor is a low voltage version compared to the more common ~12v type NEMA 17 motors.

The reality is I can wire up some 7.2v LiPo packs just as easily as the 10.8v. It was suggested in the literature I read to go with the highest practical voltage possible, (For top speed), when using these chopper drivers.
Since ultimate speed is not a priority the 7.2v might work out fine, I don't think this is a demanding application for that size of motor, lots of gear reduction involved and the payload moves very little over the coarse of time so I don't see acceleration being an issue much either.

I really hate to get into a debate on what voltage a LiPo cell really "is", especially when asking advise, but in my limited experience they don't hold that peak voltage very long before they settle into a plateau of around ~3.6v.

The specification of "10.8v" was enough of a hint for me that it is a LiPo compatible driver board, as this would be an otherwise odd arbitrary number to choose as an upper limit. I consider 11.1v as the marketing voltage for battery packs, whereas 10.8v would be more appropriate voltage for electronics design. IMO

OK so moving forward I will try this project out at 7.2v. I will use the now extra two LiPo cells to add overall capacity so I'm gaining there. Essentially I will end up with a 2S3P pack of around ~7,800mAh.

In addition to my above reply, the datasheet for the DRV8834 has 2.5v-10.8v as the recommended operating conditions. The absolute maximum voltage range is -0.3v to 11.8v, not that they endorse those types of operating conditions for extended periods of time.

As I say though, I have no issues with using 7.2v for my application, that is fine, I just wanted to mention this for future reference should this come up in a search somewhere.

Number_5:
The DRV8834 seems more appropriate for my 2.4V motor

This is a major misunderstanding. That motor would probably work best with 30v, 50v or maybe more. What matters with a stepper motor is the current in the coils and the stepper motor driver can be set to limit that so as to protect the motor.

It should work well with 10v or 12v provided you don't need the highest speeds.

...R

I suppose it would have been better to have said the DRV8834 is more appropriate for my motor and battery combination, as this driver might work well with lithium batteries as low as 3.6v.

It lends itself slightly better to portable applications as in my case since I have a variety of Lithium packs waiting to be utilized, as opposed to purchasing and lugging around SLA batteries.

I am making some progress with the code, currently reading up on buttons, constants and state change detection. The driver board should be here this afternoon, with any luck I will have the motor spinning to some degree this evening.

Cheers.

Well a bit of an update, the driver board arrived, I've set the current and run a few example sketches, everything is working good in that regard.

However I am still stumped with the code. I have tried to jam the "runClockwise" and "if (runClockwise == true)" into the code here and there with no luck.

I'm not sure if I should be replacing the "if (buttonCWpressed ==), or adding something to it.

I promise I am trying lol, I can seem to find the right little sketches to get a simple LED to toggle on the online Arduino simulators, but this has me baffled as the examples are fairly different from one another, I can't seem to get them to play along nice.

Any hints would be appreciated.

Cheers.

Number_5:
Any hints would be appreciated.

Post the latest version of your code.

...R

Sure thing. It seems as though I haven't added enough, at least compared to other examples.

// testing a stepper motor with a Pololu A4988 driver board or equivalent

// this version uses millis() to manage timing rather than delay()
// and the movement is determined by a pair of momentary push switches
// press one and it turns CW, press the other and it turns CCW

byte directionPin = 9;
byte stepPin = 8;

byte buttonCWpin = 10;
byte buttonCCWpin = 11;

boolean buttonCWpressed = false;
boolean buttonCCWpressed = false;
boolean runClockwise = false;

byte ledPin = 13;

unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long millisBetweenSteps = 25; // milliseconds

void setup() {

  Serial.begin(9600);
  Serial.println("Starting Stepper Demo with millis()");

  pinMode(directionPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  
  pinMode(buttonCWpin, INPUT_PULLUP);
  pinMode(buttonCCWpin, INPUT_PULLUP);
  
}

void loop() {
  
  curMillis = millis();
  readButtons();
  actOnButtons();
  
}

void readButtons() {
  
  buttonCCWpressed = false;
  buttonCWpressed = false;
  runClockwise = false;
  
   if (digitalRead(buttonCCWpin) == LOW) {
    runClockwise = true;
   }
   if (digitalRead(buttonCWpin) == LOW) {
    buttonCWpressed = true;
  }
  if (digitalRead(buttonCCWpin) == LOW) {
    buttonCCWpressed = true;
  }
  if (digitalRead(buttonCCWpin) == LOW) {
    buttonCCWpressed = true;
}

void actOnButtons() {
}
  if (buttonCWpressed == true) {
    digitalWrite(directionPin, LOW);
    singleStep();
  }
  if (buttonCCWpressed == true) {
    digitalWrite(directionPin, HIGH);
    singleStep();
  }
  if (runClockwise == true)  {
    digitalWrite(direction pin, LOW)
  }
}

void singleStep() {
  if (curMillis - prevStepMillis >= millisBetweenSteps) {
    prevStepMillis += millisBetweenSteps;
    digitalWrite(stepPin, HIGH);
    digitalWrite(stepPin, LOW);
  }
}

You need to change the code in readButtons() so that it checks if the button has changed from not-pressed to pressed. The way you have it, and the way I wrote the demo, it resets the value of buttonCCWpressed back to false as soon as you release the button. Hence you need to keep your finger on the button.

It may be that you only want to set buttonCCWpressed back to false when the other button is pressed - or when a 3rd STOP button is pressed.

This may be a suitable solution - it is derived from my demo code

void readButtons() {
	
	//~ buttonCCWpressed = false;
	//~ buttonCWpressed = false;
	
	if (digitalRead(buttonCWpin) == LOW) {
		buttonCWpressed = true;
		buttonCCWpressed = false; // <---- new
	}
	if (digitalRead(buttonCCWpin) == LOW) {
		buttonCCWpressed = true;
		buttonCWpressed = false; // <--- new
	}
}

...R

That works very well, thank you for adding the annotation, it was very helpful. That more or less concludes the button aspect of my project. I will still continue to try and work in the runClockwise variable on my own that allows the CW button to start AND stop, but I won't hassel you for that. You have been very helpful in making the device functional. :slight_smile:

I am going to leave the buttons as they are for the time being and get familiar with the millis function this evening, see if I can adjust the speed.

I think the millis function is desirable in this situation as I want the motor to tick away CW at a steady rate regardless of what the Arduino may or may not be doing. In other words when I add features in the future, the operation of those features shouldn't interfere with the CW step rate.

For now I am assuming I can adjust this line: unsigned long millisBetweenSteps = 25; // milliseconds

If I was to want full steps and required 9RPM from a 200 step motor, I think I would need to set the above line to 30 milliseconds. (Equals 1800 steps per minute) Now I would like to use 1/32nd micro-stepping, so I'm assuming I need to send it 32 times faster signal, ie: 57,600 steps per minute instead of 1800. (Less than 1 millisecond if I have done the math right)
Does this sound correct, or is it possible with the Arduino to pulse fast enough with the millis function?
If not I could probably live with 1/16th microstepping. Perhaps I should just be searching this part, but thought I would ask as we have been discussing your example anyways.

Once again I really appreciate this Robin2, I am very excited about this project, it is a very practical and captivating first project for me.

OK so I tried a value of 0.5 milliseconds, the motor appears to accept that, so I tried 1.041666666666667 milliseconds and it seems to work.

I used the stopwatch on my phone, it appears to make 9 rotations in around 58.5 seconds. I am sure there is some delay in me pressing start on the timer etc.
It would be more important to have consistency, rather than ultimate accuracy as I can adjust for timing, I don't know how the Arduino fairs in that regard with it's crystal.

I forgot to mention above that I will still need to eventually figure out a faster independent speed for the CCW direction, but again no big deal I can work on that, with experience I hope to tackle that.

Anyhow, things are progressing nicely.

The variable millisBetweenSteps only takes integer values and millis() only returns integer values

If you want finer control use microseconds and micros(). Note that the value reurned by micros() increments in steps of 4.

Another option for awkward timing is to do N steps at interval Y followed by M steps at interval Y-1

...R

Hmm yes I was suspecting that perhaps I was witnessing 1 millisecond whole steps rather than 1.04. I'm not sure what it was doing when I set it to 0.5, it did move quickly, nonetheless I did come across the micro function you mention last night and agree that seems to be appropriate.

If that doesn't work out then I will try the "N steps at interval Y followed by M steps at interval Y-1".

Have a good day.