diff --git a/.agents/skills/bump-version-and-release/SKILL.md b/.agents/skills/bump-version-and-release/SKILL.md index 45c511309..61aa4d309 100644 --- a/.agents/skills/bump-version-and-release/SKILL.md +++ b/.agents/skills/bump-version-and-release/SKILL.md @@ -28,7 +28,7 @@ If in doubt, bump. The CI gate enforces a strict increment vs. the base branch The version-increment check still runs on every PR, but the **only** thing it requires is that VERSION be valid semver and strictly greater than the base. For documentation-only PRs you have two options: -- **Preferred:** still bump the patch (or pre-release counter) by one. It costs nothing, keeps the gate happy, and the docker-build only fires on push to `main`/`develop` *and* a VERSION change, so an extra alpha bump on a docs PR is cheap. +- **Preferred:** still bump the patch (or pre-release counter) by one. It costs nothing, keeps the gate happy, and the docker-build only fires on push to `main`/`develop` *and* a VERSION change, so an extra dev bump on a docs PR is cheap. - **If you really want to avoid a rebuild:** the docker-build workflow only triggers when `.env` is in the changed paths AND `VERSION=` differs from `HEAD~1`. So a docs-only PR that does not touch `.env` will not rebuild — but the PR will still fail the increment check unless you bump. There is no clean way to "opt out" of the check; the simplest path is to bump the pre-release counter. Do **not** bump for: @@ -47,17 +47,17 @@ Three workflows in `.github/workflows/` interact with `VERSION`: - **Trigger:** every `pull_request`. - **Logic:** runs a Python script that reads `VERSION=` from the PR's `.env`, reads the same line from `origin/:.env`, and validates: - - PR version matches the regex `^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$` - - PR version is **strictly greater than** base version, with pre-release ordering `alpha < beta < rc < (no suffix / release)` + - PR version matches the regex `^(\d+)\.(\d+)\.(\d+)(?:-(dev|beta|rc)\.(\d+))?$` + - PR version is **strictly greater than** base version, with pre-release ordering `dev < beta < rc < (no suffix / release)` - **Accepted formats** (from the workflow's own error message): ``` MAJOR.MINOR.PATCH (e.g. 1.2.3) - MAJOR.MINOR.PATCH-alpha.N (e.g. 1.3.0-alpha.1) + MAJOR.MINOR.PATCH-dev.N (e.g. 1.3.0-dev.1) MAJOR.MINOR.PATCH-beta.N (e.g. 1.3.0-beta.2) MAJOR.MINOR.PATCH-rc.N (e.g. 1.3.0-rc.3) ``` -- **Rejected:** `1.2`, `1.2.3-rc1` (no dot before N), `1.2.3-dev`, `1.2.3+meta`, `v1.2.3`, anything with build metadata. -- **Comparison tuple:** `(major, minor, patch, pre_rank, pre_num)` where `pre_rank = alpha:0, beta:1, rc:2, release:3`. So `1.3.0-alpha.5 < 1.3.0-beta.1 < 1.3.0-rc.1 < 1.3.0`. A release version always sorts above any pre-release of the same `MAJOR.MINOR.PATCH`. +- **Rejected:** `1.2`, `1.2.3-rc1` (no dot before N), `1.2.3-dev` (missing the `.N` counter), `1.2.3-alpha.4` (the legacy `alpha` tag was replaced by `dev` in 0.20.0), `1.2.3+meta`, `v1.2.3`, anything with build metadata. +- **Comparison tuple:** `(major, minor, patch, pre_rank, pre_num)` where `pre_rank = dev:0, beta:1, rc:2, release:3`. So `1.3.0-dev.5 < 1.3.0-beta.1 < 1.3.0-rc.1 < 1.3.0`. A release version always sorts above any pre-release of the same `MAJOR.MINOR.PATCH`. ### 2. `docker-build.yml` — the publish trigger @@ -82,11 +82,11 @@ So the full release path is: bump `VERSION` → PR → merge to `main`/`develop` ## Choosing the Bump Type -Use this decision tree on the **current** version (currently `0.18.0-alpha.7`): +Use this decision tree on the **current** version (e.g. `0.21.0-dev.7`): ``` Is this a breaking API/topic/interface change? -├── yes → bump MAJOR, reset MINOR=0, PATCH=0 (e.g. 0.18.0-alpha.7 → 1.0.0-alpha.1 if pre-1.0) +├── yes → bump MAJOR, reset MINOR=0, PATCH=0 (e.g. 0.21.0-dev.7 → 1.0.0-dev.1 if pre-1.0) └── no ├── New feature / new module / new Docker image content? │ └── yes → bump MINOR, reset PATCH=0 (e.g. 0.18.0 → 0.19.0) @@ -94,16 +94,16 @@ Is this a breaking API/topic/interface change? └── yes → bump PATCH (e.g. 0.18.0 → 0.18.1) Are you mid-cycle on a pre-release line (suffix present)? -├── Same line, more iteration → increment N (0.18.0-alpha.7 → 0.18.0-alpha.8) -├── Promoting alpha → beta → reset N to 1 (0.18.0-alpha.7 → 0.18.0-beta.1) +├── Same line, more iteration → increment N (0.21.0-dev.7 → 0.21.0-dev.8) +├── Promoting dev → beta → reset N to 1 (0.21.0-dev.7 → 0.21.0-beta.1) ├── Promoting beta → rc → reset N to 1 (0.18.0-beta.4 → 0.18.0-rc.1) └── Promoting rc → release → drop suffix (0.18.0-rc.3 → 0.18.0) ``` Notes: -- AirStack is pre-1.0; many "breaking" changes still bump MINOR rather than MAJOR. Use judgment, and prefer pre-release suffixes (`-alpha.N`) for the active development line so feature PRs do not have to fight over MINOR numbers. -- The current pattern in git history is per-PR alpha bumps on the development line and a final un-suffixed bump at release time (e.g. `0.16.1-rc → 0.16.1`, `0.17.0-rc1 → 0.17.0` — note the older `-rc1` form predates the current validator and would be rejected today; use `-rc.1`). +- AirStack is pre-1.0; many "breaking" changes still bump MINOR rather than MAJOR. Use judgment, and prefer pre-release suffixes (`-dev.N`) for the active development line so feature PRs do not have to fight over MINOR numbers. +- The current pattern in git history is per-PR dev bumps on the development line and a final un-suffixed bump at release time. History before 0.21.0 used `-alpha.N` for this role, and even older releases used forms like `-rc1` — both predate the current validator and would be rejected today; use `-dev.N` / `-rc.N`. ## Bumping Steps @@ -111,7 +111,7 @@ Notes: ```bash airstack version -# → AirStack Version: 0.18.0-alpha.7 +# → AirStack Version: 0.21.0-dev.7 ``` (Equivalent: `grep '^VERSION=' .env`.) @@ -121,8 +121,8 @@ airstack version Open `/.env` and change exactly the `VERSION=` line. Keep the surrounding comments and quoting intact: ```diff -- VERSION="0.18.0-alpha.7" -+ VERSION="0.18.0-alpha.8" +- VERSION="0.21.0-dev.7" ++ VERSION="0.21.0-dev.8" ``` The validator strips surrounding `"` or `'`, so either quoting style works, but match the existing style (double quotes). @@ -147,7 +147,7 @@ git diff .env docs/release_notes/index.md # review the diff Optional regex preflight (mirrors the CI check): ```bash -python3 -c 'import re,sys; v=open(".env").read(); m=re.search(r"^VERSION\s*=\s*\"?([^\"#\s]+)", v, re.M); print(m.group(1)); assert re.fullmatch(r"^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$", m.group(1)), "INVALID"' +python3 -c 'import re,sys; v=open(".env").read(); m=re.search(r"^VERSION\s*=\s*\"?([^\"#\s]+)", v, re.M); print(m.group(1)); assert re.fullmatch(r"^(\d+)\.(\d+)\.(\d+)(?:-(dev|beta|rc)\.(\d+))?$", m.group(1)), "INVALID"' ``` ### 5. Commit @@ -155,7 +155,7 @@ python3 -c 'import re,sys; v=open(".env").read(); m=re.search(r"^VERSION\s*=\s*\ Use a clear, conventional message: ``` -Bump version to 0.18.0-alpha.8 +Bump version to 0.21.0-dev.8 ``` Recent commits in this repo use exactly this phrasing (`Bump version to 0.17.0`, `Bump version to 0.16.1`). @@ -216,18 +216,18 @@ Layout: Rules: - Use the H3 sections **Added**, **Changed**, **Fixed**, **Removed**, **Deprecated**, **Security** as needed; a release may also open with a short narrative and breaking-changes subsection. -- For pre-release bumps (`-alpha.N`, `-beta.N`, `-rc.N`), keep your bullets under the current `(Unreleased)` section. Do not create a section per alpha. +- For pre-release bumps (`-dev.N`, `-beta.N`, `-rc.N`), keep your bullets under the current `(Unreleased)` section. Do not create a section per dev bump. - For a release bump (no suffix), retitle the section to `## ` and open a fresh `## (Unreleased)` above it. - Write user-facing prose, not commit log dumps. Mention new modules, breaking changes, and notable behavior shifts, with what changed FROM what. ## Common Pitfalls - **Forgetting the bump.** The `check-version-increment` job fails with `::error::VERSION must be strictly greater than the base branch version.` Bump and force-push the branch. -- **Invalid semver.** Forms like `1.2`, `1.2.3-rc1`, `1.2.3-dev`, `1.2.3+sha.abc`, `v1.2.3`, or empty strings fail with `::error::VERSION '' does not match the required format.` The only allowed pre-release tags are exactly `alpha`, `beta`, `rc`, each followed by a literal dot and an integer (e.g. `-rc.1`, never `-rc1`). +- **Invalid semver.** Forms like `1.2`, `1.2.3-rc1`, `1.2.3-dev` (no `.N`), `1.2.3-alpha.4` (legacy tag), `1.2.3+sha.abc`, `v1.2.3`, or empty strings fail with `::error::VERSION '' does not match the required format.` The only allowed pre-release tags are exactly `dev`, `beta`, `rc`, each followed by a literal dot and an integer (e.g. `-dev.1`, never `-dev1`). - **Going backwards.** `0.18.0 → 0.18.0-rc.1` looks like progress but is a regression: release > rc. Always move forward in the comparison tuple. - **Two PRs racing for the same number.** Whichever merges last wins; the loser's `check-version-increment` will start failing the moment the base advances past it. Rebase on the updated base branch and bump again. - **Bumping but forgetting the Release Notes.** No CI gate enforces this, but reviewers will (and the versioned docs deploys snapshot the page per release, so missing entries become invisible history). -- **Bumping for pure docs PRs.** Wastes a registry tag. Prefer to keep docs-only changes off `.env` if possible — but if the gate is failing, an alpha bump is the path of least resistance. +- **Bumping for pure docs PRs.** Wastes a registry tag. Prefer to keep docs-only changes off `.env` if possible — but if the gate is failing, a dev bump is the path of least resistance. - **Editing `VERSION=` quoting.** The extractor regex `^VERSION\s*=\s*["\']?([^"\'#\s]+)` handles double quotes, single quotes, or no quotes, and stops at `#`/whitespace. Don't add inline comments after the value (e.g. `VERSION="0.18.1" # bumped`) — the trailing `# bumped` will be stripped from the value but obscures intent; put comments on their own line above. - **Touching only sub-compose `.env` files.** The check looks at the **repo-root** `.env` only. `robot/docker/.env` and friends are container env files, not the version source of truth. - **Force-pushing after merge to fix Release Notes.** Don't. Land a follow-up PR with the correction (docs-only, so no VERSION bump needed unless the gate demands one). diff --git a/.agents/skills/extract-module/SKILL.md b/.agents/skills/extract-module/SKILL.md index 535af8aa8..fa209d52d 100644 --- a/.agents/skills/extract-module/SKILL.md +++ b/.agents/skills/extract-module/SKILL.md @@ -62,7 +62,7 @@ canonical-defaults launch rule, repo anatomy) defer to - Large pinned files (model weights) → `assets:` with `url` + `sha256` + `dest`, no Git LFS. - `airstack_compat`: a real semver range against the trunk `VERSION` you - tested (e.g. `">=0.19.0-alpha.18 <0.20.0"`), never a branch. + tested (e.g. `">=0.21.0-dev.18 <0.22.0"`), never a branch. - [ ] Validate: ```bash diff --git a/.env b/.env index 0d6edf834..e05d98869 100644 --- a/.env +++ b/.env @@ -12,7 +12,7 @@ PROJECT_NAME="airstack" # If you've run ./airstack.sh setup, then this will auto-generate from the git commit hash every time a change is made # to a Dockerfile or docker-compose.yaml file. Otherwise this can also be set explicitly to make a release version. # auto-generated from git commit hash -VERSION="0.20.0-alpha.21" +VERSION="0.20.0" # Image-tag discriminator ONLY (appears in the image tag suffix, e.g. ..._robot-x86-64_dev). # No Dockerfile consumes it: "prebuilt" does NOT bake the built ros_ws into the image today — # a real prebuilt (workspace-baked) stage is future work. Keep "dev" (mounted code, built live). diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 973f0a7d3..43fec0b29 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -46,8 +46,8 @@ FYI Docs are updated via mkdocs.yml and markdown files under `docs/`. It should diff --git a/.github/workflows/check-version-increment.yml b/.github/workflows/check-version-increment.yml index 80405c85a..db368b68c 100644 --- a/.github/workflows/check-version-increment.yml +++ b/.github/workflows/check-version-increment.yml @@ -24,7 +24,7 @@ jobs: import sys SEMVER_RE = re.compile( - r'^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$' + r'^(\d+)\.(\d+)\.(\d+)(?:-(dev|beta|rc)\.(\d+))?$' ) def parse_version(v): @@ -32,9 +32,9 @@ jobs: Parse a version string into a comparable tuple. Returns None if the format is invalid. - Pre-release ordering: alpha < beta < rc < (release) + Pre-release ordering: dev < beta < rc < (release) Tuple: (major, minor, patch, pre_rank, pre_num) - where pre_rank: alpha=0, beta=1, rc=2, release=3 + where pre_rank: dev=0, beta=1, rc=2, release=3 """ m = SEMVER_RE.fullmatch(v) if not m: @@ -44,7 +44,7 @@ jobs: patch = int(m.group(3)) pre_type = m.group(4) # None for release versions pre_num = int(m.group(5)) if m.group(5) else 0 - pre_rank = {'alpha': 0, 'beta': 1, 'rc': 2, None: 3}[pre_type] + pre_rank = {'dev': 0, 'beta': 1, 'rc': 2, None: 3}[pre_type] return (major, minor, patch, pre_rank, pre_num) def extract_version(content): @@ -87,7 +87,7 @@ jobs: print(f"::error::VERSION '{pr_version}' does not match the required format.") print(" Accepted formats:") print(" MAJOR.MINOR.PATCH (e.g. 1.2.3)") - print(" MAJOR.MINOR.PATCH-alpha.N (e.g. 1.3.0-alpha.1)") + print(" MAJOR.MINOR.PATCH-dev.N (e.g. 1.3.0-dev.1)") print(" MAJOR.MINOR.PATCH-beta.N (e.g. 1.3.0-beta.2)") print(" MAJOR.MINOR.PATCH-rc.N (e.g. 1.3.0-rc.3)") failed = True diff --git a/.github/workflows/scripts/registry_sync.py b/.github/workflows/scripts/registry_sync.py index 190d9a523..7b519fde0 100644 --- a/.github/workflows/scripts/registry_sync.py +++ b/.github/workflows/scripts/registry_sync.py @@ -82,7 +82,7 @@ def bump_version() -> "tuple[str, str]": if not m: sys.exit('.env has no VERSION="..." line') old = m.group(1) - pre = re.fullmatch(r"(\d+\.\d+\.\d+-(?:alpha|beta|rc)\.)(\d+)", old) + pre = re.fullmatch(r"(\d+\.\d+\.\d+-(?:dev|alpha|beta|rc)\.)(\d+)", old) if pre: new = f"{pre.group(1)}{int(pre.group(2)) + 1}" else: diff --git a/.github/workflows/sync-develop-from-main.yaml b/.github/workflows/sync-develop-from-main.yaml index e875d8a43..25d85d5b1 100644 --- a/.github/workflows/sync-develop-from-main.yaml +++ b/.github/workflows/sync-develop-from-main.yaml @@ -54,7 +54,7 @@ jobs: python3 << 'PYEOF' import os, re, subprocess, sys - SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$') + SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)(?:-(dev|alpha|beta|rc)\.(\d+))?$') # alpha kept for parsing legacy versions def parse(v): m = SEMVER_RE.fullmatch(v) @@ -78,11 +78,11 @@ jobs: dM, dn, dp, dpre, dpn = parse(dev_ver) # If main's x.y.z has caught up to (or passed) develop's base, - # develop just released — roll forward to the next minor's alpha.0. + # develop just released — roll forward to the next minor's dev.0. # Otherwise main is a hotfix behind develop; preserve develop's # pre-release channel and bump the counter. if (mM, mm, mp) >= (dM, dn, dp): - new_ver = f"{mM}.{mm + 1}.0-alpha.0" + new_ver = f"{mM}.{mm + 1}.0-dev.0" reason = "main caught up to develop's base — rolling to next minor" else: if dpre is None: diff --git a/README.md b/README.md index f1fd0d816..6ae482fbb 100644 --- a/README.md +++ b/README.md @@ -2,51 +2,119 @@
AirStack Logo -
-AirStack is a comprehensive, modular autonomy stack for autonomous aerial -robotics, developed by the [AirLab](https://theairlab.org) at Carnegie Mellon -University's Robotics Institute. It provides an end-to-end system for -autonomous drone operations — a layered ROS 2 (Jazzy) autonomy stack, -high-fidelity simulation (NVIDIA Isaac Sim with the Pegasus extension; -Microsoft AirSim legacy), a Ground Control Station, multi-robot coordination, -and hardware deployment tools — all running in Docker. +**Build the autonomy, not the scaffolding.** + +AirStack is an open ROS 2 stack for aerial robots — simulator, ground control, +and layered onboard autonomy that launch as one system. Developed by the +[AirLab](https://theairlab.org) at Carnegie Mellon University's Robotics Institute. [![License](https://img.shields.io/github/license/castacks/AirStack)](LICENSE) -[![Documentation](https://img.shields.io/badge/docs-mkdocs-blue)](https://docs.theairlab.org) +[![Documentation](https://img.shields.io/badge/docs-docs.theairlab.org-blue)](https://docs.theairlab.org) -## Modular architecture + + Three drones flying the AirStack autonomy stack in Isaac Sim + -AirStack is organized around three concepts: -**modules** — thin external repos with a small `module.yaml`, pulled on demand -(`airstack module add --version `) and discovered through the -[module registry](https://github.com/castacks/airstack-modules-index); -**stacks** — self-contained autonomy topology folders under [`stacks/`](stacks/) -with pinned `modules.repos` and a CI-observed `wiring.md`; and **fleets** — -files under [`config/fleets/`](config/fleets/) declaring who exists, which -vehicle, which stack, and which ground hosts run split-stack offboard halves. +*Three drones flying the real stack in Isaac Sim, the Foxglove GCS, and MS AirSim — +recorded from this repo, unstaged. Watch the live demos on the +[documentation home page](https://docs.theairlab.org).* -## Quick start + + +## Zero → drones flying in sim ```bash -./airstack.sh setup # configure AirStack and add `airstack` to PATH -airstack install # install Docker and dependencies -airstack up --sim isaac # bring up sim + robot + GCS (default stack: full_default) +git clone --recursive -j8 git@github.com:castacks/AirStack.git && cd AirStack +./airstack.sh install && ./airstack.sh setup +airstack up --play --wait ``` Then follow the [Getting Started guide](https://docs.theairlab.org/latest/docs/getting_started/) and the [Modular AirStack Walkthrough](docs/getting_started/modular_airstack.md). +No Linux box or GPU? [Run AirStack on OSMO](docs/tutorials/airstack_on_osmo.md) +from any laptop. -## Documentation +## One command brings up sim, robots, and ground control -Full documentation lives at **** (built from -[`docs/`](docs/) with MkDocs — `airstack docs` serves it locally). +`airstack up` starts the simulator, one container per robot, and a +Foxglove-based ground control station, wired together over ROS 2. Flags select +the simulator, scene, and fleet size — no launch-file surgery: + +```bash +airstack up --sim airsim --scene neighborhood +airstack up --sim isaac --robots 3 --scene full-warehouse +airstack up --fleet sim_three_mixed +``` + +`airstack ready` blocks until the stack is flight-ready — containers running, +sim publishing `/clock`, autonomy nodes up, PX4 EKF armable — so scripts and CI +know exactly when takeoff is available. + +## Same code in sim and on the vehicle + +The desktop dev container and the Jetson (L4T) onboard container extend one +base service and launch the same stack entry point +(`stacks/full_default/launch/stack.launch.xml`). What you test in simulation is +what the vehicle runs. + +## CI flies the whole stack, not just unit tests + +Pull requests run pytest campaigns against the live simulators on ephemeral GPU +runners: image builds, `colcon` builds in every container, bring-up liveliness, +sensor topic rates, takeoff–hover–land, fixed trajectories with cross-track +error, and waypoint navigation judged on the odometry track. Run them yourself, +or comment `/pytest` on a PR: + +```bash +airstack test -m takeoff_hover_land --sim isaacsim --num-robots 1 -v +``` + +Marks are defined in [`tests/`](tests/); metrics regressions fail the report. + +## AI agents can drive this repo + +Module boundaries, an [`AGENTS.md`](AGENTS.md) contract, and 23 step-by-step +skills under [`.agents/skills/`](.agents/skills/) give coding agents the same +on-ramp as humans: scaffold a package, wire it into a stack, fly it in sim, +document it. Every demo video on the documentation home page was captured by an +AI agent — it brought the stack up, scripted the flights, implemented the +follow-camera it filmed with, and edited the clips. + +## Modular architecture + +AirStack follows a layered autonomy architecture: + +``` +Robot +├── Interface Layer: Communication with robot controllers +├── Sensors Layer: Data acquisition from various sensors +├── Perception Layer: State estimation and environment understanding +├── Local Layer: +│ ├── World Models: Local environment representation +│ ├── Planners: Trajectory generation and obstacle avoidance +│ └── Controls: Trajectory following +├── Global Layer: +│ ├── World Models: Global environment mapping +│ └── Planners: Mission-level path planning +└── Behavior Layer: High-level decision making +``` + +The topology that actually launches is selected by a **stack** — a +self-contained folder under [`stacks/`](stacks/) with pinned `modules.repos` +and a CI-observed `wiring.md`. Capabilities beyond the trunk live in +**modules** — thin external repos with a small `module.yaml`, pulled on demand +(`airstack module add --version `) and discovered through the +[module registry](https://github.com/castacks/airstack-modules-index). +Multi-robot deployments are declared by **fleets** under +[`config/fleets/`](config/fleets/): who exists, which vehicle, which stack, and +which ground hosts run split-stack offboard halves. ## Repository map -- [`robot/`](robot/) — onboard ROS 2 autonomy stack (interface, sensors, perception, local, global, behavior) +- [`robot/`](robot/) — onboard ROS 2 (Jazzy) autonomy stack (interface, sensors, perception, local, global, behavior) - [`stacks/`](stacks/) — reference autonomy stacks (launch topology + pinned modules + wiring baselines) -- [`config/`](config/) — fleets and vehicle definitions +- [`config/`](config/) — fleet and vehicle definitions - [`simulation/`](simulation/) — Isaac Sim (Pegasus) and Microsoft AirSim (legacy) - [`gcs/`](gcs/) — Ground Control Station - [`common/`](common/) — shared ROS packages and the [`module_schema/`](common/module_schema/) for `module.yaml` @@ -54,9 +122,24 @@ Full documentation lives at **** (built from - [`tests/`](tests/) — pytest system tests, integration tests, and contract tests - [`docs/`](docs/) — MkDocs documentation source +## System requirements + +- **Docker** with the NVIDIA Container Toolkit +- **NVIDIA GPU**: RTX 3070 minimum, RTX 4080 or better recommended (for local Isaac Sim) +- **Storage**: Docker images take ~25 GB; 100 GB free disk space recommended +- **OS**: Ubuntu 22.04 or 24.04 + +## Documentation + +Full documentation lives at **** (built from +[`docs/`](docs/) with MkDocs — `airstack docs` serves it locally). + ## Community & license -Contributions are welcome — see the [Contributing guide](https://docs.theairlab.org/latest/docs/development/) -and open issues/discussions on GitHub. Contact the AirLab team via -[theairlab.org](https://theairlab.org). Licensed under the terms in -[LICENSE](LICENSE). +Contributions are welcome — see the +[Contributing guide](docs/development/intermediate/contributing.md) and open +issues/discussions on GitHub. AirStack is developed at Carnegie Mellon +University's [AirLab](https://theairlab.org) (PI: +[Sebastian Scherer](https://theairlab.org/team/sebastian/)); contact the team +via [theairlab.org](https://theairlab.org). Licensed under the BSD 3-Clause +Clear License — see [LICENSE](LICENSE). diff --git a/airstack.yaml b/airstack.yaml index f5de0b3ef..ea25c8350 100644 --- a/airstack.yaml +++ b/airstack.yaml @@ -18,7 +18,7 @@ # file is future work — launch behavior without --fleet is unchanged). # Informational: the trunk release this checkout tracks (see `.env` VERSION). -release: "0.20.0-alpha" +release: "0.20.0" # The fleet this checkout flies (config/fleets/*.yaml — RFC #380 §2). # sim_one_default == today's defaults: one quad_default on full_default. diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index e66c84748..000000000 --- a/docs/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# AirStack: Democratizing Intelligent Mobile Robotics - -
- AirStack Logo -
- -AirStack is a comprehensive, modular autonomy stack for embodied AI and robotics developed by the [AirLab](https://theairlab.org) at Carnegie Mellon University's Robotics Institute. It provides a complete framework for developing, testing, and deploying autonomous mobile systems in both simulated and real-world environments. - -[![GitHub](https://img.shields.io/github/license/castacks/AirStack)](https://github.com/castacks/AirStack/blob/main/LICENSE) -[![Documentation](https://img.shields.io/badge/docs-mkdocs-blue)](https://docs.theairlab.org) - -## 🚀 Features - -- **Modular Architecture**: Easily swap out components to customize for your specific needs -- **ROS 2 Integration**: Built on ROS 2 for robust inter-process communication -- **Simulation Support**: Integrated with NVIDIA Isaac Sim for high-fidelity simulation -- **Multi-Robot Capability**: Control and coordinate multiple robots simultaneously -- **Ground Control Station**: Monitor and control robots through an intuitive interface -- **Comprehensive Autonomy Stack**: - - Robot Interface Layer - - Sensor Integration - - Perception Systems - - Local Planning & Control - - Global Planning - - Behavior Management - -## 📋 System Requirements - -- **Docker**: With NVIDIA Container Toolkit support -- **NVIDIA GPU**: RTX 3070 minimum, RTX 4080 or better recommended (for local Isaac Sim) -- **Storage**: Docker images take ~25GB; 100GB free disk space recommended -- **OS**: Ubuntu 22.04 or 24.04 - -## 🔧 Quick Start - -Follow the instructions in [Getting Started](./getting_started/index.md) to set up AirStack on your machine, then take the [Modular AirStack Walkthrough](getting_started/modular_airstack.md). - -## 🏗️ System Architecture - -AirStack follows a layered architecture; the topology that actually launches is selected by a **stack** (a folder under `stacks/` with pinned modules and a CI-observed `wiring.md`): - -``` -Robot -├── Interface Layer: Communication with robot controllers -├── Sensors Layer: Data acquisition from various sensors -├── Perception Layer: State estimation and environment understanding -├── Local Layer: -│ ├── World Models: Local environment representation -│ ├── Planners: Trajectory generation and obstacle avoidance -│ └── Controls: Trajectory following -├── Global Layer: -│ ├── World Models: Global environment mapping -│ └── Planners: Mission-level path planning -└── Behavior Layer: High-level decision making -``` - -Capabilities beyond the trunk live in **modules** — thin external repos pulled on demand (`airstack module add --version `) and listed in the [module registry](https://github.com/castacks/airstack-modules-index) — and multi-robot deployments are declared by **fleet files** under `config/fleets/`. - -## 📁 Repository Structure - -- `robot/`: Contains the ROS 2 workspace for the robot autonomy stack -- `stacks/`: Reference autonomy stacks (launch topology + pinned `modules.repos` + `wiring.md`) -- `config/`: Fleet files (`config/fleets/`) and vehicle definitions (`config/vehicles/`) -- `gcs/`: Software for monitoring and controlling robots -- `simulation/`: Integration with Isaac Sim and simulation environments -- `docs/`: Comprehensive documentation -- `common/`: Shared libraries and utilities (including `module_schema/` for `module.yaml`) -- `tools/`: Repo tooling (docs catalog generator, fleet resolver, wiring/DDS generators) -- `tests/`: Testing infrastructure (system, integration, and contract tests) - -## 🧪 Development - -AirStack is designed with modularity in mind, making it straightforward to extend or replace components. The development workflow is centered around Docker containers for consistent environments. - -For detailed development guidelines, see the [Developer Guide](https://docs.theairlab.org/latest/docs/development/). - -## 📚 Documentation - -Comprehensive documentation is available at [https://docs.theairlab.org](https://docs.theairlab.org) - -The documentation covers: - -- Getting started guides -- Development workflows -- Component descriptions -- API references -- Simulation setup -- Real-world deployment - -## 🤝 Contributing - -We welcome contributions to AirStack! Please see our [Contributing Guidelines](development/intermediate/contributing.md) for more information. - -## 📄 License - -AirStack is licensed under the BSD 3-Clause Clear License (SPDX: BSD-3-Clause-Clear). See the repository [LICENSE](https://github.com/castacks/AirStack/blob/main/LICENSE) file. Vendored third-party packages retain their upstream licenses. - -## 📧 Contact - -For questions or support, please contact the AirLab team at [theairlab.org](https://theairlab.org). diff --git a/docs/development/intermediate/contributing.md b/docs/development/intermediate/contributing.md index e6b26fd49..63a0f8cb7 100644 --- a/docs/development/intermediate/contributing.md +++ b/docs/development/intermediate/contributing.md @@ -82,12 +82,12 @@ To keep the git histories of `main` and `develop` related, a GitHub Actions work ### VERSION handling on develop -`develop` always carries a pre-release VERSION (e.g. `0.19.0-alpha.3`) so that it stays strictly greater than `main` and satisfies the `Verify VERSION is valid and incremented` check (`.github/workflows/check-version-increment.yml`), which requires every PR to bump `.env`'s `VERSION` above its base branch. The sync workflow bumps `develop`'s VERSION as part of the merge using two rules: +`develop` always carries a pre-release VERSION (e.g. `0.21.0-dev.3`) so that it stays strictly greater than `main` and satisfies the `Verify VERSION is valid and incremented` check (`.github/workflows/check-version-increment.yml`), which requires every PR to bump `.env`'s `VERSION` above its base branch. The sync workflow bumps `develop`'s VERSION as part of the merge using two rules: | Condition | Action | Example | |---|---|---| -| `main`'s `x.y.z` ≥ `develop`'s base `x.y.z` (a release just landed on main) | Roll `develop` to the next minor's `alpha.0` | main `0.19.0`, develop `0.19.0-alpha.7` → develop `0.20.0-alpha.0` | -| `main`'s `x.y.z` < `develop`'s base (a hotfix landed on main) | Preserve `develop`'s pre-release channel and bump the counter | main `0.19.1`, develop `0.20.0-alpha.0` → develop `0.20.0-alpha.1` | +| `main`'s `x.y.z` ≥ `develop`'s base `x.y.z` (a release just landed on main) | Roll `develop` to the next minor's `dev.0` | main `0.20.0`, develop `0.20.0-dev.7` → develop `0.21.0-dev.0` | +| `main`'s `x.y.z` < `develop`'s base (a hotfix landed on main) | Preserve `develop`'s pre-release channel and bump the counter | main `0.20.1`, develop `0.21.0-dev.0` → develop `0.21.0-dev.1` | The workflow auto-resolves conflicts on the `VERSION=` line of `.env` (keeps `develop`'s side, then applies the bump). Any other merge conflict aborts the sync and must be resolved manually: diff --git a/docs/development/intermediate/testing/ci_cd.md b/docs/development/intermediate/testing/ci_cd.md index 24fa487bf..e759a9310 100644 --- a/docs/development/intermediate/testing/ci_cd.md +++ b/docs/development/intermediate/testing/ci_cd.md @@ -222,7 +222,7 @@ declares two `cache_from` entries: | Entry | Example | Who writes it | |---|---|---| -| Versioned | `airstack:v0.19.0-alpha.7_isaac-sim` | `docker-build.yml`, per release | +| Versioned | `airstack:v0.21.0-dev.7_isaac-sim` | `docker-build.yml`, per release | | Floating | `airstack:cache_isaac-sim` | `docker-build.yml`, republished every build | The versioned entry alone cannot work on a pull request. `check-version-increment` diff --git a/docs/hooks/release_notes_current_version.py b/docs/hooks/release_notes_current_version.py index 5d9a5c808..abd12db77 100644 --- a/docs/hooks/release_notes_current_version.py +++ b/docs/hooks/release_notes_current_version.py @@ -7,8 +7,8 @@ At build time this hook reads the ``VERSION=`` line from the repo-root ``.env`` and drops every ``## X.Y.Z ...`` section whose base semver does not -match (pre-release suffixes like ``-alpha.N`` are ignored for matching, so -``VERSION="0.20.0-alpha.13"`` keeps the ``## 0.20.0 (Unreleased)`` section). +match (pre-release suffixes like ``-dev.N`` are ignored for matching, so +``VERSION="0.21.0-dev.13"`` keeps the ``## 0.21.0 (Unreleased)`` section). If no section matches the current VERSION, the page is left unfiltered and a warning is logged rather than publishing an empty page. diff --git a/docs/release_notes/index.md b/docs/release_notes/index.md index e6f742d92..8d9d7e38c 100644 --- a/docs/release_notes/index.md +++ b/docs/release_notes/index.md @@ -17,7 +17,26 @@ registered in mkdocs.yml) trims the rendered page to the section matching the repo-root .env VERSION, so each mike-deployed docs version carries only its own notes. --> -## 0.20.0 (Unreleased) +## 0.21.0 (Unreleased) + +- Nothing yet. + +## 0.20.0 — 2026-08-29 + +- **Pre-release versioning terminology: `-alpha.N` → `-dev.N`.** The + development line on `develop` now uses `X.Y.Z-dev.N` pre-release versions + (first: `0.21.0-dev.0`) instead of `X.Y.Z-alpha.N`. The + `check-version-increment` PR gate accepts exactly `dev`, `beta`, `rc` + (ordering `dev < beta < rc < release`); the main→develop sync workflow + rolls develop forward to the next minor's `-dev.0` after a release. Docs, + skills, and the PR template were updated to match. Existing `-alpha.N` + versions in git history and in declared module-compat ranges remain valid + historical references. + +- **Single, revamped repo README.** The repo now has one `README.md` (at the + root — `docs/README.md` was removed), rewritten around the redesigned docs + home page: quickstart, one-command bring-up, sim-to-real parity, CI flight + campaigns, and agent-driven workflows. - **Module-catalog sync automation + drift alarm.** Registering a module is two merges (registry PR to diff --git a/docs/robot/configuration/environment_variables.md b/docs/robot/configuration/environment_variables.md index 122c26157..02886d0f4 100644 --- a/docs/robot/configuration/environment_variables.md +++ b/docs/robot/configuration/environment_variables.md @@ -9,7 +9,7 @@ These variables assemble every image tag as `${PROJECT_DOCKER_REGISTRY}/${PROJEC | Variable | Purpose | Default | Consumed by | | -------- | ------- | ------- | ----------- | | `PROJECT_NAME` | Repository name for Docker images and part of every image tag | `"airstack"` | `image:` tags in all compose files (`robot/docker/`, `gcs/docker/`, `simulation/*/docker/`) | -| `VERSION` | Semver image version; bumped per release, so the value in `.env` is always the current release (e.g. `0.20.0-alpha.15`) | current release semver | `image:` tags in all compose files; CI version gate (`check-version-increment.yml`) | +| `VERSION` | Semver image version; bumped per release, so the value in `.env` is always the current release (e.g. `0.21.0-dev.15`) | current release semver | `image:` tags in all compose files; CI version gate (`check-version-increment.yml`) | | `DOCKER_IMAGE_BUILD_MODE` | Image-tag discriminator **only** — no Dockerfile consumes it. Keep `dev` (mounted code, built live); a real `prebuilt` workspace-baked stage is future work | `"dev"` | Tag suffix of the robot images (`robot/docker/docker-compose.yaml`) | | `PROJECT_DOCKER_REGISTRY` | Registry to push/pull images from | `"airlab-docker.andrew.cmu.edu/airstack"` | `image:` tags in all compose files | | `COMPOSE_PROFILES` | Default compose profiles when none are passed explicitly | `"desktop,isaac-sim"` | Docker Compose profile selection; rewritten by `airstack up --sim ` (swaps the simulator profile) and `--fleet` (heterogeneous fleets swap `desktop` for `fleet`) | diff --git a/mkdocs.yml b/mkdocs.yml index 662a2780c..28eaa2bcd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,9 +5,9 @@ site_name: AirStack site_dir: ../site site_url: "https://docs.theairlab.org/docs/" # Trailing slash is recommended exclude_docs: | - # docs/README.md is the GitHub-facing readme for the docs/ folder; the site - # page for that URL is docs/index.md, and same-dir would otherwise collide. - docs/README.md + # The repo README is GitHub-facing; the site's home page is docs/index.md, + # and same-dir would otherwise collide on the root URL. + README.md **/ros_ws/build **/docker/Foxglove **/ros_ws/install