【Arduino】BNO085 姿态的 3D模型 展示方法(映射到 Unity)

总览

1.arduino 代码和库等...

2.Unity 的部分,创建一个 3D 工程,然后创建一个 cube,绑定一个脚本文件

3.效果预览:

【Arduino】BNO085 姿态的 3D模型 展示方法(映射到 Unity)

一、Arduino 部分

1.使用的硬件

· 单片机:使用了 ESP32S3,当然了,我没拿我的 atmega328P 去试,应该也可以。

· 使用的通讯方式:I2C

· 引脚连接方式:
ESP32S3 ----- ----- BNO085
3V3 ----- ----- VCC
GND ----- ----- GND
19 ----- ----- SDA
18 ----- ----- SCL
6 ----- ----- INT(看情况使用,我没使用)

2.软件部分

在使用此代码前,请搜索安装这个库:

代码片:

cpp 复制代码
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO08x.h>

#define BNO08X_INT_PIN 6  // 使用 GPIO 6 作为中断引脚
#define I2C_SCL_PIN 18
#define I2C_SDA_PIN 19

Adafruit_BNO08x bno;

void setup() {
  Serial.begin(115200);  // 设置串口波特率

  // 初始化 I2C 接口并指定引脚
  Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);

  // 使用 I2C 地址 0x4B 初始化 BNO085
  if (!bno.begin_I2C(0x4B)) {
    Serial.println("BNO085 I2C 初始化失败!");
    while (1);
  }
  Serial.println("BNO085 已经初始化");

  // 启用需要的传感器报告
  if (!bno.enableReport(SH2_GAME_ROTATION_VECTOR, 2500)) {
    Serial.println("无法启用旋转向量报告");
  }
}

void loop() {
  if (digitalRead(BNO08X_INT_PIN) == LOW) {
    sh2_SensorValue_t sensorValue;

    // 读取传感器数据
    if (bno.getSensorEvent(&sensorValue)) {
      if (sensorValue.sensorId == SH2_GAME_ROTATION_VECTOR) {
        // 获取旋转向量数据
        float rotationX = sensorValue.un.gameRotationVector.i;
        float rotationY = sensorValue.un.gameRotationVector.j;
        float rotationZ = sensorValue.un.gameRotationVector.k;

        // 通过串口发送数据到 Unity,格式为:ROTATION:X,Y,Z
        Serial.print("ROTATION:");
        Serial.print(rotationX); Serial.print(",");
        Serial.print(rotationY); Serial.print(",");
        Serial.print(rotationZ); Serial.println();
      }
    }
    
    delay(5);  // 添加延迟,越小精度越高且延迟越小,但负载也随之增加,个人建议 5 - 15 ms
  }
}

二、Unity 部分的操作

1.创建一个 3D 工程

你需要下载安装好 Unity,然后打开 Unity HUB 创建一个 3D 工程。

2.创建一个 立方体

创建流程:左上角 GameObject >> 3D Object >> Cube

3.设置立方体位置 && 摄像机位置

你也可以不按照我的来,只是后面的参数你也要自己进行校准了。

· 立方体

· 摄像机

4.创建脚本文件

这是一个用于接收串口数据的脚本文件。
它的功能是接收单片机的串口数据,并且将弧度数据转为角度,映射在 cube 立方体上,实现姿态传感器可视化。

文件名:SerialReader.cs

编辑脚本文件代码(一般来说,我们使用 visual studio 打开它):

代码片:

csharp 复制代码
using System;
using System.IO.Ports;
using UnityEngine;

public class SerialReader : MonoBehaviour
{
    SerialPort serial = new SerialPort("COM3", 115200);  // 请确认COM端口
    public GameObject sensorObject;  // 3D模型对象

    // 放大比
    // 规则说明:越大,立方体就越容易转动,越小就越不容易转动。
    // 需要手动调节精度以配合 BNO085 的真实动作。
    public float rotationMultiplier = 2.2f;

    // 平滑过渡因子
    // 规则说明:调节区间为( 0.0 ,1.0 ]
    // 越大,平滑效果就越差,但是延迟越低;越小,平滑效果越好,但是延迟增高。
    // 个人建议 0.5,如果觉得卡顿就 0.2,如果想要延迟更低就0.7
    public float smoothingFactor = 0.5f;     

