Cycle 3 LEDs with one button (FSM???)

Hello

I have had some great help in another thread, making leds flash at a certain voltage.

https://forum.sparkfun.com/viewtopic.php?f=32&t=39084

My above project is a servo, that controls a three position hydraulic switch, and a certain color led for each position.

Currently, it operates with a DPDT switch. But to save space, I want to use a single mom push button.

I want to cycle between red and blue leds by clicking button. Switch on Green led (turn red & blue off) with a press.

If I can do this, I’m sure I will be able to use the format to control my servos.

Here is the existing code, a product of the help i received here previously…

/* 	Rev 1.1 of iCTD with battery monitoring, by ASF

Big thanks to Mee_n_Mac on Sparkfun
	01/09/2014
Battery monitoring is commented out for clarity
*/ 


#include <Servo.h>

Servo myservo; 			// create servo object to control a servo

int pos = 0; 			// variable to store the servo position
int selectedPos = 2; 		// sets the selected servo position to middle
const int buttonPin = 2; 	//sets pin 2 as button
const int buttonPin2 = 3; 	//sets pin 3 as button
const int ledPin1 = 10; 	// sets pin 10 as LED for Climb Blue
const int ledPin2 = 11; 	// sets pin 11 as LED for Trail Green
const int ledPin3 = 12; 	// sets pin 12 as LED for Descend Red
int buttonState = 0; 		//sets button 1 as off
int buttonState2 = 0; 		// sets button 2 as off

//declare the constants used
const float tripVolts1 = 7.5; 	//above this voltage the LEDs are always on 8
const float tripVolts2 = 7.5; 	//above this voltage the LEDs blink at rate 1 7.5
const float tripVolts3 = 6.6; 	//above this voltage the LEDs blink at rate 2 6.6
const float scaleFactor = 0.595;//ratio of divided down voltage to battery voltage
const int blinkRate1 = 1; 	//blink rate1 in Hz (blinks/sec)
const int blinkRate2 = 2; 	//blink rate2 in Hz (blinks/sec)
const int blinkRate3 = 4; 	//blink rate4 in Hz (blinks/sec)
const int battPin = A0; 	//number of analog pin used to measure battery voltage

//declare the variables used
boolean blinkState = false; 	//variable to control LEDs on or off
unsigned long blinkPeriod = 0; 	//period in msec of blinking
unsigned long blinkTime = millis(); //variable to store when blink state was last changed
float battVolts = 0; 		//battery voltage



void setup()
{
  myservo.attach(9); 		// attaches the servo on pin 9 to the servo object
  pinMode (buttonPin, INPUT); 	// sets button as input
  pinMode (buttonPin2, INPUT);	// sets button as input
  pinMode (ledPin1, OUTPUT); 	// sets led as output
  pinMode (ledPin2, OUTPUT); 	// sets led as output
  pinMode (ledPin3, OUTPUT); 	// sets led as output


  digitalWrite(ledPin1, LOW);
  digitalWrite(ledPin3, LOW);
  digitalWrite(ledPin2, HIGH); 	// will probably remove this
  myservo.write(90); 		// sets servo to mid trail position
  delay(500);
  myservo.detach();
  }

void loop()
{

  buttonState = digitalRead(buttonPin);
  buttonState2 = digitalRead(buttonPin2);

  if (buttonState == HIGH && buttonState2 == LOW && selectedPos != 1)   //if button 1 is pushed and servo is not in position 1
  {
    myservo.attach(9);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
   digitalWrite(ledPin1, HIGH);          // Comment out when using blink code below
    myservo.write(45);      		// servo moves into climb blue
    delay(250);
    myservo.detach();
    selectedPos = 1;

  }
  else if (buttonState2 == HIGH && buttonState == LOW && selectedPos != 3)//if button 2 is pushed and servo is not in the 3rd position
  {
    myservo.attach(9);
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, HIGH);        // Comment out when using blink code below
    myservo.write(135);   		// servo moves into descend red
    delay(250);
    myservo.detach();
    selectedPos = 3;

  }
  else if (buttonState == LOW && buttonState2 == LOW && selectedPos != 2)//if button is in middle position and servo is not in middle position
  {
    myservo.attach(9);
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin2, HIGH);        // Comment out when using blink code below
    myservo.write(90);      		// servo moves into trail
    delay(250);
    myservo.detach();
    selectedPos = 2;
  }
}

 //_________________________________________________________________________---

