通过树莓派Pico读取MPU6050仅获100样本/秒,求提升至1kHz方案
问题描述
我需要采集MPU6050的加速度计、陀螺仪及温度原始数据,硬件配置为MPU6050与树莓派Pico焊接,Pico通过USB连接笔记本电脑。当前采样率仅约100样本/秒,但MPU6050 datasheet标称至少支持1kHz采样率。我使用Python的pyserial库接收数据,Pico侧采用UART通信(波特率115200),串口通信本身无问题,但Pico读取MPU6050数据的速度不足,serial.in_waiting()返回大量空字节。以下是现有代码,求提升采样率的解决方法:
现有代码
Pico侧代码(main.py)
from imu import MPU6050 import utime import time from machine import Pin, I2C, UART i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000) imu = MPU6050(i2c) uart = UART(0, baudrate=115200) print("UART Info : ", uart) while True: ax = round(imu.accel.x, 2) ay = round(imu.accel.y, 2) az = round(imu.accel.z, 2) gx = round(imu.gyro.x) gy = round(imu.gyro.y) gz = round(imu.gyro.z) tem = round(imu.temperature, 2) print(ax, ay, az, gx, gy, gz, tem)
Python侧代码
import serial import time import numpy as np import matplotlib.pyplot as plt import pandas as pd ser = serial.Serial('COM4', 115200) print(ser) file = open("serial_sample.csv", "w") start_time = time.time() curr_time = time.time() output_list = [] header_string = "X_accel" + "," + "Y_accel" + "," + "Z_accel" + "," + "X_Pos" + "," + "Y_Pos" + "," + "Z_Pos" \ + "," + "Temperature" + "\n" output_list.append(header_string) while curr_time - start_time < 10: data = ser.readline() data = str(data).split("\\")[0].split(" ") output = data[0].split("'")[1] + "," + data[1] + "," + data[2] + "," + data[3] + "," + data[4] + "," + data[5] + "," + data[6] + "\n" output_list.append(output) curr_time = time.time() file.writelines(output_list) file.close()
优化方案
1. 提升Pico侧MPU6050读取效率
- 减少I2C调用次数:原代码每次访问
imu.accel.x、imu.gyro.x等属性都会单独发起I2C读取,改为一次性读取所有传感器数据,降低总线开销。 - 跳过不必要的浮点运算:
round()操作会占用Pico计算资源,将数据格式化逻辑转移到Python侧处理。 - 强制设置1kHz采样率:MPU6050默认采样率可能未达1kHz,通过寄存器配置:采样率公式为
Sample Rate = 8000Hz / (1 + SMPLRT_DIV),设置SMPLRT_DIV=7即可得到1kHz采样率。
2. 优化Pico侧UART输出
- 替换
print为uart.write:print函数会额外处理缓冲和换行逻辑,直接用uart.write发送字节串能大幅提升输出速度。 - 使用紧凑文本格式:采用逗号分隔的单行字符串,减少数据传输的冗余内容。
3. 改进Python侧接收逻辑
- 避免
readline()阻塞:readline()会等待换行符导致采样延迟,改用批量读取串口缓冲区的可用字节。 - 实时写入文件:取消将所有数据存入列表的操作,收到数据后立即写入文件,减少内存占用和批量写入耗时。
- 简化字符串解析:原代码的字符串分割逻辑复杂低效,直接按原始格式解析即可。
修改后的代码示例
Pico侧优化代码
from imu import MPU6050 import utime from machine import Pin, I2C, UART # 初始化I2C(MPU6050最高支持400kHz) i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000) imu = MPU6050(i2c) # 设置MPU6050采样率为1kHz(SMPLRT_DIV寄存器地址0x19,值7) i2c.writeto_mem(0x68, 0x19, b'\x07') uart = UART(0, baudrate=115200) while True: # 一次性读取所有传感器数据,减少I2C调用 accel_data = imu.accel gyro_data = imu.gyro temp_data = imu.temperature # 拼接为紧凑的逗号分隔字符串 output_str = f"{accel_data.x},{accel_data.y},{accel_data.z},{gyro_data.x},{gyro_data.y},{gyro_data.z},{temp_data}\n" # 直接发送字节串 uart.write(output_str.encode('utf-8'))
Python侧优化代码
import serial import time # 设置短超时,避免阻塞 ser = serial.Serial('COM4', 115200, timeout=0.001) print(ser) # 用with语句自动管理文件 with open("serial_sample.csv", "w") as file: # 修正表头(原表头中X_Pos/Y_Pos/Z_Pos应为陀螺仪数据) file.write("X_accel,Y_accel,Z_accel,X_gyro,Y_gyro,Z_gyro,Temperature\n") start_time = time.time() while time.time() - start_time < 10: # 批量读取缓冲区所有可用字节 if ser.in_waiting > 0: raw_data = ser.read(ser.in_waiting).decode('utf-8') # 按换行分割处理多行数据 for line in raw_data.split('\n'): if line.strip(): # 跳过空行 file.write(line + '\n')
内容的提问来源于stack exchange,提问作者Susmita Goswami
相关产品推荐
相关产品推荐

