Детектор жестов и движения на PIR-сенсоре и Arduino Nano
Компоненты и материалы
| Arduino Nano R3 | × | 1 |
| TPA81 Devantech 8-пиксельный термический массив | × | 1 |
| PIR-датчик движения HC-SR505 (ElectroPeak) | × | 8 |
| OLED-дисплей 0.96" SPI 128x64 (ElectroPeak) | × | 1 |
| Макетная плата | × | 1 |
| Перемыжки Male/Female | × | 1 |
Приложения и сервисы
- Arduino IDE
О проекте
В статье показано, как сделать детектор жестов из простых компонентов: PIR-сенсор и Arduino Nano. Вы научитесь:
- Понимать принцип работы PIR-сенсора
- Работать с 8-пиксельным сенсором TPA81
- Определять движение и жесты с Arduino
- Сделать регулятор громкости жестами

Пассивный инфракрасный сенсор: как это работает?
PIR-сенсор измеряет инфракрасное излучение от объектов в поле зрения. Все объекты выше абсолютного нуля излучают тепло в ИК-диапазоне. PIR не излучает энергию сам — он пассивно детектирует излучение. (Источник: Wikipedia)

TPA81 — термопильный массив, чувствителен к 2–22 мкм (тепловое излучение). В отличие от пироэлектрических датчиков (только изменение тепла), TPA81 измеряет абсолютную температуру 8 точек одновременно. Угол обзора ~12° (с линзой). Может обнаружить пламя свечи на 2 м. Независим от видимого света.

PIR-сенсоры — как камеры, видящие только тепло. TPA81 — тепловизор 8 пикселей. Человеческое тело всегда излучает тепло. Контролируя сенсор и определяя паттерны, можно распознавать жесты.
В проекте используется TPA81 (I2C, совместим с Nano). Экономия: можно заменить на 8 обычных PIR без линз, опрашивая их последовательно.
Схема подключения

Вариант с 8 отдельными PIR:

Код
Для работы с TPA81 нужна библиотека TPA81.h. Установка: Sketch → Include Library → Add .ZIP Library.
1. Базовое чтение температур
#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++) {
Serial.print(tpa.getPoint(i)); Serial.print(" ");
}
Serial.println();
delay(100);
}
Откройте Serial Plotter. Первое число — общая температура. Поднесите руку — увидите изменение.
2. Визуализация движения руки (порог 29°C)
#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);
}
В Serial Monitor увидите анимацию движения руки (# — горячее, . — фон).
3. Распознавание жеста «громкость вверх/вниз» с выводом на OLED
#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
#define SPI_SCK 13
uint8_t oled_buf[WIDTH * HEIGHT / 8];
int gesture[8][20];
int tgesture[8];
int sum = 0, sflag = 0, gcount = 0, c = 0, ex = 0, vol = 5;
//.Bitmap-иконки громкости v1..v11 хранятся в PROGMEM (массивы const uint8_t v1[] ... v11[])
// ... (код массивов опущен для краткости, см. исходник)
void dsply(int input) {
int n1, n2;
if (input < 10) {
SSD1306_char3216(10, 25, '0', oled_buf);
SSD1306_char3216(26, 25, '0' + input, oled_buf);
} else {
n1 = input / 10; n2 = input % 10;
SSD1306_char3216(10, 25, '0' + n1, oled_buf);
SSD1306_char3216(26, 25, '0' + n2, oled_buf);
}
}
void setup() {
Serial.begin(9600);
Wire.begin();
SSD1306_begin();
SSD1306_clear(oled_buf);
}
void loop() {
// Чтение 8 пикселей
for (int i = 0; i <= 7; i++) {
if (tpa.getPoint(i+1) > 29) { Serial.print("# "); gesture[i][0] = 1; }
else { Serial.print(". "); gesture[i][0] = 0; }
}
for (int y = 0; y <= 7; y++) sum += gesture[y][0];
Serial.println(sum);
Serial.println();
delay(100);
// Standby: все 8 пикселей горячие
if (sum == 8) { sflag = 1; Serial.println("standby"); }
else { sum = 0; }
// Обнаружение жеста
if (sflag == 1 && sum != 8) {
Serial.println("start gesture");
gcount = 0; c = 0; sum = 0;
while (sum < 8) {
sum = 0;
for (int i = 0; i <= 7; i++) {
if (tpa.getPoint(i+1) > 29) { Serial.print("# "); gesture[i][gcount] = 1; }
else { Serial.print(". "); gesture[i][gcount] = 0; }
}
for (int y = 0; y <= 7; y++) { sum += gesture[y][gcount]; delay(5); }
Serial.println(); delay(50);
gcount++;
}
Serial.print("sum: "); Serial.println(sum);
Serial.print("gesture length: "); 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("processing");
}
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.println("volume up"); }
if (tgesture[4] < tgesture[0]) { vol -= (gcount / 2); Serial.println("volume down"); }
sflag = 0;
}
sum = 0;
// Отображение уровня громкости на OLED
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);
}

Что дальше?
Метод можно расширить для распознавания тапов, свайпов, растяжений и т.д. Определив команды для каждого жеста, можно управлять различными устройствами.
Библиотеки
- TPA81 Library (C/C++)
- SSD1306 Library (C/C++)
Производственный процесс
- Arduino-датчики: типы, применения и реальные проекты
- Как работают схемы на PIR-датчиках: проектирование, принцип работы и реальные применения
- Управление светодиодом с PIR-датчиком движения на Raspberry Pi
- Мастерство GPIO Raspberry Pi: подключение PIR-датчика движения на B+/Model 2
- Подключение, калибровка и программирование PIR-датчика HC‑SR501 с Raspberry Pi
- Проект с датчиком DHT11: индикация температуры светодиодами и пьезо-динамиком на Arduino
- Робот для поиска людей на базе Arduino Uno: пошаговая интеграция датчиков
- Умная банка на ESP8266 + Arduino: мониторинг наполненности в реальном времени
- Интерактивный LED-дисплей в двери с PIR-датчиком — новогоднее приветствие на Arduino
- Сенсорная башня на Arduino Cloud: Мониторинг температуры, движения и газа