How to use 'not any' in a for loop array

The problem that I am trying to solve at the moment is ensuring that 3 potentiometers move together. This is done by controlling the movement with an LED, when the LED is on the potentiometer can move, when LED is off, the potentiometer can't move (this simulates a solenoid hydraulic valve controlling a cyclinder).

//pins
int leds[3] = {2, 3, 4};
int potPins[3] = {A0, A3, A5};

//vars
int potVals[3];

void setup() {
  for(int i = 0; i < 3; i++) //set led pins
  {
    pinMode(leds[i], OUTPUT);
  }
  for(int i = 0; i < 3; i++) //set pot pins
  {
    pinMode(potPins[i], INPUT);
  }
}

void loop() {
  for (int i = 0; i < 3; i++) //read pot pins
  {
    potVals[i] = analogRead(potPins[i]);
  }

  for (int i = 0; i < 3; i++) //control speed on down stroke
  {
    if(potVals[i] > 0.9*potVals[!i] && potVals[i] < 1.1*potVals[!i])
    {
      digitalWrite(leds[i], HIGH);
      digitalWrite(leds[!i], HIGH);
    }
    if(potVals[i] < 0.9*potVals[!i])
    {
      digitalWrite(leds[i], HIGH);
      digitalWrite(leds[!i], LOW);
    }
    if(potVals[i] > 1.1*potVals[!i])
    {
      digitalWrite(leds[i], LOW);
      digitalWrite(leds[!i], HIGH);
    }
  }
}

