CH347读取MPU6050传感器数据和显示

news2024/11/26 12:20:36

MPU6050 是一款集成了六轴加速度计和陀螺仪的微电子机械系统(MEMS)传感器。它由 InvenSense(现为 TDK) 公司开发,是一种广泛应用于姿态估计、运动追踪和稳定控制等领域的常用传感器。

MPU6050 具有以下主要特点和技术规格:

  1. 6轴测量能力:MPU6050 集成了三轴加速度计和三轴陀螺仪,能够同时测量物体的加速度和角速度,从而获得姿态信息。

  2. 高精度:MPU6050 提供高精度的测量性能,能够在多种环境条件下稳定工作,并具有较低的噪声和漂移。

  3. 低功耗:MPU6050 设计优化了功耗,适用于移动设备和电池供电的应用场景。

  4. 数字输出:MPU6050 输出的数据以数字形式呈现,通过 I2C 接口与微控制器或其他处理器通信,简化了数据获取和处理过程。

  5. 可编程寄存器:MPU6050 提供一些可编程寄存器,允许用户配置传感器的工作模式和测量范围,以满足不同应用需求。

  6. 姿态估计支持:由于同时具备加速度计和陀螺仪,MPU6050 能够用于姿态估计和导航,例如通过融合算法计算物体的俯仰角、滚转角和航向角。

  7. 应用广泛:MPU6050 可广泛应用于各种领域,如智能手机、游戏控制器、无人机、机器人、虚拟现实设备等。

在之前的文章 esp32连接mpu6050 中演示了esp32通过i2c连接mpu6050,并获取了mpu6050的寄存器值;ch347连接mpu6050 中演示了通过ch347连接mpu6050,并获取了mpu6050的寄存器值。今天通过ch347连接mpu6050,读取传感器数据,并显示出来。

首先编写mpu6050模块代码mpu6050.py,对mpu6050的功能进行一些封装,关键代码如下:

import ch347

