Lighting control programming

Hi,
I am implementing automated lighting control using Arduino Uno.Reference lux value is set to 350 and I use a LDR to sense the light and calibrated it into lux value in the program.
But I observe flickering in the light output because the output doesn't settle at desired 350 Lux.
Following is the code

#include<math.h>
const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to
const int analogOutPin = 11; // Analog output pin that the LED is attached to

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(analogInPin); 
float three=(-.000029333)*pow(sensorValue,3)  ;//program calibration
float two=(.0311)*pow(sensorValue,2); //program calibration
float one=(-11.1963)*sensorValue;  //program calibration
float lux= three+two+one+1426; //program calibration
if(lux<=0)
{
  lux=0;
}
if(lux>=350)
{
  lux=350;
}
 Serial.println("lux= " );                       
  Serial.println(lux);    
 // map it to the range of the analog out:
  outputValue = map(lux, 350, 0, 0, 204);  
  // change the analog out value:
   digitalWrite(9, HIGH);
 digitalWrite(10, LOW);
  analogWrite(analogOutPin, outputValue);           

  // print the results to the serial monitor:
  Serial.println("sensor = " );                       
  Serial.print(sensorValue);      
  Serial.print("\t output = ");      
  Serial.println(outputValue);   

  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading:
  delay(2);                     
}

I have attached the image of output at the terminal with this post.
Can someone help me to solve this issue?

float three=(-.000029333)*pow(sensorValue,3)  ;//program calibration

pow() is a pretty expensive operation when the arguments are ints.

float three=(-.000029333)*sensorValue*sensorValue*sensorValue;

Much faster.

  outputValue = map(lux, 350, 0, 0, 204);

map() doesn't take float arguments. It makes no sense to call it with a float.

I gave up trying to understand your output. Use print() to print the id. Use println() to print the value. Print the stuff in the order it is read/computed.

Hi, it looks as though you are trying to use the map function to control the output brightness of the LED, if the lumens is low then the map output gives a higher level to brighten the LED and vice versa.
Sorry but as you can see it doesn't work.
You should be using a PID type function.
Or do it set by step.

  • 1 In SETUP, Initially set output to LED to 0.
  • 2 In LOOP, Measure the light level, compare it to the reference POT.
  • 3 If within say 10 higher or lower than POT, do not change level
  • 4 If high then adjust output down a bit, say 5.
  • 5 If low then adjust output up a bit, say 5.
  • 6 Let program loop back to step 2

The looping then tracks the output of the LED.
Its simple, mechanical but it is easy to adjust the variables to suit your situation, I hope.
You will have to program limits, like output 0 to 255.
The 10 higher or lower than POT, is what is called dead-band and stops the program chopping around the set-point, if you make the deadband smaller you will have to also lower the adjustment steps down from the 5 in the example.

Can you please post a copy of your circuit, in CAD or picture of hand drawn circuit in jpg, png or pdf format.
And a picture of your project.

Thanks hope this helps.
Tom....... :slight_smile:

Hi PaulS,

Sorry for the bad output format. I have attached a proper one now.
The issue is that output doesn't converge to the reference value.Initially as the brightness is low, the output PWM is increasing which inturn increases the light output.Now the sensor detects this increased brightness and reduces the PWM value which decreases the brightness.
This loop goes on for ever and this causes flickering of LED lamp and also it doesn't settle at the reference brightness value.

Sorry for the bad output format. I have attached a proper one now.

Which means, I assume, that you changed the code. So, where is the new code?

Hi Tom,
I executed as per your logic and got the desired output.The only issue is that constrain function doesn't limit the values.
Here is the code:

#include<math.h>
const int analogInPin = A0;  // Analog input pin that the sensor is attached to
const int analogOutPin = 11; // Analog output pin that the LED is attached to

int sensorValue = 0;        // value read from the sensor
int outputValue = 0;  
float lux=0;
int ref=350;  //reference lux value
int tolerance=5;  / lux tolerance percentage
float mn=((100-tolerance)/100.0)*ref;
float mx=((100+tolerance)/100.0)*ref;


float pwm;
int sampling=10000;  //sensor sampling interval
void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
}

