Help with servo sweep running once when a button is pressed

Hello,

I am very new to Arduino and programming.
While I have owned some for years I have found it hard to get my head around the programming side of things.

But I now have a project where an Arduino would be very useful so I am again trying to force myself to get my head around programming.

What I would like to do is press and hold a button switch which causes a servo to move say 20° to the right then return to its original position. This will need to happen only once but while the button is continually pressed.

The servo is going to actuate a trigger on a pneumatic nail remover (the trigger needs to be released before the pin will retract).

So I have tried to modify the servo sweep example and add a button which does work in the fact that when I press the button the servo starts to sweep and when I release the button it stops.
The problem is that I cannot seem to work out how to get this to happen only once (while the button is continually pressed).

I hopefully have posted my code below.

I tried adding a counter so that when the count reached 1 it would stop but I do now understand that this would not work.

If somebody could help point me in the right place to look so that I can learn how to wright the correct code that would be great.

#include <Servo.h>

Servo servo1;
const int buttonPin = 5;
int pos = 50;
int delayPeriod = 250;
int buttonState = (digitalRead(buttonPin));
int count = 0;
void setup() {
 servo1.attach(9); // put your setup code here, to run once:
 pinMode (buttonPin,INPUT_PULLUP);
 
}

void loop() {
 buttonState = digitalRead(buttonPin);
 
 if (buttonState == LOW){
 servo1.write(pos);
 delay (delayPeriod);
 servo1.write(150);
 delay (delayPeriod);
 servo1.write(pos);
 delay (delayPeriod);
 count ++;
 if (count == 1){
 servo1.write(pos);
  count = 0;

 }   
 }
}

What I would like to do is press and hold a button switch which causes a servo to move say 20° to the right then return to its original position. This will need to happen only once but while the button is continually pressed.

Expand on this.

BTW
Use CTRL T to format your code.
Attach your ‘complete’ sketch between code tags, use the </> icon in the posting menu.
[code]Paste your sketch here[/code]

So what this is going to be used for is a punch for fixing plastic tube ends into some aluminium tube.
The idea is that the tube will be pushed into the machine and up against the button switch.

I hope this helps explain things better.

Also thanks for the tip on posting code.

“This will need to happen only once but while the button is continually pressed.”

If the switch is closed (pushed) and immediately let go, do you want the sequence to finish?

The problem is that the way the machine works you do not press and release a button with your hand.
Because it is done when you slide the tube in we don't want it left there getting punched more than once.

I know that I could add a longer delay to give enough time to remove the tube but I was just wondering if there was a way to have the code only perform this once with the button pressed?

"I was just wondering if there was a way to have the code only perform this once with the button pressed?"

Yes that can be done.

But, what happens if:

  1. You close the switch and leave it closed?
  2. You close the switch and immediately let go?

The assumption is you want this thing to cycle 'once' in either case 1 and 2 above.

Yep that's correct I only want it to cycle once.
I had not thought about what would happen if it was pressed for different periods of time.

So I am now thinking that it would be nice for the button to have to be pressed for a set time before the punch operates.

This would stop accidental firing of the pin if the button is bumped.

What would be the minimum time for a valid switch press?

EDIT
No free servo here to test, to be tested:

//Version 1

//Switch must be held or released for a minimum amount of time ex: 1/2 second

#include <Servo.h>

Servo servo1;

const byte buttonPin = 5;  //closed = pushed

//machine state stuff
const byte STOPPED  = 0;
const byte START    = 1;
const byte STATE1   = 2;

byte mState         = STOPPED;

//
byte buttonState;
byte lastState;

bool machineBusyFlag = false;

//servo timing stuff
unsigned long timingMillis;
//time at moveTo = 250ms
const unsigned long delayPeriod    = 250ul;

const byte pos                     = 50;
const byte moveTo                  = 150;

//switch timing stuff
unsigned long validateMillis;
//switch must be pressed for 1/2 second to be valid
const unsigned long validatePeriod = 500ul;

//heartBeat timing
unsigned long heartBeatMillis;

//***************************************************************************
void setup()
{
  servo1.attach(9);

  //move to position    pos
  servo1.write(pos);

  //heartBeat LED
  pinMode(13, OUTPUT);

  pinMode (buttonPin, INPUT_PULLUP);
  lastState = (digitalRead(buttonPin));

}


