Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

People counter sketch with Arduino

Status
Not open for further replies.

Liamlambchop

Member level 2
Member level 2
Joined
Sep 19, 2011
Messages
45
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
1,738
Hey guys,

I am making a break beam people counter which uses an infrared beam and an infrared sensor. When a person walks through the beam a count is recorded and is then sent with a GSM modem to a web server.
The infrared LED, which makes my beam, pulses at 38kHz and my infrared sensor, known as an IR receiver module, only responds to 38kHz infrared. This stops ambient light from interfering with the system.

I am using an arduino to do the following:
1. make the LED pulse at 38kHz for 6 cycles (ie HIGH to LOW 6 times) then pause for 60 microseconds
2. power the IR receiver module
3. receive an input from that IR receiver
4. output a short (0.1s maybe) HIGH/LOW to the GSM modem's data logger.

I need help with the code to do this.

The code I have written so far consists of modified example sketches. I have gotten as far as making, what I think (I haven't been able to test it) is, a sketch which will: make the LED pulse CONSTANTLY (remember I need it to pause for 60 microseconds) at 38kHz, power the IR receiver, and receive an input for that IR receiver. The rest of the things I need to do (getting the LED to pause, outputing a short HIGH/LOW) I need help with.

It is important to realise that the input to the Arduino from the IR receiver module is going to be 1,0,1,0,1.... (going from HIGH to LOW at 38kHz) so I can't simply say in my sketch that whenever there is a 1 or a 0 the Arduino should output to the GSM modem. I need a way to say that when there is a LOW (yes a LOW not a HIGH. The ir receiver outputs a LOW) for, let's say 0.05s (or the time it takes a person to walk through a beam of IR light), then the Arduino should output HIGH/LOW. How do I do this?

How do I get the LED to pause for 60 microseconds without delaying the entire loop?

Here is my sketch thus far:

Code:
 /*

Unfinished People Counter Sketch
 
 */

const int irLED =  13;      // the number of the irLED pin

int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

long interval = 0.02631579;           // interval at which to blink (milliseconds)

void setup() {                
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards
  pinMode(13, OUTPUT);
  pinMode (12, OUTPUT);  //assign pin 12 as output to power the irRec
  Serial.begin(38400);  //just in there so I can watch what's happening on the serial monitor
  pinMode(2, INPUT); //assign pin 2 as input for the irRec
}

void loop() 
{
 {
  int irRec = digitalRead(2); //arduino will read the value at pin 2 and assign a number (1 or 0) to it
  Serial.println(irRec, DEC); //value IR rec. will be printed on serial monitor
  digitalWrite(12, HIGH); }  // set pin 12 on high so IR receiver has 5Vs
  
  {
    unsigned long currentMillis = millis(); //check to see if it's time to blink the LED; that is, if the 
                                            // difference between the current time and last time you blinked 
                                            // the LED is bigger than the interval at which you want to 
                                            // blink the LED.
                                            //'unsigned long' is a variable which can store 32 bits, and no negative numbers
 
   if(currentMillis - previousMillis > interval){
   
     // save the last time you blinked the LED 
    previousMillis = currentMillis;   

     // if the LED is off turn it on and vice-versa:
     if (ledState == LOW)
        ledState = HIGH;
     else
        ledState = LOW;

   // set irLED with the ledState of the variable:
   digitalWrite(irLED, ledState); }
  }
 
 }


Thanks heaps to anyone who can help :))))
 
Last edited by a moderator:

I haven't used arduino but there is no way you can't use a long variable to store a float number
long interval = 0.02631579; // interval at which to blink (milliseconds)

Alex
 

This appears to be a continuation of this thread: https://www.edaboard.com/threads/226822/#post969546

Hey guys,
<snip>
It is important to realise that the input to the Arduino from the IR receiver module is going to be 1,0,1,0,1.... (going from HIGH to LOW at 38kHz) so I can't simply say in my sketch that whenever there is a 1 or a 0 the Arduino should output to the GSM modem. I need a way to say that when there is a LOW (yes a LOW not a HIGH. The ir receiver outputs a LOW) for, let's say 0.05s (or the time it takes a person to walk through a beam of IR light), then the Arduino should output HIGH/LOW. How do I do this?
<snip>

That is not like the IR receiver modules I have seen. Can you tell us which transmitter and receiver pair you are using?

As for the crux of your question, the Arduino will be receiving the modulation frequency used for the 38 KHz carrier (1 KHz is often used). You need to detect its absence. Search on "missing peak detector."