This code does sort of work, but it allows 2 of the potentimeters to run away from the other (even though it can move, if a cyclinder was under a lot more force it wouldn't move with the other), what I need it to do is compare the vals of i vs !notanyi. Because at the moment it compares !i and allows for movement if one of the !i is true.

if(potVals[i] > 1.1*potVals[not any!i])

Is there a way to do this simply?

Many thanks

I'm not sure what you want to achieve.

I think this approach is more logical

  for (int i = 0; i < 3; i++) //control speed on down stroke
  {
    if(potVals[i] < 0.9*potVals[!i])
    {
      digitalWrite(leds[i], HIGH);
      digitalWrite(leds[!i], LOW);
    }
    
    else if(potVals[i] < 1.1*potVals[!i])
    {
      digitalWrite(leds[i], HIGH);
      digitalWrite(leds[!i], HIGH);
    }
    
    else
    {
      digitalWrite(leds[i], LOW);
      digitalWrite(leds[!i], HIGH);
    }
  }

Note how it deals with the small value, the higher value and the highest value in succession.

However, even if the logic is right you are mixing floating point and integer maths and that won't work. As things stand your 0.9 will be treated as 0 and your 1.1 will be treated as 1

A simple solution would be

if(potVals[i] < (potVals[i] * 9 / 10))

and your use of potVals[!i] is not correct. I'm not sure what you want to achieve because there will be two values that are not the current value and I don't know which of them you want to compare with potVals*[/color]*
...R

Yes, that is a much more logical way of writing that code!

int potPin;
int potVal;

void setup() {
  pinMode(potPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  potVal = analogRead(potPin);
  Serial.println(0.9*potVal);
}

Well if you're correct about the 0.9 being treated as a 0... then why does the code above show it not being treated as a 0 when I read the Serial value?

Yes you are correct the (!i) is not the right thing to use, this is why I am here.

I want this code to compare one of the potentiometers against the other 2, if it is smaller than any of the values then turn the others 2 LEDs that control the other two potentiometers off. If it is bigger than the any of the other 2, turn off the LED that controls the potentiometer we're comparing. If it equals the other 2 then turn all LEDs on to allow all of them to move (but you can't have them equal as it's impossible hence the 0.9 and 1.1).

Hope this clears the problem up.

Your help is very much appreciated.

willyerburgh:
I want this code to compare one of the potentiometers against the other 2, if it is smaller than any of the values then turn the others 2 LEDs that control the other two potentiometers off.

Then you need to do that explicitly. I think this should give you the idea

//pins
int leds[3] = {2, 3, 4};
int potPins[3] = {A0, A3, A5};


//vars
int potVals[3];
byte testFailed = true;

void setup() {
    for(int i = 0; i < 3; i++) //set led pins
    {
        pinMode(leds[i], OUTPUT);
    }
    for(byte i = 0; i < 3; i++) //set pot pins
    {
        pinMode(potPins[i], INPUT);
    }
}

void loop() {
    for (byte i = 0; i < 3; i++) //read pot pins
    {
        potVals[i] = analogRead(potPins[i]);
    }
    testFailed = true;
    for (byte i = 0; i < 3; i++) //control speed on down stroke
    {
        for (byte n = 0; n < 3; n++) {
            if (i != n) {
                if(potVals[i] > potVals[n]) {
                    testFailed = false;
                }
            }
        }
        if (testFailed == false) {
            // do something
        }
    
    }
}

Incidentally, don't use an int where a byte is sufficient as that makes better use of the limited Arduino memory.

...R

Edit 21 June to change

if(potVals[i] > potVals[n];

to

if(potVals[i] > potVals[n]) {

Apologies for any confusion.

This is a great way to do it! Thank you!

I'm sure I'll figure it out now, but I am confused why in your code you're closing the for loop with the "i and n".

Shouldn't it look something like this?

    testFailed = true;
    for (byte i = 0; i < 3; i++) //control speed on down stroke
    {
        for (byte n = 0; n < 3; n++) {
            if (i != n) {
                if(potVals[i] > potVals[n];
                    testFailed = false;
                }
             if (testFailed == false)
             {
              //do something
            }
        }
    }
}

willyerburgh:
Shouldn't it look something like this?

I don't think so - at least not with my understanding of the problem.

The way you have it the code will do the failed-test thing twice - once for each failure if both tests fail. The way I have it the code should do the failed-test thing once regardless of which test failed.

Of course you may have a reason for doing it twice and I just don't understand the requirement.

...R

No, I think you understand the problem, I just don't understand the solution!

I've been trying to figure out how to make testFailed helps with the problem and I don't think it does.

Because there are 3 states that the program needs to be in, not just a true or false.

Thank you for trying to let me teach myself but I will need another hint!

Best wishes

willyerburgh:
Because there are 3 states that the program needs to be in, not just a true or false.

I wonder if that is because I did not bother to extend the code for the two other states - I assumed you could do that using my idea as a template.

If that does not make sense please tell me what the 3 states are.

And you can probably think of a more meaningful name for the variable testFailed - it's just what occurred to me on the spur of the moment.

...R

Run through the three values, find the highest one and the lowest one. To do this, set highest and lowest to the value of the first pot, then look at the remaining two (if this value > highest, then highest = this value).

If the highest value is the same as the lowest value, turn all the LEDS on.
otherwise, turn the leds on for all potentiometers not equal to the highest value.

Robin2 I just simply don't understand how I can use the testFail == Failed to make this work, you start the next part with == Failed but we have no reference to the which of the potentiometers failed because we've exited that for loop.

Please, can you give me one more hint and hopefully the light bulb will turn on.

(I have really been trying to understand)

(thank you Paul but that isn't very helpful, I understand the problem I just don't know how to write it)

willyerburgh:
Robin2 I just simply don't understand how I can use the testFail == Failed to make this work, you start the next part with == Failed but we have no reference to the which of the potentiometers failed because we've exited that for loop.

He didn't use ==Failed. He used ==false. The compiler cares about these little details. So should you.

If it's important which one failed, then record the value of n at that point.

Think of yourself working like the computer does. The computer can look at things very precisely but it can only look at one thing at a time. The computer can't look across the row and immediately see the odd one the same way that a human can. So put your blinkers on: cover up all of the others and just look at one. Is that one different to the last one you just looked at? Write down the numbers.

The computer's memory is much better than yours. It remembers things like you wrote them on a piece of paper. Look at the next one. Compare the number to the number you wrote down before.

     digitalWrite(leds[i], HIGH);
     digitalWrite(leds[!i], LOW);

Dude, this does not do what you think it does. C doesn't have funky vector list comprehension doo-dads like leds[!i] to turn off all leds but i.

The expression !i evaluates to true or to false, which gets converted to the integers 1 or 0. When i is zero, this code will turn 0 on and 1 off. When i is 1, this code will turn 1 on and 0 off. And when i is 2, it will turn 2 on and 0 off.

willyerburgh:
Robin2 I just simply don't understand how I can use the testFail == Failed to make this work, you start the next part with == Failed but we have no reference to the which of the potentiometers failed because we've exited that for loop.

I am happy to help but I genuinely can't envisage the point you are stuck at. Maybe you can post a version of my code from Reply #3 with some comments added to show what is troubling you.

Give as much explanation as you can.

...R

Here is the code from reply #3 that I've added comments to. The only part I am struggling with is the void loop part.

void loop() {
    for (byte i = 0; i < 3; i++) //read pot pins
    {
        potVals[i] = analogRead(potPins[i]); 
    }
    testFailed = true;
    for (byte i = 0; i < 3; i++) //control speed on down stroke
    {
        for (byte n = 0; n < 3; n++) {
            if (i != n) { //I can see how this can be useful, so now we're going to do stuff to all the values of n that aren't i, okay good.
                if(potVals[i] > potVals[n]; //I think you missed a brackets? and a {? Okay so now we're going to do stuff if i is greater than all of the n's, good I understand this if the brackets go where they think they do.
                    testFailed = false; //okay, so now if i is greater than any of the n's then make the testFailed = false, but isn't this test going to be false all of the time, one of the potVals will always be larger than the others?
                }
            }
        } //why have we exited the for loop for i? Now we have no reference to compare potVals?
        if (testFailed == false) {
            // do something to what? We've got no reference for which leds[] we need to do stuff too because we've exited the for(i) loop?
            
        }

I hope this shows where I am getting confused?

To sum up, what I don't get is why exiting the for loop where we're generating the conditions to compare the potVals?

I don't see from your code you've shown how we're going to get all the potVals to be within the range I'm trying to aim for.

Here is what I want the code to do below, I hope this makes more sense.

if(potVals[any] > 0.9*potVals[any of the others] && potVals[any] < 1.1*potVals[any of the others]){
 digitalWrite(leds[all of the leds], LOW);
}
if(potVals[any] < 0.9*potVals[any of the others]){
 digitalWrite(leds[any], HIGH;
 digitalWrite(leds[all the others], LOW);
}
if(potVals[any] > 1.1*potVals[any of the others]){
 digitalWrite(leds[any], LOW);
 digitalWrite(leds[all the others], HIGH);
}

I hope this shows really clearing what I am trying to do, I just don't know how to do it :frowning:

Thank you very much.

(Again Paul, thank you for telling me that my original !i doesn't work, I understand why this doesn't work hence why I'm here, and hence the name of the thread, but what you haven't actually helped me understand the problem)

Referring to the first code in Reply #13 ...

You are quite correct the line should be

if(potVals[i] > potVals[n]) {

apologies :slight_smile:

// okay, so now if i is greater than any of the n's then make the testFailed = false, but isn't this test going to be false all of the time, one of the potVals will always be larger than the others?

I had the impression that it is possible for the number being tested to be smaller than either of the others. In that case the variable testFailed would not change from true.

Maybe the problem is the somewhat upside-down logic. I am assuming a test will NOT FAIL if the main value is greater than the other value. In other words if 10 > 8 the test will be true and the test will not have failed. Or if 10 > 12 the test will be false and it will have failed.

//why have we exited the for loop for i? Now we have no reference to compare potVals?

The potVal has already been compared - that was the purpose of the line if(potVals > potVals[n]) {[/color]. When we exit the FOR loop we will have tested the main value against both of the others. If the main value was greater than either of the other values that will be signified by testFailed being true. My piece of code is the equivalent of your if(potVals[any] > 1.1*potVals[any of the others]){ (from your second piece of code).
This needs to be followed with the stuff in your second piece of code
* *if (testFailed == false) {     digitalWrite(leds[any], LOW);     digitalWrite(leds[all the others], HIGH); }* *
You will need equivalent pieces of code for your other two tests.
...R

Maybe using a different variable name will help - look at this version

void loop() {
    for (byte i = 0; i < 3; i++) //read pot pins
    {
        potVals[i] = analogRead(potPins[i]);
    }
    valueBigger = false;
    for (byte i = 0; i < 3; i++) //control speed on down stroke
    {
        for (byte n = 0; n < 3; n++) {
            if (i != n) {
                if(potVals[i] > potVals[n]) {
                    valueBigger = true;
                }
            }
        }
        if (valueBigger == true) {
            // do something
        }
   
    }
}

...R

When we exit the FOR loop we will have tested the main value against both of the others

But how do we know which led to turn on and which to turn off to make that test not true. As in my previous code an potVals_[/color] was related to a leds*[/color], how can we do this if we aren't in that loop._
To explain again what this is doing just to be 100% clear. When an led is turned on the potentiometer will move up in value, if one is smaller than the other we want those to be turned off so the smallest will move up to meet it, if one is larger than the others it'll turn off and wait for the others to catch it up, if it is within the stated range they all move together.
_
> This needs to be followed with the stuff in your second piece of code*_
Ahh! Right I see... how stupid of me, right I had another go as seen below which is still wrong I know because I am using n to power the leds which is wrong I think.
```
*//pins
int leds[3] = {2, 3, 4};
int potPins[3] = {A0, A3, A5};

//vars
int potVals[3];
byte tooSmall = true;
byte tooLarge = true;
byte justRight = true;

void setup() {
    for(int i = 0; i < 3; i++) //set led pins
    {
        pinMode(leds[i], OUTPUT);
    }
    for(byte i = 0; i < 3; i++) //set pot pins
    {
        pinMode(potPins[i], INPUT);
    }
}

void loop() {
    for (byte i = 0; i < 3; i++) //read pot pins
    {
        potVals[i] = analogRead(potPins[i]);
    }
    tooSmall = true;
    tooLarge = true;
    justRight = true;
    for (byte i = 0; i < 3; i++) //control speed on down stroke
    {
        for (byte n = 0; n < 3; n++) {
            if (i != n) { //I can see how this can be useful,
                if(potVals[i] < 0.9potVals[n]){
                  tooSmall = false;
                }
                if(potVals[i] > 1.1
potVals[n]){
                  tooLarge = false;
                }
                else {
                  justRight = false;
                }
               
            }
        if (tooSmall == false) {
          digitalWrite(leds[i], HIGH);
          digitalWrite(leds[n], LOW); 
        }
        if (tooLarge == false) {
          digitalWrite(leds[i], LOW);
          digitalWrite(leds[n], HIGH);
        }
        if (justRight == false) {
          digitalWrite(leds[i], HIGH);
          digitalWrite(leds[n], HIGH);
        }
        }
    }
}
_
```*_
This doesn't work :frowning:
Thank you so much for this I am learning a lot and hopefully, we'll get there soon!!

Look at this version

void loop() {
    for (byte i = 0; i < 3; i++) //read pot pins
    {
        potVals[i] = analogRead(potPins[i]);
    }
    tooSmall = false;
    tooLarge = false;
    justRight = true;
    for (byte i = 0; i < 3; i++) //control speed on down stroke
    {
        for (byte n = 0; n < 3; n++) {
            if (i != n) { //I can see how this can be useful,
                if(potVals[i] < 0.9*potVals[n]) {
                   tooSmall = true; // meaning potVals[i] is too small
                   justRight = false;
                }
                if(potVals[i] > 1.1*potVals[n]) {
                  tooLarge = true;
                  justRight = false;
                }
            }
        }
            // I have moved this out here so that it is triggered if (for example)
            //    potVals[i] is less than either of the others
            //    That is what
            //       if(potVals[any] < 0.9*potVals[any of the others]){
            //    means
        if (tooSmall == true) {
          digitalWrite(leds[i], HIGH);
          digitalWrite(leds[n], LOW); 
        }
        if (tooLarge == true) {
          digitalWrite(leds[i], LOW);
          digitalWrite(leds[n], HIGH);
        }
        if (justRight == true) {
          digitalWrite(leds[i], HIGH);
          digitalWrite(leds[n], HIGH);
        }
    }
}

If what I have written still does not make sense maybe you need to reconsider whether

if(potVals[any] < 0.9*potVals[any of the others]){

correctly describes what you require.

...R

This makes complete sense, I see what we've done here (except in yours you close the for n which gives an error in the code as the rest the code needs this information).

But this just turns all the leds on, no matter what values the pot pins are... they never turn off in any circumstance...

What else could we try instead of

if(potVals[any] < 0.9*potVals[any of the others]){

I can't thank you enough for the time you've given me!

Not wishing to gazump Robin2, but:

//pins
const byte leds[3] = {2, 3, 4};
const byte potPins[3] = {A0, A3, A5};

//vars
int potVals[3];

void setup() {
  //set led pins
  for(int i = 0; i < 3; i++)  {
    pinMode(leds[i], OUTPUT);
  }

  //set pot pins
  for(int i = 0; i < 3; i++)  {
    pinMode(potPins[i], INPUT);
  }
}
void loop() {
  int largestVal = 0;
  int largestCount = 0;

  // read pot pins
  for (byte i = 0; i < 3; i++)  {
    potVals[i] = analogRead(potPins[i]);
  }

  // find largest
  for (byte i = 0; i < 3; i++) {
    if(potVals[i] > largestVal) largestVal = potVals[i];
  }

  //count largest
  for (byte i = 0; i < 3; i++) {
    if(potVals[i] == largestVal) largestCount++;;
  }

  if(largestCount == 3) {
    // ok to move them all
    for (byte i = 0; i < 3; i++) {
      digitalWrite(leds[i], HIGH);
    }
  }
  else {
    //only move the ones that are NOT large
    for (byte i = 0; i < 3; i++) {
      digitalWrite(leds[i], potVals[i] == largestVal ? LOW : HIGH);
    }
  }
}

Exercises:

1: alter this so that the pots are not moved once they reach some target value

2: alter this so that it includes some slop - once all the pots are within (say) 5 of the largest value, it becomes ok to move them all (hint: think in terms of the size of the range of values of the pots.)

3: alter this so that the pots will be moved up or down so that they reach a target value, which will be given by a fourth pot. Instead of ledPin[], have six leds named ledUpPin[] and ledDownPin[]. Use red and green leds FTW.

4: (advanced) add hysteresis on an individual basis to each pot, to mimimize 'hunting'. Pots that are currently moving should tend to be permitted to continue to move, pots that are stopped should become a little "sticky". This becomes useful when one of the pots is driving a load which tends to be 'faster' or 'slower' than the other loads.