簡體   English   中英

GEKKO如何解決一個最優的月球軟着陸問題?

[英]GEKKO how to solve a optimal lunar soft landing problem?

我試圖通過 GEKKO 解決 2D 最優月球軟着陸問題。 我假設月亮沒有旋轉。 飛船在月球表面軟着陸,即最終垂直速度v和最終水平速度u應為零,最終高度r應為月球半徑。

問題可以說明如下:

在此處輸入圖像描述

state 和控制變量以及方程如下(控制變量為推力F和姿態角φ ):

在此處輸入圖像描述

我構造了燃料最優問題如下(控制變量φ寫為f ):

from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
import time
import os

r0=1753000
v0=1675

time_start = time.time()

model = GEKKO()
nt = 501
model.time = np.linspace(0,1,nt)

# optimize final time
tf = model.FV(value=1.0,lb=0.1,ub=1000.0)
tf.STATUS = 1

# controls
F = model.MV(value=0,lb=0,ub=2000)
F.STATUS = 1
f = model.MV(value=-0.5*np.pi,lb=-0.5*np.pi,ub=0.5*np.pi)
f.STATUS = 1

# state variables
r = model.Var(value=r0,lb=1738000) # height
s = model.Var(value=0) # tru anomaly
v = model.Var(value=0) # vertical velocity
u = model.Var(value=v0) # horizional velocity
m = model.Var(value=600,lb=0,ub=600) # mass

# constants
mu = 4.90275*10**(12) # lunar gravitational constant
Isp = 300*9.8 # specific impulse

# Equations
model.Equation( r.dt() == tf * v )
model.Equation( s.dt() == tf * u/r )
model.Equation( v.dt() == tf * (F/m*model.cos(f)-mu/(r**2)+u**2/r) )
model.Equation( u.dt() == tf * (F/m*model.sin(f)-u*v/r) )
model.Equation( m.dt() == tf * (-F/Isp) )

# terminal constraints
_finalMask = np.zeros(nt)
_finalMask[-1] = 1.0
finalMask = model.Param(value=_finalMask)
model.Equation(v*finalMask>=0)
model.Equation(v*finalMask<=0.5)
model.fix_final(r,val=1738000)
model.fix_final(u,val=0)

model.Obj(-m*finalMask) # Objective function to be minimized

model.options.IMODE = 6
model.solver_options = ['max_iter 5000']
model.solve() # solve

time_end=time.time()
print('Calculation Time: ',time_end-time_start)

# scaled time
print('Landing Time: ' + str(tf.value[0]))
tm = np.linspace(0,tf.value[0],nt)
finaltime = tm[-1]

# PLOT
fig = plt.figure(1)
ax1 = fig.add_subplot(2, 3, 1)
ax2 = fig.add_subplot(2, 3, 2)
ax3 = fig.add_subplot(2, 3, 3)
ax4 = fig.add_subplot(2, 3, 4)
ax5 = fig.add_subplot(2, 3, 5)
ax6 = fig.add_subplot(2, 3, 6)
ax1.plot(tm,r.value,'k-',label=r'$r$')
ax1.set_xlabel('Time')
ax1.set_ylabel('r')
ax1.set_xlim(0,finaltime)
ax2.plot(tm,v.value,'b-',label=r'$v$')
ax2.set_xlabel('Time')
ax2.set_ylabel('v')
ax2.set_xlim(0,finaltime)
ax3.plot(tm,u.value,'g-',label=r'$w$')
ax3.set_xlabel('Time')
ax3.set_ylabel('u')
ax3.set_xlim(0,finaltime)
ax4.plot(tm,m.value,'y-',label=r'$m$')
ax4.set_xlabel('Time')
ax4.set_ylabel('m')
ax4.set_xlim(0,finaltime)
ax5.plot(tm,f.value,'c-',label=r'$f$')
ax5.set_xlabel('Time')
ax5.set_ylabel('f')
ax5.set_xlim(0,finaltime)
ax6.plot(tm,F.value,'r-',label=r'$F$')
ax6.set_xlabel('Time')
ax6.set_ylabel('F')
ax6.set_xlim(0,finaltime)
plt.tight_layout()
plt.show()

