-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdemo1.py
More file actions
124 lines (100 loc) · 4.88 KB
/
Copy pathdemo1.py
File metadata and controls
124 lines (100 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Core Omniverse Kit and USD APIs for scene manipulation and simulation control.
import omni.kit.commands
import omni.usd
import omni.timeline
from pxr import Sdf, UsdGeom, Gf, UsdPhysics
# Cesium integration for real-world geospatial positioning.
# NOTE: We are NOT importing UsdPhysics, as we will move the object kinematically.
from cesium.usd.plugins.CesiumUsdSchemas import GlobeAnchorAPI as CesiumGlobeAnchorAPI
# Standard Python libraries for math and logging.
import math
import logging
# --- Script Configuration ---
DRONE_PATH = "/World/cf2x" # This is using the already existing drone in the scene
INITIAL_SCALE = 100.0
# Define the drone's starting coordinates to reset to on every run.
INITIAL_LATITUDE = 37.2201289
INITIAL_LONGITUDE = -80.4181060
INITIAL_HEIGHT = 635.0 # Height in meters above the stadium
MOVEMENT_DISTANCE = 0.0003
MOVEMENT_SPEED = 0.5
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
# Global state dictionary to hold simulation variables.
g_simulation_state = {}
def on_update_movement(e):
"""
This function is called by Isaac Sim on every frame of the simulation.
It calculates and applies the new position for the drone.
"""
timeline = g_simulation_state.get("timeline")
if not timeline or not timeline.is_playing():
return
globe_anchor = g_simulation_state.get("globe_anchor")
start_time = g_simulation_state.get("start_time")
initial_pos = g_simulation_state.get("initial_position")
if not all([globe_anchor, start_time is not None, initial_pos]):
return # Silently return if not yet initialized
# Calculate and apply new position
elapsed_time = timeline.get_current_time() - start_time
displacement = math.sin(elapsed_time * MOVEMENT_SPEED) * MOVEMENT_DISTANCE
new_longitude = initial_pos["longitude"] + displacement
globe_anchor.GetAnchorLongitudeAttr().Set(new_longitude)
def stop_movement():
"""Stops the drone's movement by cancelling the frame-by-frame update subscription."""
if g_simulation_state.get("update_subscription"):
g_simulation_state["update_subscription"].unsubscribe()
g_simulation_state["update_subscription"] = None
logging.info("Drone movement stopped.")
def setup_and_move_drone():
"""
This is the main function. It finds the drone, cleans it of any old physics components,
sets its scale and anchor, and starts the movement subscription.
"""
stop_movement()
context = omni.usd.get_context()
stage = context.get_stage()
timeline = omni.timeline.get_timeline_interface()
app_update = omni.kit.app.get_app().get_update_event_stream()
drone_prim = stage.GetPrimAtPath(DRONE_PATH)
if not drone_prim.IsValid():
logging.error(f"Drone not found at path '{DRONE_PATH}'.")
return
# --- THIS IS THE CRITICAL FIX ---
# Before doing anything, check if a stale RigidBodyAPI from a previous run
# exists on the prim. If so, remove it to prevent conflicts.
if drone_prim.HasAPI(UsdPhysics.RigidBodyAPI):
logging.warning("Found stale RigidBodyAPI on drone. Removing it to ensure a clean state.")
drone_prim.RemoveAPI(UsdPhysics.RigidBodyAPI)
# ---------------------------------
# Set scale (this is a safe, non-physics operation).
xform_api = UsdGeom.XformCommonAPI(drone_prim)
xform_api.SetScale(Gf.Vec3f(INITIAL_SCALE, INITIAL_SCALE, INITIAL_SCALE))
logging.info(f"Drone scale set to {INITIAL_SCALE}x.")
# Apply Cesium Globe Anchor. This is all we need to control its position.
globe_anchor = CesiumGlobeAnchorAPI.Apply(drone_prim)
if not globe_anchor:
logging.error("Failed to apply CesiumGlobeAnchorAPI to the drone prim.")
return
# --- POSITION RESET ---
# Explicitly set the drone's position to the configured initial coordinates.
# This acts as a "reset" every time the script is run.
globe_anchor.GetAnchorLatitudeAttr().Set(INITIAL_LATITUDE)
globe_anchor.GetAnchorLongitudeAttr().Set(INITIAL_LONGITUDE)
globe_anchor.GetAnchorHeightAttr().Set(INITIAL_HEIGHT)
logging.info(f"Drone position reset to: Lat={INITIAL_LATITUDE}, Lon={INITIAL_LONGITUDE}, H={INITIAL_HEIGHT}")
# Store the initial state and start the update loop.
g_simulation_state.update({
"timeline": timeline,
"globe_anchor": globe_anchor,
"start_time": timeline.get_current_time(),
"initial_position": {
"latitude": globe_anchor.GetAnchorLatitudeAttr().Get(),
"longitude": globe_anchor.GetAnchorLongitudeAttr().Get(),
"height": globe_anchor.GetAnchorHeightAttr().Get(),
},
"update_subscription": app_update.create_subscription_to_pop(on_update_movement)
})
logging.info("Drone controller is active. Press PLAY to see movement.")
print("--- To stop the movement, run the command: stop_movement() ---")
# --- Main Execution ---
setup_and_move_drone()