diff --git a/airstack.sh b/airstack.sh
index 1497db034..0c6558a23 100755
--- a/airstack.sh
+++ b/airstack.sh
@@ -193,6 +193,24 @@ function check_docker {
log_error "Docker daemon is not running."
exit 1
fi
+
+ # Check Docker Compose version
+ if command -v docker &> /dev/null && docker compose version &> /dev/null; then
+ local compose_version=$(docker compose version --short 2>/dev/null)
+ if [ -z "$compose_version" ]; then
+ # Fallback for parsing
+ compose_version=$(docker compose version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
+ fi
+
+ if [ -n "$compose_version" ]; then
+ local major_ver=$(echo "$compose_version" | cut -d. -f1)
+ # Check if major version is a number before comparing
+ if [[ "$major_ver" =~ ^[0-9]+$ ]] && [ "$major_ver" -lt 5 ]; then
+ log_error "Docker Compose version $compose_version is less than v5.0.0. This script requires v5.0.0 or greater."
+ exit 1
+ fi
+ fi
+ fi
}
# Find container by partial name using regex
diff --git a/common/ros_packages/robot_descriptions/iris_with_sensors_description/urdf/iris_with_sensors.pegasus.robot.urdf b/common/ros_packages/robot_descriptions/iris_with_sensors_description/urdf/iris_with_sensors.pegasus.robot.urdf
index 7f4f5d72d..13f71262a 100644
--- a/common/ros_packages/robot_descriptions/iris_with_sensors_description/urdf/iris_with_sensors.pegasus.robot.urdf
+++ b/common/ros_packages/robot_descriptions/iris_with_sensors_description/urdf/iris_with_sensors.pegasus.robot.urdf
@@ -40,7 +40,7 @@
-
+
diff --git a/config/isaac_sim_config.yaml b/config/isaac_sim_config.yaml
index 3fbbc3c86..daf256e22 100644
--- a/config/isaac_sim_config.yaml
+++ b/config/isaac_sim_config.yaml
@@ -6,7 +6,6 @@ isaac_sim:
enabled_extensions:
- "airlab.airstack"
- "pegasus.simulator"
- - "omni.physx.forcefields"
# Whether to start simulation playback automatically
play_on_start: true
diff --git a/gcs/docker/gcs-base-docker-compose.yaml b/gcs/docker/gcs-base-docker-compose.yaml
index 800fcc920..c1502d4ab 100644
--- a/gcs/docker/gcs-base-docker-compose.yaml
+++ b/gcs/docker/gcs-base-docker-compose.yaml
@@ -23,7 +23,6 @@ services:
- capabilities: [gpu]
count: 1
driver: nvidia
- runtime: nvidia
entrypoint: ''
environment:
- AUTOLAUNCH=${AUTOLAUNCH:-false}
diff --git a/robot/docker/.bashrc b/robot/docker/.bashrc
index 1899e5eb2..83f42a18c 100755
--- a/robot/docker/.bashrc
+++ b/robot/docker/.bashrc
@@ -23,8 +23,12 @@ function bws(){
COLCON_LOG_PATH="$ROS2_WS_DIR"/log colcon build --symlink-install --base-paths "$ROS2_WS_DIR"/ --build-base "$ROS2_WS_DIR"/build/ --install-base "$ROS2_WS_DIR"/install/ "$@"
}
function sws(){
- echo "Sourcing "$ROS2_WS_DIR"/install/local_setup.bash"
- source "$ROS2_WS_DIR"/install/local_setup.bash || echo "Please make sure to build first with 'bws'"
+ if [ -f "$ROS2_WS_DIR/install/local_setup.bash" ]; then
+ echo "Sourcing $ROS2_WS_DIR/install/local_setup.bash"
+ source "$ROS2_WS_DIR/install/local_setup.bash"
+ else
+ echo "Workspace not built yet. Please make sure to build first with 'bws'"
+ fi
}
# Function to prompt user for confirmation
diff --git a/robot/docker/docker-compose.yaml b/robot/docker/docker-compose.yaml
index 350bf3690..be0aed4a8 100644
--- a/robot/docker/docker-compose.yaml
+++ b/robot/docker/docker-compose.yaml
@@ -39,7 +39,12 @@ services:
# for multiple robots
deploy:
replicas: ${NUM_ROBOTS:-1}
- runtime: nvidia
+ resources:
+ reservations:
+ devices:
+ - driver: nvidia
+ count: 1
+ capabilities: [gpu]
simple-robot:
profiles: !override
@@ -74,7 +79,13 @@ services:
ipc: host
command: >
bash -c "ssh service restart; tmux new -d -s robot_bringup && tmux send-keys -t robot_bringup 'bws && sws && DATE=$(date | sed \"s/ /_/g\" | sed \"s/:/_/g\") ros2 launch ${ROBOT_LAUNCH_PACKAGE} ${ROBOT_LAUNCH_FILE} sim:="false" ' ENTER && sleep infinity"
- runtime: nvidia
+ deploy:
+ resources:
+ reservations:
+ devices:
+ - driver: nvidia
+ count: 1
+ capabilities: [gpu]
# assumes network isolation via a physical router, so uses network_mode=host
network_mode: host
volumes:
@@ -98,8 +109,14 @@ services:
&& tmux send-keys -t zed_driver
'bws && sws && ros2 launch zed_wrapper zed_dual_camera.launch.py pose_cam_serial:='41591402' wire_cam_serial:='44405253' camera_name:=\"robot_1/sensors\" node_name:=\"front_stereo\" ' ENTER
&& sleep infinity"
+ deploy:
+ resources:
+ reservations:
+ devices:
+ - driver: nvidia
+ count: 1
+ capabilities: [gpu]
network_mode: host
- runtime: nvidia
privileged: true
ipc: host
pid: host
diff --git a/simulation/isaac-sim/docker/.bashrc b/simulation/isaac-sim/docker/.bashrc
index 427f6c16f..d3714e8eb 100644
--- a/simulation/isaac-sim/docker/.bashrc
+++ b/simulation/isaac-sim/docker/.bashrc
@@ -121,13 +121,25 @@ fi
# --- ROS2 setup ---
-source /opt/ros/humble/setup.bash
-source /humble_ws/install/setup.bash # isaacsim ros2 package
+source /opt/ros/jazzy/setup.bash
+source /jazzy_ws/install/setup.bash # isaacsim ros2 package
+
# needed for communication with Isaac Sim ROS2 # https://docs.omniverse.nvidia.com/isaacsim/latest/installation/install_ros.html#enabling-the-ros-bridge-extension
export FASTRTPS_DEFAULT_PROFILES_FILE="/isaac-sim/fastdds.xml"
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
# for local development, prevent conflict with other desktops
-export ROS_LOCALHOST_ONLY=1
+export ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET
+
+# --- Environment Separation ---
+# Define the PYTHONPATH specifically for Isaac Sim (Python 3.10)
+# This strips out the System ROS (Python 3.12) paths to prevent conflicts
+export ISAAC_SIM_PYTHONPATH=$(echo $PYTHONPATH | tr ':' '\n' | grep -v "lib/python3.12/site-packages" | paste -sd ':' -):/isaac-sim/exts/isaacsim.ros2.bridge/jazzy/rclpy
+
+# Helper function to run Isaac Sim python scripts with the correct environment
+run_isaac_python() {
+ PYTHONPATH="$ISAAC_SIM_PYTHONPATH" /isaac-sim/python.sh "$@"
+}
+export -f run_isaac_python
# --- Isaac Setup ---
alias runapp="/isaac-sim/runapp.sh --path omniverse://airlab-nucleus.andrew.cmu.edu/Library/Assets/Ascent_Aerosystems/Spirit_UAV/spirit_uav_red_yellow.prop.usd"
diff --git a/simulation/isaac-sim/docker/Dockerfile.isaac-ros b/simulation/isaac-sim/docker/Dockerfile.isaac-ros
index 269211a71..17f38f434 100644
--- a/simulation/isaac-sim/docker/Dockerfile.isaac-ros
+++ b/simulation/isaac-sim/docker/Dockerfile.isaac-ros
@@ -1,9 +1,11 @@
-ARG ISAAC_VERSION="4.5.0"
+ARG ISAAC_VERSION="5.1.0"
# expects context to be the root of the repository, i.e. AirStack/. this is so we can access AirStack/ros_ws/
FROM nvcr.io/nvidia/isaac-sim:${ISAAC_VERSION}
ARG ISAAC_VERSION
WORKDIR /isaac-sim
+USER root
+
# isaac's ros2 launch run_isaacsim.launch.py hardcodes to search in this path, so we have to put the executables here
RUN mkdir -p /root/.local/share/ov/pkg/ && \
ln -s /isaac-sim /root/.local/share/ov/pkg/isaac-sim-${ISAAC_VERSION}
@@ -14,7 +16,7 @@ ENV OMNI_KIT_ALLOW_ROOT=1
# setup environment
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
-ENV ROS_DISTRO=humble
+ENV ROS_DISTRO=jazzy
# setup timezone
RUN echo 'Etc/UTC' > /etc/timezone && \
@@ -64,32 +66,35 @@ RUN set -eux; \
rm -rf "$GNUPGHOME"
# setup ros2 apt source
-RUN echo "deb [ signed-by=/usr/share/keyrings/ros2-latest-archive-keyring.gpg ] http://packages.ros.org/ros2/ubuntu jammy main" > /etc/apt/sources.list.d/ros2-latest.list
+RUN echo "deb [ signed-by=/usr/share/keyrings/ros2-latest-archive-keyring.gpg ] http://packages.ros.org/ros2/ubuntu noble main" > /etc/apt/sources.list.d/ros2-latest.list
# Remove conflicting third-party apt sources that cause libbrotli conflicts
RUN rm -f /etc/apt/sources.list.d/*deb.sury.org*.list || true && apt-get update
-RUN apt-get update && \
- apt-get install -y --allow-downgrades --no-install-recommends libbrotli1=1.0.9-2build6 && \
- apt-mark hold libbrotli1 && \
- apt-get install -y --no-install-recommends \
- libfreetype6-dev \
- libfontconfig1-dev \
- ros-humble-desktop \
- ros-dev-tools \
- python3-rosdep \
- ros-humble-tf2* \
- ros-humble-mavros \
- ros-humble-ackermann-msgs \
- ros-humble-topic-tools \
- ros-humble-grid-map \
- ros-humble-domain-bridge \
- python3-colcon-common-extensions && \
- rm -rf /var/lib/apt/lists/*
+RUN apt-get install -y --no-install-recommends libbrotli1
+RUN apt-mark hold libbrotli1
+RUN apt-get install -y --no-install-recommends libfreetype6-dev
+RUN apt-get install -y --no-install-recommends libfontconfig1-dev
+RUN apt-get install -y --no-install-recommends ros-jazzy-desktop
+RUN apt-get install -y --no-install-recommends ros-dev-tools
+RUN apt-get install -y --no-install-recommends python3-rosdep
+RUN apt-get install -y --no-install-recommends ros-jazzy-tf2*
+RUN apt-get install -y --no-install-recommends ros-jazzy-mavros
+RUN apt-get install -y --no-install-recommends ros-jazzy-ackermann-msgs
+RUN apt-get install -y --no-install-recommends ros-jazzy-topic-tools
+RUN apt-get install -y --no-install-recommends ros-jazzy-grid-map
+RUN apt-get install -y --no-install-recommends ros-jazzy-domain-bridge
+RUN apt-get install -y --no-install-recommends ros-jazzy-moveit
+RUN apt-get install -y --no-install-recommends python3-colcon-common-extensions
+RUN rm -rf /var/lib/apt/lists/*
# setup mavros dependencies
-RUN /opt/ros/humble/lib/mavros/install_geographiclib_datasets.sh
+RUN /opt/ros/jazzy/lib/mavros/install_geographiclib_datasets.sh
+
+# Update LD_LIBRARY_PATH to include ROS2 libraries (Fixes internal rclpy import)
+ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/ros/jazzy/lib:/jazzy/lib
+ENV RMW_IMPLEMENTATION=rmw_fastrtps_cpp
# install python packages
RUN /isaac-sim/python.sh -m pip install --upgrade pip && \
@@ -105,9 +110,9 @@ ARG isaac_dir_name="IsaacSim-ros_workspaces-IsaacSim-${ISAAC_VERSION}"
RUN cd /tmp/ && \
curl -L -O https://github.com/isaac-sim/IsaacSim-ros_workspaces/archive/refs/tags/IsaacSim-${ISAAC_VERSION}.zip && \
unzip IsaacSim-${ISAAC_VERSION}.zip && \
- mv ${isaac_dir_name}/humble_ws /humble_ws && \
- cd /humble_ws && \
- . /opt/ros/humble/setup.sh && \
+ mv ${isaac_dir_name}/jazzy_ws /jazzy_ws && \
+ cd /jazzy_ws && \
+ . /opt/ros/jazzy/setup.sh && \
colcon build --symlink-install && \
rm -rf /tmp/IsaacSim-${ISAAC_VERSION}.zip /tmp/${isaac_dir_name}
@@ -133,6 +138,11 @@ WORKDIR /root/Documents/Kit/shared/exts/
RUN git clone https://github.com/castacks/PegasusSimulator-AirStack-Integration.git /tmp/PegasusSimulator && \
mv /tmp/PegasusSimulator/extensions/pegasus.simulator .
+# Add extension search path configuration for Kit
+# This ensures that /root/Documents/Kit/shared/exts is always searched for extensions
+ARG KIT_ARGS="--ext-folder /root/Documents/Kit/shared/exts"
+ENV OMNI_APP_ARGS="${KIT_ARGS}"
+
# rm -rf /tmp/PegasusSimulator
ENV ISAACSIM_PATH=/isaac-sim
ENV ACCEPT_EULA="Y"
@@ -156,7 +166,7 @@ RUN git clone https://github.com/tmux-plugins/tpm /root/.tmux/plugins/tpm
# copy FastDDS config
COPY docker/fastdds.xml /isaac-sim/fastdds.xml
-# ROS2 humble launch script seeks this
+# ROS2 launch script seeks this
RUN ln -s /isaac-sim /root/isaacsim
# Cleanup. Prevent people accidentally doing git commits as root in Docker
diff --git a/simulation/isaac-sim/docker/docker-compose.yaml b/simulation/isaac-sim/docker/docker-compose.yaml
index cd7aff4d7..e08f417ff 100644
--- a/simulation/isaac-sim/docker/docker-compose.yaml
+++ b/simulation/isaac-sim/docker/docker-compose.yaml
@@ -17,7 +17,7 @@ services:
tmux new -d -s isaac;
if [ $$AUTOLAUNCH = 'true' ]; then
if [ \"${ISAAC_SIM_USE_STANDALONE_SCRIPT}\" = 'true' ]; then
- tmux send-keys -t isaac '/isaac-sim/python.sh /root/AirStack/simulation/isaac-sim/launch_scripts/${ISAAC_SIM_SCRIPT_NAME}' ENTER
+ tmux send-keys -t isaac 'run_isaac_python /root/AirStack/simulation/isaac-sim/launch_scripts/${ISAAC_SIM_SCRIPT_NAME}' ENTER
else
tmux send-keys -t isaac 'ros2 launch isaacsim run_isaacsim.launch.py gui:=\"${ISAAC_SIM_GUI}\" play_sim_on_start:=\"${PLAY_SIM_ON_START}\" ' ENTER
fi
@@ -65,7 +65,7 @@ services:
- $HOME/Documents/isaac_sim_data/data:/root/.local/share/ov/data:rw
- $HOME/documents/isaac_sim_data/documents:/root/Documents:rw
# IMPORTANT: set the version number without the trailing .0
- - ./user.config.json:/root/.local/share/ov/data/Kit/Isaac-Sim Full/4.5/user.config.json:rw
+ - ./user.config.json:/root/.local/share/ov/data/Kit/Isaac-Sim Full/5.1/user.config.json:rw
- ./ui.py:/isaac-sim/kit/exts/omni.kit.widget.nucleus_connector/omni/kit/widget/nucleus_connector/ui.py:rw
# developer stuff
- .dev:/root/.dev:rw # developer config
diff --git a/simulation/isaac-sim/extensions/PegasusSimulator b/simulation/isaac-sim/extensions/PegasusSimulator
index f6fae8d34..15379fac8 160000
--- a/simulation/isaac-sim/extensions/PegasusSimulator
+++ b/simulation/isaac-sim/extensions/PegasusSimulator
@@ -1 +1 @@
-Subproject commit f6fae8d34d9f95470c5976c11ca8a670421fbfb2
+Subproject commit 15379fac8d487b03af5a1b950541bab060b0b7bd
diff --git a/simulation/isaac-sim/launch_scripts/example_one_px4_pegasus_launch_script.py b/simulation/isaac-sim/launch_scripts/example_one_px4_pegasus_launch_script.py
index 60c24716a..b6c12b4e3 100755
--- a/simulation/isaac-sim/launch_scripts/example_one_px4_pegasus_launch_script.py
+++ b/simulation/isaac-sim/launch_scripts/example_one_px4_pegasus_launch_script.py
@@ -13,6 +13,9 @@
# Start Isaac Sim's simulation environment (Must start this before importing omni modules)
simulation_app = SimulationApp({"headless": False})
+import rclpy
+print(f"[Launcher] SUCCESS: rclpy imported from {rclpy.__file__}")
+
import omni.kit.app
import omni.timeline
from omni.isaac.core.world import World
@@ -40,9 +43,9 @@
# Explicitly enable required extensions
ext_manager = omni.kit.app.get_app().get_extension_manager()
+
for ext in [
- # "airlab.airstack",
- "omni.physx.forcefields",
+ "airlab.airstack",
"omni.graph.core", # Core runtime for OmniGraph engine
"omni.graph.action", # Action Graph framework
"omni.graph.action_nodes", # Built-in Action Graph node library
@@ -52,11 +55,15 @@
"omni.graph.window.action", # Action Graph editor window
"omni.graph.window.generic", # Generic graph UI tools
"omni.graph.ui_nodes", # UI node building helpers
- "airlab.pegasus", # Airlab extension Pegasus core extension
"pegasus.simulator",
]:
if not ext_manager.is_extension_enabled(ext):
- ext_manager.set_extension_enabled(ext, True)
+ print(f"[Launcher] Enabling extension: {ext}")
+ # Try both methods for robustness in different Kit versions
+ ext_manager.set_extension_enabled_immediate(ext, True)
+ print(f"[Launcher] Successfully enabled extension: {ext} via immediate method")
+ else:
+ print(f"[Launcher] Extension already enabled: {ext}")
class PegasusApp:
@@ -75,10 +82,10 @@ def __init__(self):
# Load default environment. You can replace with url or file path of any desired environment.
self.pg.load_environment(SIMULATION_ENVIRONMENTS["Curved Gridroom"])
-
- # Spawn a PX4 multirotor drone with a specified vehicle ID and domain ID
- # PX4 udp port = 14540 + (vehicle_id)
- # Domain ID is for ROS2 domain communication. As of now, it should match the vehicle id by convention.
+
+ # # Spawn a PX4 multirotor drone with a specified vehicle ID and domain ID
+ # # PX4 udp port = 14540 + (vehicle_id)
+ # # Domain ID is for ROS2 domain communication. As of now, it should match the vehicle id by convention.
graph_handle = spawn_px4_multirotor_node(
pegasus_node_name="PX4Multirotor",
drone_prim="/World/drone/base_link",
diff --git a/simulation/isaac-sim/launch_scripts/example_two_px4_pegasus_launch_script.py b/simulation/isaac-sim/launch_scripts/example_two_px4_pegasus_launch_script.py
index 329f1170c..768807739 100755
--- a/simulation/isaac-sim/launch_scripts/example_two_px4_pegasus_launch_script.py
+++ b/simulation/isaac-sim/launch_scripts/example_two_px4_pegasus_launch_script.py
@@ -40,9 +40,9 @@
# Explicitly enable required extensions
ext_manager = omni.kit.app.get_app().get_extension_manager()
+
for ext in [
- # "airlab.airstack",
- "omni.physx.forcefields",
+ "airlab.airstack",
"omni.graph.core", # Core runtime for OmniGraph engine
"omni.graph.action", # Action Graph framework
"omni.graph.action_nodes", # Built-in Action Graph node library
@@ -52,11 +52,15 @@
"omni.graph.window.action", # Action Graph editor window
"omni.graph.window.generic", # Generic graph UI tools
"omni.graph.ui_nodes", # UI node building helpers
- "airlab.pegasus", # Airlab extension Pegasus core extension
"pegasus.simulator",
]:
if not ext_manager.is_extension_enabled(ext):
- ext_manager.set_extension_enabled(ext, True)
+ print(f"[Launcher] Enabling extension: {ext}")
+ # Try both methods for robustness in different Kit versions
+ ext_manager.set_extension_enabled_immediate(ext, True)
+ print(f"[Launcher] Successfully enabled extension: {ext} via immediate method")
+ else:
+ print(f"[Launcher] Extension already enabled: {ext}")
class PegasusApp:
@@ -83,6 +87,7 @@ def __init__(self):
graph_handle = spawn_px4_multirotor_node(
pegasus_node_name="PX4Multirotor",
drone_prim="/World/drone1/base_link",
+ robot_name="robot_1",
vehicle_id=1, # defines MAVLink port offset
domain_id=1, # defines ROS2 domain ID
usd_file="/root/Documents/Kit/shared/exts/pegasus.simulator/pegasus/simulator/assets/Robots/Iris/iris.usd",
@@ -94,6 +99,7 @@ def __init__(self):
add_zed_stereo_camera_subgraph(
parent_graph_handle=graph_handle,
drone_prim="/World/drone1/base_link",
+ robot_name="robot_1",
camera_name="ZEDCamera",
camera_offset = [0.1, 0.0, 0.0], # X, Y, Z offset from drone base_link
camera_rotation_offset = [0.0, 0.0, 0.0], # Rotation in degrees (roll, pitch, yaw)
@@ -103,6 +109,7 @@ def __init__(self):
add_ouster_lidar_subgraph(
parent_graph_handle=graph_handle,
drone_prim="/World/drone1/base_link",
+ robot_name="robot_1",
lidar_name="OS1_REV6_128_10hz___512_resolution",
lidar_offset = [0.0, 0.0, 0.025], # X, Y, Z offset from drone base_link
lidar_rotation_offset = [0.0, 0.0, 0.0], # Rotation in degrees (roll, pitch, yaw)
@@ -126,6 +133,7 @@ def __init__(self):
add_zed_stereo_camera_subgraph(
parent_graph_handle=graph_handle,
drone_prim="/World/drone2/base_link",
+ robot_name="robot_2",
camera_name="ZEDCamera",
camera_offset = [0.1, 0.0, 0.0], # X, Y, Z offset from drone base_link
camera_rotation_offset = [0.0, 0.0, 0.0], # Rotation in degrees (roll, pitch, yaw)
@@ -135,6 +143,7 @@ def __init__(self):
add_ouster_lidar_subgraph(
parent_graph_handle=graph_handle,
drone_prim="/World/drone2/base_link",
+ robot_name="robot_2",
lidar_name="OS1_REV6_128_10hz___512_resolution",
lidar_offset = [0.0, 0.0, 0.025], # X, Y, Z offset from drone base_link
lidar_rotation_offset = [0.0, 0.0, 0.0], # Rotation in degrees (roll, pitch, yaw)
diff --git a/simulation/simple-sim/docker/docker-compose.yaml b/simulation/simple-sim/docker/docker-compose.yaml
index 07b61f6a6..65b3b6981 100644
--- a/simulation/simple-sim/docker/docker-compose.yaml
+++ b/simulation/simple-sim/docker/docker-compose.yaml
@@ -20,7 +20,7 @@ services:
tty: true
ipc: host
privileged: true
- runtime: nvidia
+ # runtime: nvidia <-- Removed deprecated runtime key
networks:
airstack_network:
ipv4_address: 172.31.0.200