Using a PIR sensor in a robotic head project is awesome... while tracking with MRL, PIR sensor is helping to identify human presence and start tracking... I have tested this and proved to be very useful... but I have some issues now... PIR sensors have retriggering option for detecting human presence and movement and continue keeping the tracking process on... there is always 2 pots on the sensor, one for sensitivity adjustment (detection range) and one is for continuity of open circuit after triggering... I usually use 30sec continuity, this allows to keep the circuit open for enough time... if the movement continues, retriggering option keeps the tracking open until movement stops or human leaves the room... this works ok for Arduino scripted tracking but when I use MRL opencv tracking service, the tracking stops in few seconds after PIR is triggered... Indeed tracking must keep on as long as the human movement is present because PIR has retriggering... but MRL doesnt check that and service stops soon... It takes some time to realize that sensor is triggered again... in the oscope image I was testing PIR triggered tracking with Greg and I was dancing in front of the sensor all the time, but as you can see service interrupts frequently... I think this is a software issue...

 

GroG

10 years 2 months ago

Thanks for the excellent post borsaci.

I have more questions :

  • can you attach, reference, or include the current script with the opencv tracking which you are having issues with
  • The PIR output is digital and represents a change of state you think the oscope trace is not accurate for what the sensor is sending out?
  • when you say 30s continuity is this implemented in the sketch or a hardware change of the POT ?

-- I am using the py script which you have prepared the basis for PIR tracking for me... here is it:

tracking.PIRTriggered.borsaci06.py

# a minimal tracking script - this will start all peer
# services and attach everything appropriately
# change parameters depending on your pan tilt, pins and
# Arduino details
# all commented code is not necessary but allows custom
# options
 
port = "COM3"
xServoPin = 9
yServoPin = 10
 
tracker = Runtime.createAndStart("tracker", "Tracking")
 
# set specifics on each Servo
servoX = tracker.getX()
servoX.setPin(xServoPin)
servoX.setMinMax(30, 150)
servoX.setInverted(True)
 
servoY = tracker.getY()
servoY.setPin(yServoPin)
servoY.setMinMax(30, 150)
 
# optional filter settings
opencv = tracker.getOpenCV()
#opencv.addFilter("PyramidDown1", "PyramidDown")
#opencv.addFilter("gray", "Gray")
#opencv.addFilter("facedetect", "FaceDetect")
 
# setting camera index to 1 default is 0
opencv.setCameraIndex(2) 
 
# connect to the Arduino
tracker.connect(port)
#set a Low sample rate, we don't want to bork serial connection !
tracker.arduino.setSampleRate(8000)
#select the pin where to start polling ( we can connect a PIR to this pin to see his state HIGH/LOW)
readDigitalPin = 3
#start polling data from the digital pin
tracker.arduino.digitalReadPollStart(readDigitalPin)
#add python as listener of the arduino service, each time arduino publish the value of the pin
tracker.arduino.addListener("publishPin", python.getName(), "input")
 
#define a function which is called every time arduino publish the value of the pin
def input():
    pin = msg_tracker.arduino_publishPin.data[0]
    print 'pin data is ', pin.pin, pin.value
    #if an HIGH state is read, PIR is detecting something so start face tracking
    if (pin.value == 1):
     tracker.faceDetect()
    #if a LOW state is read , stop tracking.. there is no human there !
    elif (pin.value == 0):
     tracker.startLKTracking()
     tracker.stopLKTracking()
   
 
 
# Gray & PyramidDown make face tracking
# faster - if you dont like these filters - you
# may remove them before you select a tracking type with
# the following command
#tracker.clearPreFilters()
 
# diffrent types of tracking
 
# simple face detection and tracking
#tracker.faceDetect()
 
# lkpoint - click in video stream with 
# mouse and it should track
#tracker.startLKTracking()
 
# scans for faces - tracks if found
#tracker.findFace()
 
-- I know that PIR triggering is digital and MRL keeps track of it. the sensor is at retriggering mode, so the output must be continued and MRL should realize that...
-- 30secs continuity setting is already set by continuity potentiometer (hardware set not by sketch)...
Hope these helps...  :)

GroG

10 years 2 months ago

So the problem is the pin appears (at least through MRL) to flip values more than it should?  If I understand you correctly, your POT value should inhibit the ability for the pin to change values for over a period of 30 seconds -  So you think its a software problem where MRL is making up changed states on that pin?

