Skip to main content

Add your description here

Project description

Fly Ruler Protocol Python Bindings

本目录提供 fly_ruler_proto_core 的 Python 绑定,基于 PyO3maturin 构建。它面向飞行模拟的数据发送端,将一架飞行器的完整生命周期封装为高层的 Python API,让 Python 脚本能够以最小网络细节向 Godot 或 Rust 服务端推送飞行器状态与事件。

Python wheels、Linux server 和自带 Web 控制台的 MSFS zip 由同一 tag workflow 发布,详见 ../../RELEASING.md

1. 定位与架构

Python 脚本
    ↓
FlyRulerClient / PyClient(本绑定)
    ↓
fly_ruler_proto_core::transport::AircraftClient
    ↓
UDP 网络  →  Fly Ruler Server / MSFS / Godot
  • PyClient:Rust 实现的 aircraft-bound 客户端(一个实例对应一架飞行器)。
  • FlyRulerClient:Python 高层包装,提供上下文管理器与最佳实践。
  • PyServer:底层 UDP 服务端包装(主要用于测试或特殊场景)。

发送到 fly-ruler-server 的状态可以在同仓库 Web 控制台中实时查看、绘制 历史曲线、按事件跳转和回放。显式 timestamp 仍使用秒;推荐 Unix wall time,前端会自动转换为相对仿真时间显示。

2. 环境准备

推荐工具链:

  • uv:Python 环境管理
  • maturin:PyO3 扩展构建
  • Rust toolchain(与仓库其他 crate 一致)

2.1 创建虚拟环境并安装构建工具

cd bindings/python

uv venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate

uv pip install maturin pytest

2.2 构建并安装本地扩展

maturin develop

这会将 Rust 扩展编译为 _core 并安装到当前虚拟环境,Python 包可直接导入。

3. 数据类型

模块导出了与 protobuf schema 对齐的基础数据类。

3.1 Vector3

from fly_ruler_proto_python import Vector3

v = Vector3(1.0, 2.0, 3.0)
print(v.x, v.y, v.z)

v.x = 9.0
zero = Vector3.zero()
属性 类型 说明
x float X 分量
y float Y 分量
z float Z 分量

3.2 Quaternion

from fly_ruler_proto_python import Quaternion

q = Quaternion(1.0, 0.0, 0.0, 0.0)
identity = Quaternion.identity()
属性 类型 说明
w float 实部
x float 虚部 i
y float 虚部 j
z float 虚部 k

3.3 DerivedState

from fly_ruler_proto_python import DerivedState

d = DerivedState(
    lat=37.7749,
    lon=-122.4194,
    altitude=500.0,
    alpha=0.05,
    beta=0.0,
    tas=50.0,
    eas=48.0,
    gamma=0.1,
    chi=0.2,
    ias=47.5,
    cas=47.5,
    mach=0.15,
)
属性 类型 说明
lat float 纬度
lon float 经度
altitude float 高度
alpha float 迎角
beta float 侧滑角
tas float 真空速
eas float 当量空速
gamma float 航迹倾斜角
chi float 航迹方位角
ias float | None 指示空速
cas float | None 校准空速
mach float | None 马赫数

3.4 AircraftState

from fly_ruler_proto_python import (
    AircraftState, ControlSurfaceState, DerivedState, EngineState,
    Quaternion, Vector3,
)

state = AircraftState(
    position=Vector3(100.0, 200.0, -300.0),
    velocity=Vector3(1.0, 2.0, 3.0),
    attitude=Quaternion(1.0, 0.0, 0.0, 0.0),
    angular_velocity=Vector3(0.1, 0.2, 0.3),
    derived=DerivedState(lat=30.0, lon=120.0, altitude=1000.0),
    control_surfaces=ControlSurfaceState(rudder_rad=0.1),
    engines=[EngineState(1, throttle_lever_ratio=0.7)],
    custom_fields={"flyruler.control.rudder_rad": 0.1},
)

# 悬停/默认状态
hover = AircraftState.hover()
属性 类型 说明
position Vector3 位置
velocity Vector3 速度
attitude Quaternion 姿态四元数
angular_velocity Vector3 角速度
derived DerivedState | None 派生气动/导航状态
control_surfaces ControlSurfaceState | None 标准舵面状态
engines list[EngineState] 从 1 开始编号的逐发动机状态
custom_fields dict[str, float | int | bool | str | bytes] protobuf 扩展字段

