- Gy-521 – модуль с гироскопом, акселерометром и термометром mpu-6050 для ардуино
- Mpu 9250 и arduino – схема подключения
- Акселерометр и гироскоп mpu6050
- Определение положения модуля в пространстве:
- Подключение imu 10dof l3g4200d adxl345 hmc5883l bmp085 – популярная робототехника
- Получение данных с акселерометра с увеличением его диапазона измерений:
- Получение данных с акселерометра:
- Получение данных с каждого датчика по отдельности в одном скетче:
- Получение кватернионов для программ визуализации:
- Самотестирование всех датчиков модуля:
- Функция read();
- Функция setbandwidths();
- Функция setscale();
Gy-521 – модуль с гироскопом, акселерометром и термометром mpu-6050 для ардуино
Датчики определения положения в пространстве широко используются в мобильных устройствах, а для самоделок чаще всего применяются в квадрокоптерах.
Также, его можно применить в светящемся шлеме! Удобно, не правда ли? Наклонил голову вправо — загорелось правое «полушарие» =) влево — левое, согнул голову в шее — сзади на шлеме высветился стоп-сигнал! Вот только, думаю, моей шеи хватит минут на 5 таких упражнений, потом — коллдаун, в виде боли на неделю обеспечен.
Итак, заказал — прислали, теперь нужно разобраться и продемонстрировать функционал для Вас, уважаемые читатели Муськи. Пришло с треком, не известно, почему, но в Киеве посылку держали неделю (или это глюки системы треккинга). Дошла чуть менее, чем за три недели. Упаковано в три слоя утеплителя — для амортизации.
Сам модуль — внутри запаянного пакетика со штрих-кодом на наклейке:Размеры платы: 20×16мм. В комплекте два набора штыревых контактов: ровные и загнутые — удобно, не придется гнуть или ровнять.
Большие отверстия не металлизированы, как на картинке в магазине, поэтому, если Вы будите их прикручивать болтами к «минусу», эффекта не будет. Я заливаю их термоклеем, а он, образуя «шапочки», надёжно фиксирует плату.Отвертия контактов металлизированы отлично, паяются без проблем.
Схема
Взята из статьи про такой же модуль — cxem.net/mc/mc324.php
MPU-6050 снабжен акселерометром, гироскопом и термометром. Зачем нужен термометр — не понятно, вероятно, его было удобно разместить в этой микросхеме.
Или, действительно, есть такие варианты применения, о которых я не знаю, где тебя вертят и греют нужно вертеться в пространстве и знать температуру =) Или, в процессе интенсивной работы с устройством, оно может нагреваться и нужно контролировать его температуру и нагрузку.
— 16-битный АЦП, — напряжение питания 3-5В, — поддержка протокола «IIC» (может, I2C ?), — диапазон ускорений: ± 2 ± 4 ± 8 ± 16g, — диапазон «гиро»: ± 250 500 1000 2000 ° / s, — покрытие иммерсионным золотом вместо лужения, — ток при работе последнего примера составил 5.3 мА и 1.
2 мА когда устройство не успело стартовать (питание на модуль было подано после выполнения setup() контроллером) Для интерфейса I2C у Ардуино имеются контакты A4 (SDA) и A5 (SCL), да-а, это те, которые расположены чёрти-где (на одной плате у меня они были справа от контроллера, на другой с левого края).
В коде нужно использовать библиотеку Wire, прочитать о ней можно туточки. Минимальная схема во Fritzing такая:… а значит у нас уже не 8 лишних штырьков, а целых двенадцать! Термометр тестировать проще всего: залил скетч отсюда, открыл монитор порта, выставил скорость на 9600, —
побежали такие строки
AcX = 1624 | AcY = -808 | AcZ = 15176 | Tmp = 25.14 | GyX = 11 | GyY = 314 | GyZ = -138 AcX = 1584 | AcY = -876 | AcZ = 15112 | Tmp = 25.00 | GyX = 0 | GyY = 193 | GyZ = -163 AcX = 1616 | AcY = -904 | AcZ = 15172 | Tmp = 25.05 | GyX = -2 | GyY = 264 | GyZ = -181 AcX = 1648 | AcY = -836 | AcZ = 14948 | Tmp = 25.
09 | GyX = 3 | GyY = 146 | GyZ = -192 AcX = 1792 | AcY = -800 | AcZ = 15216 | Tmp = 25.09 | GyX = 27 | GyY = -181 | GyZ = -218 AcX = 1864 | AcY = -900 | AcZ = 14932 | Tmp = 25.09 | GyX = 11 | GyY = 48 | GyZ = -206 AcX = 2144 | AcY = -796 | AcZ = 14860 | Tmp = 25.
05 | GyX = 8 | GyY = 100 | GyZ = -191 AcX = 2088 | AcY = -916 | AcZ = 14952 | Tmp = 25.14 | GyX = 11 | GyY = 158 | GyZ = -189 AcX = 2180 | AcY = -752 | AcZ = 14964 | Tmp = 25.14 | GyX = 6 | GyY = 334 | GyZ = -182 AcX = 2296 | AcY = -796 | AcZ = 15076 | Tmp = 25.
05 | GyX = -3 | GyY = 184 | GyZ = -189 AcX = 2160 | AcY = -788 | AcZ = 15176 | Tmp = 25.14 | GyX = -8 | GyY = 184 | GyZ = -172 AcX = 2036 | AcY = -852 | AcZ = 14988 | Tmp = 25.09 | GyX = 3 | GyY = 292 | GyZ = -172 AcX = 1984 | AcY = -836 | AcZ = 14892 | Tmp = 25.
09 | GyX = 38 | GyY = 90 | GyZ = -205 AcX = 2136 | AcY = -708 | AcZ = 14976 | Tmp = 25.19 | GyX = -5 | GyY = 270 | GyZ = -148 AcX = 2000 | AcY = -788 | AcZ = 14888 | Tmp = 25.14 | GyX = -35 | GyY = 239 | GyZ = -157 AcX = 2008 | AcY = -784 | AcZ = 15048 | Tmp = 25.
19 | GyX = -3 | GyY = 342 | GyZ = -183 AcX = 1884 | AcY = -868 | AcZ = 15140 | Tmp = 25.19 | GyX = -3 | GyY = 214 | GyZ = -194 AcX = 2072 | AcY = -820 | AcZ = 15020 | Tmp = 25.28 | GyX = 41 | GyY = 157 | GyZ = -205 AcX = 2008 | AcY = -780 | AcZ = 15144 | Tmp = 25.
24 | GyX = 0 | GyY = 220 | GyZ = -204 AcX = 1924 | AcY = -828 | AcZ = 14968 | Tmp = 25.24 | GyX = -9 | GyY = 254 | GyZ = -187 AcX = 1920 | AcY = -828 | AcZ = 14936 | Tmp = 25.33 | GyX = 7 | GyY = 253 | GyZ = -185 AcX = 2023 | AcY = -728 | AcZ = 14904 | Tmp = 25.
14 | GyX = 16 | GyY = 190 | GyZ = -167 AcX = 1900 | AcY = -744 | AcZ = 15048 | Tmp = 25.42 | GyX = -4 | GyY = 162 | GyZ = -177 AcX = 1940 | AcY = -780 | AcZ = 14992 | Tmp = 25.28 | GyX = -34 | GyY = 271 | GyZ = -191 AcX = 1960 | AcY = -900 | AcZ = 15080 | Tmp = 25.38 | GyX = 2 | GyY = 194 | GyZ = -182
AcX = 1840 | AcY = -952 | AcZ = 15012 | Tmp = 25.38 | GyX = 19 | GyY = 272 | GyZ = -167
Вследствие нагревания феном для волос, значение Tmp = взлетело до 80. Далее покрутили в пространстве платкой — другие показания тоже изменяются, но это не наглядно.
Данные, выводимые вторым скетчем
Mpu 9250 и arduino – схема подключения
MPU 9250 выполняет функции сразу нескольких датчиков: это и гироскоп, и акселерометр, и магнитометр – все три устройства в одном, что очень удобно.
Остановимся немного подробнее на каждом из них.
Гироскоп – это сенсор, реагирующий на изменение углов ориентации в пространстве. В тех же квадрокоптерах его используют, чтобы стабилизировать положение аппарата в воздухе и защитить его от ветра.
Например, во время рыбалки, мы закидываем удочки в водоем и на поверхности воды виден только поплавок.
Если погода достаточно ветреная, то поплавок постоянно будет уходить в разные стороны и наклоняться под случайным углом, что может помешать нам вовремя заметить клев рыбы. То же самое будет происходить и в воздухе.
Чтобы ваш квадрокоптер не находился постоянно в наклонном положении, его выравниванием и будет заниматься гироскоп.
В качестве иллюстрации, внизу вы можете наглядно посмотреть испытания DIY дрона вместе с установленным в его аппаратную часть гироскопом.
Акселерометр сравнивает проекцию ускорения объекта с гравитационным ускорением и способен замерять линейную скорость объекта, а вкупе с гироскопом – и положение в пространстве.
Магнитометр представляет собой устройство для измерения интенсивности ближайшего магнитного поля, действующего на объект (впрочем, название датчика говорит само за себя).
А еще, по некоторым данным, наш модуль MPU 9250 является самым миниатюрным в мире девятиосевым сенсором. Это говорит о высокой производительности микросхемы (по названию которой и назван наш “герой”), что было обеспечено применением технологии CMOS MEMS.
Состоит корпус модуля из двух мельчайших кристаллов, один из которых отвечает за гироскоп и акселерометр, а другой за магнитометр. Данные с них обрабатываются встроенным сигнальным процессором DMP с помощью алгоритмов Motion Fusion и передаются по интерфейсам I2C или SPI.
Помимо высокой производительности, модуль довольно популярен в среде ардуинщиков и тех, кто увлекается устройствами на дистанционном управлении, а также имеет низкие энергопотребление и стоимость.
Как уже было сказано ранее, подключать датчик к Arduino можно по шине I2C или SPI. Питать модуль можно от 5 В, так как на плате датчика имеется линейный стабилизатор для данного типа питания, но подавать питание можно и значением в 3,3 В.
Вы можете подключать модуль к вашему микроконтроллеру по четырем контактам через интерфейс I2C (5V, Gnd, SCL, SDA) или через SPI, используя 5 контактов на плате модуля (5V, Gnd, SCL, SDA, CS, SDO).
На картинке показано подключение через интерфейс I2C.
В качестве примеров для работы с модулем MPU 9250 можете воспользоваться предложенным ниже скетчем.
Данный код с использованием пары библиотек позволит считывать информацию (данные) со всех трех датчиков и выводить в порт. Здесь понадобится библиотека Wire 0. Она уже встроена в Arduino IDE , а, значит, ее отдельно скачивать устанавливать не нужно.
Акселерометр и гироскоп mpu6050
Прежде чем приступить к рассмотрению модуля гироскопа и акселерометра, думаю, будет не лишним коротко разобраться что это такое. Гироскоп представляет собой устройство, реагирующее на изменение углов ориентации контролируемого тела. В классическом представлении это какой-то инерционный предмет, который быстро вращается на подвесах.
Как результат вращающийся предмет всегда будет сохранять свое направление, а по положению подвесов можно определить угол отклонения. На самом же деле электронные гироскопы построены по другой схеме и устроены немного сложнее (вращающийся волчок впихнуть в микросхему было бы не просто).
Акселерометр – это устройство, которое измеряет проекцию кажущегося ускорения, то есть разницы между истинным ускорением объекта и гравитационным ускорением. На простом примере такая система представляет собой некоторую массу, закрепленную на подвесе, обладающим упругостью (пружина для хорошего примера).
Так вот если такую систему повернуть под каким-то углом, или бросить, или предать линейное ускорение, то упругий подвес отреагирует на движение под действием массы и отклонится и вот по этому отклонению определяется ускорение.
Таким образом, гироскоп реагирует на изменение в пространстве независимо от направление движения, с помощью акселерометра же может измерять линейные ускорения предмета, а так же и искусственно рассчитываемое расположение предмета в пространстве. Каждое устройство имеет свои достоинства и недостатки.
Микросхема MPU6050 содержит на борту как акселерометр, так и гироскоп, а помимо этого еще и температурный сенсор. MPU6050 является главным элементом модуля GY-531.
Помимо этой микросхемы на плате модуля расположена необходимая обвязка MPU6050, в том числе подтягивающие резисторы интерфейса I2C, а также стабилизатор напряжения на 3,3 вольта с малым падением напряжения (при питании уже в 3,3 вольта на выходе стабилизатора будет 3 ровно вольта) с фильтрующими конденсаторами.
Ну и бонусом на плате распаян SMD светодиод с ограничивающим резистором как индикатор питающего напряжения. Размер платы модуля GY-521 10 х 20 мм.
Схема модуля представлена ниже (номиналы могут немного отличаться в разных версиях модуля):
Характеристики MPU6050:
- напряжения питания 2,375 – 3,46 вольт
- потребляемый ток до 4 мА
- интерфейс передачи данных – I2C
- максимальная скорость I2C – 400 кГц
- вход для других датчиков I2C
- внутренний генератор на 8 МГц (вне модуля возможность подключить внешний кварцевый резонатор на 32,768 кГц или 19,2 МГц)
Нужно отметить возможность MPU6050 работать в мастер режиме I2C для AUX выводов, к которым можно подключить еще один внешний датчик (например магнитометр). Честно говоря, я не понимаю для чего это вообще нужно, если проще подключать дополнительные датчики к общей шине I2C микроконтроллера.
Функции MPU6050:
- трех осевой MEMS гироскоп с 16 битным АЦП
- трех осевой MEMS акселерометр с 16 битным АЦП
- Digital Motion Processor (DMP)
- slave I2C для подключения к микроконтроллеру
- master I2C для подключения к микросхеме дополнительного датчика
- регистры данных датчиков
- FIFO
- прерывания
- температурный сенсор
- самопроверка гироскопа и акселерометра
- регистр идентификации устройства
Внешний вид модуля GY-521:
В комплекте идут штыревые соединения угловые и прямые. Припаян был прямой штыревой разъем.
Данные измерений датчиков можно считывать как из регистров хранения, так и пользоваться функциями FIFO.
Имеется отдельный регистр под названием Who am I, значение, записанное в этом регистре постоянно и его можно только считать, можно использовать как идентификатор устройства, значение в регистре 104 или 0х68.
Отдельным выводом является выход прерываний, который настраивается регистрами настройки под определенные события.
Датчики гироскопа и акселерометра изготовлены как MEMS (микроэлектромеханическая система) – внешнее воздействие на датчик сначала изменяет состояние механической части, затем изменение состояния механической части приводит к изменению сигнала электрической части.
Одним словом в одном корпусе собрана не только электроника, но и механика. В микросхеме MPU6050 содержится сразу два MEMS датчика, производитель утверждает, что их взаимное воздействие друг на друга сведено к минимуму. Ну что же, совсем не плохо за цену готового модуля порядка 2 уе.
Между прочим эти модули можно приобрести на торговых площадках aliexpress или ebay.
Разберемся как можно использовать датчики акселерометра и гироскопа. Температурный датчик трогать даже не будем – данные о температуре прочитали, перевели в человеческие значения и наслаждаемся. Гироскоп выдает значения мгновенной угловой скорости с разрешением, заданным в настройках, например 2000 градусов в секунду.
Если прошить микроконтроллер и смотреть на получаемые данные, то увидим только нули. Если начать крутить датчик, то получим мгновенные значения угловой скорости. Заметьте, что скорость мы получаем в градусах в секунду, а это значит, что линейные скорости не влияют на эти показания – показания будут изменяться только при повороте датчика в пространстве.
Далее с помощью этих данных можно получить ориентацию объекта в пространстве. Для этого нужно получить мгновенное значение угловой скорости и умножить его на промежуток времени между опросами датчика гироскопа.
Пример разрешение 2000 градусов в секунду, промежуток между опросами датчика 0,1 секунда, значение мгновенной скорости 300, значит 300*0,1=30 – за это время ось гироскопа была повернута на 30 градусов. Далее каждое полученное значение нужно сложить с предыдущим.
Если ось двигалась в одном направлении – значение 30 градусов, если в другом, то -30, таким образом, при возвращении датчика в исходное положение всегда (в идеале) будет 0, при отклонении от исходного положения, при выполнении вышеописанных действий, получим угол отклонения. Обрабатывая углы трех осей гироскопа можно получить ориентацию объекта в пространстве.
Таким образом, при интегрировании состояния угла положения, также интегрируется и погрешность – при длительном использовании можно получить уже абсолютно неправильные значения. Поэтому часто гироскоп используют в паре с акселерометром, образуя в простом варианте альфа-бета фильтр или комплементарный фильтр.
С акселерометром все проще. Измеряя ускорения трех осей датчика можно получить данные, преобразуя их с помощью геометрии, по которым можно также получить ориентацию объекта в пространстве.
Помимо этого акселерометр измеряет линейные ускорения, то есть ориентация объекта может искажаться при движении датчика в линейных направлениях. Также с помощью акселерометра можно определять движение объекта или его столкновение.
Например детектировать падение объекта или толчок о преграду, чтобы обходить это.
Данные от акселерометра получаем всегда достаточно точные, то есть нуль всегда остается нулем ни при каких воздействиях (имеется ввиду не зависит ни от времени, ни от характера воздействия), однако недостаток кроется в том, что данные идут шумом в некотором диапазоне данных, то есть до десятых долей градуса точно измерять угол не получится.
Если датчик приобрели, можно переходить к рассмотрению внутренностей модуля, а именно главного элемента – микросхемы MPU6050. Информация хранится в регистрах микросхемы, которых более 100 (!). И вот тут то и кроется огромный подводный камень.
производитель не утрудился расписать в документации всю информацию, а привел лишь информацию о самом необходимом. На самом деле не известно даже сколько же всего там регистров, доступных для чтения или записи или того и другого. Также информации на некоторые регистры попросту нет, кроме его названия.
Ну что же, придется экспериментально определять влияния значений, записанных в некоторые регистры.
Определение положения модуля в пространстве:
/* ОПРЕДЕЛЕНИЕ ПОЛОЖЕНИЯ МОДУЛЯ */ // // #include <iarduino_Position_BMX055.h> // Подключаем библиотеку iarduino_Position_BMX055 для работы с Trema-модулем IMU 9 DOF. iarduino_Position_BMX055 sensor(BMX); // Создаём объект sensor указывая что требуется работать со всеми датчиками модуля. // Если указать параметр BMA - то объект будет работать только с акселерометром. // Если указать параметр BMG - то объект будет работать только с гироскопом. // Если указать параметр BMM - то объект будет работать только с магнитометром. // Если указать параметр BMX - то объект будет работать со всеми датчиками сразу. void setup(){ // Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта на скорости 9600 бит/сек. while(!Serial){} // Ждём готовность Serial к передаче данных в монитор последовательного порта. sensor.begin(); // Инициируем работу с датчиками объекта sensor. } // void loop(){ // sensor.read(); // Функция read() читает данные того датчика, для которого был создан объект. // Для объекта работающего со всеми датчиками сразу, функция read() может принять // один из трёх параметров: BMX_DEG, BMX_RAD, или BMX_M_S. Если параметра нет, то используется параметр по умолчанию. // sensor.read(BMX_DEG); - читать углы Эйлера в градусах (по умолчанию). // sensor.read(BMX_RAD); - читать углы Эйлера в радианах. // sensor.read(BMX_M_S); - читать истинное ускорение в м/с². // Данные прочитанные функцией read() сохраняются в переменных axisX, axisY, axisZ и temp. Serial.print("КУРС="); Serial.print(sensor.axisZ); Serial.print(", "); Serial.print("ТАНГАЖ="); Serial.print(sensor.axisX); Serial.print(", "); Serial.print("КРЕН="); Serial.print(sensor.axisY); Serial.print("rn"); }
Подключение imu 10dof l3g4200d adxl345 hmc5883l bmp085 – популярная робототехника
Список этих параметров включает:
- проекция ускорения на три оси x,y,z (акселерометр ADXL345);
- скорость вращения вокруг трех осей x,y,z (гироскоп L3G4200D);
- проекции магнитного поля на три оси x,y,z (компас HMC5883L);
- атмосферное давление (барометр BMP085).
Здесь следует пояснить, что показания барометра можно легко преобразовать в высоту над уровнем моря, что также является одной из пространственных координат. Также, чип барометра имеет встроенный термодатчик, показания которого также могут быть сняты микроконтроллером.
Все расположенные на плате датчики соединены I2C шиной. Благодаря этому, устройство достаточно легко подключается ко всем распространенным платформам, включая Arduino, mbed и TI LaunchPad. Кроме того, такой вариант подключения высвобождает аналоговые входы микроконтроллера, количество которых ограничено.
Плата IMU имеет 11 выводов:
- M_DRDY – сигнал готовности измерений компаса HMC5883L;
- G_INT1,2 – программируемые прерывания гироскопа L3G4200D;
- A_INT1,2 – программируемые прерывания акселерометра ADXL345;
- P_EOC – завершение измерения температуры или давления в BMP085;
- P_XCLR – сброс всех регистров BMP085;
- SCL, SDA – I2C шина;
- VCC – питание 5В, 3.3В;
- GND – земля.
Для работы устройства требуется подключить только цепь питания и каналы шины I2C. Как обычно, эксперимент по оживлению устройства происходил при помощи mbed. Схема подключения изображена ниже.
Как видно на схеме, I2C линии “подтянуты” к напряжению питания сопротивлением 2.2КОм (рекомендуется 2.2 – 10КОм). Есть подозрение, что на плате IMU уже стоят соответствующие резисторы, обязательно проверю это предположение в следующий раз.
Что касается питания, то я подключил IMU к 3.3В, хотя согласно даташиту можно использовать и 5В.
Ввиду того, что указанный IMU содержит достаточно распространенные модели датчиков, найти соответствующие библиотеки для mbed не составило труда. Уверен, что для Arduino ситуация окажется аналогичной.
Единственные проблемы возникли при подключении гироскопа. Здесь следует помнить, что адреса I2C устройств на mbed сдвинуты на один бит влево относительно аналогичных адресов для Arduino.
Например, если Arduino использует для общения с гироскопом L3G4200D адреса 0x68 или 0x69, то при работе с mbed следует использовать 0xD1 или 0xD2, соответственно.
В коде библиотеки для данного гироскопа был установлен адрес 0xD2, и попробовать 0xD1 я догадался только после сканирования всей шины.
Код программы достаточно примитивен и почти полностью заимствован у одного из резидентов портала mbed.org.
#include “mbed.h”
#include “HMC5883L.h”
#include “ADXL345.h”
#include “L3G4200D.h”
#include “BMP085.h”
DigitalOut myled(LED1);
HMC5883L cmp(p9, p10); // sda, scl
ADXL345 acc(p9, p10); // sda, scl
L3G4200D gyr(p9, p10); // sda, scl
BMP085 alt(p9, p10); // sda, scl
Serial pc(USBTX, USBRX); // tx, rx
int main() {
pc.baud(19200);
int16_t data[3];
cmp.init();
wait(0.1);
// These are here to test whether any of the initialization fails. It will print the failure
if (acc.setPowerControl(0x00)){
pc.printf(“acc: didn’t intitialize power control“);
return 0; }
wait(.001);
//Resolution setup, /-2g.
if(acc.setDataFormatControl( ADXL345_FULL_RES || ADXL345_2G )){
pc.printf(“didn’t set data format“);
return 0; }
wait(.001);
//3.2kHz data rate.
if(acc.setDataRate( ADXL345_3200HZ )){
pc.printf(“didn’t set data rate“);
return 0; }
wait(.001);
//Measurement mode.
if(acc.setPowerControl( MeasurementMode )){
pc.printf(“didn’t set the power control to measurement“);
return 0; }
alt.init();
while (1) {
cmp.getXYZ(data);
pc.printf(“C % 4i % 4i % 4i “,data[0],data[1],data[2]);
wait(0.1);
acc.getXYZ(data);
pc.printf(” A % 5i % 5i % 5i”,data[0],data[1],data[2]);
wait(0.1);
gyr.getXYZ(data);
pc.printf(” G % 5i % 5i % 5i”,data[0],data[1],data[2]);
wait(0.05);
pc.printf(” T %d”, alt.get_temperature());
pc.printf(” P %d”, alt.get_pressure());
pc.printf(” A %.2f“, alt.get_altitude_m());
myled = !myled;
Ниже представлен скриношот выходных данных тестируемого IMU в приложении TeraTerm. Как можно заметить, в моей квартире температура воздуха составляет почти 28 градусов Цельсия. У меня нет другого градусника, но учитывая постоянное нытье гостей, я склонен верить этим показаниям.
Атмосферное давление – около 98 260 Паскалей, что соответствует 737 мм ртутного столба. Согласно данным об атмосферном давлении по городу, полученная величина примерно соответствует действительности.
Теперь что касается высоты над уровнем моря, которая рассчитывается исходя из показаний термометра и барометра по известным формулам (формулы есть в гугле и в даташите датчика).
Официально, город Екатеринбург расположен в 240 метрах над уровнем моря.
Учитывая холмистый рельеф города и тот факт, что измерения проводились на 16-м этаже, полученная величина в 258 метров выглядит вполне правдоподобно.
Я вполне доволен этим, относительно дешевым китайским IMU ($21 на ebay). Справедливости ради следует отметить, что китайского в нем только сама плата и обвязка.
Сами же датчики являются продуктом весьма солидных компаний, таких как Bosch, Pololu, Analog Devices и Honeywell.
Плата изготовлена качественно, все чипы расположены строго параллельно друг другу, что очень важно в подобных составных устройствах, которые используются для точного позиционирования в пространстве.
В ближайшем будущем, именно этот IMU заменит аналоговые гироскоп и акселерометр, которые сейчас установлены на моем квадрокоптере.
Получение данных с акселерометра с увеличением его диапазона измерений:
По умолчанию акселерометр измеряет данные углового ускорения в диапазоне ±2g, где g – ускорение свободного падения = 9.81 м/с². Если модуль работает с большими ускорениями, то диапазон измерений акселерометра можно расширить вызвав функцию setScale() с указанием требуемого диапазона:
BMA_2G = ±2g (по умолчанию), BMA_4G = ±4g, BMA_8G = ±8g, BMA_16G = ±16g.
/* ЧТЕНИЕ ДАННЫХ АКСЕЛЕРОМЕТРА */ // Акселерометр будет работать в диапазоне ±39.24 м/с². // #include <iarduino_Position_BMX055.h> // Подключаем библиотеку iarduino_Position_BMX055 для работы с Trema-модулем IMU 9 DOF. iarduino_Position_BMX055 sensor(BMA); // Создаём объект sensor указывая что ему требуется работать только с акселерометром. // void setup(){ // Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта на скорости 9600 бит/сек. while(!Serial){} // Ждём готовность Serial к передаче данных в монитор последовательного порта. sensor.begin(); // Инициируем работу с акселерометром, так как именно для работы с ним создан объект sensor sensor.setScale(BMA_4G); // Указываем акселерометру производить измерения в новом диапазоне ±4g, где g=9.81 м/с². sensor.setFastOffset(); // Выполняем калибровку акселерометра (быструю компенсацию смещения данных) после установки нового диапазона. } // Акселерометр способен работать в диапазонах: BMA_2G, BMA_4G, BMA_8G, BMA_16G. void loop(){ // sensor.read(); // Читаем данные акселерометра в единицах по умолчанию (м/с²). Serial.print("X="); Serial.print(sensor.axisX); Serial.print(", "); Serial.print("Y="); Serial.print(sensor.axisY); Serial.print(", "); Serial.print("Z="); Serial.print(sensor.axisZ); Serial.print(" м/с²)rn"); }
Код данного скетча отличается от предыдущего только тем, что в конце кода setup вызываются функции setScale() и setFastOffset(), устанавливающие новый диапазон измерений и калибровку. Чем шире установленный диапазон измерений, тем меньше точность показаний.
Получение данных с акселерометра:
/* ЧТЕНИЕ ДАННЫХ АКСЕЛЕРОМЕТРА */ // // #include <iarduino_Position_BMX055.h> // Подключаем библиотеку iarduino_Position_BMX055 для работы с Trema-модулем IMU 9 DOF. iarduino_Position_BMX055 sensor(BMA); // Создаём объект sensor указывая что ему требуется работать только с акселерометром. // Если указать параметр BMA - то объект будет работать только с акселерометром. // Если указать параметр BMG - то объект будет работать только с гироскопом. // Если указать параметр BMM - то объект будет работать только с магнитометром. // Если указать параметр BMX - то объект будет работать со всеми датчиками сразу. // void setup(){ // Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта на скорости 9600 бит/сек. while(!Serial){} // Ждём готовность Serial к передаче данных в монитор последовательного порта. sensor.begin(); // Инициируем работу с акселерометром, так как именно для работы с ним создан объект sensor } // void loop(){ // sensor.read(); // Функция read() читает данные того датчика, для которого был создан объект. // Для объекта работающего с акселерометром, функция read() может принять // один из четырёх параметров: BMA_M_S, BMA_G, BMA_DEG, или BMA_RAD. // Если параметра нет, то используется параметр по умолчанию // sensor.read(BMA_M_S); читать угловое ускорение в м/с² (по умолчанию). // sensor.read(BMA_G); читать угловое ускорение в g. // sensor.read(BMA_DEG); читать углы «крен» и «тангаж» в градусах. // sensor.read(BMA_RAD); читать углы «крен» и «тангаж» в радианах. // Данные прочитанные функцией read() сохраняются в переменных axisX, axisY, axisZ и temp. Serial.print("X="); Serial.print(sensor.axisX); Serial.print(", "); Serial.print("Y="); Serial.print(sensor.axisY); Serial.print(", "); Serial.print("Z="); Serial.print(sensor.axisZ); Serial.print(" м/с² rn"); }
Этот скетч выводит только данные углового ускорения по осям XYZ в монитор последовательного порта. Данный скетч идентичен предыдущему, за исключением того, что в нём исключены все строки в которых присутствовали объекты sensorG и sensorM (объявленные для работы с гироскопом и магнитометром). Аналогичным образом можно вывести показания только гироскопа, или только магнитометра.
Получение данных с каждого датчика по отдельности в одном скетче:
/* ОТДЕЛЬНОЕ ЧТЕНИЕ ВСЕХ ДАТЧИКОВ */ // // #include <iarduino_Position_BMX055.h> // Подключаем библиотеку iarduino_Position_BMX055 для работы с Trema-модулем IMU 9 DOF. iarduino_Position_BMX055 sensorA(BMA); // Создаём объект sensorA указывая что ему требуется работать только с акселерометром. iarduino_Position_BMX055 sensorG(BMG); // Создаём объект sensorG указывая что ему требуется работать только с гироскопом. iarduino_Position_BMX055 sensorM(BMM); // Создаём объект sensorM указывая что ему требуется работать только с магнитометром. // Имена создаваемых объектов должны отличаться! void setup(){ // Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта на скорости 9600 бит/сек. while(!Serial){} // Ждём готовность Serial к передаче данных в монитор последовательного порта. sensorA.begin(); // Инициируем работу с датчиком объекта sensorA - это акселерометр. sensorG.begin(); // Инициируем работу с датчиком объекта sensorG - это гироскоп. sensorM.begin(); // Инициируем работу с датчиком объекта sensorM - это магнитометр. } // void loop(){ // // Функция read() читает данные того датчика, для которого был создан объект. // Так как мы создали 3 разных объекта для работы с разными датчиками, то // данные читаемые функцией read() будут зависеть от объекта для которого она вызвана. // Функцию read() можно вызвать с параметром, выбрав единицы измерений выводимых данных. // Если функция read вызывается без параметра, то данные выводятся в единицах по умолчанию. sensorA.read(); // sensorA.read(BMA_M_S); читать угловое ускорение в м/с² (по умолчанию). // sensorA.read(BMA_G); читать угловое ускорение в g. // sensorA.read(BMA_DEG); читать углы «крен» и «тангаж» в градусах. // sensorA.read(BMA_RAD); читать углы «крен» и «тангаж» в радианах. sensorG.read(); // sensorG.read(BMG_DEG_S); читать угловую скорость в °/c. (по умолчанию). // sensorG.read(BMG_RAD_S); читать угловую скорость в рад/c. sensorM.read(); // sensorM.read(BMM_MG); читать индукцию магнитного поля в мГс. (по умолчанию). // sensorM.read(BMM_MCT); читать индукцию магнитного поля в мкТл. // Данные прочитанные функцией read() сохраняются в переменных axisX, axisY, axisZ и temp. // Значение этих переменных у каждого объекта своё. Serial.print("АКСЕЛЕРОМЕТР("); Serial.print("X="); Serial.print(sensorA.axisX); Serial.print(", "); Serial.print("Y="); Serial.print(sensorA.axisY); Serial.print(", "); Serial.print("Z="); Serial.print(sensorA.axisZ); Serial.print(" м/с²) "); Serial.print("ГИРОСКОП("); Serial.print("X="); Serial.print(sensorG.axisX); Serial.print(", "); Serial.print("Y="); Serial.print(sensorG.axisY); Serial.print(", "); Serial.print("Z="); Serial.print(sensorG.axisZ); Serial.print(" °/c) "); Serial.print("МАГНИТОМЕТР("); Serial.print("X="); Serial.print(sensorM.axisX); Serial.print(", "); Serial.print("Y="); Serial.print(sensorM.axisY); Serial.print(", "); Serial.print("Z="); Serial.print(sensorM.axisZ); Serial.print(" мГс)rn"); }
В этом скетче мы создали 3 объекта (sensorA, sensorG и sensorM), указав каждому объекту работать со своим датчиком. Далее для каждого объекта была вызвана функция read(), которая сохранила данные в переменных (axisX, axisY, axisZ и temp) для своего объекта.
Получение кватернионов для программ визуализации:
/* ЧТЕНИЕ КВАТЕРНИОНОВ */ // // #define BMX055_DISABLE_BMM // Не использовать магнитометр. Курс будет ориентирован на начальное положение модуля #include <iarduino_Position_BMX055.h> // Подключаем библиотеку iarduino_Position_BMX055 для работы с Trema-модулем IMU 9 DOF. iarduino_Position_BMX055 sensor(BMX); // Создаём объект sensor указывая что требуется работать со всеми датчиками модуля. // Если указать параметр BMA - то объект будет работать только с акселерометром. // Если указать параметр BMG - то объект будет работать только с гироскопом. // Если указать параметр BMM - то объект будет работать только с магнитометром. // Если указать параметр BMX - то объект будет работать со всеми датчиками сразу. void setup(){ // Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта на скорости 9600 бит/сек. while(!Serial){} // Ждём готовность Serial к передаче данных в монитор последовательного порта. sensor.begin(); // Инициируем работу с датчиками объекта sensor. } // void loop(){ // sensor.read(); // Функция read() читает данные того датчика, для которого был создан объект. // В данном скетче параметр функции read() не имеет ни какого значения, так как // он влияет только на единицы измерений данных в переменных axisX, axisY, axisZ. Serial.print(sensor.q1); // Выводим кватернион q1. Serial.print(","); // разделяем запятой. Serial.print(sensor.q2); // Выводим кватернион q2. Serial.print(","); // разделяем запятой. Serial.print(sensor.q3); // Выводим кватернион q3. Serial.print(","); // разделяем запятой. Serial.println(sensor.q4); // Выводим кватернион q4 и завершаем строку. } //
Данный скетч использовался в видеообзоре.
Все скетчи представленных примеров имеются в папке examples библиотеки iarduino_Position_BMX055.
Самотестирование всех датчиков модуля:
/* САМОТЕСТИРОВАНИЕ ДАТЧИКОВ МОДУЛЯ */ // // #include <iarduino_Position_BMX055.h> // Подключаем библиотеку iarduino_Position_BMX055 для работы с Trema-модулем IMU 9 DOF. iarduino_Position_BMX055 sensor(BMX); // Создаём объект sensor указывая параметр BMX - требуется работать со всеми датчиками модуля. // Если указать параметр BMA - то объект будет работать только с акселерометром. // Если указать параметр BMG - то объект будет работать только с гироскопом. // Если указать параметр BMM - то объект будет работать только с магнитометром. // Если указать параметр BMX - то объект будет работать со всеми датчиками сразу. void setup(){ // Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта на скорости 9600 бит/сек. while(!Serial){} // Ждём готовность Serial к передаче данных в монитор последовательного порта. Serial.println("Тест модуля ...");// Выводим надпись в монитор последовательного порта. sensor.begin(); // Инициируем работу с датчиками объекта sensor. switch(sensor.test()){ // Получаем результат самотестирования для его сравнения с указанными ниже константами. case 0: Serial.println("Аппаратное самотестирование всех датчиков успешно пройдено!"); break; case BMA_ERR_ID: Serial.println("Акселерометр не найден."); break; case BMG_ERR_ID: Serial.println("Гироскоп не найден."); break; case BMM_ERR_ID: Serial.println("Магнитометр не найден."); break; case BMA_ERR_ST: Serial.println("Акселерометр не прошел самотестирование."); break; case BMG_ERR_ST: Serial.println("Гироскоп не прошел самотестирование."); break; case BMM_ERR_ST: Serial.println("Магнитометр не прошел самотестирование."); break; default: Serial.println("Модуль не прошел самотестирование по неизвестной причине."); break; } // } // void loop(){} //
Во время самотестирования модуль должен находиться в неподвижном состоянии. Если все датчики модуля работают и их показания не выходят за допустимые пределы, то в мониторе последовательного порта появится надпись «Аппаратное самотестирование всех датчиков успешно пройдено!».
Функция read();
- Назначение: Выполнение чтения показаний датчика (датчиков) модуля.
- Синтаксис: read( [ЕДИНИЦЫ_ИЗМЕРЕНИЯ] );
- Параметр: зависит от того, с каким датчиком работает объект.
- Если объект работает с акселерометром:
- BMA_M_S – выводить угловое ускорение в м/с² (по умолчанию).
- BMA_G – выводить угловое ускорение в количестве ускорений свободного падения (g).
- BMA_DEG – выводить углы «крен» и «тангаж» в градусах (для неподвижного или равноускоренного датчика).
- BMA_RAD – выводить углы «крен» и «тангаж» в радианах (для неподвижного или равноускоренного датчика).
- Если объект работает с гироскопом:
- BMG_DEG_S – выводить угловую скорость в °/c (по умолчанию).
- BMG_RAD_S – выводить угловую скорость в рад/c.
- Если объект работает с магнитометром:
- BMM_MG – выводить индукцию магнитного поля в мГс (по умолчанию).
- BMM_MCT выводить индукцию магнитного поля в мкТл.
- Если объект работает со всеми датчиками:
- BMX_DEG выводить положение модуля в пространстве в градусах (по умолчанию).
- BMX_RAD выводить положение модуля в пространстве в радианах.
- BMX_M_S выводить истинное ускорение модуля в м/с².
- Если объект работает с акселерометром:
- Возвращаемые значения: bool – успех чтения данных (true или false).
- Примечание:
- Функция возвращает результат успешности чтения, а прочитанные данные сохраняются в переменные: axisX, axisY, axisZ и temp.
- Параметры функции и читаемые ей данные зависят от того, с каким датчиком работает объект.
- Если вызвать функцию без параметра, то будет произведено чтение данных указанных для датчика по умолчанию.
- В разделе «Примеры» настоящей статьи, описан более подробный вариант использования функции.
- Пример:
iarduino_Position_BMX055 sensorA(BMA); // Создаём объект sensorA указывая что ему требуется работать только с акселерометром iarduino_Position_BMX055 sensorG(BMG); // Создаём объект sensorG указывая что ему требуется работать только с гироскопом iarduino_Position_BMX055 sensorM(BMM); // Создаём объект sensorM указывая что ему требуется работать только с магнитометром ... // void loop(){ // sensorA.read(BMA_M_S); // читаем угловое ускорение в м/с² из акселерометра, данные сохранятся в переменных axisX, axisY, axisZ и temp объекта sensorA sensorG.read(BMG_RAD_S); // читаем угловую скорость в рад/c из гироскопа, данные сохранятся в переменных axisX, axisY, axisZ и temp объекта sensorG sensorM.read(BMM_MCT); // читаем индукцию магнитного поля в мкТл из магнитометра, данные сохранятся в переменных axisX, axisY, axisZ и temp объекта sensorM } //
Функция setbandwidths();
- Назначение: Установка полосы пропускания для фильтрованных данных. Полоса пропускания влияет на то с какой скоростью датчик будет сохранять новые показания в свои регистры данных.
- Синтаксис: setBandwidths( ЧАСТОТА );
- Параметр: зависит от того, с каким датчиком работает объект.
- Если объект работает с акселерометром:
- BMA_8Hz – данные обновляются с частотой 7.81 Гц.
- BMA_16Hz – данные обновляются с частотой 15.63 Гц (по умолчанию).
- BMA_31Hz – данные обновляются с частотой 31.25 Гц.
- BMA_63Hz – данные обновляются с частотой 62.5 Гц.
- BMA_125Hz – данные обновляются с частотой 125 Гц.
- BMA_250Hz – данные обновляются с частотой 250 Гц.
- BMA_500Hz – данные обновляются с частотой 500 Гц.
- BMA_1000Hz – данные обновляются с частотой 1000 Гц.
- Если объект работает с гироскопом:
- Тут частота полосы пропускания отличается от частоты обновления данных.
- BMG_12Hz – данные обновляются с частотой 100 Гц.
- BMG_23Hz – данные обновляются с частотой 200 Гц (по умолчанию).
- BMG_32Hz – данные обновляются с частотой 100 Гц.
- BMG_47Hz – данные обновляются с частотой 400 Гц.
- BMG_64Hz – данные обновляются с частотой 200 Гц.
- BMG_116Hz – данные обновляются с частотой 1000 Гц.
- BMG_230Hz – данные обновляются с частотой 2000 Гц.
- BMG_523Hz – данные обновляются с частотой 2000 Гц.
- Если объект работает с магнитометром:
- BMM_2Hz – данные обновляются с частотой 2 Гц.
- BMM_6Hz – данные обновляются с частотой 6 Гц.
- BMM_8Hz – данные обновляются с частотой 8 Гц.
- BMM_10Hz – данные обновляются с частотой 10 Гц (по умолчанию).
- BMM_15Hz – данные обновляются с частотой 15 Гц.
- BMM_20Hz – данные обновляются с частотой 20 Гц.
- BMM_25Hz – данные обновляются с частотой 25 Гц.
- BMM_30Hz – данные обновляются с частотой 30 Гц.
- Если объект работает с акселерометром:
- Возвращаемые значения: нет.
- Примечание:
- Полоса пропускания фильтрованных данных определяет с какой скоростью датчик обновляет свои регистры данных новыми показаниями.
- Чем выше частота обновления данных, тем чаще можно читать новые данные с датчика.
- Параметры функции зависят от того, с каким датчиком работает объект.
- Функция не поддерживается объектом, который объявлен для работы со всеми датчиками.
- Если функцией read() читаются старые данные датчика (которые уже были прочитаны ранее), то функция read() вернёт false и значение переменных axisX, axisY, axisZ, и temp останется неизменным.
- Пример:
// если объект sensor объявлен с параметром BMM - для работы с магнитометром sensor.setBandwidths(BMM_30Hz); // установить полосу пропускания магнитометра в 30 Гц. // теперь новые данные магнитометра можно получать до 30 раз в секунду.
Функция setscale();
- Назначение: Установка диапазона измерений датчика (датчиков) модуля.
- Синтаксис: setScale( ДИАПАЗОН );
- Параметр: зависит от того, с каким датчиком работает объект.
- Если объект работает с акселерометром:
- BMA_2G – производить измерения в диапазоне ±2 g (по умолчанию).
- BMA_4G – производить измерения в диапазоне ±4 g.
- BMA_8G – производить измерения в диапазоне ±8 g.
- BMA_16G – производить измерения в диапазоне ±16 g.
где g – ускорение свободного падения = 9.81 м/с².
- Если объект работает с гироскопом:
- BMG_125DPS – производить измерения в диапазоне ±125 °/с (по умолчанию).
- BMG_250DPS – производить измерения в диапазоне ±250 °/с.
- BMG_500DPS – производить измерения в диапазоне ±500 °/с.
- BMG_1000DPS – производить измерения в диапазоне ±1000 °/с.
- BMG_2000DPS – производить измерения в диапазоне ±2000 °/с.
- Если объект работает с магнитометром:
- BMM_LOW_PWR – экономичный режим.
- BMM_REGULAR – обычный режим (по умолчанию).
- BMM_ENHANCED – улучшенный режим.
- BMM_HIGH – режим высокой точности.
- Если объект работает с акселерометром:
- Возвращаемые значения: нет.
- Примечание:
- После смены диапазонов измерений акселерометра или гироскопа, нужно выполнить их калибровку вызвав функцию setFastOffset().
- Увеличение диапазона измерений может понадобиться если модуль перемещается на больших скоростях. Чем шире диапазон измерений, тем меньше точность показаний датчиков.
- У магнитометра фиксированный диапазон измерений для каждой оси, по этому данная функция устанавливает один из рекомендуемых (предустановленных) режимов его работы. Чем точнее режим работы, тем точнее показания магнитометра.
- Параметры функции зависят от того, с каким датчиком работает объект.
- Функция не поддерживается объектом, который объявлен для работы со всеми датчиками.
- Пример:
// если объект sensor объявлен с параметром BMA - для работы с акселерометром sensor.setScale(BMA_16G); // производить дальнейшие измерения акселерометра в диапазоне ±16 g. sensor.setFastOffset(); // выполнить калибровку акселерометра после смены его диапазона измерений. // теперь чтение данных акселерометра будет производиться в новом диапазоне.