Calibrating an array of sensors

I am trying to make a interactive LED lights (addressable LED strip) with DIY IR range sensors, it all works fine but I just can’t figure out a way to calibrate them. I made few attempts but all totally failed, I’m working with 3x3 for testing but i want to expand it to the limits of the poor little arduino when it all works.

(gif of the working(ish) prototype)>>>>>> IMG 20200613 184228 7 GIF | Gfycat <<<<<<<<

any help will be appreciated

The issue is that the values arduino reads are kinda allover for eac sensor but remain sonsistant for each sesor.

first reading second reading … and so on
LED 0 Value : 43 >> LED 0 Value : 52
LED 1 Value : 80 >> LED 1 Value : 78
LED 2 Value : 9 >> LED 2 Value : 11
LED 3 Value : 49 >> LED 3 Value : 49
LED 4 Value : 158 >> LED 4 Value : 159
LED 5 Value : 11 >> LED 5 Value : 9
LED 6 Value : 11 >> LED 6 Value : 7
LED 7 Value : 280 >> LED 7 Value : 277
LED 8 Value : 323 >> LED 8 Value : 328

I can’t figure out how to map the values for each sensor

(some lines of code might be unnecessary but i left them in for the duration of bug fixes ill clean it up when it’s working and i know what i don’t need)

 #include <FastLED.h>

 
 #define COLOR_ORDER      GRB
 #define LED_TYPE         WS2811        
 #define LED_PIN          5
 #define NUM_LEDS         9           //LED count
 #define MAX_BRIGHTNESS   50    
 #define MIN_BRIGHTNESS   50     
 #define BRIGHTNESS       50
 #define SPEED            1000
 
 struct CRGB leds[NUM_LEDS];
 

 const int numOfInputs = 3;
 const int inputPins[numOfInputs] = {0,1,2};


 unsigned int analogVal[numOfInputs];
 int analogPin[] = {0,1,2};
 int digitalPin []={2,3,4};

 int counter;
 
unsigned int analogSensorRead[2];

 int i;
 int j;
 
 int hue;
 int mappedHue;
 int LEDno;
 
void setup() {
  Serial.begin(9600);   
  
  LEDS.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
  

    for (int counter=0; counter <= 2; counter++){       
      pinMode(digitalPin [counter], OUTPUT);

    }
}
void loop() {
  
  for(int i=0; i<=2; i++){
    
    digitalWrite(digitalPin[i], HIGH);

        
      for(int j=0; j<=2; j++){

         LEDno = ((numOfInputs-1)*i+i+j);
        delay(5);
        analogSensorRead[j] = analogRead(analogPin[j]);
       //Serial.println((String) +"Sensor  "+ LEDno + " Value: " + analogSensorRead[j]);
       //Serial.println((String) +"Row "+ i + " Column " + j + " Value: " + analogSensorRead[j]);
       //Serial.println(analogSensorRead[i][j]);
       
            // LEDno = ((numOfInputs-1)*i+i+j+1);
             hue = (analogSensorRead[j]);
             mappedHue = map(hue, 0, 1023, 0, 255);
             leds[LEDno] = CHSV(mappedHue, 255, 255);   
            Serial.println((String) +"LED  "+ LEDno + " Value : " + hue);
             //delay(300);
             FastLED.show();
        
      }
    digitalWrite(digitalPin[i], LOW);  
    
    
  }
}

Thank you in advance :slight_smile:

pff with the commented out stuff it gets a tad harder to read. But i figure that you read the sensor and then you want to map that value somehow

hue = (analogSensorRead[j]);
             mappedHue = map(hue, 0, 1023, 0, 255);
             leds[LEDno] = CHSV(mappedHue, 255, 255);

but since every sensor is different you need to compensate for that, right ?

first reading second reading ..... and so on
LED 0 Value : 43 >> LED 0 Value : 52
LED 1 Value : 80 >> LED 1 Value : 78

i suspect that these are fluctuations that you are measuring ? or is this the difference in values when there is movement ?
If these are fluctuations, then you do a few measurements, take an average, and store the result of that in a separate array for future reference. And then you can take that reference into account when you do the map conversion heremappedHue = map(hue, 0, 1023, 0, 255);or even earlier on somewhere.

