====== IMU-сенсор 10 DOF v1 для Raspberry Pi Pico: инструкция, примеры использования и документация ======
Используйте [[amp>product/waveshare-raspberry-pi-pico-imu-sensor-10dof?utm_source=man&utm_campaign=waveshare-raspberry-pi-pico-imu-sensor-10dof-v1&utm_medium=wiki|IMU-сенсор 10 DOF v1]] для определения положения вашего девайса в пространстве. Модуль выполнен в родном форм-факторе для платформы [[amp>product/raspberry-pi-pico-with-headers?utm_source=man&utm_campaign=waveshare-raspberry-pi-pico-imu-sensor-10dof-v1&utm_medium=wiki|Raspberry Pi Pico]].
{{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1.1.jpg?nolink |}}
IMU-модуль 10 DOF включает в себя:
* Акселерометр для определения величины ускорения свободного падения по осям X, Y, Z.
* Гироскоп для определения угловой скорости вокруг собственных осей X, Y, Z.
* Магнитометр для определения углов между собственными осями сенсора X, Y, Z и силовыми линиями магнитного поля Земли.
* Барометр для определения атмосферного давления, высоты над уровнем моря и температуры.
===== Подключение и настройка =====
На роль контроллера для работы с IMU-модулем рассмотрим платформу Raspberry Pi Pico.
==== Что понадобится ====
* 1× [[amp>product/raspberry-pi-pico-with-headers?utm_source=man&utm_campaign=waveshare-raspberry-pi-pico-imu-sensor-10dof-v1&utm_medium=wiki|Raspberry Pi Pico]]
* 1× [[amp>product/waveshare-raspberry-pi-pico-imu-sensor-10dof?utm_source=man&utm_campaign=waveshare-raspberry-pi-pico-imu-sensor-10dof-v1&utm_medium=wiki|IMU-сенсор 10 DOF v1]]
* 1× [[amp>product/usb-cable-micro?utm_source=man&utm_campaign=waveshare-raspberry-pi-pico-display-lcd-1n14in-spi-v1&utm_medium=wiki|Кабель USB (A — Micro USB)]]
==== Инструкция по сборке ====
- Установите Raspberry Pi Pico сверху на контактные колодки платы с IMU-сенсора. Для правильности коммуникации воспользуйтесь меткой USB-порта на плате дисплея.{{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:imu-sensor-10dof-v1-setup-hardware.1.png?nolink |}}
- Подключите полученный сет дисплеем вверх к компьютеру по USB. Для коммуникации используйте кабель micro-USB.{{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:imu-sensor-10dof-v1-setup-hardware.2.png?nolink |}}
- [[products:raspberry-pi-pico|Установите и настройте Raspberry Pi Pico c интегрированной средой разработки Thony Python IDE]].
===== Примеры работы =====
Отобразим демонстрацию работы IMU-сенсора. Для работы примеров скачайте и установите библиотеку {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:amperka_pico_imu_10dof.zip |amperka_pico_imu_10dof}}.
[[articles:thonny-python-ide#установка_библиотек|Как установить библиотеку в Raspberry Pi Pico.]]
==== Вывод показаний барометра ====
Для начала выведем в консоль показания барометра.
# Импортируем необходимые модули
import time
from amperka_pico_imu_10dof import lps22hb
# Печатаем тестовую строку в консоль
print("Pressure Sensor Test Program")
# Создаём объект для работы с барометром
barometer = lps22hb.LPS22HB()
# Выводим атмосферное давление, температуру и высоту над уровнем моря
while True:
pressure = barometer.read_pressure_millimeters_hg()
temperature = barometer.read_temperature_c()
altitude = barometer.read_altitude()
print(f"Pressure {round(pressure,2)} mmHg")
print(f"Temperature {round(temperature,2)} °C")
print(f"Altitude {round(altitude,2)} m\n")
time.sleep(0.1)
==== Вывод показаний акселерометра ====
Далее, выведем в консоль показания акселерометра: величины ускорения свободного падения по осям X, Y и Z.
# Импортируем необходимые модули
from amperka_pico_imu_10dof import icm20948
import time
import math
# Печатаем тестовую строку в консоль
print("Accelerometer Test Program")
# Создаём объект для работы с IMU-сенсором
imu=icm20948.ICM20948()
# Выводим ускорения свободного падения относительно осей X, Y и Z в «сырых значениях»
# Выводим ускорения свободного падения относительно осей X, Y и Z в G
# Выводим ускорения свободного падения относительно осей X, Y и Z в м/с²
while True:
accelerometer = imu.read_accelerometer()
accelerometer_g = imu.read_accelerometer_g()
accelerometer_a = imu.read_accelerometer_a()
print(f"Accelerometer (Raw):\t{accelerometer}")
print(f"Accelerometer (G):\t{accelerometer_g}")
print(f"Accelerometer (A):\t{accelerometer_a}")
print()
time.sleep(0.1)
==== Вывод показаний гироскопа ====
В продолжении, выведем в консоль показания гироскопа: угловую скорость вокруг собственных осей X, Y, Z.
# Импортируем необходимые модули
from amperka_pico_imu_10dof import icm20948
import time
import math
# Печатаем тестовую строку в консоль
print("IMU-sensor Test Program")
# Создаём объект для работы с IMU-сенсором
imu=icm20948.ICM20948()
# Выводим угловую скорость относительно осей X, Y и Z в «сырых значениях»
# Выводим угловую скорость относительно осей X, Y и Z в градусах в секунду
# Выводим угловую скорость относительно осей X, Y и Z в радианах
while True:
gyroscope = imu.read_gyroscope()
gyroscope_deg = imu.read_gyroscope_deg()
gyroscope_rad = imu.read_gyroscope_rad()
print(f"Gyroscope (Raw):\t{gyroscope}")
print(f"Gyroscope (Deg):\t{gyroscope_deg}")
print(f"Gyroscope (Rad):\t{gyroscope_rad}")
print()
time.sleep(0.1)
==== Вывод показаний магнитометра ====
Следующим этапом, выведем в консоль показания магнитометра: значения напряженности магнитного поля по осям X, Y, Z.
# Импортируем необходимые модули
from amperka_pico_imu_10dof import icm20948
import time
import math
# Печатаем тестовую строку в консоль
print("IMU-sensor Test Program")
# Создаём объект для работы с IMU-сенсором
imu=icm20948.ICM20948()
# Выводим значения напряженности магнитного поля по осям X, Y, Z в «сырых значениях»
# Выводим значения напряженности магнитного поля по осям X, Y, Z в «мкТс»
while True:
magnetometer = imu.read_magnetometer()
magnetometer_uT = imu.read_magnetometer_uT()
print(f"Magnetometer (RAW):\t{magnetometer}")
print(f"Magnetometer (uT):\t{magnetometer_uT}")
print()
time.sleep(0.1)
==== Вывод показаний инерциального датчика ====
Выведем показания сразу трёх сенсоров:
* акселерометра: ускорения свободного падения по осям X, Y и Z.
* гироскопа: угловую скорость вокруг собственных осей X, Y, Z.
* магнитометра: напряженность магнитного поля по осям X, Y, Z.
# Импортируем необходимые модули
from amperka_pico_imu_10dof import icm20948
import time
import math
# Печатаем тестовую строку в консоль
print("IMU-sensor Test Program")
# Создаём объект для работы с IMU-сенсором
imu=icm20948.ICM20948()
# Выводим ускорения свободного падения относительно осей X, Y и Z в м/с²
# Выводим угловую скорость относительно осей X, Y и Z в градусах в секунду
# Выводим значения напряженности магнитного поля по осям X, Y, Z в «мкТс»
while True:
accelerometer = imu.read_accelerometer_a()
gyroscope = imu.read_gyroscope_deg()
magnetometer = imu.read_magnetometer_uT()
print(f"Accelerometer:\t{accelerometer}")
print(f"Gyroscope:\t{gyroscope}")
print(f"Magnetometer:\t{magnetometer}")
print()
time.sleep(0.1)
==== Ориентация объекта в пространстве ====
Определим ориентацию объекта в пространстве с учётом направления на север. Для этого показания акселерометра, гироскопа и компаса используем как входные данные для фильтра Маджвика. На выходе получим кватернионы, которые для наглядности пересчитаем в самолётные углы Эйлера.
# Импортируем необходимые модули
from amperka_pico_imu_10dof import icm20948
import time
import math
# Печатаем тестовую строку в консоль
print("IMU-sensor Test Program")
# Создаём объект для работы с IMU-сенсором
imu=icm20948.ICM20948()
while True:
# Считываем данных с акселерометра
accelerometer = imu.read_accelerometer_g()
# Считываем данных с гироскопа
gyroscope = imu.read_gyroscope_rad()
# Считываем данных с магнитометра
magnetometer = imu.read_magnetometer_uT()
ax = accelerometer[0]
ay = accelerometer[1]
az = accelerometer[2]
gx = gyroscope[0]
gy = gyroscope[1]
gz = gyroscope[2]
mx = magnetometer[0]
my = magnetometer[1]
mz = magnetometer[2]
# Обновляем входные данные в фильтр Маджвика
imu.AHRS_update(gx, gy, gz, ax, ay, az, mx, my, mz)
# Получаем из фильтра углы Эйлера: yaw, pitch и roll
yaw = imu.get_yaw();
pitch = imu.get_pitch();
roll = imu.get_roll();
print(f"Yaw:\t{yaw}")
print(f"Pitch:\t{pitch }")
print(f"Roll:\t{roll}")
print()
time.sleep(0.1)
==== Визуальное отображение объекта в пространстве ====
Для наглядности приведём пример отображение IMU-сенсора в пространстве в виде самолёта.
=== Порядок действий ===
- [[#код_для_pico|Прошейте платформу Pico]].
- [[https://processing.org/|Скачайте и установите графическую среду Processing.]]
- {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:toxiclibs.zip |Скачайте библиотеки для Processing}} и распакуйте их в директорию хранения модулей для Processing:
userdir
Processing
libraries
- [[#код_для_processing|Запустите на Processing программный код, расположенный ниже.]]
=== Код для Pico ===
# Импортируем необходимые модули
from amperka_pico_imu_10dof import icm20948
import time
import math
# Печатаем тестовую строку в консоль
print("IMU-sensor Test Program")
# Создаём объект для работы с IMU-сенсором
imu=icm20948.ICM20948()
while True:
# Считываем данных с акселерометра
accelerometer = imu.read_accelerometer_g()
# Считываем данных с гироскопа
gyroscope = imu.read_gyroscope_rad()
# Считываем данных с магнитометра
magnetometer = imu.read_magnetometer_()
ax = accelerometer[0]
ay = accelerometer[1]
az = accelerometer[2]
gx = gyroscope[0]
gy = gyroscope[1]
gz = gyroscope[2]
mx = magnetometer[0]
my = magnetometer[1]
mz = magnetometer[2]
# Обновляем входные данные в фильтр Маджвика
imu.AHRS_update(gx, gy, gz, ax, ay, az, mx, my, mz)
# Считываем кватернион
quaternion = imu.read_quaternion()
# Выводим кватернион в консоль для передачи в Processing
print(f"{quaternion[0]},{quaternion[1]},{quaternion[2]},{quaternion[3]}")
time.sleep(0.1)
=== Код для Processing ===
import processing.serial.*;
import toxi.geom.*;
import toxi.processing.*;
// NOTE: requires ToxicLibs to be installed in order to run properly.
// 1. Download from http://toxiclibs.org/downloads
// 2. Extract into [userdir]/Processing/libraries
// (location may be different on Mac/Linux)
// 3. Run and bask in awesomeness
// The serial port
Serial port;
String message;
float[] q = new float[4];
Quaternion quat = new Quaternion(1, 0, 0, 0);
// New line character in ASCII
final char newLine = '\n';
String [] massQ = new String [4];
float[] ypr = new float[3];
void setup() {
// Size form 400x400
size(400, 400, P3D);
// Open serial port
// Replace "COM7" with the COM port on which your arduino is connected
port = new Serial(this, "COM7", 9600);
}
void draw() {
// Read and parse incoming serial message
serialEvent();
// Set background to black
background(0);
printQuaternions();
printYawPitchRoll();
// Set position to centre
translate(width / 2, height / 2);
// Begin object
pushMatrix();
float[] axis = quat.toAxisAngle();
rotate(axis[0], axis[2], axis[3], axis[1]);
// Draw main body in red
drawBody();
// Draw front-facing tip in blue
drawCylinder();
// Draw Triangles
drawTriangles();
// Draw Quads
drawQuads();
// End of object
popMatrix();
// Send character 's' to Arduino
//port.write('s');
}
void serialEvent() {
// Read from port until new line (ASCII code 13)
message = port.readStringUntil(newLine);
if (message != null) {
// Split message by commas and store in String array
massQ = split(message, ",");
q[0] = float(massQ[0]);
q[1] = float(massQ[1]);
q[2] = float(massQ[2]);
q[3] = float(massQ[3]);
}
// Print values to console
print(q[0]);
print("\t");
print(q[1]);
print("\t");
print(q[2]);
print("\t");
print(q[3]);
println("\t");
// Set our toxilibs quaternion to new data
quat.set(q[0], q[1], q[2], q[3]);
}
void drawCylinder() {
float topRadius = 0;
float bottomRadius = 20;
float tall = 20;
int sides = 8;
// Begin object
pushMatrix();
translate(0, 0, -120);
rotateX(PI/2);
fill(0, 0, 255, 200);
float angle = 0;
float angleIncrement = TWO_PI / sides;
beginShape(QUAD_STRIP);
for (int i = 0; i < sides + 1; ++i) {
vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
angle += angleIncrement;
}
endShape();
// if it is not a cone, draw the circular top cap
if (topRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, 0, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
// If it is not a cone, draw the circular bottom cap
if (bottomRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, tall, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
popMatrix();
}
void drawBody() {
fill(255, 0, 0, 200);
box(10, 10, 200);
}
void drawTriangles() {
// Draw wings and tail fin in green
fill(0, 255, 0, 200);
beginShape(TRIANGLES);
// Wing top layer
vertex(-100, 2, 30); vertex(0, 2, -80); vertex(100, 2, 30);
// Wing bottom layer
vertex(-100, -2, 30); vertex(0, -2, -80); vertex(100, -2, 30);
// Tail left layer
vertex(-2, 0, 98); vertex(-2, -30, 98); vertex(-2, 0, 70);
// Tail right layer
vertex( 2, 0, 98); vertex( 2, -30, 98); vertex( 2, 0, 70);
endShape();
}
void drawQuads() {
beginShape(QUADS);
vertex(-100, 2, 30); vertex(-100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
vertex( 100, 2, 30); vertex( 100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
vertex(-100, 2, 30); vertex(-100, -2, 30); vertex(100, -2, 30); vertex(100, 2, 30);
vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, -30, 98); vertex(-2, -30, 98);
vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
vertex(-2, -30, 98); vertex(2, -30, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
endShape();
}
void printQuaternions() {
// Set text mode to shape
textMode(SHAPE);
textSize(13);
fill(255, 255, 255);
text("Quaternions:", 20, 20, 10);
text(q[0], 20, 40, 10);
text(q[1], 20, 60, 10);
text(q[2], 20, 80, 10);
text(q[3], 20, 100, 10);
}
void printYawPitchRoll() {
// Calculate yaw/pitch/roll angles
ypr[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1) * 57.2;
ypr[1] = atan2(2 * q[2] * q[3] - 2 * q[0] * q[1], 2 * q[0] * q[0] + 2 * q[3] * q[3] - 1) * 57.2;
ypr[2] = -atan2(2 * (q[0] * q[2] - q[1] * q[3]), 1 - 2 * (q[2] * q[2] + q[1] *q[1])) * 57.2;
text("Yaw:", 150, 20, 10);
text(ypr[0], 150, 40, 10);
text("Pitch:", 220, 20, 10);
text(ypr[1], 220, 40, 10);
text("Roll:", 290, 20, 10);
text(ypr[2], 290, 40, 10);
}
При запуске визуализации на «processinge» откроется окно с графическим отображением IMU-сенсора в виде самолёта. Самолёт на экране будет повторять перемещения IMU-сенсора в пространстве.
{{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1-example.1.png?nolink |}}
===== Элементы платы =====
{{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1-annotation.png?nolink |}}
==== Инерциальный чип ICM-20948 ====
За 9 степеней свободы отвечает инерциальный чип {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:icm-20948-datasheet.pdf |ICM-20948}}, который включает в себя акселерометр, гироскоп и магнитометр.
* Акселерометр для определения величины ускорения свободного падения по осям X, Y, Z.
* Гироскоп для определения угловой скорости вокруг собственных осей X, Y, Z.
* Магнитометр для определения углов между собственными осями сенсора X, Y, Z и силовыми линиями магнитного поля Земли.
За определения десятой степени свободы отвечает отдельный чип [[#барометр_lps22hb|барометр LPS22HB]], который подскажет высоту над уровнем моря.
==== Барометр LPS22HB ====
Датчик атмосферного давления {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:lps22hb-datasheet.pdf |LPS22HB}} служит альтиметром для носимого гаджета, а также барометром для метеостанции.
==== Светодиодная индикация ====
^ Имя светодиода ^ Назначение ^
| PWR | Индикатор питания. Горит — на плату поступает напряжение, не горит — на плату не поступает напряжение.|
==== Преобразователь питания RT9193-33 ====
Понижающий DC-DC преобразователь {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:rt9193-datasheet.pdf |RT9193-33}} обеспечивает питание [[#барометр_lps22hb|барометра]] и другой логики на плате. Входное напряжение поступает от пина VSYS управляющей платы. Выходное напряжение 3,3 В с максимальным выходным током 300 мА.
==== Преобразователь питания RT9193-18 ====
Понижающий DC-DC преобразователь {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:rt9193-datasheet.pdf |RT9193-18}} обеспечивает питание [[#инерциальный_чип_icm-20948|инерциального датчика]] и [[#светодиодная_индикация|светодиодной индикации]]. Входное напряжение поступает от [[#преобразователь_питания_rt9193-33|преобразователя RT9193-33]]. Выходное напряжение 1,8 В с максимальным выходным током 300 мА.
==== Контактные колодки ====
Плата IMU-сенсор подключается к контроллерам форм-фактора Raspberry Pi Pico через две параллельных контактных колодки на 20 пинов. Все подробности коммуникации и задействованные контакты читайте в разделе [[#распиновка|распиновка]].
===== Распиновка =====
{{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1-pinout.jpg?nolink |}}
===== Принципиальная и монтажная схема =====
[[this>_media/products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1-schematic.pdf|{{:products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1-schematic.png}}]]
===== Габаритный чертёж =====
[[this>_media/products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1-dimensions.pdf|{{:products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1-dimensions.png}}]]
===== Характеристики =====
* Модель: Waveshare Pico-10DOF-IMU (SKU 19358)
* Совместимость: контроллеры Raspberry Pi Pico
* Чипы: IMU-сенсор ICM20948, барометр LPS22HB
* Напряжение питания: 5 В
* Размеры: 52×25×13 мм
==== IMU-сенсор ICM20948 ====
* Интерфейс: I²C (адрес 0x68)
* Диапазон измерения ускорения акселерометра: ±2/±4/±8/±16g
* Диапазон измерения поворота гироскопа: ±125/±250/±500/±1000/±2000 град./с
* Диапазон измерения магнитной индукции: ±4900 мкТл
==== Барометр LPS22HB ====
* Интерфейс: I²C (адрес 0x5C)
* Диапазон измерения давления: 260–1260 мбар
* Погрешность давления: ±0,025 мбар
===== Ресурсы =====
* [[amp>product/waveshare-raspberry-pi-pico-imu-sensor-10dof?utm_source=man&utm_campaign=waveshare-raspberry-pi-pico-imu-sensor-10dof-v1&utm_medium=wiki|IMU-сенсор 10 DOF v1 для Raspberry Pi Pico]] в магазине.
* [[https://github.com/amperka/hardware-drawings/blob/master/waveshare-raspberry-pi-pico-imu-sensor-10dof-v1.svg|Векторное изображение IMU-сенсора на 10 степеней свободы]]
* {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:amperka_pico_imu_10dof.zip |Библиотека для MicroPython}}
==== Полезные статьи ====
* [[products:raspberry-pi-pico|Настройка платформы Raspberry Pi Pico]]
* [[articles:arduino-ide-install|Подключение и настройка Arduino IDE]]
* [[articles:thonny-python-ide|Подключение и настройка Thonny Pyhon IDE]]
* [[articles:thonny-python-ide#установка_библиотек|Установка библиотек в Thonny Pyhon IDE]]
==== Документация ====
* {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:icm-20948-datasheet.pdf |Datasheet на IMU-сенсор ICM-20948}}
* {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:lps22hb-datasheet.pdf |Datasheet на барометр LPS22HB}}
* {{ :products:waveshare-raspberry-pi-pico-imu-sensor-10dof-v1:rt9193-datasheet.pdf |Datasheet на преобразователи напряжения: RT9193-18 с выходом 1,8 В и RT9193-33 с выходом 3,3 В}}