If statement with multiple boolean OR statements

Hi all,

I am setting a condition where if certain angle readings are detected the device will send an alert. Currently my conditional code looks like this

//Calculating the angle differences
  flex = angle_pitch_output - angle_f2;
  rot = angle_r - angle_r2;

//Vibration alert
  if(flex < -15 || flex >= -15 && flex < 0 && rot <0 || flex >= 0 && flex < 15 && rot <-30 || flex >= 15 && flex < 30 && rot <-60
  || flex >= 45 && flex < 60 && rot > 60 || flex >= 60 && flex < 75 && rot > 30 || flex >= 75 && flex < 90 && rot > 15 || flex >= 90)
  {
    analogWrite(vibration,150);
  }
  else
  {
    analogWrite(vibration,0);
  }

Is there a way to clean up the if statement here? I am basing if off of a table which I attached below.

Thanks!

OP image:

You could convert the rotation and flexion values into category codes, then use table-lookup based on
the category codes. If say the rotation code was consecutive integers, 0,1,2,... and the flexion/extension
code was a bit mask 0x1, 0x2, 0x4, 0x8, 0x10, ...., then the rotation could be an index into a table of
bitpatterns representing rows of the table.

Now is a good time to decide whether you will ever want to distinguish between "high" and "alert".

@MarkT, thanks for the suggestion! I'm quite new at coding so I'll take a look at how to make a lookup table. Is there any benefit to using a lookup table rather than what I currently have, other than cleaning up the code a bit (just curious) i.e is it faster for the processor or uses less memory?

@aarg, I am not differentiating high and alert, forgot to mention that at the start. Also thanks for posting my image.

Yes, a lookup table is much clearer to read (just look at the chart you posted for example!) so it is much easier to maintain as well as less likely to contain mistakes. It is faster in most cases.

The table seems to imply that these aren't ranges, but discrete values. Do you ever get values in between the values listed in the table?

If not, then you could reduce the entire thing to a lookup table that takes 90 bytes. Since it is constant, you could also move it into PROGMEM, so no RAM needed.

For example:

//  Anonymous enums are a good way of defining a few integer constants for readability
enum
{
   LOW,
   ALERT,
   HIGH
};

byte actionTable[9][10] = 
{
   {HIGH, HIGH, ALERT, LOW, LOW, LOW, LOW, LOW, LOW, LOW},
   //  Similarly for other 8 rows
};

//  assuming all values are exactly multiples of 15 like the table says...
//  Normalize values to range from 0-> the maximum, divide by 15 to get the index
byte action = actionTable[(rotation+60)/15][(flexion+15)/15];

If space is a premium and you still want a lookup table, you could pack each row into one 32-bit integer. Then the entire table would be 36 bytes. Slightly more complicated code of course, but not terribly difficult.

Unfortunately, I need to interpret the table as a range of values. I think it's laid out rather poorly (I didn't make it), for example if there is 0 rotation and the leg is in 90-105 degrees flexion it should send an alert. Is there a way to do a range of values with a lookup table?

Thanks for the responses!

Playing off post #2, you could map() the rotation values to array offsets like so:

// Map angles to array offsets

// https://forum.arduino.cc/index.php?topic=670804.msg4514962#msg4514962

void setup() {
  Serial.begin(115200);
  int rotationIndex;
  for (int rotationValue = -65; rotationValue < 66; rotationValue++) {
    if (rotationValue % 15 == 0) Serial.println("valu  offset");
    Serial.print(rotationValue);
    Serial.print("\t");
    rotationIndex = map(rotationValue, -60, 60, 0, 8);
    Serial.println(rotationIndex);
  }
}

void loop() {

}

and make a similar one for the flex values. The array value at [rotationIndex][flexIndex] holds the status code/value.

liux3292:
Unfortunately, I need to interpret the table as a range of values. I think it’s laid out rather poorly (I didn’t make it), for example if there is 0 rotation and the leg is in 90-105 degrees flexion it should send an alert. Is there a way to do a range of values with a lookup table?

Thanks for the responses!

Yes, it would be trivial. Just use this:

byte action = actionTable[(rotation+60+14)/15][(flexion+15+14)/15];

We take advantage of the fact that in C++ integer division of positive numbers always rounds down.
So, for a value of 91, we add 15 (to get it zero based) and another 14 (for rounding), giving 120. 120/15 = 8, which in c++ is the 9th value, which is the box you want.
At the other end, 105 maps to 134. 134/15 is, again, 8, so same box. 106 will jump to the next box.
if you want to be absolutely sure that your values always end up in the array, you can add some checks before the table look-up:

   if (rotation < -60) rotation = -60;
   if (rotation > 60 ) rotation = 60;
   //  Similarly for flexion