class MPU6050:

    # Global Variables
    GRAVITIY_MS2 = 9.80665
    address = None
    driver = None

    # Scale Modifiers
    ACCEL_SCALE_MODIFIER_2G = 16384.0
    ACCEL_SCALE_MODIFIER_4G = 8192.0
    ACCEL_SCALE_MODIFIER_8G = 4096.0
    ACCEL_SCALE_MODIFIER_16G = 2048.0

    GYRO_SCALE_MODIFIER_250DEG = 131.0
    GYRO_SCALE_MODIFIER_500DEG = 65.5
    GYRO_SCALE_MODIFIER_1000DEG = 32.8
    GYRO_SCALE_MODIFIER_2000DEG = 16.4

    # Pre-defined ranges
    ACCEL_RANGE_2G = 0x00
    ACCEL_RANGE_4G = 0x08
    ACCEL_RANGE_8G = 0x10
    ACCEL_RANGE_16G = 0x18

    GYRO_RANGE_250DEG = 0x00
    GYRO_RANGE_500DEG = 0x08
    GYRO_RANGE_1000DEG = 0x10
    GYRO_RANGE_2000DEG = 0x18

    FILTER_BW_256=0x00
    FILTER_BW_188=0x01
    FILTER_BW_98=0x02
    FILTER_BW_42=0x03
    FILTER_BW_20=0x04
    FILTER_BW_10=0x05
    FILTER_BW_5=0x06

    # MPU-6050 Registers
    PWR_MGMT_1 = 0x6B
    PWR_MGMT_2 = 0x6C

    ACCEL_XOUT0 = 0x3B
    ACCEL_YOUT0 = 0x3D
    ACCEL_ZOUT0 = 0x3F

    TEMP_OUT0 = 0x41

    GYRO_XOUT0 = 0x43
    GYRO_YOUT0 = 0x45
    GYRO_ZOUT0 = 0x47

    ACCEL_CONFIG = 0x1C
    GYRO_CONFIG = 0x1B
    MPU_CONFIG = 0x1A

    def __init__(self, address=0x68, dll="CH347DLLA64.dll", device_index=0):
        self.address = address << 1
        self.driver = ch347.CH347Driver(dll)
        self.device_index = device_index

        self.driver.open_device(self.device_index)
        # Wake up the MPU-6050 since it starts in sleep mode
        self.driver.stream_i2c(self.device_index, [self.address, self.PWR_MGMT_1, 0x00], 0)

    # I2C communication methods

    def read_byte_data(self, register):
        raw_data = self.driver.stream_i2c(self.device_index, [self.address, register], 1)
        return raw_data[0]
    
    def write_byte_data(self, register, value):
        return self.driver.stream_i2c(self.device_index, [self.address, register, value], 0)
 
    def read_i2c_word(self, register):
        """Read two i2c registers and combine them.

        register -- the first register to read from.
        Returns the combined read results.
        """
        # Read the data from the registers
        # high = self.read_byte_data(self.address, register)
        # low = self.read_byte_data(self.address, register + 1)
        raw_data = self.driver.stream_i2c(self.device_index, [self.address, register], 2)

        # value = (high << 8) + low
        value = raw_data[0] << 8 | raw_data[1]

        if (value >= 0x8000):
            return -((65535 - value) + 1)
        else:
            return value

    # MPU-6050 Methods

    def get_temp(self):
        """Reads the temperature from the onboard temperature sensor of the MPU-6050.

        Returns the temperature in degrees Celcius.
        """
        raw_temp = self.read_i2c_word(self.TEMP_OUT0)
        # raw_temp = self.driver.stream_i2c(self.device_index, [self.address, self.TEMP_OUT0], 2)
        # temp = raw_temp[0] << 8 | raw_temp[1]

        # Get the actual temperature using the formule given in the
        # MPU-6050 Register Map and Descriptions revision 4.2, page 30
        actual_temp = (raw_temp / 340.0) + 36.53

        return actual_temp

    def set_accel_range(self, accel_range):
        """Sets the range of the accelerometer to range.

        accel_range -- the range to set the accelerometer to. Using a
        pre-defined range is advised.
        """
        # First change it to 0x00 to make sure we write the correct value later
        self.write_byte_data(self.ACCEL_CONFIG, 0x00)

        # Write the new range to the ACCEL_CONFIG register
        self.write_byte_data(self.ACCEL_CONFIG, accel_range)

    def read_accel_range(self, raw = False):
        """Reads the range the accelerometer is set to.

        If raw is True, it will return the raw value from the ACCEL_CONFIG
        register
        If raw is False, it will return an integer: -1, 2, 4, 8 or 16. When it
        returns -1 something went wrong.
        """
        raw_data = self.read_byte_data(self.ACCEL_CONFIG)

        if raw is True:
            return raw_data
        elif raw is False:
            if raw_data == self.ACCEL_RANGE_2G:
                return 2
            elif raw_data == self.ACCEL_RANGE_4G:
                return 4
            elif raw_data == self.ACCEL_RANGE_8G:
                return 8
            elif raw_data == self.ACCEL_RANGE_16G:
                return 16
            else:
                return -1

    def get_accel_data(self, g = False):
        """Gets and returns the X, Y and Z values from the accelerometer.

        If g is True, it will return the data in g
        If g is False, it will return the data in m/s^2
        Returns a dictionary with the measurement results.
        """
        x = self.read_i2c_word(self.ACCEL_XOUT0)
        y = self.read_i2c_word(self.ACCEL_YOUT0)
        z = self.read_i2c_word(self.ACCEL_ZOUT0)

        accel_scale_modifier = None
        accel_range = self.read_accel_range(True)

        if accel_range == self.ACCEL_RANGE_2G:
            accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_2G
        elif accel_range == self.ACCEL_RANGE_4G:
            accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_4G
        elif accel_range == self.ACCEL_RANGE_8G:
            accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_8G
        elif accel_range == self.ACCEL_RANGE_16G:
            accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_16G
        else:
            print("Unkown range - accel_scale_modifier set to self.ACCEL_SCALE_MODIFIER_2G")
            accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_2G

        x = x / accel_scale_modifier
        y = y / accel_scale_modifier
        z = z / accel_scale_modifier

        if g is True:
            return {'x': x, 'y': y, 'z': z}
        elif g is False:
            x = x * self.GRAVITIY_MS2
            y = y * self.GRAVITIY_MS2
            z = z * self.GRAVITIY_MS2
            return {'x': x, 'y': y, 'z': z}

    def set_gyro_range(self, gyro_range):
        """Sets the range of the gyroscope to range.

        gyro_range -- the range to set the gyroscope to. Using a pre-defined
        range is advised.
        """
        # First change it to 0x00 to make sure we write the correct value later
        self.write_byte_data(self.GYRO_CONFIG, 0x00)

        # Write the new range to the ACCEL_CONFIG register
        self.write_byte_data(self.GYRO_CONFIG, gyro_range)

    def set_filter_range(self, filter_range=FILTER_BW_256):
        """Sets the low-pass bandpass filter frequency"""
        # Keep the current EXT_SYNC_SET configuration in bits 3, 4, 5 in the MPU_CONFIG register
        EXT_SYNC_SET = self.read_byte_data(self.MPU_CONFIG) & 0b00111000
        return self.write_byte_data(self.MPU_CONFIG,  EXT_SYNC_SET | filter_range)


    def read_gyro_range(self, raw = False):
        """Reads the range the gyroscope is set to.

        If raw is True, it will return the raw value from the GYRO_CONFIG
        register.
        If raw is False, it will return 250, 500, 1000, 2000 or -1. If the
        returned value is equal to -1 something went wrong.
        """
        raw_data = self.read_byte_data(self.GYRO_CONFIG)

        if raw is True:
            return raw_data
        elif raw is False:
            if raw_data == self.GYRO_RANGE_250DEG:
                return 250
            elif raw_data == self.GYRO_RANGE_500DEG:
                return 500
            elif raw_data == self.GYRO_RANGE_1000DEG:
                return 1000
            elif raw_data == self.GYRO_RANGE_2000DEG:
                return 2000
            else:
                return -1

    def get_gyro_data(self):
        """Gets and returns the X, Y and Z values from the gyroscope.

        Returns the read values in a dictionary.
        """
        x = self.read_i2c_word(self.GYRO_XOUT0)
        y = self.read_i2c_word(self.GYRO_YOUT0)
        z = self.read_i2c_word(self.GYRO_ZOUT0)

        gyro_scale_modifier = None
        gyro_range = self.read_gyro_range(True)

        if gyro_range == self.GYRO_RANGE_250DEG:
            gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_250DEG
        elif gyro_range == self.GYRO_RANGE_500DEG:
            gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_500DEG
        elif gyro_range == self.GYRO_RANGE_1000DEG:
            gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_1000DEG
        elif gyro_range == self.GYRO_RANGE_2000DEG:
            gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_2000DEG
        else:
            print("Unkown range - gyro_scale_modifier set to self.GYRO_SCALE_MODIFIER_250DEG")
            gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_250DEG

        x = x / gyro_scale_modifier
        y = y / gyro_scale_modifier
        z = z / gyro_scale_modifier

        return {'x': x, 'y': y, 'z': z}

    def get_all_data(self):
        """Reads and returns all the available data."""
        temp = self.get_temp()
        accel = self.get_accel_data()
        gyro = self.get_gyro_data()

        return [accel, gyro, temp]
    
    def close(self):
        self.driver.close_device(self.device_index)

if __name__ == "__main__":
    mpu = MPU6050()
    print(mpu.get_temp())
    accel_data = mpu.get_accel_data(True)
    print(accel_data['x'])
    print(accel_data['y'])
    print(accel_data['z'])
    gyro_data = mpu.get_gyro_data()
    print(gyro_data['x'])
    print(gyro_data['y'])
    print(gyro_data['z'])
    mpu.close()

这个文件放在ch347.pyCH347DLLA64.DLL同级目录下,将CH347与MPU6050模块连接:

CH347连接MPU6050

运行上面的代码:

❯ python mpu6050.py
29.659411764705883
-0.044921875
0.016357421875
1.291015625
-2.2977099236641223
0.35877862595419846
-3.4885496183206106

因为MPU6050传感器数据寄存器地址是连续的,获取传感器数据时其实可以快读,理论上会更快,上面的代码还没有优化,先可用。输出数据g值约1.3,没有进行校准。

接下来编写数据显示代码,mpu6050_plot.py

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

from mpu6050 import MPU6050

# Initialize the MPU6050 sensor
mpu6050 = MPU6050()

# Replace these lines with the actual import and initialization of the MPU6050 sensor
# For demonstration purposes, we use dummy functions to generate random data
def read_mpu6050_accel_data():
    accel_data = mpu6050.get_accel_data(True)
    return [accel_data['x'], accel_data["y"], accel_data["z"]]

def read_mpu6050_gyro_data():
    gyro_data = mpu6050.get_gyro_data()
    return [gyro_data['x'], gyro_data["y"], gyro_data["z"]]

# Generator function to produce data from the MPU6050 sensor
def generate_mpu6050_data():
    data_buffer = []
    while True:
        accel_data = read_mpu6050_accel_data()
        gyro_data = read_mpu6050_gyro_data()
        data_buffer.append(accel_data + gyro_data)
        yield data_buffer

# Create a figure with 6 subplots for accelerometer and gyroscope data
fig, axs = plt.subplots(6, 1, figsize=(8, 12))

# Initialize empty lines for the accelerometer and gyroscope data plots
lines = [axs[i].plot([], [], lw=2)[0] for i in range(6)]

# Set the number of data points to be displayed on the plot
num_display_points = 50

def init():
    for line in lines:
        line.set_data([], [])
    return lines

def update(frame):
    data_buffer = next(data_generator)

    # Generate the x-axis values (time steps) based on the number of data points
    time_steps = np.arange(len(data_buffer))

    # Get the starting index to display a specific number of data points
    start_index = max(0, len(data_buffer) - num_display_points)

    # Update the plot data for accelerometer and gyroscope
    for i in range(6):
        lines[i].set_data(time_steps[start_index:], [data[i] for data in data_buffer[start_index:]])

        # Adjust the plot limits for better visualization
        if i < 3:
            axs[i].set_ylim(-2, 2)  # Accelerometer data range: -2 to +2
        else:
            axs[i].set_ylim(-200, 200)  # Gyroscope data range: -200 to +200
        axs[i].set_xlim(start_index, start_index + num_display_points - 1)

    return lines

# Create the generator for MPU6050 sensor data
data_generator = generate_mpu6050_data()

# Create an animation for real-time plotting, update every 100 milliseconds (0.1 seconds)
ani = animation.FuncAnimation(fig, update, frames=range(100), init_func=init, blit=True, interval=100)

# Add labels and title to each subplot
axis_labels = ['AX', 'AY', 'AZ', 'GX', 'GY', 'GZ']
for i in range(6):
    axs[i].set_title(f'{axis_labels[i]} Data')
    axs[i].set_xlabel('Time Steps')
    axs[i].set_ylabel('MPU6050 Data Value')

plt.tight_layout()
plt.show()
mpu6050.close()

运行效果:

ch347读取mpu6050传感器数据和显示

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1056347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1、【开始】【简介】Qlib:量化平台

【简介】1、Qlib:量化平台 简介框架简介 Qlib是一个面向AI的量化投资平台,旨在实现AI技术在量化投资中的潜力,赋能研究,并创造价值。 通过Qlib,用户可以轻松利用他们的想法来创建更好的量化投资策略。 框架 在模块层,Qlib 是由上述组件组成的平台。这些组件被设计为低耦…

ssm+vue的图书管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的图书管理系统(有报告)。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spr…

正点原子嵌入式linux驱动开发——TF-A移植

经过了之前的学习&#xff0c;除了TF-A的详细启动流程仍待更新&#xff0c;TF-A的使用和其对应的大致启动流程已经进行过了学习。但是当我们实际做产品时&#xff0c;硬件平台肯定会和ST官方的有区别&#xff0c;比如DDR容量会改变&#xff0c;自己的硬件没有使用到官方EVK开发…

1.HTML-标题排版

1.Vscode快速生成基本代码结构 !enter <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" conte…

Acwing 908. 最大不相交区间数量

Acwing 908. 最大不相交区间数量 知识点题目描述思路讲解代码展示 知识点 贪心 题目描述 思路讲解 代码展示 #include <iostream> #include <algorithm>using namespace std;const int N 100010;int n;struct Range {int l, r;bool operator<(const Range …

【爬虫】用wget命令爬虫的简易教程

文章目录 1. 获取登录的请求2. 用postman模拟登录请求3. 用wget模拟登录请求并保存cookie4. 开始爬取网站5. 查看爬取结果6. 网站爬虫简易教程 爬取需要登录的网站的资源 背景&#xff1a;对于一些网站需要使用用户名和密码登录并且使用了https&#xff0c;我们如果不通过凭证将…

Arcgis提取玉米种植地分布,并以此为掩膜提取遥感影像

Arcgis提取玉米种植地分布上&#xff0c;并以此为掩膜提取遥感影像 一、问题描述 因为之前反演是整个研究区&#xff0c;然而土地利用类型有很多类&#xff0c;只在农田或者植被上进行反演&#xff0c;需要去除水体、建筑等其他类型&#xff0c;如何处理得到下图中只有耕地类…

世界前沿技术发展报告2023《世界信息技术发展报告》(六)网络与通信技术

