diff --git a/.ci b/.ci new file mode 100644 index 00000000..99df5f06 --- /dev/null +++ b/.ci @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + + +SUBMODULES_PATH=${SUBMODULES_PATH:-$(realpath .)} +source "${SUBMODULES_PATH}/adore_cli/ci_teststand/ci_core.sh" +source "${SUBMODULES_PATH}/adore_cli/ci_teststand/ci_utils.sh" +source ci.env +source "${SUBMODULES_PATH}/adore_cli/ci_teststand/tests/common_tests.sh" +source "${SUBMODULES_PATH}/adore_cli/ci_teststand/tests/docker_tests.sh" +source "${SUBMODULES_PATH}/adore_cli/ci_teststand/tests/file_tests.sh" +#source "${SUBMODULES_PATH}/ci_teststand/.static_checking_tests" +source .tests + +build(){ + ci_common_build +} + +test(){ + ci_common_test +} + + +ci_run "$@" diff --git a/.colcon_workspace/colcon.meta b/.colcon_workspace/colcon.meta deleted file mode 100644 index f3d0af83..00000000 --- a/.colcon_workspace/colcon.meta +++ /dev/null @@ -1,7 +0,0 @@ -{ - "names": { - "osqp-eigen": { - "dependencies": ["osqp"] - } - } -} diff --git a/.docker/base/Dockerfile b/.docker/base/Dockerfile deleted file mode 100644 index 1c988caa..00000000 --- a/.docker/base/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -# .docker/base/Dockerfile -FROM ros:jazzy-ros-base - -# Locale -ENV LANG=C.UTF-8 \ - LC_ALL=C.UTF-8 - -# Core APT dependencies (shared by dev & CI) -COPY .docker/base/apt.base.txt /tmp/apt.base.txt - -RUN apt-get update && \ - xargs -r -a /tmp/apt.base.txt apt-get install -y && \ - rm -rf /var/lib/apt/lists/* /tmp/* diff --git a/.docker/base/apt.base.txt b/.docker/base/apt.base.txt deleted file mode 100644 index 80cb051e..00000000 --- a/.docker/base/apt.base.txt +++ /dev/null @@ -1,32 +0,0 @@ -libeigen3-dev -libopencv-dev -libproj-dev -nlohmann-json3-dev - -build-essential -cmake -ccache - -git -curl -wget -ca-certificates -just - -python3-pip -python3-pytest -python3-colcon-common-extensions -python3-pyproj - - -ros-jazzy-rclcpp-components -ros-jazzy-cv-bridge -ros-jazzy-rosbridge-server -ros-jazzy-foxglove-msgs - -libgeographiclib-dev -geographiclib-tools - -sumo -sumo-tools -sumo-doc \ No newline at end of file diff --git a/.docker/ci/Dockerfile b/.docker/ci/Dockerfile deleted file mode 100644 index 045d7654..00000000 --- a/.docker/ci/Dockerfile +++ /dev/null @@ -1,55 +0,0 @@ -# .docker/ci/Dockerfile -FROM adore_base:latest - -# ------------------------------------------------------------------- -# CI-specific system dependencies (docs, test tooling, etc.) -# ------------------------------------------------------------------- -COPY .docker/ci/apt.ci.txt /tmp/apt.ci.txt -RUN if [ -s /tmp/apt.ci.txt ]; then \ - apt-get update && \ - xargs -r -a /tmp/apt.ci.txt apt-get install -y && \ - rm -rf /var/lib/apt/lists/* /tmp/*; \ - else \ - echo "No CI APT dependencies listed in /tmp/apt.ci.txt"; \ - fi - -# ------------------------------------------------------------------- -# CI-specific Python dependencies (MkDocs Material, plugins, ...) -# ------------------------------------------------------------------- -COPY .docker/ci/pip.ci.txt /tmp/pip.ci.txt -RUN if [ -s /tmp/pip.ci.txt ]; then \ - pip3 install --no-cache-dir --break-system-packages --ignore-installed -r /tmp/pip.ci.txt && \ - rm -f /tmp/pip.ci.txt; \ - else \ - echo "No CI pip dependencies listed in /tmp/pip.ci.txt"; \ - fi - - -# CI user (still UID/GID mapped so volume permissions behave) -ARG USERNAME=ci -ARG USER_UID=2001 -ARG USER_GID=2001 - -RUN set -eux; \ - existing_user="$(getent passwd "${USER_UID}" | cut -d: -f1 || true)"; \ - if [ -n "${existing_user}" ]; then \ - echo "Renaming user ${existing_user} to ${USERNAME}"; \ - usermod -l "${USERNAME}" "${existing_user}"; \ - usermod -d "/home/${USERNAME}" -m "${USERNAME}"; \ - groupmod -n "${USERNAME}" "${existing_user}"; \ - else \ - echo "Creating new user ${USERNAME}"; \ - groupadd -g "${USER_GID}" "${USERNAME}"; \ - useradd -m -s /usr/bin/zsh -u "${USER_UID}" -g "${USER_GID}" "${USERNAME}"; \ - fi - -USER ${USERNAME} - -ENV WORKSPACE="/home/${USERNAME}/adore" -WORKDIR ${WORKSPACE} - -ENV CCACHE_DIR="${WORKSPACE}/.cache/ccache" \ - CC="/usr/lib/ccache/gcc" \ - CXX="/usr/lib/ccache/g++" - -CMD ["/bin/bash"] diff --git a/.docker/ci/apt.ci.txt b/.docker/ci/apt.ci.txt deleted file mode 100644 index c07e9efa..00000000 --- a/.docker/ci/apt.ci.txt +++ /dev/null @@ -1 +0,0 @@ -mkdocs \ No newline at end of file diff --git a/.docker/ci/pip.ci.txt b/.docker/ci/pip.ci.txt deleted file mode 100644 index 42e3efe0..00000000 --- a/.docker/ci/pip.ci.txt +++ /dev/null @@ -1,4 +0,0 @@ -mkdocs-material -pymdown-extensions -mkdocs-redirects -gcovr \ No newline at end of file diff --git a/.docker/dev/Dockerfile b/.docker/dev/Dockerfile deleted file mode 100644 index ff8dd610..00000000 --- a/.docker/dev/Dockerfile +++ /dev/null @@ -1,90 +0,0 @@ -# .docker/dev/Dockerfile -FROM adore_base:latest - -# Dev-only APT deps (shell candy, X11, tracing, etc.) -COPY .docker/dev/apt.dev.txt /tmp/apt.dev.txt - -RUN apt-get update && \ - xargs -r -a /tmp/apt.dev.txt apt-get install -y && \ - rm -rf /var/lib/apt/lists/* /tmp/* - -# Helix editor -RUN curl -L https://github.com/helix-editor/helix/releases/download/25.07.1/helix-25.07.1-x86_64-linux.tar.xz \ - | tar -xJ && \ - mv helix-25.07.1-x86_64-linux /opt/helix && \ - ln -s /opt/helix/hx /usr/local/bin/hx && \ - echo "export HELIX_RUNTIME=/opt/helix/runtime" >> /etc/profile - -# User setup (UID/GID mapping) -ARG USERNAME=developer -ARG USER_UID=2001 -ARG USER_GID=2001 - -RUN set -eux; \ - existing_user="$(getent passwd "${USER_UID}" | cut -d: -f1 || true)"; \ - if [ -n "${existing_user}" ]; then \ - echo "Renaming user ${existing_user} to ${USERNAME}"; \ - usermod -l "${USERNAME}" "${existing_user}"; \ - usermod -d "/home/${USERNAME}" -m "${USERNAME}"; \ - groupmod -n "${USERNAME}" "${existing_user}"; \ - else \ - echo "Creating new user ${USERNAME}"; \ - groupadd -g "${USER_GID}" "${USERNAME}"; \ - useradd -m -s /usr/bin/zsh -u "${USER_UID}" -g "${USER_GID}" "${USERNAME}"; \ - fi - -USER ${USERNAME} -ENV IN_ADORE_DOCKER=1 - -# Oh My Zsh (non-interactive) -ENV RUNZSH=no \ - CHSH=no - -RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" - -# Workspace + ccache -ENV WORKSPACE="/home/${USERNAME}/adore" -WORKDIR ${WORKSPACE} - -ENV CCACHE_DIR="${WORKSPACE}/.cache/ccache" \ - CC="/usr/lib/ccache/gcc" \ - CXX="/usr/lib/ccache/g++" - -# Zsh history & QoL -RUN echo '\ -export HISTFILE=~/adore/.zsh_history\n\ -export HISTSIZE=100000\n\ -export SAVEHIST=100000\n\ -setopt HIST_IGNORE_DUPS\n\ -setopt HIST_REDUCE_BLANKS\n\ -setopt SHARE_HISTORY\n\ -setopt INC_APPEND_HISTORY\n\ -' >> "/home/${USERNAME}/.zshrc" && \ - mkdir -p "${WORKSPACE}" && \ - touch "${WORKSPACE}/.zsh_history" && \ - chown -R "${USERNAME}:${USERNAME}" "${WORKSPACE}" - -# --- ADORe: auto-source ROS + workspace in interactive zsh shells --- -RUN set -eux; \ - ZSHRC="$HOME/.zshrc"; \ - touch "$ZSHRC"; \ - { \ - echo ''; \ - echo '# --- ADORe ROS environment -----------------------------------------'; \ - echo '# Source the chosen ROS distro (defaults to jazzy if ROS_DISTRO unset)'; \ - echo 'if [ -f "/opt/ros/${ROS_DISTRO:-jazzy}/setup.zsh" ]; then'; \ - echo ' source "/opt/ros/${ROS_DISTRO:-jazzy}/setup.zsh"'; \ - echo 'fi'; \ - echo ''; \ - echo '# Source local colcon workspace overlay if it exists'; \ - echo 'if [ -f "$HOME/adore/.colcon_workspace/install/local_setup.zsh" ]; then'; \ - echo ' source "$HOME/adore/.colcon_workspace/install/local_setup.zsh"'; \ - echo 'elif [ -f "$HOME/adore/.colcon_workspace/install/setup.zsh" ]; then'; \ - echo ' source "$HOME/adore/.colcon_workspace/install/setup.zsh"'; \ - echo 'fi'; \ - echo 'if [[ -n "$IN_ADORE_DOCKER" ]]; then'; \ - echo ' PROMPT="%F{green}[ADORe-DEV]%f ${PROMPT}"'; \ - echo 'fi'; \ - } >> "$ZSHRC" - -CMD ["/usr/bin/zsh", "-l"] diff --git a/.docker/dev/apt.dev.txt b/.docker/dev/apt.dev.txt deleted file mode 100644 index cf5d0663..00000000 --- a/.docker/dev/apt.dev.txt +++ /dev/null @@ -1,37 +0,0 @@ -zsh -fzf -zsh-syntax-highlighting -zsh-autosuggestions - -htop -tree -bat -ripgrep -gdb -clangd -clangd++ -libstdc++-12-dev - -ros-jazzy-rqt -ros-jazzy-rqt-common-plugins -ros-jazzy-foxglove-bridge -ros-jazzy-ros2trace -ros-jazzy-tracetools-analysis - -babeltrace -lttng-modules-dkms - -x11-apps -libx11-6 -libxext6 -libxrender1 -libxtst6 -libxi6 -libgl1 -mesa-utils - -python3-flask -python3-flask-cors - -jq -x11-utils diff --git a/.docker/scripts/build_ci.sh b/.docker/scripts/build_ci.sh deleted file mode 100755 index 327e6c56..00000000 --- a/.docker/scripts/build_ci.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -cd "${WORKSPACE_ROOT}" - -# Ensure the base image exists (adore_base:latest) -if ! docker image inspect "${DOCKER_BASE_IMAGE_LATEST}" >/dev/null 2>&1; then - echo "--- Building base Docker image ${DOCKER_BASE_IMAGE_LATEST} (${DOCKER_BASE_IMAGE_TAGGED}) ---" - docker build \ - -f "${DOCKER_BASE_DOCKERFILE}" \ - -t "${DOCKER_BASE_IMAGE_LATEST}" \ - -t "${DOCKER_BASE_IMAGE_TAGGED}" \ - . -fi - -echo "--- Building CI Docker image ${DOCKER_CI_IMAGE_LATEST} (${DOCKER_CI_IMAGE_TAGGED}) ---" -docker build \ - -f "${DOCKER_CI_DOCKERFILE}" \ - --build-arg USER_UID="${USER_UID}" \ - --build-arg USER_GID="${USER_GID}" \ - --build-arg USERNAME="${USER_NAME}" \ - -t "${DOCKER_CI_IMAGE_LATEST}" \ - -t "${DOCKER_CI_IMAGE_TAGGED}" \ - . diff --git a/.docker/scripts/build_dev.sh b/.docker/scripts/build_dev.sh deleted file mode 100755 index e4337aef..00000000 --- a/.docker/scripts/build_dev.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Build the base and dev Docker images for ADORe. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -require_host "Hint: to build *inside* the dev container, run colcon directly instead of this script." - -cd "${WORKSPACE_ROOT}" - -if ! docker image inspect "${DOCKER_BASE_IMAGE_LATEST}" >/dev/null 2>&1; then - echo "--- Building base Docker image ${DOCKER_BASE_IMAGE_LATEST} (${DOCKER_BASE_IMAGE_TAGGED}) ---" - docker build \ - -f "${DOCKER_BASE_DOCKERFILE}" \ - -t "${DOCKER_BASE_IMAGE_LATEST}" \ - -t "${DOCKER_BASE_IMAGE_TAGGED}" \ - . -fi - -echo "--- Building dev Docker image ${DOCKER_DEV_IMAGE_LATEST} (${DOCKER_DEV_IMAGE_TAGGED}) ---" -docker build \ - -f "${DOCKER_DEV_DOCKERFILE}" \ - --build-arg USER_UID="${USER_UID}" \ - --build-arg USER_GID="${USER_GID}" \ - --build-arg USERNAME="${USER_NAME}" \ - -t "${DOCKER_DEV_IMAGE_LATEST}" \ - -t "${DOCKER_DEV_IMAGE_TAGGED}" \ - . diff --git a/.docker/scripts/clean_images.sh b/.docker/scripts/clean_images.sh deleted file mode 100755 index 48371445..00000000 --- a/.docker/scripts/clean_images.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Remove ADORe Docker images and the dev container. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -require_host "You appear to be inside a container; image cleanup should be done on the host." - -echo "--- Removing dev container '${DOCKER_CONTAINER_NAME}' if it exists ---" -docker rm -f "${DOCKER_CONTAINER_NAME}" >/dev/null 2>&1 || true - -echo "--- Removing ADORe Docker images (dev, CI, base) ---" -# Remove dev + CI images before base to avoid dependency issues. -for repo in "${DOCKER_DEV_IMAGE_BASE}" "${DOCKER_CI_IMAGE_BASE}" "${DOCKER_BASE_IMAGE_BASE}"; do - ids=$(docker images --format '{{.Repository}} {{.ID}}' | awk -v repo="$repo" '$1 == repo {print $2}') - if [[ -n "${ids}" ]]; then - echo " -> Removing images for repository '${repo}'" - docker rmi -f ${ids} || true - fi -done diff --git a/.docker/scripts/common.sh b/.docker/scripts/common.sh deleted file mode 100755 index 25f55702..00000000 --- a/.docker/scripts/common.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Shared Docker/CI configuration for ADORe scripts. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Load environment helpers (host vs container, etc.) -# shellcheck source=/dev/null -if [[ -f "${SCRIPT_DIR}/env.sh" ]]; then - source "${SCRIPT_DIR}/env.sh" -fi - -# Repository root (where the git repo lives) -WORKSPACE_ROOT="${WORKSPACE_ROOT:-$(cd "${SCRIPT_DIR}/../.." && pwd)}" - -# ROS distro -ROS_DISTRO="${ROS_DISTRO:-jazzy}" - -# Host user info (used when building dev image / running containers) -USER_NAME="${USER_NAME:-$(id -un)}" -USER_UID="${USER_UID:-$(id -u)}" -USER_GID="${USER_GID:-$(id -g)}" - -# Git / arch info for tagging images -GIT_HASH="${GIT_HASH:-$(cd "${WORKSPACE_ROOT}" && git rev-parse --short HEAD 2>/dev/null || echo dev)}" -ARCH="${ARCH:-$(uname -m)}" -IMAGE_TAG="${IMAGE_TAG:-${GIT_HASH}-${ARCH}}" - -# Container name for the dev shell -DOCKER_CONTAINER_NAME="${DOCKER_CONTAINER_NAME:-adore}" - -# Base image (ROS + apt deps, no user/tooling) -DOCKER_BASE_IMAGE_BASE="${DOCKER_BASE_IMAGE_BASE:-adore_base}" -DOCKER_BASE_IMAGE_TAGGED="${DOCKER_BASE_IMAGE_BASE}:${IMAGE_TAG}" -DOCKER_BASE_IMAGE_LATEST="${DOCKER_BASE_IMAGE_BASE}:latest" -DOCKER_BASE_DOCKERFILE="${DOCKER_BASE_DOCKERFILE:-${WORKSPACE_ROOT}/.docker/base/Dockerfile}" - -# Dev image (what developers use locally) -DOCKER_DEV_IMAGE_BASE="${DOCKER_DEV_IMAGE_BASE:-adore_dev}" -DOCKER_DEV_IMAGE_TAGGED="${DOCKER_DEV_IMAGE_BASE}:${IMAGE_TAG}" -DOCKER_DEV_IMAGE_LATEST="${DOCKER_DEV_IMAGE_BASE}:latest" -DOCKER_DEV_DOCKERFILE="${DOCKER_DEV_DOCKERFILE:-${WORKSPACE_ROOT}/.docker/dev/Dockerfile}" - -# CI image (used for tests/docs in GitHub Actions and locally) -DOCKER_CI_IMAGE_BASE="${DOCKER_CI_IMAGE_BASE:-adore_ci}" -DOCKER_CI_IMAGE_TAGGED="${DOCKER_CI_IMAGE_BASE}:${IMAGE_TAG}" -DOCKER_CI_IMAGE_LATEST="${DOCKER_CI_IMAGE_LATEST:-${DOCKER_CI_IMAGE_BASE}:latest}" -DOCKER_CI_DOCKERFILE="${DOCKER_CI_DOCKERFILE:-${WORKSPACE_ROOT}/.docker/ci/Dockerfile}" - -# Location for saved images -DOCKER_BUILD_DIR="${DOCKER_BUILD_DIR:-${WORKSPACE_ROOT}/build}" -DOCKER_TAR_NAME="${DOCKER_TAR_NAME:-${DOCKER_DEV_IMAGE_BASE}_${IMAGE_TAG}.tar}" - - -dev_greeting() { - local mode="${1:-shell}" - - # Only use colors if stdout is a TTY - if [ -t 1 ]; then - local RESET="\033[0m" - local BOLD="\033[1m" - local DIM="\033[2m" - local FG_CYAN="\033[36m" - local FG_BLUE="\033[34m" - local FG_YELLOW="\033[33m" - local FG_MAGENTA="\033[35m" - else - local RESET="" BOLD="" DIM="" FG_CYAN="" FG_BLUE="" FG_YELLOW="" FG_MAGENTA="" - fi - - # Try to get a nice OS description; fall back to uname - - local kernel arch user container workspace - kernel="$(uname -r 2>/dev/null || echo "?")" - arch="$(uname -m 2>/dev/null || echo "?")" - user="${USER_NAME:-$(id -un 2>/dev/null || echo "unknown")}" - container="${DOCKER_CONTAINER_NAME:-adore}" - workspace="${WORKSPACE_ROOT:-$(pwd)}" - - # Clear screen (if possible) - if command -v clear >/dev/null 2>&1; then - clear - else - printf '\033c' - fi - - printf "%b" "${FG_MAGENTA}${BOLD}" - printf "Welcome to the ADORe Development Environment!\n" - printf "%b" "${FG_CYAN}${BOLD}" - - printf " ...... .......... . \n" - printf " .. --****++*+++--***##################*#---++. \n" - printf " . --#*-+-----+++*##-#####***+++++++++++**+**######-- \n" - printf " --#******+-----::-+##**+*++++++----------------------*##- \n" - printf " ::**#*+----+***+----*##+----+-------:::--:::::---::::------*##- \n" - printf " .:.+**+--------+*++--+###+++++----------..:::::::::----------++*###*: \n" - printf " .:..:--++++###*+++**---------+*##*--*####*-----++**+****########################* \n" - printf " ..----*****************################*+::+***#########################**#*#####***++-. \n" - printf " .:-+******++++****##########################*--*###########*******************#######**+++- \n" - printf " -++*+++******################################****###*#*+**************++++++++***+---+++++--: \n" - printf " .---+--++++*#########**#########**++***########******++----++++++-++++++--+++-++-:... ..--+-++. \n" - printf " :::--...:--+---++----+**#####+-:. .:-++++++++++++----------------------------..----: .-+---. \n" - printf " ------:::----+-++*++++*#####+-. .::.. .-++-++--------------------------------:.-----+: :---- \n" - printf " :...::---+*###############*+: .:-:*:-+:. .---------------------------+++++++++- --+++-*- :--.: \n" - printf " :... .---****###########*+: .:-+:+:--+-. ----------+++++++++**++++++++++--+--: -+**+-*-:-.. \n" - printf " -. .--++:----+-++**+- .-+--++++--*: :--+*****+++++++++--+++-----------:. .-*#+*+.-. \n" - printf " ..... .:-. ---*++++:..---++***--*- :--------------------::::... :---.:: \n" - printf " ..:::..:..:------+-+++-. .-+++*+*--**. .::::::::.... .....::::::::::::.. \n" - printf " ........::::::::::: .--**+#-*+: ....... ....... \n" - printf " --++-+- .......... \n" - printf " ..... . .::.::--:::.. \n" - printf " \n\n" - -printf "%b" "${FG_YELLOW}" - -printf " Type %bjust --list%b to see available commands,\n" "${FG_CYAN}" "${FG_YELLOW}" - -printf "%b" "${RESET}" - - -} \ No newline at end of file diff --git a/.docker/scripts/env.sh b/.docker/scripts/env.sh deleted file mode 100755 index 527b2c88..00000000 --- a/.docker/scripts/env.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Environment helpers shared by all ADORe scripts. - -# NOTE: Do *not* set -euo pipefail here; the parent script does that. - -# Detect whether we're running inside a Docker container. -is_in_docker() { - if [[ -f "/.dockerenv" ]]; then - return 0 - fi - - if grep -qiE '(docker|lxc|containerd)' /proc/1/cgroup 2>/dev/null; then - return 0 - fi - - case "${CI:-}" in - true|1|github_actions) - # Treat CI as "in Docker" for our purposes. - return 0 - ;; - esac - - return 1 -} - -# Ensure a script is executed on the host (outside Docker). -require_host() { - if is_in_docker; then - echo "ERROR: This script is intended to be run on the HOST (outside Docker)." >&2 - if [[ $# -gt 0 ]]; then - printf '%s\n' "$*" >&2 - fi - exit 1 - fi -} - -# Ensure a script is executed *inside* a Docker container. -require_docker() { - if ! is_in_docker; then - echo "ERROR: This script is intended to be run INSIDE a Docker container." >&2 - if [[ $# -gt 0 ]]; then - printf '%s\n' "$*" >&2 - fi - exit 1 - fi -} diff --git a/.docker/scripts/force_kill_ros2.sh b/.docker/scripts/force_kill_ros2.sh deleted file mode 100755 index 0f3926b8..00000000 --- a/.docker/scripts/force_kill_ros2.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Kill lingering ROS 2 / colcon processes. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" -source "${SCRIPT_DIR}/env.sh" - -# Dev container name can be overridden from env -DOCKER_CONTAINER_NAME="${DOCKER_CONTAINER_NAME:-adore}" - -# Repo root: two levels up from .docker/scripts, unless WORKSPACE_ROOT already set -if [[ -n "${WORKSPACE_ROOT-}" ]]; then - REPO_ROOT="${WORKSPACE_ROOT}" -else - REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" -fi - -echo "=== Forcefully killing lingering ROS 2 / colcon processes ===" - -if is_in_docker; then - # -------------------------------------------------------------- - # Running *inside* a container (dev or CI) - # -------------------------------------------------------------- - echo "[container] Cleaning ROS 2 / colcon processes inside this container..." - - echo "-> Killing ros2/colcon wrapper processes..." - pkill -9 -f "ros2 launch" || true - pkill -9 -f "ros2 run" || true - pkill -9 -f "python3.*launch" || true - pkill -9 -f "rclpy" || true - pkill -9 -f "ros2 daemon" || true - pkill -9 -f "colcon" || true - pkill -9 -f "rosapi" || true - - - echo "-> Killing workspace binaries from build tree (container)..." - # Prefer REPO_ROOT if set; fall back to $HOME/adore - workspace_root_in_container="${REPO_ROOT:-$HOME/adore}" - workspace_pattern="${workspace_root_in_container}/.colcon_workspace/build" - pids=$(ps axo pid,command | grep "$workspace_pattern" | grep -v grep | awk '{print $1}') - if [ -n "$pids" ]; then - echo " Killing workspace processes: $pids" - kill -9 $pids || true - else - echo " No workspace binary processes found." - fi - -else - # -------------------------------------------------------------- - # Running on the host - # -------------------------------------------------------------- - echo "[host] Cleaning host + dev container (if running)" - echo "Workspace root: ${REPO_ROOT}" - echo "Dev container : ${DOCKER_CONTAINER_NAME}" - - # 1) Inside dev container - if docker ps --format '{{.Names}}' | grep -qx "${DOCKER_CONTAINER_NAME}"; then - echo "-> Killing ROS 2 processes inside dev container '${DOCKER_CONTAINER_NAME}'..." - docker exec "${DOCKER_CONTAINER_NAME}" bash -lc ' - set -e - echo " (container) Killing ros2/colcon wrappers..." - pkill -9 -f "ros2 launch" || true - pkill -9 -f "ros2 run" || true - pkill -9 -f "python3.*launch" || true - pkill -9 -f "rclpy" || true - pkill -9 -f "ros2 daemon" || true - pkill -9 -f "colcon" || true - pkill -9 -f "rosapi" || true - - - echo " (container) Killing workspace binaries from build tree..." - workspace_pattern="$HOME/adore/.colcon_workspace/build" - pids=$(ps axo pid,command | grep "$workspace_pattern" | grep -v grep | awk "{print \$1}") - if [ -n "$pids" ]; then - echo " PIDs: $pids" - kill -9 $pids || true - else - echo " No workspace binary processes found." - fi - ' - else - echo "-> Dev container '${DOCKER_CONTAINER_NAME}' not running; skipping container cleanup." - fi - -fi - -echo "=== Done. ===" diff --git a/.docker/scripts/run_ci.sh b/.docker/scripts/run_ci.sh deleted file mode 100755 index 3bac2508..00000000 --- a/.docker/scripts/run_ci.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Convenience wrapper: run tests + docs using the CI Docker image. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -# Prepare .colcon_workspace/src (symlinks into src/ etc.) -"${SCRIPT_DIR}/setup_colcon_src.sh" - -# --------------------------------------------------------------------------- -# On arm64, disable the sumo_bridge package via COLCON_IGNORE -# --------------------------------------------------------------------------- -ARCH="$(uname -m)" -COLCON_WS_ROOT="${WORKSPACE_ROOT}/.colcon_workspace" -if [[ "${DOCKER_DEFAULT_PLATFORM:-}" == "linux/arm64" || "${ARCH}" == "aarch64" ]]; then - SUMO_BRIDGE_DIR="${COLCON_WS_ROOT}/src/adore_interfaces/sumo_bridge" - - if [[ -d "${SUMO_BRIDGE_DIR}" ]]; then - echo "Disabling sumo_bridge on arm64 via COLCON_IGNORE" - touch "${SUMO_BRIDGE_DIR}/COLCON_IGNORE" - else - echo "sumo_bridge package directory not found at ${SUMO_BRIDGE_DIR}, skipping COLCON_IGNORE" - fi -fi - -# -------------------------------------------------------------------- -# Ensure ci image exists; build it if needed -# -------------------------------------------------------------------- -if ! docker image inspect "${DOCKER_CI_IMAGE_LATEST}" >/dev/null 2>&1; then - echo "--- ci image ${DOCKER_CI_IMAGE_LATEST} not found; building it ---" - "${SCRIPT_DIR}/build_ci.sh" -fi - - -# --------------------------------------------------------------------------- -# Run build + tests + docs inside the CI image -# --------------------------------------------------------------------------- - -# Default for COLCON_WS_ROOT inside the container (relative to repo root) -CONTAINER_COLCON_WS_ROOT="${CONTAINER_COLCON_WS_ROOT:-.colcon_workspace}" - -echo "--- Running CI in Docker image ${DOCKER_CI_IMAGE_LATEST} ---" -docker run --rm \ - -v "${WORKSPACE_ROOT}:/home/${USER_NAME}/adore" \ - -w "/home/${USER_NAME}/adore" \ - -e ROS_DISTRO="${ROS_DISTRO}" \ - -e COLCON_WS_ROOT="${CONTAINER_COLCON_WS_ROOT}" \ - -e COLCON_COVERAGE_ARGS="--cmake-args -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_C_FLAGS=--coverage -DCMAKE_POSITION_INDEPENDENT_CODE=ON" \ - "${DOCKER_CI_IMAGE_LATEST}" \ - bash -lc ' - set -euo pipefail - echo "--- Inside CI container ---" - echo "ROS_DISTRO=$ROS_DISTRO" - echo "COLCON_WS_ROOT=${COLCON_WS_ROOT}" - echo "PWD=$(pwd)" # should be /home/${USER_NAME}/adore - - just clean_build - just test_ws - - if command -v gcovr >/dev/null 2>&1; then - echo "--- Generating coverage reports with gcovr ---" - mkdir -p .gcovr_reports - # XML - gcovr \ - . \ - -r . \ - --exclude 'vendor/.*' \ - --exclude 'adore_interfaces/.*' \ - --exclude '.*rosidl.*' \ - --exclude '.*CMakeFiles/.*' \ - --exclude '.*.colcon_workspace/.*' \ - --xml-pretty \ - --output .gcovr_reports/coverage.xml - - # HTML - gcovr \ - . \ - -r . \ - --exclude 'vendor/.*' \ - --exclude 'adore_interfaces/.*' \ - --exclude '.*rosidl.*' \ - --exclude '.*CMakeFiles/.*' \ - --exclude '.*.colcon_workspace/.*' \ - --html-details \ - --output .gcovr_reports/coverage.html - else - echo "gcovr not found in CI image, skipping coverage generation" - fi - - just docs_build - - - ' - -echo "--- CI run finished ---" diff --git a/.docker/scripts/run_dev.sh b/.docker/scripts/run_dev.sh deleted file mode 100755 index 77239faa..00000000 --- a/.docker/scripts/run_dev.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Run or attach to the ADORe dev container, with persistent zsh history. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -require_host "Use this script from the host, not from inside a container." - -cd "${WORKSPACE_ROOT}" - -IMAGE="${DOCKER_DEV_IMAGE_LATEST}" -CONTAINER_NAME="${DOCKER_CONTAINER_NAME}" - -# -------------------------------------------------------------------- -# Ensure dev image exists; build it if needed -# -------------------------------------------------------------------- -if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then - echo "--- Dev image ${IMAGE} not found; building it ---" - "${SCRIPT_DIR}/build_dev.sh" -fi - -# -------------------------------------------------------------------- -# If a container with this name is already running, exec into it -# -------------------------------------------------------------------- -if docker ps --format '{{.Names}}' | grep -qx "${CONTAINER_NAME}"; then - echo "--- Attaching to running dev container ${CONTAINER_NAME} ---" - clear - dev_greeting - docker exec -it \ - -w "/home/${USER_NAME}/adore/" \ - -e HISTFILE="/home/${USER_NAME}/.zsh_history" \ - -e HISTSIZE=100000 \ - -e SAVEHIST=100000 \ - "${CONTAINER_NAME}" \ - zsh - exit 0 -fi - -# If a container with this name exists but is stopped, remove it -if docker ps -a --format '{{.Names}}' | grep -qx "${CONTAINER_NAME}"; then - echo "--- Removing stopped container ${CONTAINER_NAME} ---" - docker rm "${CONTAINER_NAME}" >/dev/null -fi - -# -------------------------------------------------------------------- -# Start a fresh dev container with persistent zsh history -# -------------------------------------------------------------------- -HOST_ZSH_HISTORY="${WORKSPACE_ROOT}/.zsh_history" -if [ ! -f "${HOST_ZSH_HISTORY}" ]; then - touch "${HOST_ZSH_HISTORY}" -fi - -echo "--- Starting dev container ${CONTAINER_NAME} (image: ${IMAGE}) ---" -clear -dev_greeting - -docker run --rm -it \ - --name "${CONTAINER_NAME}" \ - --network host \ - -e DISPLAY \ - -e QT_X11_NO_MITSHM=1 \ - -v /tmp/.X11-unix:/tmp/.X11-unix:rw \ - -v "${WORKSPACE_ROOT}:/home/${USER_NAME}/adore" \ - -v "${HOST_ZSH_HISTORY}:/home/${USER_NAME}/.zsh_history" \ - -w "/home/${USER_NAME}/adore/" \ - -e ROS_DISTRO="${ROS_DISTRO}" \ - -e HISTFILE="/home/${USER_NAME}/.zsh_history" \ - -e HISTSIZE=100000 \ - -e SAVEHIST=100000 \ - "${IMAGE}" diff --git a/.docker/scripts/run_docs.sh b/.docker/scripts/run_docs.sh deleted file mode 100755 index c28c6650..00000000 --- a/.docker/scripts/run_docs.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Convenience wrapper: run tests + docs using the CI Docker image. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -# Prepare .colcon_workspace/src (symlinks into src/ etc.) -"${SCRIPT_DIR}/setup_colcon_src.sh" - -# --------------------------------------------------------------------------- -# On arm64, disable the sumo_bridge package via COLCON_IGNORE -# --------------------------------------------------------------------------- -ARCH="$(uname -m)" -COLCON_WS_ROOT="${WORKSPACE_ROOT}/.colcon_workspace" -if [[ "${DOCKER_DEFAULT_PLATFORM:-}" == "linux/arm64" || "${ARCH}" == "aarch64" ]]; then - SUMO_BRIDGE_DIR="${COLCON_WS_ROOT}/src/adore_interfaces/sumo_bridge" - - if [[ -d "${SUMO_BRIDGE_DIR}" ]]; then - echo "Disabling sumo_bridge on arm64 via COLCON_IGNORE" - touch "${SUMO_BRIDGE_DIR}/COLCON_IGNORE" - else - echo "sumo_bridge package directory not found at ${SUMO_BRIDGE_DIR}, skipping COLCON_IGNORE" - fi -fi - -# -------------------------------------------------------------------- -# Ensure ci image exists; build it if needed -# -------------------------------------------------------------------- -if ! docker image inspect "${DOCKER_CI_IMAGE_LATEST}" >/dev/null 2>&1; then - echo "--- ci image ${DOCKER_CI_IMAGE_LATEST} not found; building it ---" - "${SCRIPT_DIR}/build_ci.sh" -fi - - -# --------------------------------------------------------------------------- -# Run build + tests + docs inside the CI image -# --------------------------------------------------------------------------- - -# Default for COLCON_WS_ROOT inside the container (relative to repo root) -CONTAINER_COLCON_WS_ROOT="${CONTAINER_COLCON_WS_ROOT:-.colcon_workspace}" - -echo "--- Running CI in Docker image ${DOCKER_CI_IMAGE_LATEST} ---" -docker run --rm \ - -v "${WORKSPACE_ROOT}:/home/${USER_NAME}/adore" \ - -w "/home/${USER_NAME}/adore" \ - -e ROS_DISTRO="${ROS_DISTRO}" \ - -e COLCON_WS_ROOT="${CONTAINER_COLCON_WS_ROOT}" \ - -e COLCON_COVERAGE_ARGS="--cmake-args -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_C_FLAGS=--coverage -DCMAKE_POSITION_INDEPENDENT_CODE=ON" \ - "${DOCKER_CI_IMAGE_LATEST}" \ - bash -lc ' - just docs_all - ' - -echo "--- CI run finished ---" diff --git a/.docker/scripts/setup_colcon_src.sh b/.docker/scripts/setup_colcon_src.sh deleted file mode 100755 index b67dee1b..00000000 --- a/.docker/scripts/setup_colcon_src.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -# Ensure .colcon_workspace/src mirrors the top-level package layout via symlinks. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -SRC_DIR="${WORKSPACE_ROOT}/.colcon_workspace/src" -mkdir -p "${SRC_DIR}" - -# Top-level dirs that contain colcon packages -CATEGORIES=( - "adore_scenarios" - "adore_ros2_conversions" - "adore_interfaces" - "adore_libraries" - "adore_test_programs" - "adore_ros2_nodes" - "adore_ros2_msgs" - "vendor" -) - -link_category() { - local category="$1" - - local target_dir="${WORKSPACE_ROOT}/${category}" - if [[ ! -d "${target_dir}" ]]; then - echo "WARN: Skipping category '${category}' – directory not found at ${target_dir}" >&2 - return 0 - fi - - local link_path="${SRC_DIR}/${category}" - local target_rel="../../${category}" - - if [[ -L "${link_path}" ]]; then - # Already a symlink – check if it points to the expected location - local current - current="$(readlink "${link_path}")" - if [[ "${current}" == "${target_rel}" ]]; then - echo "OK: Symlink for '${category}' already correct." - return 0 - else - echo "Updating symlink for '${category}': ${current} -> ${target_rel}" - rm -f "${link_path}" - fi - fi - - if [[ -e "${link_path}" ]]; then - echo "ERROR: ${link_path} exists and is not a symlink. Please remove or rename it." >&2 - return 1 - fi - - echo "Creating symlink: ${link_path} -> ${target_rel}" - ln -sfn "${target_rel}" "${link_path}" -} - -for cat in "${CATEGORIES[@]}"; do - link_category "${cat}" -done diff --git a/.docker/scripts/test_quick_start.sh b/.docker/scripts/test_quick_start.sh deleted file mode 100755 index 3ccf3efc..00000000 --- a/.docker/scripts/test_quick_start.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -set -euo pipefail - -# Base image for testing (Ubuntu because the setup script assumes Ubuntu + apt) -IMAGE="ubuntu:24.04" - -# URL to use when no local setup script is provided -DEFAULT_SETUP_URL="https://raw.githubusercontent.com/eclipse-adore/adore/develop/tools/adore_setup.sh" - -LOCAL_SETUP_PATH="${1:-}" # Optional: path to local setup script - -echo "Pulling base image ${IMAGE} if necessary..." -docker pull "${IMAGE}" >/dev/null - -# Common docker run args: mount host docker socket so the setup script can build images -DOCKER_CMD=(docker run --rm -v /var/run/docker.sock:/var/run/docker.sock) - -if [[ -n "${LOCAL_SETUP_PATH}" ]]; then - # --- Local script mode ---------------------------------------------------- - if [[ ! -f "${LOCAL_SETUP_PATH}" ]]; then - echo "ERROR: Provided setup script '${LOCAL_SETUP_PATH}' not found" >&2 - echo "false" - exit 1 - fi - - # Resolve to absolute path (without relying on realpath) - SETUP_ABS_PATH="$( - cd "$(dirname "${LOCAL_SETUP_PATH}")" - pwd - )/$(basename "${LOCAL_SETUP_PATH}")" - - echo "INFO: Testing local setup script: ${SETUP_ABS_PATH}" - - # Mount the local script into the container - DOCKER_CMD+=(-v "${SETUP_ABS_PATH}:/opt/adore_setup.sh:ro") - - # Command executed inside the container - # - Install tools (including docker.io + sudo) - # - Ensure group 'docker' exists (needed for newgrp docker in the setup script) - # - Run the setup script in headless mode - RUN_CMD='export DEBIAN_FRONTEND=noninteractive; \ - apt-get update && \ - apt-get install -y ca-certificates curl git sudo docker.io && \ - groupadd -f docker && \ - bash /opt/adore_setup.sh --headless' - -else - # --- Remote script mode --------------------------------------------------- - echo "INFO: No local setup script provided." - echo "INFO: Will curl '${DEFAULT_SETUP_URL}' inside the container." - - # No extra volume for the script; it will be downloaded inside the container - RUN_CMD="export DEBIAN_FRONTEND=noninteractive; \ - apt-get update && \ - apt-get install -y ca-certificates curl git sudo docker.io && \ - groupadd -f docker && \ - bash <(curl -sSL ${DEFAULT_SETUP_URL}) --headless" -fi - -# Add image + command to docker run invocation -DOCKER_CMD+=("${IMAGE}" bash -lc "${RUN_CMD}") - -echo "Running setup script inside container..." -if "${DOCKER_CMD[@]}"; then - echo "true" - exit 0 -else - echo "false" - exit 1 -fi diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 34327e7b..bb63ca8d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,93 +1,197 @@ -name: CI +name: ADORe CI +run-name: "ADORe CI #${{ github.run_number }}: ${{ github.event.head_commit.message }} by ${{ github.actor }}" on: push: - branches: [ main, master, develop ] + branches: ["**"] + tags: ["v*"] pull_request: - branches: [ "**" ] + branches: ["**"] + release: + types: [published] + +permissions: + contents: write + packages: write jobs: - ci: - name: Tests + Docs (CI image) — ${{ matrix.name }} + build-test-push-publish: strategy: fail-fast: false matrix: include: - - name: x86_64 - runner: ubuntu-24.04 - platform: linux/amd64 - - name: arm64 + - arch: x86_64 + runner: ubuntu-latest + - arch: aarch64 runner: ubuntu-24.04-arm - platform: linux/arm64 runs-on: ${{ matrix.runner }} - permissions: - contents: read - env: - ROS_DISTRO: jazzy - DOCKER_DEFAULT_PLATFORM: ${{ matrix.platform }} - COLCON_WS_ROOT: .colcon_workspace + ADORE_CLI_REPO: ${{ github.repository }} + steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: submodules: recursive + fetch-depth: 0 - - name: Show environment - run: | - echo "Runner: ${{ matrix.runner }}" - echo "Platform: ${{ matrix.platform }}" - uname -a - docker info - - - name: Cache ccache - uses: actions/cache@v4 + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 with: - path: .cache/ccache - # One cache per OS + arch + branch - key: ccache-${{ runner.os }}-${{ matrix.name }}-${{ github.ref_name }} - restore-keys: | - ccache-${{ runner.os }}-${{ matrix.name }}- - ccache-${{ runner.os }}- + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # ── Lichtblick ──────────────────────────────────────────────────────────── + - name: Build Lichtblick + run: cd tools/lichtblick && make build + + - name: Push Lichtblick image + if: github.event_name != 'pull_request' + run: cd tools/lichtblick && make push_lichtblick + + # ── ADORe CLI + ADORe ───────────────────────────────────────────────────── + - name: Build ADORe + run: make build + + # ── Package ───────────────────────────────────────────────────────────────── + #- name: Package ADORe + # run: make package - - name: Build CI Docker image - run: .docker/scripts/build_ci.sh + # ── Tests ───────────────────────────────────────────────────────────────── + - name: Run tests + run: make test - - name: Run tests + docs inside CI image - run: .docker/scripts/run_ci.sh + # ── Push images (only after tests pass) ─────────────────────────────────── + - name: Push ADORe CLI user image + if: github.event_name != 'pull_request' + run: make push_user_image - - name: Upload colcon logs (${{ matrix.name }}) + # ── ADORe Embedded ──────────────────────────────────────────────────────── + - name: Build ADORe Embedded + run: cd adore_embedded && make build + + - name: Package ADORe Embedded + run: cd adore_embedded && make package && make bundle + + - name: Push ADORe Embedded image + if: github.event_name != 'pull_request' + run: cd adore_embedded && make push + + - name: Upload logs if: always() uses: actions/upload-artifact@v4 with: - name: colcon-logs-${{ matrix.name }} - path: ${{ env.COLCON_WS_ROOT }}/log + name: logs-${{ matrix.arch }} + path: | + .log + ros2_workspace/log if-no-files-found: ignore + - - name: Upload colcon test results - if: always() + - name: Generate ADORe Embedded Release uses: actions/upload-artifact@v4 with: - name: test-results-${{ matrix.name }} - path: ${{ env.COLCON_WS_ROOT }}/build/*/test_results/**/*.xml - if-no-files-found: ignore + name: adore-embedded-packages-${{ matrix.arch }} + path: adore_embedded/packages/adore_embedded_*.tar.gz + if-no-files-found: error - - name: Upload coverage reports - if: always() - uses: actions/upload-artifact@v4 + # ── Release ─────────────────────────────────────────────────────────────────── + release: + needs: build-test-push-publish + if: >- + always() && + needs.build-test-push-publish.result == 'success' && + github.event_name == 'push' && + github.repository == 'eclipse-adore/adore' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 with: - name: coverage-${{ matrix.name }} - path: | - .gcovr_reports/coverage.xml - .gcovr_reports/coverage.html - if-no-files-found: error # or 'ignore' while you're iterating locally + submodules: recursive + fetch-depth: 0 - - name: Upload built docs (${{ matrix.name }}) - if: always() - uses: actions/upload-artifact@v4 + - name: Download ADORe Embedded packages (x86_64) + uses: actions/download-artifact@v4 with: - name: docs-site-${{ matrix.name }} - path: documentation/docs - if-no-files-found: ignore + name: adore-embedded-packages-x86_64 + path: dist/ + + - name: Download ADORe Embedded packages (aarch64) + uses: actions/download-artifact@v4 + with: + name: adore-embedded-packages-aarch64 + path: dist/ + + - name: Create source archive + run: | + ref="${{ github.ref_name }}" + ref_slug="${ref//\//-}" + if [[ "$ref" == "develop" ]]; then + release_tag="release" + release_name="release" + else + release_tag="dev-${ref_slug}" + release_name="development snapshot for ${ref}" + fi + echo "RELEASE_TAG=${release_tag}" >> "$GITHUB_ENV" + echo "RELEASE_NAME=${release_name}" >> "$GITHUB_ENV" + echo "REF_SLUG=${ref_slug}" >> "$GITHUB_ENV" + mkdir -p dist + git archive --format=tar.gz \ + --prefix=adore_embedded/ \ + --output="dist/adore_embedded_source_${ref_slug}.tar.gz" \ + HEAD:adore_embedded + + - name: Stage README + run: | + release_url="https://github.com/${{ github.repository }}/releases/tag/${{ env.RELEASE_TAG }}" + x86_file=$(basename "$(ls dist/adore_embedded_x86_64_*.tar.gz | grep -v bundle | head -1)") + aarch64_file=$(basename "$(ls dist/adore_embedded_aarch64_*.tar.gz | grep -v bundle | head -1)") + x86_bundle=$(basename "$(ls dist/adore_embedded_x86_64_*_bundle.tar.gz | head -1)") + aarch64_bundle=$(basename "$(ls dist/adore_embedded_aarch64_*_bundle.tar.gz | head -1)") + awk \ + -v release_tag="${{ env.RELEASE_TAG }}" \ + -v release_url="$release_url" \ + -v x86_file="$x86_file" \ + -v aarch64_file="$aarch64_file" \ + -v x86_bundle="$x86_bundle" \ + -v aarch64_bundle="$aarch64_bundle" \ + -v x86_dir="${x86_file%.tar.gz}" \ + -v aarch64_dir="${aarch64_file%.tar.gz}" \ + '{ + gsub(//, release_tag) + gsub(//, release_url) + gsub(//, x86_bundle) + gsub(//, aarch64_bundle) + gsub(//, x86_file) + gsub(//, aarch64_file) + gsub(//, x86_dir) + gsub(//, aarch64_dir) + print + }' \ + adore_embedded/README.release.md > dist/README.md + + - name: Delete existing release assets + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release view "${{ env.RELEASE_TAG }}" --json assets \ + --jq '.assets[].name' 2>/dev/null \ + | xargs -r -I{} gh release delete-asset \ + "${{ env.RELEASE_TAG }}" "{}" --yes 2>/dev/null \ + || true + + - name: Publish GitHub release assets + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ env.RELEASE_TAG }} + name: ${{ env.RELEASE_NAME }} + target_commitish: ${{ github.sha }} + body_path: dist/README.md + prerelease: ${{ github.ref_name != 'develop' }} + files: | + dist/adore_embedded_*.tar.gz + fail_on_unmatched_files: true diff --git a/.github/workflows/docs_publish.yaml b/.github/workflows/docs_publish.yaml deleted file mode 100644 index a5735621..00000000 --- a/.github/workflows/docs_publish.yaml +++ /dev/null @@ -1,45 +0,0 @@ -name: Publish Docs - -on: - push: - branches: [ main ] - paths: - - 'documentation/**' - - 'Justfile' - - '.docker/scripts/**' - - '.github/workflows/docs-publish.yml' - -jobs: - publish-docs: - name: Build & publish docs - runs-on: ubuntu-24.04 - - permissions: - contents: write # needed to push gh-pages - pages: write - id-token: write - - env: - ROS_DISTRO: jazzy - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: recursive - # keep default persist-credentials: true so pushes use GITHUB_TOKEN - - - name: Show Docker info - run: docker info - - - name: Build CI Docker image - run: .docker/scripts/build_ci.sh - - - name: Build docs in CI image - run: .docker/scripts/run_docs.sh - - - name: Publish docs to gh-pages - run: | - set -euo pipefail - cd documentation - bash publish_gh-pages.sh diff --git a/.gitignore b/.gitignore index ded9487d..6cdcdbbb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,23 @@ -.zsh_history +ros2_workspace/colcon_defaults.yaml +**.zsh_history **/build **/.tmp build **.jpg **.log +**.zip deploy.env libraries/cmake/ignore/ignore.log .log plugins/* !plugins/.gitkeep +adore_embedded/context/ +adore_embedded/packages/ +adore_embedded/build/ +**.rej +**.orig +ros2_workspace/src/vendor/adore_extended +Function **.vscode .colcon_workspace/build @@ -17,6 +26,11 @@ plugins/* .colcon_workspace/src/ **__pycache__** *.pyc +**.tar.gz +**.orj +**.rej + +ros2_workspace/colcon_defaults.yaml ### C++ ### # Prerequisites diff --git a/.gitmodules b/.gitmodules index dbafdb06..942a7345 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,82 +1,122 @@ [submodule "ros2_messages/adore_ros2_msgs"] - path = adore_ros2_msgs + path = ros2_workspace/src/adore_ros2_msgs url = git@github.com:eclipse-adore/adore_ros2_msgs.git [submodule "nodes/adore_simulated_vehicle"] - path = adore_ros2_nodes/simulated_vehicle + path = ros2_workspace/src/adore_ros2_nodes/simulated_vehicle url = git@github.com:eclipse-adore/adore_simulated_vehicle.git [submodule "mission_control"] - path = adore_ros2_nodes/mission_control + path = ros2_workspace/src/adore_ros2_nodes/mission_control url = git@github.com:eclipse-adore/adore_mission_control.git [submodule "nodes/adore_visualizer"] - path = adore_ros2_nodes/visualizer + path = ros2_workspace/src/adore_ros2_nodes/visualizer url = git@github.com:eclipse-adore/adore_visualizer.git [submodule "nodes/adore_decision_maker"] - path = adore_ros2_nodes/decision_maker + path = ros2_workspace/src/adore_ros2_nodes/decision_maker url = git@github.com:eclipse-adore/adore_decision_maker.git [submodule "nodes/adore_trajectory_tracker"] - path = adore_ros2_nodes/trajectory_tracker + path = ros2_workspace/src/adore_ros2_nodes/trajectory_tracker url = git@github.com:eclipse-adore/adore_trajectory_tracker.git [submodule "adore_scenarios/adore_simulation_scenarios"] path = adore_scenarios/simulation_scenarios url = git@github.com:eclipse-adore/adore_simulation_scenarios.git -[submodule "vendor/libOpenDRIVE"] - path = vendor/libOpenDRIVE - url = git@github.com:markomiz/libOpenDRIVE.git [submodule "interfaces/sumo_bridge"] - path = adore_interfaces/sumo_bridge + path = ros2_workspace/src/adore_interfaces/sumo_bridge url = git@github.com:eclipse-adore/sumo_if_ros.git [submodule "interfaces/carla_bridge"] - path = adore_interfaces/carla_bridge + path = ros2_workspace/src/adore_interfaces/carla_bridge url = git@github.com:eclipse-adore/adore_if_carla.git [submodule "ros2_messages/ros-carla-msgs"] - path = vendor/ros-carla-msgs + path = ros2_workspace/src/vendor/ros-carla-msgs url = git@github.com:carla-simulator/ros-carla-msgs.git [submodule "tools/ros2_observer"] path = tools/ros2_observer url = git@github.com:DLR-TS/ros2_observer.git [submodule "libraries/adore_planning"] - path = adore_libraries/adore_planning + path = ros2_workspace/src/adore_libraries/adore_planning url = git@github.com:eclipse-adore/adore_planning.git [submodule "libraries/adore_controllers"] - path = adore_libraries/adore_controllers + path = ros2_workspace/src/adore_libraries/adore_controllers url = git@github.com:eclipse-adore/adore_controllers.git [submodule "libraries/adore_map"] - path = adore_libraries/adore_map + path = ros2_workspace/src/adore_libraries/adore_map url = git@github.com:eclipse-adore/adore_map.git [submodule "libraries/adore_math"] - path = adore_libraries/adore_math + path = ros2_workspace/src/adore_libraries/adore_math url = git@github.com:eclipse-adore/adore_math.git [submodule "libraries/adore_dynamics"] - path = adore_libraries/adore_dynamics + path = ros2_workspace/src/adore_libraries/adore_dynamics url = git@github.com:eclipse-adore/adore_dynamics.git [submodule "conversions/adore_dynamics_conversions"] - path = adore_ros2_conversions/adore_dynamics_conversions + path = ros2_workspace/src/adore_ros2_conversions/adore_dynamics_conversions url = git@github.com:eclipse-adore/adore_dynamics_conversions.git [submodule "conversions/adore_map_conversions"] - path = adore_ros2_conversions/adore_map_conversions + path = ros2_workspace/src/adore_ros2_conversions/adore_map_conversions url = git@github.com:eclipse-adore/adore_map_conversions.git [submodule "conversions/adore_math_conversions"] - path = adore_ros2_conversions/adore_math_conversions + path = ros2_workspace/src/adore_ros2_conversions/adore_math_conversions url = git@github.com:eclipse-adore/adore_math_conversions.git [submodule "nodes/adore_decision_maker_infrastructure"] - path = adore_ros2_nodes/decision_maker_infrastructure + path = ros2_workspace/src/adore_ros2_nodes/decision_maker_infrastructure url = git@github.com:eclipse-adore/adore_decision_maker_infrastructure.git [submodule "nodes/adore_simulated_remote_operator"] - path = adore_ros2_nodes/simulated_remote_operator + path = ros2_workspace/src/adore_ros2_nodes/simulated_remote_operator url = git@github.com:eclipse-adore/adore_simulated_remote_operator.git [submodule "vendor/osqp_eigen"] - path = vendor/osqp_eigen - url = https://github.com/robotology/osqp-eigen.git -[submodule "vendor/multi_agent_solver"] - path = vendor/multi_agent_solver - url = git@github.com:markomiz/multi_agent_solver.git + path = vendor/osqp/osqp_eigen + url = https://github.com/dlr-ts/osqp-eigen.git [submodule "vendor/osqp"] - path = vendor/osqp + path = vendor/osqp/osqp url = https://github.com/osqp/osqp.git [submodule "tools/adore_model_checker"] path = tools/adore_model_checker url = git@github.com:DLR-TS/adore_model_checker.git [submodule "vendor/caches"] - path = vendor/caches + path = ros2_workspace/src/vendor/caches url = git@github.com:s0nofab1t/caches.git branch = feature/wfs-downloader +[submodule "adore_cli"] + path = adore_cli + url = git@github.com:eclipse-adore/adore_cli.git +[submodule "vendor/OptiNLC"] + path = vendor/OptiNLC + url = git@github.com:dlr-ts/OptiNLC.git +[submodule "vendor/mathematics_toolbox"] + path = vendor/mathematics_toolbox + url = git@github.com:dlr-ts/mathematics_toolbox.git + +[submodule "vendor/ros2_observer"] + path = vendor/ros2_observer + url = git@github.com:dlr-ts/ros2_observer.git +[submodule "tools/lichtblick/lichtblick"] + path = tools/lichtblick/lichtblick + url = https://github.com/Lichtblick-Suite/lichtblick.git +[submodule "vendor/libOpenDRIVE/libOpenDRIVE"] + path = vendor/libOpenDRIVE/libOpenDRIVE + url = git@github.com:pageldev/libOpenDRIVE.git +[submodule "ros2_workspace/src/vendor/osqp-eigen"] + path = ros2_workspace/src/vendor/osqp_eigen + url = https://github.com/robotology/osqp-eigen.git +[submodule "ros2_workspace/src/vendor/multi_agent_solver"] + path = ros2_workspace/src/vendor/multi_agent_solver + url = git@github.com:DLR-TS/multi_agent_solver.git +[submodule "ros2_workspace/src/vendor/osqp"] + path = ros2_workspace/src/vendor/osqp/osqp + url = https://github.com/osqp/osqp.git +[submodule "ros2_workspace/src/vendor/libOpenDRIVE"] + path = ros2_workspace/src/vendor/libOpenDRIVE + url = git@github.com:pageldev/libOpenDRIVE.git +[submodule "ros2_workspace/src/vendor/qdldl"] + path = ros2_workspace/src/vendor/osqp/qdldl + url = git@github.com:osqp/qdldl.git +[submodule "ros2_workspace/src/vendor/pugixml"] + path = ros2_workspace/src/vendor/osqp/pugixml + url = git@github.com:zeux/pugixml.git +[submodule "ros2_workspace/src/vendor/osqp_build/osqp"] + path = ros2_workspace/src/vendor/osqp_build/osqp + url = https://github.com/osqp/osqp.git +[submodule "vendor/adore_model_checker"] + path = vendor/adore_model_checker + url = git@github.com:DLR-TS/adore_model_checker.git +[submodule "ros2_workspace/src/adore_ros2_nodes/operational_design_domain"] + path = ros2_workspace/src/adore_ros2_nodes/operational_design_domain + url = git@github.com:DLR-TS/operational_design_domain.git diff --git a/.tests b/.tests new file mode 100644 index 00000000..0e896eb3 --- /dev/null +++ b/.tests @@ -0,0 +1,459 @@ +#!/usr/bin/env bash + +#Define module specific tests here +# each test function should be post fixed with "_test" to be automatically +# invoked. + +LOG_DIRECTORY="${LOG_DIRECTORY:-.log}" + + +# Global timeout for API readiness check (in seconds) +API_READINESS_TIMEOUT=60 + +SIMULATION_TEST_SCENARIO_RUNTIME=45 +SIMULATION_TEST_SCENARIO_REQUEST_TIMEOUT=120 + + +wait_for_api_ready() { + local timeout=${1:-$API_READINESS_TIMEOUT} + local status_url="http://localhost:8888/api/status" + local elapsed=0 + + while [ $elapsed -lt $timeout ]; do + if curl -s --max-time 5 "$status_url" > /dev/null 2>&1; then + local http_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$status_url") + if [ "$http_code" = "200" ]; then + return 0 + fi + fi + sleep 1 + elapsed=$((elapsed + 1)) + done + + return 1 +} + +01_api_health_check_test() { + local action=health_check + local name="API Health Check Test" + local description="This test validates that the API is responding correctly to basic requests." + local status="" + local message="" + local api_health_output_json_file="${LOG_DIRECTORY}/api_health_check_results.json" + printf "\n" + printf " Test: %s\n" "${name}" + printf " Description: %s\n" "${description}" + printf " This test aims to answer the following questions: \n" + printf " Is the API server responding?\n" + printf " Are the basic endpoints accessible?\n" + printf " Do the endpoints return valid JSON?\n" + printf " Starting API health check...\n" + make start > /dev/null 2>&1 + + printf " Waiting for API to be ready...\n" + if ! wait_for_api_ready; then + printf " Status: $(bold $(red "FAILED")) - API not ready after ${API_READINESS_TIMEOUT} seconds\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + # Test 1: Status endpoint + printf " Testing status endpoint...\n" + status_http_code=$(curl -s --max-time 10 -o /tmp/status_response -w "%{http_code}" http://localhost:8888/api/status) + status_exit_code=$? + + if [ $status_exit_code -ne 0 ]; then + printf " Status: $(bold $(red "FAILED")) - Status endpoint failed with exit code $status_exit_code\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + if [ "$status_http_code" != "200" ]; then + printf " Status: $(bold $(red "FAILED")) - Status endpoint returned HTTP $status_http_code\n" + printf " Response: %s\n" "$(cat /tmp/status_response)" + make stop > /dev/null 2>&1 + exit 1 + fi + + status_result=$(cat /tmp/status_response) + # Validate status response is valid JSON + if ! echo "$status_result" | jq . > /dev/null 2>&1; then + printf " Status: $(bold $(red "FAILED")) - Status endpoint returned invalid JSON\n" + printf " Response: %s\n" "$status_result" + make stop > /dev/null 2>&1 + exit 1 + fi + + # Test 2: Scenario endpoint + printf " Testing scenario endpoints...\n" + scenario_http_code=$(curl -s --max-time 10 -o /tmp/scenario_response -w "%{http_code}" http://localhost:8888/api/scenario/get) + scenario_exit_code=$? + + if [ $scenario_exit_code -ne 0 ]; then + printf " Status: $(bold $(red "FAILED")) - Scenario endpoint failed with exit code $scenario_exit_code\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + if [ "$scenario_http_code" != "200" ]; then + printf " Status: $(bold $(red "FAILED")) - Scenario endpoint returned HTTP $scenario_http_code\n" + printf " Response: %s\n" "$(cat /tmp/scenario_response)" + make stop > /dev/null 2>&1 + exit 1 + fi + + scenario_result=$(cat /tmp/scenario_response) + # Validate scenario response is valid JSON + if ! echo "$scenario_result" | jq . > /dev/null 2>&1; then + printf " Status: $(bold $(red "FAILED")) - Scenario endpoint returned invalid JSON\n" + printf " Response: %s\n" "$scenario_result" + make stop > /dev/null 2>&1 + exit 1 + fi + + # Test 3: Test invalid endpoint returns proper error + printf " Testing error handling...\n" + error_http_code=$(curl -s --max-time 10 -o /dev/null -w "%{http_code}" http://localhost:8888/api/nonexistent) + error_exit_code=$? + + if [ $error_exit_code -ne 0 ]; then + printf " Status: $(bold $(red "FAILED")) - Error test failed with exit code $error_exit_code\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + # Check that we get a 404 for non-existent endpoint + if [ "$error_http_code" != "404" ]; then + printf " Status: $(bold $(red "FAILED")) - Expected 404 for non-existent endpoint, got $error_http_code\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + printf "\n" + printf " Compiling results...\n" + + # Create summary JSON + health_summary=$(jq -n \ + --arg status_response "$status_result" \ + --arg scenario_response "$scenario_result" \ + --arg status_http_code "$status_http_code" \ + --arg scenario_http_code "$scenario_http_code" \ + --arg error_http_code "$error_http_code" \ + '{ + "test_name": "API Health Check", + "timestamp": now | strftime("%Y-%m-%d %H:%M:%S"), + "results": { + "status_endpoint": { + "status": "PASSED", + "http_code": $status_http_code, + "response": ($status_response | fromjson) + }, + "scenario_endpoint": { + "status": "PASSED", + "http_code": $scenario_http_code, + "response_length": ($scenario_response | length) + }, + "error_handling": { + "status": "PASSED", + "http_code": $error_http_code + } + }, + "overall_status": "PASSED" + }') + + echo "$health_summary" > "$api_health_output_json_file" + + # Extract key info for display + api_version=$(echo "$status_result" | jq -r '.version // "unknown"' 2> /dev/null) + + message=" API Health Check Summary: + Status endpoint: PASSED (HTTP $status_http_code) + Scenario endpoint: PASSED (HTTP $scenario_http_code) + Error handling: PASSED (proper 404 response) + API version: ${api_version}" + + status=$(bold $(green "PASSED")) + printf " Message:\n%s\n" "$message" + printf " %-77s %s\n" "Status:" "${status}" + make stop > /dev/null 2>&1 + printf " See the health check log for more info: %s\n" "$api_health_output_json_file" + + # Clean up temp files + rm -f /tmp/status_response /tmp/scenario_response + exit 0 +} + +00_ros2_build_check_test() { + local name="ROS2 Build Check" + local description="Verifies that the ROS2 workspace has been successfully built before running simulation tests." + local build_success_file="ros2_workspace/build/build.success" + + printf "\n" + printf " Test: %s\n" "${name}" + printf " Description: %s\n" "${description}" + printf " Checking for ROS2 build artifact...\n" + + if [ ! -f "${build_success_file}" ]; then + printf " Status: $(bold $(red "FAILED")) - Build success marker not found: %s\n" "${build_success_file}" + printf " Run 'make build' or build the ROS2 workspace before executing simulation tests.\n" + exit 1 + fi + + printf " Build success marker found: %s\n" "${build_success_file}" + printf " %-77s %s\n" "Status:" "$(bold $(green "PASSED"))" + exit 0 +} + +02_simulation_test_scenario_test() { + local action=simulate + local name="Simulation Test" + local description="This test executes the simulation_test.launch.py scenario and verify the model checking results." + local status="" + local message="" + local model_checking_output_json_file="${LOG_DIRECTORY}/simulation_test_model_checking_results.json" + printf "\n" + printf " Test: %s\n" "${name}" + printf " Description: %s\n" "${description}" + printf " This test aims to answer the following questions: \n" + printf " Did the vehicle move?\n" + printf " Did the vehicle reach its goal?\n" + printf " Did the scenario generate any exceptions?\n" + printf " Running scenario...\n" + make start > /dev/null 2>&1 + + printf " Waiting for API to be ready...\n" + if ! wait_for_api_ready; then + printf " Status: $(bold $(red "FAILED")) - API not ready after ${API_READINESS_TIMEOUT} seconds\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + { + while true; do + sleep 1 + printf "." >&2 + done + } & + dot_pid=$! + + + result=$(curl -s --max-time ${SIMULATION_TEST_SCENARIO_REQUEST_TIMEOUT} \ + -X POST http://localhost:8888/api/scenario/start/model_checked \ + -H "Content-Type: application/json" \ + -d "{\"duration\":${SIMULATION_TEST_SCENARIO_RUNTIME}}") + curl_exit_code=$? + + kill $dot_pid 2> /dev/null + wait $dot_pid 2> /dev/null + + if [ $curl_exit_code -eq 28 ]; then + printf "\n" + printf " Status: $(bold $(red "FAILED")) - Request timed out after ${SIMULATION_TEST_SCENARIO_REQUEST_TIMEOUT} seconds\n" + make stop > /dev/null 2>&1 + exit 1 + elif [ $curl_exit_code -ne 0 ]; then + printf "\n" + printf " Status: $(bold $(red "FAILED")) - Request failed with exit code $curl_exit_code\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + printf "\n" + printf " Parsing results...\n" + echo "${result}" > "${model_checking_output_json_file}" + + if [ -z "$result" ] || [ "$result" = "null" ]; then + printf " Status: $(bold $(red "FAILED")) - API returned no results\n" + make stop > /dev/null 2>&1 + exit 1 + fi + + if ! echo "$result" | jq . > /dev/null 2>&1; then + printf " Status: $(bold $(red "FAILED")) - API returned invalid JSON\n" + printf " Response: %s\n" "$result" + make stop > /dev/null 2>&1 + exit 1 + fi + + if ! echo "$result" | jq -e '.model_check_result.results' > /dev/null 2>&1; then + printf " Status: $(bold $(red "FAILED")) - API response missing expected model check results\n" + printf " Response: %s\n" "$result" + make stop > /dev/null 2>&1 + exit 1 + fi + + message=$(echo "$result" | jq -r ' + .model_check_result.results.SUMMARY as $s | + ( + " Model Check Summary: " + + (($s.total_propositions // $s.analyzed // 0) | tostring) + " analyzed, " + + (($s.passed // 0) | tostring) + " passed, " + + (($s.failed // 0) | tostring) + " failed, success rate: " + + (((($s.success_rate // 0) * 100) | round) | tostring) + "% - Overall result: " + + ($s.overall_result // "UNKNOWN") + + "\n" + ) + + " Propositions:\n" + + ( + (.model_check_result.results // {}) + | to_entries + | map(select(.key != "SUMMARY")) + | map( + " " + (.value.description.title // .value.title // .key) + ": " + (.value.status // "UNKNOWN") + "\n" + + " Description: " + (.value.description.description // .value.description // "N/A") + "\n" + + " Safety Goal: " + (.value.description.safety_rationale // .value.safety_rationale // "N/A") + "\n" + + " Formula Description: " + (.value.formula_description // "N/A") + "\n" + + " Formula Type: " + (.value.formula_type // "N/A") + ) + | join("\n\n") + ) + ') + + model_checking_status=$(echo "$result" | jq -r ' + if ((.model_check_result.results.SUMMARY.success_rate // 0) == 1 and + ([.model_check_result.results | to_entries[] | select(.key != "SUMMARY") | .value.status] | + any(. == "NO_DATA" or . == "FAIL")) | not) then 0 else 1 end + ') + + if [ "$model_checking_status" -eq 0 ]; then + status=$(bold $(green "PASSED")) + else + status=$(bold $(red "FAILED")) + fi + + printf " Message:\n%s\n" "$message" + printf " %-77s %s\n" "Status:" "${status}" + make stop > /dev/null 2>&1 + printf " See the model checking log for more info: %s\n" "$model_checking_output_json_file" + exit $model_checking_status +} + +03_eclipse_due_diligence_scan() { + local action=due_diligence_scan + local name="Eclipse Due Diligence Scan Test" + local description="This test runs 'make due_diligence_scan' and validates the scan output." + local status="" + local message="" + local scan_log_file="${LOG_DIRECTORY}/due_diligence_scan.log" + printf "\n" + printf " Test: %s\n" "${name}" + printf " Description: %s\n" "${description}" + printf " This test runs the eclipse due diligence scanner to verify all source code has the proper license header comment. \n" + printf " Starting make due_diligence_scan...\n" + + if ! make due_diligence_scan >"$scan_log_file" 2>&1; then + status=$(bold $(red "FAILED")) + message=" Make due_diligence_scan command failed. See log: ${scan_log_file}" + cat "${scan_log_file}" + printf " Message:\n%s\n" "$message" + printf " %-77s %s\n" "Status:" "${status}" + exit 1 + fi + + status=$(bold $(green "PASSED")) + message=" Make due_diligence_scan succeeded. Tail of log shown below:" + printf " Message:\n%s\n" "$message" + tail -15 "${scan_log_file}" + printf " %-77s %s\n" "Status:" "${status}" + printf " See the due_diligence_scan log for full details: %s\n" "$scan_log_file" + exit 0 +} + +04_x11_integration_test() { + local action=x11_integration_test + local name="X11 Integration Test" + local description="Validates the display stack: DISPLAY var, X11 socket, xhost, xdpyinfo, and xeyes." + local status="" + local display_val="" + local display_num="" + local socket="" + local container="" + local cmd_out="" + local cmd_rc=0 + + printf "\n" + printf " Test: %s\n" "${name}" + printf " Description: %s\n" "${description}" + printf " This test aims to answer the following questions: \n" + printf " Is DISPLAY set inside the container?\n" + printf " Does the X11 socket exist for that display?\n" + printf " Is the X server accessible via xdpyinfo?\n" + printf " Can xeyes connect and render (full display pipeline)?\n" + printf " Starting Docker context...\n" + + if ! make start; then + status=$(bold $(red "FAILED")) + printf " make start failed — cannot proceed with display checks.\n" + printf " %-77s %s\n" "Status:" "${status}" + exit 1 + fi + + container=$(make container_name_adore_cli 2>/dev/null) + + printf "\n --- DISPLAY variable ---\n" + display_val=$(docker exec "${container}" cat /tmp/.adore_display 2>/dev/null | grep -o 'DISPLAY=.*' | cut -d= -f2- | tail -1) + if [ -z "${display_val}" ]; then + status=$(bold $(red "FAILED")) + printf " DISPLAY is not set inside the container.\n" + printf " /tmp/.adore_display contents:\n" + docker exec "${container}" cat /tmp/.adore_display 2>&1 || printf " (file not found)\n" + printf " Container logs (tail):\n" + docker logs "${container}" 2>&1 | tail -20 + printf " %-77s %s\n" "Status:" "${status}" + make stop + exit 1 + fi + printf " DISPLAY=%s\n" "${display_val}" + + printf "\n --- X11 socket ---\n" + display_num="${display_val##*:}" + display_num="${display_num%%.*}" + socket="/tmp/.X11-unix/X${display_num}" + if ! docker exec "${container}" test -S "${socket}" 2>/dev/null; then + status=$(bold $(red "FAILED")) + printf " X11 socket %s does not exist inside the container.\n" "${socket}" + printf " If using host display: check /tmp/.X11-unix is mounted (-v /tmp/.X11-unix:/tmp/.X11-unix).\n" + printf " If using Xvfb: check that entrypoint.sh Xvfb started cleanly (check container logs).\n" + docker logs "${container}" 2>&1 | tail -20 + printf " %-77s %s\n" "Status:" "${status}" + make stop + exit 1 + fi + printf " X11 socket %s: found\n" "${socket}" + + printf "\n --- xdpyinfo ---\n" + cmd_out=$(docker exec -e DISPLAY="${display_val}" "${container}" xdpyinfo 2>&1) + cmd_rc=$? + if [ "${cmd_rc}" -ne 0 ]; then + status=$(bold $(red "FAILED")) + printf " xdpyinfo failed (exit %d) on DISPLAY=%s\n" "${cmd_rc}" "${display_val}" + printf " xdpyinfo output:\n%s\n" "${cmd_out}" + printf " %-77s %s\n" "Status:" "${status}" + make stop + exit 1 + fi + printf " xdpyinfo: OK\n" + + printf "\n --- xeyes ---\n" + cmd_out=$(docker exec -e DISPLAY="${display_val}" "${container}" timeout 1 xeyes 2>&1) + cmd_rc=$? + if [ "${cmd_rc}" -ne 0 ] && [ "${cmd_rc}" -ne 124 ]; then + status=$(bold $(red "FAILED")) + printf " xeyes failed (exit %d) on DISPLAY=%s\n" "${cmd_rc}" "${display_val}" + printf " xeyes output:\n%s\n" "${cmd_out}" + printf " %-77s %s\n" "Status:" "${status}" + make stop + exit 1 + fi + printf " xeyes: OK\n" + + status=$(bold $(green "PASSED")) + printf "\n Display stack fully functional:\n" + printf " DISPLAY=%s socket=%s xdpyinfo OK xeyes OK\n" "${display_val}" "${socket}" + printf " %-77s %s\n" "Status:" "${status}" + + printf " Stopping Docker context...\n" + make stop + exit 0 +} + diff --git a/Justfile b/Justfile deleted file mode 100644 index 2f84720d..00000000 --- a/Justfile +++ /dev/null @@ -1,277 +0,0 @@ -# Use bash as the shell -set shell := ["/bin/bash", "-c"] - -# ------------------------------------------------------------------- -# Global paths & environment -# ------------------------------------------------------------------- - -# Root of the repo (directory containing this Justfile) -export WORKSPACE_ROOT := justfile_directory() - -# Colcon workspace dir (always .colcon_workspace under repo root) -export COLCON_WS_ROOT := WORKSPACE_ROOT + "/.colcon_workspace" - -# Documentation root -export DOCS_ROOT := WORKSPACE_ROOT + "/documentation" - -# Default ROS distro; can be overridden from the environment -export ROS_DISTRO := env('ROS_DISTRO', 'jazzy') - -# Script to set up colcon_workspace/src symlinks -export SETUP_COLCON_SCRIPT := ".docker/scripts/setup_colcon_src.sh" - -# Helpers: use shell variables and command substitution, no {{...}} inside -source_ros := 'source /opt/ros/$ROS_DISTRO/setup.sh; \ -if [ -d install ] && [ -f install/local_setup.sh ]; then \ - source install/local_setup.sh; \ -fi' -# Extra colcon build args from environment variable (COLCON_COVERAGE_ARGS) -colcon_extra_args := env_var_or_default("COLCON_COVERAGE_ARGS", "") - -colcon_cmd := 'colcon build ' + colcon_extra_args - - -# Host uid/gid for docker -u in docs_spellcheck/docs_lint -uid := `id -u` -gid := `id -g` - -# Default target -default: help - -# Show all available recipes -help: - @just --list - -# ------------------------------------------------------------------- -# Symlink setup for colcon workspace -# ------------------------------------------------------------------- - -# Ensure .colcon_workspace/src symlinks are up to date -setup_colcon_src: - cd "$WORKSPACE_ROOT" && \ - if [ -x "$SETUP_COLCON_SCRIPT" ]; then \ - echo "--- Ensuring colcon_workspace/src symlinks are set up ---"; \ - "$SETUP_COLCON_SCRIPT"; \ - else \ - echo "ERROR: $SETUP_COLCON_SCRIPT not found or not executable" >&2; \ - exit 1; \ - fi - -# ------------------------------------------------------------------- -# Docker-backed targets (dev image) -# ------------------------------------------------------------------- - -# Build the dev Docker image (adore_dev) -build_ci: - cd "$WORKSPACE_ROOT" && .docker/scripts/build_ci.sh -# Build the dev Docker image (adore_dev) -build_dev: - cd "$WORKSPACE_ROOT" && .docker/scripts/build_dev.sh - -# Start or attach to the ADORe dev container -dev: setup_colcon_src - cd "$WORKSPACE_ROOT" && .docker/scripts/run_dev.sh - -# Remove local ADORe Docker images -clean_images: - cd "$WORKSPACE_ROOT" && .docker/scripts/clean_images.sh - -# Remove .colcon_workspace build/install/log directories -clean_ws: - rm -rf "$COLCON_WS_ROOT/build" "$COLCON_WS_ROOT/install" "$COLCON_WS_ROOT/log" - -# Full clean: Docker images + .colcon_workspace artifacts -clean: clean_images clean_ws - echo "--- Cleaned docker images and .colcon_workspace build artifacts ---" - -# Clean workspace and rebuild (host colcon) -clean_build: clean_ws build - -# Save dev/CI images to tarball(s) -save: - cd "$WORKSPACE_ROOT" && .docker/scripts/save_image.sh - -# Load dev/CI images from tarball(s) -load: - cd "$WORKSPACE_ROOT" && .docker/scripts/load_image.sh - -# ------------------------------------------------------------------- -# Local tools (always run from repo root) -# ------------------------------------------------------------------- - -# Launch the ADORe GUI (scenario launcher) -gui: - cd "$WORKSPACE_ROOT" && python3 tools/adore_gui.py - -# Run the road network editor -edit_roads: - cd "$WORKSPACE_ROOT" && python3 tools/edit_roads.py - -# Run the Lichtblick visualization wrapper -lichtblick: - cd "$WORKSPACE_ROOT" && ./tools/lichtblick/run_lichtblick.sh - -# ------------------------------------------------------------------- -# CI helpers (use the CI image under the hood) -# ------------------------------------------------------------------- - -# Build documentation inside the CI Docker image -docs: setup_colcon_src - cd "$WORKSPACE_ROOT" && .docker/scripts/run_docs.sh - -# Convenience: run tests and docs (full CI) locally -ci: setup_colcon_src - cd "$WORKSPACE_ROOT" && .docker/scripts/run_ci.sh - -publish: - cd "$WORKSPACE_ROOT" && documentation/publish_gh-pages.sh - -# ------------------------------------------------------------------- -# ADORe API control (via tools/adore_api/adore_api.sh) -# ------------------------------------------------------------------- - -# Start adore api server -api_start: - cd "$WORKSPACE_ROOT" && \ - source tools/adore_api/adore_api.sh && \ - start_adore_api - -# Stop adore api server -api_stop: - cd "$WORKSPACE_ROOT" && \ - source tools/adore_api/adore_api.sh && \ - stop_adore_api - -# Restart adore api server -api_restart: - cd "$WORKSPACE_ROOT" && \ - source tools/adore_api/adore_api.sh && \ - restart_adore_api - -# Check adore api server status -api_status: - cd "$WORKSPACE_ROOT" && \ - source tools/adore_api/adore_api.sh && \ - status_adore_api - - -# ------------------------------------------------------------------- -# Host colcon builds in .colcon_workspace (no Docker) -# ------------------------------------------------------------------- - -# Build the entire workspace locally (host colcon) -build: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - {{colcon_cmd}} - -# Run colcon tests locally (host), skipping vendor + ros-carla-msgs -test_ws: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - colcon test \ - --packages-skip `colcon list --base-paths src/vendor --names-only`; \ - colcon test-result --all --verbose || true - -# Run system tests -test_system: - ./tools/system_tests/run_system_tests.sh - -# Kill lingering ROS 2 / colcon processes (host + container aware script) -force_kill_ros2: - cd "$WORKSPACE_ROOT" && .docker/scripts/force_kill_ros2.sh - -# Build adore_scenarios packages only (host colcon) -build_scenarios: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - {{colcon_cmd}} --packages-select `colcon list --base-paths src/adore_scenarios --names-only` - -# Build conversions packages only (host colcon) -build_conversions: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - {{colcon_cmd}} --packages-select `colcon list --base-paths src/conversions --names-only` - -# Build library packages only (host colcon) -build_libraries: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - {{colcon_cmd}} --packages-select `colcon list --base-paths src/libraries --names-only` - -# Build node packages only (host colcon) -build_nodes: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - {{colcon_cmd}} --packages-select `colcon list --base-paths src/nodes --names-only` - -# Build ros2_messages packages only (host colcon) -build_messages: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - {{colcon_cmd}} --packages-select `colcon list --base-paths src/ros2_messages --names-only` - -# Build vendor packages only (host colcon) -build_vendor: - cd "$COLCON_WS_ROOT" && {{source_ros}} && \ - {{colcon_cmd}} --packages-select `colcon list --base-paths src/vendor --names-only` - -# ------------------------------------------------------------------- -# Documentation (mkdocs in documentation/) -# ------------------------------------------------------------------- - -# Clean and rebuild documentation (mkdocs + docs/) -docs_all: docs_clean docs_serve - -# Build mkdocs site into documentation/mkdocs/site -docs_build_mkdocs: - cd "$DOCS_ROOT" && \ - mkdir -p mkdocs/docs && \ - rm -rf mkdocs/docs/generated mkdocs/site && \ - cp -r technical_reference_manual mkdocs/docs/technical_reference_manual && \ - python3 mkdocs/gen_docs.py && \ - cd mkdocs && mkdocs build - -# Build docs/ tree from mkdocs output (gh-pages-ready) -docs_build: docs_build_mkdocs - cd "$DOCS_ROOT" && \ - rm -rf docs && \ - mkdir -p docs && \ - cp -r mkdocs/site docs/mkdocs &&\ - cp -r mkdocs/img docs/mkdocs &&\ - cp -r mkdocs/stylesheets docs/mkdocs &&\ - cp -r mkdocs/overrides docs/mkdocs - -# Build and serve docs at http://localhost:8000 -docs_serve: docs_build - cd "$DOCS_ROOT/docs" && python3 -m http.server 8000 - -# Publish docs to gh-pages branch -docs_publish_gh_pages: - cd "$DOCS_ROOT" && bash publish_gh-pages.sh - -# Publish docs (wrapper with reminder to review publish.env) -docs_publish: docs_publish_gh_pages - @echo "Review documentation/publish.env before publishing." - -# Watch docs and rebuild automatically on changes (needs inotify-tools) -docs_watch: - cd "$DOCS_ROOT" && \ - while inotifywait -e modify -e create -e delete -r .; do \ - just docs_build; \ - done - -# Remove generated docs and mkdocs build artifacts -docs_clean: - cd "$DOCS_ROOT" && \ - rm -rf docs mkdocs/docs mkdocs/site technical_reference_manual/generated/ - -# Interactive spellcheck of technical_reference_manual via aspell container -docs_spellcheck: docs_clean - cd "$DOCS_ROOT" && \ - docker build -f Dockerfile.aspell -t aspell . && \ - docker run -it --rm -u "{{uid}}:{{gid}}" -v "$PWD:/mnt" aspell \ - bash -lc 'find /mnt/technical_reference_manual -name "*.md" -exec aspell check --encoding=utf-8 --mode=markdown --home-dir=/mnt --personal=/mnt/.aspell.en.pws {} \;' - -# Non-interactive spellcheck/lint of docs using aspell container -docs_lint: docs_clean - cd "$DOCS_ROOT" && \ - docker build -f Dockerfile.aspell -t aspell . && \ - docker run -u "{{uid}}:{{gid}}" -v "$PWD:/mnt" aspell:latest python3 spellcheck.py - -# run scan for eclipse due diligence -due_diligence_scan: - cd "$WORKSPACE_ROOT" && python3 ./tools/eclipse_due_diligence_scanner.py --ignore ./tools/.eclipse_due_diligance_ignore diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..706b19ce --- /dev/null +++ b/Makefile @@ -0,0 +1,125 @@ +SHELL:=/bin/bash +MAKEFLAGS += --no-print-directory +.NOTPARALLEL: +ROOT_DIR:=$(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") + +# This will automatically check if submodules have been updated when the +# Makefile is invoked for the first time. +MAKE_GADGETS_DIR := adore_cli/make_gadgets +MAKE_GADGETS_HAS_FILES := $(shell [ -d $(MAKE_GADGETS_DIR) ] && [ -n "$$(find $(MAKE_GADGETS_DIR) -mindepth 1 -maxdepth 1 -not -name '.git' 2>/dev/null)" ] && echo "yes") +ifeq ($(MAKE_GADGETS_HAS_FILES),) + $(shell git submodule update --init --recursive >&2 || true) +endif + +$(shell git config core.hooksPath .githooks >&2 || true) + + +include ${MAKE_GADGETS_DIR}/make_gadgets.mk + +.EXPORT_ALL_VARIABLES: +SOURCE_DIRECTORY:=${ROOT_DIR} +SUBMODULES_PATH:=${ROOT_DIR} +VENDOR_PATH:=${ROOT_DIR}/vendor +ROS_NODE_PATH:=${ROOT_DIR}/ros2_workspace/src +ADORE_LIBRARY_PATH:=${ROOT_DIR}/libraries +DOCKER_BUILDKIT?=1 +DOCKER_CONFIG?= + + +# Branch information +BRANCH:=$(shell bash ${MAKE_GADGETS_DIR}/tools/branch_name.sh) + +include ${SUBMODULES_PATH}/adore_cli/ci_teststand/ci_teststand.mk +include utils.mk +include adore_cli/adore_cli.mk +include adore_cli/package.mk + +.PHONY: clean +clean: stop docker_host_context_check stop clean_adore_cli clean_tag_history ## Clean ADORe build artifacts + cd vendor && make clean + cd ros2_workspace && make clean + cd adore_embedded && make clean + rm -rf build + +$(shell [ -d "$(VENDOR_PATH)/build" ] || (cd vendor && $(MAKE) --no-print-directory build >&2)) + +.PHONY: build +build: docker_host_context_check stop_adore_cli build_vendor_libraries build_adore_cli build_ros_workspace build_services ## Build and setup adore cli + @make clean_tag_history + +.PHONY: build_adore_embedded +build_adore_embedded: docker_host_context_check # Build ADORe Embedded docker image + cd adore_embedded && make build + +.PHONY: build_all +build_all: clean build #build_services + +.PHONY: build_services +build_services: ## Build ADORe supporting services such as Foxglove Studio aka Lichtblick Suite + cd tools/lichtblick && make build + +.PHONY: start_services +start_services: docker_host_context_check ## Start ADORe supporting services + cd tools/lichtblick && make start + +.PHONY: stop_services +stop_services: docker_host_context_check ## Stop ADORe supporting services + cd tools/lichtblick && make stop + +.PHONY: build_vendor_libraries +build_vendor_libraries: docker_host_context_check ## Builds vendor libraries located in: ${VENDOR_PATH} + cd "${VENDOR_PATH}" && make build + +.PHONY: build_documentation +build_documentation: docker_host_context_check ## Builds ADORe Documentation in: ./documentation + echo todo + #cd documentation && make build + +.PHONY: build_ros_workspace +build_ros_workspace: ## Builds ROS2 workspace located in: ${ROS_NODE_PATH} + if [ -f /.dockerenv ]; then \ + cd ros2_workspace && make build; \ + else \ + make run cmd="cd ros2_workspace && make build"; \ + fi + +.PHONY: check_adore_binaries +check_adore_binaries: ## Checks for ADORe binaries + bash tools/check_adore_binaries.sh + +.PHONY: lint_nodes +lint_nodes: + @if [ -f /.dockerenv ]; then \ + clang-format -Werror -i -output-replacements-xml --checks=* -dry-run $(shell find ros2_workspace/src -type f \( -name "*.cpp" -or -name "*.hpp" -or -name "*.h" \)); \ + else \ + make run cmd="clang-format -Werror -i --checks=* -output-replacements-xml -dry-run $(shell find ros2_workspace/src -type f \( -name "*.cpp" -or -name "*.hpp" -or -name "*.h" \))"; \ + fi + +.PHONY: due_diligence_scan +due_diligence_scan: ## Scan repo for eclipse due diligence, checks if source files have the proper doc header. + python3 tools/eclipse_due_diligence_scanner.py --ignore tools/.eclipse_due_diligance_ignore + +.PHONY: due_diligence_fix +due_diligence_fix: ## Fix due diligence issues + python3 tools/eclipse_due_diligence_scanner.py --ignore tools/.eclipse_due_diligance_ignore --fix + +.PHONY: benchmark +benchmark: ## Run the ROS Topic benchmark script + if [ -f /.dockerenv ]; then \ + bash tools/ros_topic_benchmark.sh; \ + else \ + make run cmd="bash tools/ros_topic_benchmark.sh"; \ + fi + +.PHONY: package_adore_ros2_msgs +package_adore_ros2_msgs: ## Build & package adore_ros2_msgs + if [ -f /.dockerenv ]; then \ + cd ros2_workspace && make package_adore_ros2_msgs; \ + else \ + make run cmd="cd ros2_workspace && make package_adore_ros2_msgs"; \ + fi + +.PHONY: test +test: ## Run ADORe Unit Tests + bash .ci test + diff --git a/README.md b/README.md index 31936b79..47eea6dc 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # Automated Driving Open Research (ADORe) -![ADORe Logo](documentation/technical_reference_manual/img/adore_logo_white.png) +![ADORe Logo](documentation/landing_page/img/adore_logo_white.png) ## About ADORe - Eclipse ADORe is a modular software library and toolkit for decision making, planning, control and simulation of automated vehicles. It is developed by [The German Aerospace Center (DLR), Institute for Transportation Systems 🔗](https://www.dlr.de/ts/en). - ADORe is [ROS 2 🔗](https://ros.org) based @@ -12,89 +11,48 @@ automated vehicles. It is developed by [The German Aerospace Center (DLR), Insti - ADORe is developed with algorithms and data models applied in real automated driving system for motion planning and control - ADORe features mechanisms for safe interaction with other CAVs, infrastructure, traffic management, interactions with human-driven vehicles, bicyclists, pedestrians -ADORe is designed around both single agent automated driving (SAAD) and multi agent automated driving (MAAD), to allow both individual and cooperative driving behaviors. - -# Documentation -Please see full docs at [Github Pages](https://eclipse-adore.github.io/adore/) - -## Getting Started -In order to get started, it is advised to first check system requirements, follow the installation instruction and then -try out the demo scenarios. - -This guide will help you get your system set up and configured to run ADORe. - -1. First review the [System Requirements 🔗](documentation/technical_reference_manual/getting_started/system_requirements.md). +ADORe is designed around both single agent automated driving (SAAD) and multi agent automated driving (MAAD), to allow both individual and cooperative driving behaviors. ADORes features can be seperated into the following categories. -2. Next review the [Prerequisites 🔗](documentation/technical_reference_manual/getting_started/prerequisites.md) +![ADORe Overview](documentation/landing_page/img/adore_categories_overview.svg) -## Cloning the ADORe repository -> **ℹ️INFO:** -> By default this guide assumes you have ssh keys configured for GitHub your GitHub account. -> For help on configuring your ssh keys visit: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account +### SAAD +While driving automated for a single agent, for example on a vehicle like the DLR NGC, ADORe utilized the SAAD modules, viewing ADORe SAAD as a black box of inputs and outputs, get a representation as seen below. -```bash -git clone git@github.com:eclipse-adore/adore.git -cd adore -git submodule update --init --recursive -``` +![ADORe SAAD](documentation/landing_page/img/adore_saad.svg) -> **⚠️ WARNING:** Failing to update and recursively clone the submodules will result in build failures! +Diving deeper into the ROS2 node structure of ADORe SAAD leads to be the structure seen below. -> **ℹ️INFO:** If you would rather clone ADORe anonymously over https please review the [Anonymous Cloning 🔗](documentation/technical_reference_manual/system_and_development/anonymous_cloning.md) guide. +![ADORe SAAD Structure](documentation/landing_page/img/adore_saad_structure.svg) -## Building ADORe Developer Environment -> **⚠️ WARNING:** -> To use the ADORe developer environment you must have Docker installed. -To have the easiest entry you can [install just](https://github.com/casey/just) +### MAAD -and run: -```bash -just dev -``` +When using ADORe for control of multiple agent in a cooperative environment, ADORe MAAD can calculate trajectories and behaviors for multiple vehicles at once. Viewing ADORe MAAD as a black box of inputs and outputs, it can been show as seen here. -Alternatively, simple call +![ADORe MAAD](documentation/landing_page/img/adore_maad.svg) -```bash -.docker/scripts/run_dev.sh -``` - -This will create and the developer environment where you can build all relevant packages with - -```bash -just build -``` - -The full command list is available with - -```bash -just help -``` - -> **⚠️ WARNING:** -> Building ADORe **will** fail until all submodules have been properly initialized. -> If cloning or repository initialization fails refer to the -> [troubleshooting](documentation/technical_reference_manual/problems_and_solutions.md) guide before proceeding. -> Do not proceed with building ADORe until `git submodule update --init --receive` -> finishes without error. +## Documentation +In order to get started, it is advised to first check system requirements, follow the installation instruction and then +try out the demo scenarios. -Next proceed to [Running Your First Scenario 🔗](documentation/technical_reference_manual/getting_started/running_your_first_scenario.md) +- [Github Pages](https://eclipse.github.io/eclipse-adore/adore) +- [Getting started/Quick Start](documentation/technical_reference_manual/getting_started/getting_started.md) +- [Technical Reference Manual](https://eclipse-adore.github.io/adore/mkdocs/about_adore/index.html) -## Using in an existing ROS2 project -The ADORe packages adore_(libraries/ros2_conversions/ros2_msgs/ros2_nodes/scenarios) can all be used directly in your existing ros2 project by pasting or symlining them into you ros2/colcon workspace. +## ADORe In Action +Here you can see one of our automated test vehicles being operated by ADORe: +[![ADORe example video 🔗](https://github.com/DLR-TS/adore_support/blob/master/vivre_flythrough_screenshot2.png?raw=true)](https://youtu.be/tlhPDtr4yxg) -# ADORe In Action +[![YouTube Video](https://img.youtube.com/vi/bRZc1iFohCU/0.jpg)](https://www.youtube.com/watch?v=bRZc1iFohCU) -### ADORe Road Driving -[![ADORe Along Road Driving Video](documentation/technical_reference_manual/img/driving_road_video_image.png)](https://www.youtube.com/watch?v=bRZc1iFohCU) +[![YouTube Video](https://img.youtube.com/vi/MANc_xQ_8sI/0.jpg)](https://www.youtube.com/watch?v=MANc_xQ_8sI) -### ADORe Remote Operations -[![ADORe Remote Operations Video](documentation/technical_reference_manual/img/remote_operations_video_image.png)](https://www.youtube.com/watch?v=Aqvd82A40S4) +[![YouTube Video](https://img.youtube.com/vi/Aqvd82A40S4/0.jpg)](https://www.youtube.com/watch?v=Aqvd82A40S4) -### Simulated Multi-Agent Driving / planning -[![ADORe Simulated MAAD Video](documentation/technical_reference_manual/img/simulated_maad_video_image.png)](https://www.youtube.com/watch?v=IYbv7Y2nt-k) +[![YouTube Video](https://img.youtube.com/vi/IYbv7Y2nt-k/0.jpg)](https://www.youtube.com/watch?v=IYbv7Y2nt-k) -### ADORe at intelligent intersection -[![YouTube Video](documentation/technical_reference_manual/img/adore_intelligent_intersection_video_image.png)](https://www.youtube.com/watch?v=kDOtkMxxtyM) +# Example application +The following video shows an automated vehicle controlled by ADORe in an urban setting in Braunschweig, Germany: +[![ADORe example video](https://github.com/DLR-TS/adore_support/blob/master/adore_vivre_video_preview_20221027.png?raw=true)](https://youtu.be/tlhPDtr4yxg) diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md index dfc0bcd0..43b4ef92 100644 --- a/THIRD-PARTY.md +++ b/THIRD-PARTY.md @@ -14,9 +14,8 @@ Paths indicate where the content lives in this repository or how it is consumed | OSQP | Apache License 2.0 | `vendor/osqp` | https://osqp.org/ | | OSQP-Eigen | BSD 3-Clause License | `vendor/osqp_eigen` | https://github.com/robotology/osqp-eigen | | multi_agent_solver | Apache License 2.0 | `vendor/multi_agent_solver` | https://https://github.com/markomiz/multi_agent_solver | -| websocketpp | BSD 3-Clause License | `tools/websocketpp/LICENSE` | https://github.com/zaphoyd/websocketpp | -| adore_model_checker| Apache License 2.0 | `tools/adore_model_checker` | https://github.com/DLR-TS/adore_model_checker | -| ros2_observer | Apache License 2.0 | `tools/ros2_observer` | https://github.com/DLR-TS/ros2_observer | +| adore_model_checker| Apache License 2.0 | `vendor/adore_model_checker` | https://github.com/DLR-TS/adore_model_checker | +| ros2_observer | Apache License 2.0 | `vendor/ros2_observer` | https://github.com/DLR-TS/ros2_observer | | ROS 2 | Apache License 2.0 | System dependency | https://docs.ros.org/ | | MkDocs & Material | BSD 2-Clause / MIT | `documentation/` (documentation build system) | https://www.mkdocs.org/ ; https://squidfunk.github.io/mkdocs-material/ | | spline.h | GNU General Public License v2 | `libraries/lib/adore_math/include/spline.h` | https://kluge.in-chemnitz.de/opensource/spline/spline.h | diff --git a/adore.env b/adore.env new file mode 100644 index 00000000..ec9de451 --- /dev/null +++ b/adore.env @@ -0,0 +1,188 @@ +# ADORe Environment Variables + +## This file provides the ability of modifying the behavior of the ADORe CLI. +## Review the environmental variables and their corresponding documentation +## for a complete explanation of all behavioral changes to the ADORe CLI. + +## All variables set in this file will be part of the ADORe CLI environmenet + + +set -a + +# General Configuration +# ===================== +# MAX_COMMIT_FILE_SIZE_kB: +# - Maximum allowed file size (in kilobytes) for the pre-commit hook. +# +# SUBMODULES_PATH: +# - Path to project submodules. Defaults to the current working directory. +# +# ROS_HOME: +# - Path to the ROS home directory for logging and runtime files. +# ----------------------------------------------------------------------------- +MAX_COMMIT_FILE_SIZE_kB=5000 +SUBMODULES_PATH=$(pwd) +LOG_DIRECTORY=${SOURCE_DIRECTORY}/.log +ROS_HOME=${SOURCE_DIRECTORY}/.log/.ros +ROS_DOMAIN_ID=0 +#ROS_AUTOMATIC_DISCOVERY_RANGE=localhost + +# The ADORe CLI includes x11 integration to run graphical applications. It will +# auto-detect if a display is connected otherwise default to a virtual xvfb +# display. +# VIRTUAL_DISPLAY: Disable auto-detection and force virtual display creation +# - Set to "true" to always create virtual display on :99 (bypasses auto-detection) +# - Set to "false" or leave unset to auto-detect physical displays +# - Default: false (auto-detect physical displays, create virtual only if none found) +VIRTUAL_DISPLAY=false + +# Zenoh Configuration +# =================== +# The ADORe CLI runs a native zenoh router and optionally the zenoh_message_bridge +# node as host processes. Logs are written to ${LOG_DIRECTORY}/zenoh/. +# +# ZENOH_ROUTER_ENABLE: Start a local zenoh router on the host at CLI start. +# - Set to "true" to start rmw_zenohd alongside the CLI container. +# - Set to "false" or leave unset to skip the router. +# - Default: false +# - Note: Required when RMW_IMPLEMENTATION=rmw_zenoh_cpp or ZENOH_BRIDGE_ENABLE=true. +ZENOH_ROUTER_ENABLE=true + +# ZENOH_ROUTER_CONFIG: Path to the zenoh router config file. +# - Defaults to the zenoh_bridge_config.json5 in the adore_cli directory. +# - Default: ${SOURCE_DIRECTORY}/adore_cli/zenoh_bridge_config.json5 +ZENOH_ROUTER_CONFIG=${SOURCE_DIRECTORY}/adore_cli/zenoh_router_config.json5 + +# ZENOH_BRIDGE_ENABLE: Start the zenoh_message_bridge ROS node on the host. +# - Bridges specific FastDDS topics to/from zenoh as defined in bridge_config.yaml. +# - Requires ZENOH_ROUTER_ENABLE=true or an external router to be reachable. +# - Set to "true" to launch the bridge node alongside the CLI container. +# - Set to "false" or leave unset to disable. +# - Default: false +ZENOH_BRIDGE_ENABLE=true + +# ZENOH_BRIDGE_ROUTER: Zenoh router endpoint the bridge node connects to. +# - Default: tcp/localhost:7447 +# This config parameter overrides the ZENOH_ROUTER_CONFIG +ZENOH_BRIDGE_ROUTER=tcp/localhost:7447 + +# RMW_IMPLEMENTATION: ROS2 middleware to use. +# - rmw_fastrtps_cpp: FastDDS (default, no router needed) +# - rmw_cyclonedds_cpp: CycloneDDS (no router needed) +# - rmw_zenoh_cpp: Zenoh (requires ZENOH_ROUTER_ENABLE=true) +RMW_IMPLEMENTATION=rmw_fastrtps_cpp + +# Build Configuration +# =================== +# FORCE_SINGLE_CORE_BUILD: +# adore libraries in `libraries` and ros nodes in `ros2_workspace` are built in +# parallel using colcon and -j$(nproc - 1). This can crash systems that do not +# meet the minimum build specs for ADORe. Disable parallel builds with this +# environmental variable. +# - Set to "true" to force sequential builds regardless of available RAM. +# - Set to "false" to use automatic RAM-based parallel build detection. +# - Default: false +# ----------------------------------------------------------------------------- +FORCE_SINGLE_CORE_BUILD=false + +# ROS Topic Benchmark Configuration +# =================== +# RUN the topic benchmark with `make benchmark` +# Scenario file to launch for benchmarking (located in adore_scenarios/simulation_scenarios/) +export ROS_BENCHMARK_SCENARIO="simulation_test.launch.py" + +# Minimum acceptable message rate in Hz - benchmark fails if average rate is below this value +export ROS_BENCHMARK_MIN_RATE=10 + +# Maximum acceptable jitter in seconds (difference between max and min message intervals) +# Benchmark fails if jitter exceeds this threshold +export ROS_BENCHMARK_MAX_JITTER=0.04 + +# Maximum acceptable standard deviation in seconds for message timing consistency +# Benchmark fails if standard deviation exceeds this threshold +export ROS_BENCHMARK_MAX_STD=0.014 + + +# ADORE API Configuration +# ===================== +# ENABLE_ADORE_API: +# - Set to "true" to enable the ADORE API (default if unset or empty). +# - Set to "false" to disable the ADORE API. +# +# ADORE_API_PORT: +# - The port on which the ADORE API server will listen. +# ----------------------------------------------------------------------------- +ENABLE_ADORE_API=true +ADORE_API_PORT=8888 + +# SUMO Bridge Configuration +# ========================= +# SUMO_BRIDGE_ENABLE: Start the sumo_bridge ROS 2 node on the host. +# - Set to "true" to launch the bridge node alongside the CLI container. +# - Set to "false" or leave unset to disable. +# - Default: false +SUMO_BRIDGE_ENABLE=false + +# SUMO_BRIDGE_CONFIG_FILE: SUMO scenario config filename. +# - Filename only, resolved relative to SUMO_CONFIG_DIRECTORY. +# - Default: demo_sumo_bridge.sumocfg +SUMO_CONFIG_FILE="${SUMO_BRIDGE_CONFIG_FILE:-demo_sumo_bridge.sumocfg}" + +# SUMO_CONFIG_DIRECTORY: Path relative to SOURCE_DIRECTORY containing SUMO config files. +# - Default: ros2_workspace/src/adore_interfaces/sumo_bridge/sumo_configs +SUMO_CONFIG_DIRECTORY="ros2_workspace/src/adore_interfaces/sumo_bridge/sumo_configs" + +# SUMO_HOME: Path to the SUMO installation directory. +# - Default: /usr/share/sumo +SUMO_HOME="/usr/share/sumo" + +# Rsyslog Configuration +# ===================== +# The ADORe CLI includes rsyslog server. The rsyslog output directory for log +# files is: `.log/rsyslog`. The ADORe CLI rsyslog provides a rsyslog server +# which can be configured with the 'RSYSLOG_PORT' and 'RSYSLOG_PROTOCOL' +# environmental variables. Rsyslog can also be configured to forward messages +# with the 'RSYSLOG_FORWARD_HOST', 'RSYSLOG_FORWARD_PORT', and +# 'RSYSLOG_FORWARD_PROTOCOL' +# +# Rsyslog messages with tags "ros2" and "telemetry" will be stored and forwarded +# example(from within the ADORe CLI run): logger --tag ros2 "Hello, World!" + +# RSYSLOG_BANNER: Show rsyslog configuration banner on start/attach +# - Set to "false" to suppress the banner +# - Default: true +RSYSLOG_BANNER=false + + +# RSYSLOG_PORT: Port for local rsyslog server to listen on +# - Set to a port number (e.g., 514) to enable syslog reception +# - Leave empty or unset to disable local syslog server entirely +# - Default: unset (syslog server disabled) +RSYSLOG_PORT=514 + +# RSYSLOG_PROTOCOL: Protocol for local rsyslog server input +# - Options: "udp" or "tcp" +# - Determines whether to use UDP or TCP for incoming syslog messages +# - Only used when RSYSLOG_PORT is set +# - Default: udp +RSYSLOG_PROTOCOL=udp + +# RSYSLOG_FORWARD_HOST: Remote syslog server to forward logs to +# - Set to hostname or IP address to enable log forwarding +# - Leave empty or unset to disable forwarding +# - Default: unset (no forwarding) +RSYSLOG_FORWARD_HOST=10.34.192.60 + +# RSYSLOG_FORWARD_PORT: Port on remote syslog server for forwarding +# - Port number to use when forwarding to RSYSLOG_FORWARD_HOST +# - Only used when RSYSLOG_FORWARD_HOST is set +# - Default: 514 +RSYSLOG_FORWARD_PORT=2514 + +# RSYSLOG_FORWARD_PROTOCOL: Protocol for log forwarding +# - Options: "udp" or "tcp" +# - Only used when RSYSLOG_FORWARD_HOST is set +# - Default: udp +RSYSLOG_FORWARD_PROTOCOL=udp + +set +a diff --git a/adore_cli b/adore_cli new file mode 160000 index 00000000..0eb025a5 --- /dev/null +++ b/adore_cli @@ -0,0 +1 @@ +Subproject commit 0eb025a5c0033163be6b7ed5d9c1b3c748de6618 diff --git a/adore_cli.env b/adore_cli.env new file mode 120000 index 00000000..1f5fe065 --- /dev/null +++ b/adore_cli.env @@ -0,0 +1 @@ +adore.env \ No newline at end of file diff --git a/adore_embedded/.dockerignore b/adore_embedded/.dockerignore new file mode 100644 index 00000000..3290e419 --- /dev/null +++ b/adore_embedded/.dockerignore @@ -0,0 +1,3 @@ +build/ +context/vendor/*.deb.tmp +Dockerfile.patched diff --git a/adore_embedded/.gitignore b/adore_embedded/.gitignore new file mode 100644 index 00000000..ee5c69d7 --- /dev/null +++ b/adore_embedded/.gitignore @@ -0,0 +1 @@ +Dockerfile.patched diff --git a/adore_embedded/Dockerfile b/adore_embedded/Dockerfile new file mode 100644 index 00000000..b37657a2 --- /dev/null +++ b/adore_embedded/Dockerfile @@ -0,0 +1,80 @@ +# syntax=docker/dockerfile:1 +ARG ROS_DISTRO=jazzy +ARG OS_CODE_NAME=noble + +FROM ros:${ROS_DISTRO}-ros-core-${OS_CODE_NAME} AS base + +ARG ROS_DISTRO=jazzy +ARG ARCH +ARG SHORT_HASH +ARG REQUIREMENTS_HASH + +ENV ROS_DISTRO=${ROS_DISTRO} + +LABEL org.adore.image-type="embedded" \ + org.adore.arch="${ARCH}" \ + org.adore.commit="${SHORT_HASH}" \ + org.adore.requirements-hash="${REQUIREMENTS_HASH}" + +RUN rm -f /etc/apt/apt.conf.d/docker-clean && \ + apt-get update && \ + apt-get upgrade -y --no-install-recommends + +RUN apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + gettext-base \ + git \ + ccache \ + make \ + python3-pip \ + python3-colcon-common-extensions + +COPY context /tmp/context + +RUN bash /tmp/context/install_requirements.sh && \ + bash /tmp/context/install_packages.sh && \ + rm -rf /tmp/context + +RUN git clone --recursive https://github.com/osqp/osqp.git /tmp/osqp && \ + cmake -S /tmp/osqp -B /tmp/osqp/build -G "Unix Makefiles" && \ + cmake --build /tmp/osqp/build -j$(nproc) && \ + cmake --install /tmp/osqp/build --prefix /usr/local && \ + ldconfig && \ + rm -rf /tmp/osqp + +RUN echo "/usr/local/lib" >> /etc/ld.so.conf.d/local.conf && ldconfig + +# ── Workspace build stage ────────────────────────────────────────────────────── +# ros2_workspace is supplied as an external BuildKit build context: +# docker build --build-context ros2_workspace=../ros2_workspace ... +FROM base AS workspace-builder + +COPY --from=ros2_workspace src /ros2_workspace_dist/src +COPY --from=ros2_workspace Makefile /ros2_workspace_dist/Makefile +COPY --from=ros2_workspace colcon_defaults.yaml.template /ros2_workspace_dist/colcon_defaults.yaml + +RUN --mount=type=cache,target=/root/.ccache,sharing=locked \ + . /opt/ros/${ROS_DISTRO}/setup.sh && \ + cd /ros2_workspace_dist && \ + make clean build && \ + rm -rf /ros2_workspace_dist/log + +# ── Runtime image ────────────────────────────────────────────────────────────── +FROM base AS runtime + +RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> /etc/bash.bashrc && \ + echo "source /ros2_workspace_dist/install/setup.bash" >> /etc/bash.bashrc && \ + echo "source /ros2_workspace/install/setup.bash 2>/dev/null || true" >> /etc/bash.bashrc + +RUN mkdir -p /home/user && chmod 1777 /home/user +ENV HOME=/home/user + +# Pre-built workspace baked into the image; volume-mount /ros2_workspace at +# runtime to override with a live workspace for development. +COPY --from=workspace-builder /ros2_workspace_dist /ros2_workspace_dist +# adore_scenarios supplied via: --build-context adore_scenarios=../adore_scenarios +COPY --from=adore_scenarios . /ros2_workspace_dist/adore_scenarios +COPY context /ros2_workspace_dist/context + +WORKDIR /ros2_workspace_dist diff --git a/adore_embedded/Makefile b/adore_embedded/Makefile new file mode 100644 index 00000000..d13ecea2 --- /dev/null +++ b/adore_embedded/Makefile @@ -0,0 +1,331 @@ +SHELL := /bin/bash +MAKEFLAGS += --warn-undefined-variables --no-builtin-rules +.NOTPARALLEL: +.DEFAULT_GOAL := build + +ROOT_DIR := $(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") +HOST_UID := $(shell id -u) +HOST_GID := $(shell id -g) + +ifndef _GATHERING +$(shell $(MAKE) --no-print-directory _gather _GATHERING=1 >/dev/null 2>&1) +endif + +DOCKER_BUILDKIT ?= 1 +ROS_DISTRO ?= jazzy +OS_CODE_NAME ?= noble +ARCH ?= $(shell uname -m) +DOCKER_PLATFORM ?= linux/$(ARCH) + +VENDOR_PATH ?= $(ROOT_DIR)/../vendor +ROS2_WORKSPACE ?= $(ROOT_DIR)/../ros2_workspace +ROS2_SRC ?= $(ROS2_WORKSPACE)/src + +SHORT_HASH := $(shell git -C "$(ROOT_DIR)" rev-parse --short HEAD 2>/dev/null || echo "0000000") +REQUIREMENTS_HASH := $(shell \ + { find $(ROOT_DIR) -maxdepth 2 -type f \( -name "*.system" -o -name "*.pip3" -o -name "*.ppa" \) \ + ! -path "*/context/*" 2>/dev/null; \ + find $(ROS2_SRC) -type f \( -name "*.system" -o -name "*.pip3" -o -name "*.ppa" \) \ + 2>/dev/null; } \ + | LC_ALL=C sort | xargs -r grep -hv '^\s*#' | grep -v '^\s*$$' \ + | LC_ALL=C sort -u | sha256sum | cut -c1-7 || echo "0000000") + +IMAGE_NAME := adore_embedded +IMAGE_TAG := $(ARCH)_$(SHORT_HASH)_RH$(REQUIREMENTS_HASH) +IMAGE := $(IMAGE_NAME):$(IMAGE_TAG) +CONTAINER_NAME := $(IMAGE_NAME)_$(IMAGE_TAG) + +REPO := $(shell git -C "$(ROOT_DIR)/.." config --get remote.origin.url 2>/dev/null \ + | sed -e 's|.*github.com[:/]||' -e 's|\.git$$||' | tr '[:upper:]' '[:lower:]') +ifeq ($(REPO),) + REPO := eclipse-adore/adore +endif +REGISTRY := ghcr.io/$(REPO) +REGISTRY_IMAGE := $(REGISTRY)/$(IMAGE) + +PATCHES := $(sort $(wildcard $(ROOT_DIR)/patches/*.patch)) +DOCKERFILE := $(ROOT_DIR)/Dockerfile +BUILD_DOCKERFILE := $(if $(PATCHES),$(DOCKERFILE).patched,$(DOCKERFILE)) + +BUILD_DIR := $(ROOT_DIR)/build/$(IMAGE_TAG) +PACKAGES_DIR := $(ROOT_DIR)/packages +CONTEXT_DIR := $(ROOT_DIR)/context +IMAGE_ARCHIVE_NAME := $(IMAGE_NAME)_$(IMAGE_TAG).tar +IMAGE_ARCHIVE := $(BUILD_DIR)/$(IMAGE_ARCHIVE_NAME) + +LICHTBLICK_DIR := $(ROOT_DIR)/../tools/lichtblick +LICHTBLICK_IMAGE := $(shell cd $(LICHTBLICK_DIR) && $(MAKE) --no-print-directory lichtblick_image 2>/dev/null) +LICHTBLICK_ARCHIVE_NAME := $(subst :,_,$(LICHTBLICK_IMAGE)).tar.gz + +.PHONY: help +help: ## Show this help + @printf "\n\033[1mTargets:\033[0m\n" + @grep -E '^[a-zA-Z][a-zA-Z0-9_-]*:.*##' $(MAKEFILE_LIST) \ + | awk 'BEGIN {FS = ":.*##"}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' + @printf "\n" + +.PHONY: patch +patch: +ifneq ($(PATCHES),) + @cp $(DOCKERFILE) $(DOCKERFILE).patched + @for p in $(PATCHES); do \ + echo "Applying patch: $$(basename $$p)"; \ + patch -p1 $(DOCKERFILE).patched < "$$p" || exit 1; \ + done +endif + +.PHONY: _build +_build: patch _gather ## Build the image, compile the ROS2 workspace via BuildKit, and save to build// + @echo "=== Building $(IMAGE) ===" + cd ${VENDOR_PATH} && make build + cd $(LICHTBLICK_DIR) && make build + @echo "=== Saving lichtblick image → $(BUILD_DIR)/lichtblick/$(LICHTBLICK_ARCHIVE_NAME) ===" + @mkdir -p $(BUILD_DIR)/lichtblick + docker save $(LICHTBLICK_IMAGE) | gzip > $(BUILD_DIR)/lichtblick/$(LICHTBLICK_ARCHIVE_NAME) + docker build \ + --platform $(DOCKER_PLATFORM) \ + --build-arg ROS_DISTRO=$(ROS_DISTRO) \ + --build-arg OS_CODE_NAME=$(OS_CODE_NAME) \ + --build-arg ARCH=$(ARCH) \ + --build-arg SHORT_HASH=$(SHORT_HASH) \ + --build-arg REQUIREMENTS_HASH=$(REQUIREMENTS_HASH) \ + --build-context ros2_workspace=$(ROS2_WORKSPACE) \ + --build-context adore_scenarios=$(ROOT_DIR)/../adore_scenarios \ + --target runtime \ + -t $(IMAGE) \ + -f $(BUILD_DOCKERFILE) \ + $(ROOT_DIR) + @mkdir -p $(BUILD_DIR) + @echo "=== Extracting built workspace from image ===" + @cid=$$(docker create --platform $(DOCKER_PLATFORM) $(IMAGE) /bin/true); \ + docker cp "$$cid":/ros2_workspace_dist/. $(BUILD_DIR)/ros2_workspace_dist/; \ + docker rm "$$cid" + @cp -r "$(CONTEXT_DIR)" $(BUILD_DIR)/ros2_workspace_dist/context + @echo "=== Saving $(IMAGE) → $(IMAGE_ARCHIVE).gz ===" + docker save $(IMAGE) | gzip > $(IMAGE_ARCHIVE).gz + @$(MAKE) --no-print-directory _write_scripts \ + _BUILD_DIR=$(BUILD_DIR) \ + _IMAGE=$(IMAGE) \ + _IMAGE_TAG=$(IMAGE_TAG) \ + _IMAGE_ARCHIVE_NAME=$(IMAGE_ARCHIVE_NAME) \ + _CONTAINER_NAME=$(CONTAINER_NAME) \ + _LICHTBLICK_IMAGE=$(LICHTBLICK_IMAGE) \ + _LICHTBLICK_ARCHIVE_NAME=$(LICHTBLICK_ARCHIVE_NAME) + @echo "=== Done: $(BUILD_DIR) ===" + +.PHONY: pull +pull: ## Pull the image from the registry; tag it locally + @echo "=== Pulling $(REGISTRY_IMAGE) ===" + docker pull "$(REGISTRY_IMAGE)" + docker tag "$(REGISTRY_IMAGE)" "$(IMAGE)" + @echo "=== Pulled and tagged as $(IMAGE) ===" + +.PHONY: build +build: _gather ## Pull from registry if available, otherwise build from source + @if docker image inspect "$(IMAGE)" >/dev/null 2>&1 && [ -d "$(BUILD_DIR)/ros2_workspace_dist" ]; then \ + echo "✓ Image already present: $(IMAGE)"; \ + $(MAKE) --no-print-directory _write_scripts \ + _BUILD_DIR=$(BUILD_DIR) \ + _IMAGE=$(IMAGE) \ + _IMAGE_TAG=$(IMAGE_TAG) \ + _IMAGE_ARCHIVE_NAME=$(IMAGE_ARCHIVE_NAME) \ + _CONTAINER_NAME=$(CONTAINER_NAME) \ + _LICHTBLICK_IMAGE=$(LICHTBLICK_IMAGE) \ + _LICHTBLICK_ARCHIVE_NAME=$(LICHTBLICK_ARCHIVE_NAME); \ + elif docker image inspect "$(IMAGE)" >/dev/null 2>&1; then \ + echo "Image present but build dir missing, repopulating..."; \ + $(MAKE) --no-print-directory _build; \ + elif docker pull "$(REGISTRY_IMAGE)" 2>/dev/null; then \ + echo "✓ Pulled from registry: $(REGISTRY_IMAGE)"; \ + docker tag "$(REGISTRY_IMAGE)" "$(IMAGE)"; \ + $(MAKE) --no-print-directory _build; \ + else \ + echo "Registry pull failed, building from source..."; \ + $(MAKE) --no-print-directory _build; \ + fi + +.PHONY: push +push: ## Push the local image to the registry + @if ! docker image inspect "$(IMAGE)" >/dev/null 2>&1; then \ + echo "ERROR: image $(IMAGE) not found. Run 'make build' first."; exit 1; \ + fi + @echo "=== Pushing $(IMAGE) → $(REGISTRY_IMAGE) ===" + docker tag "$(IMAGE)" "$(REGISTRY_IMAGE)" + docker push "$(REGISTRY_IMAGE)" + @echo "=== Pushed: $(REGISTRY_IMAGE) ===" + +.PHONY: start +start: _ensure_loaded ## Start the container detached with the live workspace mounted + @if docker ps --format "{{.Names}}" | grep -q "^$(CONTAINER_NAME)$$"; then \ + echo "✓ Already running: $(CONTAINER_NAME)"; \ + else \ + docker run --detach \ + --name $(CONTAINER_NAME) \ + --platform $(DOCKER_PLATFORM) \ + --network host \ + --user "$(HOST_UID):$(HOST_GID)" \ + --env-file "$(ROOT_DIR)/container.env" \ + -e ROS_DISTRO=$(ROS_DISTRO) \ + -v "$(ROS2_WORKSPACE):/ros2_workspace" \ + $(IMAGE) \ + sleep infinity; \ + echo "✓ Started: $(CONTAINER_NAME)"; \ + fi + +.PHONY: stop +stop: ## Stop and remove the container + @docker stop $(CONTAINER_NAME) 2>/dev/null || true + @docker rm -f $(CONTAINER_NAME) 2>/dev/null || true + @echo "✓ Stopped: $(CONTAINER_NAME)" + +.PHONY: package +package: ## Save the current build output as a tar.gz in packages/ + @if [ ! -d "$(BUILD_DIR)" ]; then \ + echo "ERROR: No build output at $(BUILD_DIR). Run 'make build' first."; exit 1; \ + fi + @mkdir -p $(PACKAGES_DIR) + @PKG=$(PACKAGES_DIR)/$(IMAGE_NAME)_$(IMAGE_TAG).tar.gz; \ + echo "=== Packaging $(BUILD_DIR) → $$PKG ==="; \ + tar -czf "$$PKG" --transform "s|^$(IMAGE_TAG)|$(IMAGE_NAME)_$(IMAGE_TAG)|" -C "$(ROOT_DIR)/build" "$(IMAGE_TAG)"; \ + echo "=== Saved: $$PKG ===" + +.PHONY: bundle +BUNDLE_NAME := $(IMAGE_NAME)_$(IMAGE_TAG)_bundle +BUNDLE_DIR := $(PACKAGES_DIR)/$(BUNDLE_NAME) +bundle: ## Create a self-contained Docker-free rootfs bundle in packages/ + @if ! docker image inspect $(IMAGE) >/dev/null 2>&1; then \ + echo "ERROR: Image $(IMAGE) not found. Run 'make build' first."; exit 1; \ + fi + @if [ ! -d "$(BUILD_DIR)/ros2_workspace_dist" ]; then \ + echo "ERROR: No workspace at $(BUILD_DIR)/ros2_workspace_dist. Run 'make build' first."; exit 1; \ + fi + @mkdir -p $(PACKAGES_DIR) + @echo "=== Creating bundle → $(BUNDLE_DIR).tar.gz ===" + @rm -rf $(BUNDLE_DIR) && mkdir -p $(BUNDLE_DIR)/rootfs + @echo " Exporting rootfs (this may take a while)..." + @cid=$$(docker create --platform $(DOCKER_PLATFORM) $(IMAGE) /bin/true); \ + docker export "$$cid" | tar -x -C $(BUNDLE_DIR)/rootfs; \ + docker rm "$$cid" + @cp -r $(BUILD_DIR)/ros2_workspace_dist $(BUNDLE_DIR)/ros2_workspace_dist + @cp $(ROOT_DIR)/container.env $(BUNDLE_DIR)/container.env + @printf 'ROS_DISTRO=%s\nDOCKER_PLATFORM=%s\n' "$(ROS_DISTRO)" "$(DOCKER_PLATFORM)" \ + > $(BUNDLE_DIR)/bundle.env + @printf 'LICHTBLICK_IMAGE=%s\nLICHTBLICK_ARCHIVE_NAME=%s\n' \ + "$(LICHTBLICK_IMAGE)" "$(LICHTBLICK_ARCHIVE_NAME)" \ + > $(BUNDLE_DIR)/lichtblick.env + @cp $(ROOT_DIR)/scripts/bundle_run.sh $(BUNDLE_DIR)/start.sh && chmod +x $(BUNDLE_DIR)/start.sh + @cp $(ROOT_DIR)/scripts/bundle_stop.sh $(BUNDLE_DIR)/stop.sh && chmod +x $(BUNDLE_DIR)/stop.sh + @cp $(ROOT_DIR)/scripts/bundle_shell_dev.sh $(BUNDLE_DIR)/shell_dev.sh && chmod +x $(BUNDLE_DIR)/shell_dev.sh + @cp $(ROOT_DIR)/scripts/bundle_shell_dist.sh $(BUNDLE_DIR)/shell_dist.sh && chmod +x $(BUNDLE_DIR)/shell_dist.sh + @cp $(ROOT_DIR)/scripts/bundle_start_lichtblick.sh $(BUNDLE_DIR)/start_lichtblick.sh && chmod +x $(BUNDLE_DIR)/start_lichtblick.sh + @cp $(ROOT_DIR)/scripts/bundle_stop_lichtblick.sh $(BUNDLE_DIR)/stop_lichtblick.sh && chmod +x $(BUNDLE_DIR)/stop_lichtblick.sh + @cp $(ROOT_DIR)/scripts/bundle_inner.sh $(BUNDLE_DIR)/.bundle_inner.sh && chmod +x $(BUNDLE_DIR)/.bundle_inner.sh + @echo " Saving Lichtblick image → $(BUNDLE_DIR)/lichtblick/$(LICHTBLICK_ARCHIVE_NAME)" + @mkdir -p $(BUNDLE_DIR)/lichtblick + @docker save $(LICHTBLICK_IMAGE) | gzip > $(BUNDLE_DIR)/lichtblick/$(LICHTBLICK_ARCHIVE_NAME) + @cp $(ROOT_DIR)/README.release.md $(BUNDLE_DIR)/README.md + @echo " Compressing..." + @tar -czf $(BUNDLE_DIR).tar.gz -C $(PACKAGES_DIR) $(BUNDLE_NAME) + @rm -rf $(BUNDLE_DIR) + @echo "=== Bundle: $(BUNDLE_DIR).tar.gz ===" + +.PHONY: shell_debug +shell_debug: start ## Attach an interactive shell to the running container (dev workspace) as root + docker exec -u root -it --workdir /ros2_workspace $(CONTAINER_NAME) /bin/bash + +.PHONY: shell_dev +shell_dev: start ## Attach an interactive shell to the running container (dev workspace) + docker exec -it --workdir /ros2_workspace $(CONTAINER_NAME) /bin/bash + +.PHONY: shell_dist +shell_dist: start ## Attach an interactive shell scoped to the dist scenarios workspace + docker exec -it \ + --workdir /ros2_workspace_dist/adore_scenarios/simulation_scenarios \ + $(CONTAINER_NAME) \ + /bin/bash --init-file /ros2_workspace_dist/install/setup.bash + +.PHONY: clean +clean: ## Remove image, build output, and build context + docker rmi $(IMAGE) 2>/dev/null || true + rm -rf $(ROOT_DIR)/build $(CONTEXT_DIR) + @rm -f $(DOCKERFILE).patched + +.PHONY: _ensure_loaded +_ensure_loaded: + @if ! docker image inspect $(IMAGE) >/dev/null 2>&1; then \ + if [ -f "$(IMAGE_ARCHIVE)" ]; then \ + echo "Loading $(IMAGE_ARCHIVE)..."; \ + docker load -i "$(IMAGE_ARCHIVE)"; \ + else \ + echo "ERROR: image $(IMAGE) not found. Run 'make build' first."; exit 1; \ + fi \ + fi + +.PHONY: _write_scripts +_write_scripts: + @printf 'IMAGE=%s\nIMAGE_TAG=%s\nIMAGE_ARCHIVE_NAME=%s\nCONTAINER_NAME=%s\nDOCKER_PLATFORM=%s\nROS_DISTRO=%s\n' \ + "$(_IMAGE)" "$(_IMAGE_TAG)" "$(_IMAGE_ARCHIVE_NAME)" "$(_CONTAINER_NAME)" \ + "$(DOCKER_PLATFORM)" "$(ROS_DISTRO)" \ + > $(_BUILD_DIR)/adore.env + @cp $(ROOT_DIR)/scripts/load.sh $(_BUILD_DIR)/load.sh && chmod +x $(_BUILD_DIR)/load.sh + @cp $(ROOT_DIR)/scripts/start.sh $(_BUILD_DIR)/start.sh && chmod +x $(_BUILD_DIR)/start.sh + @cp $(ROOT_DIR)/scripts/shell_dev.sh $(_BUILD_DIR)/shell_dev.sh && chmod +x $(_BUILD_DIR)/shell_dev.sh + @cp $(ROOT_DIR)/scripts/shell_dist.sh $(_BUILD_DIR)/shell_dist.sh && chmod +x $(_BUILD_DIR)/shell_dist.sh + @cp $(ROOT_DIR)/scripts/stop.sh $(_BUILD_DIR)/stop.sh && chmod +x $(_BUILD_DIR)/stop.sh + @cp $(ROOT_DIR)/scripts/build_ros_workspace.sh $(_BUILD_DIR)/build_ros_workspace.sh && chmod +x $(_BUILD_DIR)/build_ros_workspace.sh + @cp $(ROOT_DIR)/scripts/bundle_run.sh $(_BUILD_DIR)/bundle_run.sh && chmod +x $(_BUILD_DIR)/bundle_run.sh + @cp $(ROOT_DIR)/scripts/bundle_shell_dev.sh $(_BUILD_DIR)/bundle_shell_dev.sh && chmod +x $(_BUILD_DIR)/bundle_shell_dev.sh + @cp $(ROOT_DIR)/scripts/bundle_shell_dist.sh $(_BUILD_DIR)/bundle_shell_dist.sh && chmod +x $(_BUILD_DIR)/bundle_shell_dist.sh + @cp $(ROOT_DIR)/scripts/bundle_inner.sh $(_BUILD_DIR)/.bundle_inner.sh && chmod +x $(_BUILD_DIR)/.bundle_inner.sh + @cp $(ROOT_DIR)/scripts/start_lichtblick.sh $(_BUILD_DIR)/start_lichtblick.sh && chmod +x $(_BUILD_DIR)/start_lichtblick.sh + @cp $(ROOT_DIR)/scripts/stop_lichtblick.sh $(_BUILD_DIR)/stop_lichtblick.sh && chmod +x $(_BUILD_DIR)/stop_lichtblick.sh + @cp $(ROOT_DIR)/container.env $(_BUILD_DIR)/container.env + @printf 'LICHTBLICK_IMAGE=%s\nLICHTBLICK_ARCHIVE_NAME=%s\n' \ + "$(_LICHTBLICK_IMAGE)" "$(_LICHTBLICK_ARCHIVE_NAME)" \ + > $(_BUILD_DIR)/lichtblick.env + @mkdir -p $(_BUILD_DIR)/lichtblick + @cp -r $(LICHTBLICK_DIR)/. $(_BUILD_DIR)/lichtblick/ + @cp $(ROOT_DIR)/README.release.md $(_BUILD_DIR)/README.md + +.PHONY: _gather +_gather: + @echo "=== Gathering requirements ===" + @rm -rf $(CONTEXT_DIR) + @mkdir -p $(CONTEXT_DIR)/vendor + @{ find $(ROOT_DIR) -maxdepth 2 -type f -name "*.system" \ + ! -path "*/context/*" 2>/dev/null; \ + find $(ROS2_SRC) -type f -name "*.system" 2>/dev/null; } \ + | LC_ALL=C sort \ + | xargs -r grep -hv '^\s*#' \ + | grep -v '^\s*$$' \ + | LC_ALL=C sort -u \ + > $(CONTEXT_DIR)/requirements.system || true + @{ find $(ROOT_DIR) -maxdepth 2 -type f -name "*.pip3" \ + ! -path "*/context/*" 2>/dev/null; \ + find $(ROS2_SRC) -type f -name "*.pip3" 2>/dev/null; } \ + | LC_ALL=C sort \ + | xargs -r grep -hv '^\s*#' \ + | grep -v '^\s*$$' \ + | LC_ALL=C sort -u \ + > $(CONTEXT_DIR)/requirements.pip3 || true + @{ find $(ROOT_DIR) -maxdepth 2 -type f -name "*.ppa" \ + ! -path "*/context/*" 2>/dev/null; \ + find $(ROS2_SRC) -type f -name "*.ppa" 2>/dev/null; } \ + | LC_ALL=C sort \ + | xargs -r grep -hv '^\s*#' \ + | grep '^ppa:' \ + | LC_ALL=C sort -u \ + > $(CONTEXT_DIR)/requirements.ppa || true + @find "$(VENDOR_PATH)/build" -name '*.deb' 2>/dev/null \ + | sort | xargs -r -I{} cp {} $(CONTEXT_DIR)/vendor/ || true + @cp $(ROOT_DIR)/scripts/install_packages.sh $(CONTEXT_DIR)/install_packages.sh && chmod +x $(CONTEXT_DIR)/install_packages.sh + @cp $(ROOT_DIR)/scripts/install_requirements.sh $(CONTEXT_DIR)/install_requirements.sh && chmod +x $(CONTEXT_DIR)/install_requirements.sh + @echo " system : $$(wc -l < $(CONTEXT_DIR)/requirements.system)" + @echo " pip3 : $$(wc -l < $(CONTEXT_DIR)/requirements.pip3)" + @echo " ppa : $$(wc -l < $(CONTEXT_DIR)/requirements.ppa)" + @echo " debs : $$(find $(CONTEXT_DIR)/vendor -name '*.deb' | wc -l)" + @echo "=== Gather complete ===" + +.PHONY: image +image: ## Prints the current docker image tag + @echo ${IMAGE} diff --git a/adore_embedded/README.md b/adore_embedded/README.md new file mode 100644 index 00000000..dd5acebc --- /dev/null +++ b/adore_embedded/README.md @@ -0,0 +1,42 @@ +# adore_embedded + +This project builds a complete stand-alone deployment package for ADORe +with a versioned Docker image for the ADORe ROS2 workspace. The image bundles +all system, Python, and vendor dependencies needed to compile and run the +workspace in a reproducible environment. + +Each build is tagged with the current git commit and a hash of all dependency +files, so the image tag changes only when the code or dependencies change. + +The output package in `build/` can be copied to a new host and executed +immediately. The output package only requires docker to execute. + +## Requirements + +- Docker +- GNU Make + +## Usage + +``` +make build Build the image, compile the ROS2 workspace, and save to build// +make start Start the container with the workspace mounted +make stop Stop and remove the container +make shell Open a shell inside the running container +make clean Remove the image, build output, and context +make help Show available targets +``` + +The first `make build` produces a `build//` directory containing the +image archive, compiled workspace, and helper +scripts (`load.sh`, `shell.sh`, `run.sh`, `stop.sh`) for use on machines +without this repo. + +## Configuration + +Environment variables passed to the container are read from `container.env`. +The ROS distro and target architecture can be overridden at build time: + +``` +make build ROS_DISTRO=humble ARCH=aarch64 +``` diff --git a/adore_embedded/README.release.md b/adore_embedded/README.release.md new file mode 100644 index 00000000..b057c954 --- /dev/null +++ b/adore_embedded/README.release.md @@ -0,0 +1,253 @@ +# ADORe Embedded — Release + +## Requirements + +**Docker (recommended)** +- Docker Engine 24+ — [install guide](https://docs.docker.com/engine/install/) +- `x86_64` or `aarch64` host matching the image architecture in the filename +- GNU Make + +**Docker-free bundle** +- `podman` — [install guide](https://podman.io/docs/installation), **or** +- `util-linux` with `unshare`, `chroot`, and `mount` (standard on most Linux distributions) +- Lichtblick visualisation in the bundle requires `podman` + +## Fetch + +https://github.com/eclipse-adore/adore/releases/ + +Release: []() + +**Docker image** + +```bash +# x86_64 +curl -L -o https://github.com/eclipse-adore/adore/releases/download// +wget https://github.com/eclipse-adore/adore/releases/download// + +# aarch64 +curl -L -o https://github.com/eclipse-adore/adore/releases/download// +wget https://github.com/eclipse-adore/adore/releases/download// +``` + +**Docker-free bundle** + +```bash +# x86_64 +curl -L -o https://github.com/eclipse-adore/adore/releases/download// +wget https://github.com/eclipse-adore/adore/releases/download// + +# aarch64 +curl -L -o https://github.com/eclipse-adore/adore/releases/download// +wget https://github.com/eclipse-adore/adore/releases/download// +``` + +## Unpack + +```bash +# x86_64 +tar -xzf +cd + +# aarch64 +tar -xzf +cd +``` + +The image archive (`*.tar.gz`) inside the directory is loaded separately on first run — no manual extraction needed. + +## Quick start + +```bash +./load.sh # import Docker image (first run only) +./start.sh # start container +./start_lichtblick.sh # start Lichtblick visualiser (optional) +./shell_dist.sh # attach to pre-built workspace +./stop_lichtblick.sh # stop visualiser +./stop.sh # stop container +``` + +## Running a scenario + +`shell_dist.sh` drops directly into the simulation scenarios directory with the workspace pre-sourced. + +```bash +./shell_dist.sh +``` + +Inside the shell, launch any scenario by name: + +```bash +ros2 launch simulation_test.launch.py +``` + +Other available scenarios in the same directory: + +```bash +ros2 launch template.launch.py +ros2 launch dlr_campus.launch.py +ros2 launch saad_maad.launch.py +``` + +## Visualizing with Lichtblick + +Lichtblick connects to the running scenario over rosbridge (WebSocket on port 9090) and renders a pre-configured layout shipped with the release. + +**1. Start Lichtblick** (in a separate terminal, before or after launching a scenario): + +```bash +./start_lichtblick.sh +``` + +**2. Launch a scenario** (in another terminal): + +```bash +./shell_dist.sh +ros2 launch simulation_test.launch.py +``` + +**3. Open Lichtblick** in a Chromium-based browser: + +``` +http://localhost:8080/?ds=rosbridge-websocket&ds.url=ws://localhost:9090 +``` + +The default layout loads automatically. To load the shipped layout explicitly, open it from `ros2_workspace_dist/context/` inside the container, or from the `adore_scenarios/assets/lichtblick_layouts/Default.json` path in the release directory. + +> **Note:** Lichtblick requires a Chromium-based browser (Chrome, Chromium, Edge). Firefox is not supported. + +**4. Stop when done:** + +```bash +./stop_lichtblick.sh +./stop.sh +``` + +## Dev vs dist workspace + +| | Dev (`shell_dev.sh`) | Dist (`shell_dist.sh`) | +|---|---|---| +| Mount | Live `ros2_workspace/` from host | Pre-built `ros2_workspace_dist/` baked into the image | +| ROS2 setup | Not sourced — run `source install/setup.bash` after building | Sourced automatically on shell entry | +| Use when | Actively modifying and rebuilding source | Running scenarios against a known-good build | + +Use `shell_dev.sh` during development. Use `shell_dist.sh` to run scenarios against the shipped build without any host dependencies. + +## Docker-free bundle + +No Docker required. The bundle ships a complete Linux rootfs extracted from the Docker image alongside the pre-built ROS2 workspace and the Lichtblick image archive. + +### How it works + +`start.sh` uses `podman` if available, otherwise falls back to `unshare`/`chroot` from `util-linux`. Both paths mount the `ros2_workspace_dist/` directory from the bundle into the rootfs at runtime, so scenarios always run against the shipped build without copying it into the container. + +The `unshare` path creates an unprivileged user namespace with a private mount and PID namespace, then calls `chroot` into the rootfs. No root access is required with either backend. + +Lichtblick in the bundle requires `podman`. The Lichtblick container image is included in the bundle as `lichtblick/.tar.gz` and is imported into podman on first use. + +### Unpack + +```bash +tar -xzf +cd +``` + +### Workflow + +```bash +./shell_dist.sh # enter the dist workspace shell +./shell_dev.sh # enter the dev workspace shell +./stop.sh # remove the imported podman image (podman only; no-op for unshare) +./start_lichtblick.sh # start the Lichtblick visualiser (requires podman) +./stop_lichtblick.sh # stop the Lichtblick visualiser +``` + +### Running a scenario (bundle) + +Open two terminals in the bundle directory. + +**Terminal 1 — start the environment and launch a scenario:** + +```bash +./shell_dist.sh +ros2 launch simulation_test.launch.py +``` + +**Terminal 2 — start Lichtblick:** + +```bash +./start_lichtblick.sh +``` + +Then open in a Chromium-based browser: + +``` +http://localhost:8080/?ds=rosbridge-websocket&ds.url=ws://localhost:9090 +``` + +**When done:** + +```bash +./stop_lichtblick.sh +./stop.sh +``` + +`stop.sh` removes the imported podman image (`adore_bundle_`). Re-running `start.sh` or any shell script will re-import it from the rootfs directory on the next invocation. When using the `unshare` backend, `stop.sh` prints a notice and exits cleanly — there is no persistent state to remove. + +### Backend selection + +| Backend | Selected when | Persistent state | +|---|---|---| +| `podman` | `podman` is on `PATH` | Podman image `adore_bundle_` imported on first run; removed by `stop.sh` | +| `unshare`/`chroot` | `podman` not found | None — namespace torn down when the shell exits | + +### Bundle contents + +| Path | Description | +|---|---| +| `rootfs/` | Complete Linux rootfs with all ROS2 and ADORe dependencies | +| `ros2_workspace_dist/` | Pre-built ROS2 workspace mounted into the rootfs at runtime | +| `lichtblick/.tar.gz` | Lichtblick container image archive, imported into podman on first use | +| `bundle.env` | `ROS_DISTRO` and `DOCKER_PLATFORM` consumed by the bundle scripts | +| `lichtblick.env` | `LICHTBLICK_IMAGE` and `LICHTBLICK_ARCHIVE_NAME` consumed by `start_lichtblick.sh` | +| `container.env` | Runtime environment variables passed into the environment | +| `start.sh` | Start an interactive session via podman or unshare/chroot | +| `stop.sh` | Remove the imported podman image; no-op for unshare | +| `shell_dist.sh` | Shell into the pre-built dist workspace | +| `shell_dev.sh` | Shell into the dev workspace | +| `start_lichtblick.sh` | Start Lichtblick via podman (loads archive on first use) | +| `stop_lichtblick.sh` | Stop the Lichtblick podman container | +| `.bundle_inner.sh` | Internal helper — mounts filesystems and execs into the chroot (not called directly) | +| `README.md` | This file | + +## Rebuild ROS2 workspace + +```bash +./shell_dev.sh # enter dev shell +make build # rebuild inside container +``` + +Or non-interactively: + +```bash +./build_ros_workspace.sh +``` + +## Contents (Docker release) + +| Path | Description | +|---|---| +| `adore.env` | Image name, tag, and container configuration | +| `container.env` | Runtime environment variables passed into the container | +| `load.sh` | Load the image archive into Docker | +| `start.sh` | Start the container detached | +| `stop.sh` | Stop and remove the container | +| `shell_dev.sh` | Interactive shell — live source workspace | +| `shell_dist.sh` | Interactive shell — pre-built distribution workspace | +| `build_ros_workspace.sh` | Rebuild the ROS2 workspace inside the container | +| `start_lichtblick.sh` / `stop_lichtblick.sh` | Lichtblick visualiser | +| `bundle_run.sh` | Run without Docker via podman or `unshare` | +| `bundle_shell_dev.sh` / `bundle_shell_dist.sh` | Shells for the Docker-free bundle | +| `ros2_workspace_dist/` | Pre-built ROS2 workspace | +| `lichtblick/` | Lichtblick image archive and supporting files | +| `*.tar.gz` | Docker image archive | diff --git a/adore_embedded/container.env b/adore_embedded/container.env new file mode 100644 index 00000000..a6c793ab --- /dev/null +++ b/adore_embedded/container.env @@ -0,0 +1 @@ +FASTDDS_BUILTIN_TRANSPORTS=UDPv4 diff --git a/adore_embedded/patches/001_fastcdr_fastrtps_snapshot_pin.patch b/adore_embedded/patches/001_fastcdr_fastrtps_snapshot_pin.patch new file mode 100644 index 00000000..ca965f18 --- /dev/null +++ b/adore_embedded/patches/001_fastcdr_fastrtps_snapshot_pin.patch @@ -0,0 +1,46 @@ +# PATCH: 001_fastcdr_fastrtps_snapshot_pin.patch +# +# PROBLEM: +# ros-jazzy-fastcdr (2.2.7-1noble.20260225.051855) ships a binary built from a +# source snapshot where Cdr::serialize(uint8_t const&) was still an inline header +# function and therefore not exported from libfastcdr.so.2. ros-jazzy-fastrtps +# (2.14.6-1noble.20260303.233638) was compiled against the real v2.2.7 tag where +# that method became out-of-line, producing an unresolvable symbol at runtime: +# libfastrtps.so.2.14: undefined symbol: _ZN8eprosima7fastcdr3Cdr9serializeERKh +# The base image ros:jazzy-ros-core-noble ships these broken versions, and +# apt-get upgrade in the base stage promotes all ros-jazzy-* packages to the +# broken post-20260121 builds. +# +# FIX: +# After all apt operations in the base stage, pin all installed ros-jazzy-* +# packages to the jazzy/2026-01-28 snapshot using Pin-Priority: 1001 (above +# apt's downgrade threshold), force-downgrade them, then hold to prevent +# subsequent layers from re-upgrading. +# +# REMOVE WHEN: +# The ros-jazzy apt repo publishes a consistent set of fastcdr/fastrtps packages +# where all rosidl_typesupport_fastrtps_* libraries are built against the same +# fastcdr ABI. +--- a/Dockerfile ++++ b/Dockerfile +@@ -45,6 +45,20 @@ + + RUN echo "/usr/local/lib" >> /etc/ld.so.conf.d/local.conf && ldconfig + ++RUN gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys AD19BAB3CBF125EA && \ ++ gpg --export AD19BAB3CBF125EA > /usr/share/keyrings/ros-snapshot-keyring.gpg && \ ++ echo "deb [ signed-by=/usr/share/keyrings/ros-snapshot-keyring.gpg ] \ ++ http://snapshots.ros.org/jazzy/2026-01-28/ubuntu noble main" \ ++ > /etc/apt/sources.list.d/ros2-snapshot.list && \ ++ printf 'Package: ros-jazzy-*\nPin: origin snapshots.ros.org\nPin-Priority: 1001\n' \ ++ > /etc/apt/preferences.d/ros-snapshot-pin && \ ++ apt-get update && \ ++ apt-get install -y --allow-downgrades \ ++ $(dpkg -l "ros-jazzy-*" | awk '/^[hi]i/{print $2}') && \ ++ dpkg -l "ros-jazzy-*" | awk '/^[hi]i/{print $2}' | xargs apt-mark hold && \ ++ rm /etc/apt/sources.list.d/ros2-snapshot.list \ ++ /etc/apt/preferences.d/ros-snapshot-pin ++ + # ── Workspace build stage ────────────────────────────────────────────────────── + # ros2_workspace is supplied as an external BuildKit build context: + # docker build --build-context ros2_workspace=../ros2_workspace ... diff --git a/adore_embedded/requirements.pip3 b/adore_embedded/requirements.pip3 new file mode 100644 index 00000000..4707807c --- /dev/null +++ b/adore_embedded/requirements.pip3 @@ -0,0 +1,6 @@ +# Python package requirements for adore_embedded. +# One pip package name (with optional version specifier) per line. +# These are installed into the Docker image at build time via install_requirements.sh. +# Add any Python packages required by the embedded runtime that are not declared +# in a ROS package's own requirements.pip3 file. +# Environment variables (e.g. ${ROS_DISTRO}) are expanded at build time via envsubst. diff --git a/adore_embedded/requirements.ppa b/adore_embedded/requirements.ppa new file mode 100644 index 00000000..1b66ab97 --- /dev/null +++ b/adore_embedded/requirements.ppa @@ -0,0 +1,6 @@ +# PPA requirements for adore_embedded. +# One PPA per line in the format: ppa:/ +# These are added to apt sources at build time via install_requirements.sh. +# Add any PPAs required by the embedded runtime that are not declared +# in a ROS package's own requirements.ppa file. +# Environment variables (e.g. ${ROS_DISTRO}) are expanded at build time via envsubst. diff --git a/adore_embedded/requirements.system b/adore_embedded/requirements.system new file mode 100644 index 00000000..d7799660 --- /dev/null +++ b/adore_embedded/requirements.system @@ -0,0 +1,10 @@ +# System package requirements for adore_embedded. +# One apt package name per line. These are installed into the Docker image at build time +# via install_requirements.sh. Add any apt packages required by the embedded runtime +# that are not declared in a ROS package's own requirements.system file. +# Environment variables (e.g. ${ROS_DISTRO}) are expanded at build time via envsubst. +ros-${ROS_DISTRO}-rosbridge-suite +ros-${ROS_DISTRO}-rosbridge-msgs +ros-${ROS_DISTRO}-rmw-fastrtps-cpp +ros-${ROS_DISTRO}-rosapi +ros-${ROS_DISTRO}-rosapi-msgs diff --git a/adore_scenarios/scenario_helpers/simulation_controller_params.py b/adore_embedded/scripts/build_ros_workspace.sh old mode 100644 new mode 100755 similarity index 59% rename from adore_scenarios/scenario_helpers/simulation_controller_params.py rename to adore_embedded/scripts/build_ros_workspace.sh index a02d2050..2c54dbdf --- a/adore_scenarios/scenario_helpers/simulation_controller_params.py +++ b/adore_embedded/scripts/build_ros_workspace.sh @@ -1,5 +1,6 @@ +#!/usr/bin/env bash # ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation +# Copyright (c) 2026 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -11,15 +12,10 @@ # SPDX-License-Identifier: EPL-2.0 # ******************************************************************************** -simulation_pid_params = { - "k_long": 1.0, - "k_v": 1.0, - "k_feed_forward_ax": 1.0, - "dt": 0.1, - "acc_smoothing": 0.95, - "min_lookahead": 0.1, - "max_lookahead": 1.0, - "base_lookahead": 0.5, - "lookahead_gain": 0.1, - "slow_steer_smoothing": 4.0 -} +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" + +bash "${SCRIPT_DIR}/run.sh" +docker exec --workdir /ros2_workspace "${CONTAINER_NAME}" make build +bash "${SCRIPT_DIR}/stop.sh" diff --git a/adore_embedded/scripts/bundle_inner.sh b/adore_embedded/scripts/bundle_inner.sh new file mode 100755 index 00000000..4d4ae6a9 --- /dev/null +++ b/adore_embedded/scripts/bundle_inner.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +# Runs inside the unshare namespace. Args: [cmd...] +set -euo pipefail +ROOTFS="$1"; shift +ROS_DISTRO="$1"; shift +WORKSPACE="$1"; shift + +mount -t proc proc "${ROOTFS}/proc" +mount --rbind /sys "${ROOTFS}/sys" +mount --rbind /dev "${ROOTFS}/dev" +mount --bind "${WORKSPACE}" "${ROOTFS}/ros2_workspace_dist" + +exec chroot "${ROOTFS}" /bin/bash -c ' + source /opt/ros/'"${ROS_DISTRO}"'/setup.bash + source /ros2_workspace_dist/install/setup.bash 2>/dev/null || true + exec "$@" +' -- "$@" diff --git a/adore_embedded/scripts/bundle_run.sh b/adore_embedded/scripts/bundle_run.sh new file mode 100755 index 00000000..9c1d5540 --- /dev/null +++ b/adore_embedded/scripts/bundle_run.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/bundle.env" + +_run_podman() { + if ! podman image exists adore_bundle_${ROS_DISTRO} 2>/dev/null; then + echo "Importing rootfs into podman (first run only)..." + tar -c -C "${SCRIPT_DIR}/rootfs" . \ + | podman import \ + --change "ENV ROS_DISTRO=${ROS_DISTRO}" \ + --change "WORKDIR /ros2_workspace_dist" \ + - "adore_bundle_${ROS_DISTRO}" + fi + exec podman run --rm -it \ + --network host \ + --env-file "${SCRIPT_DIR}/container.env" \ + -e ROS_DISTRO="${ROS_DISTRO}" \ + -v "${SCRIPT_DIR}/ros2_workspace_dist:/ros2_workspace_dist:z" \ + "adore_bundle_${ROS_DISTRO}" \ + "$@" +} + +_run_unshare() { + for tool in unshare chroot mount; do + command -v "$tool" &>/dev/null || { + echo "ERROR: '${tool}' not found — install util-linux" + exit 1 + } + done + set -a; source "${SCRIPT_DIR}/container.env"; set +a + exec unshare --user --map-root-user --mount --pid --fork \ + "${SCRIPT_DIR}/.bundle_inner.sh" \ + "${SCRIPT_DIR}/rootfs" \ + "${ROS_DISTRO}" \ + "${SCRIPT_DIR}/ros2_workspace_dist" \ + "$@" +} + +if command -v podman &>/dev/null; then + _run_podman "$@" +else + _run_unshare "$@" +fi diff --git a/adore_scenarios/scenario_helpers/ngc_controller_params.py b/adore_embedded/scripts/bundle_shell_dev.sh old mode 100644 new mode 100755 similarity index 62% rename from adore_scenarios/scenario_helpers/ngc_controller_params.py rename to adore_embedded/scripts/bundle_shell_dev.sh index 2dd17660..864d00b5 --- a/adore_scenarios/scenario_helpers/ngc_controller_params.py +++ b/adore_embedded/scripts/bundle_shell_dev.sh @@ -1,5 +1,6 @@ +#!/usr/bin/env bash # ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation +# Copyright (c) 2026 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -11,15 +12,6 @@ # SPDX-License-Identifier: EPL-2.0 # ******************************************************************************** -ngc_pid_params = { - "kp_x": 0.05, - "ki_x": 0.0, - "velocity_weight": 0.3, - "kp_y": 0.0, - "ki_y": 0.0, - "heading_weight": 0.0, - "kp_omega": 0.05, - "dt": 0.05, - "steering_comfort": 2.5, - "acceleration_comfort": 15.0, -} \ No newline at end of file +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "${SCRIPT_DIR}/start.sh" /bin/bash diff --git a/adore_scenarios/scenario_helpers/simulation_planner_params.py b/adore_embedded/scripts/bundle_shell_dist.sh old mode 100644 new mode 100755 similarity index 53% rename from adore_scenarios/scenario_helpers/simulation_planner_params.py rename to adore_embedded/scripts/bundle_shell_dist.sh index c353c51c..32e7f358 --- a/adore_scenarios/scenario_helpers/simulation_planner_params.py +++ b/adore_embedded/scripts/bundle_shell_dist.sh @@ -1,5 +1,6 @@ +#!/usr/bin/env bash # ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation +# Copyright (c) 2026 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -11,19 +12,7 @@ # SPDX-License-Identifier: EPL-2.0 # ******************************************************************************** -planner_params = { - "dt": 0.1, - "horizon_steps": 40, - "lane_error": 1.0, - "long_error": 0.01, - "speed_error": 1.0, - "heading_error": 1.0, - "steering_angle": 1.0, - "acceleration": 0.1, - "max_iterations": 100, - "max_ms": 80, - "debug": 0.0, - "max_lateral_acceleration": 2.0, - "idm_time_headway": 3.0, - "ref_traj_length": 200 -} +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "${SCRIPT_DIR}/start.sh" \ + /bin/bash -c 'source /ros2_workspace_dist/install/setup.bash && cd /ros2_workspace_dist/adore_scenarios/simulation_scenarios && exec /bin/bash' diff --git a/adore_embedded/scripts/bundle_start_lichtblick.sh b/adore_embedded/scripts/bundle_start_lichtblick.sh new file mode 100644 index 00000000..da3fc505 --- /dev/null +++ b/adore_embedded/scripts/bundle_start_lichtblick.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/bundle.env" +source "${SCRIPT_DIR}/lichtblick.env" + +LICHTBLICK_CONTAINER="lichtblick_bundle" + +if ! command -v podman &>/dev/null; then + echo "ERROR: Lichtblick requires podman. Install podman and re-run." + exit 1 +fi + +if podman ps --format "{{.Names}}" | grep -q "^${LICHTBLICK_CONTAINER}$"; then + echo "Already running: ${LICHTBLICK_CONTAINER}" + exit 0 +fi + +if ! podman image exists "${LICHTBLICK_IMAGE}" 2>/dev/null; then + ARCHIVE="${SCRIPT_DIR}/lichtblick/${LICHTBLICK_ARCHIVE_NAME}" + if [ ! -f "${ARCHIVE}" ]; then + echo "ERROR: Lichtblick image '${LICHTBLICK_IMAGE}' not found and archive missing: ${ARCHIVE}" + exit 1 + fi + echo "Loading Lichtblick image from ${ARCHIVE}..." + podman load -i "${ARCHIVE}" +fi + +podman run --detach \ + --name "${LICHTBLICK_CONTAINER}" \ + --network host \ + "${LICHTBLICK_IMAGE}" +echo "Started: ${LICHTBLICK_CONTAINER}" +echo "" +echo "Open Lichtblick in a Chromium-based browser:" +echo " http://localhost:8080/?ds=rosbridge-websocket&ds.url=ws://localhost:9090" diff --git a/.docker/scripts/load_image.sh b/adore_embedded/scripts/bundle_stop.sh old mode 100755 new mode 100644 similarity index 53% rename from .docker/scripts/load_image.sh rename to adore_embedded/scripts/bundle_stop.sh index 57fa071a..a666ddae --- a/.docker/scripts/load_image.sh +++ b/adore_embedded/scripts/bundle_stop.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation +# Copyright (c) 2026 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -12,23 +12,19 @@ # SPDX-License-Identifier: EPL-2.0 # ******************************************************************************** -# Load the dev Docker image from a tarball under ${DOCKER_BUILD_DIR}. - set -euo pipefail - SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -require_host "Saving/loading images should be done from the host." +source "${SCRIPT_DIR}/bundle.env" -IN="${DOCKER_BUILD_DIR}/${DOCKER_TAR_NAME}" - -if [[ ! -f "${IN}" ]]; then - echo "ERROR: Image tarball not found: ${IN}" >&2 - echo " Run save_image.sh first to create it." >&2 - exit 1 +if command -v podman &>/dev/null; then + IMAGE_NAME="adore_bundle_${ROS_DISTRO}" + if podman image exists "${IMAGE_NAME}" 2>/dev/null; then + echo "Removing podman image: ${IMAGE_NAME}" + podman rmi "${IMAGE_NAME}" + echo "Removed: ${IMAGE_NAME}" + else + echo "No podman image found: ${IMAGE_NAME}" + fi +else + echo "Bundle uses unshare/chroot — no persistent state to clean up." fi - -echo "--- Loading dev Docker image from ${IN} ---" -docker load -i "${IN}" diff --git a/adore_embedded/scripts/bundle_stop_lichtblick.sh b/adore_embedded/scripts/bundle_stop_lichtblick.sh new file mode 100644 index 00000000..9e50799f --- /dev/null +++ b/adore_embedded/scripts/bundle_stop_lichtblick.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail + +LICHTBLICK_CONTAINER="lichtblick_bundle" + +if ! command -v podman &>/dev/null; then + echo "ERROR: podman not found." + exit 1 +fi + +podman stop "${LICHTBLICK_CONTAINER}" 2>/dev/null || true +podman rm -f "${LICHTBLICK_CONTAINER}" 2>/dev/null || true +echo "Stopped: ${LICHTBLICK_CONTAINER}" diff --git a/adore_embedded/scripts/container.env b/adore_embedded/scripts/container.env new file mode 100644 index 00000000..a6c793ab --- /dev/null +++ b/adore_embedded/scripts/container.env @@ -0,0 +1 @@ +FASTDDS_BUILTIN_TRANSPORTS=UDPv4 diff --git a/.docker/scripts/save_image.sh b/adore_embedded/scripts/install_packages.sh similarity index 54% rename from .docker/scripts/save_image.sh rename to adore_embedded/scripts/install_packages.sh index 6855718b..c03912e7 100755 --- a/.docker/scripts/save_image.sh +++ b/adore_embedded/scripts/install_packages.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation +# Copyright (c) 2026 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -12,20 +12,12 @@ # SPDX-License-Identifier: EPL-2.0 # ******************************************************************************** -# Save the dev Docker image to a tarball under ${DOCKER_BUILD_DIR}. - set -euo pipefail - SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "${SCRIPT_DIR}/common.sh" - -require_host "Saving/loading images should be done from the host." - -mkdir -p "${DOCKER_BUILD_DIR}" - -OUT="${DOCKER_BUILD_DIR}/${DOCKER_TAR_NAME}" -echo "--- Saving dev Docker image ${DOCKER_DEV_IMAGE_LATEST} to ${OUT} ---" -docker save -o "${OUT}" "${DOCKER_DEV_IMAGE_LATEST}" -echo "Docker image saved to ${OUT}" +if find "${SCRIPT_DIR}/vendor" -name '*.deb' | grep -q .; then + find "${SCRIPT_DIR}/vendor" -name '*.deb' | sort | xargs dpkg -i || true + apt-get install -f -y --no-install-recommends +else + echo "No .deb packages found in ${SCRIPT_DIR}/vendor" +fi diff --git a/adore_embedded/scripts/install_requirements.sh b/adore_embedded/scripts/install_requirements.sh new file mode 100755 index 00000000..f25f14e3 --- /dev/null +++ b/adore_embedded/scripts/install_requirements.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ -s "${SCRIPT_DIR}/requirements.ppa" ]; then + apt-get install -y --no-install-recommends software-properties-common + while IFS= read -r ppa; do + add-apt-repository -y "$ppa" + done < "${SCRIPT_DIR}/requirements.ppa" + apt-get update +fi + +if [ -s "${SCRIPT_DIR}/requirements.system" ]; then + apt-get update + envsubst < "${SCRIPT_DIR}/requirements.system" \ + | xargs -r apt-get install -y --no-install-recommends +fi + +if [ -s "${SCRIPT_DIR}/requirements.pip3" ]; then + pip3 install --no-cache-dir --break-system-packages \ + -r "${SCRIPT_DIR}/requirements.pip3" +fi diff --git a/adore_embedded/scripts/load.sh b/adore_embedded/scripts/load.sh new file mode 100755 index 00000000..af40d122 --- /dev/null +++ b/adore_embedded/scripts/load.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" +docker load -i "${SCRIPT_DIR}/${IMAGE_ARCHIVE_NAME}.gz" diff --git a/adore_embedded/scripts/shell_dev.sh b/adore_embedded/scripts/shell_dev.sh new file mode 100755 index 00000000..361d4a62 --- /dev/null +++ b/adore_embedded/scripts/shell_dev.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" +bash "${SCRIPT_DIR}/start.sh" +docker exec -it --user "$(id -u):$(id -g)" --workdir /ros2_workspace "${CONTAINER_NAME}" /bin/bash diff --git a/adore_embedded/scripts/shell_dist.sh b/adore_embedded/scripts/shell_dist.sh new file mode 100755 index 00000000..4d502ed9 --- /dev/null +++ b/adore_embedded/scripts/shell_dist.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" +bash "${SCRIPT_DIR}/start.sh" +docker exec -it --user "$(id -u):$(id -g)" \ + --workdir /ros2_workspace_dist/adore_scenarios/simulation_scenarios \ + "${CONTAINER_NAME}" \ + /bin/bash --init-file /ros2_workspace_dist/install/setup.bash diff --git a/adore_embedded/scripts/start.sh b/adore_embedded/scripts/start.sh new file mode 100755 index 00000000..9bc6520d --- /dev/null +++ b/adore_embedded/scripts/start.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" + +WORKSPACE="${SCRIPT_DIR}/ros2_workspace" +if [ ! -d "${WORKSPACE}" ]; then + mkdir -p "${WORKSPACE}" +fi +if [ ! -d "${WORKSPACE}/src" ] && [ -d "${SCRIPT_DIR}/src" ]; then + cp -r "${SCRIPT_DIR}/src" "${WORKSPACE}/src" +fi +for f in Makefile colcon_defaults.yaml colcon_defaults.yaml.template; do + if [ -f "${SCRIPT_DIR}/${f}" ] && [ ! -f "${WORKSPACE}/${f}" ]; then + cp "${SCRIPT_DIR}/${f}" "${WORKSPACE}/${f}" + fi +done +if [ ! -d "${WORKSPACE}/adore_scenarios" ] && [ -d "${SCRIPT_DIR}/adore_scenarios" ]; then + cp -r "${SCRIPT_DIR}/adore_scenarios" "${WORKSPACE}/adore_scenarios" +fi + +if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then + "${SCRIPT_DIR}/load.sh" +fi + +if docker ps --format "{{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then + echo "Already running: ${CONTAINER_NAME}" +else + docker run --detach \ + --name "${CONTAINER_NAME}" \ + --platform "${DOCKER_PLATFORM}" \ + --network host \ + --user "$(id -u):$(id -g)" \ + --env-file "${SCRIPT_DIR}/container.env" \ + -e ROS_DISTRO="${ROS_DISTRO}" \ + -v "${SCRIPT_DIR}/ros2_workspace:/ros2_workspace" \ + "${IMAGE}" \ + sleep infinity + echo "Started: ${CONTAINER_NAME}" +fi diff --git a/adore_embedded/scripts/start_lichtblick.sh b/adore_embedded/scripts/start_lichtblick.sh new file mode 100755 index 00000000..d59b4a88 --- /dev/null +++ b/adore_embedded/scripts/start_lichtblick.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" +source "${SCRIPT_DIR}/lichtblick.env" + +if ! docker image inspect "${LICHTBLICK_IMAGE}" >/dev/null 2>&1; then + ARCHIVE="${SCRIPT_DIR}/lichtblick/${LICHTBLICK_ARCHIVE_NAME}" + if [ ! -f "${ARCHIVE}" ]; then + echo "ERROR: Lichtblick image '${LICHTBLICK_IMAGE}' not found and archive missing: ${ARCHIVE}" + exit 1 + fi + echo "Loading lichtblick image from ${ARCHIVE}..." + docker load -i "${ARCHIVE}" +fi + +cd "${SCRIPT_DIR}/lichtblick" +exec make start diff --git a/adore_embedded/scripts/stop.sh b/adore_embedded/scripts/stop.sh new file mode 100755 index 00000000..f2e61c5d --- /dev/null +++ b/adore_embedded/scripts/stop.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" +docker stop "${CONTAINER_NAME}" 2>/dev/null || true +docker rm -f "${CONTAINER_NAME}" 2>/dev/null || true +echo "Stopped: ${CONTAINER_NAME}" diff --git a/adore_embedded/scripts/stop_lichtblick.sh b/adore_embedded/scripts/stop_lichtblick.sh new file mode 100755 index 00000000..80b17d3d --- /dev/null +++ b/adore_embedded/scripts/stop_lichtblick.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# ******************************************************************************** +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +# ******************************************************************************** + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/adore.env" + +cd "${SCRIPT_DIR}/lichtblick" +exec make stop diff --git a/adore_interfaces/carla_bridge b/adore_interfaces/carla_bridge deleted file mode 160000 index 674af7a0..00000000 --- a/adore_interfaces/carla_bridge +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 674af7a04a1b3d51ea01b0be1e7f4ae5ebea70fa diff --git a/adore_interfaces/sumo_bridge b/adore_interfaces/sumo_bridge deleted file mode 160000 index ae0d8f6c..00000000 --- a/adore_interfaces/sumo_bridge +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ae0d8f6cb61cc4177ea0e84893a28662f692d539 diff --git a/adore_libraries/adore_controllers b/adore_libraries/adore_controllers deleted file mode 160000 index 1b74aa15..00000000 --- a/adore_libraries/adore_controllers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1b74aa159b883c51a27ea0bcbca7e42fe09ddccc diff --git a/adore_libraries/adore_map b/adore_libraries/adore_map deleted file mode 160000 index 7e3162ec..00000000 --- a/adore_libraries/adore_map +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7e3162ec7b26b1407cac58f1264a96bbbaeb56ba diff --git a/adore_libraries/adore_math b/adore_libraries/adore_math deleted file mode 160000 index f1e4b754..00000000 --- a/adore_libraries/adore_math +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f1e4b754723671e06d35946acd944913257d72fb diff --git a/adore_libraries/adore_planning b/adore_libraries/adore_planning deleted file mode 160000 index ad91f921..00000000 --- a/adore_libraries/adore_planning +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ad91f92106b477e939e7e9f11815aa4366b90689 diff --git a/adore_ros2_conversions/adore_dynamics_conversions b/adore_ros2_conversions/adore_dynamics_conversions deleted file mode 160000 index 7733f280..00000000 --- a/adore_ros2_conversions/adore_dynamics_conversions +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7733f28011968d7d968faf16dcc96f28766235e5 diff --git a/adore_ros2_conversions/adore_map_conversions b/adore_ros2_conversions/adore_map_conversions deleted file mode 160000 index 8aa18a8c..00000000 --- a/adore_ros2_conversions/adore_map_conversions +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8aa18a8c2cda93bdf9d853cc8e557c80c351def8 diff --git a/adore_ros2_conversions/adore_math_conversions b/adore_ros2_conversions/adore_math_conversions deleted file mode 160000 index 50a5472a..00000000 --- a/adore_ros2_conversions/adore_math_conversions +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 50a5472aef48945dd7d1fb52b8c9441ece33fb8f diff --git a/adore_ros2_msgs b/adore_ros2_msgs deleted file mode 160000 index bb0f118e..00000000 --- a/adore_ros2_msgs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bb0f118e0fca7e60a861a3d7d4d7223ced8a62c8 diff --git a/adore_ros2_nodes/decision_maker b/adore_ros2_nodes/decision_maker deleted file mode 160000 index f522d78f..00000000 --- a/adore_ros2_nodes/decision_maker +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f522d78f04b85621e18253ecafc6bc2d156c5236 diff --git a/adore_ros2_nodes/decision_maker_infrastructure b/adore_ros2_nodes/decision_maker_infrastructure deleted file mode 160000 index c244a4ac..00000000 --- a/adore_ros2_nodes/decision_maker_infrastructure +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c244a4acc8b008ad1d2a18269de250a293957419 diff --git a/adore_ros2_nodes/mission_control b/adore_ros2_nodes/mission_control deleted file mode 160000 index 63b02754..00000000 --- a/adore_ros2_nodes/mission_control +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 63b02754aefb61260816056bbfdf8aaeca634f67 diff --git a/adore_ros2_nodes/simulated_remote_operator b/adore_ros2_nodes/simulated_remote_operator deleted file mode 160000 index 7f7a05f8..00000000 --- a/adore_ros2_nodes/simulated_remote_operator +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7f7a05f8cbf4bdadc63e7165c4b62732eab64d88 diff --git a/adore_ros2_nodes/simulated_vehicle b/adore_ros2_nodes/simulated_vehicle deleted file mode 160000 index 3bb1c835..00000000 --- a/adore_ros2_nodes/simulated_vehicle +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3bb1c83532cc4876a0d5183767c8112f34f7b047 diff --git a/adore_ros2_nodes/trajectory_tracker b/adore_ros2_nodes/trajectory_tracker deleted file mode 160000 index b530c69c..00000000 --- a/adore_ros2_nodes/trajectory_tracker +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b530c69c4e4e55ac72b74e0752eed256d59a4133 diff --git a/adore_ros2_nodes/visualizer b/adore_ros2_nodes/visualizer deleted file mode 160000 index f47cfabd..00000000 --- a/adore_ros2_nodes/visualizer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f47cfabd7a784cb475469322de3d3585ccb71ced diff --git a/plugins/.gitkeep b/adore_scenarios/COLCON_IGNORE similarity index 100% rename from plugins/.gitkeep rename to adore_scenarios/COLCON_IGNORE diff --git a/tools/lichtblick/lichblick_layouts/Default.json b/adore_scenarios/assets/lichtblick_layouts/Default.json similarity index 100% rename from tools/lichtblick/lichblick_layouts/Default.json rename to adore_scenarios/assets/lichtblick_layouts/Default.json diff --git a/adore_scenarios/assets/odd/simulation_odd.json b/adore_scenarios/assets/odd/simulation_odd.json new file mode 100644 index 00000000..facf82f8 --- /dev/null +++ b/adore_scenarios/assets/odd/simulation_odd.json @@ -0,0 +1,6 @@ +{ + "max_speed": 70, + "minimum_road_width": 2.0, + "valid_hours_of_the_day": [0, 24], + "max_wind_intensity": 4 +} diff --git a/adore_scenarios/scenario_helpers/ngc.py b/adore_scenarios/scenario_helpers/ngc.py deleted file mode 100644 index 2a36088a..00000000 --- a/adore_scenarios/scenario_helpers/ngc.py +++ /dev/null @@ -1,109 +0,0 @@ -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -from launch_ros.actions import Node -import os -from scenario_helpers.simulation_planner_params import planner_params -from scenario_helpers.ngc_controller_params import ngc_pid_params - -def create_ngc_nodes( - namespace: str, - goal_position: tuple[float, float], - map_file: str, - debug: bool = False, - optinlc_route_following: bool = True, - controller: int = 1, - custom_start_pose: tuple[float, float, float] | None = None, - request_assistance_polygon: list[float] = [0.0,0.0]) -> list[Node]: - - launch_file_dir = os.path.dirname(os.path.realpath(__file__)) - vehicle_param = os.path.abspath(os.path.join(launch_file_dir, "../assets/vehicle_params/")) - model_file = vehicle_param + "/NGC.json" - x, y, psi = custom_start_pose - goal_x, goal_y = goal_position - - nodes = [ - Node( - package='adore_bob_interface', - namespace='ego_vehicle', - executable='adore_bob_interface', - name='adore_bob_interface', - parameters=[ - {"publish_traffic_participants": True}, - {"vehicle_name": "ngc"}, - ], - #output={'both': 'log'}, - ), - Node( - package='adore_v2x_interface', - namespace='ego_vehicle', - executable='ego_v2x_interface_node', - name='adore_v2x_interface', - parameters=[ - {"ego_v2x_id": 222}, - ], - - ), - Node( - package='adore_vehicle_interface', - namespace='ego_vehicle', - executable='vehicle_udp_gateway_node', - name='vehicle_udp_gateway_node', - parameters=[ - {"VehicleID":"NGC"}, - ], - shell=False, - output="screen", - prefix=['xterm -e'], - ), - Node( - package="mission_control", - namespace=namespace, - executable="mission_control", - name="mission_control", - parameters=[ - {"map file": map_file}, - {"goal_position_x": goal_x}, - {"goal_position_y": goal_y}, - ], - ), - Node( - package="decision_maker", - namespace=namespace, - executable="decision_maker", - name="decision_maker", - parameters=[ - {"debug_mode_active": debug}, - {"optinlc_route_following": optinlc_route_following}, - {"planner_settings_keys": list(planner_params.keys())}, - {"planner_settings_values": list(planner_params.values())}, - {"request_assistance_polygon": request_assistance_polygon}, - {"vehicle_model_file": model_file} - ], - # output={"both": "log"}, - ), - Node( - package="trajectory_tracker", - namespace=namespace, - executable="trajectory_tracker_node", - name="trajectory_tracker", - parameters=[ - {"set_controller": controller}, - {"controller_settings_keys": list(ngc_pid_params.keys())}, - {"controller_settings_values": list(ngc_pid_params.values())}, - {"vehicle_model_file": model_file}, - ], - ), - ] - - return nodes diff --git a/adore_scenarios/scenario_helpers/simulated_infrastructure.py b/adore_scenarios/scenario_helpers/simulated_infrastructure.py deleted file mode 100644 index e417d132..00000000 --- a/adore_scenarios/scenario_helpers/simulated_infrastructure.py +++ /dev/null @@ -1,60 +0,0 @@ -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -from launch_ros.actions import Node - -# example only -simulated_v2x_topic_parameters = { - "planned_traffic_out_topic": "v2x_planned_traffic", - "traffic_participant_in_topic": "v2x_traffic_participant", -} -topic_parameters = { - "planned_traffic_out_topic": "/planned_traffic", - "traffic_participant_in_topic": "traffic_participant", -} - - -def with_topic_params(*param_dicts: dict, topic_params) -> list[dict]: - - return list(param_dicts) + [topic_params] - - -def create_infrastructure_nodes(position: tuple[float, float], - polygon: list[float], - map_file: str, - simulated_v2x_mode: bool = False, - debug=True) -> list[Node]: - x, y = position - topic_params = topic_parameters - if simulated_v2x_mode: - topic_params = simulated_v2x_topic_parameters - - return [ - Node( - package='decision_maker_infrastructure', - namespace='infrastructure', - executable='decision_maker_infrastructure', - name='decision_maker_infrastructure', - parameters=with_topic_params( - {"map file": map_file}, - {"infrastructure_position_x": x}, - {"infrastructure_position_y": y}, - {"debug": debug}, - {"validity_polygon": polygon}, - {"multi_agent_PID_settings_keys": ["preview_distance", "k_yaw", "k_distance"] - }, - {"multi_agent_PID_settings_values": [4.5, 2.0, 1.0] - }, topic_params=topic_params - ), - ) - ] diff --git a/adore_scenarios/scenario_helpers/simulated_vehicle.py b/adore_scenarios/scenario_helpers/simulated_vehicle.py deleted file mode 100644 index fd0e530b..00000000 --- a/adore_scenarios/scenario_helpers/simulated_vehicle.py +++ /dev/null @@ -1,291 +0,0 @@ -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -from __future__ import annotations - -from typing import Any, Dict, List, Optional, Tuple - -from launch import Action -from launch_ros.actions import ComposableNodeContainer, Node -from launch_ros.descriptions import ComposableNode - -from scenario_helpers.simulation_planner_params import planner_params -from scenario_helpers.simulation_controller_params import simulation_pid_params - -# Example only -SIMULATED_V2X_TOPIC_PARAMETERS: Dict[str, str] = { - "topic_infrastructure_participants": "v2x_planned_traffic", -} -STANDARD_TOPIC_PARAMETERS: Dict[str, str] = { - "topic_infrastructure_participants": "/planned_traffic", -} - - -def with_topic_params( - *param_dicts: Dict[str, Any], - topic_params: Dict[str, Any], -) -> List[Dict[str, Any]]: - """Return a list of parameter dictionaries ending with topic parameters. - - Enforces topic_params as keyword-only for clarity. - """ - return list(param_dicts) + [topic_params] - - -def _build_composable_components( - *, - namespace: str, - x: float, - y: float, - psi: float, - controllable: bool, - vehicle_id: int, - v2x_id: int, - map_file: str, - model_file: str, - goal_x: float, - goal_y: float, - local_map_size: float, - request_assistance_polygon: List[float], - topic_params: Dict[str, Any], - debug: bool, - controller: int, -) -> List[ComposableNode]: - """Create composable components for the simulated vehicle stack.""" - return [ - ComposableNode( - package="simulated_vehicle", - plugin="adore::simulated_vehicle::SimulatedVehicleNode", - name="simulated_vehicle", - namespace=namespace, - parameters=with_topic_params( - {"set_start_position_x": x}, - {"set_start_position_y": y}, - {"set_start_psi": psi}, - {"controllable": controllable}, - {"vehicle_id": vehicle_id}, - {"v2x_id": v2x_id}, - {"vehicle_model_file": model_file}, - topic_params=topic_params, - ), - ), - ComposableNode( - package="mission_control", - plugin="adore::MissionControlNode", - name="mission_control", - namespace=namespace, - parameters=with_topic_params( - {"map file": map_file}, # kept literal key as in original - {"goal_position_x": goal_x}, - {"goal_position_y": goal_y}, - {"local_map_size": local_map_size}, - {"request_assistance_polygon": request_assistance_polygon}, - topic_params=topic_params, - ), - ), - ComposableNode( - package="decision_maker", - plugin="adore::DecisionMaker", - name="decision_maker", - namespace=namespace, - parameters=with_topic_params( - {"debug_mode_active": debug}, - {"planner_settings_keys": list(planner_params.keys())}, - {"planner_settings_values": list(planner_params.values())}, - {"vehicle_model_file": model_file}, - {"v2x_id": v2x_id}, - topic_params=topic_params, - ), - ), - ComposableNode( - package="trajectory_tracker", - plugin="adore::TrajectoryTrackerNode", - name="trajectory_tracker", - namespace=namespace, - parameters=with_topic_params( - {"set_controller": controller}, - {"controller_settings_keys": list( - simulation_pid_params.keys())}, - {"controller_settings_values": list( - simulation_pid_params.values())}, - {"vehicle_model_file": model_file}, - topic_params=topic_params, - ), - ), - ] - - -def _build_standalone_nodes( - *, - namespace: str, - x: float, - y: float, - psi: float, - controllable: bool, - vehicle_id: int, - v2x_id: int, - map_file: str, - model_file: str, - goal_x: float, - goal_y: float, - local_map_size: float, - request_assistance_polygon: List[float], - topic_params: Dict[str, Any], - debug: bool, - controller: int, -) -> List[Action]: - """Create standalone ROS 2 nodes for the simulated vehicle stack.""" - return [ - Node( - package="simulated_vehicle", - executable="simulated_vehicle", - name="simulated_vehicle", - namespace=namespace, - parameters=with_topic_params( - {"set_start_position_x": x}, - {"set_start_position_y": y}, - {"set_start_psi": psi}, - {"controllable": controllable}, - {"vehicle_id": vehicle_id}, - {"v2x_id": v2x_id}, - {"vehicle_model_file": model_file}, - topic_params=topic_params, - ), - ), - Node( - package="mission_control", - executable="mission_control", - name="mission_control", - namespace=namespace, - parameters=with_topic_params( - {"map file": map_file}, # kept literal key as in original - {"goal_position_x": goal_x}, - {"goal_position_y": goal_y}, - {"local_map_size": local_map_size}, - {"request_assistance_polygon": request_assistance_polygon}, - topic_params=topic_params, - ), - ), - Node( - package="decision_maker", - executable="decision_maker", - name="decision_maker", - namespace=namespace, - parameters=with_topic_params( - {"debug_mode_active": debug}, - {"planner_settings_keys": list(planner_params.keys())}, - {"planner_settings_values": list(planner_params.values())}, - {"vehicle_model_file": model_file}, - {"v2x_id": v2x_id}, - topic_params=topic_params, - ), - ), - Node( - package="trajectory_tracker", - executable="trajectory_tracker", - name="trajectory_tracker", - namespace=namespace, - parameters=with_topic_params( - {"set_controller": controller}, - {"controller_settings_keys": list( - simulation_pid_params.keys())}, - {"controller_settings_values": list( - simulation_pid_params.values())}, - {"vehicle_model_file": model_file}, - topic_params=topic_params, - ), - ), - ] - - -def create_simulated_vehicle_nodes( - namespace: str, - start_pose: Tuple[float, float, float], - goal_position: Tuple[float, float], - vehicle_id: int, - map_file: str, - model_file: str, - debug: bool = False, - controller: int = 1, - controllable: bool = True, - v2x_id: int = 0, - simulated_v2x_mode: bool = False, - request_assistance_polygon: Optional[List[float]] = None, - composable: bool = False, - local_map_size: float = 100.0, -) -> List[Action]: - """Create simulated vehicle nodes or components for ROS 2 launch. - - Returns a list of launch Actions (either a container or individual Nodes). - """ - x, y, psi = start_pose - goal_x, goal_y = goal_position - - if request_assistance_polygon is None: - request_assistance_polygon = [0.0, 0.0] - - topic_params = ( - SIMULATED_V2X_TOPIC_PARAMETERS if simulated_v2x_mode else STANDARD_TOPIC_PARAMETERS - ) - - if composable: - components = _build_composable_components( - namespace=namespace, - x=x, - y=y, - psi=psi, - controllable=controllable, - vehicle_id=vehicle_id, - v2x_id=v2x_id, - map_file=map_file, - model_file=model_file, - goal_x=goal_x, - goal_y=goal_y, - local_map_size=local_map_size, - request_assistance_polygon=request_assistance_polygon, - topic_params=topic_params, - debug=debug, - controller=controller, - - ) - - container = ComposableNodeContainer( - name="sim_container", - namespace="", - package="rclcpp_components", - executable="component_container_mt", - composable_node_descriptions=components, - output="screen", - ) - return [container] - - # Standalone nodes - return _build_standalone_nodes( - namespace=namespace, - x=x, - y=y, - psi=psi, - controllable=controllable, - vehicle_id=vehicle_id, - v2x_id=v2x_id, - map_file=map_file, - model_file=model_file, - goal_x=goal_x, - goal_y=goal_y, - local_map_size=local_map_size, - request_assistance_polygon=request_assistance_polygon, - topic_params=topic_params, - debug=debug, - controller=controller, - - ) diff --git a/adore_scenarios/scenario_helpers/visualizer.py b/adore_scenarios/scenario_helpers/visualizer.py deleted file mode 100644 index c3004520..00000000 --- a/adore_scenarios/scenario_helpers/visualizer.py +++ /dev/null @@ -1,65 +0,0 @@ -# ******************************************************************************** -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# https://www.eclipse.org/legal/epl-2.0 -# -# SPDX-License-Identifier: EPL-2.0 -# ******************************************************************************** - -from launch_ros.actions import Node -import os - - -def create_visualization_nodes(whitelist, asset_folder, visualization_offset, ns="visualizer", port=9090, send_buffer_limit=500000000): - """ - Returns a list of nodes for visualization (foxglove bridge and visualizer). - - Parameters: - whitelist (list[str]): List of topic namespace prefixes to visualize. - asset_folder (str): Path to folder containing map image assets. - port (int): Port for Foxglove Bridge. - send_buffer_limit (int): Buffer limit for Foxglove Bridge. - - Returns: - list[Node]: Launchable ROS 2 Node actions. - """ - return [ - Node( - package='rosapi', - executable='rosapi_node', - name='rosapi', - output='screen' - ), - Node( - package='rosbridge_server', - executable='rosbridge_websocket', - name='rosbridge_websocket', - output='screen', - parameters=[ - {'port': port}, - {'address': '0.0.0.0'}, - {'use_compression': False}, - {'fragment_timeout': 600}, - {'delay_between_messages': 0.0}, - {'max_message_size': 10000000}, - {'unregister_timeout': 10.0} - ] - ), - Node( - package='visualizer', - namespace=ns, - executable='visualizer', - name='visualizer', - parameters=[ - {"asset folder": asset_folder}, - {"whitelist": whitelist}, - {"visualization_offset_x": visualization_offset[0]}, - {"visualization_offset_y": visualization_offset[1]}, - ] - ) - ] diff --git a/adore_scenarios/simulation_scenarios b/adore_scenarios/simulation_scenarios index 71f63762..66572820 160000 --- a/adore_scenarios/simulation_scenarios +++ b/adore_scenarios/simulation_scenarios @@ -1 +1 @@ -Subproject commit 71f637620f8cf4a00d455e3b5e514a55872dcb72 +Subproject commit 665728203c4cc78b3e0215b76ceca4e80ae29467 diff --git a/ci.env b/ci.env new file mode 100644 index 00000000..bb3d1bf4 --- /dev/null +++ b/ci.env @@ -0,0 +1,18 @@ +project=adore_cli +build_directory="build" +log_directory=".log" +docker_image="$(make image_$project)" + +docker_images=( + $(make images_adore_cli) + $(cd tools/lichtblick && make lichtblick_image) +) + +build_artifacts=( + #${build_directory}/adore_cli_*.tar.gz +) + +log_files=( + "${log_directory}/${project}.ci.log" + "${log_directory}/adore_api.log" +) diff --git a/configuring_adore.md b/configuring_adore.md new file mode 100644 index 00000000..91399bd9 --- /dev/null +++ b/configuring_adore.md @@ -0,0 +1,22 @@ +# Configuring ADORe + +ADORe and the ADORe CLI can be configured through environment variables defined in [`adore.env`](./adore.env). + +## Configuration File + +The configuration file can be used to configure control ADORe's behavior: + +- **Build Configuration**: Control parallel vs sequential builds +- **API Configuration**: Enable/disable and configure the ADORe API server +- **Logging Configuration**: Configure rsyslog server and forwarding +- **General Settings**: File size limits, paths, and other runtime parameters +- **ROS Settings**: ROS Domain ID, ROS logging directory + +## Usage + +The environment variables are automatically sourced by ADORe components and +build scripts. Modify the values in `adore.env` and restart the ADORe CLI with +`make stop && make start` or `make restart` to apply changes. + +See the `adore.env` configuration file for detailed documentation on each +variable and its available options. diff --git a/documentation/Makefile b/documentation/Makefile new file mode 100644 index 00000000..7c32a568 --- /dev/null +++ b/documentation/Makefile @@ -0,0 +1,116 @@ +SHELL:=/bin/bash + +.DEFAULT_GOAL := help + +ROOT_DIR:=$(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") + +.EXPORT_ALL_VARIABLES: +DOCKER_BUILDKIT?=1 +DOCKER_CONFIG?= + +USER := $(shell whoami) +UID := $(shell id -u) +GID := $(shell id -g) + +.PHONY: help +help: + @printf "Usage: make \033[36m\033[0m\n%s\n" "$$(awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) | sort | uniq)" + +.PHONY: all +all: clean build + +.PHONY: build +build: build_gh-pages ## Build ADORe documentation + +.PHONY: update_submodules +update_submodules: + git submodule update --init --recusrive || true + +.PHONY: build_doxygen_docs +build_doxygen_docs: stop ## Build doxygen documentation. Requires doxygen to be installed + @command -v doxygen >/dev/null 2>&1 || { echo >&2 "Error: doxygen is not installed. Install with: 'sudo apt-get install -y doxygen'."; exit 1; } + cd doxygen && doxygen Doxyfile-project.cfg + +.PHONY: build_sphinx_docs +build_sphinx_docs: ## Build sphinx documentation + command -v sphinx-build >/dev/null 2>&1 || { echo >&2 "Error: sphinx-build is not installed. Install with: 'sudo apt-get install -y sphinx'."; exit 1; } + python -c "import breathe" 2>/dev/null || { echo >&2 "Error: sphinx extension breathe is not installed. Install with: 'python3 -m pip install breathe'."; exit 1; } + python -c "import exhale" 2>/dev/null || { echo >&2 "Error: sphinx extension exhale is not installed. Install with: 'python3 -m pip install exhale'."; exit 1; } + + cd sphinx && make html + +.PHONY: build_gh-pages_docnado +build_gh-pages_docnado: stop clean build_doxygen_docs build_docnado_docs + mkdir -p docs + cp -r landing_page/* docs/ + cp -r docnado/html docs/docnado + cp -r doxygen/generated_doxygen_documentation/html docs/docnado/w/generated_doxygen_documentation + +.PHONY: build_gh-pages +build_gh-pages: stop build_doxygen_docs build_mkdocs + rm -rf docs + mkdir -p docs + cp -r landing_page/* docs/ + cp -r mkdocs/site docs/mkdocs + cp -r doxygen/generated_doxygen_documentation/html docs/generated_doxygen_documentation + +.PHONY: build_mkdocs +build_mkdocs: stop update_submodules ## Build mkdocs + rm mkdocs/docs -rf + rm mkdocs/site -rf + bash populate_module_readme_docs.sh + bash populate_ros_node_summary_docs.sh + bash copy_module_documents.sh + cp -r technical_reference_manual mkdocs/docs + cd mkdocs && docker build -f Dockerfile.mkdocs -t mkdocs:latest . + docker run --user ${UID}:${GID} -v ${ROOT_DIR}/mkdocs:/tmp/docs mkdocs:latest + +.PHONY: serve_nginx +serve_nginx: stop build + docker rm --force adore-docs + docker run -it --rm --name "adore-docs" -d -p 80:80 -v ${ROOT_DIR}/docs:/usr/share/nginx/html nginx:latest + sleep 1s + firefox http://localhost + @echo "Docs can be found at: http://localhost" + +.PHONY: publish_gh-pages +publish_gh-pages: + bash publish_gh-pages.sh + +.PHONY: publish +publish: publish_gh-pages ## Publish docs to gh-pages branch review the "publish.env" file before publishing + +.PHONY: serve +serve: stop serve_nginx ## Build and serve docs to http://localhost + +.PHONY: stop +stop: ## Stop the adore_docs docker container which is started by "make serve" + docker stop adore-docs || true + docker rm --force adore-docs || true + + +.PHONY: watch +watch: + while inotifywait -e modify -e create -e delete -r .; do \ + make serve; \ + sleep 1s; \ + done + +.PHONY: clean +clean: stop + rm -rf docs || true + rm -rf mkdocs/docs || true + rm mkdocs/site -rf + rm doxygen/generated_doxygen_documentation/* -rf + rm -rf technical_reference_manual/generated/ + +.PHONY: spellcheck +spellcheck: clean ## Start an interactive spell checking session with the tool aspell + docker build -f Dockerfile.aspell -t aspell . + docker run -it --rm -u "${UID}:${GID}" -v "$$(pwd):/mnt" aspell 'find /mnt/technical_reference_manual -name "**.md" -exec bash -c "aspell check --encoding=utf-8 --mode=markdown --home-dir=/mnt --personal=/mnt/.aspell.en.pws {}" \;' + +.PHONY: lint +lint: clean ## Lint aka spell check the markdown files + docker build -f Dockerfile.aspell -t aspell . + docker run -u "${UID}:${GID}" -v $$(pwd):/mnt aspell:latest "python3 spellcheck.py" + diff --git a/documentation/copy_module_documents.sh b/documentation/copy_module_documents.sh new file mode 100644 index 00000000..a8b67c6f --- /dev/null +++ b/documentation/copy_module_documents.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +SCRIPT_DIRECTORY="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" +SOURCE_DIRECTORY="$(realpath "${SCRIPT_DIRECTORY}/..")" + +GENERATED_DIRECTORY="technical_reference_manual/generated/" +mkdir -p "${GENERATED_DIRECTORY}" + +cp "${SOURCE_DIRECTORY}/CODE_OF_CONDUCT.md" "${GENERATED_DIRECTORY}" +cp "${SOURCE_DIRECTORY}/CONTRIBUTING.md" "${GENERATED_DIRECTORY}" +cp "${SOURCE_DIRECTORY}/NOTICE.md" "${GENERATED_DIRECTORY}" + +cp -r "${SOURCE_DIRECTORY}/ros2_workspace/src/adore_ros2_msgs" "${GENERATED_DIRECTORY}" + +cp -r "${SOURCE_DIRECTORY}/ros2_workspace/src/adore_interfaces/carla_bridge" "${GENERATED_DIRECTORY}" +cp -r "${SOURCE_DIRECTORY}/ros2_workspace/src/adore_interfaces/sumo_bridge" "${GENERATED_DIRECTORY}" + +mkdir -p "${GENERATED_DIRECTORY}/api" +cp -r "${SOURCE_DIRECTORY}/tools/adore_api" "${GENERATED_DIRECTORY}/api" + +mkdir -p "${GENERATED_DIRECTORY}/configuring_adore" +cp "${SOURCE_DIRECTORY}/adore.env" "${GENERATED_DIRECTORY}/configuring_adore/" +cp -r "${SOURCE_DIRECTORY}/configuring_adore.md" "${GENERATED_DIRECTORY}/configuring_adore/" + +cp -r "${SOURCE_DIRECTORY}/adore_cli" "${GENERATED_DIRECTORY}" + +cp -r "${SOURCE_DIRECTORY}/vendor/adore_model_checker" "${GENERATED_DIRECTORY}" + +mkdir -p "${GENERATED_DIRECTORY}/visualization" +cp -r "${SOURCE_DIRECTORY}/tools/lichtblick" "${GENERATED_DIRECTORY}/visualization" +rm -rf "${GENERATED_DIRECTORY}/visualization/lichtblick/lichtblick" + +cp -r "${SOURCE_DIRECTORY}/THIRD-PARTY.md" "${GENERATED_DIRECTORY}" +cp -r "${SOURCE_DIRECTORY}/NOTICE.md" "${GENERATED_DIRECTORY}" + +find "${GENERATED_DIRECTORY}" -type f ! \( -name '*.md' -o -name '*.yaml' -o -name '*.yml' -o -name '*.env' \) -delete diff --git a/documentation/doxygen/.gitignore b/documentation/doxygen/.gitignore new file mode 100644 index 00000000..448118db --- /dev/null +++ b/documentation/doxygen/.gitignore @@ -0,0 +1 @@ +.generated** diff --git a/documentation/doxygen/Doxyfile-project.cfg b/documentation/doxygen/Doxyfile-project.cfg new file mode 100644 index 00000000..37ad0df2 --- /dev/null +++ b/documentation/doxygen/Doxyfile-project.cfg @@ -0,0 +1,74 @@ +#******************************************************************************** +#* Copyright (C) 2017-2020 German Aerospace Center (DLR). +#* Eclipse ADORe, Automated Driving Open Research https://eclipse.org/adore +#* +#* This program and the accompanying materials are made available under the +#* terms of the Eclipse Public License 2.0 which is available at +#* http://www.eclipse.org/legal/epl-2.0. +#* +#* SPDX-License-Identifier: EPL-2.0 +#* +#* Contributors: +#* Thomas Lobig +#******************************************************************************** + +@INCLUDE = "./Doxyfile.cfg" +GENERATE_HTML = YES +GENERATE_XML = YES +GENERATE_XML2DOT = YES +GENERATE_XML = YES +OUTPUT_DIRECTORY = "./generated_doxygen_documentation" + +# Project Stuff +PROJECT_NAME = "ADORe" +PROJECT_BRIEF = "ADORe is a modular open source software library and toolkit for decision making, planning, control and simulation of automated vehicles" + +# Inputs +INPUT = "./../../ros2_workspace/src" + +EXCLUDE_PATTERNS = */build/* +EXCLUDE_PATTERNS += */external/* +EXCLUDE_PATTERNS += */vendor/* + +RECURSIVE = YES + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.py + +UML_LOOK = YES + + +HAVE_DOT = YES +DOT_CLEANUP = NO + +GRAPHICAL_HIERARCHY = YES +GENERATE_TREEVIEW = YES + +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_ANON_NSPACES = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +EXTRACT_PACKAGE = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES + +CALL_GRAPH = YES +CALLER_GRAPH = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INHERITANCE_GRAPH = YES +CLASS_DIAGRAMS = YES +DISABLE_INDEX = YES + diff --git a/documentation/doxygen/Doxyfile.cfg b/documentation/doxygen/Doxyfile.cfg new file mode 100644 index 00000000..4e042b04 --- /dev/null +++ b/documentation/doxygen/Doxyfile.cfg @@ -0,0 +1,2579 @@ +# Doxyfile 1.8.17 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "ADORe" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.doc \ + *.txt \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /