Unity和智能硬件交互系列:MPU6050

Posted B612灯夫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity和智能硬件交互系列:MPU6050相关的知识,希望对你有一定的参考价值。

文章目录


前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


一、陀螺仪传感器

陀螺仪:

是一种用来感测与维持方向的装置,基於角动量不灭的理论设计出来的。 陀螺仪一旦开始旋转,由於轮子的角动量,陀螺仪有抗拒方向改变的趋向。一般在无人机、平衡车上使用,我们再用个各种型号手机,基本都包含这个组件。

三轴陀螺仪和六轴的区别

三轴陀螺仪是分别感应Roll(左右倾斜)、Pitch(前后倾斜)、Yaw(左右摇摆)的全方位动态信息。而6轴陀螺仪是指三轴加速器和三轴陀螺仪合在一起的称呼。
    三轴加速器是检测横向加速的,三轴陀螺仪是检测角度旋转和平衡的,合在一起称为六轴传感器。
  三轴加速器就是感应XYZ(立体空间三个方向,前后左右上下)轴向上的加速,当装有6轴陀螺仪的设备受到外力运动时,可以根据力的方向和大小,计算出对应的加速度
  简单的说,6轴比3轴增加了额外的加速度功能,稍微高级一些。

六轴的区别和九轴陀螺仪的区别

所谓的六轴陀螺仪叫六轴动作感应器比较合适 是三轴陀螺仪和加速计的合称。如果有三轴陀螺仪也有加速计那就具有六轴动作感应。
  而九轴感测组件是:三轴加速度计、三轴陀螺仪、三轴磁强计,然后欧拉角加四元数数据融合。

二、实验设备

本次我们将使用6轴传感器,实现串口与Unity3D的通信,并通过传感器控制Unity3D场景中的游戏物体,检验角度传感器的实际性能,以便在未来的项目中使用。本次演示不包含Arduino设备,在以后有空我们再进行Arduino对角度传感设备的操控。

1.串口6轴加速度计/陀螺仪MPU6050模块

本次我们测试和使用的是6轴陀螺仪,这个设备支持51/AVR/Arduino/STM8/STM32,自身自带卡尔曼滤波,支持串口输出滤波数据同时也支持高端玩家访问底层原始数据。
直接使用串口输出倾角(懒人模式),通过TTL转USB与计算机进行通信,通过对数据的解析,完成对场景种物体的控制。

2.USB转TTL 3.3V 5V

USB转TTL模块,如下图所示。该模块一端接入PC机的USB接口,另一端有TXD、RXD、GND、5V、3.3V五个引脚,分别与单片机的RXD、TXD、GND、5V引脚相连,注意:TXD和RXD是要互相反接。对于采用3.3V供电的单片机则把5V改为3.3V即可。首次使用需要安装对应的驱动,具体驱动类型根据所采购的设备,安装即可。
如下使用CH340+单片机控制,资料

3.硬件设备准备

以下为实物接线图

USB转TTL:

三、代码编写

因为不使用Arduino作为硬件模块的接入设备,所以不写硬件代码,只需要对Unity 3D进行场景搭建和串口通信代码编写。

1.场景搭建

很简单的场景,3D场景中的X、Y轴;屏幕Canvas的X、Y、Z数据展示。

2.串口通信


using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;

