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

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

代码也预留了:

相关推荐
AI_Auto20 小时前
【智能制造】- 工业制造中的3D视觉四大核应用场景
3d·制造
la_vie_est_belle1 天前
Pygame Studio——用Python自制的一款可视化游戏编辑器
python·游戏·编辑器·游戏引擎·pygame·pyside6·pygame-ce
ZC跨境爬虫1 天前
跟着 MDN 学 HTML day_16:(音频与视频处理——从画布滤镜到3D沉浸音频的进阶指南)
前端·javascript·ui·3d·html·音视频
LF男男2 天前
GameManager.cs
unity
晴夏。2 天前
c++调用lua的方法
c++·游戏引擎·lua·ue
RPGMZ3 天前
RPGMakerMZ 地图存档点制作 标题继续游戏直接读取存档
开发语言·javascript·游戏·游戏引擎·rpgmz·rpgmakermz
爱看书的小沐3 天前
【小沐杂货铺】基于Three.js绘制三维艺术画廊3DArtGallery (Three.js,WebGL)
javascript·3d·webgl·three.js·babylon.js·三维画廊
格林威3 天前
3D相机视觉检测:环境光太强,结构光点云全是噪点怎么办?
开发语言·人工智能·数码相机·计算机视觉·3d·视觉检测·工业相机
郝学胜-神的一滴3 天前
[简化版 GAMES 101] 计算机图形学 07:图形学投影完全推导
c++·unity·图形渲染·three.js·unreal engine
threelab3 天前
Three.js 3D 饼图效果 | 三维可视化 / AI 提示词
javascript·人工智能·3d