Unable to get multiple "if statements" to produce desired results

I’m trying to write the required code to get a light box to increase it’s brightness in accordance to specific distance readings from an Ultra Sonic Distance sensor. The sensor is reading correctly and the code I have verifies that. I originally had a script that would change the brightness from a specific starting brightness to a brighter state and while it worked, I now want something more precise with regard to distances from the box. I’m attempting (unsuccessfully) to have an init state of 1/4 LED intensity, then 1/2, 3/4 and finally full brightness. I’m using: analogWrite(transistorPin, 64 … transistorPin 127 … transistorPin 191 … and transistorPin 255) respectively. I feel as though my failure is a lack of understanding of the if/else interaction. If any one could help me straighten out my code, I’d be grateful. Thanks in advance.

What I’m attempting to produce is:

1/4 LED intensity if an individual was “read” to be standing 240 inches from the light box.
1/2 intensity when the person was within 114"
3/4 intensity when 72"from the light box
Full brightness when standing 18’’ from the light box.

My code reads as follows:

#include "Arduino.h"
class Ultrasonic
{
	public:
		Ultrasonic(int pin);
        void DistanceMeasure(void);
		long microsecondsToCentimeters(void);
		long microsecondsToInches(void);
	private:
		int _pin;//pin number of Arduino that is connected with SIG pin of Ultrasonic Ranger.
        long duration;// the Pulse time received;
};
Ultrasonic::Ultrasonic(int pin)
{
	_pin = pin;
}
/*Begin the detection and get the pulse back signal*/
void Ultrasonic::DistanceMeasure(void)
{
    pinMode(_pin, OUTPUT);
	digitalWrite(_pin, LOW);
	delayMicroseconds(2);
	digitalWrite(_pin, HIGH);
	delayMicroseconds(5);
	digitalWrite(_pin,LOW);
	pinMode(_pin,INPUT);
	duration = pulseIn(_pin,HIGH);
}
/*The measured distance from the range 0 to 400 Centimeters*/
long Ultrasonic::microsecondsToCentimeters(void)
{
	return duration/29/2;	
}
/*The measured distance from the range 0 to 240 Inches*/
long Ultrasonic::microsecondsToInches(void)
{
	return duration/74/2;	
}

Ultrasonic ultrasonic(7);
const int transistorPin = 9; // from dimmer sketch
void setup()

{
	Serial.begin(9600);
        pinMode(transistorPin, OUTPUT);
}

void loop()
{
	long RangeInInches;
	long RangeInCentimeters;
	ultrasonic.DistanceMeasure();// get the current signal time;
    RangeInInches = ultrasonic.microsecondsToInches();//convert the time to inches;
	RangeInCentimeters = ultrasonic.microsecondsToCentimeters();//convert the time to centimeters
	Serial.println("The distance to obstacles in front is: ");
	Serial.print(RangeInInches);//0~240 inches
	Serial.println(" inch");
//	Serial.print(RangeInCentimeters);//0~400cm
//	Serial.println(" cm");
	delay(1000);

// For Full Brightness
if (RangeInInches < 18)
      {
        int brightness = (17-RangeInInches)*2; 
        //times 2 was close enough for converting inches to 0-255
        //transition from side maybe a problem
        if(brightness > 254)
        {
          analogWrite(transistorPin, 255);
        }
        else
        {
          analogWrite(transistorPin, brightness);
        }
      
       
      }
      
      else
      {
        analogWrite(transistorPin,191); // raise or lower from 64 minimum 1/4 brightness
        Serial.println(" Full Brightness");
      }

// For 3/4 Brightness
if (RangeInInches < 72)
      {
        int brightness = (71-RangeInInches)*2; 
        //times 2 was close enough for converting inches to 0-255
        //transition from side maybe a problem
        if(brightness > 254)
        {
          analogWrite(transistorPin, 191);
        }
        else
        {
          analogWrite(transistorPin, brightness);
        }
      
       
      }
      
      else
      {
        analogWrite(transistorPin, 127); // raise or lower from 64 minimum 1/4 brightness
        Serial.println(" 3/4 light value");
      }

// For 1/2 Brightness
if (RangeInInches < 114)
      {
        int brightness = (113-RangeInInches)*2; 
        //times 2 was close enough for converting inches to 0-255
        //transition from side maybe a problem
        if(brightness > 254)
        {
          analogWrite(transistorPin, 127);
        }
        else
        {
          analogWrite(transistorPin, brightness);
        }
      
       
      }
      
      else
      {
        analogWrite(transistorPin, 64); // raise or lower from 64 minimum 1/4 brightness
        Serial.println(" Half light value");
      }

// For 1/4 Brightness
if (RangeInInches < 240)
      {
        int brightness = (239-RangeInInches)*2; 
        //times 2 was close enough for converting inches to 0-255
        //transition from side maybe a problem
        if(brightness > 254)
        {
          analogWrite(transistorPin, 64);
        }
        else
        {
          analogWrite(transistorPin, brightness);
        }
      
       
      }
      
      else
      {
        analogWrite(transistorPin, 64); // raise or lower from 64 minimum 1/4 brightness
        Serial.println(" Minimum light value");
      }
      
      
//for (int brightness = 0; brightness < 255; brightness++) {
//      analogWrite(transistorPin, brightness);
//      delay(10);
//    }
//
//    delay(2000);
//
//    for (int brightness = 255; brightness >= 0; brightness--) {
//          analogWrite(transistorPin, brightness);
//          delay(10);
//    }

    delay(500);

}

The way you have it now, if the range is less than 18", your if tests fall all the way through, so the last test is the one that persists. What you need to do is a cascading if test where you put the furthest distance test first:

  if (RangeInInches > 114) {
    // Do this
  } else {
    if (RangeInInches > 72) {
      // Do this instead
    } else {
      if (RangeInInches > 18) {
        // Do getting closer
      } else {
          Serial.println("We're going to hit the wall!");
        }
      }
    }
  }

