项目描述
本项目的核心目标是开发一款基于STM32 NUCLEO-G0B1RE开发板和X-NUCLEO-IKS4A1传感器扩展板的VR体感追踪器。
此设备主要利用了板载的LSM6DSV16X 6轴传感器和LPS22DF气压传感器,用于实时计算和监测空间姿态以及相对海拔高度的变化,并通过串口将这些数据传输至上位机。
上位机软件基于Python开发,实时显示一个立方体的三维空间变化,从而直观地展示传感器捕获的动态信息。
设计思路:
STM32 NUCLEO-G0B1RE作为主控板,具有足够的处理能力和丰富的接口,同时选择X-NUCLEO-IKS4A1扩展板作为传感器模块,因为它集成了多种MEMS传感器,能够提供所需的运动及环境数据。
软件开发分为两大部分:嵌入式系统开发和上位机接口设计。
嵌入式系统负责实时数据采集和初步处理,上位机则负责数据的进一步处理和可视化展示。
嵌入式开发采用了PlatformIO平台,这是一个开源的集成开发环境,支持多种开发板和框架,极大地简化了STM32的编程和调试过程。
硬件介绍:
- STM32 NUCLEO-G0B1RE开发板:
- 基于32位ARM Cortex-M0+ MCU,支持
- X-NUCLEO-IKS4A1传感器扩展板:
- 板载传感器:
- LSM6DSO16IS:MEMS 3D加速度计 + 3D陀螺仪 与ISPU
- LIS2MDL:MEMS 3D磁力计
- LIS2DUXS12:超低功耗MEMS 3轴加速度计
- 低功率和高精度MEMS绝对数字输出气压计
- SHT40AD1B:高精度超低功耗的温湿度传感器
- STTS22H:低电压,超低功耗,0.5°C精度的温度传感器
- LSM6DSV16X:MEMS 3D加速度计+ 3D陀螺仪
- 适用于高精度运动追踪和海拔高度测量。
工作流程:
- 数据采集:从IMU(惯性测量单元)传感器中采集加速度计和陀螺仪数据。如果设备包含磁力计数据,也可以采集。
- 传感器数据预处理:对原始传感器数据进行滤波和预处理,以去除噪声和漂移。
- 姿态估计:使用传感器融合算法(如卡尔曼滤波器或互补滤波器)来估计设备的姿态。
- 输出结果:生成表示姿态的四元数或欧拉角,供应用程序使用。
6轴传感器原理
LSM6DSV16X传感器包含一个3轴加速度计和一个3轴陀螺仪。
加速度计测量设备在X、Y和Z轴上的线性加速度(单位g),陀螺仪测量设备在X、Y和Z轴上的角速度(单位dps)。
传感器通过I2C总线与MCU通信,并将测量数据存储在FIFO(先进先出)缓冲区中,以便后续读取和处理。
四元数介绍
一种用来表示三维旋转的数学工具。
它由一个实部和三个虚部组成,通常表示为 q=w+xi+yj+zkq = w + xi + yj + zkq=w+xi+yj+zk,其中 www、xxx、yyy 和 zzz 是实数。
与欧拉角(Yaw, Pitch, Roll)相比,四元数在计算旋转时具有更高的精度和稳定性,特别是对于连续旋转的情况。
四元数的优点:
- 避免万向锁问题:欧拉角在某些旋转情况下会遇到万向锁问题,而四元数不会。
- 更高的计算效率:四元数在进行旋转插值和组合时效率更高。
- 更稳定的姿态表示:四元数提供更平滑和连续的旋转表示。
气压计原理
LPS22DF传感器用于测量环境气压(单位hPa)。根据国际民航组织(ICAO)标准大气模型,可以通过气压计算相对高度。公式如下:
其中,Initial Pressure
是初始气压值,Pressure
是当前测量的气压值。通过这个公式,可以计算出设备相对于初始位置的高度变化。
环境搭建
- 安装PlatformIO:
- 访问PlatformIO官网下载并安装PlatformIO IDE,该IDE可以集成到VS Code等流行的代码编辑器中。
- 安装后,在PlatformIO的主界面中创建一个新项目,选择对应的开发板型号(NUCLEO-G0B1RE),并设置合适的配置参数。
- 库文件依赖:
- 在项目的
platformio.ini
配置文件中添加必要的库依赖项,确保项目能够顺利编译和上传到开发板
- 在项目的
[env:nucleo_g0b1re]
platform = ststm32
framework = arduino
board = nucleo_g0b1re
monitor_speed = 115200
lib_deps =
https://github.com/stm32duino/X-NUCLEO-IKS4A1.git
https://github.com/stm32duino/LsM6DsV16x.git
https://github.com/stm32duino/LPS22DF.git
https://github.com/stm32duino/LIS2MDL.git
https://github.com/stm32duino/MotionFX.git
参考链接
https://stm32-base.org/guides/platformio.html
https://docs.platformio.org/en/latest/platforms/ststm32.html
软件流程图及代码片段
嵌入式部分流程图:
上位机流程图:
- 传感器数据采集与发送:
// Check the number of samples inside FIFO
if (accGyr.FIFO_Get_Num_Samples(&fifo_samples) != LSM6DSV16X_OK) {
SerialPort.println("LSM6DSV16X Sensor failed to get number of samples inside FIFO");
while (1);
}
// Read the FIFO if there is one stored sample
if (fifo_samples > 0) {
for (int i = 0; i < fifo_samples; i++) {
accGyr.FIFO_Get_Tag(&tag);
if (tag == 0x13) {
accGyr.FIFO_Get_Rotation_Vector(&quaternions[0]);
// Compute the elapsed time within loop cycle and wait
elapsedTime = millis() - startTime;
if ((long)(ALGO_PERIOD - elapsedTime) > 0) {
delay(ALGO_PERIOD - elapsedTime);
}
}
}
}
// Print Quaternion data
SerialPort.print("Quaternion: ");
SerialPort.print(quaternions[3], 4);
SerialPort.print(", ");
SerialPort.print(quaternions[0], 4);
SerialPort.print(", ");
SerialPort.print(quaternions[1], 4);
SerialPort.print(", ");
SerialPort.println(quaternions[2], 4);
// Read pressure and temperature.
float pressure = 0, temperature2 = 0;
PressTemp.GetPressure(&pressure);
PressTemp.GetTemperature(&temperature2);
// Calculate relative altitude
if (!initialPressureSet) {
initialPressure = pressure;
initialPressureSet = true;
}
float altitude = 44330.0 * (1.0 - pow(pressure / initialPressure, 0.1903));
SerialPort.print("Pres: ");
SerialPort.print(pressure, 2);
SerialPort.print(" Temp: ");
SerialPort.print(temperature2, 2);
SerialPort.print(" Altitude: ");
SerialPort.println(altitude, 2);
delay(100); - 图形化显示(上位机Python):
def project_vertex(vertex, offset_y):
""" Project 3D vertex to 2D space """
x, y, z = vertex
factor = 200 / (z + 200)
x = x * factor + width // 2
y = -y * factor + height // 2 + offset_y
return x, y
def draw_cube(offset_y):
screen.fill((0, 0, 0))
# Project and draw cube edges
projected_vertices = [project_vertex(vertex, offset_y) for vertex in cube_vertices]
for i, edge in enumerate(edges):
start, end = edge
color = colors[i % len(colors)]
pygame.draw.line(screen, color, projected_vertices[start], projected_vertices[end], 2)
pygame.display.flip()
功能展示及说明
- 上位机接收到的数据用于实时更新3D立方体的姿态。
心得体会
通过本项目,我深入理解了STM32的传感器数据处理和串口通信机制,同时对Python进行数据可视化的能力有了更进一步的掌握。项目过程中,PlatformIO的强大功能给我的开发工作带来了极大的便利,使我能够更专注于算法的实现和优化。希望未来能有更多机会针对不同的应用场景开发类似的嵌入式系统,进一步提升我的技术能力。
对活动的建议
建议未来的活动能增加更多关于云计算和AI的集成应用,这将有助于开发更智能的物联网设备,实现更广泛的应用场景。同时,增设更多实战演练和案例分析,能够帮助参与者更好地理解理论与实践的结合点。