void loop() {
// if lux reference is less than 20; switch off the lamp
  if(ref<20)
  {
    digitalWrite(9, HIGH);
 digitalWrite(10, LOW);
    analogWrite(analogOutPin, 0);
  }
  /*Serial.print("minimum= " );                       
 Serial.println(mn); 
 Serial.print("maximum= " );                       
 Serial.println(mx); */
  // find the corrsponding PWM value for reference:
  if(lux<mn || lux>mx)
  {
  float a=(-0.00012415)*ref*ref;
  float b=0.2901*ref;
  pwm=a+b+1.0156;
  Serial.print("initial pwm");
  Serial.println(pwm);
  outputValue=pwm*2.55;
  Serial.print("initial output");
  Serial.println(outputValue);
   digitalWrite(9, HIGH);
 digitalWrite(10, LOW);
  analogWrite(analogOutPin, outputValue); 
//convert the sensor input value to lux value          
  sensorValue = analogRead(analogInPin); 
   Serial.print("initial sensor = " );                       
  Serial.println(sensorValue); 
float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
float two=(.0311)*pow(sensorValue,2);
float one=(-11.1963)*sensorValue;
lux= three+two+one+1426;
 Serial.print("initial lux = ");
 constrain(lux, 0, 500);
  Serial.println(lux);

for(;lux<mn;)
{
  outputValue=outputValue+5;
  constrain(outputValue, 0, 255);
  Serial.print("output value = " );                       
 Serial.println(outputValue);
   analogWrite(analogOutPin, outputValue);
  sensorValue = analogRead(analogInPin); 
  float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
float two=(.0311)*pow(sensorValue,2);
float one=(-11.1963)*sensorValue;
lux= three+two+one+1426;
constrain(lux, 0, 500);
Serial.print("lux= " );                       
 Serial.println(lux);  
   
 
}
for(;lux>mx;)
{
  outputValue=outputValue-5;
  constrain(outputValue, 0, 255);
  Serial.print("output value = " );                       
 Serial.println(outputValue);
   analogWrite(analogOutPin, outputValue);
  sensorValue = analogRead(analogInPin); 
  float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
float two=(.0311)*pow(sensorValue,2);
float one=(-11.1963)*sensorValue;
lux= three+two+one+1426;
constrain(lux, 0, 500);
Serial.print("lux= " );                       
 Serial.println(lux);  
  
}
  }
 
 /* Serial.print("output value = " );                       
 Serial.println(outputValue);*/
//sample the brighness again after a delay 
 delay(sampling); 
  sensorValue = analogRead(analogInPin); 
  float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
float two=(.0311)*pow(sensorValue,2);
float one=(-11.1963)*sensorValue;
lux= three+two+one+1426;
constrain(lux, 0, 500);
 Serial.print("lux= " );                       
 Serial.println(lux);  
}

