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
18 changes: 18 additions & 0 deletions airstack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<axis xyz="0. 0. 1."/>
</joint>
<joint name="joint_OS1_REV6_128_10hz___512_resolution-lidar" type="fixed">
<origin xyz="0. 0. 0.03622" rpy="0 1.57 1.57"/>
<origin xyz="0. 0. 0.03622" rpy="0 0 1.57"/>
<parent link="OS1_REV6_128_10hz___512_resolution"/>
<child link="lidar"/>
</joint>
Expand Down
1 change: 0 additions & 1 deletion config/isaac_sim_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion gcs/docker/gcs-base-docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ services:
- capabilities: [gpu]
count: 1
driver: nvidia
runtime: nvidia
entrypoint: ''
environment:
- AUTOLAUNCH=${AUTOLAUNCH:-false}
Expand Down
8 changes: 6 additions & 2 deletions robot/docker/.bashrc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 20 additions & 3 deletions robot/docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down
18 changes: 15 additions & 3 deletions simulation/isaac-sim/docker/.bashrc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
60 changes: 35 additions & 25 deletions simulation/isaac-sim/docker/Dockerfile.isaac-ros
Original file line number Diff line number Diff line change
@@ -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}
Expand All @@ -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 && \
Expand Down Expand Up @@ -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 && \
Expand All @@ -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}

Expand All @@ -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"
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions simulation/isaac-sim/docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion simulation/isaac-sim/extensions/PegasusSimulator
Submodule PegasusSimulator updated 26 files
+12 −1 README.md
+11 −0 docs/index.rst
+2 −2 docs/source/features/ardupilot.rst
+101 −17 docs/source/setup/installation.rst
+1 −1 docs/source/tutorials/create_custom_backend.rst
+1 −1 docs/source/tutorials/create_simulation_with_people.rst
+1 −1 docs/source/tutorials/create_standalone_application.rst
+1 −1 docs/source/tutorials/create_standalone_simulation.rst
+2 −2 docs/source/tutorials/run_extension_mode.rst
+1 −1 examples/10_graphs.py
+3 −0 examples/3_ros2_single_vehicle.py
+2 −2 extensions/pegasus.simulator/config/extension.toml
+124 −82 extensions/pegasus.simulator/pegasus/simulator/logic/backends/ardupilot_mavlink_backend.py
+9 −9 extensions/pegasus.simulator/pegasus/simulator/logic/backends/ros2_backend.py
+7 −2 extensions/pegasus.simulator/pegasus/simulator/logic/backends/tools/px4_launch_tool.py
+30 −17 extensions/pegasus.simulator/pegasus/simulator/logic/graphical_sensors/monocular_camera.py
+28 −2 extensions/pegasus.simulator/pegasus/simulator/logic/graphs/ros2_camera_graph.py
+35 −16 extensions/pegasus.simulator/pegasus/simulator/logic/people/person.py
+1 −25 extensions/pegasus.simulator/pegasus/simulator/ogn/OgnPegasusMultirotorArduPilotNodeDatabase.py
+1 −28 extensions/pegasus.simulator/pegasus/simulator/ogn/OgnPegasusMultirotorPX4NodeDatabase.py
+0 −2 extensions/pegasus.simulator/pegasus/simulator/ogn/api/shared_node_names.py
+0 −11 extensions/pegasus.simulator/pegasus/simulator/ogn/api/spawn_multirotor.py
+13 −11 extensions/pegasus.simulator/pegasus/simulator/ogn/python/nodes/OgnPegasusMultirotorNodeBase.py
+1 −1 extensions/pegasus.simulator/pegasus/simulator/params.py
+1 −1 extensions/pegasus.simulator/pegasus/simulator/ui/ui_delegate.py
+1 −1 extensions/pegasus.simulator/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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",
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Loading