Logic sequence (process flow) using arduino

I have a need to move an actuator to 7 positions, the middle position being the default.

The various positions are determined by 6 latching switches, but they need to follow a sequence.

For example, if switches 1 and 6 are "on", the actuator would be in middles position, 7. If only switch 1 is on, actuator in position 1. if switch 3 is on, then actuator is in position 3.

The positions of switches would override each other, as they are moved.

I have tried it using if/else statements and Boolean && which I am struggling with.

Does anyone have an example of nested if/else?

Or, should I be using switch case?

Here is a process flow of what I am trying to accomplish.

Belt Divider Logic Diagram V2.pdf (145 KB)

You need a state machine. The loop would go something like this:

  1. Check the switches.
  2. Is there is no change, return from loop()
  3. If there is a change, is it valid? If not respond to invalid switch
  4. Act according to new switch setting.

I think switch/case works best when you get to #4

For example, if switches 1 and 6 are "on", the actuator would be in middles position, 7.

Why would position 7 be the middle position, when there are only 7 positions?

The positions of switches would override each other, as they are moved.

If the value determined from the switch positions is overridden, there must be some (undefined) priority order to the switches, and that would seem to eliminate the possibility of two switches being considered at the same time.

I have tried it using if/else statements and Boolean && which I am struggling with.

I suspect that the struggle is happening because your requirements are not clear to you.

That diagram presents a pretty clear picture. Instead of trying to build a set of nested if statements, create a function for each level.

if(digitalRead(masterSwitchPin) == LOW) // Or HIGH if that is what means pressed
{
   CheckSwitchOne();
}
else
   Stop();

You can see, I hope, what you need to do in CheckSwitchOne() and in Stop().

If not, at least make these two functions, and call them in loop(), so we can help you with the next level. That way, we'll know what pin names you have, etc.

In reply to PaulS

In my application I am spreading a product evenly. The switches 1-6 refer to the width of the spread pattern, in this case 100 feet. Going left to right, Switch 1 refers to left 20 feet, Switch 2 is next 20 feet, switch 3 is the 15' to the left of center, switch 4 is the 15' to the right of center, switch 5 is the next 20' and switch 6 is the far right 20 feet.

The middle position would be the default position, i.e. if all switches are on or off. This is where everything starts from.

So, if all switches are on, my actuator would move my divider to the middle (what I am calling position 7, the default position), to allow even product across the full width.

If only switch 1 is on, then the actuator would move to the right so that no product moves to that side.

If switch 1 and 6 are on, requiring product on each side of the spreading, therefore actuator ends up putting divider in the middle as it can't prioritize one over the other.

Does this make more sense?

Does this make more sense?

Yes, thank you.

It doesn't really change the situation, though. You have some rules. You have a flowchart. You are trying to understand how to put all the code in loop(). That is not the best place for all the code.

There appear to be a number of situations where the user has asked the system to do something it can't do. You should assume that the position is center. Then, you should check the switch states to see if they are all in reasonable positions, counting the number of switches on on the left side and the number of switches on on the right side.

If there are switches on on the left, and none on on the right, you can move the actuator from the center position to the correct position on the left, based on which switch(es) are on on the left.

If there are switches on on the right, and none on the left, you can move the actuator from the center position to the correct position on the right, based on which switch(es) are on on the right.

(I may have the actuator side reversed above.)

PaulS, can this be accomplished through the if/else in the loops? Or state machine as the other poster suggested?

you are correct that the center position will be the primary - and I can adjust my thinking along those lines, does make it cleaner (i.e. move from default)

PaulS, can this be accomplished through the if/else in the loops? Or state machine as the other poster suggested?

Either one will work. Given the better explanation, I think the state machine is more than what is needed. The if/else statements are sufficient, and easy to understand and implement.

PaulS, how dynamic can the code be? For example, if a switch is triggered and the actuator is moving towards it's new target but another switch is triggered before it gets there, will the code accept that or will the loop be "on hold" until the initial target position is reached?