//***************************************************************************
void loop()
{
  //********************************
  //to monitor for blocking code, toggle the heart beat LED every 500ms
  if (millis() - heartBeatMillis >= 500)
  {
    //restart timer
    heartBeatMillis = millis();
    //toggle heartBeat LED
    digitalWrite(13, !digitalRead(13));

  }

  //********************************
  readSwitch();
  stateMachine();

  //other non-blocking code

} //END of   loop()



//***************************************************************************
void readSwitch()
{
  //********************************
  if (machineBusyFlag == true)
  {
    //we are busy now don't read the switch
    return;
  }

  buttonState = digitalRead(buttonPin);

  //********************************
  //is the switch in the same position?
  if (lastState == buttonState)
  {
    //restart the validation timer
    validateMillis = millis();
  }

  //********************************
  //has the validation time passed?
  if (millis() - validateMillis < validatePeriod)
  {
    //switch has not stayed stable long enough
    return;
  }

  //********************************
  if (lastState != buttonState)
  {
    lastState = buttonState;

    //********************************
    //has the switch just been closed
    if (buttonState == LOW)
    {
      servo1.write(pos); //move to position    pos

      //machine state to the starting state
      mState = START;
      timingMillis = millis();
      machineBusyFlag = true;
    }

  } //END of   if (lastState != buttonState)

} //END of   readSwitch()


//***************************************************************************
void stateMachine()
{
  switch (mState)
  {
    case STOPPED:
      //do nothing

      break;

    case START:
      if (millis() - timingMillis >= delayPeriod)
      {
        servo1.write(moveTo);
        timingMillis = millis();

        mState = STATE1;
      }

      break;

    case STATE1:
      if (millis() - timingMillis >= delayPeriod)
      {
        servo1.write(pos);
        mState = STOPPED;
        //flag that we are not busy now
        machineBusyFlag = false;
      }

      break;

  } //END of switch/case

} //END of   stateMachine()

ServoSweep.ino (3.26 KB)

Wow thanks for that.

I will try it out later tonight and let you know how it goes.

Hi larryd,

I just tried your sketch and it works perfect.

also thanks for tacking the time to add the information on what each part of the code is doing.

I will defiantly be having a play with the code to help learn what each part is doing.

Thanks again for the help.

Hi larryd,

I have a question regarding your code.
Did you use "byte" instead of "int" to save on program size and if so is there a reason not to use byte all of the time?

Yes

Number ‘type’s.

  • boolean (8 bit) - simple logical true/false, Arduino does not use single bits for bool :frowning:
  • byte (8 bit) - unsigned number from 0-255
  • char (8 bit) - signed number from -128 to 127. The compiler will attempt to interpret this data type as a character in some circumstances, which may yield unexpected results
  • unsigned char (8 bit) - same as 'byte'; if this is what you're after, you should use 'byte' instead, for reasons of clarity
  • word (16 bit) - unsigned number from 0-65535
  • unsigned int (16 bit)- the same as 'word'. Use 'word' instead for clarity and brevity
    int (16 bit) - signed number from -32768 to 32767. This is most commonly what you see used for general purpose variables in Arduino example code provided with the IDE
  • unsigned long (32 bit) - unsigned number from 0-4,294,967,295. The most common usage of this is to store the result of the millis() function, which returns the number of milliseconds the current code has been running
  • long (32 bit) - signed number from -2,147,483,648 to 2,147,483,647
    float (32 bit) - signed number from -3.4028235E38 to 3.4028235E38. Floating point on the Arduino is not native; the compiler has to jump through hoops to make it work. If you can avoid it, you should. We'll touch on this later.

You select the ‘type’ best suited for your variables.

ex:

  • your variable does not change and it defines a pin on the Arduino. const byte limitSwitchPin = 34;
  • since an analog variable can be 0 to 1023, a byte will not do, you can select ‘int’. int temperature;
  • if your variable needs to be within -64 to +64 a ‘char’ will do nicely. char joystick;
  • if your variable is used for ASCII then you need type ‘char’, char myText[] = {“AtomicWedgie”};
  • if your variable enables some code then boolean can be used. boolean enableFlag = false;
    etc.

Again thanks for the advice!!

I did have a
play and changed the bytes to an integer and noticed that the file size was 50 bytes larger with int.

I really have learnt a huge amount in the last couple of days.

Having a project which you need to do helps but not as much as having people like yourself who are willing to help people learn.