Let's Make Robots!

Motion Tracking Head Using 4 PIRs, Servo and Arduino Uno

Head follows movement based on 4 PIR sensors

Updated: Mar 31,2014 - modified program to use PIR only once per HIGH state.

I wanted to make a motion tracker originally using sound sensors but that was too much work and I thought using PIRs would be just like programming on and off switches, simpler. This works pretty fair considering it's utter simplicity, not rocket science. I used 4 PIRs (actually 5 but one wiring harness shorted and I was too lazy to fix it), a servo to turn the head (bird), and an arduino uno to do the heavy number crunching (45 lines of code, see below).

I hate to program, too frustrating but I finally broke down and got an Arduino, man what a cinch. The last chip I played with I had to download Java, and Keil Uvision, and a bunch of other stuff and it took me two or three days just to set up the environment. The Arduino I had everything installed and running the Blink program in minutes. Where was Arduino when I was young?

The tracker works well if you are walking normally past the PIR sensors, if you move slowly it gets a little confused sometimes between two adjacent sensors but ends up shaking its head quickly which is definitely bird like. My algorithm couldn't be simpler, cycle through the PIRs and place the servo where a PIR has just gone HIGH. Suppose it could be made more complex, but what for? NOTE: modified on Mar 31,2014 to address this problem by allowing PIR to be used only once after it goes HIGH so that it doesnt jump back and forth between adjacent positions. Works quite nicely now even with 2.5 second response time.

The PIRs have an on cycle time of about 2.5 seconds at its fastest so if one found some quicker PIRs or wanted to play with the hardware then the tracker would have quicker response time but its pretty good as is. Don't use any slower PIRs or it will just sit there longer before responding. Ideally if the PIR would go HIGH at movement and then immediately go LOW even if there was continued movement then response time would be quicker too, I think, not sure how it would behave frankly.

Used 9mm EPP to hold the PIRs, a tea container to support the servo.

After I had begun building I did see a video where someone did something similar (nothing new under the sun) but his algorithm sounded too complex and frankly I feel mine works better.

Here is a closeup of the Uno board. I just wired all the PIRs in parallel and ran them off the 5v from the Uno, plugged the PIR out wires into 3,4,5,6,7 sockets and servo into 9.

Close up shot of the board:

 

 

Here is the code: 

#include <Servo.h>

// author: jim demello feb 2014 //

// modified: Mar 31,2014 - added array to allow PIR to be used only once per HIGH state so it doesnt jump back

//                                    and forth between adjacent PIR servo positions.

boolean pirStatus;

Servo servo1; 

int servangle = 0; // servo angle variable

int pirNo[] = {3,4,5,6,7};          // pir pin numbers

int pirPrevLow[] = {1,1,1,1,1};     // previously low flag set to true

int pirPrevUsed[] = {0,0,0,0,0};   // track if PIR has been used after going HIGH

int pirPos[] = {10,60,100,140,170}; // positions for servo (0-180)

int curPosPir = 0;

int pirPin = 3;   

int ledPin = 13;

 

void setup(){

  Serial.begin(9600);

  servo1.attach(9); 

  for(int i=0;i<4;i++){

  pinMode(pirNo[i], INPUT);

   }

  pinMode(ledPin, OUTPUT);

  delay(10000); // calibrate for about 10 seconds

   }

////////////////////////////

//Main LOOP 

//////////////////

void loop(){

  for(int j=0;j<4;j++){ // for each PIR

     pirPin=pirNo[j];

     pirStatus = digitalRead(pirPin);

     if (pirStatus == HIGH) {

          digitalWrite(ledPin, HIGH);   // turn on led for kicks and to show PIRs are HIGH

          if(pirPrevLow[j])    {  

                if (curPosPir != pirPin && pirPrevUsed[j] == 0) { // if high PIR is different than current position PIR then move to new position

                   servo1.write(pirPos[j]);

                   curPosPir = pirPin; // keep current PIR 

                   pirPrevUsed[j] == 1;

                }

          pirPrevLow[j] = 0; // pir is now not low

          }

      } 

      else {

              digitalWrite(ledPin, LOW);  // turn off the led

              pirPrevLow[j] = 1;   // pir is now low

              pirPrevUsed[j] == 0;

      }

    } // end j number of pirs loop

  }// end infinite loop

 

Suppose I will post this over at the doilie makers website (instructables.com) too.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

I duffed this comment.

I have thought about using a PIR array for motion tracking but I haven't gotten around to trying it out.  I have come accross the same issue of the PIR resetting.  Have you tried connecting the Vcc of one of the sensors to a digital output on the arduino and as soon as the sensor goes high you could cut the power to the sensor and see if that will reset it faster.  It may not work if the PIR has to wait for an internal capacitor to discharge. 

Other options would be to try a putting a diode backwards in parallel with the Vcc and ground.  It it would act like a free wheeling diode in a circuit that uses an inductor when power is turned off.  Another thing to try would be putting a resistor in parallel instead of the diode but that would increase power consumption.  Have you tried removing the plastic diffuser off the PIR to see how that affects the results?

It works pretty well now without having to resort to resetting the PIR. I just used another array to allow the PIR to be used only once after going HIGH then not use it again (by not moving the servo to that PIR position) until it goes LOW. This eliminates the situation that I described and it works quite nicely now.

I suppose faster response time would be nice but 2.5 seconds is ok. Pretty sure the PIR uses capacitor for timer.

ok I removed diffusers but pirs seem less sensitive and it doesnt seem to make a lot of difference. I think something is wrong with my algorithm but cant wrap my head around it. If pirs are 0,1,2,3 from left to right and you walk from left to right then it triggers 0,1,2,3 and then jumps back to 2. Want to check that out before I play with diodes and stuff.

I used my arduino in another project so will have to connect it back up to test it. I will do it at some point because I like playing with this one. Thanks for your great ideas. I will try removing the difuser first as I like the easiest ones best.

That's a cool gadget, makes a great toy for kids.

I'd say if you would remove the diffuser caps you'll get more directional readings?

Thanks for your idea, also proposed by the Doctor. Will get to it and let you know.

I removed difusers but then PIRs were less sensitive to movement so I altered my program a bit so now it responds only once per PIR HIGH state and doesnt jump back and forth between adjacent PIRs. 2.5 second PIR response time is livable with. Thanks for your input.

-sorry for the double post-