/*   Commented out for clarity
  
 if (selectedPos == 1) 				// climb
  {
   
     //measure the divided down voltage and convert back into battery voltage
  battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
  if (battVolts > tripVolts1) { 		//check voltage above or below high trip point
    blinkPeriod = 0; 				//voltage above, special condition for no blinking
  } 

  //now blink the LEDs if conditions are correct
  if (blinkPeriod == 0) { //special condition means no blinking
    digitalWrite(ledPin1, HIGH); 		//turn led on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; 		//change blinkState
      blinkTime = millis(); 			//reset blinkTime
    }
    digitalWrite(ledPin1, blinkState); 		//turn led on or off per blinkState
  }
    delay(blinkPeriod/10);
  }
 //_________________________________________________________________________---

 else if (selectedPos == 2 ) 			//trail
 {
  //measure the divided down voltage and convert back into battery voltage
   battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
  if (battVolts > tripVolts1) { 		//check voltage above or below high trip point
    blinkPeriod = 0; //voltage above, special condition for no blinking
  } 
  else if (battVolts > tripVolts2) { 		//check voltage above or below 2nd trip point
    blinkPeriod = (1000 / blinkRate1); 		//voltage above, blink at rate1
  } 
  else if (battVolts > tripVolts3) { 		//check voltage above or below 3rd trip point
    blinkPeriod = (1000 / blinkRate2); 		//voltage above, blink at rate2
  } 		
  else {
    blinkPeriod = (1000 / blinkRate3); 		//voltage below, blink at rate3
  }
  //now blink the LEDs if conditions are correct
  if (blinkPeriod == 0) { 			//special condition means no blinking
    digitalWrite(ledPin2, HIGH); 		//turn led on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; 		//change blinkState
      blinkTime = millis(); 			//reset blinkTime
    }
    digitalWrite(ledPin2, blinkState); 		//turn led on or off per blinkState
  }
  delay(blinkPeriod/10);
 }
 
 //_________________________________________________________________________---

 else if (selectedPos == 3 ) 			//descend
 {
  //measure the divided down voltage and convert back into battery voltage
   battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
  if (battVolts > tripVolts1) { //check voltage above or below high trip point
    blinkPeriod = 0; 				//voltage above, special condition for no blinking
  } 

  //now blink the LEDs if conditions are correct
  if (blinkPeriod == 0) { //special condition means no blinking
    digitalWrite(ledPin3, HIGH); //turn led on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; 		//change blinkState
      blinkTime = millis(); 			//reset blinkTime
    }
    digitalWrite(ledPin3, blinkState); 		//turn led on or off per blinkState
  }	
  delay(blinkPeriod/10);
 }
 
 } 
  

*/