Sorry I can't help with the C program, my experience is limited to Assembly and PIC devices. Basically, when I detected a high, I started a timer to detect the next high based on the expected frequency. If the next high is not detected, that indicated a beam break. The next high indicates a "make" and the process is repeated. You can detect highs, lows, or transitions. For counting people, I think 1 KHz will be more than adequate. My routine also had an error correction scheme. In your case, you might assume that a walking person will interrupt the beam for at least 30 mS, so any break of less than 30 mS may be an interference, like a fly or bird.

John
 
Last edited:
I haven't used arduino but there is no way you can't use a long variable to store a float number
long interval = 0.02631579; // interval at which to blink (milliseconds)

Alex

I'm quite a novice when it comes to programming, so could you explain what you mean?
 

I'm quite a novice when it comes to programming, so could you explain what you mean?

Alex is pointing out that the statement in your code:

long interval = 0.02631579; // interval at which to blink (milliseconds)

Attempts to storage a floating point value into a long integer variable, which is clearly an error.

A more proper statement would be:

float interval = 0.02631579; // interval at which to blink (milliseconds)

Or

double interval = 0.02631579; // interval at which to blink (milliseconds)

BigDog
 

Basically, when I detected a high, I started a timer to detect the next high based on the expected frequency. If the next high is not detected, that indicated a beam break. The next high indicates a "make" and the process is repeated. You can detect highs, lows, or transitions. For counting people, I think 1 KHz will be more than adequate. My routine also had an error correction scheme. In your case, you might assume that a walking person will interrupt the beam for at least 30 mS, so any break of less than 30 mS may be an interference, like a fly or bird.

John

John, that is very helpful thank you.

The thread you linked me to was actually started by me :) I decided to start this one because I had a specific programming problem, so the thread needed to be in the programming area of the forum.

The components I am using are: TSOP341 IR receiver module, and a TSTS7100 IR LED. Both are made by Vishay. I have attached their data sheets if you want to use them. Yes, if you would, have a look at the IR receiver and see if you can figure out what it's output will be. Like will is be outputing a LOW when i make the beam pulsing pause for 60 microseconds?

I haven't used arduino but there is no way you can't use a long variable to store a float number
long interval = 0.02631579; // interval at which to blink (milliseconds)

Alex

I'm quite a novice when it comes to programming, so could you explain what you mean?


I still need to learn how to write this sketch....

Thanks for all your help guys :)
 

Attachments

  • ir led data shet.pdf
    145.5 KB · Views: 147
  • IR receiver module data sheet.pdf
    212.2 KB · Views: 165

After reviewing your code/sketch, I have a question for you.

Where does the value 0.02631579 originate from? Is this in seconds? So the equivalent in milliseconds would be 26.31579 ms?

The reason I ask, it that the routine milli() return a long integer value. Therefore, using a floating point value stored in the variable "interval" would most likely not yield the expected results.

BigDog
 

Figures 1 and 3 and the section called suitable data format at the end of the datasheet are very useful. I think the pause of 60 microsceconds is too short between the packets of signals at 38 KHz. Also note, 6 cycles is the minimum packet size to facilitate faster data rates. You do not need such data rates, and I suggest having more pulses per packet. A typical packet (Figure 3) has about 22 pulses (i.e, 0.6 mS).

The receiver goes low when it detects the proper light pulses (see: Figure 1). It then goes high after a short time (also shown in Figure 1). I have developed this very crude flow chart to illustrate what I am thinking you might do:



Let me emphasize that the wait periods are chosen arbitrarily. You will need to adjust them as needed. Also note that people passing through the beam together will not increment the counter. Finally, when I say Rx LOW, it may be easier and better to look at the transition of the input pin on the Arduino rather than its high/low state per se.

John
 
using this command we can calculate time duration i guess....
this is one example:
int pin = 7;
unsigned long duration;

void setup()
{
pinMode(pin, INPUT);
}

void loop()
{
duration = pulseIn(pin, HIGH);
}
 
The 0.02631579 is in milliseconds and is equal to 1/38th of a millisecond. I want my IR LED to blink at a frequency of 38kHz, hence why I use that number. However, I must have done something wrong here.... I didn't know what a floating point value was until I just did a little bit of reading just then. Apparently it isn't very accurate. What would be the best way for me to have the IR LED blinking at 38kHz?

I have re-written my sketch. It now pauses for 0.6 microseconds between bursts of pulses. I haven't yet modified it to suit the information John provided me with.

here it is now:


Code:
/*

People Counter sketch.
 
 */

#include <TimedAction.h>

TimedAction pulsefunction = TimedAction (0.6, pulse);

