下位机读取传感器四元数(四元数是一种用于表示三维空间中旋转的方法,它由一个实部和三个虚部组成),通过串口读取数据并更新 Blender 中的骨骼(Armature)的旋转。代码结合了 Blender 的 Python API 和串口通信,主要用于将外部设备(如传感器或运动捕捉系统)的数据映射到 Blender 中的骨骼上。
一.功能概述
下位机读取传感器四元数(四元数是一种用于表示三维空间中旋转的方法,它由一个实部和三个虚部组成),通过串口读取数据并更新 Blender 中的骨骼(Armature)的旋转。这段代码结合了 Blender 的 Python API 和串口通信,主要用于将外部设备(如传感器或运动捕捉系统)的数据映射到 Blender 中的骨骼上。跟上一篇帖子不一样的是这一篇处理了10个关节的数据,上一篇只处理了2个。本篇将代码集成在一个python file中,代码解释会比上一篇更加详细。下位机代码在上上篇帖子。
上一篇帖子里面有关于使用四元数控制骨骼旋转的详细解释,在这里就不赘述了,导航:Blender使用脚本控制骨骼旋转1.0
二.代码解析部分
1.导入必要的库
这些库包括Blender的API、时间处理、系统操作、串口通信和科学计算等。
import bpy
import time
import sys
import serial
import glob
import numpy as np
bpy
: Blender的Python API,用于操控Blender环境。time
: 时间相关的操作。sys
: 系统级操作,如修改路径。serial
: 用于串口通信。glob
: 文件路径操作,但在本代码中未实际使用。numpy
: 科学计算库,主要用于四元数运算。
2.串口配置
设置串口端口和波特率,并尝试打开串口。
FPS = 60
# 串口配置
port = 'COM10' # 指定串口号,根据实际情况修改
baudrate = 57600 # 波特率,根据实际情况修改
# 创建串口对象
ser = serial.Serial(port, baudrate, timeout=1)
if ser.isOpen():
print(f"串口 {
port} 已打开,波特率 {
baudrate}")
else:
print(f"无法打开串口 {
port}")
- 设置帧率
FPS
为60。 - 配置串口端口
port
和波特率baudrate
,并尝试打开串口。如果成功打开,打印成功信息,否则打印失败信息。
3.获取Blender场景和骨骼对象与骨骼的具体部分
获取当前Blender场景和名为“骨架”的骨骼对象。
# # Get the whole bge scene
# scene = bge.logic.getCurrentScene()
# # Helper vars for convenience
# source = scene.objects
# # Get the whole Armature
# main_arm = source.get('Armature')
# ob = bge.logic.getCurrentController().owner
# 获取当前场景
scene = bpy.context.scene
# 获取 'Armature' 骨骼对象
armature = bpy.data.objects["骨架"]
# 获取当前对象(这里假设是骨骼对象的所有者,可以根据实际情况修改)
ob = bpy.context.active_object
# get the bones we need
bone_upper_arm_R = armature.pose.bones.get("armUp.R")
bone_lower_arm_R = armature.pose.bones.get("armDown.R")
bone_upper_arm_L = armature.pose.bones.get("armUp.L")
bone_lower_arm_L = armature.pose.bones.get("armDown.L")
bone_trunk = armature.pose.bones.get("trunk.001")
bone_head = armature.pose.bones.get("head.001")
bone_upper_leg_R = armature.pose.bones.get("legUp.R.001")
bone_lower_leg_R = armature.pose.bones.get("legDown.R.001")
bone_upper_leg_L = armature.pose.bones.get("legUp.L.001")
bone_lower_leg_L = armature.pose.bones.get("legDown.L.001")
- 获取当前Blender场景。
- 获取名为
骨架
的骨骼对象。 - 获取当前活动对象。
4.定义四元数运算函数
四元数乘法函数,用于旋转计算。
def multiplyQuaternion(q1, q0):
w0, x0, y0, z0 = q0
w1, x1, y1, z1 = q1
return np.array([-x1 * x0 - y1 * y0 - z1 * z0 + w1 * w0,
x1 * w0 + y1 * z0 - z1 * y0 + w1 * x0,
-x1 * z0 + y1 * w0 + z1 * x0 + w1 * y0,
x1 * y0 - y1 * x0 + z1 * w0 + w1 * z0], dtype=np.float64)
5.设置骨骼旋转的函数
根据四元数设置骨骼的旋转。
def setBoneRotation(bone, rotation):
w, x, y, z = rotation
bone.rotation_quaternion[0] = w
bone.rotation_quaternion[1] = x
bone.rotation_quaternion[2] = y
bone.rotation_quaternion[3] = z
关于四元数控制骨骼旋转看上一篇就行,这里不再赘述。导航一下:Blender使用脚本控制骨骼旋转1.0
6.更新角度的函数(!!重点!!)
根据从串口接收到的数据更新骨骼的旋转。该函数 updateAngles 是整个代码的核心之一。它的作用是将从串口接收到的角度数据应用到Blender中的骨骼Armature
上。具体来说,它首先将输入的角度数据转换为适当的格式,然后计算各个骨骼部分的相对旋转,并最终将这些旋转应用到相应的骨骼上。
①将角度数据转换位NumPy数组:
- 以便进行后续的四元数运算。
lowerarmR_out = np.array([angles[0][0], angles[0][1], angles[0][2], angles[0][3]])
... ...
②计算各个骨骼部分的相对旋转:
trunk_inv
是trunk_out
的共轭四元数,用于计算head_rel
。head_rel
是头部相对于躯干的旋转。upperarmR_inv
是右上臂的共轭四元数,用于计算lowerarmR_rel
。- 依此类推,计算其他骨骼部分的相对旋转。
trunk_inv = trunk_out * np.array([1, -1, -1, -1])
head_rel = multiplyQuaternion(trunk_inv, head_out)
upperarmR_inv = upperarmR_out * np.array([1, -1, -1, -1]