Now I have looked into some arduino tutorials online, the OneButton library (http://www.mathertel.de/Arduino/OneButtonLibrary.aspx) and the clickbutton library (https://code.google.com/p/clickbutton/)

I cant get them to work as I don’t fully understand them. I’ve looked into FSM, but all the examples look too complicated. And I think I am trying to over complicate the code anyway!

I’ve tried this as an example…

#include "OneButton.h"
/*  Cycle through (alternate) red and blue leds by clicking button. 
    Switch on Green led (turn off red and blue) with a press

*/


// setup a new OneButton on pin 2
OneButton button(2, true);
const int ledPin1 = 9;
const int ledPin2 = 10;
const int ledPin3 = 11;
int a = 0;    

int buttonPushCounter = 0;  // set button click counter to 0



void setup()
{
  pinMode (ledPin1, OUTPUT);
  pinMode (ledPin2, OUTPUT);
  pinMode (ledPin3, OUTPUT);
  button.attachClick(singleClick);  // link click and press functions to be called on an event
  button.attachPress(singlePress);
 
 
  
  // put your setup code here, to run once:
  
}

void loop()
{
  // put your main code here, to run repeatedly:
  
  button.tick();  //Monitor the button
  delay(10);
  
}

void singleClick()
{
    buttonPushCounter++;  
    if(buttonPushCounter ==3)
    {
      buttonPushCounter = 0;    //there are only 2 states for the button, 3 is not allowed
    }
    if (buttonPushCounter == 1 ||buttonPushCounter ==0) 
    {
    ledPin1, HIGH;
    a = 0;
    }
    
    if (buttonPushCounter == 2 ||buttonPushCounter <= 2)  
    {
    ledPin2, HIGH;
    a = 1;
    }

It doesn’t compile and I dont understand the errors.

Any help or direction would be very much appreciated!

Thanks

Thanks for posting your code, but…

It doesn’t compile and I dont understand the errors.

http://ricojansen.nl/image/magic_ball.jpeg

:confusion-shrug:

Magic ball says “No”

piesoup:

...

void loop()
{
// put your main code here, to run repeatedly:

button.tick(); //Monitor the button
delay(10);

}



It doesn't compile and I dont understand the errors.

Last edited by piesoup on Sat Dec 27, 2014 9:02 pm, edited 1 time in total.

I see what you did there in that minute after I posted: //}

Does that mean that it now compiles through to the end? What are/were the compiler errors?

Before we even think about code, let’s look at your Problem Statement.

This:

/* Cycle through (alternate) red and blue leds by clicking button.

Switch on Green led (turn off red and blue) with a press

means nothing to me. What is it supposed to mean? It sounds like you want to do two different things, but imply that all you want to do is cycle through red, green and blue LEDs by depressing (assume press and release?) a pushbutton. Is this correct? Or is “clicking button” a different action than “a press?”

I’ve looked into FSM, but all the examples look too complicated.

Perhaps but you have a 3 state FSM and that's pretty simple. There are multiple ways to code that.

And I think I am trying to over complicate the code anyway!

Probably.

Think about it this way. You have 3 independent conditions (aka states). Let’s name them after the LEDs which are on for each; a green state, a red state and a blue state. You have a state variable, buttonPushCounter, which at any moment controls what the desired state is. You only have one button so the state can either increment or decrement w/each push. You’ve chosen to increment it.

So the loop() pseudo code would look something like this:

void loop() {
  // read the push button
  // if pushed increment state variable
  // be sure to debounce switch !!

  ?? push button code and debounce code goes here ??

  // now set LEDs on and off per the state variable
  if(state_variable == red_state){
    // turn on red LED, turn off other LEDs

    ?? LED code ??
  }
  if(state_variable == blue_state){
    // turn on blue LED, turn off other LEDs

    ?? LED code ??
  }
  if(state_variable == green_state){
    // turn on green LED, turn off other LEDs

    ?? LED code ??
  }
  // add a delay if you want to keep a state for some min time
  // or as a method to debounce switch (wait for switch to stop bouncing)
  delay(minTime);
}

You could use if…else() in place of if(), it might run quicker (but who cares) or you could use the switch…case(). All would work but the above is perhaps the simplest to understand.

http://arduino.cc/en/Tutorial/InputPullupSerial

http://en.wikipedia.org/wiki/Switch#Contact_bounce

http://playground.arduino.cc/Code/Bounce

(FWIW I think the Bounce2() Lock-out interval method is the same as waiting some msecs between reading of the switch, that is a simple delay(). )

lyndon:
Before we even think about code, let’s look at your Problem Statement.

This:

/* Cycle through (alternate) red and blue leds by clicking button.

Switch on Green led (turn off red and blue) with a press

means nothing to me. What is it supposed to mean? It sounds like you want to do two different things, but imply that all you want to do is cycle through red, green and blue LEDs by depressing (assume press and release?) a pushbutton. Is this correct? Or is “clicking button” a different action than “a press?”

Hi, yeah, it isn’t very clear!

Click, is a quick push and release, < 0.2 second

Press, is a push and holdd, then release, >1 second but < 2 second.

So clicks alternate between red and blue. Independent of wishl which colour is lit, a press will turn off the lit LED and turn on the green.

Then further clicks will turn off the green, and continue alternating thev red and blue.

The colours represent Climb, Trail and Descend modes on a rear shock on a mtb bike.

Mac, Howdie! Thanks for those examples. When I get home I’ll have a play. I think I’ll be able to do it if it was just clicks, but having the press to move to another function confuses me. I’ll reach out later on once I’ve had a go v

Thanks all!

Valen:

piesoup:

...

void loop()
{
// put your main code here, to run repeatedly:

button.tick(); //Monitor the button
delay(10);

}



It doesn't compile and I dont understand the errors.

Last edited by piesoup on Sat Dec 27, 2014 9:02 pm, edited 1 time in total.

I see what you did there in that minute after I posted: //}

Does that mean that it now compiles through to the end? What are/were the compiler errors?

Yeah, sorry! I had a break then went back to it, silly errors! I think there were errors but it looks like they are related to the library as they all involved the location where the library is installed. I’ll have a look later.

piesoup:
Hi, yeah, it isn’t very clear!

Click, is a quick push and release, < 0.2 second

Press, is a push and holdd, then release, >1 second but < 2 second.

Yup, I missed the distinction above. But they’re still incomplete. What happens if a press is > 2 secs ? Nothing ??

Mee_n_Mac:

piesoup:
Hi, yeah, it isn’t very clear!

Click, is a quick push and release, < 0.2 second

Press, is a push and holdd, then release, >1 second but < 2 second.

Yup, I missed the distinction above. But they’re still incomplete. What happens if a press is > 2 secs ? Nothing ??

I will have a need for a longer press, but at the moment, nothing will happen on a longer than 2 seconds press.

What I’d like is, if I’m in Descend, and the button is held down, the servo moves to Climb for as long as the button is held down. (Longer than 2 seconds though). When the button is released, the servo returns to Descend mode. Then clicks on the button cycle between Trail and Climb, until a press longer than 1 but less than 2 ( I can fine tune that later) moved to Descend.

You are correct in that a simple FSM is a good way to handle this. In a nutshell, the tasks are

  • Measure the time that the button is held down

  • Depending on that time, set the state

  • Do the operation for that particular state (red on, green on, blue on, etc)

  • Repeat.

I posted some example code [here. I would have just pasted it here, but it was getting pretty long.

I don’t know that it will work correctly, but it does illustrate the concepts. If you’re interested, I can get it working correctly as time permits and then just make it available as a zip file for download. That depends on how bored I get over the next week, though ;-)](http://www.cedarlakeinstruments.com/blog/archives/221)

Wow, you wrote all that! Thank you!

I understand most of it and where it’s going. What is ‘enum’?

At the end of your code, do I add in the code for RED_OUTPUT 0 etc?

For example

digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
   digitalWrite(ledPin1, HIGH);

I have read, you always need an IDLE state. Is that the initial start up state? So if I want the shock to always be in GREEN state on start up, do I code the IDLE state to do this?

I am at home tomorrow so will spend time going though it.

Thank you very much for your time, really appreciate it!

I’ll let you know how I get on!

Correct. “activateOutput” will turn on/off LEDs based on the current state. I fleshed that out a bit just now since I couldn’t sleep.

I made a minor change to the readSwitch function to fix a bug so a click is a keypress between 25-200 ms.

You don’t need the IDLE state. I just didn’t know what the startup condition would be so I removed it now. Still haven’t run the code to test it though.

enum is a C/C++ construct that defines a set of constants. It allows the compiler to limit what values are assigned to a variable and makes the code a bit easier to read.

The “theoretical” need for an idle state is because a complete state machine allows behaviors on entry into and exit from a state, so you would need an IDLE state to allow a behavior on entering the GREEN state. Technically, turning on the (e.g., green) LED should be done on entering the GREEN state (a state entry behavior) and turning off the red and blue ones would be done on exiting the previous state (state exit behavior). I have done this on complex state processing engines that I’ve built, but this one is simple and doesn’t need all that stuff cluttering it up. Someday I will write a post about a generic Arduino state machine that illustrates how that additional functionality can be useful.

Ok, I think I’m falling at the first hurdle,

I cant work out how to handle clicks and presses in one piece of code.

Click, is a quick push and release, < 0.2 second

Press, is a push and hold, then release, >1 second but < 2 second. If held for longer, a just take it as a press.

These timings are rough, just as an idea.

I can handle alternating between 2 LEDs by clicking the button using the one button library. It is very slow, 1 second for the LED to react to a click.

/*  Cycle through red and blue leds by clicking button. 
    Switch on Green led with a press
However, this just cycles through all three...
*/
#include <OneButton.h>

// setup a new OneButton on pin 2
OneButton button(4, true);
const int ledPin1 = 11;
const int ledPin2 = 12;
const int ledPin3 = 13;
int a = 0;    

int buttonPushCounter = 0;  // set button click counter to 0



void setup()
{



  pinMode (ledPin1, OUTPUT);
  pinMode (ledPin2, OUTPUT);
  pinMode (ledPin3, OUTPUT);
 // button.attachClick(singleClick);  // click function doesnt work
  button.attachPress(singlePress);    // this acts just like a click
 // button.attachDoubleClick(doubleclick); // double click function doesnt work
  Serial.begin(9600);
} 

void loop()
{  
  button.tick();  //Monitor the button
  delay(10);
}

void singlePress()
{
    buttonPushCounter++;  
    if(buttonPushCounter ==4)
    {
      buttonPushCounter = 1;    //there are only 2 states for the button, 3 is not allowed
    }
    if (buttonPushCounter == 1)
    {
    blueLED();
    a = 0;
    
    }
    
   if 
    (buttonPushCounter == 2)  
    {
    greenLED();
    a = 1;
    }
       
    if 
    (buttonPushCounter == 3)  
    
    {
    redLED();
    a = 2;
    }
    
    Serial.println(buttonPushCounter);
     //Serial.println(a);
}

void greenLED()
{
 digitalWrite (ledPin1, LOW ); 
 digitalWrite (ledPin2, HIGH );
 digitalWrite (ledPin3, LOW );
}

void redLED()
{
 digitalWrite (ledPin1, LOW ); 
 digitalWrite (ledPin2, LOW );
 digitalWrite (ledPin3, HIGH );
}

void blueLED()
{
 digitalWrite (ledPin1, HIGH ); 
 digitalWrite (ledPin2, LOW );
 digitalWrite (ledPin3, LOW ); 
}

http://www.mathertel.de/Arduino/OneButtonLibrary.aspx

I can also use the click button library to turn on ONE LED from a click, then turn on one LED from a press. Brilliant, but I cannot use this library to alternate between two LEDs like I can on the first code. All I get (from all LEDs off) is click makes green LED HIGH; press makes green LED LOW and red LED HIGH. This repeats, click makes green LED HIGH; press makes green LED LOW and red LED HIGH.

#include "ClickButton.h"

// the LED
const int ledPin1 = 11; 
const int ledPin2 = 12;
const int ledPin3 = 13;
int ledState = 0;

// the Button
const int buttonPin1 = 4;
ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP);
int buttonPushCounter = 0; // set button press counter to 0
// Arbitrary LED function 
int LEDfunction = 0;


void setup()
{
  pinMode(ledPin1,OUTPUT);  
  pinMode(ledPin2,OUTPUT);
  pinMode(ledPin3,OUTPUT);
  // Setup button timers (all in milliseconds / ms)
  // (These are default if not set, but changeable for convenience)
  button1.debounceTime   = 20;   // Debounce timer in ms
  button1.multiclickTime = 250;  // Time limit for multi clicks
  button1.longClickTime  = 1000; // time until "held-down clicks" register
}


void loop()
{
  // Update button state
  button1.Update();
  
delay(5);


  
  if (button1.clicks != 0) LEDfunction = button1.clicks;
  // green LED if button clicked
  if(button1.clicks == 1) 
      greenLED();

       
  
  // red LED if button held held down (press)
  if(button1.clicks == -1) 
      redLED();

  
  // This is what I cant get to work. 
  if (button1.clicks == 2)
      blueLED();
  
}

void greenLED()
{
 digitalWrite (ledPin1, LOW ); 
 digitalWrite (ledPin2, HIGH );
 digitalWrite (ledPin3, LOW );
}

void redLED()
{
 digitalWrite (ledPin1, LOW ); 
 digitalWrite (ledPin2, LOW );
 digitalWrite (ledPin3, HIGH );
}

void blueLED()
{
 digitalWrite (ledPin1, HIGH ); 
 digitalWrite (ledPin2, LOW );
 digitalWrite (ledPin3, LOW ); 
}

https://code.google.com/p/clickbutton/wiki/Usage

So, in a nutshell, I am unsure how to combine the clicks and press into one piece of code. The click button one looks easier. I understand that (button1.clicks == -1) is a press. I just cant seem to advance the counter for the clicks like in the first bit of code.

Lydon, I had a read of the code you posted, I think its above my learning at the mo!

Mac, I think I am going in the right direction?! I have seen code that will turn on and off LEDs that’s a lot shorter, but I like the long winded way, I can see exactly whats happening.

Got it!!! :dance: :dance: :dance:

I was struggling to get the if statements and the ( ) correct.

Especially the () with in the other ().

// If led is green or blue, and button is clicked, turn on red
     else if(button1.clicks == 1 && (ledState == 2 || ledState == 3))
          redLED();   // 1

But I did it! Probably not the quickest way but it works.

Now I’m going to change the led states to servo states.

I’ll probably be back very soon.

    #include "ClickButton.h"

    // the LED
    const int ledPin1 = 11; //red
    const int ledPin2 = 12; //green
    const int ledPin3 = 13; //blue
    int ledState = 0;

    // the Button
    const int buttonPin1 = 4;
    ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP);
    // Arbitrary LED function
    int LEDfunction = 0;


    void setup()
    {
      Serial.begin(9600);
      pinMode(ledPin1,OUTPUT); 
      pinMode(ledPin2,OUTPUT);
      pinMode(ledPin3,OUTPUT);
      // Setup button timers (all in milliseconds / ms)
      // (These are default if not set, but changeable for convenience)
      button1.debounceTime   = 20;   // Debounce timer in ms
      button1.multiclickTime = 250;  // Time limit for multi clicks
      button1.longClickTime  = 1000; // time until "held-down clicks" register
      button1.clicks = 0;
     digitalWrite (ledPin1, HIGH );
     digitalWrite (ledPin2, HIGH );
     digitalWrite (ledPin3, HIGH );
     delay(1500);
     digitalWrite (ledPin1, LOW );
     digitalWrite (ledPin2, LOW );
     digitalWrite (ledPin3, LOW );
    }


    void loop()
    {
      // Update button state
      button1.Update();
     
    delay(10);
     
      if (button1.clicks != 0) LEDfunction = button1.clicks ;
      
      // green LED on if button is clicked and led is not green
      if(button1.clicks == 1 && ledState != 2)       //  (button1.clicks = 1) is a click
       greenLED();  // 2
      
       // If led is green or blue, and button is clicked, turn on red
     else if(button1.clicks == 1 && (ledState == 2 || ledState == 3))
          redLED();   // 1
          
       
      if (ledState !=3 )
      {
      // blue LED if button held held down (press)
         if (button1.clicks == -1)                  //  (button1.clicks = -1) is a press
          blueLED();  // 3
      }
     
     
    Serial.print("led"); 
     Serial.println(ledState);
    
    Serial.println(LEDfunction);  
  }

    void greenLED()
    {
     digitalWrite (ledPin1, LOW );
     digitalWrite (ledPin2, HIGH );
     digitalWrite (ledPin3, LOW );
     ledState=2;
    }

    void blueLED()
    {
     digitalWrite (ledPin1, LOW );
     digitalWrite (ledPin2, LOW );
     digitalWrite (ledPin3, HIGH );
     ledState=3;
    }

    void redLED()
    {
     digitalWrite (ledPin1, HIGH );
     digitalWrite (ledPin2, LOW );
     digitalWrite (ledPin3, LOW );
     ledState=1;
    }