This code checks for far away objects first and reacts accordingly. Because your code checked for closeness as separate distance checks, you would almost always fall into the last if block.

EconJack, I’m beholding to you, Thanks for your time. I do understand the logic and my inversion.

I didn’t have much time to access the light boxes this evening, I can get back at them tomorrow. It’s clear to me you understand what I’m trying to achieve, am I interpreting your correction properly?

#include "Arduino.h"
class Ultrasonic
{
	public:
		Ultrasonic(int pin);
        void DistanceMeasure(void);
		long microsecondsToCentimeters(void);
		long microsecondsToInches(void);
	private:
		int _pin;//pin number of Arduino that is connected with SIG pin of Ultrasonic Ranger.
        long duration;// the Pulse time received;
};
Ultrasonic::Ultrasonic(int pin)
{
	_pin = pin;
}
/*Begin the detection and get the pulse back signal*/
void Ultrasonic::DistanceMeasure(void)
{
    pinMode(_pin, OUTPUT);
	digitalWrite(_pin, LOW);
	delayMicroseconds(2);
	digitalWrite(_pin, HIGH);
	delayMicroseconds(5);
	digitalWrite(_pin,LOW);
	pinMode(_pin,INPUT);
	duration = pulseIn(_pin,HIGH);
}
/*The measured distance from the range 0 to 400 Centimeters*/
long Ultrasonic::microsecondsToCentimeters(void)
{
	return duration/29/2;	
}
/*The measured distance from the range 0 to 157 Inches*/
long Ultrasonic::microsecondsToInches(void)
{
	return duration/74/2;	
}

Ultrasonic ultrasonic(7);
const int transistorPin = 9; // from dimmer sketch
void setup()

{
	Serial.begin(9600);
        pinMode(transistorPin, OUTPUT);
}

void loop()
{
	long RangeInInches;
	long RangeInCentimeters;
	ultrasonic.DistanceMeasure();// get the current signal time;
    RangeInInches = ultrasonic.microsecondsToInches();//convert the time to inches;
	RangeInCentimeters = ultrasonic.microsecondsToCentimeters();//convert the time to centimeters
	Serial.println("The distance to obstacles in front is: ");
	Serial.print(RangeInInches);//0~240 inches
	Serial.println(" inch");
//	Serial.print(RangeInCentimeters);//0~400cm
//	Serial.println(" cm");
	delay(1000);

      if (RangeInInches > 114) {
    // Do this
    analogWrite(transistorPin, 127)
  } else {
    if (RangeInInches > 72) {
      // Do this instead
      analogWrite(transistorPin, 191)
    } else {
      if (RangeInInches > 18) {
        // Do getting closer
        analogWrite(transistorPin, 255)
      } else {
          Serial.println("We're going to hit the wall!");
        }
      }
    }
  }

      
      else
      {
        analogWrite(transistorPin, 75); // raise or lower from 75 minimum
        Serial.println(" Minimum light value");
      }
      
//for (int brightness = 0; brightness < 255; brightness++) {
//      analogWrite(transistorPin, brightness);
//      delay(10);
//    }
//
//    delay(2000);
//
//    for (int brightness = 255; brightness >= 0; brightness--) {
//          analogWrite(transistorPin, brightness);
//          delay(10);
//    }

    delay(500);

}

“Are you under 18?”

  • yes
    “Ok - do A”.
    “Are you under 72”
  • yes
    “Ok - do B”.

If the number is (say) three, then they will do BOTH A and B. Which is not what you want.

First, I would pull the analogWrite to the bottom, making the whole thing a little clearer. This means pulling brightness outside the if()s

Your next problem is - obviously - that the later ifs are not ignoring the case where brightness would have been caught by the previous if(). You probably want else’s in there. Oh, and there’s no case to handle range > 240. I’ll add a final else.

Your next issue is the hideous way you are handling the math.

We usually rely on the fact that division with integers truncates. So if a value ranges up to (but not including) 34, and we want to scale it to a value up to (but not including) 256, then multiply it by 256 and divide by 34.

Using these techniques, we get this:

int brightness;

const int range_100 = 18;
const int range_75 = 72;
const int range_50 = 114;
const int range_25 = 240;  

// For Full Brightness
if (RangeInInches < range_100) {
  brightness = ((range_100 - RangeInInches) * 64) / (range_100) + 64*3;
}
// For 3/4 Brightness
else
if (RangeInInches < range_75) {
  brightness = ((range_75-RangeInInches) * 64) / (range_75-range_100) + 64*2; 
}

// For 1/2 Brightness
else
if (RangeInInches < range_50) {
  brightness = ((range_50-RangeInInches) * 64) / (range_50-range_75) + 64*1; 
}

// For 1/4 Brightness
else
if (RangeInInches < range_25)  {
  brightness = ((range_25-RangeInInches) * 64) / (range_25-range_50); 
}
      
else {
  brightness = 0;
}

brightness = constrain(brightness, 0, 255); // just to be sure. http://arduino.cc/en/Reference/Constrain

analogWrite(transistorPin, brightness);

Notice that we multiply by 64 before the scaling. This is important, because integer division truncates. If we did the division first, the values would be zero. The parenthesis rate there to force the compiler to do the right thing, rather than precalculating (64/range_100).

I suppose the fenceposts could also be put into an array, and this nest of ifs() replaced by a loop - but meh.

Another alternative would be to work out a mathematical function that achieves the effect you want. Maybe what you actually want is for the brightness to be proportional to the inverse of the square-root of the distance, or something (that is, the brightness of the led is proportional to how bright a light held by the target would appear to the unit).