3.5 辅助函数 create_aircraft_state

from fly_ruler_proto_python import create_aircraft_state

state = create_aircraft_state(
    position=(1.0, 2.0, 3.0),
    velocity=(4.0, 5.0, 6.0),
    attitude=(1.0, 0.1, 0.2, 0.3),
    angular_velocity=(0.4, 0.5, 0.6),
    derived=DerivedState(lat=30.0, lon=120.0, altitude=1000.0),
    control_surfaces=ControlSurfaceState(rudder_rad=0.1),
    engines=[EngineState(1, throttle_lever_ratio=0.7)],
    custom_fields={"flyruler.control.rudder_rad": 0.1},
)

提供元组形式的便捷构造,并可传入标准空气数据、舵面、逐发动机状态与 类型化 custom_fields

4. FlyRulerClient — 高层客户端

4.1 构造参数

class FlyRulerClient:
    def __init__(
        self,
        address: str,
        aircraft_name: str,
        initial_state: AircraftState | None = None,
        toml_config: str = "",
        heartbeat_interval_secs: float = 1.0,
    ) -> None: ...
参数 类型 默认值 说明
address str 必填 服务端地址,例如 "127.0.0.1:18002"
aircraft_name str 必填 飞行器名称
initial_state AircraftState | None None 初始状态,默认悬停
toml_config str "" TOML 格式飞行器配置
heartbeat_interval_secs float 1.0 心跳间隔(秒)

构造函数会自动完成:连接 UDP、发送 Handshake、发送 Spawn 请求。

4.2 属性

client.client_uuid     # str,客户端 UUID
client.aircraft_uuid   # str,飞行器 UUID

4.3 方法

update_state(state, timestamp=None)

client.update_state(state)
client.update_state(state, timestamp=123.456)

向服务端发送飞行器状态更新。

create_event(event_name, timestamp=None)

client.create_event("missile_launch")
client.create_event("missile_launch", timestamp=123.456)

发送自定义事件。

MSFS bridge 识别两个标准起落架事件:

client.create_event("flyruler.control.gear_up")
client.create_event("flyruler.control.gear_down")

despawn(reason=None, timestamp=None)

client.despawn(reason="mission_complete")

发送 Despawn 事件,标记该飞行器生命周期结束。

close()

client.close()
  • 若尚未 despawn,会自动发送 Despawn(reason="client_close")
  • 停止后台任务(sender / operation / heartbeat)。
  • 关闭网络连接。

4.4 上下文管理器

推荐使用 with 语句,确保退出时自动关闭:

from fly_ruler_proto_python import FlyRulerClient, create_aircraft_state

with FlyRulerClient("127.0.0.1:18002", "F-16") as aircraft:
    aircraft.update_state(create_aircraft_state(position=(100.0, 0.0, -1000.0)))
    aircraft.create_event("missile_launch")

5. PyClient — 底层 Rust 客户端

FlyRulerClient 内部包装了 PyClient。若需要直接使用 Rust 层暴露的客户端,可从 _core 导入:

from fly_ruler_proto_python._core import PyClient, AircraftState

client = PyClient(
    "127.0.0.1:18002",
    "F-16",
    AircraftState.hover(),
    "",
    1.0,
)

PyClient 提供的方法与 FlyRulerClient 一致:

  • client_uuid()
  • aircraft_uuid()
  • update_state(state, timestamp=None)
  • create_event(event_name, timestamp=None)
  • despawn(reason=None, timestamp=None)
  • close()

区别:

  • PyClient 在析构时 __del__ 会尝试自动调用 close()
  • FlyRulerClient 提供更符合 Python 习惯的高阶封装(上下文管理器、create_aircraft_state 集成等)。

6. PyServer — 底层 UDP 服务端

主要用于测试或需要直接操作 UDP socket 的场景。

from fly_ruler_proto_python._core import PyServer

server = PyServer("127.0.0.1:18002")
print(server.local_addr())
server.close()

注:生产环境推荐使用 Rust 的 KernelRuntime 或 Godot 的 FlyRulerServer,它们提供完整的会话管理、心跳握手与时序存储。

7. 协议版本

from fly_ruler_proto_python import PROTOCOL_VERSION, get_protocol_version

print(PROTOCOL_VERSION)           # "1.0.0"
print(get_protocol_version())     # "1.0.0"

版本号来自 fly_ruler_proto_core::PROTOCOL_VERSION,所有绑定共享同一来源。