I have noticed a fault but cannot find where in the code it is. I have isolated the servo and just used LEDs in a separate code to see if it has anything to do with servo timings but the fault is still there.

I have a feeling its to do with my if / else statements. Even putting in ; changes the output! I’ve been on this most of last night and today, please help!

Just for a recap,

(button1.clicks = 1) is a click and (button1.clicks == -1) is a press (longer than 400ms)

And how I imagine its written out in English…

One click moves to TRAIL if it is not already in TRAIL (selectedPos != 2)

Else if the servo is already in TRAIL, or DESCEND, move to CLIMB.

Next, if not already in DESCEND, a press will move servo into DESCEND. “if (selectedPos !=3 && button1.clicks == -1)”

All that ^^^ works well…

If already in DESCEND and button pressed “else if (selectedPos == 3 && button1.clicks == -1 )”

Move to CLIMB for 2000ms then back to DESCEND. tempCLIMB1()

But then the above line runs and it all goes wrong. I’ve typed out line for line what is happening.

A press moved to Descend() (as commanded)

A press while in DESCEND, moved to Climb() (as commanded)

Delay in Climb mode of “const int climbDelay = 2000;” (as expected)

However, with no further input from me on the button, there seems

to be a press read from the button, which starts to move the servo

into Descend mode (Pos3)