you can see from the code that I have constrained lux between 0 to 500(this is because i get negative lux value after calibration) and output to 0 to 255( so that PWM output doesn't exceed 255).
Any help on that front will be appreciated.Thank you :slight_smile:

HI PaulS,
I have changed the logic now. Pls see my previous post.

  if(ref<20)
  {

ref is (supposed to be) a constant. Why are you comparing one constant to another?

  if(lux<mn || lux>mx)
  {

You have not assigned a value to lux, by reading anything, or by computing anything.

  float a=(-0.00012415)*ref*ref;
  float b=0.2901*ref;
  pwm=a+b+1.0156;

These are never going to change. Is there any reason to compute them on every pass through loop()?

  outputValue=pwm*2.55;
  Serial.print("initial output");
  Serial.println(outputValue);

Why is the output value based on a constant?

 constrain(lux, 0, 500);

If lux is less than 0, return 0, and discard the result.
If lux is greater than 500, return 500, and discard the result.
If lux is between 0 and 500, return the value of lux, and discard the result.

You might as well delete this line for all the good it is doing.

for(;lux<mn;)

That's about the stupidest for loop I've ever seen. It just screams clueless.

I stopped reading there.

Hi,
I have modified the program to receive reference LUX value from user.
Here is the part of the code for receiving the reference value

if (Serial.available() ==3)
 {
                // read the incoming byte:
                Serial.readBytesUntil('\n',buffer1, 3);
                 ref=atoi(buffer1);
                 Serial.print("Reference Lux value  :");
                 Serial.println(ref);
}

The problem here is that,If the user enters say "12345" it takes "123" as reference value and executes the program.And next time when user enters say "234" it clubs the remaining "45" entered in the previous input with "2" and takes the reference lux to be "452".This loop goes on.
How can I clear the remaining nos after the input is taken?

I tried the following code.But it doesn't help

 if (Serial.available() ==3)
 {
                // read the incoming byte:
                Serial.readBytesUntil('\n',buffer1, 3);
                 ref=atoi(buffer1);
                 Serial.print("Reference Lux value  :");
                 Serial.println(ref);
  while(Serial.available())
  {
  Serial.read();
  }
 }

Hi, ditto what PaulS said.

I would suggest you start you program from scratch and build it up section by section.
I cannot see anything in your program that looks like the process I described.
You need to add structure to your programming.

I am surprised it complied after fixing a missing / in line 9.
Also can you do TOOLS, AUTO FORMAT please in the IDE to offset the for and if functions.

Tom.... :slight_smile:

Can you please post a copy of your circuit, in CAD or picture of hand drawn circuit in jpg, png or pdf format.

I agree. And to start, forget the lux calculations and try to get the led to return an analogRead() value first.

Then you can add the math for lux . All you have to do is map the lux input to a number from 0-1023, IMO it looks like a lot of unnecessary machinations.

The problem here is that,If the user enters say "12345"

Dumb ass user! Perhaps YOU should be smart enough to print a (better) prompt.

How can I clear the remaining nos after the input is taken?

Size the array correctly. Do NOT expect users to enter nothing but valid data. Expect them to do dumb shit. Every time!

I tried the following code.But it doesn't help

Y o u . D o n ' t s e e m t o u n d e r s t a n d s e r i a l d a t a i s s l o w.

Once you've read the first three bytes, the rest of the data hasn't arrived yet. So, of course, that block does nothing.

Hi guys,

The code which I have put earlier works perfectly for my requirement.
The only issue is constrain function. It doesnt seem to execute what it is supposed to do.Right now I am using IF loop to acheive the same,But as you know it takes more space.And the second issue is about how to clear extra values stored at buffer if more than 3 digits are entered. It will be helpful if someone can clear that.I can't ask the user to type exactly only 3 digit nos for receiving lux values.

Hi Tom,
I will upload the circuit diagram soon. For ur reference,following is the structured code

 #include<math.h>
const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to
const int analogOutPin = 11; // Analog output pin that the LED is attached to

int sensorValue = 0;        // value read from the pot
int outputValue = 0;  
float lux=0;
int ref=350;
int tolerance=5;
float mn=((100-tolerance)/100.0)*ref;
float mx=((100+tolerance)/100.0)*ref;


float pwm;
int sampling=10000;
void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
}

void loop() {
  if(ref<20)
  {
    digitalWrite(9, HIGH);
    digitalWrite(10, LOW);
    analogWrite(analogOutPin, 0);
  }
  /*Serial.print("minimum= " );                       
   Serial.println(mn); 
   Serial.print("maximum= " );                       
   Serial.println(mx); */
  // read the analog in value:
  if(lux<mn || lux>mx)
  {
    float a=(-0.00012415)*ref*ref;
    float b=0.2901*ref;
    pwm=a+b+1.0156;
    Serial.print("initial pwm");
    Serial.println(pwm);
    outputValue=pwm*2.55;
    Serial.print("initial output");
    Serial.println(outputValue);
    digitalWrite(9, HIGH);
    digitalWrite(10, LOW);
    analogWrite(analogOutPin, outputValue);           
    sensorValue = analogRead(analogInPin); 
    Serial.print("initial sensor = " );                       
    Serial.println(sensorValue); 
    float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
    float two=(.0311)*pow(sensorValue,2);
    float one=(-11.1963)*sensorValue;
    lux= three+two+one+1426;
    Serial.print("initial lux = ");
    constrain(lux, 0, 500);
    Serial.println(lux);

    for(;lux<mn;)
    {
      outputValue=outputValue+5;
      constrain(outputValue, 0, 255);
      Serial.print("output value = " );                       
      Serial.println(outputValue);
      analogWrite(analogOutPin, outputValue);
      sensorValue = analogRead(analogInPin); 
      float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
      float two=(.0311)*pow(sensorValue,2);
      float one=(-11.1963)*sensorValue;
      lux= three+two+one+1426;
      constrain(lux, 0, 500);
      Serial.print("lux= " );                       
      Serial.println(lux);  


    }
    for(;lux>mx;)
    {
      outputValue=outputValue-5;
      constrain(outputValue, 0, 255);
      Serial.print("output value = " );                       
      Serial.println(outputValue);
      analogWrite(analogOutPin, outputValue);
      sensorValue = analogRead(analogInPin); 
      float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
      float two=(.0311)*pow(sensorValue,2);
      float one=(-11.1963)*sensorValue;
      lux= three+two+one+1426;
      constrain(lux, 0, 500);
      Serial.print("lux= " );                       
      Serial.println(lux);  

    }
  }

  /* Serial.print("output value = " );                       
   Serial.println(outputValue);*/
  delay(sampling); 
  sensorValue = analogRead(analogInPin); 
  float three=(-.000029333)*sensorValue*sensorValue*sensorValue ;
  float two=(.0311)*pow(sensorValue,2);
  float one=(-11.1963)*sensorValue;
  lux= three+two+one+1426;
  constrain(lux, 0, 500);
  Serial.print("lux= " );                       
  Serial.println(lux);  

}

you will want to review how to use constrain()

constrain(lux, 0, 500);

you are nor assigning this expression to a variable.

you would typically see:

myConstrainedNumber = constrain(lux, 0, 500);

Hi BulldogLowell,

Thank you.constrain function is working now :).

Hi Guys,

The problem here is that,If the user enters say "12345" it takes "123" as reference value and executes the program.And next time when user enters say "234" it clubs the remaining "45" entered in the previous input with "2" and takes the reference lux to be "452".This loop goes on.

Can u help me solve this issue? I tried limiting the buffer size to 4 (3 data bytes and one for '\n').But it doesn't help. Here is the code

char buffer1[ 4];
void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  Serial.println("enter reference lux value");
}

