diff --git a/docs/setup_hil.md b/docs/setup_hil.md index 479e85b..b024f13 100644 --- a/docs/setup_hil.md +++ b/docs/setup_hil.md @@ -13,7 +13,7 @@ This repository is compatible with the following system: #### Clone the Repository ```shell -git clone git@github.com:RobotecAI/agentic-mobile-manipulator.git +git clone https://github.com/RobotecAI/agentic-mobile-manipulator.git cd agentic-mobile-manipulator ``` diff --git a/docs/setup_sim.md b/docs/setup_sim.md index 8f7bcaa..d2627ab 100644 --- a/docs/setup_sim.md +++ b/docs/setup_sim.md @@ -13,7 +13,7 @@ This repository is compatible with the following system: #### Clone the Repository ```shell -git clone git@github.com:RobotecAI/agentic-mobile-manipulator.git +git clone https://github.com/RobotecAI/agentic-mobile-manipulator.git cd agentic-mobile-manipulator ``` diff --git a/docs/setup_single_machine.md b/docs/setup_single_machine.md index 7a57f90..6687ee2 100644 --- a/docs/setup_single_machine.md +++ b/docs/setup_single_machine.md @@ -13,8 +13,7 @@ This repository is compatible with the following system: #### Clone the Repository ```shell -cd /home/${USER} -git clone git@github.com:RobotecAI/agentic-mobile-manipulator.git +git clone https://github.com/RobotecAI/agentic-mobile-manipulator.git cd agentic-mobile-manipulator ``` @@ -75,16 +74,22 @@ pixi run -e local build-llama # this step is hardware specific. By default, it b pixi run -e local download-models # or download the models manually, check the links below ``` +`pixi run download-models` fetches all required models in parallel using `aria2c` and places them in `$DEMO_ROOT/models/`. Already downloaded files are skipped. If a download is interrupted, re-running the command will resume from where it left off. + --- ### Download Models -For every model configured in `config.toml`, download the GGUF file and place it in `$DEMO_ROOT/models/`: +The following models are required for local inference. `pixi run download-models` handles all of them automatically, but the links below are provided for reference or manual download: + +| Model | Type | Size | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------- | +| [GPT-OSS-20B](https://huggingface.co/unsloth/gpt-oss-20b-GGUF/resolve/main/gpt-oss-20b-Q4_K_M.gguf?download=true) | LLM | ~12 GB | +| [LFM2-VL-3B](https://huggingface.co/LiquidAI/LFM2-VL-3B-GGUF/resolve/main/LFM2-VL-3B-Q8_0.gguf?download=true) + [mmproj](https://huggingface.co/LiquidAI/LFM2-VL-3B-GGUF/resolve/main/mmproj-LFM2-VL-3B-Q8_0.gguf?download=true) | VLM | ~3.2 GB + ~0.5 GB | +| [Qwen3-Embedding-0.6B](https://huggingface.co/Qwen/Qwen3-Embedding-0.6B-GGUF/resolve/main/Qwen3-Embedding-0.6B-Q8_0.gguf?download=true) | Embedding | ~0.6 GB | +| [Qwen3-Reranker-0.6B](https://huggingface.co/ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/resolve/main/qwen3-reranker-0.6b-q8_0.gguf?download=true) | Reranker | ~0.6 GB | -- [GPT-OSS-20B](https://huggingface.co/unsloth/gpt-oss-20b-GGUF/resolve/main/gpt-oss-20b-Q4_K_M.gguf?download=true) -- [LFM2-VL-3B-GGUF](https://huggingface.co/LiquidAI/LFM2-VL-3B-GGUF/resolve/main/LFM2-VL-3B-Q8_0.gguf?download=true) + [mmproj](https://huggingface.co/LiquidAI/LFM2-VL-3B-GGUF/resolve/main/mmproj-LFM2-VL-3B-Q8_0.gguf?download=true) -- [Qwen3-Embedding-0.6B](https://huggingface.co/Qwen/Qwen3-Embedding-0.6B-GGUF/resolve/main/Qwen3-Embedding-0.6B-Q8_0.gguf?download=true) -- [Qwen3-Reranker-0.6B](https://huggingface.co/ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/resolve/main/qwen3-reranker-0.6b-q8_0.gguf?download=true) +All files should be placed in `$DEMO_ROOT/models/`. --- diff --git a/monitoring/README.md b/monitoring/README.md index a03f2e5..812757d 100644 --- a/monitoring/README.md +++ b/monitoring/README.md @@ -31,7 +31,7 @@ On **tested hardware**: 1. Install dependencies with poetry: ```bash - git clone git@github.com:RobotecAI/agentic-mobile-manipulator.git + git clone https://github.com/RobotecAI/agentic-mobile-manipulator.git cd agentic-mobile-manipulator/monitoring poetry install ``` diff --git a/pixi.lock b/pixi.lock index 9c32427..c41cd60 100644 --- a/pixi.lock +++ b/pixi.lock @@ -12,6 +12,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.14.1-py312h5d8c7f2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.16.1-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aria2-1.37.0-h4b33fff_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-atk-2.38.0-h0630a04_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 @@ -981,6 +982,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.14.1-py312h5d8c7f2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.16.1-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aria2-1.37.0-h4b33fff_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-atk-2.38.0-h0630a04_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 @@ -1938,6 +1940,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.14.1-py312h5d8c7f2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.16.1-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aria2-1.37.0-h4b33fff_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-atk-2.38.0-h0630a04_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 @@ -2895,6 +2898,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.14.1-py312h5d8c7f2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.16.1-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aria2-1.37.0-h4b33fff_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-atk-2.38.0-h0630a04_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 @@ -3907,6 +3911,25 @@ packages: - aom >=3.9.1,<3.10.0a0 size: 2706396 timestamp: 1718551242397 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aria2-1.37.0-h4b33fff_4.conda + sha256: a57932dfc4252f58772dfe8b6cef4b88ce76119474c3f405812628983a40ca66 + md5: 95fb49dd7b23d4e788da61095ec258de + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - c-ares >=1.34.6,<2.0a0 + - libxml2 + - libxml2-16 >=2.15.2 + - openssl >=3.5.6,<4.0a0 + - libsqlite >=3.53.0,<4.0a0 + - libzlib >=1.3.2,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + license: GPL-2.0-only + license_family: GPL + run_exports: {} + size: 1829525 + timestamp: 1775760709970 - conda: https://conda.anaconda.org/conda-forge/linux-64/assimp-5.4.3-hecf2907_1.conda sha256: c49e992c1a2978f5a8cdf3cdf9aac0c0a444bbddb7316dbfbf16f5a94ff71c10 md5: 649115e82c2a9620fcf0d3a846ee365f diff --git a/pixi.toml b/pixi.toml index 4cebd22..1306938 100644 --- a/pixi.toml +++ b/pixi.toml @@ -8,10 +8,13 @@ platforms = ["linux-64"] # ─── Activation ───────────────────────────────────────────────────────────────── # scripts/setup_env.sh sources the ros2_ws overlay when available. [activation] -env = {DEMO_ROOT = "${PIXI_PROJECT_ROOT}"} +env = { DEMO_ROOT = "${PIXI_PROJECT_ROOT}" } scripts = ["scripts/setup_env.sh"] [dependencies] +uv = ">=0.5" +aria2 = ">=1.37" + # ─── ROS 2 Jazzy (RoboStack) ───────────────────────────────────────────────── # The full ROS 2 runtime comes from the robostack-jazzy conda channel. # pixi runs RoboStack's activation scripts automatically, so AMENT_PREFIX_PATH, @@ -215,7 +218,14 @@ depends-on = ["clone-gems", "clone-ros2-ws"] description = "Clone all repositories (gems and ROS 2 workspace)" [feature.profile-default.tasks.setup] -depends-on = ["clone", "install-o3de", "fetch-gems", "build-ros2", "build-sim", "sync"] +depends-on = [ + "clone", + "install-o3de", + "fetch-gems", + "build-ros2", + "build-sim", + "sync", +] description = "Full setup (O3DE + ROS 2 + Python)" [feature.profile-hil.tasks.setup] @@ -223,7 +233,13 @@ depends-on = ["clone-ros2-ws", "build-ros2", "sync"] description = "Setup HIL machine (ROS 2 + Python, no O3DE)" [feature.profile-hil-local.tasks.setup] -depends-on = ["clone-ros2-ws", "clone-inference", "build-ros2", "sync", "build-llama"] +depends-on = [ + "clone-ros2-ws", + "clone-inference", + "build-ros2", + "sync", + "build-llama", +] description = "Setup HIL machine with local llama.cpp inference" [feature.profile-local.tasks.clone] @@ -231,7 +247,15 @@ depends-on = ["clone-gems", "clone-ros2-ws"] description = "Clone all repositories (gems and ROS 2 workspace)" [feature.profile-local.tasks.setup] -depends-on = ["clone", "install-o3de", "fetch-gems", "build-ros2", "build-sim", "sync", "build-llama"] +depends-on = [ + "clone", + "install-o3de", + "fetch-gems", + "build-ros2", + "build-sim", + "sync", + "build-llama", +] description = "Full setup including local llama.cpp inference" [feature.profile-local.tasks.demo] @@ -276,8 +300,19 @@ description = "Run test suite" # e.g. `build-sim` cannot be run in the `hil` environment. [environments] -default = {features = ["dev", "ros2", "sim", "profile-default"]} -hil = {features = ["dev", "ros2", "profile-hil"]} -hil-local = {features = ["dev", "ros2", "local-inference", "profile-hil-local"]} -local = {features = ["dev", "ros2", "sim", "local-inference", "profile-local"]} -dev = {features = ["dev"], no-default-feature = true} +default = { features = ["dev", "ros2", "sim", "profile-default"] } +hil = { features = ["dev", "ros2", "profile-hil"] } +hil-local = { features = [ + "dev", + "ros2", + "local-inference", + "profile-hil-local", +] } +local = { features = [ + "dev", + "ros2", + "sim", + "local-inference", + "profile-local", +] } +dev = { features = ["dev"], no-default-feature = true } diff --git a/scripts/download_models.sh b/scripts/download_models.sh index 256364b..a57b0c8 100755 --- a/scripts/download_models.sh +++ b/scripts/download_models.sh @@ -1,41 +1,74 @@ #!/usr/bin/env bash -set -e +set -euo pipefail MODELS_DIR="${DEMO_ROOT}/models" mkdir -p "$MODELS_DIR" -download() { - local name="$1" - local url="$2" - local dest="$3" - if [ -f "$dest" ]; then - echo " [skip] $name — already exists" - else - echo " [download] $name" - wget -q --show-progress -c -O "$dest" "$url" - fi -} +model_names=() +model_urls=() +model_files=() -echo "" -echo "=== Downloading models to $MODELS_DIR ===" -echo "" +add_model() { + model_names+=("$1") + model_urls+=("$2") + model_files+=("$3") +} -download "GPT-OSS-20B (LLM)" \ +add_model "GPT-OSS-20B (LLM, ~12 GB)" \ "https://huggingface.co/unsloth/gpt-oss-20b-GGUF/resolve/main/gpt-oss-20b-Q4_K_M.gguf?download=true" \ - "$MODELS_DIR/gpt-oss-20b-Q4_K_M.gguf" + "gpt-oss-20b-Q4_K_M.gguf" -download "LFM2-VL-3B (VLM)" \ +add_model "LFM2-VL-3B (VLM, ~3.2 GB)" \ "https://huggingface.co/LiquidAI/LFM2-VL-3B-GGUF/resolve/main/LFM2-VL-3B-Q8_0.gguf?download=true" \ - "$MODELS_DIR/LFM2-VL-3B-Q8_0.gguf" + "LFM2-VL-3B-Q8_0.gguf" -download "LFM2-VL-3B mmproj" \ +add_model "LFM2-VL-3B mmproj (VLM, ~0.5 GB)" \ "https://huggingface.co/LiquidAI/LFM2-VL-3B-GGUF/resolve/main/mmproj-LFM2-VL-3B-Q8_0.gguf?download=true" \ - "$MODELS_DIR/mmproj-LFM2-VL-3B-Q8_0.gguf" + "mmproj-LFM2-VL-3B-Q8_0.gguf" -download "Qwen3-Embedding-0.6B (Embed)" \ +add_model "Qwen3-Embedding (Embed, ~0.6 GB)" \ "https://huggingface.co/Qwen/Qwen3-Embedding-0.6B-GGUF/resolve/main/Qwen3-Embedding-0.6B-Q8_0.gguf?download=true" \ - "$MODELS_DIR/Qwen3-Embedding-0.6B-Q8_0.gguf" + "Qwen3-Embedding-0.6B-Q8_0.gguf" -download "Qwen3-Reranker-0.6B (Rerank)" \ +add_model "Qwen3-Reranker (Rerank, ~0.6 GB)" \ "https://huggingface.co/ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/resolve/main/qwen3-reranker-0.6b-q8_0.gguf?download=true" \ - "$MODELS_DIR/qwen3-reranker-0.6b-q8_0.gguf" + "qwen3-reranker-0.6b-q8_0.gguf" + +echo "" +echo "=== Downloading models to $MODELS_DIR ===" +echo "" + +input_lines=() +for i in "${!model_names[@]}"; do + dest="$MODELS_DIR/${model_files[$i]}" + if [ -f "$dest" ] && [ ! -f "${dest}.aria2" ]; then + echo " [skip] ${model_names[$i]}" + else + echo " [fetch] ${model_names[$i]}" + input_lines+=("${model_urls[$i]}") + input_lines+=(" out=${model_files[$i]}") + fi +done + +if [ ${#input_lines[@]} -eq 0 ]; then + echo "" + echo " All models already present." + echo "" + exit 0 +fi + +echo "" +echo " Starting parallel download..." +echo "" +printf '%s\n' "${input_lines[@]}" | aria2c \ + --input-file=- \ + --dir="$MODELS_DIR" \ + --continue=true \ + --max-concurrent-downloads=5 \ + --max-connection-per-server=4 \ + --split=4 \ + --console-log-level=warn + +echo "" +echo "=== All models ready in $MODELS_DIR ===" +echo ""