The servo starts to move, doesn’t complete it’s full travel, but then returns to Climb (Pos1), after

what looks like an input on the button. (NOT EXPECTED)

Another delay in Climb mode of 2000, so it looks like CLIMB() has

been carried out again. (NOT EXPECTED)

Then without a press it returns to Descend(), (as expected)

I’m unsure how there serial monitor is reading the -1 as a press here, as I haven’t touched the button…

/* 	Rev 1.1 of iCTD with battery monitoring, by ASF

Big thanks to Mee_n_Mac on Sparkfun
	01/09/2014
Battery monitoring is commented out for clarity
*/ 


#include <Servo.h>
#include "ClickButton.h"
Servo myservo; 			// create servo object to control a servo

int pos = 0; 			// variable to store the servo position
int selectedPos = 2; 		// sets the selected servo position to middle
const int buttonPin1 = 4; 	//sets pin 2 as button
const int ledPin1 = 11; 	// sets pin 11 as LED for Climb Blue
const int ledPin2 = 12; 	// sets pin 12 as LED for Trail Green
const int ledPin3 = 13; 	// sets pin 13 as LED for Descend Red

//int buttonState = 0; 		//sets button 1 as off
//int buttonState2 = 0; 		// sets button 2 as off
ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP);
//declare the constants used
const float tripVolts1 = 7.5; 	//above this voltage the LEDs are always on 8
const float tripVolts2 = 7.5; 	//above this voltage the LEDs blink at rate 1 7.5
const float tripVolts3 = 6.6; 	//above this voltage the LEDs blink at rate 2 6.6
const float scaleFactor = 0.595;//ratio of divided down voltage to battery voltage
const int blinkRate1 = 1; 	//blink rate1 in Hz (blinks/sec)
const int blinkRate2 = 2; 	//blink rate2 in Hz (blinks/sec)
const int blinkRate3 = 4; 	//blink rate4 in Hz (blinks/sec)
const int battPin = A0; 	//number of analog pin used to measure battery voltage

