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..dd297ac --- /dev/null +++ b/scripts/macos.sh @@ -0,0 +1,164 @@ +#!/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" || { 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}" +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