We could fix this in the Python software just by setting up a timer which does not allow states to change (tracking / not tracking) until at least 30 seconds from the previous state has transpired.

But as a wise sage said to me, "You should always solve your problems up-stream!" .. meaning this would be just masking the root problem.

The root problem is the pin is changing states many more times than it should in 30s..    This "seems" like a hardware problem to me, no ?

I completely understand what you mean and agree with you... restricting the state change with a timer in py script will not solve the problem but will keep tracking on for at least 30secs... I dont agree with you about this being a hardware issue because when I test the PIR with std arduino sketch, the state led never goes out when there is movement within the sensor detection range... however when using with MRL tracking, the state led doesnt even lit... but as we can see on the oscope the state changes are there... we should more elaborate on this issue...

 

sure here it is...from Arduino playground site... PIRsense.ino

// Uses a PIR sensor to detect movement, buzzes a buzzer
// email me, John Park, at jp@jpixl.net
// based upon:
// PIR sensor tester by Limor Fried of Adafruit
// tone code by michael@thegrebs.com
 
 
int ledPin = 13;                // choose the pin for the LED
int inputPin = 3;               // choose the input pin (for PIR sensor)
int pirState = LOW;             // we start, assuming no motion detected
int val = 0;                    // variable for reading the pin status
int pinSpeaker = 10;           //Set up a speaker on a PWM pin (digital 9, 10, or 11)
 
void setup() {
  pinMode(ledPin, OUTPUT);      // declare LED as output
  pinMode(inputPin, INPUT);     // declare sensor as input
  pinMode(pinSpeaker, OUTPUT);
  Serial.begin(9600);
}
 
void loop(){
  val = digitalRead(inputPin);  // read input value
  if (val == HIGH) {            // check if the input is HIGH
    digitalWrite(ledPin, HIGH);  // turn LED ON
    playTone(300, 160);
    delay(150);
 
    
    if (pirState == LOW) {
      // we have just turned on
      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirState = HIGH;
    }
  } else {
      digitalWrite(ledPin, LOW); // turn LED OFF
      playTone(0, 0);
      delay(300);    
      if (pirState == HIGH){
      // we have just turned of
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirState = LOW;
    }
  }
}
// duration in mSecs, frequency in hertz
void playTone(long duration, int freq) {
    duration *= 1000;
    int period = (1.0 / freq) * 1000000;
    long elapsed_time = 0;
    while (elapsed_time < duration) {
        digitalWrite(pinSpeaker,HIGH);
        delayMicroseconds(period / 2);
        digitalWrite(pinSpeaker, LOW);
        delayMicroseconds(period / 2);
        elapsed_time += (period);
    }
}
the state led I mentioned in my previous post is not the ledpin13 on arduino as in this sketch... there is also a state pin on the PIR sensor which should lit to show PIR-on state... 

AH HA !

Your sketch is just hiding the hardware problem !  

When it switches high .. it looks like it tries to play a tone for 300*100 milliseconds !   This would keep it in a high state (since its single threaded) for that length of time !

So when you say you turned some pot on the hardware for 30 second delay - this apparently is not working.  Now your saying MRL has a "bug" because its not behaving like the sketch ?  hmmmm..

I would not consider this a bug in MRL, its behaving as I would expect given the hardware's behavior.  So if your interested in having MRL change its behavior, lets call it an "enhancement" :)

Grog,

I never complained about a "bug" in MRL... :) I just posted a problem about PIR retriggering not handled properly by MRL... Thought that this can be solved within MRL and as a Guru, by you... I just asked your help about the issue... :) to be of a little bit more help, I didnt say that "when tested by Arduino sketch the PIR sensor stays on for 30secs", the state led on the sensor stays lit as long as movement continues... I know that there is a "buzzer" in the sketch which I didnt use,( will test deleting that parts of the code), whether the buzzer works or not, the state led on the sensor stays on as long as the movement continues, sometimes  longer than 30secs if I am in the vicinity of the sensor... but when I use MRL PIR affected tracking, the case is not like that... the led on the sensor doesnt even lit... I am sure you will find an "enhancement" about the issue...

 

Ok,

I just needed to get more understanding of what is going on.   Usually, I have higher priority on fixing "bugs".  Bugs are defects, enhancements are ways we want it to behave.  Not really a big deal and the distinction between the two is subjective.  The part I was concerned about is MRL "making up" values the hardware was not sending - this would definately be a bug ..  but that's not happening .. so Onward !