//declare the variables used
boolean blinkState = false; 	//variable to control LEDs on or off
unsigned long blinkPeriod = 0; 	//period in msec of blinking
unsigned long blinkTime = millis(); //variable to store when blink state was last changed
float battVolts = 0; 		//battery voltage
const int climbDelay = 2000;

void setup()
{
  Serial.begin(9600);
   		
  pinMode (ledPin1, OUTPUT); 	// sets led as output
  pinMode (ledPin2, OUTPUT); 	// sets led as output
  pinMode (ledPin3, OUTPUT); 	// sets led as output
  button1.debounceTime   = 20;   // Debounce timer in ms
  button1.multiclickTime = 80;  // Time limit for multi clicks
  button1.longClickTime  = 400; // time until "held-down clicks" register
  button1.clicks = 0;
  myservo.attach(9);                // attaches the servo on pin 9 
  digitalWrite (ledPin1, HIGH );
  digitalWrite (ledPin2, HIGH );
  digitalWrite (ledPin3, HIGH );   // Just for fun
  delay(100);
  digitalWrite (ledPin1, LOW );
  digitalWrite (ledPin2, LOW );
  digitalWrite (ledPin3, LOW );
  delay(100);  
  
  myservo.write(90); 		// sets servo to mid trail position
  digitalWrite (ledPin2, HIGH);
  delay(50);
 // myservo.detach();
  }

