[Solved] Bench with counting capabilities

For an installation I am building as part of a team, we aim to make a bench that will have thirteen LDRs in its surface, hooked up to an arduino mega, with an electromechanical counter as their output, in an array (preliminarily) as shown below.

This is a plan view. The image is a little deceptive as the scale is off, but the small circles will be the locations of the LDRs, and the black rectangle on the left will be the location of the electromechanical counter. The arduino will be housed beneath the counter. CNC milled channels in the bench's surface will be inlaid with brass (maybe copper) flats to act as the wiring from the LDRs to the arduino. Here is a simple perspective:

The idea behind this is that when the LDRs are covered by people sitting on them, the LDR effects a change of the numerical readout of the counter - it shows the cumulative amount of people who have sat on the bench. The code also needs to be elegant enough that if one LDR and its diagonally neigbouring LDR(s) are covered, it only reads one person. The LDRs are spaced that if both are covered, it is very unlikely that two people will be there, but rather that one person is covering both.

The reason the central line of LDRs is there at all is so that if someone should happen to sit directly between two LDRs on the outer edges, they are very probably covering the central LDR. The outer edge LDRs are spaced so that people can sit between them so that they never sit on two horizontally adjacent LDRs, giving a false reading for two people.

I have never programmed for arduino before, but the language seems nice and logical, and I can't imagine too difficult, but I need to work out an elegant solution to code this with.

Actual questions:

  • Is there an easier/more effective array of LDRs?
  • I realise I need an 'if', but will i need to map every possibility, or is there some way of the arduino being told that the LDRs are set up in a certain way?
  • Is a digital TRUE pulse to an electromechanical counter all it needs to create a cumulative total?
  • Any other pointers/glaring difficulties you can spot in my description?

Thank you very much!

I'm glad you posted the perspective view because I had no idea what the heck that was.

Is there an easier/more effective array of LDRs?

Not sure what you mean, you can use photo transistors as well.

I realise I need an 'if',

More than one I would think :slight_smile:
The most obvious way to me is to use a lookup table however with 13 sensors that's 8192 bytes in size, very fast but too large and you don't need speed anyway.

Then there's a dozens of if-then-else blocks, yuk.

There's probably some sort of neat binary tree algorithm for this, but I suspect a switch with 13 case statements each with 2-3 ifs would do.

Is a digital TRUE pulse to an electromechanical counter all it needs to create a cumulative total?

These counters normally have a small solenoid AFAIK, in that case you need to amplify the Ardiuno pin signal with a transistor. The logic level used in the most common circuit is HIGH.


Rob

Interesting project. I am always cautious with projects that involve counting humans. They are just too creative and always beat the system. What if someone sits with legs across the bench and starts ridding up and down on it. Kids do that. What if one sits down and then starts moving sideways to make space for a second person? Will the first person be double counted?
Your design probably works for a group of well-behaved people that don't do those I mentioned. Programming is not too hard. You compare a map of covered LDRs from a while ago to now and see how many are changing. I would suggest putting an accelerometer below the bench and record acceleration changes. That can tell if someone is actually sitting down and possible how many at the same time.

That can tell if someone is actually sitting down and possible how many at the same time.

As opposed to kids jumping up and down?

PaulS:

That can tell if someone is actually sitting down and possible how many at the same time.

As opposed to kids jumping up and down?

Yes, I mean no. Kids beat any logic grownups think of.

My reaction when I saw that was the privacy issue. Imagine a sign:

Warning: the bench you are sitting on has sensors connected to a computer.

And if there was no sign, imagine what will happen when people discover you did it without warning them. "Oh no, you'll try to explain, there were no cameras there!".

Then think of someone sitting down and covering sensors with a book, newspaper, lunch, backpack etc.

I would think some sort of pressure sensor might be most reliable - like they use in bathroom scales. If the bench has cushions they could be located underneath them. Books or lunches would be too light to be mistaken for an adult weight then.

We have sort of decided that since there aren't many children in the area that the anomalous results we'll collect from people sitting on more than one sensor will probably equal out with the number of people who aren't caught by the sensors.

