Controlling motor using two buttons

I am trying to create a simple code using two buttons.

  • When you click one button, it should rotate by 90 degrees clockwise for a set acceleration and speed
  • When you click on another button it should rotate by 90 degrees anticlockwise for a set acceleration and speed i.e., to go back to the original position
  • Right now, the issue is that I need to click on the buttons a couple of times to activate. Its probably because of the state of the button but I am unable to debug that. I want to avoid using the state of the button and just take a click sensor to activate the rotation of the motor.

I also want to add a physical limitation in case someone accidentally moves the object by a couple of degrees, I want to reset to the previous position reached by the motor - I have not yet figured out how to do this or whether I need to add any controlling element.

I am including a link to Wokwi simulation as well 2 button test

I am not an expert in programming and this is a DIY project so I am learning things as I try different ideas and learn tricks.

Thank you!

#include <AccelStepper.h>

#define dirPin 8
#define stepPin 9

// Define button pins
#define buttonPinCW 2
#define buttonPinCCW 3

AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);


void setup() {
  // put your setup code here, to run once:
  stepper.setMaxSpeed(20); // Set maximum speed value for the stepper
  stepper.setAcceleration(1); // Set acceleration value for the stepper
  stepper.setCurrentPosition(0); // Set the current position to 0 steps

}


void loop() {
  
  boolean CWActive = digitalRead(buttonPinCW);
  boolean CCWActive = digitalRead(buttonPinCCW);

  if(CWActive == true) {
    //Serial.println("Going Clockwise");
    //stepper.setCurrentPosition(0)
    stepper.moveTo(50);
    stepper.run();
  
  }

  else if (CCWActive == true) {
    //Serial.println("Going Counter Clockwise");
    //stepper.setCurrentPosition(0);
    stepper.moveTo(-50);
    stepper.run();
    

  }


}

Non sense! I see no attempts in the code you posted. There is always serial.Print() showing the results of some instruction. And there are LEDs you can add to show the results of something.

4 Likes

To play with buttons,
pinMode(your_pin, INPUT_PULLUP);
might help. To start with...

1 Like

So your switches are wired to ground when closed. And you never set the pins to INPUT_PULLUP. You might want to think about what digitalRead will return when the switches are open, and the input pins aren't connected to anything.

Furthermore, your code looks at the state of the pin, not the event of being pressed. Something else to think about.

2 Likes

Try and see what decklaring the button pins will do.
Debounce the buttons.

Thanks Paul! I am not an expert in programming and this is a DIY project for me :slight_smile: I am learning on the go :slight_smile:

Consider These:

In particular, read the "How to Wire and Program a Button" stuff. Your inputs are floating, and if you use INPUT_PULLUP, they will be in the HIGH state and odd things will happed with your ==true logic.

The original position is 0, and there is nothing in the code to moveTo(0).

Consider also the MobaTools Stepper Example 3 -- it has a couple jog buttons and uses a nice state machine to do interesting logic handling:

2 Likes

Hi @vimit,

As you're not setting the input/output mode of the two buttons pins you're using the default mode of the mcu, that is OD INPUT. you'll have to set the pinmode to INPUT_PULLUP, or set an external pullup or pulldown depending on your preferences.

You also need to debounce the button to ensure a clear and unique signal start and keep it stable, simply add a library to take care of that. In the simulation I see you added the toggle library, but never used it in your code.

Start there, then come back with the results to go further.

Good Luck!
Gaby.//

1 Like

I gave you two concrete ideas that all beginners use to debug their code.

1 Like

The toughest thing about your project to "learn" (not just "do") is reading a button press. You need to "wire" it, hold it steady when not active, know when it goes from "not pressed" to "pressed, disregard "noise" ("bounce"), know when the button goes from "pressed" to "not pressed" and register the button "was pressed" (as opposed to "is pressed."

Write your code while on the shoulders of giants who have written libraries that do all that thinking. These libraries and examples are linked in the other comments.

The "button press" I learned from this forum...

2 Likes

I looked at the code and did not immindiantly see a need for any button handling, on the assumption that the run() method blocks.

It does not. It's not just non-blocking, it actually needs to be called repeatedly in order for the motor to take the necessary steps (one at a time) to the targa position. From the documentation:

Note that each call to run() will make at most one step, and then only when a step is due, based on the current speed and the time since the last step.

Which would suit many of us just fine. @vimit might do better with an interrupt-driven stepper library that has more a launch and forget style of control for which now, yes, proper button handling will be necessary.

a7

1 Like

Thank you everyone for all your great input and guidance!! I learned new things along the way! I was able to simplify using a toggle switch and added a LnED as well.

Updated simulation - Updated simulation using a switch

The next challenge for me is to figure out how to use closed loop control in case the user (in this case myself) accidentally rotates the object by a couple of degrees. Object in this case is a counter table so a slim glass (more like a turn table). I'll reach out here again for questions. Any guidance would be helpful! :slight_smile:

#include <AccelStepper.h>

#define dirPin 8
#define stepPin 9
#define switchPin 6

AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);

void setup() {
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  
  stepper.setMaxSpeed(20); // Set maximum speed value for the stepper
  stepper.setAcceleration(1); // Set acceleration value for the stepper
  stepper.setCurrentPosition(0); // Set the current position to 0 steps
}

void loop() {
  
  if(digitalRead(switchPin) == HIGH) {
    digitalWrite(LED_BUILTIN, digitalRead((6)));
    stepper.moveTo(50);
    stepper.runToPosition();
  }
  else if (digitalRead(switchPin) == LOW) {
    digitalWrite(LED_BUILTIN, digitalRead((6)));
      stepper.moveTo(0);
      stepper.runToPosition();
   }
  }

Nice and thanks for sharing the simuation.

As I suggested, this sidesteps all issues around switch bounce…

… at the cost of blocking during the sweep one way or the other.

So for example we can't change in the middle of a sweep. In fact, we can't do anything whilst waiting.

In addition to learning more about pushbuttons and handling them, a big area for study is how to make this code non-blocking.

I don't have the three links I usually post in this circumstance at hand, I am sure others will help point the way.

a7

1 Like

  if(digitalRead(switchPin) == HIGH) {
    digitalWrite(LED_BUILTIN, digitalRead((6)));
    stepper.moveTo(50);
    stepper.runToPosition();
  }

  • You should look at a switch’s change in state rather than a switches level.

  • Try to be consistent in writing code: digitalRead(switchPin) verses digitalRead((6))

  • Read switches every 50ms to handle switch bounce.

  • Moving a stepper all at once to the destination, blocks your code.

1 Like

Thank you for these tips! I can definitely try to make it cleaner and robust

Hi @vimit,
I'll add something to the situation noted by @alto777:

The change in the slide switch in the middle of a sweep will be ignored until the quarter turn ends... and then it'll be read, so you'll have your rotation backwards started even if you changed your mind of reversing, but forgot to set the slide switch back.
I mean... it's ok if you decide to label your switch with something like oº position, 90º position and it's what you really want, but if it's not, you're justa adjusting your whole project due to lack of debouncing procedure.
Once again, you can always use a debouncing library or a switch building library and keep the reigns of your project!

Good Luck!
Gaby.//

1 Like