void loop()
{
   // Update button state
      button1.Update();
      delay(10);
  
//------------------Clicks to cycle through TRAIL and CLIMB---------------------------
       
      // green LED on if button is clicked and led is not green
      if(button1.clicks == 1 && selectedPos != 2)       //  (button1.clicks = 1) is a click
      
       TRAIL(); // selectedPos now = 2
      
      else if(button1.clicks == 1 && (selectedPos == 2 || selectedPos == 3))
       CLIMB(); // selectedPos now = 1
 //------------------------------------------------------------------------------------
 
 
//-----------------Press to move into DESCEND------------------------------------------ 
      
      
       if (selectedPos !=3 && button1.clicks == -1)  // (button1.clicks == -1) is a press
      {
    //if (button1.clicks == -1) 
       DESCEND(); //selectedPos now = 3
      }

 
 //----------------If in DESCEND Press moves into temp CLIMB for 2000ms----------------------------- 
     else if (selectedPos == 3 && button1.clicks == -1 )
       { 
       tempCLIMB1();
       }

}


void CLIMB()                        //Blue LED
{
  
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, HIGH);          // Comment out when using blink code below
    myservo.write(45);      		// servo moves into climb blue
  
    selectedPos = 1;
    Serial.println(button1.clicks);
    Serial.print("selectedPos");
    Serial.println(selectedPos);
}