它可以找到與其他研究非常相似的解決方案。

在此處輸入圖像描述

但是f有一個急轉彎。 這是不可接受的,因為角度φ應該不斷變化。

另外,我嘗試縮放 function

scale = 1e-6
model.Equation( r.dt() == tf * v )
model.Equation( r*s.dt()*scale == tf * u*scale )
model.Equation( m*(r**2)*v.dt()*scale**2 == tf * ((r**2)*F*model.cos(f)-mu*m+(u**2)*r*m)*(scale**2) )
model.Equation( m*r*u.dt()*scale == tf * (F*r*model.sin(f)-u*v*m)*scale )
model.Equation( Isp*m.dt() == tf * (-F) )

但失敗了

Solution Not Found
EXIT: Converged to a point of local infeasibility. Problem may be infeasible.

為了獲得平滑的f ,我將第二個控制變量更改為 angular 加速度a ,並且 state 方程變為

在此處輸入圖像描述

代碼變成了:

from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
import time
import os

r0=1753000
v0=1675

time_start = time.time()

model = GEKKO() # remote=False
nt = 501
model.time = np.linspace(0,1,nt)

tf = model.FV(value=1.0,lb=0.1,ub=1000.0)
tf.STATUS = 1

# controls
F = model.MV(value=0,lb=0,ub=2000)
F.STATUS = 1
a = model.MV(value=0,lb=-0.5*np.pi/180,ub=0.5*np.pi/180)
a.STATUS = 1

# state variables
r = model.Var(value=r0,lb=1738000) # height
s = model.Var(value=0) # tru anomaly
v = model.Var(value=0) # vertical velocity
u = model.Var(value=v0) # horizional velocity
f = model.Var(value=-0.5*np.pi) # angle
w = model.Var(value=0, lb=-10*np.pi/180,ub=10*np.pi/180) # angular velocity
m = model.Var(value=600,lb=0,ub=600) # mass

# constants
mu = 4.90275*10**(12) # lunar gravitational constant
Isp = 300*9.8 # specific impulse

# Equations
model.Equation( r.dt() == tf * v )
model.Equation( s.dt() == tf * u/r )
model.Equation( v.dt() == tf * (F/m*model.cos(f)-mu/(r**2)+u**2/r) )
model.Equation( u.dt() == tf * (F/m*model.sin(f)-u*v/r) )
model.Equation( f.dt() == tf * (w - u/r) ) # ---newly added
model.Equation( w.dt() == tf * a ) # ---newly added
model.Equation( m.dt() == tf * (-F/Isp) )

# terminal constraints
_finalMask = np.zeros(nt)
_finalMask[-1] = 1.0
finalMask = model.Param(value=_finalMask)
model.Equation(v*finalMask>=0)
model.Equation(v*finalMask<=0.5)
model.Equation(f*finalMask>=-5*np.pi/180) # ***newly added
model.Equation(f*finalMask<=5*np.pi/180) # ***newly added
model.fix_final(r,val=1738000)
model.fix_final(u,val=0)

model.Obj(-m*finalMask) # Objective function to be minimized

model.options.IMODE = 6
model.solver_options = ['max_iter 99999']
model.solve() # solve

time_end=time.time()
print('Calculation Time: ',time_end-time_start)

# scaled time
print('Landing Time: ' + str(tf.value[0]))
tm = np.linspace(0,tf.value[0],nt)
finaltime = tm[-1]

