球坐标系

球坐标系是三维坐标系中的一种,在无人机中一般使用球坐标系来表示相机姿态,相机姿态的坐标是相对于无人机的,而无人机的飞行姿态则是相对于大地坐标系的。这里我们使用的相机是2自由度的相机,即可以水平 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针 和垂直 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_02 两个方向转动,其中 用平面直角坐标与无人机大地坐标系相互转换 python_坐标系_03用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_04用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_05,这里 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_06 为球半径(默认我们使用右手坐标系

用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_07


球坐标与笛卡尔坐标的转换

在后面的计算中因为球坐标不方便作旋转变换,我们需要用到球坐标与笛卡尔坐标的坐标转换

用平面直角坐标与无人机大地坐标系相互转换 python_坐标系_08

球坐标到笛卡尔坐标

用平面直角坐标与无人机大地坐标系相互转换 python_无人机_09

用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_10

用平面直角坐标与无人机大地坐标系相互转换 python_坐标系_11

笛卡尔坐标到球坐标

用平面直角坐标与无人机大地坐标系相互转换 python_坐标系_12

用平面直角坐标与无人机大地坐标系相互转换 python_无人机_13

用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_14

相机相对大地坐标系的姿态

为了计算方便,我们一般旋转坐标系将用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_15轴向下,这个时候无人机机头方向即是 用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_16 轴方向,用平面直角坐标与无人机大地坐标系相互转换 python_顺时针即是相对于无人机机头的相机水平旋转角度,用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_02在垂直于无人机方向上为0度;这时的无人机载体的坐标系就是我们常用的北东地坐标系(NED,即用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_16轴指向北,用平面直角坐标与无人机大地坐标系相互转换 python_无人机_20轴指向东,用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_15轴指向地面)。

用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_22

在无人机飞行中,无人机平台由于飞行运动及气流运动等因素,会影响无人机的飞行姿态,这时搭载的相机姿态相对大地坐标系会发生变化,需要加入无人机姿态去计算修正,以便于更准确计算相机的观测位置

无人机姿态一般包括3个角度即:偏航角(Yaw)、俯仰角(Pitch)、翻滚角(Roll)。偏行角一般指无人机相对北极的顺时针角度,也即整个坐标系沿 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_15 轴顺时针旋转的角度,俯仰角即飞机的攻角或者飞机机头的俯仰角,在上面的坐标系中是沿 用平面直角坐标与无人机大地坐标系相互转换 python_无人机_20 轴旋转的角度。翻滚角则是飞机左右倾斜的角度,在上面的坐标系中是沿 用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_16 轴旋转的角度。

用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_26


以上需要注意的是:偏航角与其他角不同,这里偏航角的旋转的角度是:用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_27,如上图,是3维坐标系的俯视图,蓝色坐标系即是无人机载体坐标系NED,黑色坐标系即是大地坐标系。所以这里无人机载体的坐标系是相对于大地坐标系顺时针旋转了用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_27度。另一个需要注意的是:最后得到的相机水平 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针 角度需要取反,即 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_30;因为NED坐标系和大地坐标系中用平面直角坐标与无人机大地坐标系相互转换 python_无人机_20轴是对称的,如:上图可将蓝色用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_16轴转到用平面直角坐标与无人机大地坐标系相互转换 python_无人机_33轴上,这时俩坐标系用平面直角坐标与无人机大地坐标系相互转换 python_无人机_20轴是对称的,所以角度是相反的。

三维空间的旋转矩阵

沿 用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_16

用平面直角坐标与无人机大地坐标系相互转换 python_无人机_36

沿 用平面直角坐标与无人机大地坐标系相互转换 python_无人机_20

用平面直角坐标与无人机大地坐标系相互转换 python_无人机_38

沿 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_15

用平面直角坐标与无人机大地坐标系相互转换 python_相机姿态_40

合并旋转后的三维旋转矩阵

用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_41

这里需要注意的是:1.旋转矩阵相乘的顺序,矩阵乘法不满足交换律,所以不同顺序一般最后得到的相机旋转角度不同(比较常用的顺序为 用平面直角坐标与无人机大地坐标系相互转换 python_坐标系_42用平面直角坐标与无人机大地坐标系相互转换 python_相机姿态_43,这个依赖于惯性测量单元(IMU)的姿态解算约定的旋转顺序 )。 2. 旋转方向,这里默认写的都是正向旋转。下面贴一下逆向的旋转矩阵作为参考:

沿 用平面直角坐标与无人机大地坐标系相互转换 python_旋转矩阵_16

用平面直角坐标与无人机大地坐标系相互转换 python_相机姿态_45

沿 用平面直角坐标与无人机大地坐标系相互转换 python_无人机_20

用平面直角坐标与无人机大地坐标系相互转换 python_无人机_47

沿 用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_15

用平面直角坐标与无人机大地坐标系相互转换 python_顺时针_49

很显然 用平面直角坐标与无人机大地坐标系相互转换 python_无人机_50,同理沿其他轴也是一样的,所以两种矩阵是形式等价的,只用一种就行了,注意旋转方向的正负。

代码实现

from math import *
import numpy as np

def rad(x):
    return radians(x)

def deg(x):
    return degrees(x)

def coord_sphere2cart(theta,phi, rho = 1):
    x = rho*sin(rad(theta))*cos(rad(phi))
    y = rho*sin(rad(theta))*sin(rad(phi))
    z = rho*cos(rad(theta))
    return x,y,z

def coord_cart2sphere(x,y,z):
    rho = sqrt(x**2+y**2+z**2)
    theta = acos(z/rho)
    phi = atan2(y,x)
    return rho,deg(theta),deg(phi)

def uav_rot(x,y,z,RX,RY,RZ):
    R = rad(RX) #Roll-X
    P = rad(RY) #Pitch-Y
    Y = rad(RZ) #Yaw-Z
    
    Rx = [[1,0,0],
          [0,cos(R),-sin(R)],
          [0,sin(R),cos(R)]]
    Ry = [[cos(P),0,sin(P)],
          [0,1,0],
          [-sin(P),0,cos(P)]]
    Rz = [[cos(Y),-sin(Y),0],
          [sin(Y),cos(Y),0],
          [0,0,1]]
    Rx = np.array(Rx)
    Ry = np.array(Ry)
    Rz = np.array(Rz)
    R3d = Rz @ Ry @ Rx
    xyz = np.array([x,y,z])
    return R3d @ xyz

def camera_rectify(pan,tilt,yaw,pitch,roll):
    x,y,z = coord_sphere2cart(theta=tilt,phi=pan,rho=1)
    x_,y_,z_ = uav_rot(x,y,z,RX=roll,RY=pitch,RZ=yaw)
    rho,theta,phi = coord_cart2sphere(x_,y_,z_)
    pan = phi
    tilt = theta
    return pan,tilt
    
def rot_mat_to_symbol():
    from sympy import Symbol,Matrix,sin,cos
    R = Symbol("R") #Roll-X
    P = Symbol("P")  #Pitch-Y
    Y = Symbol("Y") #Yaw-Z
    
    x = Symbol("x")
    y = Symbol("y")
    z = Symbol("z")
    xyz = Matrix([[x],[y],[z]])

    Rx = Matrix([[1,0,0],
                 [0,cos(R),-sin(R)],
                 [0,sin(R),cos(R)]
                ])

    Ry = Matrix([[cos(P),0,sin(P)],
                 [0,1,0],
                 [-sin(P),0,cos(P)],
                ])

    Rz = Matrix([[cos(Y),-sin(Y),0],
                 [sin(Y),cos(Y),0],
                 [0,0,1]
                ])

    res = Rz*Ry*Rx*xyz
    for a,m in zip(xyz,res):
        print(a,"=",m)

参考:

  1. Geometric transformations in 3D and coordinate frames