We are now using a new array, where we ditch the middle row completely and just have ten sensors along the outer edges spaced 400mm apart so that it is likely you're sitting on one, but unlikely you're sitting on two.

Given the argument for pressure sensors, I have written a code that hopefully will use the analogue nature of the LDRs to the full advantage. It is as follows:

int ldr0 =A0; //Sets Analog 0 to LDR0 (Number 1)
int ldr1 =A1;
int ldr2 =A2;
int ldr3 =A3;
int ldr4 =A4;
int ldr5 =A5;
int ldr6 =A6;
int ldr7 =A7;
int ldr8 =A8;
int ldr9 =A9;
int counterPin =A10; //Sets Analog 10 to Counter
int thresh =200; //Sets threshold value to 200 - to be changed to give the thing sensitivity when I get all the components
int now0 =0; //Sets initial 'now' value to zero
int then0 =0; //Sets initial 'then' value to zero, this means that an initial reading is taken when the system starts for it to compare 'now' to.
int now1 =0;
int then1 =0;
int now2 =0;
int then2 =0;
int now3 =0;
int then3 =0;
int now4 =0;
int then4 =0;
int now5 =0;
int then5 =0;
int now6 =0;
int then6 =0;
int now7 =0;
int then7 =0;
int now8 =0;
int then8 =0;
int now9 =0;
int then9 =0;

void setup(){
pinMode(counterPin, OUTPUT); //Sets Counter to OUTPUT
pinMode(13, OUTPUT); //Sets Pin 13 the LED to Output
}

void loop(){
int now0 = analogRead(ldr0);
int now1 = analogRead(ldr1);
int now2 = analogRead(ldr2);
int now3 = analogRead(ldr3);
int now4 = analogRead(ldr4);
int now5 = analogRead(ldr5);
int now6 = analogRead(ldr6);
int now7 = analogRead(ldr7);
int now8 = analogRead(ldr8);
int now9 = analogRead(ldr9);
if (now0 < then0 - thresh || now1 < then1 - thresh || now2 < then2 - thresh || now3 < then3 - thresh || now4 < then4 - thresh || now5 < then5 - thresh || now6 < then6 - thresh || now7 < then7 - thresh || now8 < then8 - thresh || now9 < then9 - thresh ) {
  digitalWrite(counterPin, HIGH);
  digitalWrite(13, HIGH); 
}
else {
  digitalWrite(counterPin, LOW);
  digitalWrite(13, LOW);
}
int then0 = now0;
int then1 = now1;
int then2 = now2;
int then3 = now3;
int then4 = now4;
int then5 = now5;
int then6 = now6;
int then7 = now7;
int then8 = now8;
int then9 = now9;
}

It's a bit Jimmy Saville... Any flaws/ways to save some lines of code that you guys can see? Will this be fast enough to essentially check every sensor 'at the same time'? Thank you for your help so far!

Also, I was wondering if anyone could help with the breadboard setup? I'm not really sure how to go about arranging this physically, so if anyone could post relevant links or explain how to do it briefly, it would be much appreciated!

And, just by the way, @Nick, I'm glad you spotted that this is a privacy issue - it's a large part of the reason for the installation!

Here's a smaller version

int ldr_pins[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9};
int now[] = {0,0,0,0,0,0,0,0,0};
int then[] = {0,0,0,0,0,0,0,0,0};

int counterPin = A10; //Sets Analog 10 to Counter
const int THRESH = 200; //Sets threshold value to 200 - to be changed to give the thing sensitivity when I get all the components


void setup(){
pinMode(counterPin, OUTPUT); //Sets Counter to OUTPUT
pinMode(13, OUTPUT); //Sets Pin 13 the LED to Output
}

void loop(){
	int flag = false;
	
	for (int i = 0; i < 9; i++) {
		now[i] = analogRead(ldr_pins[i]);
		if (now[i] < then[i] - THRESH) {
			flag = true;
		}
		then[i] = now[i];
	}
	
	if (flag) {
		digitalWrite(counterPin, HIGH);
		digitalWrite(13, HIGH); 			
	} else {
		digitalWrite(counterPin, LOW);
		digitalWrite(13, LOW); 
	}

}

I hope I got the logic the same as yours but I didn't analyse it to understand if it makes sense. I think it's clear that using arrays and loops is a better way to go (IMO anyway).


Rob

That's fantastic, thank you Rob, much prettier.

Am I right in thinking that the 'for' runs for all increments of ?
And that int now[] sets the value of all instances of 'now' to 0, as specified?
Also, nice idea with the flag!

Am I right in thinking that the 'for' runs for all increments of ?

1, the i++

int now[] sets the value of all instances of 'now' to 0, as specified?

If you have the {0,0...

Probably without as well because C will init RAM to 0s IIRC but I like to make sure.


Rob

So I've built the circuit on a breadboard, and tested each LDR individually with the following code:

void setup(){
  Serial.begin(9600);
}

void loop() {
  
  delay(100);
  Serial.println(analogRead(A0),DEC);
}

However, when I use the following code, there's never 'anything to see'... Any ideas?

int ldr_pins[] = {
  A0, A1, A2, A3, A4, A5, A6, A7, A8, A9};
int now[] = {
  0,0,0,0,0,0,0,0,0};
int then[] = {
  0,0,0,0,0,0,0,0,0};

int counterPin = A10; //Sets Analog 10 to Counter
const int THRESH = 200; //Sets threshold value to 200 - to be changed to give the thing sensitivity when I get all the components


void setup(){
  pinMode(counterPin, OUTPUT); //Sets Counter to OUTPUT
  pinMode(13, OUTPUT); //Sets Pin 13 the LED to Output
  Serial.begin(9600);
}

void loop(){
  int flag = false;

  for (int i = 0; i < 9; i++) {
    now[i] = analogRead(ldr_pins[i]);
    if (now[i] < then[i] - THRESH) {
      flag = true;
    }
    then[i] = now[i];
  }

  if (flag) {
    digitalWrite(counterPin, HIGH);
    digitalWrite(13, HIGH); 
    Serial.println("Hello World.");			
  } 
  else {
    digitalWrite(counterPin, LOW);
    digitalWrite(13, LOW); 
    Serial.println("Nothing to see here.");	
  }

}

I'm using the print command as a test for the circuit before I go and shell out on a lovely, lovely electromechanical counter, but I can't seem to make it work!

Thanks again for all your help, guys, this is very close to being complete now!

EDIT: Stupidly didn't remember that the value in from the LDR when covered would actually increase... Even so, changing the equation to now[i] > then[i] + THRESHdoesn't seem to work?

EDIT 2: Reverting to the original code I wrote, with the new equation also doesn't work, so there must be a problem with my understanding of quite how this works. Basically, if the 'new' value is more than 200 larger than the 'then' value, I want the counter triggered, and the Serial.print to run; is that not what this code does?

EDIT 3: Changing the equation to the more simplisticnow[i] > 800for testing purposes makes the system print the command everything in the circuit must work, similarly, everything else in the code must work, including the part that specifies what 'now' is, therefore by process of elimination, there must be something wrong with how either 'then' is specified, or 'THRESH'.
My guess is 'then', since changing the value of THRESH to the number '200' in the equation, so that it isn't actually referencing the number, has the exact same effect. It also can't be anything to with the definition of 'i' since the, when using thenow[i] > 800code, every single LDR responds (correct me if I'm wrong here, or in fact, anywhere).
Also, I have had to change the initial values of the 'then's to 1000 each, so that I don't get a false positive in starting the program.
The only other line with 'then' in is then[i] = now[i];What?

hendos43:

    if (now[i] < then[i] - THRESH) {

I recommend that whenever you have an expression which can produce different answers depending on the order of evaluation, you use parenthesis to show the order you want. At worst, they will be redundant. At best, they will save you from expressions that are evaluated in an unexpected order.

For example:

if (now[i] < (then[i] - THRESH)) {

is quite different to

if ((now[i] < then[i]) - THRESH) {

Thank you for your speedy reply, Peter, changed to:

if (now[i] > (then[i] + THRESH)) {

Unfortunately although it's now tidier, and correct, the problem persists :frowning:

I would be more comfortable if you made up your mind how many sensors you have and put that in the code. For example:

int ldr_pins[] = {  A0, A1, A2, A3, A4, A5, A6, A7, A8, A9};   // 10 pins
int now[] = {  0,0,0,0,0,0,0,0,0};   // 9 pins

So make it explicit:

const byte numberOfSensors = 10;

int ldr_pins[numberOfSensors] = {  A0, A1, A2, A3, A4, A5, A6, A7, A8, A9};   
int now[numberOfSensors] = {  0,0,0,0,0,0,0,0,0, 0};

Then:

 for (int i = 0; i < numberOfSensors; i++) {
    now[i] = analogRead(ldr_pins[i]);
    Serial.print ("now [i] = ");
    Serial.println (now [i]);    // debugging
    if (now[i] < then[i] - THRESH) {
      flag = true;
      Serial.println ("flag is true");  // more debugging
    }
    then[i] = now[i];
  }

Then add some debugging prints as shown and review the results.

Thank you for your post Nick, I had added an extra zero to the list of 'now's from the other post anyhow, but have switched to your code since it looks a little more reliable.

Excerpt from Serial Monitor:

now [i] =566
now [i] =888
flag is true

However when I remove the lines

    Serial.print ("now [i] =");
    Serial.println (now [i]); //debugging

I get no 'flag is true' printed. Similarly, if I place the print 'flag is true' piece of code here:

 if (flag) {
    digitalWrite(counterPin, HIGH);
    digitalWrite(13, HIGH); 		
    Serial.println ("flag is true"); // more debugging
  } 
  else {
    digitalWrite(counterPin, LOW);
    digitalWrite(13, LOW);	
  }
}

it works. However, in removing the

    Serial.print ("now [i] =");
    Serial.println (now [i]); //debugging

bit again, it stops working. Surely I don't need to be printing anything initially for this to work? This is all slightly academic anyhow, because the real test will be connecting it to an electromechanical counter, however if it's not going to produce 'HIGH' pulse unless I'm streaming data to a non-existent serial output, then it will be useless, and really I wanted to test the output behaviour in situations such as two or more LDRs being covered simultaneously.

If printing debugging information changes the results it sounds like you have a timing issue.

Okay, I'm not sure quite what you mean by that; is it a mechanical problem, or a programming problem?

As an update I'm posting the current code I'm using below:

const byte numberOfSensors = 10;

int ldr_pins[numberOfSensors] = {
  A0, A1, A2, A3, A4, A5, A6, A7, A8, A9};
int now[numberOfSensors] = {
  0,0,0,0,0,0,0,0,0,0};
int then[numberOfSensors] = {
  1000,1000,1000,1000,1000,1000,1000,1000,1000,1000};

int counterPin = A10; //Sets Analog 10 to Counter

const int THRESH = 200; //Sets threshold value to 200

void setup(){
  pinMode(counterPin, OUTPUT); //Sets Counter to OUTPUT
  pinMode(13, OUTPUT); //Sets Pin 13 the LED to Output
  Serial.begin(9600);
}

void loop(){
  int flag = false;

  for (int i = 0; i < numberOfSensors; i++) {
    now[i] = analogRead(ldr_pins[i]);
    Serial.print ("now [i] =");
    Serial.println (now [i]); //debugging
    if (now[i] > (then[i] + THRESH) )   {
      flag = true;
    }
    then[i] = now[i];
  }

  if (flag) {
    digitalWrite(counterPin, HIGH);
    digitalWrite(13, HIGH); 		
    Serial.println ("Someone sat on the bench."); // more debugging
  } 
  else {
    digitalWrite(counterPin, LOW);
    digitalWrite(13, LOW);	
  }
}

Having spent all day working on timing-related problems (displaying video) the answer isn't clear cut.

Let's say you miss the bus to work. Is that because the bus came too early, you got to the bus stop too late, catching the bus was a bad idea in the first place, you can't run fast enough ... timing problems can be tricky to solve.

However back to reality for a moment, taking time to display debugging information will slow down the rate at which you collect that information.

I did notice that replacing the debugging code with

Serial.println ("");

left it working, but actually made it work more poorly.

Basically, then, it's almost as if it's reading the situation too quickly? Perhaps I will go back to the less elegant code and see if it solves it.

Try:

  Serial.begin(115200);

That might help marginally.