使用python将Spring物理应用于四元数
我想用python创建一个简单的物理系统,它以与使用python将Spring物理应用于四元数,python,numpy,physics,quaternions,Python,Numpy,Physics,Quaternions,我想用python创建一个简单的物理系统,它以与velocity/position类似的方式处理quaternions。它的主要目标是模拟一个被拖动的对象,并试图随着时间的推移赶上另一个对象。模拟使用3个变量:k:弹簧常数,d:阻尼系数,m:拖动对象的质量 使用经典的euler积分,我可以通过以下方法求解位置: import numpy as np from numpy.core.umath_tests import inner1d # init simulation values dt =
velocity/position
类似的方式处理quaternions
。它的主要目标是模拟一个被拖动的对象,并试图随着时间的推移赶上另一个对象。模拟使用3个变量:k
:弹簧常数,d
:阻尼系数,m
:拖动对象的质量
使用经典的euler积分,我可以通过以下方法求解位置:
import numpy as np
from numpy.core.umath_tests import inner1d
# init simulation values
dt = 1./30. # delta t @ 30fps
k = 0.5 # Spring constant
d = 0.1 # Damping
m = 0.1 # Mass
p_ = np.array([0,0,0]) # initial position of the dragged object
p = np.array([1,2,0]) # position to catch up to, in real life this value could change over time
v = np.array([0,0,0]) # velocity buffer (init speed is assumed to be 0)
# Euler Integration
n = 200 # loop over 200 times just to see the values converge
for i in xrange(n):
x = (p-p_)
F = (k*x - d*v) / m # spring force
v = v + F * dt # update velocity
p_ = p_ + v * dt # update dragged position
print p_ # values oscillate and eventually stabilize to p
这对职位很有用。通过更改k
、d
和m
我可以获得更快/更重的结果,总的来说,我对感觉很满意:
现在我想对四元数做同样的事情。因为我没有使用四元数
做物理的经验,所以我走了一条简单的道路,应用了相同的函数,并做了一些修改来处理四元数
翻转和规范化
# quaternion expressed as x,y,z,w
q_ = np.array([0., 0., 0., 1.]) # initial quaternion of the dragged object
q = np.array([0.382683, 0., 0., 0.92388]) # quaternion to catch up to (equivalent to xyz euler rotation of 45,0,0 degrees)
v = np.array([0.,0.,0.,0.]) # angular velocity buffer (init speed is assumed to be 0)
# Euler Intration
n = 200
for i in xrange(n):
# In a real life use case, q varies over time and q_ tries to catch up to it.
# Test to see if q and q_ are flipped with a dot product (innder1d).
# If so, negate q
if inner1d(q,q_) < 0:
q = np.negative(q)
x = (q-q_)
F = (k*x - d*v) / m # spring force
v = v + F * dt # update velocity
q_ = q_ + v * dt # update dragged quaternion
q_ /= inner1d(q_,q_) # normalize
print q_ # values oscillate and eventually stabilize to q
用x,y,z,w表示的四元数
q_u=np.数组([0,0,0,1.])#拖动对象的初始四元数
q=np.数组([0.382683,0,0,0.92388])#要赶上的四元数(相当于45,0,0度的xyz欧拉旋转)
v=np.数组([0,0,0,0.])#角速度缓冲器(初始速度假定为0)
#欧拉插管
n=200
对于x范围内的i(n):
#在现实生活中的用例中,q随时间而变化,q_uu试图跟上它。
#测试以查看q和q_是否用点积翻转(innder1d)。
#如果是,则否定q
如果inner1d(q,q_)<0:
q=np.负(q)
x=(q-q_389;)
F=(k*x-d*v)/m#弹簧力
v=v+F*dt#更新速度
q_=q_+v*dt#更新拖动的四元数
q_/=inner1d(q_,q_)#规格化
打印q#值振荡并最终稳定到q
令我大吃一惊的是,它给了我非常好的结果
因为我凭直觉行事,所以我确信我的解决方案是有缺陷的(比如q和q_是对立的),并且有一种正确/更好的方法来实现我想要的
问题:
模拟四元数上弹簧力的正确方法是什么?该方法考虑(至少)被拖动对象的质量、弹簧刚度和阻尼系数
非常感谢实际的python代码,因为我很难阅读博士论文:)。同样对于我通常提到的四元数
操作,但请在回答中随意使用任何其他操作。关于“模拟四元数上弹簧力的正确方法是什么”的问题,回答是正确地写下势能
orientation = vector_part(q_ r q_*)
其中恒星表示共轭,r是一个固定方向(例如“沿z的单位向量”,它在系统中对于所有对象都必须是唯一的)。假设q_,r和q_*的乘法是“四元数乘法”energy = dot_product(orientation, unit_z)
qinv = quaternion_inverse(q) # Using Gohlke's package
x = quaternion_multiply(q_, qinv)
现在,对于小的θ,theta=~sin(θ)
,只要差很小,这个x
与减法的结果没有太大差别。像这样滥用“小角度定理”通常用于所有类型的模拟,但重要的是要知道何时打破它们以及它对模型的限制
加速度和速度仍然在增加,所以我认为这仍然有效:
F = (k*x - d*v) / m
v = v + F * dt
组成单元旋转
q_ = quaternion_multiply(q_, unit_vector(v * dt)) # update dragged quaternion
同样,对于小角度(即与速度相比,dt
很小),总和和乘积非常接近
然后,如有必要,像以前一样正常化
q_ = unit_vector(q_)
我认为这应该行得通,但会比您以前的版本慢一点,并且可能会有非常相似的结果。我怀疑您在将四元数与numpy结合使用时领先于我们大多数人。我不确定如何正确地找到
v
,但x
可能应该与,而且q\uu
可能应该使用步进法;我想你偶然发现了一个四元数振荡器的快速数值近似。