diff --git a/README.md b/README.md index 805bf2d..e31a4d5 100644 --- a/README.md +++ b/README.md @@ -67,15 +67,24 @@ make DRIVE=differential WORLD=field bc # behaviour clone make DRIVE=differential WORLD=field rl # KL-PPO fine-tune make DRIVE=differential WORLD=field eval # 10-seed env eval -# 4. Run in Webots +# 4. Run in Webots — interactive picker (recommended starting point) +tools/webots_menu.sh +# Prompts for mode / drive / world / LiDAR FOV / number of dogs / +# flock size / perception (LiDAR vs GT) / headless, then dispatches. + +# Or invoke the launcher directly: tools/run_webots.sh 10 bc differential field # BC, diff, rect field tools/run_webots.sh 10 rl differential field_round # RL, diff, round field tools/run_webots.sh 5 strombom differential field # analytic baseline HERDING_USE_GT=1 tools/run_webots.sh 5 strombom differential field - # GT bypass for ablation + # GT bypass ablation +HERDING_LIDAR=360 tools/run_webots.sh 5 bc differential field + # 360° FOV ablation +HERDING_NDOGS=2 HERDING_AXIS_LEAK=0.3 tools/run_webots.sh 5 strombom differential field + # dual-shepherd axis split ``` -`make help` lists every target and the overridable hyperparameters. +`make help` lists every Makefile target and the overridable hyperparameters. **Mecanum note**: the `ShepherdDogMecanum.proto` uses physical roller hinges in Webots. The Webots calibration shows ~60% strafe efficiency diff --git a/tools/webots_menu.sh b/tools/webots_menu.sh new file mode 100755 index 0000000..50b17bf --- /dev/null +++ b/tools/webots_menu.sh @@ -0,0 +1,184 @@ +#!/usr/bin/env bash +# Interactive Webots launcher. Prompts for the experiment knobs +# (mode, drive, world, LiDAR FOV, number of dogs, flock size, GT +# bypass) and then dispatches to tools/run_webots.sh with the +# selected configuration. +# +# Usage: bash tools/webots_menu.sh + +set -e +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT="$( cd "$SCRIPT_DIR/.." && pwd )" + +# Resolve HERDING_PYTHON the same way every other launcher does. +source "$SCRIPT_DIR/setup_env.sh" + +# ----- Cosmetics ---------------------------------------------------- +if [[ -t 1 ]]; then + B=$'\e[1m'; D=$'\e[2m'; R=$'\e[0m' + G=$'\e[32m'; Y=$'\e[33m'; C=$'\e[36m' +else + B=""; D=""; R=""; G=""; Y=""; C="" +fi + +banner () { + cat <= 1 && raw <= ${#labels[@]} )); then + CHOICE="${values[$((raw-1))]}"; return + fi + echo " ${Y}invalid — try again${R}" + done +} + +ask_int () { + # ask_int "Prompt" default min max + local prompt="$1" default="$2" lo="$3" hi="$4" + while true; do + printf "${B}%s${R} [${G}%s${R}-${G}%s${R}, default ${G}%s${R}]: " "$prompt" "$lo" "$hi" "$default" + local raw; read -r raw || true + raw="${raw:-$default}" + if [[ "$raw" =~ ^[0-9]+$ ]] && (( raw >= lo && raw <= hi )); then + CHOICE="$raw"; return + fi + echo " ${Y}must be an integer in [$lo, $hi]${R}" + done +} + +# ----- Prompts ------------------------------------------------------ +banner + +ask_choice "Mode" "bc" \ + "BC (behaviour-cloned MLP):bc" \ + "RL (KL-PPO fine-tune):rl" \ + "Strömbom (analytic):strombom" \ + "Sequential (analytic):sequential" \ + "Universal teacher (BC source):universal" +MODE="$CHOICE" +echo + +ask_choice "Drive" "differential" \ + "Differential (2-wheel):differential" \ + "Mecanum (4-wheel, omnidirectional):mecanum" +DRIVE="$CHOICE" +echo + +ask_choice "World" "field" \ + "Rectangular (field):field" \ + "Round (field_round):field_round" +WORLD="$CHOICE" +echo + +# LiDAR ablation only applies to differential (mecanum proto has its +# own 140° sensor that we don't fork). +if [[ "$DRIVE" == "differential" ]]; then + ask_choice "LiDAR FOV" "140" \ + "140° (canonical, ShepherdDog.proto):140" \ + "360° (FOV ablation, ShepherdDog360.proto):360" + LIDAR="$CHOICE" +else + LIDAR="140" + echo "${D}LiDAR: 140° (mecanum drive — no 360° proto variant available)${R}" +fi +echo + +ask_choice "Number of shepherd dogs" "1" \ + "1 — solo:1" \ + "2 — axis-split (X-dog + Y-dog):2" +NDOGS="$CHOICE" +echo + +if [[ "$NDOGS" == "2" ]]; then + ask_choice "Axis-split leak (soft mask gain on the off-axis)" "0.3" \ + "0.0 — strict (each dog only moves on its axis; tends to deadlock):0.0" \ + "0.3 — default (off-axis at 30% gain; verified to pen):0.3" \ + "0.5 — softer:0.5" \ + "1.0 — no mask (both dogs run full policy):1.0" + AXIS_LEAK="$CHOICE" + echo +fi + +ask_int "Flock size (number of sheep)" 5 1 10 +N_SHEEP="$CHOICE" +echo + +ask_choice "Perception" "lidar" \ + "LiDAR (canonical):lidar" \ + "Ground-truth bypass (HERDING_USE_GT=1):gt" +if [[ "$CHOICE" == "gt" ]]; then USE_GT=1; else USE_GT=0; fi +echo + +ask_choice "Headless?" "no" \ + "No — show the Webots window:no" \ + "Yes — headless, fast simulation (xvfb-run):yes" +HEADLESS="$CHOICE" +echo + +# ----- Summary ------------------------------------------------------ +cat <