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

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

代码也预留了:

相关推荐
一个小狼娃15 小时前
Android集成Unity避坑指南
android·游戏·unity
极客柒15 小时前
Unity 协程GC优化记录
java·unity·游戏引擎
黄思搏16 小时前
Unity SpriteRenderer 进度条 Shader 实现
unity·游戏引擎
猫屋小鱼丸17 小时前
手把手教你在unity中实现一个视觉小说系统(一)
unity
CHOTEST中图仪器20 小时前
3d光学轮廓仪如何局部测量标准台阶?
3d·光学轮廓仪·三维形貌·微观尺寸
国服第二切图仔21 小时前
Rust开发实战之简单游戏开发(piston游戏引擎)
开发语言·rust·游戏引擎
HahaGiver6661 天前
Unity与Android原生交互开发入门篇 - 打开Unity游戏的设置
android·unity·交互
@LYZY1 天前
Unity TextMeshPro 文本对齐方式详解
unity·游戏引擎·textmeshpro·tmp
在路上看风景1 天前
2.1 ShaderLab - 渲染状态
unity
AA陈超1 天前
虚幻引擎5 GAS开发俯视角RPG游戏 P07-06 能力输入的回调
c++·游戏·ue5·游戏引擎·虚幻