void loop()
{ 
  if (Serial.available() ==3)
  {
    // read the incoming byte:
    Serial.readBytesUntil('\n',buffer1, 3);
    Serial.print("Buffer  :");
    Serial.println(buffer1);
    int ref=atoi(buffer1);

    Serial.print("Reference Lux value  :");
    Serial.println(ref);
  }
}

try this:

void setup() 
{
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  Serial.println("enter reference lux value");
}

void loop()
{ 
  if (Serial.available())
  {
    // read the incoming int:
    int myInt = Serial.parseInt();
    Serial.print("Reference Lux value  :");
    Serial.println(myInt);
  }
  //error check your input here
}

Thank You BulldogLowell :slight_smile:

I just modified the program a little since I want to take only values between o and 350.
Here is the code

void setup() 
{
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  Serial.println("enter reference lux value");
}

void loop()
{ 
  if (Serial.available())
  {
    // read the incoming int:
    int myInt = Serial.parseInt();
    if(myInt>=0 && myInt<=350)
    {
    Serial.print("Reference Lux value  :");
    Serial.println(myInt);
    }
    else
     Serial.print("Enter valid Lux value between 0 to 350  :");
  }
  
}

Hi guys,

I am trying to implement the same thing wireless.
The Light sensors will communicate to the Light control arduino node through xbee radios (S2). I have put two light sensors to communicate with the control node.
I am a newbie to zigbee communication. I want to learn to configure these xbee in API mode.I am using X-CTU version 6.1.1 to configure.Any help would be appreciated.
I have configured them as follows

Radio 1.
XB24-ZB Ver:21A7
ZIGBEE COORDINATOR API
Pan ID: 10
SH:13A200
SL:4086DE9E
DH:13A200
DL:40B3EE21

Radio 2.
XB24-ZB Ver:29A7
ZIGBEE ROUTER API
PAN ID :10
SH:13A200
SL:40B3EE21
DH:13A200
DL:4086DE9E

I checked for the network topology and found both nodes are connected.Pls find the attached image for the topology.
Now how to test communication between them?. I tried to communicate as in AT mode by typing in one console and receiving the same in another radios console. But API mode is asking for frames. I have attached the image of the screen. Can someone help on how to proceed from here?

I checked for the network topology and found both nodes are connected.

So, what is the problem?

Now how to test communication between them?

Send a frame of data from one to the other. Have the Arduino that the other is connected to print the frame that it received.

I tried to communicate as in AT mode by typing in one console and receiving the same in another radios console.

Why?

But API mode is asking for frames.

Well, of course it is. Why is that a surprise?

Can someone help on how to proceed from here?

This being the programming forum, where we discuss programming, posting some code just might be the next step.