This commit is contained in:
zhouyr9
2026-01-15 10:26:20 +08:00
parent fe2ebd6a70
commit 085b2032af
2 changed files with 74 additions and 56 deletions
Binary file not shown.
+68 -50
View File
@@ -1,7 +1,9 @@
import time import time
import krpc import krpc
import math
G_EARTH = 9.80665
def get_surface_speed(): def get_surface_speed():
conn = krpc.connect(name='Vessel speed') conn = krpc.connect(name='Vessel speed')
@@ -62,7 +64,31 @@ def vessel_available_thrust():
print('Vessel available thrust = %.1f kN' % (thrust / 1000)) print('Vessel available thrust = %.1f kN' % (thrust / 1000))
time.sleep(1) time.sleep(1)
def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=50000, target_altitude=0.5, target_vspeed=-2.0, safety_margin=5.0, verbose=True): def get_body_g(local_vessel):
try:
body = local_vessel.orbit.body
g = float(getattr(body, 'surface_gravity', G_EARTH))
if g > 0:
return g
except Exception:
pass
try:
g = float(getattr(local_vessel.flight(), 'surface_gravity', G_EARTH))
if g > 0:
return g
except Exception:
pass
return G_EARTH
def auto_land_predictive(
bottom_clearance_margin=12,
thrust_discount_wait=0.85,
host='localhost',
port=50000,
target_altitude=1.0,
target_vspeed=-1.0,
safety_margin=3.0,
verbose=True):
"""预测式自动着陆(suicide burn 思路)。 """预测式自动着陆(suicide burn 思路)。
关键点: 关键点:
@@ -83,14 +109,46 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
若需要更精细,可改成取 surface_velocity 向量的径向分量/或用垂直速度替代。 若需要更精细,可改成取 surface_velocity 向量的径向分量/或用垂直速度替代。
bottom_clearance_margin = 12 # m:按载具尺寸调整(越大越早开始末端减速) bottom_clearance_margin = 12 # m:按载具尺寸调整(越大越早开始末端减速)
"""
try:
import math
except Exception:
math = None
if krpc is None: 参数说明:
raise RuntimeError('krpc 未安装') bottom_clearance_margin (float):
- 单位:米(m)
- 说明:从雷达(bedrock_altitude)读取的高度中减去该几何余量以近似载具最低点到地面的距离。
用于避免脚本在实际着陆时因底部结构接触地面而过早判断已着陆。值越大会更早开始末端减速。
- 典型值:10~25,根据载具底部高度调整。
thrust_discount_wait (float):
- 单位:无(比例系数)
- 说明:在 WAIT 阶段估算可用推力时对 vessel.available_thrust 的折减因子。
会用 avail_thrust * thrust_discount_wait 来保守估算用于决定何时点火(补偿推力建立/响应延迟)。
- 取值范围:0.0~1.0;越小越保守(更早点火)。默认 0.85。
host (str) / port (int):
- 说明:连接 kRPC 服务的地址和 RPC 端口(用于 krpc.connect)。一般本地运行时用 'localhost' 和 50000。
target_altitude (float):
- 单位:米(m)
- 说明:目标的“触地点高度基准”,脚本在计算剩余高度时会把 radar_alt - bottom_clearance_margin 与此值比较。
通常设为想要在接触地面时的质心高度(或 0/地面高度上方的偏移)。
- 典型值:0~5(例如 3 表示目标在底部余量之上 3m 处被视为触地)。
target_vspeed (float):
- 单位:m/s(竖直速度,负值表示向下)
- 说明:期望的着陆竖直速度(向下为负)。脚本会把该值取绝对值作为目标的向下速度(vf_down)。
在计算刹车距离和 PID/前馈控制里以该目标速度为参考。
- 典型值:-0.5 ~ -1.5(更接近 0 的值更“柔和”但更难实现)。默认为 -1.0。
safety_margin (float):
- 单位:米(m)
- 说明:在刹车距离上再加的安全余量,用于补偿模型误差(如空气阻力、推力随时间变化等)。
- 典型值:几米(例如 3~10)。默认 5.
verbose (bool):
- 说明:是否打印并记录运行时信息到返回的 status['logs'],用于调试或观察倒计时/燃烧过程。
返回值:
返回一个 dict 格式的状态描述,包含 'result' 字段('failed' / 'landed' / 'touchdown_pending')和 'logs'(运行时消息列表)。
"""
conn = krpc.connect(name='auto_land_predictive', address=host, rpc_port=port) conn = krpc.connect(name='auto_land_predictive', address=host, rpc_port=port)
sc = conn.space_center sc = conn.space_center
@@ -102,7 +160,7 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
status = {'result': 'failed', 'logs': []} status = {'result': 'failed', 'logs': []}
# WAIT 阶段按折减推力估算刹车距离(提前点火,补偿点火/推力建立延迟) # WAIT 阶段按折减推力估算刹车距离(提前点火,补偿点火/推力建立延迟)
thrust_discount_wait = 0.85
# 低空/接地参数(用于“最后几米慢下来”) # 低空/接地参数(用于“最后几米慢下来”)
touchdown_vspeed_tol = 0.6 # m/s:认为“软着陆”的竖直速度容差 touchdown_vspeed_tol = 0.6 # m/s:认为“软着陆”的竖直速度容差
@@ -112,22 +170,6 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
# 由于 surface_altitude 近似是“载具质心高度”,末端会偏乐观。 # 由于 surface_altitude 近似是“载具质心高度”,末端会偏乐观。
# 用 bedrock_altitude(雷达高度)并减去一个底部几何余量,近似得到“最低点离地高度”。 # 用 bedrock_altitude(雷达高度)并减去一个底部几何余量,近似得到“最低点离地高度”。
def _get_g(local_vessel):
try:
body = local_vessel.orbit.body
g = float(getattr(body, 'surface_gravity', 9.81))
if g > 0:
return g
except Exception:
pass
try:
g = float(getattr(local_vessel.flight(), 'surface_gravity', 9.81))
if g > 0:
return g
except Exception:
pass
return 9.81
# 使用 body 的 reference_frame 读取 surface speed / vertical_speed(对应 get_surface_speed 思路) # 使用 body 的 reference_frame 读取 surface speed / vertical_speed(对应 get_surface_speed 思路)
try: try:
surface_frame = vessel.orbit.body.reference_frame surface_frame = vessel.orbit.body.reference_frame
@@ -152,19 +194,13 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
v_speed = float(getattr(flight, 'vertical_speed', 0.0)) v_speed = float(getattr(flight, 'vertical_speed', 0.0))
mass = float(getattr(vessel, 'mass', 0.0)) mass = float(getattr(vessel, 'mass', 0.0))
avail_thrust = float(getattr(vessel, 'available_thrust', 0.0)) avail_thrust = float(getattr(vessel, 'available_thrust', 0.0))
g_local = _get_g(vessel) g_local = get_body_g(vessel)
try:
situation_name = str(getattr(getattr(vessel, 'situation', None), 'name', '')) situation_name = str(getattr(getattr(vessel, 'situation', None), 'name', ''))
except Exception:
situation_name = ''
return alt, radar_alt, srf_speed, v_speed, mass, avail_thrust, g_local, situation_name return alt, radar_alt, srf_speed, v_speed, mass, avail_thrust, g_local, situation_name
try: try:
# 初始确保不点火 # 初始确保不点火
try:
vessel.control.throttle = 0.0 vessel.control.throttle = 0.0
except Exception:
pass
# 倒计时/等待点火 # 倒计时/等待点火
last_log_t = 0.0 last_log_t = 0.0
@@ -213,18 +249,9 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
break break
# 确保仍在滑行 # 确保仍在滑行
try:
vessel.control.throttle = 0.0 vessel.control.throttle = 0.0
except Exception:
pass
time.sleep(0.01) time.sleep(0.01)
# # 点火
# try:
# vessel.control.activate_next_stage()
# except Exception:
# pass
# 燃烧闭环:根据 remaining_alt 反推需要的减速度 -> 油门 # 燃烧闭环:根据 remaining_alt 反推需要的减速度 -> 油门
while True: while True:
alt, radar_alt, srf_speed, v_speed, mass, avail_thrust, g_local, situation_name = _read_state() alt, radar_alt, srf_speed, v_speed, mass, avail_thrust, g_local, situation_name = _read_state()
@@ -239,10 +266,7 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
# 因此要求:LANDED 且竖直速度足够小才结束 # 因此要求:LANDED 且竖直速度足够小才结束
is_landed = str(situation_name).strip().lower() == 'landed' is_landed = str(situation_name).strip().lower() == 'landed'
if is_landed and v_down <= (vf_down + float(touchdown_vspeed_tol)): if is_landed and v_down <= (vf_down + float(touchdown_vspeed_tol)):
try:
vessel.control.throttle = 0.0 vessel.control.throttle = 0.0
except Exception:
pass
status['result'] = 'landed' status['result'] = 'landed'
status['logs'].append('检测到 vessel.situation=LANDED 且竖直速度满足软着陆阈值,着陆完成') status['logs'].append('检测到 vessel.situation=LANDED 且竖直速度满足软着陆阈值,着陆完成')
if verbose: if verbose:
@@ -251,10 +275,7 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
# 兜底:极低高度 + 速度足够小(防止 situation 迟迟不切换导致卡死) # 兜底:极低高度 + 速度足够小(防止 situation 迟迟不切换导致卡死)
if remaining_alt <= max(0.2, float(target_altitude)) and v_down <= (vf_down + float(touchdown_vspeed_tol)): if remaining_alt <= max(0.2, float(target_altitude)) and v_down <= (vf_down + float(touchdown_vspeed_tol)):
try:
vessel.control.throttle = 0.0 vessel.control.throttle = 0.0
except Exception:
pass
status['result'] = 'touchdown_pending' status['result'] = 'touchdown_pending'
status['logs'].append('达到高度/速度阈值,但 vessel.situation 仍未变为 LANDED') status['logs'].append('达到高度/速度阈值,但 vessel.situation 仍未变为 LANDED')
if verbose: if verbose:
@@ -295,10 +316,7 @@ def auto_land_predictive(bottom_clearance_margin=12, host='localhost', port=5000
if is_landed and v_down > (vf_down + float(touchdown_vspeed_tol)): if is_landed and v_down > (vf_down + float(touchdown_vspeed_tol)):
throttle = max(throttle, 0.8) throttle = max(throttle, 0.8)
try:
vessel.control.throttle = throttle vessel.control.throttle = throttle
except Exception:
pass
if verbose: if verbose:
msg = ( msg = (