本翻译基于 [kRPC 官方文档](https://krpc.github.io/krpc),遵循 LGPL v3 许可。 部分内容可能受 GPLv3 或 MIT 许可约束,详见原始仓库。 Copyright 2015-2023 kRPC Org.
本教程和示例脚本合集详细说明了如何使用 kRPC 的功能特性。
参考系
介绍
kRPC 中的所有位置、方向、速度和旋转都是相对于某个参考系而言的,而*参考系*定义了这些"某个参考系"是什么。
一个参考系规定了:
- 原点 (0,0,0) 的位置
- 坐标轴 x、y、z 的方向
- 原点的线速度(如果参考系移动的话)
- 坐标轴的角速度(轴旋转的速度和方向)
注意:KSP 和 kRPC 使用左手坐标系
原点位置和轴方向
下面给出了一些不同参考系的原点位置和坐标轴方向的例子。
天体参考系
通过调用 Kerbin 的CelestialBody.reference_frame获得的参考系具有以下属性:
- 原点位于 Kerbin 的中心,
- y 轴从 Kerbin 中心指向北极,
- x 轴从 Kerbin 中心指向本初子午线与赤道的交点(0°经度、0°纬度的地表位置),
- z 轴从 Kerbin 中心指向东经 90° 的赤道位置,
- 坐标轴随行星旋转,即该参考系与 Kerbin 有相同的旋转/角速度。
这意味着该参考系相对于 Kerbin 是“固定的”——它随行星中心移动,也随行星旋转。因此,该参考系中的位置是相对于行星中心的。以下代码打印出了当前活动航天器在 Kerbin 参考系中的位置:
import krpc conn = krpc.connect() vessel = conn.space_center.active_vessel print('(%.1f, %.1f, %.1f)' % vessel.position(vessel.orbit.body.reference_frame))对于停放在发射台上的航天器,该位置矢量的大小约为 600,000 米(等于 Kerbin 的半径)。位置矢量不会随时间变化,因为航天器停在 Kerbin 表面,而参考系也随 Kerbin 一起旋转。
航天器轨道参考系
另一个例子是航天器的轨道参考系,通过调用Vessel.orbital_reference_frame获取。该参考系固定在航天器上(原点随航天器移动),坐标轴指向轨道顺向/法向/径向方向。
- 原点位于航天器的质心,
- y 轴指向航天器轨道的顺向方向,
- x 轴指向航天器轨道的反径向方向,
- z 轴指向航天器轨道的法向方向,
- 坐标轴随顺向/法向/径向方向的变化而旋转,例如当航天器沿轨道继续运动时顺向方向会发生变化。
航天器参考系
另一个例子是Vessel.reference_frame。与前一个例子一样,它也固定在航天器上(原点随航天器移动),但坐标轴的朝向不同。它们跟踪航天器的朝向:
- 原点位于航天器的质心,
- y 轴指向航天器所朝的方向,
- x 轴指向航天器的右侧,
- z 轴指向航天器底部向下,
- 坐标轴随航天器方向的任何变化而旋转。
线速度和角速度
参考系之间会相互移动和旋转。例如,前面讨论的参考系的原点位置都固定在某些物体上(如航天器或行星)。这意味着它们会移动和旋转以跟踪该物体,因此具有与之相关的线速度和角速度。
例如,通过调用Kerbin的CelestialBody.reference_frame获得的参考系是相对于 Kerbin 固定的。这意味着该参考系的角速度与 Kerbin 的角速度相同,参考系的线速度与 Kerbin 当前的轨道速度一致。
可用参考系
kRPC 提供以下参考系:
Vessel.reference_frame Vessel.orbital_reference_frame Vessel.surface_reference_frame Vessel.surface_velocity_reference_frame CelestialBody.reference_frame CelestialBody.non_rotating_reference_frame CelestialBody.orbital_reference_frame Node.reference_frame Node.orbital_reference_frame Part.reference_frame Part.center_of_mass_reference_frame DockingPort.reference_frame Thruster.thrust_reference_frame同时还可以从上述参考系构造相对和混合参考系。
自定义参考系
自定义参考系可以从上面列出的内置参考系构造而来。它们有两种类型:"相对"和"混合"。
相对参考系由一个父参考系、一个固定的位置偏移和一个固定的旋转偏移构造而成。例如,以下代码通过在Vessel.reference_frame的 z 轴上施加 10 米的位置偏移,构建了一个原点在航天器下方 10 米处的参考系。相对参考系可通过调用ReferenceFrame.create_relative()来构造。
混合参考系从其他参考系的组件(位置、旋转、速度和角速度)中继承其组件。注意这些组件不一定是固定的。例如,你可以构建一个参考系,其位置是航天器的质心(继承自 Vessel.reference_frame),旋转则是被环绕行星的旋转(继承自 CelestialBody.reference_frame)。混合参考系可通过调用 ReferenceFrame.create_hybrid() 来构造。
自定义参考系的父参考系也可以是其他自定义参考系。例如,你可以将上面两个例子结合起来:先构造一个以航天器为中心、随被环绕行星旋转的混合参考系,然后创建一个在该参考系的 z 轴上偏移 10 米位置的相对参考系。最终得到的参考系其原点在航天器下方 10 米处,并且随被环绕的行星旋转。
参考系之间的转换
kRPC 提供了用于在不同参考系之间转换位置、方向、旋转和速度的实用方法:
SpaceCenter.transform_position() SpaceCenter.transform_direction() SpaceCenter.transform_rotation() SpaceCenter.transform_velocity()可视化调试
参考系可能会让人困惑,选择合适的参考系本身就是个挑战。为了辅助调试,kRPC 的绘图功能可用于在游戏中可视化方向向量。
Drawing.add_direction_from_com()将绘制一个方向向量,从活动航天器的质心开始。例如,以下代码绘制当前航天器相对于其所环绕天体表面的速度方向:
import krpc conn = krpc.connect(name='Visual Debugging') vessel = conn.space_center.active_vessel ref_frame = vessel.surface_velocity_reference_frame conn.drawing.add_direction_from_com((0, 1, 0), ref_frame) while True: pass注意:
客户端必须保持连接才能持续绘制该线条,因此示例末尾使用了一个无限循环。
示例
下面的示例演示了参考系的各种用法。
导航球方向
此示例演示如何让航天器指向导航球上的各个方向:
import krpc conn = krpc.connect(name='Navball directions') vessel = conn.space_center.active_vessel ap = vessel.auto_pilot ap.reference_frame = vessel.surface_reference_frame ap.engage() # Point the vessel north on the navball, with a pitch of 0 degrees ap.target_direction = (0, 1, 0) ap.wait() # Point the vessel vertically upwards on the navball ap.target_direction = (1, 0, 0) ap.wait() # Point the vessel west (heading of 270 degrees), with a pitch of 0 degrees ap.target_direction = (0, 0, -1) ap.wait() ap.disengage()该代码使用了航天器的表面参考系(Vessel.surface_reference_frame),如下图所示:
第一部分指示自动驾驶仪指向航天器表面参考系中的方向 (0,1,0)(即沿 y 轴)。该参考系的 y 轴指向北方,符合要求。
第二部分指示自动驾驶仪指向航天器表面参考系中的方向 (1,0,0)(沿 x 轴)。该参考系的 x 轴指向天顶(远离行星),符合要求。
最后,代码指示自动驾驶仪指向方向 (0,0,-1)(沿负 z 轴)。该参考系的 z 轴指向东方,因此请求的方向指向西方——符合要求。
轨道方向
此示例演示如何让航天器指向导航球在「轨道」模式下的各个轨道方向。它使用了Vessel.orbital_reference_frame。
import krpc conn = krpc.connect(name='Orbital directions') vessel = conn.space_center.active_vessel ap = vessel.auto_pilot ap.reference_frame = vessel.orbital_reference_frame ap.engage() # Point the vessel in the prograde direction ap.target_direction = (0, 1, 0) ap.wait() # Point the vessel in the orbit normal direction ap.target_direction = (0, 0, 1) ap.wait() # Point the vessel in the orbit radial direction ap.target_direction = (-1, 0, 0) ap.wait() ap.disengage()该代码使用了航天器的轨道参考系,如下图所示:
表面「顺向」
此示例演示如何在导航球处于「表面」模式时,让航天器指向「顺向」方向。这是航天器相对于表面的速度方向:
import krpc conn = krpc.connect(name='Surface prograde') vessel = conn.space_center.active_vessel ap = vessel.auto_pilot ap.reference_frame = vessel.surface_velocity_reference_frame ap.target_direction = (0, 1, 0) ap.engage() ap.wait() ap.disengage()以下代码使用了 Vessel.surface_velocity_reference_frame,如下图所示:
航天器速度
本示例演示如何获取飞行器的轨道速度和表面速度,其数值等同于导航球上显示的值。
要计算飞行器的轨道速度,需要获取相对于行星非旋转参考系(CelestialBody.non_rotating_reference_frame)的速度。该参考系相对于天体固定,但不随天体旋转。
对于表面速度,则需要使用行星的参考系(CelestialBody.reference_frame),因为该参考系随天体一同旋转。
import time import krpc conn = krpc.connect(name='Vessel speed') vessel = conn.space_center.active_vessel obt_frame = vessel.orbit.body.non_rotating_reference_frame srf_frame = vessel.orbit.body.reference_frame while True: obt_speed = vessel.flight(obt_frame).speed srf_speed = vessel.flight(srf_frame).speed print('Orbital speed = %.1f m/s, Surface speed = %.1f m/s' % (obt_speed, srf_speed)) time.sleep(1)本示例演示如何获取飞行器相对于被环绕天体表面的速度(以向量形式)。
要实现这一点,需要使用混合参考系。这是因为我们希望得到一个以飞行器为中心、但其线速度相对于地面保持固定的参考系。
因此,我们创建一个混合参考系,将其旋转设置为飞行器的表面参考系(Vessel.surface_reference_frame),而将所有其他属性(包括位置和速度)设置为天体的参考系(CelestialBody.reference_frame)——该参考系随天体一同旋转。
import time import krpc conn = krpc.connect(name='Orbital speed') vessel = conn.space_center.active_vessel ref_frame = conn.space_center.ReferenceFrame.create_hybrid( position=vessel.orbit.body.reference_frame, rotation=vessel.surface_reference_frame) while True: velocity = vessel.flight(ref_frame).velocity print('Surface velocity = (%.1f, %.1f, %.1f)' % velocity) time.sleep(1)攻角
本示例计算飞行器指向方向与其运动方向(相对于表面)之间的夹角。
import math import time import krpc conn = krpc.connect(name='Angle of attack') vessel = conn.space_center.active_vessel while True: d = vessel.direction(vessel.orbit.body.reference_frame) v = vessel.velocity(vessel.orbit.body.reference_frame) # Compute the dot product of d and v dotprod = d[0]*v[0] + d[1]*v[1] + d[2]*v[2] # Compute the magnitude of v vmag = math.sqrt(v[0]**2 + v[1]**2 + v[2]**2) # Note: don't need to magnitude of d as it is a unit vector # Compute the angle between the vectors angle = 0 if dotprod > 0: angle = abs(math.acos(dotprod / vmag) * (180.0 / math.pi)) print('Angle of attack = %.1f degrees' % angle) time.sleep(1)请注意,用于获取方向向量和速度向量的参考系朝向并不重要,因为两个向量之间的夹角与坐标轴的方向无关。然而,如果我们使用随飞行器移动的参考系,速度将返回(0,0,0)。因此,我们需要一个相对于飞行器不是固定的参考系。CelestialBody.reference_frame恰好满足这些要求。
着陆点
本示例计算一个位于天体表面指定高度处的参考系,该参考系可用作着陆自动驾驶仪的目标目标点。
import time from math import sin, cos, pi import krpc conn = krpc.connect(name='Landing Site') vessel = conn.space_center.active_vessel body = vessel.orbit.body create_relative = conn.space_center.ReferenceFrame.create_relative # Define the landing site as the top of the VAB landing_latitude = -(0+(5.0/60)+(48.38/60/60)) landing_longitude = -(74+(37.0/60)+(12.2/60/60)) landing_altitude = 111 # Determine landing site reference frame # (orientation: x=zenith, y=north, z=east) landing_position = body.surface_position( landing_latitude, landing_longitude, body.reference_frame) q_long = ( 0, sin(-landing_longitude * 0.5 * pi / 180), 0, cos(-landing_longitude * 0.5 * pi / 180) ) q_lat = ( 0, 0, sin(landing_latitude * 0.5 * pi / 180), cos(landing_latitude * 0.5 * pi / 180) ) landing_reference_frame = \ create_relative( create_relative( create_relative( body.reference_frame, landing_position, q_long), (0, 0, 0), q_lat), (landing_altitude, 0, 0)) # Draw axes conn.drawing.add_line((0, 0, 0), (1, 0, 0), landing_reference_frame) conn.drawing.add_line((0, 0, 0), (0, 1, 0), landing_reference_frame) conn.drawing.add_line((0, 0, 0), (0, 0, 1), landing_reference_frame) while True: time.sleep(1)