Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions client/python/example_user_scripts/hello_drone_secondary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
Copyright (C) Microsoft Corporation.
Copyright (C) 2025 IAMAI Consulting Corp.
MIT License. All rights reserved.

Secondary controller: flies the drone using only service calls (no topic subscriptions).
"""

import asyncio

from projectairsim import ProjectAirSimClient, Drone, World
from projectairsim.utils import projectairsim_log


async def main():
client = ProjectAirSimClient()

try:
# 1) Connect to the running simulation (primary already loaded the scene)
client.connect()

# 2) Attach to current world without loading a new scene
world = World(client)

# 3) Attach to the existing drone
drone = Drone(client, world, "Drone1")

# ----------------- FLIGHT SEQUENCE (control) -----------------
drone.enable_api_control()
drone.arm()

projectairsim_log().info("takeoff_async: starting")
takeoff_task = await drone.takeoff_async()
await takeoff_task
projectairsim_log().info("takeoff_async: completed")

# Move up 1 m/s for 4 s
move_up_task = await drone.move_by_velocity_async(
v_north=0.0, v_east=0.0, v_down=-1.0, duration=4.0
)
projectairsim_log().info("Move-Up invoked")
await move_up_task
projectairsim_log().info("Move-Up completed")

# Move down 1 m/s for 4 s
move_down_task = await drone.move_by_velocity_async(
v_north=0.0, v_east=0.0, v_down=1.0, duration=4.0
)
projectairsim_log().info("Move-Down invoked")
await move_down_task
projectairsim_log().info("Move-Down completed")

projectairsim_log().info("land_async: starting")
land_task = await drone.land_async()
await land_task
projectairsim_log().info("land_async: completed")

# Disarm/disable at the end
drone.disarm()
drone.disable_api_control()

except Exception as err:
projectairsim_log().error(f"Exception occurred: {err}", exc_info=True)
finally:
client.disconnect()


if __name__ == "__main__":
asyncio.run(main())
88 changes: 88 additions & 0 deletions client/python/example_user_scripts/two_drones_split_drone1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""
Copyright (C) Microsoft Corporation.
Copyright (C) 2025 IAMAI CONSULTING CORP
MIT License.

Control script for Drone1.
This script loads the two-drone scene and controls only Drone1.
"""

import asyncio

from projectairsim import Drone, ProjectAirSimClient, World
from projectairsim.image_utils import ImageDisplay
from projectairsim.utils import projectairsim_log


def imu_callback_drone1(_, imu_msg):
print(f"[Drone1][IMU] {imu_msg}")


async def fly_box_pattern(drone: Drone, label: str):
"""Fly a simple box-like path for one drone."""
cmd_duration_sim_sec = 3
velocity_mps = 1

projectairsim_log().info(f"[{label}] Move Up")
task = await drone.move_by_velocity_async(0, 0, -velocity_mps, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move North")
task = await drone.move_by_velocity_async(velocity_mps, 0, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move West")
task = await drone.move_by_velocity_async(0, -velocity_mps, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move South")
task = await drone.move_by_velocity_async(-velocity_mps, 0, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move East")
task = await drone.move_by_velocity_async(0, velocity_mps, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move Down")
task = await drone.move_by_velocity_async(0, 0, velocity_mps, cmd_duration_sim_sec)
await task


async def main():
client = ProjectAirSimClient()
image_display = ImageDisplay()

try:
client.connect()

# Drone1 script is the one that loads the scene.
world = World(client, "scene_two_drones.jsonc", delay_after_load_sec=2)
drone1 = Drone(client, world, "Drone1")

chase_cam_window = "Drone1-ChaseCam"
image_display.add_chase_cam(chase_cam_window)
client.subscribe(
drone1.sensors["Chase"]["scene_camera"],
lambda _, chase: image_display.receive(chase, chase_cam_window),
)
client.subscribe(drone1.sensors["IMU1"]["imu_kinematics"], imu_callback_drone1)
image_display.start()

drone1.enable_api_control()
drone1.arm()

await fly_box_pattern(drone1, "Drone1")

drone1.disarm()
drone1.disable_api_control()

except Exception as err:
projectairsim_log().error(f"Exception occurred: {err}", exc_info=True)

finally:
client.disconnect()
image_display.stop()


if __name__ == "__main__":
asyncio.run(main())
90 changes: 90 additions & 0 deletions client/python/example_user_scripts/two_drones_split_drone2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""
Copyright (C) Microsoft Corporation.
Copyright (C) 2025 IAMAI CONSULTING CORP
MIT License.

Control script for Drone2.
This script does NOT reload the scene; it attaches to the current world with World(client).
Run this after the Drone1 script has already loaded the scene.
"""

import asyncio

from projectairsim import Drone, ProjectAirSimClient, World
from projectairsim.utils import projectairsim_log


def imu_callback_drone2(_, imu_msg):
print(f"[Drone2][IMU] {imu_msg}")


async def fly_box_pattern(drone: Drone, label: str):
"""Fly a simple box-like path for one drone."""
cmd_duration_sim_sec = 3
velocity_mps = 1

projectairsim_log().info(f"[{label}] Move Up")
task = await drone.move_by_velocity_async(0, 0, -velocity_mps, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move North")
task = await drone.move_by_velocity_async(velocity_mps, 0, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move West")
task = await drone.move_by_velocity_async(0, -velocity_mps, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move South")
task = await drone.move_by_velocity_async(-velocity_mps, 0, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move East")
task = await drone.move_by_velocity_async(0, velocity_mps, 0, cmd_duration_sim_sec)
await task

projectairsim_log().info(f"[{label}] Move Down")
task = await drone.move_by_velocity_async(0, 0, velocity_mps, cmd_duration_sim_sec)
await task


async def main():
client = ProjectAirSimClient()

try:
client.connect()

# Drone2 script attaches to the already-loaded scene.
world = World(client)
drone2 = Drone(client, world, "Drone2")

if not client.is_service_only_mode():
imu_topic = drone2.sensors.get("IMU1", {}).get("imu_kinematics")
if imu_topic:
client.subscribe(imu_topic, imu_callback_drone2)
else:
projectairsim_log().warning(
"[Drone2] IMU topic was not found; continuing without topic subscription."
)
else:
projectairsim_log().warning(
"[Drone2] Client is running in service-only mode; skipping topic subscription."
)

drone2.enable_api_control()
drone2.arm()

await fly_box_pattern(drone2, "Drone2")

drone2.disarm()
drone2.disable_api_control()

except Exception as err:
projectairsim_log().error(f"Exception occurred: {err}", exc_info=True)

finally:
client.disconnect()


if __name__ == "__main__":
asyncio.run(main())
Loading
Loading