public  delegate void OnMessageArrived(float[] angle);
public class PortControl : MonoBehaviour

    #region 定义串口属性
    //定义基本信息
    public string portName = "COM3";//串口名
    public int baudRate = 115200;//波特率
    public Parity parity = Parity.None;//效验位
    public int dataBits = 8;//数据位
    public StopBits stopBits = StopBits.One;//停止位
    SerialPort sp = null;
    Thread dataReceiveThread;
    //发送的消息
    string message = "";
    public List<byte> listReceive = new List<byte>();
    char[] strchar = new char[100];//接收的字符信息转换为字符数组信息
    string str;
    public OnMessageArrived messageListener;
    #endregion
    void Start()
    
        OpenPort();
        dataReceiveThread = new Thread(new ThreadStart(DataReceiveFunction));
        dataReceiveThread.Start();
    
    void Update()
    
    
    #region 创建串口,并打开串口
    public void OpenPort()
    
        //创建串口
        sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
        sp.ReadTimeout = 400;
        try
        
            sp.Open();
        
        catch (Exception ex)
        
            Debug.Log(ex.Message);
        
    
    #endregion
    #region 程序退出时关闭串口
    void OnApplicationQuit()
    
        ClosePort();
    
    public void ClosePort()
    
        try
        
            sp.Close();
            dataReceiveThread.Abort();
        
        catch (Exception ex)
        
            Debug.Log(ex.Message);
        
    
    #endregion
    /// <summary>
    /// 打印接收的信息
    /// </summary>
    void PrintData()
    
        for (int i = 0; i < listReceive.Count; i++)
        
            strchar[i] = (char)(listReceive[i]);
            str = new string(strchar);
        
        Debug.Log(str);
    

    #region 接收数据
    void DataReceiveFunction()
    
        #region 按单个字节发送处理信息,不能接收中文
        #endregion
        float[] a = new float[3];
        float[] w = new float[3];
        float[] angle = new float[3];
        float T=0;

        #region 按字节数组发送处理信息,信息缺失
        byte[] Re_buf = new byte[11];
        int step = 0;
        int bytes = 0;
        while (true)
        
            if (sp != null && sp.IsOpen)
            
                try
                
                    bytes = sp.Read(Re_buf, 0, Re_buf.Length);//接收字节
                    if (bytes == 0)
                    
                        continue;
                    
                    else
                    
                        //  string strbytes = Encoding.Default.GetString(buffer);
                       string[] esStr=new string[Re_buf.Length];
                        string hexStr = "";
                        for(int i=0;i< Re_buf.Length; i++)
                        
                            esStr[i]= Re_buf[i].ToString("X2") + "";
                            hexStr += esStr[i]+"";
                        
                        
                        if (esStr[0] != "55")
                        
                            for(int k=0;k< esStr.Length; k++)
                            
                                if(esStr[k] == "55")
                                
                                    step = k;
                                    byte[] thr = new byte[step];
                                   int iss= sp.Read(thr, 0, thr.Length);//接收字节
                                    break;
                                
                            
                        
                        byte[] data = HexStrTobyte(hexStr);
                     //   Debug.Log(.Length);
                        if (data[0] == 0x55)      //检查帧头
                        
                            switch (data[1])
                            
                                //根据客服给的参考案例,修改为C#的数据解析方式
                                case 0x51:
                                    a[0] = ((short)(data[3] << 8 | data[2])) / 32768.0f * 16;
                                    a[1] = ((short)(data[5] << 8 | data[4])) / 32768.0f * 16;
                                    a[2] = ((short)(data[7] << 8 | data[6])) / 32768.0f * 16;
                                    T = ((short)(data[9] << 8 | data[8])) / 340.0f + 36.25f;
                                    break;
                                case 0x52:
                                    w[0] = ((short)(data[3] << 8 | data[2])) / 32768.0f * 2000;
                                    w[1] = ((short)(data[5] << 8 | data[4])) / 32768.0f * 2000;
                                    w[2] = ((short)(data[7] << 8 | data[6])) / 32768.0f * 2000;
                                    T = ((short)(data[9] << 8 | data[8])) / 340.0f + 36.25f;
                                    break;
                                case 0x53:
                                    angle[0] = ((short)(data[3] << 8 | data[2])) / 32768.0f * 180;
                                    angle[1] = ((short)(data[5] << 8 | data[4])) / 32768.0f * 180;
                                    angle[2] = ((short)(data[7] << 8 | data[6])) / 32768.0f * 180;
                                    T = ((short)(data[9] << 8 | data[8])) / 340.0f + 36.25f;
                                    break;
                            
                            messageListener(angle);
                          
                        
                          
                    
                
                catch (Exception ex)
                
                    if (ex.GetType() != typeof(ThreadAbortException))
                    
                    
                
            
          //  Thread.Sleep(10);
        
        #endregion
    
    #endregion
    private byte[] HexStrTobyte(string hexString)
    
        hexString = hexString.Replace(" ", "");
        if ((hexString.Length % 2) != 0)
            hexString += " ";
        byte[] returnBytes = new byte[hexString.Length / 2];
        for (int i = 0; i < returnBytes.Length; i++)
            returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
        return returnBytes;
    
    #region 发送数据
    public void WriteData(string dataStr)
    
        if (sp.IsOpen)
        
            sp.Write(dataStr);
        
    
    #endregion



控制脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SerialListener : MonoBehaviour

    public PortControl portMessage;
    public Transform obj;
    public Text xAngle;
    public Text yAngle;
    public Text zAngle;
    Queue<float[]> message;
    // Start is called before the first frame update
    void Start()
    
        message = new Queue<float[]>(20);
        portMessage.messageListener = OnMessageArrived;
    
    public void OnMessageArrived(float[] angle)
    
        /*  string s = "";
                            foreach (float bb in angle)
                                s += bb + "_";
                           Debug.Log(s + "");*/
        message.Enqueue(angle);
     //   Debug.Log(message.Count);
    
    
    // Update is called once per frame
    void Update()
    
        if (message.Count > 0)
        
            float[] angle = message.Dequeue();
            xAngle.text = angle[0] + "";
            yAngle.text = angle[1] + "";
            zAngle.text = angle[2] + "";
            obj.eulerAngles = new Vector3( angle[1], angle[2], angle[0]);
        
    


3.效果

四、总结

以上仅是今天我们测试和展示的整体内容,陀螺仪设备的串口通信以及和Unity 3D的互动。
通过本次个人的体验,这款智能硬件模块可以比较稳定、实时的进行数据回传,精确控制3D场景中的物体
可以用在如定机位的游戏互动,比如线下捕鱼达人,望远镜、AR打怪之类的互动,如果您有什么新奇的想法,也可参与评论互动。

五、资源

传感器模块:淘宝链接
USB转TTL:淘宝链接

以上是关于Unity和智能硬件交互系列:MPU6050的主要内容,如果未能解决你的问题,请参考以下文章

HAL库硬件IIC_MPU6050_DMP移植

为啥mpu6050读出来全是0xff

Unity和智能硬件交互系列:互动风车

Unity和智能硬件交互系列:互动风车

STM32CubeMX移植MPU6050的DMP库读取角度信息

linux驱动之i2c子系统mpu6050设备驱动