В наше время стали весьма популярными разнообразные браслеты для фитнеса, которые могут не только считать шаги, но и показывать количество сожжённых вами калорий, отображать на экране вашу частоту пульса, показывать время и многое другое. Большинство этих умных устройств, относящихся к категории интернета вещей (IoT – Internet of Things) сохраняют всю эту информацию в облаке, благодаря чему вы всегда можете просмотреть ее на своем смартфоне. Ранее на нашем сайте мы уже рассматривали умную систему мониторинга здоровья пациента на основе Arduino, которая сохраняет всю критически важную информацию на сервере ThingSpeak, откуда ее можно прочесть из любой точки мира (где есть интернет).
Но кроме таких умных браслетов в настоящее время также востребованы и обычные счетчики шагов (шагомеры). В данной статье мы рассмотрим создание простого и дешевого шагомера (педометра) на основе платы Arduino и акселерометра. Этот шагомер будет подсчитывать количество шагов и отображать его на экране ЖК дисплея 16×2. Этот шагомер можно интегрировать с умными часами на основе Arduino. Также на нашем сайте вы можете посмотреть проект шагомера на основе микроконтроллера ATtiny85.
Необходимые компоненты
- Плата Arduino Nano (купить на AliExpress).
- Акселерометр (ADXL335) (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Модуль I2C для работы с ЖК дисплеем (LCD I2C Module) (купить на AliExpress).
- Батарейка.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Акселерометр ADXL335
ADXL335 представляет собой 3-осевой аналоговый акселерометр, принцип работы которого основан на обнаружении изменения емкости. ADXL335 имеет небольшие размеры, потребляет мало мощности и содержит внутри себя поликристаллический кремниевый датчик и схему обработки сигналов от данного датчика. Данный акселерометр может измерять как статическое, так и динамическое ускорение. В нашем проекте счетчика шагов на Arduino акселерометр ADXL335 будет выполнять роль датчика шагов.
Акселерометр является устройством, которое преобразует ускорение в любом направлении в соответствующее изменение напряжения. Это достигается при помощи использования конденсаторов внутри акселерометра, при ускорении емкость этих конденсаторов изменяется, что приводит к изменению напряжения.
На следующем рисунке показан внешний вид передней и задней частей акселерометра.
Назначение контактов акселерометра ADXL335:
Vcc – контакт для подачи напряжения постоянного тока 5 В.
X-OUT – выход акселерометра по оси x.
Y-OUT – выход акселерометра по оси y.
Z-OUT – выход акселерометра по оси z.
GND – общий провод (земля).
ST – этот контакт используется для установки чувствительности датчика.
На нашем сайте вы можете посмотреть следующие проекты с использованием акселерометра ADXL335:
- игра в Ping Pong с использованием Arduino и акселерометра;
- робот на Arduino управляемый с помощью жестов рук и акселерометра;
- система предупреждения об авариях автомобилей с использованием Arduino, GPS и GSM.
Схема проекта
Схема шагомера на основе платы Arduino и акселерометра ADXL335 представлена на следующем рисунке.
На представленной схеме контакты X, Y и Z акселерометра подключены к аналоговым контактам A1, A2 & A3 платы Arduino Nano. Для подключения ЖК дисплея 16×2 к плате Arduino Nano мы в этом проекте использовали модуль интерфейса I2C. Контакты SCL и SDA данного модуля подключены к контактам A5 и A4 платы Arduino Nano соответственно. Полная схема соединений нашего проекта представлена в следующей таблице.
Arduino Nano | ADXL335 |
3.3V | VCC |
GND | GND |
A1 | X |
A2 | Y |
A3 | Z |
Arduino Nano | LCD I2C Module |
5V | VCC |
GND | GND |
A4 | SDA |
A5 | SCL |
Внешний вид собранной на макетной плате конструкции нашего проекта показан на следующем рисунке.
После тестирования проекта на макетной плате мы спаяли его затем на перфорированной плате (Perfboard) и у нас получилась конструкция следующего вида:
Принцип работы счетчика шагов (шагомера)
Счетчик шагов (шагомер) подсчитывает общее количество шагов, сделанное человеком, используя значения изменения осей X, Y и Z, получаемые с акселерометра. Акселерометр непрерывно обновляет максимальное и минимальное значения этих осей после определенного числа отсчетов. Среднее значение этих трех осей ((Max + Min)/2) называется динамическим пороговым значением и именно это значение используется для принятия решения о том был ли сделан шаг или нет.
Во время движения шагомер может находиться в любой ориентации (положении), поэтому он считает шаги вдоль той оси, вдоль которой происходят наибольшие изменения ускорения.
Краткий алгоритм работы шагомера выглядит следующим образом:
- После подачи питания шагомер производит свою калибровку.
- Затем в функции void loop он непрерывно считывает значения осей X, Y и Z.
- После этого шагомер рассчитывает вектор суммарного ускорения от начальной точки.
- Вектор ускорения представляет собой квадратный корень из (x^2+y^2+z^2).
- Далее шагомер сравнивает рассчитанный вектор ускорения с заранее определенной границей и на основании этого принимает решение увеличивать ли счетчик шагов или нет.
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Вначале в программе подключим библиотеку для работы с ЖК дисплеем по протоколу I2C. Для работы с акселерометром ADXL335 не требуется никакой библиотеки поскольку у него аналоговый выход.
1 |
#include <LiquidCrystal_I2C.h> |
После этого объявим контакты платы Arduino, к которым подключен акселерометр.
1 2 3 |
const int xpin = A1; const int ypin = A2; const int zpin = A3; |
Зададим границу (граничное значение) для срабатывания счетчика шагов – с ней будет сравниваться рассчитанный вектор ускорения.
1 |
float threshold = 6; |
Внутри функции void setup будем запускать функцию калибровки.
1 |
calibrate(); |
Внутри функции void loop мы будем считывать значения осей X, Y и Z на протяжении 100 отсчетов.
1 2 3 4 5 6 7 8 |
for (int a = 0; a < 100; a++) { xaccl[a] = float(analogRead(xpin) - 345); delay(1); yaccl[a] = float(analogRead(ypin) - 346); delay(1); zaccl[a] = float(analogRead(zpin) - 416); delay(1); |
После этого мы будем рассчитывать суммарный вектор ускорения при помощи вычисления квадратного корня из суммы квадратов значений осей X, Y и Z.
1 |
totvect[a] = sqrt(((xaccl[a] - xavg) * (xaccl[a] - xavg)) + ((yaccl[a] - yavg) * (yaccl[a] - yavg)) + ((zval[a] - zavg) * (zval[a] - zavg))); |
Затем мы будем рассчитывать среднее от максимального и минимального значений вектора ускорения.
1 |
totave[a] = (totvect[a] + totvect[a - 1]) / 2 ; |
После этого мы будем сравнивать рассчитанное среднее значения ускорения с определенным нами ранее граничным значением. Если среднее ускорение больше этого граничного значения, то мы будем увеличивать счетчик шагов и устанавливать соответствующий флаг.
1 2 3 4 |
if (totave[a] > threshold && flag == 0) { steps = steps + 1; flag = 1; } |
Если среднее ускорение больше граничного значения, но флаг уже установлен, то не делаем ничего.
1 2 3 4 |
else if (totave[a] > threshold && flag == 1) { // Don’t Count } |
Если среднее ускорение меньше граничного значения и флаг установлен, то сбрасываем флаг.
1 2 3 4 |
if (totave[a] < threshold && flag == 1) { flag = 0; } |
Выводим подсчитанное значение шагов в окно монитора последовательной связи и на экран ЖК дисплея.
1 2 3 |
Serial.println(steps ); lcd.print("Steps: "); lcd.print(steps); |
Тестирование работы шагомера (педометра)
После того, как аппаратная часть проекта будет готова, загрузите программу в плату Arduino. После этого возьмите шагомер в руки и начните делать шаги – вы увидите сделанное число шагов на экране ЖК дисплея. Иногда наш шагомер может срабатывать от ложных вибраций – но у нас же максимально дешевое устройство, поэтому не относитесь к этому слишком критично. Более подробно весь этот процесс можно посмотреть на видео, приведенном в конце статьи.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
#include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); const int xpin = A1; const int ypin = A2; const int zpin = A3; byte p[8] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; float threshold = 6; float xval[100] = {0}; float yval[100] = {0}; float zval[100] = {0}; float xavg, yavg, zavg; int steps, flag = 0; void setup() { Serial.begin(9600); lcd.begin(); lcd.backlight(); lcd.clear(); calibrate(); } void loop() { for (int w = 0; w < 16; w++) { lcd.write(byte(0)); delay(500); } int acc = 0; float totvect[100] = {0}; float totave[100] = {0}; float xaccl[100] = {0}; float yaccl[100] = {0}; float zaccl[100] = {0}; for (int a = 0; a < 100; a++) { xaccl[a] = float(analogRead(xpin) - 345); delay(1); yaccl[a] = float(analogRead(ypin) - 346); delay(1); zaccl[a] = float(analogRead(zpin) - 416); delay(1); totvect[a] = sqrt(((xaccl[a] - xavg) * (xaccl[a] - xavg)) + ((yaccl[a] - yavg) * (yaccl[a] - yavg)) + ((zval[a] - zavg) * (zval[a] - zavg))); totave[a] = (totvect[a] + totvect[a - 1]) / 2 ; Serial.println("totave[a]"); Serial.println(totave[a]); delay(100); if (totave[a] > threshold && flag == 0) { steps = steps + 1; flag = 1; } else if (totave[a] > threshold && flag == 1) { // Don't Count } if (totave[a] < threshold && flag == 1) { flag = 0; } if (steps < 0) { steps = 0; } Serial.println('\n'); Serial.print("steps: "); Serial.println(steps); lcd.print("Steps: "); lcd.print(steps); delay(1000); lcd.clear(); } delay(1000); } void calibrate() { float sum = 0; float sum1 = 0; float sum2 = 0; for (int i = 0; i < 100; i++) { xval[i] = float(analogRead(xpin) - 345); sum = xval[i] + sum; } delay(100); xavg = sum / 100.0; Serial.println(xavg); for (int j = 0; j < 100; j++) { yval[j] = float(analogRead(ypin) - 346); sum1 = yval[j] + sum1; } yavg = sum1 / 100.0; Serial.println(yavg); delay(100); for (int q = 0; q < 100; q++) { zval[q] = float(analogRead(zpin) - 416); sum2 = zval[q] + sum2; } zavg = sum2 / 100.0; delay(100); Serial.println(zavg); } |