From what I understand, the code stops until the condition is met, before it can move on/be modified.

For example, if a switch is triggered and the actuator is moving towards it's new target but another switch is triggered before it gets there, will the code accept that or will the loop be "on hold" until the initial target position is reached?

That depends on how you write the code. If you are moving the actuator in little steps, using a for loop, with delay() between the steps, not very.

If you just tell the actuator to get to some position, and then loop() ends and repeats, then the code will be very responsive.

From what I understand, the code stops until the condition is met, before it can move on/be modified.

What code?

PaulS, here is a mock up of the code I am working on. I have figured out how to use either a relay bank or a multimoto on an Arduino Mega to move my actuators to present positions.

Will an if/else sequence such as posted continue to loop and check for switch changes, or will it get stuck in a portion of the if/else conditions? From what I understand of your previous answers, it will not get stuck.

Each switch is a latching style, not momentary. I also plan to establish the present positions as constants so that they are easier to update/change if required.

//This code is to move 4 linear actuators based on 6 input positions.  Positions are 1-6, from left to right, with the middle default position being position 7.
//Each actuator has a potentiometer.


// Each position has a threshold of 25-50
// Actuator 1 default position is 520
// Actuator 2 default position is 520
// Actuator 3 default position is 450
// Actuator 4 default position is 450
// Switch 1 HIGH action - Actuator 1 setting is 450, Actuator 2 is 450, Actuator 3 is 450, Actuator 4 is default
// Switch 2 HIGH action - Actuator 1 setting is 475, Actuator 2 is 475, Actuator 3 is 475, Actuator 4 is default
// Switch 3 HIGH action - Actuator 1 setting is 500, Actuator 2 is 500, Actuator 3 is 500, Actuator 4 is default
// Switch 4 HIGH action - Actuator 1 setting is 540, Actuator 2 is 540, Actuator 3 is default, Actuator 4 is 500
// Switch 5 HIGH action - Actuator 1 setting is 565, Actuator 2 is 565, Actuator 3 is default, Actuator 4 is 475
// Switch 6 HIGH action - Actuator 1 setting is 590, Actuator 2 is 590, Actuator 3 is default, Actuator 4 is 450
// All switches off - default position all actuators
// All switches on - default position all actuators

// Check voltage on Switch 1
// If it is HIGH, then Check Voltage on Switch 6
  // Else If Switch 1 is HIGH and 6 is HIGH, then move all actuators to default position
  // Else If Switch 1 is HIGH and 6 is LOW then Check Voltage on Switch 5
    // Else if Switch 5 is HIGH, Then move Actuator 1 to 500, Actuator 2 to 500, Actuator 3 to default, Actuator 4 to 475
    // Else Switch 5 is LOW, Then check Voltage on Switch 4
      // Else if Switch 4 is HIGH, then move Actuator 1 to 475, Actuator 2 to 475, Actuator 3 to default, Actuator 4 to 500
      // Else if Switch 4 is LOW, the move Actuator 1 to 450, Actuator 2 to 450, Actuator 3 to default, Actuator 4 to 500