    private Quaternion targetRotation;       // 目标旋转角度

    void Start()
    {
        Debug.Log("SerialReader script started!");

        try
        {
            serial.Open();
            serial.ReadTimeout = 100;
            Debug.Log("UART has opened!");

            // 初始化目标旋转
            targetRotation = sensorObject.transform.rotation;
        }
        catch (Exception e)
        {
            Debug.LogError("Error, can't open UART: " + e.Message);
        }
    }

    void Update()
    {
        if (serial.IsOpen)
        {
            try
            {
                string data = serial.ReadLine();
                Debug.Log("Received data: " + data);
                if (data.StartsWith("ROTATION:"))
                {
                    string[] values = data.Substring(9).Split(',');

                    // 反转 X 轴,并交换 Y 轴和 Z 轴
                    float rotX = -Mathf.Rad2Deg * float.Parse(values[0]) * rotationMultiplier;  // 反转X轴
                    float rotY = -Mathf.Rad2Deg * float.Parse(values[2]) * rotationMultiplier;   // 将Z轴数据用作Y轴
                    float rotZ = -Mathf.Rad2Deg * float.Parse(values[1]) * rotationMultiplier;   // 将Y轴数据用作Z轴

                    // 计算目标旋转
                    targetRotation = Quaternion.Euler(rotX, rotY, rotZ);
                }
            }
            catch (TimeoutException)
            {
            }
        }

        // 使用 Slerp 平滑过渡到目标旋转
        sensorObject.transform.rotation = Quaternion.Slerp(sensorObject.transform.rotation, targetRotation, smoothingFactor);
    }

    void OnApplicationQuit()
    {
        if (serial.IsOpen)
        {
            serial.Close();
        }
    }
}

5.保存,不需要退出 visual studio

6.关联 cube 和 我们刚才创建的脚本文件 SerialReader.cs

点击立方体 >> 点击右侧最下栏的 "Add Component" >> 搜索 serial >> 选择 "Serial Reader"

点这个小圆点,然后选定我们的 cube

7.开始 RUN

至此,所有配置已结束,RUN 一下吧
请注意,如果大家在 RUN 的时候发现 cube 的动作太小,请关闭 Unity 程序,重新打开一次再运行

三、后记

1.如果我们旋转 BNO085 的角度 和 Unity 中 Cube 立方体的角度对不上怎么办?

代码中已经给大家留了可以手动调节放大比的地方。

2.立方体卡顿 || 有延迟怎么办

卡顿和延迟成反比关系,通过调节平滑因子来调节两者到合适的情况。

代码也预留了:

相关推荐
飞浪纪元[FWC–FE]14 小时前
【无标题】
unity·游戏引擎
红黑色的圣西罗16 小时前
对象池简述
unity·c#
水龙吟啸16 小时前
基于Orbbec-Gemini深度相机与SFM-2D to 3D重建算法、手部识别视觉算法、Unity运动控制的3D水果切割游戏
python·深度学习·神经网络·c#·游戏引擎·3d视觉·3d重建
zl_vslam19 小时前
SLAM中的非线性优-3D图优化之相对位姿Between Factor位姿图优化(十三)
人工智能·算法·计算机视觉·3d
军军君0120 小时前
Three.js基础功能学习五:雾与渲染目标
开发语言·前端·javascript·学习·3d·前端框架·three
资讯雷达21 小时前
工业扫描选型指南:蓝光 3D 扫描仪哪个品牌更靠谱?
3d
淡海水1 天前
【节点】[Texture2DAsset节点]原理解析与实际应用
unity·游戏引擎·shadergraph·图形·texture2dasset
向宇it1 天前
【unity游戏开发——网络】unity+PurrNet联机实战,实现一个多人对战类《CS/CSGO》《CF/穿越火线》《PUBG/吃鸡》的FPS射击游戏
游戏·unity·游戏引擎·交互·联机
旧梦吟1 天前
脚本网页 双子星棋
算法·flask·游戏引擎·css3·html5
gshh__1 天前
SuperMap Hi-Fi 3D SDK for Unreal 如何修改模型选中高亮颜色
ue5·游戏引擎·supermap