【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.立方体卡顿 || 有延迟怎么办

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

代码也预留了:

相关推荐
Tian_Hang1 小时前
eclipse ditto 学习笔记
运维·服务器·开发语言·javascript·3d
AI视觉网奇4 小时前
BambuStudio 编译实战 2026
3d
AI前沿资讯4 小时前
AI3D角色生产如何减少返工?用 V2Fun 前移建模与动画流程
人工智能·3d
蓝速科技5 小时前
蓝速科技视觉 3D 全息舱 AI 数字人一体机带灯与无灯款深度评测
人工智能·科技·3d
yangmu32035 小时前
《星露谷物语》MOD配置与实战安装综合指南
游戏·游戏引擎·游戏程序
xcLeigh5 小时前
Unity基础:Game视图详解——游戏预览、分辨率模拟与性能显示
游戏·unity·游戏引擎·音频·视频·game·play模式
ZJU_fish19966 小时前
全局光照/阴影的几个常见问题
游戏引擎·图形渲染
IT·陈寒7 小时前
Superpowers 游戏引擎核心应用场景与落地指南
游戏引擎
xcLeigh16 小时前
Unity基础:Scene视图操作完全指南——视角控制、物体选择与场景导航
unity·游戏引擎·scene·试图·场景导航
mxwin20 小时前
Unity Shader exp 函数的算法与渲染应用
算法·unity·游戏引擎·shader