// Else if Switch 1 is LOW, then Check Voltage on Switch 2
  // Else if Switch 2 is HIGH, Check Voltage on Switch 6
    // Else if Switch 6 is HIGH, then move Actuator 1 to 540, Actuator 2 to 540, Actuator 3 to 475, Actuator 4 to default
    // Else Switch 6 is LOW, then Check Voltage on Switch 5
      // Else if Switch 5 is HIGH, then move Actuator 1 to default, Actuator 2 to default, Actuator 3 to 475, Actuator 4 to 475
      // Else Switch 5 is LOW, then Check Voltage on Switch 4
        // Else if Switch 4 is HIGH, then move Actuator 1 to 475, Actuator 2 to 475, Actuator 3 to 475, Actuator 4 to 500
        // Else Switch 4 is LOW, then move Actuator 1 to 450, Actuator to 450, Actuator 3 to 475, Actuator 4 to 500
   // Else Switch 2 is LOW(Switch 1 is also LOW), Check Voltage on Switch 3
     // Else if Switch 3 is HIGH, Check Voltage on Switch 6
       // Else if Switch 6 is HIGH, move Actuator 1 to 565, Actuator 2 to 565, Actuator 3 to 500, Actuator 4 to default
       // Else Switch 6 is LOW, Check Voltage on Switch 5
         // Else if Switch 5 is HIGH, move Actuator 1 to 565, Actuator 2 to 565, Actuator 3 to 500, Actuator 4 to 475
         // Else Switch 5 is LOW, Check Voltage on Switch 4
           // Else if Switch 4 is HIGH, move Actuator 1 to default, Actuator 2 to default, Actuator 3 to 500, Actuator 4 to 500
           // Else Switch 4 is LOW, move Actuator 1 to 450, Actuator 2 to 450 Actuator 3 to 500, Actuator 4 to 500 
      // Else Switch 3 is LOW (Switches 1 and 2 are LOW), Check Voltage on Switch 6
        // Else if Switch 6 is HIGH, move Actuator 1 to 590, Actuator 2 to 590, Actuator 3 to 500, Actuator 4 to default
        // Else Switch 6 is LOW, Check Voltage on Switch 5
          // Else if Switch 5 is HIGH, move Actutator 1 to 590, Actuator 2 to 590, Actuator 3 to 500, Actuator 4 to 475
          // Else Switch 5 is LOW, Check Voltage on Switch 4
            // Else if Switch 4 is HIGH, move Actuator 1 to 590, Actuator 2 to 590, Actuator 3 to 500, Actuator 4 to 500
            // Else Switch 4 is LOW, Move Actuator 1 to default, Actuator 2 to default, Actuator 3 to default, Actuator 4 to default

//  end loop

You can't get stuck in an if statement or an else statement. They evaluate to true or false in a few nanoseconds.

You CAN get stuck in the BODY of the if statement or the BODY of the else statement, IF you write blocking code. So, don't.

So I am working my way through this. Been verifying/compiling as a go to try to catch errors while I can.

came up with this one that I can't figure out. I thought I had it working before but now getting message . I searched the boards but I didn't see a solution to what I thought was happening.

keep in mind I am not nearly done yet but I thought I should figure this out before I get further in.

Wondering if I can't used the && with the digitalRead?

Arduino: 1.6.7 (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

C:\Users\Chuck Baresich\Documents\Arduino\Beltdivider\Beltdivider.ino: In function 'void loop()':

Beltdivider:210: error: lvalue required as left operand of assignment

if(b1State = HIGH && b6State = HIGH)

^

Beltdivider:231: error: expected ';' before ':' token

pwm1 = 255:

^

exit status 1
lvalue required as left operand of assignment

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.

Beltdivider.ino (10.6 KB)

The error it's pointing to is actually this:

pwm1 = 255: //<<<<<<<<<< colon should be semi-colon

But while you're at it, these ='s should be =='s as comparisons not assignments

if(b1State = HIGH && b6State = HIGH)

And it's complaining about A8 not being declared.

edit... that part was me, ide set to Uno but I assume you have a Mega. Went away when I changed board type.

SandFarmer:
So, if all switches are on, my actuator would move my divider to the middle (what I am calling position 7, the default position), to allow even product across the full width.

If only switch 1 is on, then the actuator would move to the right so that no product moves to that side.

If switch 1 and 6 are on, requiring product on each side of the spreading, therefore actuator ends up putting divider in the middle as it can't prioritize one over the other.

Ok, can you formulate a simple rule for where the divider should be? Perhpas something like "take the average of the position of the on switches, and move the divider as close as possible to that position.

So if switches 1,2,and 5 are on, the averge is 4 and that's where the divider gets moved to.

Or maybe the rule should be "move the divider so that the same number of on and off switches are to the left and right of it. If there's an odd number of switches on, then err towards having the divider to the center".

In any case, your loop becomes:

read the switches;
work out where the divider should be;
if the divider isn't there {
  move it there
}

