Testes ao PIR SE-10 com resultados preocupantes

Olá malta

Eu estou a desenvolver um projeto em que uso os sensores de movimento PIR para detetar a presença de pessoas numa sala. Eu optei pela compra do SE-10 disponibilizado pela http://www.sparkfun.com/products/8630.

Apesar de o sensor ser bastante simples e de fácil funcionamento, estou obtendo resultados pouco positivos.
Esta manhã estive a fazer uns testes, colocando o sensor no interior de uma caixa envolto em plástico.

Seria de prever que não fosse detetado movimento, mas os resultados foram os seguintes:
em 1275 iterações, os sensor diz ter detetado movimento em 140 das vezes , o que dá uma percentagem de 10% de erro!!!

Eu segui o esquema de funcionamento de um coletor aberto com uma resistência de pullup de 10k ohms segundo sugerido pelo sítio http://bildr.org/2011/06/pir_arduino/

Será este um defeito do sensor?eu tentei com dois e ambos dão este erro...
:roll_eyes: :roll_eyes:

A única coisa que consigo pensar é que a caixa é demasiado pequena.
Já experimentaste num quarto durante a noite, por exemplo?

Pode ser uma boa sugestão. segunda feira faço o teste e digo-te as conclusões a que cheguei
:wink:

Já agora por curiosidade aqui fica o código que utilizei

int calibrationTime = 60;        

int pirPin1 = 2; //digital 2

int LED1 = 4;
int n_detecoes=0;
int n_iteracoes=0;
int per_detecoes=0;

  
void setup()
{
  Serial.begin(9600);
  pinMode(pirPin1,INPUT);

  pinMode(LED1,OUTPUT);

  digitalWrite(LED1,LOW);

  //give the sensor some time to calibrate
  Serial.println("Sensor Calibration in Progress");
  Serial.println("------------------------------");
  for(int i = 0; i < calibrationTime; i++){
    Serial.print(".");
    digitalWrite(LED1, HIGH);
    delay(250);
    digitalWrite(LED1, LOW);
    delay(250);
  }

  Serial.println("");
  Serial.println("Sensor Calibration Completed");
  Serial.println("Sensor Reading Active");
  delay(50);
  
}

void loop()
{
  int pirVal1 = digitalRead(pirPin1);
  
  if(pirVal1 == LOW)
  { 
    //was motion detected
    Serial.print(pirVal1);
    Serial.print(';');
    
    n_detecoes=n_detecoes+1;
    Serial.print(n_detecoes);
    Serial.print(';');
    
    digitalWrite(LED1,HIGH);
    delay(2000);
  }
    else
    {
    Serial.print(pirVal1);
    Serial.print(';');
    Serial.print(n_detecoes);
    Serial.print(';');

    
    digitalWrite(LED1,LOW); 
    delay(2000);
    }
    
    n_iteracoes +=1;
    Serial.print(n_iteracoes); 
    Serial.print(';');
    per_detecoes =(n_detecoes*100)/n_iteracoes;
    Serial.print(per_detecoes);
    Serial.println(';');
}

O código parece-me correcto. Não vejo erros nenhuns lá.

Os PIR funcionam por temperatura, a caixa esteve sujeita a alguma diferença de temperatura?
Algo que a sparkfun não tem é o campo de visão deste sensor, que indica o alcance e qual a maneira como a sensibilidade do sensor é distribuída. Isso seria mais ou menos importante para assumir que a caixa é pequena demais e interfere com o campo de visão.

O ideal é mudar as variáveis para unsigned long e deixar isso a rolar numa sala vazia durante a noite.

Obrigado pela resposta Bubu

A caixa é feita em papelão e não tem qualquer diferença de temperatura brusca, só se houver por aqui fantasmas :slight_smile:

Já tentei arranjar o tal alcance e sensibilidades dos sensores, mas o fabricante, meio chinês meio coreano, não responde...

Vou seguir a tua sugestão e ver quais são os resultados numa sala escura...

