diff --git a/.env b/.env index 767ebe0e7..50ed20f7d 100644 --- a/.env +++ b/.env @@ -1,14 +1,60 @@ +# This is the main .env file for AirStack, which sets docker compose variables for variable interpolation. +# Standard Usage: docker compose --env-file .env up + +# See overrides/ for overriding specific variables. +# To override, run docker compose --env-file .env --env-file overrides/.env up. Any variables set in +# the following --env-file will override previous ones. + +# Warning: all variables get propagated to all sub-level docker-compose files, so be careful about naming conflicts. + +# =============== PROJECT ==================== # This top-level .env file under AirStack/ defines variables that are propagated through docker-compose.yaml PROJECT_NAME="airstack" -# auto-generated from git commit hash +# Auto-generated from git commit hash DOCKER_IMAGE_TAG="f3f93a5" -# can replace with your docker hub username +# Can replace with your docker hub username PROJECT_DOCKER_REGISTRY="airlab-storage.andrew.cmu.edu:5001/shared" +# ============================================ + +# ================ SIMULATION ================= DEFAULT_ISAAC_SCENE="omniverse://airlab-storage.andrew.cmu.edu:8443/Projects/AirStack/AFCA/fire_academy_faro_with_sky.scene.usd" PLAY_SIM_ON_START="true" -# the file under robot/docker/ that contains the robot's environment variables -ROBOT_ENV_FILE_NAME="robot.env" +# ============================================= + +# ================= ROBOT ===================== +# See robot/docker/docker-compose.yaml for how these variables get propagated in +# the container's entry command. +ROBOT_LAUNCH_PACKAGE="robot_bringup" +ROBOT_LAUNCH_FILE="robot.launch.xml" + +# See robot-base-docker-compose.yaml for how these variables get propagated. +# We use relative launch path (not file) because these are launch files get included +# from the top level robot launch file, and the include-format requires a path. +AUTONOMY_LAUNCH_PACKAGE="autonomy_bringup" +AUTONOMY_LAUNCH_PATH="launch/autonomy.launch.xml" +# -- +INTERFACE_LAUNCH_PACKAGE="interface_bringup" +INTERFACE_LAUNCH_PATH="launch/interface.launch.xml" +# -- +SENSORS_LAUNCH_PACKAGE="sensors_bringup" +SENSORS_LAUNCH_PATH="launch/sensors.launch.xml" +# -- +PERCEPTION_LAUNCH_PACKAGE="perception_bringup" +PERCEPTION_LAUNCH_PATH="launch/perception.launch.xml" +# -- +LOCAL_LAUNCH_PACKAGE="local_bringup" +LOCAL_LAUNCH_PATH="launch/local.launch.xml" +# -- +GLOBAL_LAUNCH_PACKAGE="global_bringup" +GLOBAL_LAUNCH_PATH="launch/global.launch.xml" +# -- +BEHAVIOR_LAUNCH_PACKAGE="behavior_bringup" +BEHAVIOR_LAUNCH_PATH="launch/behavior.launch.xml" +# =============================================== -# format as "[package_name] [launch_file_name]" -ROBOT_MAIN_LAUNCH="robot_bringup robot.launch.xml" -GCS_MAIN_LAUNCH="gcs_bringup gcs.launch.xml" +# =========== GROUND CONTROL STATION ============ +# See ground_control_station/docker/docker-compose.yaml for how these variables +# get propagated in the container's entry command. +GCS_LAUNCH_PACKAGE="gcs_bringup" +GCS_LAUNCH_FILE="gcs.launch.xml" +# =============================================== \ No newline at end of file diff --git a/.github/workflows/main_version_increment.yaml b/.github/workflows/main_version_increment.yaml deleted file mode 100644 index 6440dbd88..000000000 --- a/.github/workflows/main_version_increment.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: Check Project Version Increment - -on: - pull_request: - branches: [main] - -jobs: - check_version: - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - - name: Get Current Version from PR - run: | - PR_VERSION=$(grep 'PROJECT_VERSION=' .env | cut -d'=' -f2 | tr -d '"') - echo "PR_VERSION=$PR_VERSION" >> $GITHUB_ENV - - - name: Get Previous Version from Main - run: | - git fetch origin main - PREV_VERSION=$(git show origin/main:.env | grep 'PROJECT_VERSION=' | cut -d'=' -f2 | tr -d '"') - echo "PREV_VERSION=$PREV_VERSION" >> $GITHUB_ENV - - - name: Validate Version Increment - run: | - compare_versions() { - IFS='.' read -r -a CUR <<< "$PR_VERSION" - IFS='.' read -r -a PREV <<< "$PREV_VERSION" - - if (( CUR[0] > PREV[0] )); then exit 0; fi - if (( CUR[0] == PREV[0] && CUR[1] > PREV[1] )); then exit 0; fi - if (( CUR[0] == PREV[0] && CUR[1] == PREV[1] && CUR[2] > PREV[2] )); then exit 0; fi - echo "ERROR: PROJECT_VERSION must be incremented semantically. Current: $PR_VERSION, Previous: $PREV_VERSION" - exit 1 - } - compare_versions - - - name: Report Success - run: | - echo "PROJECT_VERSION successfully incremented: $PR_VERSION" diff --git a/airstack.sh b/airstack.sh index 6def39f97..dcd9b3a2d 100755 --- a/airstack.sh +++ b/airstack.sh @@ -34,7 +34,7 @@ function print_usage { echo "Available commands:" # Sort commands alphabetically - local sorted_ommands=($(echo "${!COMMANDS[@]}" | tr ' ' '\n' | sort)) + local sorted_commands=($(echo "${!COMMANDS[@]}" | tr ' ' '\n' | sort)) # Calculate the longest command name for padding local max_len=0 @@ -505,9 +505,58 @@ function cmd_setup { function cmd_up { check_docker - # Build docker-compose command - local cmd="docker compose -f $PROJECT_ROOT/docker-compose.yaml up $@ -d" + local env_files=() + local other_args=() + + # Convert arguments to array for easier processing + local args=("$@") + local i=0 + + while [ $i -lt ${#args[@]} ]; do + local arg="${args[$i]}" + + if [[ "$arg" == "--env-file" ]]; then + # Get the next argument as the env file path + i=$((i+1)) + if [ $i -lt ${#args[@]} ]; then + env_files+=("--env-file" "${args[$i]}") + else + log_error "Missing value for --env-file argument" + return 1 + fi + elif [[ "$arg" == "--env-file="* ]]; then + # Handle --env-file=path format + env_files+=("$arg") + else + # Skip the command name 'up' itself + if [[ "$arg" != "up" ]]; then + other_args+=("$arg") + fi + fi + + i=$((i+1)) + done + + # Build docker-compose command with env files before the 'up' command + local cmd="docker compose -f $PROJECT_ROOT/docker-compose.yaml" + + # Add all env files + for env_file in "${env_files[@]}"; do + cmd="$cmd $env_file" + done + + # Add the 'up' command and other arguments + cmd="$cmd up" + # Add other arguments if any + if [ ${#other_args[@]} -gt 0 ]; then + cmd="$cmd ${other_args[*]}" + fi + + # Add -d flag + cmd="$cmd -d" + + log_info "Executing: $cmd" eval "$cmd" log_info "Services brought up successfully" } @@ -775,13 +824,41 @@ if [ $# -eq 0 ]; then exit 0 fi -command="$1" -shift +# Simple command detection - just look for the first argument that matches a command +command="" + +# First check if the first argument is a command +if [[ -n "${COMMANDS[$1]}" || "$1" == "commands" || "$1" == "help" ]]; then + command="$1" +else + # Otherwise, look through all arguments for a command + for arg in "$@"; do + if [[ -n "${COMMANDS[$arg]}" || "$arg" == "commands" || "$arg" == "help" ]]; then + command="$arg" + break + fi + done + + # If still no command found, show usage + if [ -z "$command" ]; then + print_usage + exit 1 + fi +fi # Check if command exists if [[ -n "${COMMANDS[$command]}" ]]; then - # Execute the command function - ${COMMANDS[$command]} "$@" + # Execute the command function with filtered arguments + # We need to remove the command name from the arguments + filtered_args=() + for arg in "$@"; do + if [[ "$arg" != "$command" ]]; then + filtered_args+=("$arg") + fi + done + + # Execute the command with the filtered arguments + ${COMMANDS[$command]} "${filtered_args[@]}" elif [ "$command" == "commands" ]; then # Special case for listing all commands list_commands diff --git a/docs/development/docker_usage.md b/docs/development/docker_usage.md index f509e9082..ece633f1e 100644 --- a/docs/development/docker_usage.md +++ b/docs/development/docker_usage.md @@ -1,4 +1,4 @@ -# Workflow with Docker and Docker Compose +# Launch Workflow with Docker and Docker Compose To mimic interacting with multiple real world robots, we use Docker Compose to manage Docker containers that isolate the simulation, each robot, and the ground control station. @@ -163,3 +163,32 @@ graph TD style D fill:#fbf,stroke:#333,stroke-width:2px ``` + +## Docker Compose Variable Overrides +Sometimes you may want to test different configurations of the autonomy stack. For example, you may want to disable automatically playing the sim on startup, +or to change a child launch file. + +The `docker compose` workflow is designed to support these overrides for local development. +`docker compose` uses `.env` files to set docker-compose variables that get propagated and interpolated into `docker-compose.yaml` files. +See the [docker compose documentation](https://docs.docker.com/compose/how-tos/environment-variables/variable-interpolation/) for more details. + +The default `.env` file is in the project root directory. +When no `--env-file` argument is passed to `docker compose`, it automatically uses this default `.env` file. + +To override the default `.env` file, you can pass the `--env-file` argument to `docker compose` with a path to your custom `.env` file. + +For example, this command disables playing the simulation on startup by overriding the `PLAY_SIM_ON_START` variable: +```bash +docker compose --env-file .env --env-file overrides/no_play_sim_on_start.env up -d +``` + +As another example, this command changes the perception launch file to `perception_no_macvo.launch.xml`: +```bash +docker compose --env-file .env --env-file overrides/no_macvo.env up -d +``` + + +When overriding, the default `.env` file must be loaded first. The overrides are applied on top of it. + + + diff --git a/docs/getting_started.md b/docs/getting_started.md index ce9028a73..d51cbdcb6 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -3,6 +3,10 @@ !!! warning "" AirStack is currently in ALPHA and only meant for internal usage. + + We'd really appreciate your feedback and contributions to improve this project for everyone! + Please join our #airstack channel on Slack to contribute or ask questions. + You will need to have an account with AirLab to access the AirLab Docker registry, Nucleus server, and other resources. The API and functionality are not stable and are subject to change. @@ -16,6 +20,8 @@ You need at least 25GB free to install the Docker image. Check the hardware requirements for the NVIDIA Isaac Sim [here](https://docs.isaacsim.omniverse.nvidia.com/latest/installation/requirements.html). A GPU of GeForce RTX 4080 or higher is recommended for the best performance. +AirStack is primarily tested on Ubuntu 22.04. + ## Clone ```bash git clone --recursive -j8 git@github.com:castacks/AirStack.git diff --git a/ground_control_station/docker/ground-control-station-base-docker-compose.yaml b/ground_control_station/docker/ground-control-station-base-docker-compose.yaml index fc1879e9a..8cbfc6aba 100644 --- a/ground_control_station/docker/ground-control-station-base-docker-compose.yaml +++ b/ground_control_station/docker/ground-control-station-base-docker-compose.yaml @@ -12,7 +12,7 @@ services: bash -c "ssh service restart; tmux new -d -s gcs_bringup && tmux send-keys -t gcs_bringup - 'bws && sws; ros2 launch ${GCS_MAIN_LAUNCH}' ENTER + 'bws && sws; ros2 launch ${GCS_LAUNCH_PACKAGE} ${GCS_LAUNCH_FILE}' ENTER && sleep infinity" # Interactive shell stdin_open: true # docker run -i diff --git a/overrides/no_macvo.env b/overrides/no_macvo.env new file mode 100644 index 000000000..a4013c41a --- /dev/null +++ b/overrides/no_macvo.env @@ -0,0 +1,2 @@ +# run as docker compose --env-file .env --env-file overrides/no_macvo.env up +PERCEPTION_LAUNCH_FILE="perception_no_macvo.launch.xml" diff --git a/overrides/no_play_sim_on_start.env b/overrides/no_play_sim_on_start.env new file mode 100644 index 000000000..43d142631 --- /dev/null +++ b/overrides/no_play_sim_on_start.env @@ -0,0 +1,2 @@ +# run as docker compose --env-file .env --env-file overrides/no_play_sim_on_start.env up +PLAY_SIM_ON_START="false" \ No newline at end of file diff --git a/robot/docker/docker-compose.yaml b/robot/docker/docker-compose.yaml index 16babefd5..956312f76 100644 --- a/robot/docker/docker-compose.yaml +++ b/robot/docker/docker-compose.yaml @@ -23,7 +23,7 @@ services: tmux new -d -s robot_bringup && tmux send-keys -t robot_bringup 'bws && sws && - ros2 launch ${ROBOT_MAIN_LAUNCH}' ENTER + ros2 launch ${ROBOT_LAUNCH_PACKAGE} ${ROBOT_LAUNCH_FILE}' ENTER && sleep infinity" # assumes you're connected to work internet, so creates a network to isolate from other developers on your work internet networks: @@ -65,7 +65,7 @@ services: 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_bringup robot.launch.xml sim:="false" ' ENTER + DATE=$(date | sed \"s/ /_/g\" | sed \"s/:/_/g\") ros2 launch ${ROBOT_LAUNCH_PACKAGE} ${ROBOT_LAUNCH_FILE} sim:="false" ' ENTER && sleep infinity" runtime: nvidia # assumes network isolation via a physical router, so uses network_mode=host diff --git a/robot/docker/robot-base-docker-compose.yaml b/robot/docker/robot-base-docker-compose.yaml index 932657d02..22775ea54 100644 --- a/robot/docker/robot-base-docker-compose.yaml +++ b/robot/docker/robot-base-docker-compose.yaml @@ -10,8 +10,27 @@ services: environment: - DISPLAY - QT_X11_NO_MITSHM=1 - env_file: - - ${ROBOT_ENV_FILE_NAME} + # docker compose interpolation to env variables + - AUTONOMY_LAUNCH_PACKAGE=${AUTONOMY_LAUNCH_PACKAGE} + - AUTONOMY_LAUNCH_PATH=${AUTONOMY_LAUNCH_PATH} + # -- + - INTERFACE_LAUNCH_PACKAGE=${INTERFACE_LAUNCH_PACKAGE} + - INTERFACE_LAUNCH_PATH=${INTERFACE_LAUNCH_PATH} + # -- + - SENSORS_LAUNCH_PACKAGE=${SENSORS_LAUNCH_PACKAGE} + - SENSORS_LAUNCH_PATH=${SENSORS_LAUNCH_PATH} + # -- + - PERCEPTION_LAUNCH_PACKAGE=${PERCEPTION_LAUNCH_PACKAGE} + - PERCEPTION_LAUNCH_PATH=${PERCEPTION_LAUNCH_PATH} + # -- + - LOCAL_LAUNCH_PACKAGE=${LOCAL_LAUNCH_PACKAGE} + - LOCAL_LAUNCH_PATH=${LOCAL_LAUNCH_PATH} + # -- + - GLOBAL_LAUNCH_PACKAGE=${GLOBAL_LAUNCH_PACKAGE} + - GLOBAL_LAUNCH_PATH=${GLOBAL_LAUNCH_PATH} + # -- + - BEHAVIOR_LAUNCH_PACKAGE=${BEHAVIOR_LAUNCH_PACKAGE} + - BEHAVIOR_LAUNCH_PATH=${BEHAVIOR_LAUNCH_PATH} deploy: # let it use the GPU resources: diff --git a/robot/docker/robot.env b/robot/docker/robot.env deleted file mode 100644 index 807fc0053..000000000 --- a/robot/docker/robot.env +++ /dev/null @@ -1,2 +0,0 @@ -# These become environment variables in the robot container -USE_MACVO="true" \ No newline at end of file diff --git a/robot/ros_ws/src/autonomy/2_perception/perception_bringup/launch/perception.launch.xml b/robot/ros_ws/src/autonomy/2_perception/perception_bringup/launch/perception.launch.xml index 31883577d..d0efcc47a 100644 --- a/robot/ros_ws/src/autonomy/2_perception/perception_bringup/launch/perception.launch.xml +++ b/robot/ros_ws/src/autonomy/2_perception/perception_bringup/launch/perception.launch.xml @@ -4,7 +4,7 @@ - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/robot/ros_ws/src/autonomy/autonomy_bringup/launch/autonomy.launch.xml b/robot/ros_ws/src/autonomy/autonomy_bringup/launch/autonomy.launch.xml index 0380d6c7e..88cfb088e 100644 --- a/robot/ros_ws/src/autonomy/autonomy_bringup/launch/autonomy.launch.xml +++ b/robot/ros_ws/src/autonomy/autonomy_bringup/launch/autonomy.launch.xml @@ -1,22 +1,22 @@ - + - + - + - + - + - + \ No newline at end of file diff --git a/robot/ros_ws/src/robot_bringup/launch/robot.launch.xml b/robot/ros_ws/src/robot_bringup/launch/robot.launch.xml index 6c93953ad..b76d1727d 100644 --- a/robot/ros_ws/src/robot_bringup/launch/robot.launch.xml +++ b/robot/ros_ws/src/robot_bringup/launch/robot.launch.xml @@ -37,7 +37,7 @@ - + diff --git a/robot/ros_ws/src/robot_bringup/launch/static_transforms.launch.xml b/robot/ros_ws/src/robot_bringup/launch/static_transforms.launch.xml index e5fa843ba..0a2da8b2e 100644 --- a/robot/ros_ws/src/robot_bringup/launch/static_transforms.launch.xml +++ b/robot/ros_ws/src/robot_bringup/launch/static_transforms.launch.xml @@ -1,19 +1,13 @@ + + + args="0 0 0 0 0 0 mavros_enu map" /> - -