Your problem is articulating your rule for where to move the divider, not in writing the code to do it. (calling the center "position 7" doesn't help).

SandFarmer:
Beltdivider:210: error: lvalue required as left operand of assignment

if(b1State = HIGH && b6State = HIGH)

^

You mean ==, not =.

PaulMurrayCbr:
Your problem is articulating your rule .... not in writing the code to do it.

I've lost count of how many times I've given that advice on these boards.

PaulMurrayCbr:
You mean ==, not =.

Answered already.....

To JimboZA - thanks for the tip - I was so focussed on the && that I glossed over the single =.

Fixed my issue, as did the ;. And yes, my board is a mega

to PaulMurrayCbr - I can't average the positions as the gate needs to be precise (actuator within a few millimeters) so that the amount of fertilizer I am applying is correct.

JimboZA and Paul, perhaps you are on to something.

I have been focused on my spreading distance, not the amount of product which maybe is goofing me up. My problem is that the product to be applied is delivered via a single belt, which while the gate is the in the centre, equally delivers 50% to either side. My switches refer to an application width - 50 feet on either side. So while theoretically I could have a code that adds up the number of switches on each side, and translates that into a position of the actuator, I still think I need the same logic to determine "which side" the actuator moves to?

I am struggling to describe this clearly, which I thought was a fairly simple idea.

Hang on, let's go back to the initial post:

For example, if switches 1 and 6 are "on", the actuator would be in middles position, 7. If only switch 1 is on, actuator in position 1. if switch 3 is on, then actuator is in position 3.

The positions of switches would override each other, as they are moved.

Do you mean that when a switch becomes switched on, that any prior position no longer matters?

And do you want it to be that when a switch is switched off, that the sketch "remembers" the previous position it was in? So if I switch on 1, 2, 3, then switch off 2, 3, you want the actuator to stay on position 3 and then go back to position 1?

That's do-able. You keep track of which positions are on or off, and you keep a stack of the sequence in which they were switched on. If a switch becomes on, you add it to the top of the stack and mover the actuator there. If a switch becomes off, then if it's the top item of the stack, you pop it off the stack and move the actuator to the next position down, or to position 7 if the stack is now empty (all switched off). IF it is not the top item of the stack, you remove it from wherever it is.

byte currentState[8]; // we number our switches 1-7
byte stack[7]; // the stack of swich actuations
int currentStack = 0; // the number of locations currently in the stack

void loop() {
  for(int switch = 1; switch<=7; switch++) {
    byte state = digitalRead(pin_for_switch[switch]);
    if(state == HIGH && currentState[i]==LOW) {
      popSwitch(switch);
    }

    if(state == LOW && currentState[switch]==HIGH) {
      pushSwitch(switch);
    }

    currentState[switch] = state;
  }
}

void popSwitch(int switch) {
   // find where the switch is in the stack

   int switchLocation;
   for(switchLocation = 0; switchLocation < currentStack; switchLocation++) {
     if(stack[switchLocation] == switch) {
       break;
     }
   }
  
   // move it out of the stack
   for(int i = switchLocation; i < 6; i++) {
     stack[i] = stack[i+1];
   }
   currentStack --;

   if(currentStack == 0) {
     // all switches off
     move_to_position(7);
   }
   else if(switchLocation == currentStack) {
     // the switch we switched off was the top one
     move_to_position(stack[currentStack-1]);
   }
}

void pushSwitch(int switch) {
  // find the switch in the stack, if it's there

  int switchLocation = -1;
  for(switchLocation = 0; switchLocation < currentStack; switchLocation++) {
    if(stack[switchLocation] == switch) {
      break;
    }
  }

  // switch was in the stack
  if(switchLocation != -1) {
   // move it out of the stack
   for(int i = switchLocation; i < 6; i++) {
     stack[i] = stack[i+1];
   }

   currentStack --;
  }

  // push the switch onto the top of the stack
  stack[currentStack] = switch;
  currentStack++;

  // move the actuator to the new position
  move_to_position(stack[currentStack-1]);
}

PaulS or PaulMurrayCbr - Here is where I am at with the logic part (if/else) of the code. I guess this is one way to do it - if you think it will work.

I am not sure about having the code "remember" where the actuators are at - if that will provide a benefit to me? Maybe in terms of stability?

Another way I could go at this, which was suggested in an earlier post by PaulS I think, would be to check the switches on either side of the middle or start position and work from there.

I was wondering - can I use a multiple && in a code? for example, can I have "if(switch1 == HIGH && switch2 == HIGH && switch3 == HIGH && etc) or am I limited to just one comparison?

If I can I think I could simplify things greatly.

here is my code so far:

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

  // All switches off - default position all actuators
  // All switches on - default position all actuators

  b1State = digitalRead(b1Pin);
  b2State = digitalRead(b2Pin);
  b3State = digitalRead(b3Pin);
  b4State = digitalRead(b4Pin);
  b5State = digitalRead(b5Pin);
  b6State = digitalRead(b6Pin);

  // Check voltage on Switch 1
  // If it is HIGH, then Check Voltage on Switch 6
  // Else If Switch 1 is HIGH and 6 is HIGH, then move all actuators to default position
  if (b1State == HIGH && b6State == HIGH)
  {
    currentla1 = analogRead(la1potPin);
    currentla2 = analogRead(la2potPin);
    currentla3 = analogRead(la3potPin);
    currentla4 = analogRead(la4potPin);
    if (la1default > currentla1 && la1default < currentla1 + coarse)
    {
      la1out = false;
      la1in = true;
      dir1 = 1;
      pwm1 = 255;
      digitalWrite(dir_m1Pin, dir1);
      analogWrite(pwm_m1Pin, pwm1);
      Serial.print("Actuator 1 Extending");
    }
    else if (la1default < currentla1 && la1default < currentla1 - coarse)
    {
      la1in = true;
      la1out = false;
      dir1 = 0;
      pwm1 = 255;
      digitalWrite(dir_m1Pin, dir1);
      digitalWrite(pwm_m1Pin, pwm1);
      Serial.print("Actuator 1 Retracting");
    }
    if (la1out = true && currentla1 > la1default + fine)
    {
      dir1 = 1;
      pwm1 = 0;
      digitalWrite(dir_m1Pin, dir1);
      digitalWrite(pwm_m1Pin, pwm1);
      boolean la1out = false;
      Serial.print("Actuator 1 Idle");
    }
    if (la1in = true && currentla1 < la1default + fine)
    {
      dir1 = 0;
      pwm1 = 0;
      digitalWrite(dir_m1Pin, dir1);
      digitalWrite(pwm_m1Pin, pwm1);
      boolean la1in = false;
      Serial.print("Actuator 1 Idle");
    }
    // end first if
    // Else If Switch 1 is HIGH and 6 is LOW
    else if (b1State == HIGH && b6State == LOW)
    {
      // then Check Voltage on Switch 5
      if (b5State == HIGH)
        // If Switch 5 is HIGH,
      {
        // Then move Actuator 1 to 500, Actuator 2 to 500, Actuator 3 to default, Actuator 4 to 475

      }
      else // Switch 5 is LOW
      {
        // Else Switch 5 is LOW, Then check Voltage on Switch 4
        if (b4State == HIGH) // Else if Switch 4 is HIGH
        {
          // then move Actuator 1 to 475, Actuator 2 to 475, Actuator 3 to default, Actuator 4 to 500
        }
        else    // Else if Switch 4 is LOW
        {
          // then move Actuator 1 to 450, Actuator 2 to 450, Actuator 3 to default, Actuator 4 to 500
        }
      }

    }
    else if (b1State == LOW) // Check voltage on Switch 2
    {
      if (b2State == HIGH && b6State == HIGH) // Check voltage on Switch 6
      {
        // then move Actuator 1 to 540, Actuator 2 to 540, Actuator 3 to 475, Actuator 4 to default
      }
      else
      {
        if (b6State == LOW && b5State == HIGH) // Else Switch 6 is LOW, then Check Voltage on Switch 5
        {
          // then move Actuator 1 to default, Actuator 2 to default, Actuator 3 to 475, Actuator 4 to 475
        }
        else if (b5State == LOW && b4State == HIGH) //Else Switch 5 is LOW, then Check Voltage on Switch 4
        {
          // then move Actuator 1 to 475, Actuator 2 to 475, Actuator 3 to 475, Actuator 4 to 500
        }
        else if (b5State == LOW && b4State == LOW)
        {
          // then move Actuator 1 to 450, Actuator to 450, Actuator 3 to 475, Actuator 4 to 500
        }
      }
    }
    else if (b2State == LOW && b3State == HIGH) // Else Switch 2 is LOW(Switch 1 is also LOW), Check Voltage on Switch 3
    {
      if (b6State == HIGH) // Else if Switch 3 is HIGH, Check Voltage on Switch 6
      {
        // Else if Switch 6 is HIGH, move Actuator 1 to 565, Actuator 2 to 565, Actuator 3 to 500, Actuator 4 to default
      }
      else if (b6State == LOW && b5State == HIGH)        // Else Switch 6 is LOW, Check Voltage on Switch 5
      {
        // move Actuator 1 to 565, Actuator 2 to 565, Actuator 3 to 500, Actuator 4 to 475
      }
      else if (b6State == LOW && b5State == LOW)
      {
        if (b4State = HIGH) // Else Switch 5 is LOW, Check Voltage on Switch 4
        {
          // move Actuator 1 to default, Actuator 2 to default, Actuator 3 to 500, Actuator 4 to 500
        }
        else   // Else Switch 4 is LOW
        {
          // move Actuator 1 to 450, Actuator 2 to 450 Actuator 3 to 500, Actuator 4 to 500
        }
      }
    }
    else if (b3State == LOW && b6State == HIGH)    // Else Switch 3 is LOW (Switches 1 and 2 are LOW), Check Voltage on Switch 6
    {
      // move Actuator 1 to 590, Actuator 2 to 590, Actuator 3 to 500, Actuator 4 to default
    }
    else if (b3State == LOW && b6State == LOW) // Else Switch 6 is LOW, Check Voltage on Switch 5
    {
      if (b5State == HIGH)
      {
        // move Actutator 1 to 590, Actuator 2 to 590, Actuator 3 to 500, Actuator 4 to 475
      }
      else
      {
        if (b4State == HIGH)     // Else Switch 5 is LOW, Check Voltage on Switch 4
        {
          // move Actuator 1 to 590, Actuator 2 to 590, Actuator 3 to 500, Actuator 4 to 500
        }
        else
        {
          //  Move Actuator 1 to default, Actuator 2 to default, Actuator 3 to default, Actuator 4 to default
        }
      }

    }
  }



  //  end loop
}

can I use a multiple && in a code? for example, can I have "if(switch1 == HIGH && switch2 == HIGH && switch3 == HIGH && etc) or am I limited to just one comparison?

Yes, you can use multiple && in an if statement.

Since the actual position of the actuator is a function of all the switch states, that seems like the best solution.

IIRC, though, the position isn't really a function of all the switch states. Rather, it is a function pressing two switches, equidistant from the center switch will cause the position to be the same as if just the center switch, or no switch was pressed. If that is the case, you really have fewer possible positions to choose from.