Um sensor PIR funciona por variação de infravermelho, as fontes podem ser muitas, uma janela aberta por exemplo.
O sistema de detecção compara um sinal através de um integrador com o sinal normal, se houver diferença significa que algo penetrou no campo, se a variação for lenta ele não dispara, pois o integrador se ajusta ao novo valor, se a variação for rápida, significa que algo que emite infravermelho penetrou no campo de detecção.
Alguns anos atras desenvolvemos esse sensor que une micro-ondas com infravermelho, pois se você colocar uma madeira na frente do corpo o sensor de infravermelho não detecta nada, pois a fonte de calor fica bloqueada, já o de micro-ondas detecta:
http://www.eck-projeto-eletronico.com.br/2011/04/05/eck-desenvolveu-um-projeto-de-eletronica-sensor-presenca-com-micro-ondas-e-infravermelho/
Edson

Olá de novo pessoal!
Parece que o Bubu acertou em cheio no problema. Quando coloquei o sensor numa sala escura ele já não detetou qualquer movimento inexistente :slight_smile:

Só tive pena de passar algumas vezes por ele e o sensor não me detetar :frowning:
Poderá ser do delay ser 2000?

Obrigado a todas pela ajuda

He shoots, he scores... :slight_smile:

Quando vi o delay no código pensei isso mesmo... mas depois pensei que não querias contar o mesmo pulso mais que uma vez e meteste o delay.

Já experimentaste contar por flancos?

sensor = digitalRead(PIR);
char flanco=0;

if (sensor == HIGH && flanco == 0) {
    flanco = 1; 
    hits++;
    }
if (sensor == LOW) {flanco = 0;}

Outra hipótese mais engracada e talvez mais simples de codificar seria ligar o sensor a um dos pinos dos temporizadores (T1 ou T2 se precisares do millis()) e usares o relógio como contador de eventos. Aí não terias problemas já que o relógio conta apenas nas transicões.
Depois era tão simples como:

set_cnt(unsigned int value) {
TCNTx = value;
}

unsigned int read_cnt() {
return TCNTx;
}

Estou a ver que dominas bem mais que eu o arduino XD

Não estou a entender bem nem os objetivos do flanco nem da segunda opção que sugeres…

A primeira opção é contar as transições de LOW para HIGH em vez de contar o número de vezes que o sinal está activo. Esse PIR mantém o sinal activo durante um segundo sempre que detecta alguém. Se o arduino estiver sempre a correr (sem o delay), vai contar várias vezes a mesma detecção. Se incrementares o contador sempre que o sinal do sensor passar de 0 para 1, estás descansado porque não conta a mesma detecção mais que uma vez.

A segunda opção implica algum conhecimento dos timers. Mas basicamente os timers do Arduino podem ter várias fontes de "temporização". Se reparares no manual, diz Timer/Counter. Isto significa que na realidade o que chamamos de timer é um counter... se dermos um sinal com uma determinada frequência a esse contador, estamos efectivamente a contar tempo.

No entanto, o Arduino permite usar um dos pinos dos microcontrolador como fonte para esse contador. Assim sendo, sempre que existe uma transição de baixo para alto nesse pino o contador incrementa automaticamente. Estranhamente não consegui encontrar exemplos para isto na net. :expressionless:
Amanhã posso dar uma vista de olhos ao manual e meter aqui uma configuração do timer para exemplificar este modo. Nota que isto faz com que não possas usar PWM ou millis dependendo do timer que usares para contar os eventos.

Olá

Estou vendendo um produto no MercadoLivre Brasil que usa exatamente essas peças que usastes no teu projecto: Arduino Uno, SE-10, um breadboard, alguns fios, dois resistores (um deles para o pull-up) e um LED (para depurações de erros :wink: ).

No meu caso, o sensor funciona bem até mesmo em locais com iluminação.

Por que não usas a função pulseIn() do Arduino, em vez de esperar por um LOW e depois um HIGH?

Os meus SE-10 fornecem um pulso LOW de aproximadamente 900 ms quando há detecção.