sorry for the late reply and I’m not good with coding (its goten bit messy from my trial and error). (LED X Value Y) for each led x i get a value y and its imidiely displayed on the led strip. I wanted to save min and max values for each led and then use the min and max values to map each leds hue. but lets say with a press of a button itd recod a set of values and then sensors would get covers and another button would then record max values. and then min and max values would be used in mapping hue. if ti was just individual sensors id be fine but with

 for(int i=0; i<=2; i++){
  
   digitalWrite(digitalPin[i], HIGH);

      
     for(int j=0; j<=2; j++){
        LEDno = ((numOfInputs-1)*i+i+j+1);

i cant figure it out. i have an equation that gives me an led number for corresponding i and j values (LEDno = ((numOfInputs-1)*i+i+j):wink: what i wanted to do is sorta

ledmin[0]= some value (recored during calibration)
ledmax[0]= some value
ledmin[1] = some value
ledmax[1]= some value

and then use something like

mappedHue = map(hue, ledmin[LEDno], 1023-ledmax[LEDno], 0, 255);
i tired for over 8 hours and i cant get values to save or to be used in the way that i want even if i try manual calibration

sensors are sensitive to some extend to the ambient light so doing it manualy each tme would suck big time

oh and just incase its not clear i want each value from the sensor to be close to zero and because they dont have an even offset i cant just use a constant

ledmin[0]= some value (recored during calibration)
ledmax[0]= some value
ledmin[1] = some value
ledmax[1]= some value

and then use something like

mappedHue = map(hue, ledmin[LEDno], 1023-ledmax[LEDno], 0, 255);
i tired for over 8 hours and i cant get values to save or to be used in the way that i want even if i try manual calibration

sensors are sensitive to some extend to the ambient light so doing it manualy each tme would suck big time

oh and just incase its not clear i want each value from the sensor to be close to zero and because they dont have an even offset i cant just use a constant

That is still not quite clear to me, maybe if you explain to me for a single sensor.
Anyway i did some cleaning here, your calculation to get to LEDno seemed incorrect, somehow if you have 9 LED’s in a 3x3, it is either the way i did it, or

LEDno = j * ANPINS + i;

depending on what are your rows & collums.

#include <FastLED.h>


#define COLOR_ORDER      GRB
#define LED_TYPE         WS2811
#define LED_PIN          5
#define NUM_LEDS         9           //LED count
#define MAX_BRIGHTNESS   50
#define MIN_BRIGHTNESS   50
#define BRIGHTNESS       50
#define SPEED            1000
#define DIGPINS          3
#define ANPINS           3

struct CRGB leds[NUM_LEDS];


uint8_t  analogPin[ANPINS] = {A0, A1, A2};
uint8_t digitalPin[DIGPINS] = {2, 3, 4};

uint16_t analogSensorRead[ANPINS * DIGPINS];  // eg 3 x 3
uint16_t calSensorRead[ANPINS * DIGPINS];  // eg 3 x 3


void setup() {
  Serial.begin(9600);
  LEDS.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);

  for (int i = 0; i < DIGPINS; i++) {
    pinMode(digitalPin [i], OUTPUT);
  }
  CalibrateSensors();
}


void loop() {
  for (uint8_t i = 0; i < DIGPINS; i++) {
    digitalWrite(digitalPin[i], HIGH);
    for (uint8_t j = 0; j < ANPINS; j++) {
      delay(5);
      uint8_t LEDno = i * DIGPINS + j;
      analogSensorRead[LEDno] = analogRead(analogPin[j]);

      // now we have the new reading and can compare it to the one taken at the start
      uint16_t hue = (analogSensorRead[j]);

      uint8_t mappedHue = map(hue, 0, 1023, 0, 255);
      // and assign that to the LED
      leds[LEDno] = CHSV(mappedHue, 255, 255);
      FastLED.show();
    }
    digitalWrite(digitalPin[i], LOW);
  }
}

void CalibrateSensors() {
  for (uint8_t i = 0; i < DIGPINS; i++) {
    digitalWrite(digitalPin[i], HIGH);
    for (uint8_t j = 0; j < ANPINS; j++) {
      delay(5);
      uint8_t LEDno = i * DIGPINS + j;
      calSensorRead[LEDno] = analogRead(analogPin[j]);
    }
    digitalWrite(digitalPin[i], LOW);
  }
}

Basically if you store the readings at startup you can use those later on, but as i said i am still not quite sure what you want to do with them, so i didn’t use those values yet.
Since you actually have a 3 x 3 sensor network, it would make sense to use a 2 dimensional array for this info, but then you have to do the conversion to the led later, hence the choice to let a sensor value correspond to the led. Anyway this is a decent point to start from.

ah sorry yea LEDno is probably a bit complicated it still gives right values but thanks

I tired your code i just needed to make a single change

void loop() {
  for (uint8_t i = 0; i < DIGPINS; i++) {
    digitalWrite(digitalPin[i], HIGH);
    for (uint8_t j = 0; j < ANPINS; j++) {
      delay(5);
      uint8_t LEDno = i * DIGPINS + j;
      analogSensorRead[j] = analogRead(analogPin[j]); //  (analogSensorRead[j] instead of LEDno otherwise whole column lights up with the same hue)

other than that it looks like it works the same but now it probably runs more efficiently :slight_smile:
it looks good but how can I get the calSensorRead to save and then be used with the rest of the code that is my main issue for each corresponding LED.

how can I get the calSensorRead to save and then be used with the rest of the code that is my main issue for each corresponding LED.

it is saved herecalSensorRead[LEDno] = analogRead(analogPin[j]);, you can then use the value in the main loop.

I tired your code i just needed to make a single change

Ah yeah, well actually the analogSensorRead array is not used as an array at the moment.

analogSensorRead[LEDno] = analogRead(analogPin[j]);
      uint16_t hue = (analogSensorRead[LEDno]);  // the mistake was here

It is just being transferred to the 'hue' value. But you can use calSensorRead[LEDno] here to do the equation (or map) that you want as well.

ahh so i dont need to add extra int variables manually?

map(hue, (0-calSensorRead[LEDno]), 1023, 0, 255);

will work even if it's in a different scope? I'll get to work and hopefully it works :slight_smile:

well serial print don't lie
LEDMapped 0 Value : 2
LEDMapped 1 Value : 2
LEDMapped 2 Value : 0
LEDMapped 3 Value : 2
LEDMapped 4 Value : 2
LEDMapped 5 Value : 0
LEDMapped 6 Value : 255 (reading too low so it wrapped around nothing to worry about)
LEDMapped 7 Value : 1
LEDMapped 8 Value : 1

LEDCal 0 Value : 43
LEDCal 1 Value : 73
LEDCal 2 Value : 7
LEDCal 3 Value : 49
LEDCal 4 Value : 153
LEDCal 5 Value : 6
LEDCal 6 Value : 16
LEDCal 7 Value : 289
LEDCal 8 Value : 310
LEDCal 0 Value : 43

thanks a lot i was trying for over 12 hours xD to add int variables because i didn't know itd commit the values to memory otherwise hahaha i feel like a fool all leds are single color and the even with my hand over it the sesor reading doesnt change but it is one step clsoer :slight_smile:

just need to figure out what unit8 and unit16 things mean :slight_smile:

I'll try to mess around with it, and tomorrow I'll post an update.....

on closer inspections values jump from 0,1,2 to 254,255 when I put my hand close

IT WORKS!!!

 uint8_t mappedHue = map(hue, 25-calSensorReadLow[LEDno], 1023-calSensorReadHigh[LEDno], 0, 255); //didnt work
 uint8_t mappedHue = map(25+hue-calSensorReadLow[LEDno], 0, 1023-calSensorReadHigh[LEDno], 0, 255); works flawlessly

caibration for high values still needs to be tweeked a little color change isnt even but they are all the same color when nothing is close,

Deva_Rishi thanks a lot :slight_smile:

working code (except for high calibration ill add it later if anyone one wants to use or play around with it) and ill upload a gif tho my test rig is a little faulty

#include <FastLED.h>


#define COLOR_ORDER      GRB
#define LED_TYPE         WS2811
#define LED_PIN          5
#define NUM_LEDS         9           //LED count
#define MAX_BRIGHTNESS   50
#define MIN_BRIGHTNESS   50
#define BRIGHTNESS       50
#define SPEED            1000
#define DIGPINS          3
#define ANPINS           3

struct CRGB leds[NUM_LEDS];

#define buttonPinLow        11  //calibrate button pin
#define buttonPinHigh       12  //calibrate button pin


uint8_t  analogPin[ANPINS] = {A0, A1, A2};
uint8_t digitalPin[DIGPINS] = {2, 3, 4};

uint16_t analogSensorRead[ANPINS * DIGPINS];  // eg 3 x 3
uint16_t calSensorReadLow[ANPINS * DIGPINS];  // eg 3 x 3 
uint16_t calSensorReadHigh[ANPINS * DIGPINS];  // eg 3 x 3


void setup() {
  Serial.begin(9600);
  LEDS.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);

  for (int i = 0; i < DIGPINS; i++) {
    pinMode(digitalPin [i], OUTPUT);
  }
//  Calibrate();
}


void loop() {

  while (digitalRead(buttonPinLow) == HIGH) {
   CalibrateLow();
   }
  while (digitalRead(buttonPinHigh) == HIGH) {
   CalibrateHigh();
   }
  for (uint8_t i = 0; i < DIGPINS; i++) {
    digitalWrite(digitalPin[i], HIGH);
    for (uint8_t j = 0; j < ANPINS; j++) {
      delay(5);
      uint8_t LEDno = i * DIGPINS + j;
      analogSensorRead[j] = analogRead(analogPin[j]);

      // now we have the new reading and can compare it to the one taken at the start
      uint16_t hue = (analogSensorRead[j]);

      uint8_t mappedHue = map(25+hue-calSensorReadLow[LEDno], 0, 1023-calSensorReadHigh[LEDno], 0, 255);
      // and assign that to the LED
      leds[LEDno] = CHSV(mappedHue, 255, 255);
      //Serial.println((String) +"LEDMapped  "+ LEDno + " Value : " + mappedHue+ "   AnalogRead : "+analogSensorRead[j]+ " calLow  :"+calSensorReadLow[LEDno]+"  calHigh  :"+ calSensorReadHigh[LEDno]);
      FastLED.show();
    }
    digitalWrite(digitalPin[i], LOW);
  }
}

void CalibrateLow() {
  for (uint8_t i = 0; i < DIGPINS; i++) {
    digitalWrite(digitalPin[i], HIGH);
    for (uint8_t j = 0; j < ANPINS; j++) {
      delay(5);
      uint8_t LEDno = i * DIGPINS + j;
      calSensorReadLow[LEDno] = analogRead(analogPin[j]);
     // Serial.println((String) +"LEDCalLow  "+ LEDno + " Value : " + calSensorReadLow[LEDno]);
    }
    digitalWrite(digitalPin[i], LOW);
  }
} 
void CalibrateHigh() {
  for (uint8_t i = 0; i < DIGPINS; i++) {
    digitalWrite(digitalPin[i], HIGH);
    for (uint8_t j = 0; j < ANPINS; j++) {
      delay(5);
      uint8_t LEDno = i * DIGPINS + j;
      calSensorReadHigh[LEDno] = analogRead(analogPin[j]);
      //Serial.println((String) +"LEDCalHigh  "+ LEDno + " Value : " + calSensorReadHigh[LEDno]);
    }
    digitalWrite(digitalPin[i], LOW);
  }  
 }

You are welcome !

will work even if it’s in a different scope?

It isn’t actually in a different scope, the variable is declared globally and is therefore available in all functions.
I had changed a few other variables that were declared globally (but not used as such) to be local in the cleaned up sketch in #3

Anyway great your issues have been resolved.

Ah I get it now, thank you I learend a lot today :slight_smile:

How do I mark this as solved?

Adi94:
How do I mark this as solved?

I think you can just add it to the topic name.