# PLOT
fig = plt.figure(1)
ax1 = fig.add_subplot(2, 4, 1)
ax2 = fig.add_subplot(2, 4, 2)
ax3 = fig.add_subplot(2, 4, 3)
ax4 = fig.add_subplot(2, 4, 4)
ax5 = fig.add_subplot(2, 4, 5)
ax6 = fig.add_subplot(2, 4, 6)
ax7 = fig.add_subplot(2, 4, 7)
ax8 = fig.add_subplot(2, 4, 8)
ax1.plot(tm,r.value,'k-',label=r'$r$')
ax1.set_xlabel('Time')
ax1.set_ylabel('r')
ax1.set_xlim(0,finaltime)
ax2.plot(tm,v.value,'b-',label=r'$v$')
ax2.set_xlabel('Time')
ax2.set_ylabel('v')
ax2.set_xlim(0,finaltime)
ax3.plot(tm,u.value,'g-',label=r'$u$')
ax3.set_xlabel('Time')
ax3.set_ylabel('u')
ax3.set_xlim(0,finaltime)
ax4.plot(tm,m.value,'y-',label=r'$m$')
ax4.set_xlabel('Time')
ax4.set_ylabel('m')
ax4.set_xlim(0,finaltime)
ax5.plot(tm,F.value,'r-',label=r'$F$')
ax5.set_xlabel('Time')
ax5.set_ylabel('F')
ax5.set_xlim(0,finaltime)
ax6.plot(tm,f.value,'k-',label=r'$f$')
ax6.set_xlabel('Time')
ax6.set_ylabel('f')
ax6.set_xlim(0,finaltime)
ax7.plot(tm,w.value,'b-',label=r'$w$')
ax7.set_xlabel('Time')
ax7.set_ylabel('w')
ax7.set_xlim(0,finaltime)
ax8.plot(tm,a.value,'r-',label=r'$a$')
ax8.set_xlabel('Time')
ax8.set_ylabel('a')
ax8.set_xlim(0,finaltime)
plt.tight_layout()
plt.show()

但是,我已經運行代碼很多小時,但沒有得到解決方案或結果。 更具體地說,它在某些迭代處停止:

在此處輸入圖像描述

我嘗試使用軟終端約束,但也沒有得到任何結果:

model.Equation(r*finalMask>=1738000)
model.Equation(r*finalMask<=1738001)
model.Equation(v*finalMask>=0)
model.Equation(v*finalMask<=0.5)
model.Equation(u*finalMask>=-0.5)
model.Equation(u*finalMask<=0.5)
model.Equation(f*finalMask>=-5*np.pi/180)
model.Equation(f*finalMask<=5*np.pi/180)

我無法讓您的代碼運行,因為w未定義,但可能已更改為u 此外,還有很多地方需要用分號來分隔同一行中的語句。 我試圖獲得一個可以運行但尚未成功的版本。 您能否驗證發布的代碼是否運行以顯示您描述的問題,或者發布您的更新代碼並成功運行?

我修改了方程式以與您的問題陳述保持一致,並避免除以零時可能出現的潛在問題。 我還包括了一個比例因子,因為一些方程的r**2是一個非常大的數字。

# equations
scale = 1e-6
model.Equation( r.dt() == tf * v )
model.Equation( r * s.dt()*scale == tf * u*scale )
model.Equation( m * (r**2) * v.dt() * scale**2 \
                == tf * ((r**2)*F*model.cos(f)-mu+(u**2)*(r**3)) *(scale**2))
model.Equation( m * r * u.dt()*scale == tf * (-u*v*m+F*model.cos(f))*scale )
model.Equation( Isp * m.dt() == -tf * F )
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt

model = GEKKO() # initialize gekko
nt = 501
model.time = np.linspace(0,1,nt)

# optimize final time
tf = model.FV(value=100.0,lb=1.0,ub=1000.0)
tf.STATUS = 1

# controls
F = model.MV(value=0,lb=0,ub=1500)
F.STATUS = 1
f = model.MV(value=0,lb=-0.5*np.pi,ub=0.5*np.pi)
f.STATUS = 1

# state variables
# height = 1753 km
r = model.Var(value=1753000,lb=1738000) 
# vertical velocity = 0 m/s
v = model.Var(value=0)
# azimuth = 0 rad
s = model.Var(value=0)
# azimuth angular velocity rad/s
u = model.Var(value=9.65e-4)
# mass = 600 kg
m = model.Var(value=600,lb=0,ub=600) 

