STM32
直播中

唯爱萌meng

9年用户 1020经验值
擅长:可编程逻辑
私信 关注
[问答]

如何使用六轴传感器去实现串口与Unity3D的通信呢

什么是陀螺仪?

三轴陀螺仪和六轴陀螺仪的区别在哪?
如何使用六轴传感器去实现串口与Unity3D的通信呢?

回帖(1)

黄飞高

2021-11-9 09:15:25
  一、陀螺仪传感器
  陀螺仪:
  是一种用来感测与维持方向的装置,基於角动量不灭的理论设计出来的。 陀螺仪一旦开始旋转,由於轮子的角动量,陀螺仪有抗拒方向改变的趋向。一般在无人机、平衡车上使用,我们再用个各种型号手机,基本都包含这个组件。
  三轴陀螺仪和六轴的区别
  三轴陀螺仪是分别感应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打怪之类的互动,如果您有什么新奇的想法,也可参与评论互动。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分