[SOLVED] proximity_to_brightness _using_multiple_sensors

Hello there!

This is my first post here, as I am new to Arduino. My programming skills are base-level and i could really use some help building the code for my first project.

So, my project is an interacive art installation, where the viewer's dinstance from a light source(high powered led) will be sensed and accordingly the brightness of the LED will change. (the closer the viewer will be, the more bright the led will become).

Because I want 360 degrees sensing, i thought of using multiple ultrasonic sensors (12 or more) and try to adjust the New Ping code (15 sensors example Arduino Playground - NewPing Library ) according to my needs.

So far I have adjusted and tried the code with 3 sensors and I get some results (but not the ones I want). With the code as it is right now the result i get is that the led will dim or brighten only according to the values sent from the last sensor in line(sensor 2) , while the other two(sensor 0, 1) are ignored.

What i would ideally want the code to do is find which is the smallest distance it gets from all the sensors (except from 0cm because this is the value it gets when it receives no signal at all) and change the brightness of the led accordingly. I have tried some things myself but they failed, i think it exceeds my programming skills...

Furthermore, because i want the dimming to be smooth, i have to find a way to somehow merge some smoothing code to avoid noise and false readings(maybe this one http://arduino.cc/en/Tutorial/Smoothing or this method from the new ping library sonar.ping_median(iterations); - Do multiple pings (default=5), discard out of range pings and return median in microseconds -) .

Also I thought of using a low-pass filter to smoothen the pwm signal (before reaching the dim pin of the dimmable led driver).

Any ideas or suggestions on this would be also really appreciated.

Thanks in advance!!

I will now post the code here

/ ---------------------------------------------------------------------------
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
// would normally process the sensor results in this function (for example, decide if a robot needs to
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
// ---------------------------------------------------------------------------
#include <NewPing.h>

#define SONAR_NUM     3 // Number of sensors.
#define MAX_DISTANCE 150// Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

int led = 3;           // the pin that the LED is attached to
int brightness = 1;    // how bright the LED is

unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
uint8_t currentSensor = 0;          // Keeps track of which sensor is active.

int allSensors = (0, 1, 2);  //include all sensors under the name "allSensor"

NewPing sonar[SONAR_NUM] = {     // Sensor object array.
  NewPing(23, 22, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(25, 24, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(27, 26, MAX_DISTANCE)  // Each sensor's trigger pin, echo pin, and max distance to ping.
};

void setup() {
  Serial.begin(115200);
  pingTimer[0] = millis() + 75;           // First ping starts at 75ms, gives time for the Arduino to chill before starting.
  for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {
 
  
  for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
    if (millis() >= pingTimer[i]) {         // Is it this sensor's time to ping?
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
      if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      currentSensor = i;                          // Sensor being accessed.
      cm[currentSensor] = 0;                      // Make distance zero in case there's no ping echo for this sensor.
      sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
      
  long duration, inches, cm;
     
   cm = microsecondsToCentimeters(duration);  // convert the time into a distance
  }
  }
  
}

void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.


 brightness = map(constrain(cm[allSensors], 10, 150), 150, 10, 1, 255); // maps the brightness to the                        distance, for 150cm to 10 cm the brightness changes from (almost) dark to bright,
                                                                      //from 10cm to 2cm(which is the smallest distance that the sensor can detect) it remains full brightness  
 
 analogWrite(led, brightness);  //lights the LED according to the brightness set above


if (cm[allSensors]==0)

 {
   analogWrite(led, 1);  //this is necessary so that the LED doesn t remain lit when the sensor doesn't get any value 
    } 
    
    
    delay(5); //delays 5mils for smoother result
    
  
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(cm[i]);
    Serial.print("cm ");
  }
  Serial.println();
}

 
long microsecondsToCentimeters(long microseconds)
 {
   // The speed of sound is 340 m/s or 29 microseconds per centimeter.
   // The ping travels out and back, so to find the distance of the
   // object we take half of the distance travelled.
   return microseconds / 29 / 2;
 }
int allSensors = (0, 1, 2);  //include all sensors under the name "allSensor"

That doesn't do what you seem to expect. An 'int' variable can only store one value. The parens allow you to write several expressions in place of one, but only the result of the last expression is kept. The other expressions in the list are of use only if they have side-effects like a function call or assignment expression.

To get the smallest value you will want to step through all of the values. Start with a value of 0. If the value is still 0, replace it with the current entry, otherwise replace it if the current entry is less than the current value but greater than 0. When the loop is done the value will be 0 if all the entries were 0 or it will be the smallest non-zero value. Then you can calculate the brightness based on distance.

Thanks, I will try that!

Ok, so I tried what you suggested (for 2 sensors to make it simpler) but it still doesn't work and adjusts the brightness
only according to the last sensor's readings. I tried placing it at different places inside the code but with no luck.

int sensorVal = cm[0];

...

      if (sensorVal == 0) {sensorVal = cm[1];}  //Start with a value of 0.
If the value is still 0, replace it with the current entry

else if   ((sensorVal > cm[1]) && ( cm[1] > 0)) { sensorVal = cm[1];}  //otherwise replace it if the current entry is less than the current value but greater than 0

 else {sensorVal = cm[0];}  // otherwise do nothing, (I am not sure if this is necessary, but i put it to be sure :/ )

Maybe you can tell where am I wrong?

Instead of checking with multiple sensor. first try with one sensor. Just fix range. try to calibrate brightless accordingly

Can you check this part of code working.

 brightness = map(constrain(cm[allSensors], 10, 150), 150, 10, 1, 255);

Use Serial print so that we can understand where exact what happening. Then share screen shot. Since we dont have sensor based on output serial monitor we can tell what exact happening

This part of the code works well with one sensor, it changes the brightness of the led according to the distance (although not so smooth and linear, but in any case it is working). Where my problem is , is when I am trying to compare the readings of more than one sensors and use them accordingly.

int sensorVal = cm[0];

An array with space for zero entries ? Interesting.

if (sensorVal == 0) {sensorVal = cm[1];}  //Start with a value of 0.

Now you read a value from the second entry in the array with space for no entries. Even more interesting.

else if   ((sensorVal > cm[1]) && ( cm[1] > 0)) { sensorVal = cm[1];}  //otherwise replace it if the current entry is less than the current value but greater than 0

Getting more interesting all the time.

When an array is declared you need to declare how many entries it can hold and optionally what their initial values are.

Array indices start at zero so cm[1] refers to the contents of the second entry in the cm array, not whether the value of cm is one, which is meaningless in the context of an array.

Perhaps a little reading up on arrays would be in order.

OK finally got it working right!!
Actually @UKHeliBob I wasn t trying to set an array, just initialize a value, where the number inside the brackets (cm[0]) would be the number of the sensor (I understand that 0 is confusing, but this is how the code names the first sensor) Anyway, you helped me to get the code working and thank you for that!!

This is the improved part (for 3 sensors )

int sensorVal;

....

sensorVal = cm[0];  //set sensorVal the value of the first sensor (0)

if (sensorVal == 0) 
{sensorVal = cm[1];} //Start with a value of 0.If the value is still 0, replace it with the current entry

else if   ((sensorVal > cm[1]) && ( cm[1] > 0))    // otherwise replace it if the current entry is less than the current value but greater than 0  
   
{ sensorVal = cm[1];}                             


  if (sensorVal == 0)                              // as above
{sensorVal = cm[2];}

else if   ((sensorVal > cm[2]) && ( cm[2] > 0))    //as above
{ sensorVal = cm[2];}

//When the loop is done the value will be 0 if all the entries were 0 or it will be the smallest non-zero value.  
// Then you can calculate the brightness based on distance.

...

I will create a new thread, concerning the issues I still have with smoothing and linear dimming the Led.

Thanks again!! :slight_smile:

I will post here the whole code so that maybe it will help someone in the future

/*  Proximity_to_brightness_using_multiple_sensors

This code is an adjustment of the 15_Sensors_Example - arduino-new-ping code, which compares the results of multiple sensors' readings and sets the brightness of a LED according to the smallest distance that is received.

*/

#include <NewPing.h>

#define SONAR_NUM     3// Number of sensors.
#define MAX_DISTANCE 40//Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

int led = 3;           // the pin that the LED is attached to
int brightness = 1;    // how bright the LED is


unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
uint8_t currentSensor = 0;          // Keeps track of which sensor is active.

int sensorVal;



NewPing sonar[SONAR_NUM] = {     // Sensor object array.
  NewPing(23, 22, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(25, 24, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(27, 26, MAX_DISTANCE)  // Each sensor's trigger pin, echo pin, and max distance to ping.
};

void setup() {
  Serial.begin(115200);
  pingTimer[0] = millis() + 75;           // First ping starts at 75ms, gives time for the Arduino to chill before starting.
  for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {
 
  
  for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
    if (millis() >= pingTimer[i]) {         // Is it this sensor's time to ping?
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
      if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.

      sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      currentSensor = i;                          // Sensor being accessed.
      cm[currentSensor] = 0;                      // Make distance zero in case there's no ping echo for this sensor.
      sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
      
  long duration, inches, cm;
     
   cm = microsecondsToCentimeters(duration);  // convert the time into a distance
  }
  }
  
  
}

void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.



sensorVal = cm[0];  //set sensorVal the value of the first sensor (0)

if (sensorVal == 0) 
{sensorVal = cm[1];} //Start with a value of 0.If the value is still 0, replace it with the current entry

else if   ((sensorVal > cm[1]) && ( cm[1] > 0))    // otherwise replace it if the current entry is less than the current value but greater than 0  
   
{ sensorVal = cm[1];}                             


  if (sensorVal == 0)                              // as above
{sensorVal = cm[2];}

else if   ((sensorVal > cm[2]) && ( cm[2] > 0))    //as above
{ sensorVal = cm[2];}

//When the loop is done the value will be 0 if all the entries were 0 or it will be the smallest non-zero value.  
// Then you can calculate the brightness based on distance.


 brightness = map(constrain(sensorVal, 5, 40),40, 5, 1, 255); // maps the brightness to the distance, for 40cm to 5 cm the brightness changes from (almost) dark to bright,
                                                                      //from 10cm to 2cm(which is the smallest distance that the sensor can detect) it remains full brightness  
                                                                      
 if (sensorVal==0)

 {
   brightness = 1  ;     //this is necessary so that the LED doesn t remain lit when the sensor doesn't get any value 
    } 
    
 
 analogWrite(led, brightness);  //lights the LED according to the brightness set above
 
    delay(5); //delays 5mils for smoother result
    
  
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(cm[i]);
    Serial.print("cm ");
    
  }
  Serial.print("      ");
  Serial.print("sensorVal");
  Serial.print("=");
  Serial.print(sensorVal);
  Serial.print("    ");
  Serial.print("brightness");
  Serial.print("=");
  Serial.print(brightness);
  Serial.println();
}

 
long microsecondsToCentimeters(long microseconds)
 {
   // The speed of sound is 340 m/s or 29 microseconds per centimeter.
   // The ping travels out and back, so to find the distance of the
   // object we take half of the distance travelled.
   return microseconds / 29 / 2;
 }
sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).

Can you please explain what this line of code does bearing in mind that
(a) echoCheck is a function and you are not actually calling it here
(b) even if you did call it properly echoCheck is a void function that does not return a value

I cannot explain it to you, because I have not written it, and do not understand it completely either, I took it as it is from the New Ping library (15 sensors example sketch). Maybe you can post a question or find more information here NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.7 - #283 by teckel - Sensors - Arduino Forum