From f678c74b2cecfefcdc60c13dcb24725583dbf270 Mon Sep 17 00:00:00 2001 From: Yassin Soliman Date: Sat, 8 Aug 2026 14:15:22 -0600 Subject: [PATCH 1/2] Add native macOS RoboStack setup --- BuildInstructions.md | 52 ++++++++++++++ CONTRIBUTING.md | 6 +- README.md | 15 ++++ robostack.yaml | 19 ++++++ scripts/macos.sh | 158 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 robostack.yaml create mode 100755 scripts/macos.sh diff --git a/BuildInstructions.md b/BuildInstructions.md index 31c0765..e332d05 100644 --- a/BuildInstructions.md +++ b/BuildInstructions.md @@ -24,3 +24,55 @@ ros2 launch waybionic_bringup ground_station.launch.py - **RViz** and **Joint State Publisher GUI** (separate small window) will pop up after the last command - RViz opens pre-configured with `base_link` fixed frame, `RobotModel`, and `TF` displays already loaded - Move the slider in the Joint State Publisher GUI (small window) to move the arm + +## macOS (Apple Silicon) + +The workspace runs natively through RoboStack. Docker and XQuartz are not required. +Intel macOS is not currently verified. + +### Prerequisites + +Install the Xcode command-line tools, Git, and Miniforge: + +```bash +xcode-select --install +brew install git +brew install --cask miniforge +``` + +Reopen the terminal if `mamba` or `conda` is not immediately available. + +### Setup and launch + +For a new clone, run: + +```bash +git clone https://github.com/Waybionic/waybionic_ground_station.git && cd waybionic_ground_station && ./scripts/macos.sh setup +``` + +For an existing clone, run `./scripts/macos.sh setup` from the repository root. +The command creates or updates the `waybionic_robostack` environment and builds +the workspace. + +Launch RViz and Joint State Publisher GUI: + +```bash +./scripts/macos.sh launch +``` + +Other useful commands: + +```bash +./scripts/macos.sh build # rebuild the workspace +./scripts/macos.sh run ros2 topic list # run any overlaid ROS command +``` + +After pulling repository changes, update and rebuild with: + +```bash +git pull && ./scripts/macos.sh setup +``` + +If RViz reports a missing workspace package, rerun `./scripts/macos.sh build`. +Do not source `install/setup.bash` directly from zsh; the helper handles the +workspace overlay through Bash. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c9f7a7..f92dfcb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,9 +115,9 @@ Full build and launch steps are in [BuildInstructions.md](./BuildInstructions.md - **Target:** ROS 2 **Jazzy** on **Ubuntu 24.04**. - **Windows:** use **WSL2** with Ubuntu 24.04. - **Linux:** native, no extra setup. -- **macOS (Apple Silicon):** first-class support is still being worked out (Docker / VM). - Ask in the team channel before starting, and **don't commit Mac-specific local paths** - into shared config. +- **macOS (Apple Silicon):** use the native RoboStack workflow in + [BuildInstructions.md](./BuildInstructions.md). Do not commit Mac-specific + local paths into shared config. ## Questions diff --git a/README.md b/README.md index a999278..08416a1 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,21 @@ Currently, this repository contains the clean foundation and placeholder robot m - **`waybionic_bringup`** Launch files and RViz configurations to bring up the robot state and visualization. +## macOS (Apple Silicon) + +Install Miniforge once, then clone and set up the native RoboStack environment: + +```bash +brew install --cask miniforge +git clone https://github.com/Waybionic/waybionic_ground_station.git && cd waybionic_ground_station && ./scripts/macos.sh setup +``` + +Launch the ground station visualization: + +```bash +./scripts/macos.sh launch +``` + ## Building and Launching Please refer to [BuildInstructions.md](./BuildInstructions.md) for complete instructions on how to build the workspace and launch the ground station visualization. diff --git a/robostack.yaml b/robostack.yaml new file mode 100644 index 0000000..fac5030 --- /dev/null +++ b/robostack.yaml @@ -0,0 +1,19 @@ +name: waybionic_robostack + +channels: + - conda-forge + - robostack-jazzy + - nodefaults + +dependencies: + - ros-jazzy-ros-base + - ros-jazzy-rviz2 + - ros-jazzy-xacro + - ros-jazzy-joint-state-publisher-gui + - colcon-common-extensions + - compilers + - cmake + - pkg-config + - make + - ninja + - pytest <9 \ No newline at end of file diff --git a/scripts/macos.sh b/scripts/macos.sh new file mode 100755 index 0000000..0d77b9c --- /dev/null +++ b/scripts/macos.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +ENV_NAME="waybionic_robostack" +ENV_FILE="$ROOT/robostack.yaml" +MANAGER="" +ENV_EXISTS=false + +fail() { + echo "error: $*" >&2 + exit 1 +} + +usage() { + cat <<'EOF' +Usage: ./scripts/macos.sh COMMAND [ARGS...] + +Commands: + setup Create/update the RoboStack environment and build the workspace + build Build the workspace + launch Launch the ground station visualization + run Run any command inside the ROS workspace +EOF +} + +check_host() { + [[ "$(uname -s)" == "Darwin" ]] || fail "this helper is for macOS" + if [[ "$(uname -m)" != "arm64" ]]; then + echo "warning: this setup is tested on Apple Silicon; Intel macOS is unverified" >&2 + fi +} + +select_manager() { + local candidate + + if [[ -n "${CONDA_EXE:-}" && -x "$CONDA_EXE" ]] \ + && "$CONDA_EXE" env list 2>/dev/null \ + | awk '{print $1}' \ + | grep -qx "$ENV_NAME"; then + MANAGER="$CONDA_EXE" + ENV_EXISTS=true + return + fi + + for candidate in mamba conda; do + if command -v "$candidate" >/dev/null 2>&1 \ + && "$candidate" env list 2>/dev/null \ + | awk '{print $1}' \ + | grep -qx "$ENV_NAME"; then + MANAGER="$candidate" + ENV_EXISTS=true + return + fi + done + + for candidate in mamba conda; do + if command -v "$candidate" >/dev/null 2>&1; then + MANAGER="$candidate" + return + fi + done + + fail "install Miniforge first: brew install --cask miniforge" +} + +prepare() { + check_host + select_manager +} + +setup_environment() { + if [[ "$ENV_EXISTS" == true ]]; then + echo "Updating $ENV_NAME with $MANAGER..." + if [[ "$(basename "$MANAGER")" == "mamba" ]]; then + "$MANAGER" env update --yes --name "$ENV_NAME" --file "$ENV_FILE" --prune + else + "$MANAGER" env update --name "$ENV_NAME" --file "$ENV_FILE" --prune + fi + else + echo "Creating $ENV_NAME with $MANAGER..." + "$MANAGER" env create --yes --file "$ENV_FILE" + ENV_EXISTS=true + fi +} + +ensure_environment() { + if [[ "$ENV_EXISTS" != true ]]; then + fail "$ENV_NAME is missing; run ./scripts/macos.sh setup" + fi +} + +run_environment() { + if [[ "$(basename "$MANAGER")" == "mamba" ]]; then + "$MANAGER" run --attach "" -n "$ENV_NAME" "$@" + else + "$MANAGER" run --no-capture-output -n "$ENV_NAME" "$@" + fi +} + +build_workspace() { + ensure_environment + echo "Building workspace..." + ( + cd "$ROOT" + run_environment colcon build --symlink-install + ) +} + +ensure_workspace() { + ensure_environment + if [[ ! -f "$ROOT/install/setup.bash" ]]; then + build_workspace + fi +} + +run_workspace() { + ensure_workspace + # shellcheck disable=SC2016 + run_environment bash -c \ + 'cd "$1"; source install/setup.bash; shift; exec "$@"' \ + _ "$ROOT" "$@" +} + +command_name="${1:-help}" +if [[ $# -gt 0 ]]; then + shift +fi + +case "$command_name" in + help|-h|--help) + usage + ;; + setup) + prepare + setup_environment + build_workspace + echo + echo "Setup complete. Launch with: ./scripts/macos.sh launch" + ;; + build) + prepare + build_workspace + ;; + launch) + prepare + run_workspace ros2 launch waybionic_bringup ground_station.launch.py "$@" + ;; + run) + [[ $# -gt 0 ]] || fail "run requires a command" + prepare + run_workspace "$@" + ;; + *) + usage >&2 + fail "unknown command: $command_name" + ;; +esac \ No newline at end of file From 5b7c619bf4794501e8b4615d9cf5400d85c58777 Mon Sep 17 00:00:00 2001 From: Yassin Soliman <108886216+yassinsolim@users.noreply.github.com> Date: Sat, 8 Aug 2026 15:17:11 -0600 Subject: [PATCH 2/2] Fail fast when the workspace overlay cannot be sourced run_workspace spawned a new `bash -c`, which does not inherit the script's `set -euo pipefail`. A failing `cd` or a failing `source install/setup.bash` was therefore ignored, and the user's command still ran without the workspace overlay while the helper reported success (exit 0). Guard both steps explicitly so the helper aborts with an actionable message instead of silently running commands against the wrong environment. Explicit guards are used rather than `set -e` because `set -u` breaks ROS's generated setup.bash (COLCON_TRACE unbound) and `set -e` would propagate into that sourced script. --- scripts/macos.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/macos.sh b/scripts/macos.sh index 0d77b9c..dd297ac 100755 --- a/scripts/macos.sh +++ b/scripts/macos.sh @@ -117,9 +117,15 @@ ensure_workspace() { run_workspace() { ensure_workspace # shellcheck disable=SC2016 - run_environment bash -c \ - 'cd "$1"; source install/setup.bash; shift; exec "$@"' \ - _ "$ROOT" "$@" + run_environment bash -c ' + cd "$1" || { echo "error: cannot enter workspace $1" >&2; exit 1; } + . install/setup.bash || { + echo "error: failed to source install/setup.bash; run ./scripts/macos.sh build" >&2 + exit 1 + } + shift + exec "$@" + ' _ "$ROOT" "$@" } command_name="${1:-help}"