I believe I understand most of the details, now lets jump back and get the big picture :D

How do you want it to optimally behave ?  I'm pretty sure I could get it to do what you want if you could very clearly describe what you want.  For example, turning on the LED would be easy - and you want it on continuously for 30 seconds after the last movement is sensed?

I just want the tracking to continue as long as a human is inside sensor's detection range.. whether 10secs or few mins... the state led is not a problem too, because it is inside the head enclosure and we dont see it lit... but it is an indication of sensor output... :)

I am sure you will find a solution inside MRL to this problem... Gael and I will be so happy if this is solved... and I am sure you will also want PIR triggered tracking when your InMoov is finished and start tracking...

Problems will always be a part of robotics... and challenge us.... :)

borsaci06

10 years 2 months ago

Grog,

I tried to test the Arduino sketch for PIRsense without the buzzer parts and realized that it was not the actual sketch I first tested the sensor... It was this sketch:

/* 
 * //////////////////////////////////////////////////
 * //making sense of the Parallax PIR sensor's output
 * //////////////////////////////////////////////////
 *
 * Switches a LED according to the state of the sensors output pin.
 * Determines the beginning and end of continuous motion sequences.
 *
 * @author: Kristian Gohlke / krigoo (_) gmail (_) com / http://krx.at
 * @date:   3. September 2006 
 *
 * kr1 (cleft) 2006 
 * released under a creative commons "Attribution-NonCommercial-ShareAlike 2.0" license
 *
 *
 * The Parallax PIR Sensor is an easy to use digital infrared motion sensor module. 
 *
 * The sensor's output pin goes to HIGH if motion is present.
 * However, even if motion is present it goes to LOW from time to time, 
 * which might give the impression no motion is present. 
 * This program deals with this issue by ignoring LOW-phases shorter than a given time, 
 * assuming continuous motion is present during these phases.
 *  
 */
 
/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;        
 
//the time when the sensor outputs a low impulse
long unsigned int lowIn;         
 
//the amount of milliseconds the sensor has to be low 
//before we assume all motion has stopped
long unsigned int pause = 5000;  
 
boolean lockLow = true;
boolean takeLowTime;  
 
int pirPin = 2;    //the digital pin connected to the PIR sensor's output
int ledPin = 13;
 
 
/////////////////////////////
//SETUP
void setup(){
  Serial.begin(9600);
  pinMode(pirPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(pirPin, LOW);
 
  //give the sensor some time to calibrate
  Serial.print("calibrating sensor ");
    for(int i = 0; i < calibrationTime; i++){
      Serial.print(".");
      delay(1000);
      }
    Serial.println(" done");
    Serial.println("SENSOR ACTIVE");
    delay(50);
  }
 
////////////////////////////
//LOOP
void loop(){
 
     if(digitalRead(pirPin) == HIGH){
       digitalWrite(ledPin, HIGH);   //the led visualizes the sensors output pin state
       if(lockLow){  
         //makes sure we wait for a transition to LOW before any further output is made:
         lockLow = false;            
         Serial.println("---");
         Serial.print("motion detected at ");
         Serial.print(millis()/1000);
         Serial.println(" sec"); 
         delay(50);
         }         
         takeLowTime = true;
       }
 
     if(digitalRead(pirPin) == LOW){       
       digitalWrite(ledPin, LOW);  //the led visualizes the sensors output pin state
 
       if(takeLowTime){
        lowIn = millis();          //save the time of the transition from high to LOW
        takeLowTime = false;       //make sure this is only done at the start of a LOW phase
        }
       //if the sensor is low for more than the given pause, 
       //we assume that no more motion is going to happen
       if(!lockLow && millis() - lowIn > pause){  
           //makes sure this block of code is only executed again after 
           //a new motion sequence has been detected
           lockLow = true;                        
           Serial.print("motion ended at ");      //output
           Serial.print((millis() - pause)/1000);
           Serial.println(" sec");
           delay(50);
           }
       }
  }
 
After a careful examination of the code I found out that sensor digital output can be unreliable and creating false low states for short periods of time and the code deals with it by ignoring short low states... If you take a look at the heading info of the code you can see that explained there... From this we can deduce that there is a hardware issue with this sensor and must be handled i,n the code... MRL is doing its job as expected and detects that false short low states... that it why the reading of publishpin interrupts from time to time... so you were definitely right about this being a hardware issue with the sensor... now we must handle this in the py script by doing the same... telling the "readpublishpin" process to ignore short low states... :)