&#xff08;六&#xff09;网络与通信技术 1. 概述2. 5G与光通讯2.1 美国研究人员利用电磁拓扑绝缘体使5G频谱带宽翻倍2.2 日本东京工业大学推出可接入5G网络的高频收发器2.3 美国得克萨斯农工大学通过波束管理改进5G毫米波通信2.4 联发科完成全球首次5G NTN卫星手机连线测试2…

springmvc-国际化中英文切换文件上传下载

1. 国际化 1.1 介绍 国际化(internationalization)&#xff0c; 简称国际化。一个产品支持国际化是指产品在无需做大的改变就能够适应不同的语言和地区的能力。i18n是指是一种让软件在开发阶段就支持多种语言的技术。 1.2 java.util.Locale 该类对象表示了特定的地理&#…

【算法学习】-【双指针】-【复写零】

LeetCode原题链接&#xff1a;1089. 复写零 下面是题目描述&#xff1a; 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素。请对输入的数组 …

【word】从正文开始设置页码

在写报告的时候&#xff0c;会要求有封面和目录&#xff0c;各占一页。正文从第3页开始&#xff0c;页码从正文开始设置 word是新建的 分出三节&#xff08;封面、目录、正文&#xff09; 布局--->分割符--->分节符--->下一页 这样就能将word分为3节&#xff0c;分…

『RSSHub』搭建部署指南

前言 相信各位对推荐算法已经很熟悉了&#xff0c;平台基于推荐算法不断推送我们感兴趣的信息&#xff0c;但是身处推荐算法中心&#xff0c;有时我们可能感觉视野越来越闭塞&#xff0c;原来节约我们时间的推荐系统&#xff0c;这时却成了困住我们的信息茧房 那么也许 RSS&a…

想做网络安全但是没有任何证书可以吗

大家好&#xff0c;我是网络工程师成长日记实验室的郑老师&#xff0c;您现在正在查看的是网络工程师成长日记专栏&#xff0c;记录网络工程师日常生活的点点滴滴 有个同学说他打算做网络安全工程师。他问我说如果考这个软考的网络工程师或者信息安全这个工程师&#xff0c;到时…

基于SSM的公司项目管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

世界前沿技术发展报告2023《世界信息技术发展报告》(七)网络与信息安全技术

&#xff08;七&#xff09;网络与信息安全技术 1. 概述2. 网络安全关键技术2.1 美国特种作战司令部举办网络挑战赛以寻找边缘安全技术2.2 英国卡迪夫大学开发出在1秒内阻止网络攻击的方法2.3 国研究人员开发出检测恶意网页的新方法2.4 韩国仁川大学研发出一种基于5G的人工智能…

SpringBoot的全局异常拦截

在 Spring Boot 中&#xff0c;可以通过使用 ControllerAdvice 注解和 ExceptionHandler 注解来实现全局异常拦截。 RestControllerAdvice RestControllerAdvice 是 Spring Framework 提供的注解&#xff0c;用于定义全局异常处理类&#xff0c;并且结合 ExceptionHandler 注…

Python——ASCII编码与Unicode(UTF-8,UTF-16 和 UTF-32)编码

Python3 Python——ASCII编码与Unicode&#xff08;UTF-8&#xff0c;UTF-16 和 UTF-32&#xff09;编码 文章目录 Python3一、编码与编码格式二、ASCII编码与UTF-8编码&#xff08;UTF-16 和 UTF-32编码&#xff09;三、ASCII 字符串和 Unicode 字符串 最近看Python程序的文件…

C程序设计内容与例题讲解 -- 第四章--选择结构程序设计第二部分(第五版)谭浩强

前言:在前面我们学习了选择结构和条件判断&#xff0c;用if语句实现选择结构&#xff0c;关系运算符和关系表达式&#xff0c;逻辑运算符和逻辑表达式等知识。今天我们将接着上一篇未讲完的继续讲解。 鸡汤:种一棵树最好的时间是十年前&#xff0c;其次是现在&#xff01;加油各…

springmvc-controller视图层配置SpringMVC处理请求的流程

目录 1. 什么是springmvc 2.项目中加入springmvc支持 2.1 导入依赖 2.2 springMVC配置文件 2.3 web.xml配置 2.4 中文编码处理 3. 编写一个简单的controller 4. 视图层配置 4.1 视图解析器配 4.2 静态资源配置 4.2 编写页面 4.3 页面跳转方式 5. SpringMVC处理请求…

Vue3快速入门

简介 什么是Vue Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&…