8. 日志

Python 绑定在首次创建运行时(即构造 PyClient / PyServer)时,会初始化一次 tracing 订阅器。初始化是幂等的。

默认日志过滤:

warn,
fly_ruler_proto_python.client=info,
fly_ruler_proto_python.server=info,
fly_ruler_proto_core.runtime=warn,
fly_ruler_proto_core.store=warn,
fly_ruler_proto_core.transport=warn

可通过 RUST_LOG 环境变量覆盖:

RUST_LOG=debug python your_script.py

9. 完整示例

import time
from fly_ruler_proto_python import FlyRulerClient, create_aircraft_state

SERVER = "127.0.0.1:18002"


def main():
    with FlyRulerClient(SERVER, "F-16", heartbeat_interval_secs=1.0) as aircraft:
        print(f"client_uuid={aircraft.client_uuid}")
        print(f"aircraft_uuid={aircraft.aircraft_uuid}")

        for i in range(100):
            state = create_aircraft_state(
                position=(float(i), 0.0, -1000.0),
                velocity=(10.0, 0.0, 0.0),
            )
            aircraft.update_state(state, timestamp=time.time())
            time.sleep(0.001)  # 1000Hz

        aircraft.create_event("waypoint_reached", timestamp=time.time())


if __name__ == "__main__":
    main()

10. 测试

cd bindings/python
source .venv/bin/activate

# Rust 侧单元测试
cargo test -p fly_ruler_proto_python

# Python 侧测试
pytest tests/

测试覆盖:

  • 数据类构造与属性读写(Vector3QuaternionDerivedStateAircraftState
  • create_aircraft_state 辅助函数
  • 协议版本一致性
  • FlyRulerClient 包装器转发与上下文管理器行为

11. 错误处理

绑定层将 Rust 错误统一映射为 Python ConnectionError

try:
    client = FlyRulerClient("127.0.0.1:18002", "F-16")
except ConnectionError as e:
    print(f"连接失败: {e}")

常见失败原因:

  • 网络不可达
  • 服务端未启动
  • 协议版本不匹配(此时服务端会返回错误响应,连接仍可能建立,但后续操作可能失败)

12. 构建配置速查

pyproject.toml 中的关键配置:

[build-system]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"

[project]
name = "fly_ruler_proto_python"
version = "0.2.1"
requires-python = ">=3.10"
  • 包名:fly_ruler_proto_python
  • Rust crate:bindings/python/Cargo.toml 中的 fly_ruler_proto_python
  • 入口模块:src/lib.rs 定义 _core,Python 包通过 __init__.py 重新导出。

13. 相关文档

  • 内核文档:../../core/README.md
  • Godot 绑定:../godot/README.md
  • 项目总览:../../CLAUDE.md
  • Protobuf Schema:../../proto/fly_ruler.proto

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

fly_ruler_proto_python-0.2.1-cp39-abi3-win_amd64.whl (1.1 MB view details)

Uploaded CPython 3.9+Windows x86-64

fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.3 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

File details

Details for the file fly_ruler_proto_python-0.2.1-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for fly_ruler_proto_python-0.2.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 0eb3b37dd4b0543552295694531789d68ab04105548b2746cdf27fef5be6b11d
MD5 a9f6f6595c0cad75fefc3b04359e1721
BLAKE2b-256 3af921e0908d0870515b4a086f21b3293343eac239acdd71d48b34fb0c44f7de

See more details on using hashes here.

Provenance

The following attestation bundles were made for fly_ruler_proto_python-0.2.1-cp39-abi3-win_amd64.whl:

Publisher: release.yml on WindLX/fly_ruler_proto

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d88ebb8715d558f11f78753d821f736ffeb8a04f4227ae6866dabb5f60a74703
MD5 500fe9b42b3b54b65c563a9c83b05c16
BLAKE2b-256 05a54aa3fce369e679bd054cacac00026176d3b1351891d4c6310dcdde0e15bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on WindLX/fly_ruler_proto

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3d43aa6e70cd494bca903b4b71527392f70f0f2a86ed42f945896331936279c3
MD5 c963afe0e3c93041f4336fb5ffee9ec5
BLAKE2b-256 58a45363d88e18b42e0137333e4bc630ca08cbf6d3470e4face5cf25e6c3a77a

See more details on using hashes here.

Provenance

The following attestation bundles were made for fly_ruler_proto_python-0.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on WindLX/fly_ruler_proto

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page