🚁 无人机实体#

Genesis 提供专门的无人机模拟,包括螺旋桨物理和电机控制。

创建无人机#

import genesis as gs
import numpy as np

gs.init(backend=gs.gpu)

scene = gs.Scene(
    sim_options=gs.options.SimOptions(dt=0.01, gravity=(0, 0, -9.81)),
)

scene.add_entity(gs.morphs.Plane())

drone = scene.add_entity(
    morph=gs.morphs.Drone(
        file="urdf/drones/cf2x.urdf",
        model="CF2X",
        pos=(0.0, 0.0, 0.5),
    ),
)

scene.build()

无人机 Morph 选项#

gs.morphs.Drone(
    file="urdf/drones/cf2x.urdf",  # URDF 文件路径
    model="CF2X",                   # 模型: "CF2X", "CF2P", 或 "RACE"
    pos=(0.0, 0.0, 0.5),           # 初始位置
    euler=(0.0, 0.0, 0.0),         # 初始方向 (度)
    propellers_link_name=('prop0_link', 'prop1_link', 'prop2_link', 'prop3_link'),
    propellers_spin=(-1, 1, -1, 1), # 旋转方向: 1=逆时针, -1=顺时针
)

电机控制#

通过 RPM(每分钟转数)控制螺旋桨:

hover_rpm = 14475.8  # CF2X 的近似悬停 RPM
max_rpm = 25000.0

for step in range(1000):
    # 为每个螺旋桨设置 RPM [前左, 前右, 后左, 后右]
    rpms = np.array([hover_rpm, hover_rpm, hover_rpm, hover_rpm])

    # 添加差动推力以实现运动
    rpms[0] += 100  # 增加前左
    rpms[3] += 100  # 增加后右
    rpms = np.clip(rpms, 0, max_rpm)

    drone.set_propellels_rpm(rpms)  # 每步调用一次
    scene.step()

重要: set_propellels_rpm() 必须在每个模拟步骤中恰好调用一次。

物理模型#

  • 推力: F = KF × RPM² (每个螺旋桨的垂直力)

  • 扭矩: τ = KM × RPM² × spin_direction (偏航力矩)

  • 控制:

    • 螺旋桨之间的差动推力 → 平移

    • 螺旋桨对之间的差动力矩 → 旋转

多环境#

scene.build(n_envs=32)

# 控制形状: (n_envs, n_propellers)
rpms = np.tile([hover_rpm] * 4, (32, 1))
drone.set_propellels_rpm(rpms)

可用模型#

模型

文件

描述

CF2X

urdf/drones/cf2x.urdf

Crazyflie 2.0 X 配置

CF2P

urdf/drones/cf2p.urdf

Crazyflie 2.0 Plus

RACE

urdf/drones/racer.urdf

竞速无人机

示例:悬停控制#

import genesis as gs
import numpy as np

gs.init()
scene = gs.Scene()
scene.add_entity(gs.morphs.Plane())
drone = scene.add_entity(gs.morphs.Drone(file="urdf/drones/cf2x.urdf", pos=(0, 0, 1)))
scene.build()

target_height = 1.0
kp = 5000.0

for _ in range(500):
    pos = drone.get_pos()[0]
    error = target_height - pos[2].item()

    base_rpm = 14475.8
    correction = kp * error
    rpms = np.clip([base_rpm + correction] * 4, 0, 25000)

    drone.set_propellels_rpm(rpms)
    scene.step()