void DESCEND()                      //Red LED
{
    
    digitalWrite(ledPin1, HIGH);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);        // Comment out when using blink code below
    myservo.write(135);   		// servo moves into descend red
   
    selectedPos = 3;
    Serial.println(button1.clicks);
    Serial.print("selectedPos");
    Serial.println(selectedPos);
    
    
}

void TRAIL()                        //Green LED
{
     
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, HIGH);
    digitalWrite(ledPin3, LOW);        // Comment out when using blink code below
    myservo.write(90);      		// servo moves into trail
    
    selectedPos = 2;
    Serial.println(button1.clicks);
    Serial.print("selectedPos");
    Serial.println(selectedPos);
}



void tempCLIMB1()
{
  CLIMB();
  delay(climbDelay);
  DESCEND();
  delay(50);
}

I have to admit, I’m a bit lost when trying to follow click vs presses and the resulting actions. And then there’s this …

Just for a recap,

(button1.clicks = 1) is a click and (button1.clicks == -1) is a press (longer than 400ms)

And how I imagine its written out in English…

One click moves to TRAIL if it is not already in TRAIL (selectedPos != 2)

Else if the servo is already in TRAIL, or DESCEND, move to CLIMB.

Next, if not already in DESCEND, a press will move servo into DESCEND. “if (selectedPos !=3 && button1.clicks == -1)”

All that ^^^ works well…

So if a click moves the system into TRAIL if not already in TRAIL, then how does the servo go to CLIMB when in DESCEND ? Shouldn't DESCEND and a click go to TRAIL, as stated in the 1'st sentence ? :?:

I think a state transition diagram might be in order now. Basically a set of bubbles (=states) with a depiction of what action happens (an arrow) to make the state change from one to any other.

http://www.oocities.org/siliconvalley/s … xample.gif

https://farm8.staticflickr.com/7537/159 … 7a285d.jpg

How about this?

Sorry, my brain had been fried after moving brackets and commas about to try and prevent that false move!

The initial transition from Idle to Trail is in in the Setup().

Ideally, what I’d like is to have the transition from Descend to tempClimb, and to stay in tempClimb only for as long as the button is held down. The delay is only there as I cant seem to get that to work, yet.

Like thiis…

https://farm8.staticflickr.com/7471/155 … dcb899.jpg

Replace “climbDelay” with “buttonUp” or similar and it may more clearly describe what you want.

Sorry, looked like there were issues posting img links from a phone.

First pic is what should happen now, the press being >80ms but <400ms of the button being down.

Next pic is ideally what I’d like, but still looking in to how to do that!

FWIW I might suggest that now may be the time to look at using the switch_case() statement as lyndon did. It will make the tracking of what happens when in what state easier. You’ve already had problems w/{}s and that’s why that statement exists. I’m aware that “switching horses in mid-stream” is painful and not always a good idea, but …

Looking at the state diagram I now see it’s not as bad as I thought.