O inconveniente do SE-10 é que o alcance dele é de apenas 2-3 metros.

s

neuron_upheaval

neuron_upheaval:
Por que não usas a função pulseIn() do Arduino, em vez de esperar por um LOW e depois um HIGH?

pulseIn() - Arduino Reference

O problema do pulse in é que bloqueia o programa...

unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
	// cache the port and bit of the pin in order to speed up the
	// pulse width measuring loop and achieve finer resolution.  calling
	// digitalRead() instead yields much coarser resolution.
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);
	uint8_t stateMask = (state ? bit : 0);
	unsigned long width = 0; // keep initialization out of time critical area
	
	// convert the timeout from microseconds to a number of times through
	// the initial loop; it takes 16 clock cycles per iteration.
	unsigned long numloops = 0;
	unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
	
	// wait for any previous pulse to end
	while ((*portInputRegister(port) & bit) == stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to start
	while ((*portInputRegister(port) & bit) != stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to stop
	while ((*portInputRegister(port) & bit) == stateMask) {
		if (numloops++ == maxloops)
			return 0;
		width++;
	}

	// convert the reading to microseconds. The loop has been determined
	// to be 20 clock cycles long and have about 16 clocks between the edge
	// and the start of the loop. There will be some error introduced by
	// the interrupt handlers.
	return clockCyclesToMicroseconds(width * 21 + 16); 
}

Ou seja, apesar do timeout, etc... é processamento desperdicado. Além do facto que o pulseIn não garante contagem dum impulso. Basta que o impulso aconteca logo após um timeout e pronto... perdeu-se esse impulso.

Daí que testar o flanco (que é o que se pretende, em vez da duracão do impulso) seja uma melhor solucão. Ainda assim, a minha preferida é a do timer como contador.

Desculpa não ter dado uma vista de olhos ainda acerca de como o configurar. Vou tentar ver isso hoje.

Mais uma vez agradeço toda a vossa ajuda!
Antes de responder às vossas sugestões gostaria de vos dizer que experimentei outra alternativa, utilizar a entrada analógica do arduino para ver como reagia o sensor. Pois bem, com este novo código ele deteta bem o movimento, o que me faz pensar que o problema do códiog que vos mostrei deve ser mesmo o delay...

Em relação às vossas 3 sugestões, pelo que entendi, sugerem que em vez de trabalhar com o HIGH e o LOW que o sensor devolve, que use o tempo entre as deteções de forma a evitar que este repita resultados certo??

Ainda estou a tentar colocar os códigos com as vossas sugestões a funcionar, pois são coisas novas que sem vocês não descobriria :slight_smile:

Desculpa bubu mas não tinha visto a tua última mensagem...

Fico à espera da tua configuração

bubulindo:

neuron_upheaval:
Por que não usas a função pulseIn() do Arduino, em vez de esperar por um LOW e depois um HIGH?

pulseIn() - Arduino Reference

O problema do pulse in é que bloqueia o programa...

[code snipped]

Ou seja, apesar do timeout, etc... é processamento desperdicado. Além do facto que o pulseIn não garante contagem dum impulso. Basta que o impulso aconteca logo após um timeout e pronto... perdeu-se esse impulso.

Daí que testar o flanco (que é o que se pretende, em vez da duracão do impulso) seja uma melhor solucão. Ainda assim, a minha preferida é a do timer como contador.

Desculpa não ter dado uma vista de olhos ainda acerca de como o configurar. Vou tentar ver isso hoje.

Mas o fato de o pulseIn() pausar o programa é indiferente se o programa depende exclusivamente da detecção do sensor para fazer o que precisa; além do mais, Serial.print()'s e delay()'s também bloqueiam o programa

Se queres algo que realmente execute apesar dos bloqueios no programa, usa interrupções:

http://arduino.cc/en/Reference/AttachInterrupt

neuron_upheaval:
além do mais, Serial.print()'s e delay()'s também bloqueiam o programa

Bloqueavam, agora só o delay é que bloqueia o programa... daí ter sugerido não usar o pulseIn, já que o pulseIn faz o mesmo que o delay().

Lembrei-me de ver os tutoriais do Nick Gammon (com o mesmo nick aqui no fórum) e ele tem um exemplo para usar um timer como contador de eventos. :slight_smile:

NEste link:

http://gammon.com.au/forum/?id=11504

O primeiro exemplo que aparece conta o número de pulsos no pino T1, ou seja D5 no arduino. Experimenta e vê os resultados.

P.S.: O código completo cria um contador de eventos e de frequência, no entanto no teu caso podes limpar o código de tudo o que tenha a ver com o Timer2.

Bem esta ajuda talvez seja demasiada avançada para o meu projeto. Penso não ser necessário incluir este código.
Estou um pouco confuso com tanta informação :~ daí talvez seja melhor dizer de novo o que estou procurando.
O sistema PIR deve detetar quando uma pessoa está num dado espaço. Como o objetivo é relacionar a presença de pessoas com o consumo, e enviar os dados para processing, vai-se assumir que essa pessoa permanece na sala um x tempo até o sensor fazer nova deteção.
Isto acontece pois é dificil construir um sistema com estes sensores que detete de forma eficaz a entrada e a saída de pessoas. Eu vi algo do género neste projeto http://r00li.com/rolihome mas como se vê pelas images não seria muito fácil adaptar o sistema.

O Arduino é mesmo um mundo bem grande XD

Muito obrigado pela ajuda Bubu

Aqui fica o código de principiante que estou a utilizar neste momento :slight_smile:
Esqueci-me de referir que estou a usar dois sensores PIR e além destes cou acrescentar um de ultra-sons…

int PIR1 = 2;
int PIR2 = 3;
int LED1 = 4;
int LED2 = 5;
int val1 = 0;
int val2 = 0;
int count1 = 0;
int count2 = 0;
int calibrationTime = 20;

void setup (){
  Serial.begin(9600);
  pinMode(PIR1,INPUT);
  pinMode(PIR2,INPUT);
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
  
  //give the sensor some time to calibrate
  Serial.println("Sensor Calibration in Progress");
  Serial.println("------------------------------");
  for(int i = 0; i < calibrationTime; i++){
    Serial.print(".");
    digitalWrite(LED1, HIGH);
    delay(250);
    digitalWrite(LED2, HIGH);
    delay(250);
    digitalWrite(LED1, LOW);
    delay(250);
    digitalWrite(LED2, LOW);
    delay(250);
  }

  Serial.println("");
  Serial.println("Sensor Calibration Completed");
  Serial.println("Sensor Reading Active");
  delay(100);
}

void loop(){
  int val1 = digitalRead(PIR1);
  int val2 = digitalRead(PIR2);

  if((val1 == LOW) ) 
    count1=1;
    Serial.print(val1);
    Serial.print(',');
  
  if((val2 == LOW) ) 
    count2=2;
    Serial.println(val2);
    
  if(count1>0){
    count1++;
    digitalWrite(LED1,HIGH);
  }   
  
  if(count2>0){
    count2++;
    digitalWrite(LED2,HIGH);
  }   
      
  if(count1 == 500){
    digitalWrite(LED1,LOW);
    Serial.print(val1);
    Serial.print(',');
    count1=0;
    
  }
  
  if(count2 == 500){
    digitalWrite(LED2,LOW);
    Serial.println(val2);
    count2=0;
    
  }
}

xaral:
Isto acontece pois é dificil construir um sistema com estes sensores que detete de forma eficaz a entrada e a saída de pessoas.

O melhor que vi para isto até hoje foi um sensor de barreira. :\ Aí o pulso é indicativo de alguém a tapá-lo, enquanto que com estes PIR (a não ser que alteres a cúpula por cima deles) a gama de detecção é algo elevada demais para o que pretendes e durante o segundo que ele indicou movimento, pode haver muito mais gente a entrar e sair. Claro que alguém pode parar a conversar na porta e mais pessoas entrarem sem contagem... mas isso são pormenores. :stuck_out_tongue: