Исследование MEMS-датчиков: Акселерометры, гироскопы и магнетометры для проектов на Arduino
В этом уроке мы узнаем, как работают MEMS-акселерометр, гироскоп и магнетометр, и как использовать их с платой Arduino. Также с помощью среды Processing IDE мы создадим несколько практических приложений с использованием этих датчиков. Вы можете посмотреть следующее видео или прочитать письменный урок ниже. MEMS — это очень маленькие системы или устройства, состоящие из микрокомпонентов размером от 0.001 мм до 0.1 мм. Эти компоненты изготавливаются из кремния, полимеров, металлов и/или керамики, и они обычно комбинируются с ЦПУ (микроконтроллером) для завершения системы. Теперь мы кратко объясним, как работает каждый из этих микроэлектромеханических систем (MEMS) датчиков. Он измеряет ускорение, измеряя изменение емкости. Его микроструктура выглядит примерно так. У нее есть масса, прикрепленная к пружине, которая ограничена движением в одном направлении, и фиксированные внешние пластины. Когда в определенном направлении применяется ускорение, масса движется, и емкость между пластинами и массой меняется. Это изменение емкости измеряется, обрабатывается и соответствует определенному значению ускорения. Гироскоп измеряет угловую скорость, используя эффект Кориолиса. Когда масса движется в определенном направлении с определенной скоростью, и когда применяется внешняя угловая скорость (как показано зеленой стрелкой), возникает сила (как показано красно-синей стрелкой), которая вызывает перпендикулярное смещение массы. Как и в акселерометре, это смещение вызывает изменение емкости, которое измеряется, обрабатывается и соответствует определенной угловой скорости. Микроструктура гироскопа выглядит примерно так. Масса, которая постоянно движется или колеблется, и когда применяется внешняя угловая скорость, гибкая часть массы движется и создает перпендикулярное смещение. Он измеряет магнитное поле Земли, используя эффект Холла или магниторезистивный эффект. На самом деле почти 90% датчиков на рынке используют эффект Холла, и вот как это работает. Если у нас есть проводящая пластина, как показано на фото, и мы пропускаем через нее ток, электроны будут течь прямо от одной стороны пластины к другой. Теперь, если мы приблизим какое-то магнитное поле к пластине, мы нарушим прямое течение, и электроны отклонятся к одной стороне пластины, а положительные полюса — к другой. Это означает, что если мы сейчас подключим вольтметр между этими двумя сторонами, мы получим некоторое напряжение, которое зависит от силы магнитного поля и его направления. Другие 10% датчиков на рынке используют магниторезистивный эффект. Эти датчики используют материалы, чувствительные к магнитному полю, обычно состоящие из железа (Fe) и никеля (Ni). Поэтому, когда эти материалы подвергаются воздействию магнитного поля, они меняют свое сопротивление. Хорошо, теперь подключим эти датчики к плате Arduino и сделаем из них пользу. В качестве примера я буду использовать плату расширения GY-80, которая имеет следующие датчики: ADXL345 3-осевой акселерометр, L3G4200D 3-осевой гироскоп, MC5883L 3-осевой магнетометр, а также барометр и термометр, которые мы не будем использовать в этом уроке. Вы можете приобрести эти компоненты на любом из сайтов ниже: Эта плата использует протокол связи I2C, что означает, что мы можем использовать все датчики всего с двумя проводами. Чтобы обеспечить связь между Arduino и датчиками, нам нужно знать их уникальные адреса устройств и адреса их внутренних регистров для получения данных из них. Эти адреса можно найти в даташитах датчиков: Для получения более подробной информации о том, как работает связь I2C, вы можете проверить мой другой урок про протокол связи I2C. Теперь посмотрим коды для получения данных с датчиков. Мы начнем с акселерометра, и перед каждым кодом будет некоторое объяснение, а также дополнительное описание в комментариях кода. Сначала нам нужно подключить библиотеку Arduino Wire и определить адреса регистров датчика. В разделе setup нам нужно инициализировать библиотеку Wire и запустить последовательную коммуникацию, так как мы будем использовать монитор последовательного порта для отображения результатов. Также здесь нам нужно активировать датчик или включить измерение, отправив соответствующий байт в регистр Power_CTL, и вот как это сделать. Используя функцию Wire.beginTransmission(), мы выбираем, с каким датчиком мы будем общаться — в данном случае 3-осевым акселерометром. Затем, используя функцию Wire.write(), мы указываем, с каким внутренним регистром мы будем общаться. После этого мы отправим соответствующий байт для включения измерения. Используя функцию Wire.endTransmission(), мы завершим передачу, и это передаст данные в регистры. В разделе loop нам нужно прочитать данные для каждой оси. Мы начнем с оси X. Сначала мы выберем, с какими регистрами мы будем общаться — с двумя внутренними регистрами оси X в данном случае. Затем, используя функцию Wire.requestFrom(), мы запросим переданные данные или два байта из двух регистров. Функция Wire.available() вернет количество байтов, доступных для чтения, и если это число совпадает с нашими запрошенными байтами, в нашем случае 2 байта, используя функцию Wire.read() мы прочитаем байты из двух регистров оси X. Выходные данные из регистров представлены в дополнительном коде, где X0 — младший значащий байт, а X1 — старший значащий байт, поэтому нам нужно преобразовать эти байты в значения float от -1 до +1 в зависимости от направления оси X относительно ускорения Земли или гравитации. Мы повторим эту процедуру для двух других осей, и в конце выведем эти значения на монитор последовательного порта. Для получения данных с гироскопа у нас будет похожий код, как и предыдущий. Сначала мы должны определить адреса регистров и некоторые переменные для данных. В разделе setup мы должны разбудить датчик и перевести его в нормальный режим, используя CTRL_REG1, а также выбрать чувствительность датчика. Для этого примера я выберу режим чувствительности 2000 dps. В разделе loop, аналогично акселерометру, мы прочитаем данные для осей X, Y и Z. Затем сырые данные должны быть преобразованы в угловые значения. Из даташита датчика мы видим, что для режима чувствительности 2000 dps соответствует 70 mdps/цифра. Это означает, что нам нужно умножить сырые выходные данные на 0.07, чтобы получить угловую скорость в градусах в секунду. Затем, если умножить угловую скорость на время, мы получим значение угла. Поэтому нам нужно вычислить временной интервал каждого раздела loop, и мы можем сделать это, используя функцию millis() в начале и в конце раздела loop, и сохраним его значение в эту переменную "dt". Так для каждого выполненного цикла мы вычислим угол и добавим его к конечному значению угла. Мы сделаем то же самое для двух других осей, и в конце выведем результаты в монитор последовательного порта. Снова мы будем использовать технику, похожую на предыдущую. Сначала нам нужно определить адреса регистров, и в разделе setup перевести датчик в режим непрерывного измерения. В разделе loop мы получим сырые данные для каждой оси тем же методом, что и для предыдущих датчиков. Затем нам нужно преобразовать сырые данные в значение магнитного поля или в единицы Гаусса. Из даташита датчика мы видим, что режим чувствительности по умолчанию составляет 0.92 мГс/цифра. Это означает, что нам нужно умножить сырые данные на 0.00092, чтобы получить магнитное поле Земли в Гауссах. В конце мы выведем значения на монитор последовательного порта. Вот крутое приложение датчика — MEMS цифровой компас, сделанный с использованием Processing IDE. Вы можете найти больше деталей и исходный код этого примера по следующей ссылке:Что такое MEMS?
MEMS-акселерометр

MEMS-гироскоп


MEMS-магнетометр


Arduino и MEMS-датчики

Исходный код
Код Arduino для акселерометра
#include <Wire.h>
//--- Адреса регистров акселерометра
#define Power_Register 0x2D
#define X_Axis_Register_DATAX0 0x32 // Шестнадцатеричный адрес внутреннего регистра DATAX0.
#define X_Axis_Register_DATAX1 0x33 // Шестнадцатеричный адрес внутреннего регистра DATAX1.
#define Y_Axis_Register_DATAY0 0x34
#define Y_Axis_Register_DATAY1 0x35
#define Z_Axis_Register_DATAZ0 0x36
#define Z_Axis_Register_DATAZ1 0x37
int ADXAddress = 0x53; // Адрес устройства, в который также включен 8-й бит для выбора режима, в данном случае чтение.
int X0,X1,X_out; int Y0,Y1,Y_out; int Z1,Z0,Z_out;
float Xa,Ya,Za;
void setup() {
Wire.begin(); // Инициализация библиотеки Wire
Serial.begin(9600); delay(100);
Wire.beginTransmission(ADXAddress);
Wire.write(Power_Register); // Регистр Power_CTL
// Включение измерения
Wire.write(8); // Бит D3 высокий для включения измерения (0000 1000)
Wire.endTransmission();
}
void loop() {
// Ось X
Wire.beginTransmission(ADXAddress); // Начало передачи к датчику
// Запрос данных из конкретных регистров
Wire.write(X_Axis_Register_DATAX0); Wire.write(X_Axis_Register_DATAX1);
Wire.endTransmission(); // Завершает передачу и передает данные из двух регистров
Wire.requestFrom(ADXAddress,2); // Запрашивает переданные два байта из двух регистров
if(Wire.available()<=2) {
// X0 = Wire.read(); // Читает данные из регистра
X1 = Wire.read();
/* Преобразование сырых данных оси X в ускорение оси X - Выходные данные в дополнительном коде
* X0 как младший значащий байт
* X1 как старший значащий байт
*/
X1=X1<<8; X_out =X0+X1; Xa=X_out/256.0; // Xa = выходное значение от -1 до +1, гравитационное ускорение на оси X
}
// Ось Y
Wire.beginTransmission(ADXAddress);
Wire.write(Y_Axis_Register_DATAY0); Wire.write(Y_Axis_Register_DATAY1);
Wire.endTransmission(); Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2) {
Y0 = Wire.read(); Y1 = Wire.read();
Y1=Y1<<8; Y_out =Y0+Y1; Ya=Y_out/256.0;
}
// Ось Z
Wire.beginTransmission(ADXAddress);
Wire.write(Z_Axis_Register_DATAZ0); Wire.write(Z_Axis_Register_DATAZ1);
Wire.endTransmission(); Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2) {
Z0 = Wire.read(); Z1 = Wire.read();
Z1=Z1<<8; Z_out =Z0+Z1; Za=Z_out/256.0;
}
// Вывод данных на монитор последовательного порта
Serial.print("Xa= "); Serial.print(Xa);
Serial.print(" Ya= "); Serial.print(Ya);
Serial.print(" Za= "); Serial.println(Za);
}Язык кода: Arduino (arduino)Код Arduino для гироскопа
#include <Wire.h>
//--- Адреса регистров гироскопа
#define Gyro_gX0 0x28 #define Gyro_gX1 0x29
#define Gyro_gY0 0x2A #define Gyro_gY1 0x2B
#define Gyro_gZ0 0x2C #define Gyro_gZ1 0x2D
int Gyro = 0x69; // Адрес устройства с 8-м битом для выбора режима (чтение)
int gX0, gX1, gX_out; int gY0, gY1, gY_out; int gZ0, gZ1, gZ_out;
float Xg,Yg,Zg; float angleX,angleY,angleZ,angleXc,angleYc,angleZc;
unsigned long start, finished, elapsed; float dt=0.015;
void setup() {
Wire.begin(); Serial.begin(9600); delay(100);
Wire.beginTransmission(Gyro); Wire.write(0x20); // CTRL_REG1 - Режим питания
Wire.write(15); // Нормальный режим: 15d - 00001111b
Wire.endTransmission();
Wire.beginTransmission(Gyro); Wire.write(0x23); // CTRL_REG4 - Чувствительность, выбор шкалы
Wire.write(48); // 2000dps: 48d - 00110000b
Wire.endTransmission();
}
void loop() {
start=millis();
//---- Ось X
Wire.beginTransmission(Gyro); Wire.write(Gyro_gX0); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) { gX0 = Wire.read(); }
Wire.beginTransmission(Gyro); Wire.write(Gyro_gX1); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) { gX1 = Wire.read(); }
//---- Ось Y
Wire.beginTransmission(Gyro); Wire.write(Gyro_gY0); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) { gY0 = Wire.read(); }
Wire.beginTransmission(Gyro); Wire.write(Gyro_gY1); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) { gY1 = Wire.read(); }
//---- Ось Z
Wire.beginTransmission(Gyro); Wire.write(Gyro_gZ0); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) { gZ0 = Wire.read(); }
Wire.beginTransmission(Gyro); Wire.write(Gyro_gZ1); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) { gZ1 = Wire.read(); }
//---------- Ось X
gX1=gX1<<8; gX_out =gX0+gX1; // Сырые данные
Xg=gX_out*0.07; // Угловая скорость (из даташита: 70 mdps/цифра)
angleXc = Xg*dt; angleX = angleX + angleXc; // Угол
//---------- Ось Y
gY1=gY1<<8; gY_out =gY0+gY1; Yg=gY_out*0.07;
angleYc = Yg*dt; angleY = angleY + angleYc;
//---------- Ось Z
gZ1=gZ1<<8; gZ_out =gZ0+gZ1; Zg=gZ_out*0.07;
angleZc = Zg*dt; angleZ = angleZ + angleZc;
// Вывод данных на монитор последовательного порта
Serial.print("angleX= "); Serial.print(angleX);
Serial.print(" angleY= "); Serial.print(angleY);
Serial.print(" angleZ= "); Serial.println(angleZ);
delay(10);
// Вычисление dt
finished=millis(); elapsed=finished-start; dt=elapsed/1000.0; start = elapsed = 0;
}Язык кода: Arduino (arduino)Код Arduino для магнетометра
#include <Wire.h> // Библиотека I2C Arduino
#define Magnetometer_mX0 0x03 #define Magnetometer_mX1 0x04
#define Magnetometer_mZ0 0x05 #define Magnetometer_mZ1 0x06
#define Magnetometer_mY0 0x07 #define Magnetometer_mY1 0x08
int mX0, mX1, mX_out; int mY0, mY1, mY_out; int mZ0, mZ1, mZ_out;
float Xm,Ym,Zm;
#define Magnetometer 0x1E // I2C 7-битный адрес HMC5883
void setup(){
// Инициализация последовательной и I2C связи
Serial.begin(9600); Wire.begin(); delay(100);
Wire.beginTransmission(Magnetometer); Wire.write(0x02); // Выбор регистра режима
Wire.write(0x00); // Режим непрерывного измерения
Wire.endTransmission();
}
void loop(){
//---- Ось X
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mX1); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mX0 = Wire.read(); }
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mX0); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mX1 = Wire.read(); }
//---- Ось Y
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mY1); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mY0 = Wire.read(); }
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mY0); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mY1 = Wire.read(); }
//---- Ось Z
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mZ1); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mZ0 = Wire.read(); }
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mZ0); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mZ1 = Wire.read(); }
//---- Ось X
mX1=mX1<<8; mX_out =mX0+mX1; // Сырые данные
Xm = mX_out*0.00092; // Единицы Гаусса
//* Магнитное поле Земли варьируется от 0.25 до 0.65 Гаусса, так что эти значения нам нужно получить примерно.
//---- Ось Y
mY1=mY1<<8; mY_out =mY0+mY1; Ym = mY_out*0.00092;
//---- Ось Z
mZ1=mZ1<<8; mZ_out =mZ0+mZ1; Zm = mZ_out*0.00092;
// Вывод значений каждой оси
Serial.print("x: "); Serial.print(Xm);
Serial.print(" y: "); Serial.print(Ym);
Serial.print(" z: "); Serial.println(Zm);
delay(50);
}Язык кода: Arduino (arduino)
Производственный процесс
- Что такое магнитометр? Основы, принципы и реальные применения
- Использование данных в Интернете надежности: стратегии эффективного управления
- Создание игры в реальном времени на Arduino Nano с гироскопом MPU-6050 и OLED-дисплеем
- Интерактивный гироскопический LED-дисплей на NeoPixel Ring и Arduino
- Датчик CO2 K30: мониторинг качества воздуха в реальном времени на Arduino
- Устройство для общения глухосліпых людей с помощью 1Sheeld и Arduino
- Умная копилка: управление монетоприёмником на Arduino Nano
- Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
- Интеграция ёмкостного сканера отпечатков DFRobot с Arduino или ESP8266
- Интерактивный HMI-проект на Nextion с Arduino Mega и датчиками