HyperDroneΒΆ
%pip install -q "hyperdrone[examples]" foundation-policy==1.0.1SetupΒΆ
dataset = hyperlux.datasets.procthor.Train200()
scenes = [dataset[index].reference for index in (1, 0)]
WIDTH, HEIGHT = 640, 360
STEPS, STRIDE, FPS = 500, 4, 25
output = Path("hyperdrone_videos")
output.mkdir(exist_ok=True)
drone_asset = rigged_model_path("x500")
config = Config(instances_per_world=1, width=WIDTH, height=HEIGHT, preset="x500_fpv", motion_blur_samples=8)
initial = {"mdp": {"init": {
"guidance": 0.0, "max_position": 0.25, "max_angle": 0.1,
"max_linear_velocity": 0.0, "max_angular_velocity": 0.0,
"min_rpm": 0.0, "max_rpm": 0.0,
}}}
fpv = camera([0.1, 0, 0.19], 0.3, 0, 100)
chase = camera([-0.8, -0.8, 0.6], 0.45, np.pi / 4, 65)Fly the presetΒΆ
sensor_config = replace(config, dataset="procthor", cameras=(CameraSpec("front", (RGB("float32"), Depth(), Segmentation(labels="semantic"), Normals(), Flow(), FlowStatus())), CameraSpec("chase", (RGB("float32"),))))
with closing(HyperDrone(scenes, config=sensor_config, drone_asset=drone_asset,
parameters={"dynamics": initial, "cameras": {"front": fpv, "chase": chase}})) as env:
print("Rendering backend:", env.render_backend)
env.reset(spawn_points=shots["flight"])
env.observe()
semantic_classes = env.segmentation_classes
semantic_ids = env.outputs[Segmentation(labels="semantic")].read()[0, 0]
print("Visible semantic IDs:", {int(id): semantic_classes[int(id)]
for id in np.unique(semantic_ids) if id != 0xFFFFFFFF})
base_layout = env.observation_layout_privileged
image_layout = env.observation_layout
policies, previous = pilots(env)
assert np.isclose(STRIDE * env.dt, 1 / FPS)
with writer(output / "01-preset.mp4", FPS) as video:
for step in range(STEPS):
target = np.array([0.25 if step >= 200 else 0, 0, 0], dtype=np.float32)
previous = act(env, policies, previous, target)
env.step(previous)
if (step + 1) % STRIDE == 0:
env.render()
frames = env.outputs[RGB("float32")].read()[0]
views = panel(frames,
["1 / Fly the preset - FPV", "Same flight - chase camera"])
sensors = sensor_panel(env.outputs[Depth()].read()[0, 0], env.outputs[Segmentation(labels="semantic")].read()[0, 0],
env.outputs[Normals()].read()[0, 0], env.outputs[Flow()].read()[0, 0], env.outputs[FlowStatus()].read()[0, 0])
video.append_data(np.concatenate([views, sensors], axis=0))
show_video(output / "01-preset.mp4")Rendering backend: optix
Visible semantic IDs: {96: 'FloorLamp', 127: 'Dresser', 159: 'Floor', 162: 'Wall', 4294967293: 'Agent'}
Multiple drone modelsΒΆ
fpv_positions = {
"x500": [0.1, 0, 0.19],
"arpl": [0.08, 0, 0.08],
"soft": [0.1, 0, 0.105],
"crazyflie_brushless": [0.016, 0, 0.026],
"crazyflie": [0.012, 0, 0.022],
"savagebee_pusher": [0.035, 0, 0.035],
}
names = list(fpv_positions)
drones = [{"asset": rigged_model_path(name), "parameters": {
"dynamics": {"dynamics": {"model": name}}, "cameras": {"front": camera(fpv_positions[name], 0.3, 0, 100)},
}} for name in names]
group_config = replace(config, num_agents=len(names) + 1, num_camera_agents=len(names) + 1)
with closing(HyperDrone(scenes, config=group_config, drones=drones,
parameters={"dynamics": initial})) as mixed:
mixed.reset(spawn_points=shots["models"])
mixed.set_instance_parameters({"agents": [
{"cameras": {"front": camera([0.4, 0, 0.12], 0.35, 0, 90)}}, *[{} for _ in names],
]})
anchors = np.array(shots["models"][0]["poses"], dtype=np.float32)[:, :3]
policies, previous = pilots(mixed)
with writer(output / "02-models.mp4", FPS) as video:
for step in range(STEPS):
targets = anchors.copy()
targets[1:, 2] += 0.12 * np.sin(2 * np.pi * step * mixed.dt / 4 + np.arange(len(names)))
previous = act(mixed, policies, previous, targets)
mixed.step(previous)
if (step + 1) % STRIDE == 0:
filming_view = mixed.frames().reshape(1, mixed.num_views, HEIGHT, WIDTH, 3)[0, 0]
video.append_data(panel([filming_view], ["Six drone models | filmed by a seventh drone"]))
show_video(output / "02-models.mp4")Target-frame taskΒΆ
with closing(HyperDrone(scenes, config=replace(config, task="target_frame"),
drone_asset=drone_asset, parameters={"dynamics": initial, "cameras": {"front": fpv}})) as task:
print("preset:", image_layout.blocks, "target_frame:", task.observation_layout.blocks)
task.reset(spawn_points=shots["flight"])
task.observe()
target_offset, target_size = task.observation_layout.blocks["target_image"]
target_image = task.frames()[0, ..., target_offset:target_offset + target_size].copy()
policies, previous = pilots(task)
with writer(output / "03-target.mp4", FPS) as video:
for step in range(STEPS):
previous = act(task, policies, previous)
task.step(previous)
if (step + 1) % STRIDE == 0:
frame = task.frames()[0]
images = [frame[..., offset:offset + size] for offset, size in task.observation_layout.blocks.values()]
np.testing.assert_array_equal(images[1], target_image)
video.append_data(panel(images, ["2 / Current image - returning to the goal", "Target image - fixed this episode"]))
show_video(output / "03-target.mp4")preset: {'image': (0, 3)} target_frame: {'image_stack': (0, 3), 'target_image': (3, 3)}
Python taskΒΆ
with closing(HyperDrone(scenes, config=replace(config, instances_per_world=2), drone_asset=drone_asset,
parameters={"dynamics": initial, "cameras": {"front": fpv}})) as env:
spawn_cycles = [[cycle(starts) for starts in room] for room in shots["python_task"]]
room = 0
env.reset(spawn_points=[next(starts) for starts in spawn_cycles[room]])
policies, previous = pilots(env)
targets = np.array([[0.2, 0, 0], [-0.2, 0, 0]], dtype=np.float32)
age, episodes = np.zeros(2, dtype=int), np.zeros(2, dtype=int)
last_reset = np.full(2, -100)
with writer(output / "04-python-task.mp4", FPS) as video:
for step in range(800):
previous = act(env, policies, previous, targets)
env.step(previous)
state = env.observe_privileged()
distance = np.linalg.norm(block(state, base_layout, "position") - targets, axis=1)
speed = np.linalg.norm(block(state, base_layout, "linear_velocity"), axis=1)
reward = -distance - 0.1 * speed
age += 1
terminated = ((distance < 0.04) & (speed < 0.15) & (age >= 100)) | (distance > 1.0)
reset = terminated | (age >= [250, 350])
if step == 399:
env.rotate_scene()
room = 1
reset[:] = True
env.reset(reset, spawn_points=[next(spawn_cycles[room][i]) for i in np.flatnonzero(reset)])
for i in np.flatnonzero(reset):
policies[i].reset()
previous[i] = 0
age[i] = 0
episodes[i] += 1
targets[i] *= -1
last_reset[i] = step
if (step + 1) % STRIDE == 0:
env.observe()
titles = [f"3 / Instance {i} | episode {episodes[i]} | " +
("RESET" if step - last_reset[i] < 20 else f"reward {reward[i]:.2f} | error {distance[i]:.2f} m")
for i in range(2)]
video.append_data(panel(env.frames(), titles))
print("completed episodes:", episodes.tolist())
show_video(output / "04-python-task.mp4")completed episodes: [8, 8]
Custom C++ worldΒΆ
%%writefile my_world.h
#pragma once
#include <rl_tools/rl/environments/hyperdrone/presets.h>
#include <cstddef>
namespace hyperdrone_user {
struct SPEC: rl_tools::rl::environments::hyperdrone::presets::X500FPV<float, std::size_t> {
static constexpr std::size_t N_CAMERA_AGENTS = 1;
static constexpr std::size_t INSTANCES_PER_WORLD = 1;
static constexpr std::size_t CAM_WIDTH = 640;
static constexpr std::size_t CAM_HEIGHT = 360;
using SHADING = rl_tools::hyperlux::VeryHigh;
static constexpr bool ENABLE_MOTION_BLUR = true;
static constexpr std::size_t MOTION_BLUR_SAMPLES = 8;
static constexpr bool ENABLE_ANTI_ALIASING = true;
static constexpr std::size_t ANTI_ALIASING_GRID_SIZE = 2;
};
using WORLD = rl_tools::rl::environments::hyperdrone::World<SPEC>;
}with closing(HyperDrone(scenes, config=Config(spec_header="my_world.h"),
drone_asset=drone_asset, parameters={"dynamics": initial, "cameras": {"camera0": chase}})) as custom:
custom.reset(spawn_points=shots["flight"])
policies, previous = pilots(custom)
with writer(output / "05-custom-world.mp4", FPS) as video:
for step in range(STEPS):
target = np.array([0.25 if step >= 200 else 0, 0, 0], dtype=np.float32)
previous = act(custom, policies, previous, target, layout=base_layout)
custom.step(previous)
if (step + 1) % STRIDE == 0:
views = custom.observe().reshape(custom.total_instances, HEIGHT, WIDTH, custom.image_channels)
video.append_data(panel([views[0]], ["4 / Custom C++ world"]))
show_video(output / "05-custom-world.mp4")Combined videoΒΆ
clips = [output / name for name in ("01-preset.mp4", "02-models.mp4", "03-target.mp4",
"04-python-task.mp4", "05-custom-world.mp4")]
join(clips, "hyperdrone.mp4", FPS)
show_video("hyperdrone.mp4")
print("Saved", Path("hyperdrone.mp4").resolve())