一、代碼示例
def fix_range(x):
if x == 0:
return x
x %= 2*np.pi*x/abs(x)
x -= 2*np.pi*x/abs(x) if abs(x)>np.pi else 0
return x
二、推理過程:
我這里將轉換過程分為了兩步:
- 先轉到[-2pi, 2pi]
如果原弧度是正,則轉到[0,2*pi]:
if x>=0:
x = x%(2*np.pi)
如果是負,轉到[0,-2*pi]:
if x<0:
x = x%(-2*np.pi)
當x!=0, 則可以用*x/abs(x)表示x的正負。
合并后可去掉條件判斷:x %= 2*np.pi*x/abs(x) 。
-
再從[-2pi, 2pi] 到 [-pi, pi]
如果x>pi,那么它應該被修正到x-2pi;
如果x<-pi,應該修正到x+2pi。
依然是用*x/abs(x)影響式子的正負, 且用 x的絕對值跟pi比較來合并上述兩個條件。
合并后得到:x -= 2*np.pi*x/abs(x) if abs(x)>np.pi else 0
三、問題擴展
3.1 引入
上述問題其實是一個簡單問題。
我最初的想法其實是對任意兩個yaw角插值:
用線性插值就是:
- 求兩個yaw的差值delta_yaw, 和兩個yaw的時間差delta_t;
- yaw_rate = delta_yaw/delta_t;
- result = yaw1 + yaw_rate*(result_time-t1)
在駕駛場景,目標的yaw角取值范圍是[-pi, pi], 作為一個圓, -pi和pi其實一樣的,而且在此處取值連續(xù);但是在數(shù)值上,-pi和pi差了2pi。
這會造成一個問題:對于面對我們的目標,它的yaw角接近pi,如果前后的yaw角一個是接近pi的正數(shù),一個是接近-pi的負數(shù),我們期望的線性插值結果應該也是pi附近,但是如果直接用上述方法插值,會得到一個接近0的結果,相當于目標調了個頭。
3.2 一個可行解法
一個想法是先轉成四元數(shù),然后求delta_yaw:
rot_1 = Quaternion(axis=(0.0, 0.0, 1.0), radians=yaw_1).rotation_matrix
rot_2 = Quaternion(axis=(0.0, 0.0, 1.0), radians=yaw_2).rotation_matrix
delta_rot = rot_2 @ np.linalg.inv(rot_1)
yaw, _, _ = Quaternion(matrix=delta_rot).yaw_pitch_roll
但這樣做總覺得舍近求遠。
3.3 簡單解法
于是分情況討論:
- 出現(xiàn)上述情況其實主要是面對我們的目標,它們的yaw角以pi為中心左右擺動;
- 這種情況下,delta_yaw的絕對值接近2pi,假設把條件再放寬,可得到 abs(delta_yaw)>pi。
例如,yaw_1 = 170° , yaw_2 = -175° (用角度表示利于理解)。
delta_yaw = yaw_2 - yaw_1 = 345°, 但實際它應該是 15° (逆時針為正)。
其實就是: 360-abs(yaw_2-yaw_1)。
考慮反過來的情況,yaw_1 = -170° , yaw_2 = 175°, 差值應該是-15°。
其實就是:abs(yaw_2-yaw_1)-360.
以上,我們可以用代碼表示為:
delta_yaw = yaw_2 - yaw_1
if abs(delta_yaw)>np.pi:
delta_yaw = (abs(delta_yaw)-2*np.pi)*(delta_yaw/abs(delta_yaw))
式子右邊整理得到:
delta_yaw = delta_yaw-2*np.pi*delta_yaw/abs(delta_yaw)
即:
if abs(delta_yaw)>np.pi:
delta_yaw -= 2*np.pi*delta_yaw/abs(delta_yaw)
該表達式即上述的fix_range函數(shù)第二步的表達式。而delta_yaw本來就滿足第一步處理過后的條件。
也就是說,兩個yaw角的差值,也可以用上述fix_range函數(shù)修正為我們期望的值。
最后,經(jīng)過實驗,我發(fā)現(xiàn)兩個yaw角即使不滿足在[-pi, pi]取值,任意取值,他們的差值也能通過上述函數(shù)得到期望差值。
3.4 結論
對任意兩個yaw角插值問題,首先在第一步求delta_yaw時調用fix_range函數(shù),最終在正常差值得到y(tǒng)aw角之后,再調用一次fix_range函數(shù)對結果進行取值范圍修正即可。