Construa um Detector de Gestos e Movimento com Sensor PIR e Arduino Nano
Componentes e Materiais Necessários
- Arduino Nano R3 × 1
- Sensor de Array Térmico 8 Pixels TPA81 Devantech × 1
- Sensor de Movimento Infravermelho PIR HC-SR505 ElectroPeak × 8
- Display OLED 0.96" SPI 128x64 ElectroPeak × 1
- Protoboard (genérico) × 1
- Jumpers Macho/Fêmea × 1
Aplicativos e Serviços Online
- Arduino IDE
Sobre este Projeto
Neste artigo, mostraremos como fazer um detector de gestos usando componentes simples como sensor PIR e Arduino Nano. Ao final, você poderá:
- Explicar aplicações do sensor PIR e como funciona
- Operar um sensor PIR de 8 pixels chamado TPA81
- Usar sensor PIR para detectar movimento e gestos com Arduino
- Fazer um detector legal para aumentar/diminuir volume do som
Sensor Infravermelho Passivo (PIR): Como Funciona?
Um sensor infravermelho passivo (sensor PIR) é um sensor eletrônico que mede luz infravermelha (IR) radiada por objetos em seu campo de visão. São mais usados em detectores de movimento baseados em PIR. Todos objetos com temperatura acima do zero absoluto emitem energia térmica na forma de radiação. Geralmente esta radiação não é visível ao olho humano pois irradia em comprimentos de onda infravermelhos, mas pode ser detectada por dispositivos eletrônicos projetados para tal fim.
O termo passivo refere-se ao fato de que dispositivos PIR não geram ou irradiam energia para detecção. Funcionam inteiramente detectando radiação infravermelha emitida ou refletida por objetos. Não detectam ou medem calor diretamente. (Fonte: Wikipedia)
O TPA81 é um array termopilha detectando infravermelho na faixa 2µm-22µm, o comprimento de onda do calor radiante. Sensores piroelétricos comuns em alarmes e luzes externas detectam infravermelho na mesma faixa, mas só detectam mudança nos níveis de calor – por isso são detectores de movimento. Embora úteis em robótica, suas aplicações são limitadas pois não detectam nem medem temperatura de fonte de calor estática. Outro tipo é o array termopilha, usado em termômetros infravermelhos sem contato. Têm ângulo de detecção muito amplo (FOV ~100°) e precisam de proteção ou lente para FOV útil de ~12°. Alguns têm lente embutida. Recentemente, sensores com array de termopilhas, eletrônica embutida e lente de silício tornaram-se disponíveis – este é o tipo usado no TPA81. Possui array de oito termopilhas em linha. O TPA81 mede temperatura de 8 pontos adjacentes simultaneamente. Também pode controlar servo para panear o módulo e construir imagem térmica. Detecta chama de vela a 2 metros (6 pés) e não é afetado por luz ambiente!
Sensores PIR são similares a câmeras que só veem coisas quentes. O TPA81 é uma câmera térmica de 8 pixels de resolução, e o corpo humano sempre emite calor. Se controlarmos o sensor PIR por um controlador e definirmos alguns gestos para o sensor PIR, podemos fazer um detector de gestos simples.
Neste projeto, decidimos fazer um sistema detector de gestos usando PIR e Arduino. Usamos TPA81 como PIR, mas é um pouco caro; para economizar, pode usar 8 sensores PIR simples sem a cabeça branca (parte de foco). O TPA81 suporta protocolo I2C e é compatível com Arduino Nano. Este projeto legal ajuda a entender fundamentos de processamento de imagem e detecção de gestos. Vamos lá!
Circuito
Se quiser usar 8 sensores PIR em vez do TPA81, conecte 8 sensores PIR individuais a uma placa Arduino e leia-os sequencialmente. Assim economiza dinheiro!
Código
Para o primeiro circuito (usando TPA81), copie o código na IDE Arduino. Primeiro adicione a biblioteca e depois faça upload. Baixe a biblioteca TPA81 no link a seguir. Se é sua primeira vez com Arduino, não se preocupe. Siga estes passos:
- Acesse www.arduino.cc/en/Main/Software e baixe o software do seu SO. Instale a IDE conforme instruções.
- Execute a IDE Arduino, limpe o editor e copie o código abaixo.
- Vá em Sketch > Include Library > Add .ZIP Library e adicione as bibliotecas baixadas.
- Em Tools > Board, selecione Arduino Nano.
- Conecte o Arduino ao PC e defina a porta COM em Tools > Port.
- Pressione Upload (seta).
- Pronto!
Teste Básico do TPA81
#include "Wire.h"
#include "TPA81.h"
// Cria nova instância TPA81
TPA81 tpa;
void setup() {
Serial.begin(9600);
// Precisa iniciar biblioteca Wire para usar TPA81
Wire.begin();
}
void loop() {
// Imprime temperatura ambiente
Serial.print(tpa.getAmbient());
Serial.print(" ");
// Imprime todos os 8 pontos de temperatura
for (int i = 1; i <= 8; i++) {
Serial.print(tpa.getPoint(i));
Serial.print(" ");
}
Serial.println(" ");
delay(100);
}
Após rodar, abra o Terminal Serial na IDE Arduino e observe os 8 valores de temperatura. O primeiro número de cada linha é a temperatura ambiente. Coloque a mão frente ao sensor e veja a temperatura do seu corpo. Para definir gesto com a mão, deve saber a temperatura da mão e definir como offset. Definimos 29 graus. Carregue o próximo código para ver movimento da mão frente ao TPA81.
Visualização de Movimento
#include "Wire.h"
#include "TPA81.h"
TPA81 tpa;
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Serial.print(tpa.getAmbient());
Serial.print(" ");
for (int i = 1; i <= 8; i++) {
if (tpa.getPoint(i) > 29) Serial.print("# ");
else Serial.print(". ");
}
Serial.println(" ");
delay(100);
}
Detector de Gestos para Controle de Volume
Escrevemos um algoritmo para detectar gesto simples como aumentar/diminuir volume de um player de som. Copie o código abaixo e teste.
#include "Wire.h"
#include "TPA81.h"
#include "ssd1306.h"
#include "DHT.h"
TPA81 tpa;
#define VCCSTATE SSD1306_SWITCHCAPVCC
#define WIDTH 128
#define HEIGHT 64
#define PAGES 8
#define OLED_RST 9
#define OLED_DC 8
#define OLED_CS 10
#define SPI_MOSI 11 // conecta ao pino DIN do OLED
#define SPI_SCK 13
uint8_t oled_buf[WIDTH * HEIGHT / 8];
int gesture[8][20];
int tgesture[8];
int sum = 0;
int sflag; // standby flag
int gcount;
int c;
int ex;
int vol = 5;
// Bitmaps para níveis de volume (v1 a v11) armazenados em PROGMEM
const uint8_t v1 [] PROGMEM = { ... }; // (dados omitidos por brevidade)
const uint8_t v2 [] PROGMEM = { ... };
const uint8_t v3 [] PROGMEM = { ... };
const uint8_t v4 [] PROGMEM = { ... };
const uint8_t v5 [] PROGMEM = { ... };
const uint8_t v6 [] PROGMEM = { ... };
const uint8_t v7 [] PROGMEM = { ... };
const uint8_t v8 [] PROGMEM = { ... };
const uint8_t v9 [] PROGMEM = { ... };
const uint8_t v10 [] PROGMEM = { ... };
const uint8_t v11 [] PROGMEM = { ... };
void dsply(int input) {
int n1, n2;
if (input < 10) {
SSD1306_char3216(10, 25, '0', oled_buf);
switch(input) {
case 0: SSD1306_char3216(26, 25, '0', oled_buf); break;
case 1: SSD1306_char3216(26, 25, '1', oled_buf); break;
case 2: SSD1306_char3216(26, 25, '2', oled_buf); break;
case 3: SSD1306_char3216(26, 25, '3', oled_buf); break;
case 4: SSD1306_char3216(26, 25, '4', oled_buf); break;
case 5: SSD1306_char3216(26, 25, '5', oled_buf); break;
case 6: SSD1306_char3216(26, 25, '6', oled_buf); break;
case 7: SSD1306_char3216(26, 25, '7', oled_buf); break;
case 8: SSD1306_char3216(26, 25, '8', oled_buf); break;
case 9: SSD1306_char3216(26, 25, '9', oled_buf); break;
}
} else {
n1 = input / 10;
n2 = input % 10;
switch(n1) {
case 0: SSD1306_char3216(10, 25, '0', oled_buf); break;
case 1: SSD1306_char3216(10, 25, '1', oled_buf); break;
case 2: SSD1306_char3216(10, 25, '2', oled_buf); break;
case 3: SSD1306_char3216(10, 25, '3', oled_buf); break;
case 4: SSD1306_char3216(10, 25, '4', oled_buf); break;
case 5: SSD1306_char3216(10, 25, '5', oled_buf); break;
case 6: SSD1306_char3216(10, 25, '6', oled_buf); break;
case 7: SSD1306_char3216(10, 25, '7', oled_buf); break;
case 8: SSD1306_char3216(10, 25, '8', oled_buf); break;
case 9: SSD1306_char3216(10, 25, '9', oled_buf); break;
}
switch(n2) {
case 0: SSD1306_char3216(26, 25, '0', oled_buf); break;
case 1: SSD1306_char3216(26, 25, '1', oled_buf); break;
case 2: SSD1306_char3216(26, 25, '2', oled_buf); break;
case 3: SSD1306_char3216(26, 25, '3', oled_buf); break;
case 4: SSD1306_char3216(26, 25, '4', oled_buf); break;
case 5: SSD1306_char3216(26, 25, '5', oled_buf); break;
case 6: SSD1306_char3216(26, 25, '6', oled_buf); break;
case 7: SSD1306_char3216(26, 25, '7', oled_buf); break;
case 8: SSD1306_char3216(26, 25, '8', oled_buf); break;
case 9: SSD1306_char3216(26, 25, '9', oled_buf); break;
}
}
}
void setup() {
Serial.begin(9600);
Wire.begin();
SSD1306_begin();
SSD1306_clear(oled_buf);
}
void loop() {
// Leitura dos 8 pixels
for (int i = 0; i <= 7; i++) {
if (tpa.getPoint(i) > 29) {
Serial.print("#");
Serial.print(" ");
gesture[i][0] = 1;
} else {
Serial.print(".");
Serial.print(" ");
gesture[i][0] = 0;
}
}
for (int y = 0; y <= 7; y++) sum += gesture[y][0];
Serial.println(sum); // soma dos 8 pixels
Serial.println(" ");
delay(100); // velocidade de leitura
////////////////////////////////////////////////////////////////////////////////////// standby
if (sum == 8) {
sflag = 1;
Serial.println("standby");
} else {
sum = 0;
}
////////////////////////////////////////////////////////////////////////////////////// progresso do gesto
if (sflag == 1 && sum != 8) {
Serial.println("inicio gesto");
gcount = 0;
c = 0;
sum = 0;
while (sum < 8) {
sum = 0;
for (int i = 0; i <= 7; i++) {
if (tpa.getPoint(i) > 29) {
Serial.print("#");
Serial.print(" ");
gesture[i][gcount] = 1;
} else {
Serial.print(".");
Serial.print(" ");
gesture[i][gcount] = 0;
}
}
for (int y = 0; y <= 7; y++) {
sum += gesture[y][gcount];
delay(5);
}
Serial.println(" ");
delay(50); // velocidade de leitura
gcount++; // duração do gesto
}
Serial.print("soma: ");
Serial.println(sum);
Serial.print("comprimento do gesto: ");
Serial.println(gcount);
delay(5);
for (c = 0; c <= 7; c++) {
for (int z = 0; z <= gcount; z++) {
tgesture[c] += gesture[c][z];
delay(5);
}
Serial.println("processando");
}
tgesture[0] += tgesture[1];
tgesture[2] += tgesture[3];
tgesture[4] += tgesture[5];
tgesture[6] += tgesture[7];
tgesture[0] += tgesture[2];
tgesture[4] += tgesture[6];
if (tgesture[0] < tgesture[4]) {
vol += (gcount / 2);
Serial.print("volume up");
}
if (tgesture[4] < tgesture[0]) {
vol -= (gcount / 2);
Serial.print("volume down");
}
sflag = 0;
}
sum = 0;
SSD1306_clear(oled_buf);
switch (vol) {
case 1: SSD1306_bitmap(0, 0, v1, 128, 64, oled_buf); break;
case 2: SSD1306_bitmap(0, 0, v2, 128, 64, oled_buf); break;
case 3: SSD1306_bitmap(0, 0, v3, 128, 64, oled_buf); break;
case 4: SSD1306_bitmap(0, 0, v4, 128, 64, oled_buf); break;
case 5: SSD1306_bitmap(0, 0, v5, 128, 64, oled_buf); break;
case 6: SSD1306_bitmap(0, 0, v6, 128, 64, oled_buf); break;
case 7: SSD1306_bitmap(0, 0, v7, 128, 64, oled_buf); break;
case 8: SSD1306_bitmap(0, 0, v8, 128, 64, oled_buf); break;
case 9: SSD1306_bitmap(0, 0, v9, 128, 64, oled_buf); break;
case 10: SSD1306_bitmap(0, 0, v10, 128, 64, oled_buf); break;
case 11: SSD1306_bitmap(0, 0, v11, 128, 64, oled_buf); break;
}
SSD1306_display(oled_buf);
}
O que Vem a Seguir?
Usando o método acima, você pode estender o código para detectar outros gestos como toque, arrastar, soltar, esticar, etc. Então defina comandos para executar certas tarefas ao detectar cada um desses movimentos e gestos.
Código
Biblioteca TPA81
Disponível apenas para download (C/C++).
Biblioteca SSD1306
Disponível apenas para download (C/C++).
Processo de manufatura
- Sensores Arduino: Tipos, Aplicações e Projetos do Mundo Real
- Como Funcionam Circuitos de Sensor PIR: Projeto, Operação e Aplicações Reais
- Controle um LED com Sensor de Movimento PIR no Raspberry Pi
- Domine GPIO do Raspberry Pi: Interface com Sensor PIR de Movimento no B+/Modelo 2
- Como Conectar, Calibrar e Programar Sensor PIR HC‑SR501 com Raspberry Pi
- Projeto DHT11: Sensor Temperatura/Umidade com LEDs Indicadores e Buzzer
- Robô de Detecção Humana Baseado em Arduino Uno: Integração de Sensores Passo a Passo
- Construa um Pote Inteligente IoT com ESP8266, Arduino e Sensor Ultrassônico – Monitoramento em Tempo Real
- Display Interativo de Matriz LED na Porta com Sensor PIR – Saudação de Férias Arduino
- Construa uma Torre de Sensores com Arduino Cloud: Monitoramento de Temperatura, Movimento e Gás