int irLED =  13;      // the number of the irLED pin
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
long interval = 0.02631579;           // interval at which to blink (milliseconds)

void setup() {                
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards
  pinMode(13, OUTPUT);
  pinMode (12, OUTPUT);  //assign pin 12 as output to power the irRec
  digitalWrite (12, HIGH); //give irREC power
  Serial.begin(9600);  //just in there so I can watch what's happening on the serial monitor
  pinMode(2, INPUT); //assign pin 2 as input for the irRec
  
}

void loop() 
{
  {
  pulsefunction.check(); //check pulsefunction to see if the interval is complete
  int irRec = digitalRead(2); //arduino will read the value at pin 2 and assign a number (1 or 0) to it
  Serial.println(irRec, DEC);} //value IR rec. will be printed on serial monitor

}    

 
 void pulse() {
    digitalWrite(13, HIGH);   // set the IR LED on #1
    delay(0.02631579);              // wait for 1/38 of a milisecond 
    digitalWrite(13, LOW);    // set the IR LED off
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #2
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #3
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #4
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #5
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #6
    delay(0.02631579);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
  }
 
Last edited:

using this command this we can calculate time duration of that pulse for duration
this example......
int pin = 7;
unsigned long duration;

void setup()
{
pinMode(pin, INPUT);
}

void loop()
{
duration = pulseIn(pin, HIGH);
}
 

Thanks emcmalik, I'm glad you showed me that function :)
 

Unfortunately your pulse() routine has some syntax errors. The delay() function requires an integer value and cannot accept a float.

Try this code instead:

Code:
 void pulse() {
    digitalWrite(13, HIGH);   // set the IR LED on #1
    delayMicroseconds(26);              // wait for 1/38 of a milisecond 
    digitalWrite(13, LOW);    // set the IR LED off
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #2
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #3
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #4
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #5
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, HIGH);   // set the IR LED on #6
    delayMicroseconds(26);              // wait for 1/38 of a milisecond
    digitalWrite(13, LOW);    // set the IR LED off
  }

Using a delay is not the best method, however with a frequency of 38kHz you are pushing the limitations of a 16MHz clocked Arduino/AVR and the available libraries. A more viable option maybe using an Arduino Timer routine.

BigDog
 

I suggest having more pulses per packet. A typical packet (Figure 3) has about 22 pulses (i.e, 0.6 mS).

You know, all along I actually had in my sketch 0.6ms as the break time. However I was reading it as 60 microseconds. I worry myself sometimes....

The receiver goes low when it detects the proper light pulses (see: Figure 1). It then goes high after a short time (also shown in Figure 1)
.

So does this mean the receiver goes back to HIGH before it detects the proper light again? That's a bit odd isn't it?

Finally, when I say Rx LOW, it may be easier and better to look at the transition of the input pin on the Arduino rather than its high/low state per se.

I don't quite understand what you mean here.




John, thank you so much!!! You put in more effort than you needed to and I really appreciate it. That flow diagram will be of great help :)

---------- Post added at 17:42 ---------- Previous post was at 17:30 ----------

Using a delay is not the best method, however with a frequency of 38kHz you are pushing the limitations of a 16MHz clocked Arduino/AVR and the available libraries. A more viable option maybe using an Arduino Timer routine.

BigDog

Hey thanks BigDog! As you can see I have put a timed action routine in there... would you suggest something like Metro (Arduino playground - Metro) instead of using delay()? What sort of issues will I have if I stick to my current sketch?
 

Hey thanks BigDog! As you can see I have put a timed action routine in there... would you suggest something like Metro (Arduino playground - Metro) instead of using delay()?

There are some timer library routines which accept timer periods in the microseconds, which is what you need for delays as short as 26 us.

What sort of issues will I have if I stick to my current sketch?

The problem with the TimedAction library is that it requires the delay specified as an integer in milliseconds, so your 0.6 ms won't fly. You need to find a library which accepts microseconds which would be 600 us in this case.

BigDog

---------- Post added at 08:08 ---------- Previous post was at 07:53 ----------

Another issue I should mention, if you are attempting to pulse the LED at 38kHz then you need to cycle it ON and OFF every 13 microseconds approximately, not 26 microseconds. Each cycle consists of the LED being ON half the time and OFF half the time, so if the period is approximately 26us then the duration of each state must be 13us.

BigDog
 
So does this mean the receiver goes back to HIGH before it detects the proper light again? That's a bit odd isn't it?

My comment was very poorly stated and mixed two concepts, thus creating confusion. I apologize for that.

First, I was trying to point out the delay in recognition of the signal and the delay in return to a high state after the signal burst ended. I then mixed in this comment the datasheet cautions related to reception of a continuous 38 KHz signal:

Source: Datasheet
Suitable Data Format

The circuit of the TSOP341.. is designed in that way that unexpected output pulses due to noise or disturbance signals are avoided. A bandpass filter, an integrator stage and an automatic gain control are used to suppress such disturbances. The distinguishing mark between data signal and disturbance signal are carrier frequency, burst length and duty cycle. The data signal should fulfill the following conditions:
• Carrier frequency should be close to center frequency
of the bandpass (e.g. 38 kHz).
• Burst length should be 6 cycles/burst or longer.
• After each burst which is between 6 cycles and 70
cycles a gap time of at least 10 cycles is necessary.
• For each burst which is longer than 1.8 ms a corresponding
gap time is necessary at some time in the
data stream. This gap time should have at least same
length as the burst.
• Up to 2200 short bursts per second can be received
continuously.
<snip>
When a disturbance signal is applied to the TSOP341.. it can still receive the data signal. However the sensitivity is reduced to that level that no
unexpected pulses will occur.
Some examples for such disturbance signals which are suppressed by the TSOP341.. are:
• DC light (e.g. from tungsten bulb or sunlight)
• Continuous signal at 38 kHz or at any other frequency
• Signals from fluorescent lamps with electronic ballast
(an example of the signal modulation is in the figure
below). <snip>

In other words, if fed a continuous 38 KHz signal, the sensitivity will be reduced to such an extent that the receiver output may go High, even when the light path is not blocked.

My recommendation was and is to use a suitable burst length (minimum of 6 on/off 38 KHz pulses, maximum of 70) with a suitable gap between bursts. An easy way to do that is to modulate the 38 KHz at something like 833 Hz to a couple of KHz (as shown in Figure 3). Since you are detecting a relatively slow event, i.e., people walking past a point, I see no reason to push the limits for fast detection. I did not understand what burst period and space period you were using, most likely because I don't understand C code.

Again, my apologies. My only excuse is that it was late (for me) and a Saturday night.

John
 
Thank you BigDog. That's really great :) Cheers!
I found "Timer 1" (Arduino playground - Timer1) which uses microseconds.

Here is the example code provided with it. I don't understand why the number 512 is used after Timer1.pwm()?

Code:
/*
 *  Timer1 library example
 *  June 2008 | jesse dot tane at gmail dot com
 */
 
#include "TimerOne.h"
 
void setup()
{
  pinMode(10, OUTPUT);
  Timer1.initialize(500000);         // initialize timer1, and set a 1/2 second period
  Timer1.pwm(9, 512);                // setup pwm on pin 9, 50% duty cycle
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
}
 
void callback()
{
  digitalWrite(10, digitalRead(10) ^ 1);
}
 
void loop()
{
  // your program here...
}


John, thanks so much for your help. I have sorted everything out with the IR receiver now. So that's great!!
 
Last edited:

According to the link you have provided
The duty cycle is specified as a 10 bit value, so anything between 0 and 1023
so PWM is set to 50% using Timer1.pwm(9, 512);

Alex
 

So you mean the duty cycle is in binary? I still don't get it sorry. how does 512 = 50%?

---------- Post added at 19:06 ---------- Previous post was at 19:00 ----------

I have been trying to get used to Timer1.

I wrote this code to try and learn how to call a function every x seconds. I want to use it in my people counter sketch to call my LED pulse every 60 microseconds. In this sketch I am trying to get an LED to blink 3 times (at 1/4 second intervals) every 5 seconds. But it doesn't work. What have I done wrong?

Code:
#include <TimerOne.h>

void setup() {
  pinMode(9, OUTPUT);
  Timer1.initialize();
  Timer1.attachInterrupt(pwm, 5000000);
  
}

void loop(){
  digitalWrite(13,HIGH);
}

void pwm(){
 digitalWrite(9, HIGH);
 delay(250);
 digitalWrite(9,LOW);
 delay(250);
 digitalWrite(9, HIGH);
 delay(250);
 digitalWrite(9,LOW);
 delay(250);digitalWrite(9, HIGH);
 delay(250);
 digitalWrite(9,LOW);
 delay(250);
}
 

The PWM is determined by the value in the range [0, 1023] with 0 representing a duty cycle of 0% or always OFF and 1023 representing a duty cycle of 100% or always ON.

So 512 represent a duty cycle of 50%, ON 50% of the waveforms period and OFF the other 50% of the period, representing a normal square wave.

BigDog
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top