# constants
mu = 4.90275e12 # lunar gravitational constant
Isp = 300*9.8 # specific impulse

# equations
scale = 1e-6
model.Equation( r.dt() == tf * v )
model.Equation( r * s.dt()*scale == tf * u*scale )
model.Equation( m * (r**2) * v.dt() * scale**2 \
                == tf * ((r**2)*F*model.cos(f)-mu+(u**2)*(r**3)) *(scale**2))
model.Equation( m * r * u.dt()*scale == tf * (-u*v*m+F*model.cos(f))*scale )
model.Equation( Isp * m.dt() == -tf * F )

# terminal conditions
_finalMask = np.zeros(nt)
_finalMask[-1] = 1.0
finalMask = model.Param(value=_finalMask)

# Terminal Constraint 1
if False:
    model.Equation((r-1738000)*finalMask==0)
    model.Equation(v*finalMask==0)
    model.Equation(u*finalMask==0)

# Terminal Constraint 2
if False:
    model.Equation((r-1738000)*finalMask<=0)
    model.Equation(v*finalMask<=0)
    model.Equation(u*finalMask<=0)

if True:
    # terminal constraints
    _finalMask = np.zeros(nt)
    _finalMask[-1] = 1.0
    finalMask = model.Param(value=_finalMask)
    model.Equation(v*finalMask>=0)
    model.Equation(v*finalMask<=0.2)
    model.fix_final(r,val=1738000)
    model.fix_final(u,val=0)

model.Minimize(tf)
model.options.IMODE = 6
model.solve()

print('Final Time: ' + str(tf.value[0]))
tm = np.linspace(0,tf.value[0],nt)

# PLOT
fig = plt.figure(1)
ax1 = fig.add_subplot(2, 3, 1)
ax2 = fig.add_subplot(2, 3, 2)
ax3 = fig.add_subplot(2, 3, 3)
ax4 = fig.add_subplot(2, 3, 4)
ax5 = fig.add_subplot(2, 3, 5)
ax6 = fig.add_subplot(2, 3, 6)
ax1.plot(tm,r.value,'k-',label=r'$r$')
ax1.set_xlabel('Time'); ax1.set_ylabel('r')
ax2.plot(tm,v.value,'b-',label=r'$v$')
ax2.set_xlabel('Time'); ax2.set_ylabel('v')
ax3.plot(tm,s.value,'g-',label=r'$s$')
ax3.set_xlabel('Time'); ax3.set_ylabel('s')
ax4.plot(tm,f.value,'y-',label=r'$f$')
ax4.set_xlabel('Time'); ax4.set_ylabel('f')
ax5.plot(tm,F.value,'c-',label=r'$F$')
ax5.set_xlabel('Time'); ax5.set_ylabel('F')
ax6.plot(tm,m.value,'r-',label=r'$m$')
ax6.set_xlabel('Time'); ax6.set_ylabel('m')
plt.tight_layout()
plt.show()

如果所有變量都在 1 附近並且方程殘差從大約相同的水平開始,則數值解更容易求解。 Gekko 根據初始條件自動縮放變量。

正如您所觀察到的,找到一個小范圍內的解決方案比准確地達到一個精確的最終條件更容易。 另一件有幫助的事情是包括一個目標(軟約束)和等式約束(硬約束)。 這種組合通常更適用於這些類型的最終時間可調整的終端約束問題。

您可能還想使用指定的最終時間進行初始化,然后再次求解。 您可以關閉自由度,例如:

# solve first time without adjustable tf
tf.STATUS = 0
model.solve()

# solve again with tf adjustable
tf.STATUS = 1
# don't advance the initial condition
model.options.TIME_SHIFT=0
model.solve()

另一種選擇是使用F.UPPER=1500求解,然后嘗試F.UPPER=2000進行另一個求解。 Jennings 最優控制問題是另一個可能有幫助的例子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM