====== 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 В}}