diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..d048962 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +{ + "name": "vortex-image-segmentation-devcontainer", + "image": "vortex-image-segmentation:latest", + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash" + }, + "extensions": [ + "ms-azuretools.vscode-docker", + "ms-vscode.cpptools", + "ranch-hand-robotics.rde-pack", + "ms-python.vscode-pylance", + "twxs.cmake", + "ms-vsliveshare.vsliveshare", + "eamodio.gitlens", + "njpwerner.autodocstring", + "cschlosser.doxdocgen", + "xaver.clang-format", + "visualstudioexptteam.vscodeintellicode", + "ms-vscode-remote.remote-ssh", + "gxl.git-graph-3", + "ms-vscode-remote.remote-containers", + "gruntfuggly.todo-tree" + ] + } + }, + "remoteUser": "devuser", + "workspaceFolder": "/ros2_ws", + "workspaceMount": "source=${localWorkspaceFolder},target=/ros2_ws,type=bind,consistency=cached", + "runArgs": [ + "--privileged", + "--network=host", + "--ipc=host" + ] +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ab2a35e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,30 @@ +# Ignore build artifacts and large/runtime folders +build/ +install/ +log/ +*.log + +# Docker and local config +docker/ +.dockerignore + +# VCS +.git +.gitignore + +# VS Code +.vscode/ + +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +venv/ +.env + +# Misc +*.swp +*.swo +node_modules/ +bags/ diff --git a/.gitignore b/.gitignore index b24b6e0..a8f5dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -163,5 +163,10 @@ runs/ *.pt *jpg +# ROS 2 build artifacts +install/ +build/ +log/ + # data data/ \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..963557d --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,75 @@ +# ---------------------------------------------------------------------------- +# Base Image +# ---------------------------------------------------------------------------- +ARG BASE_IMAGE=ros:humble +FROM ${BASE_IMAGE} + +# ---------------------------------------------------------------------------- +# Setup Arguments & Environment +# ---------------------------------------------------------------------------- +USER root +SHELL ["/bin/bash", "-c"] +ARG DEBIAN_FRONTEND=noninteractive +ARG ROS_DISTRO=humble + +# Define User Args +ARG USER_ID=1000 +ARG GROUP_ID=1000 +ARG USERNAME=devuser + +ENV WORKSPACE=/ros2_ws +WORKDIR ${WORKSPACE} + +# ---------------------------------------------------------------------------- +# Create non-root user +# ---------------------------------------------------------------------------- +RUN groupadd --gid ${GROUP_ID} ${USERNAME} || true && \ + useradd --uid ${USER_ID} --gid ${GROUP_ID} -m -s /bin/bash ${USERNAME} || true && \ + apt-get update && apt-get install -y sudo && \ + echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# ---------------------------------------------------------------------------- +# Install System Dependencies +# ---------------------------------------------------------------------------- +RUN apt-get update && apt-get install -y \ + git \ + python3-vcstool \ + python3-pip \ + ros-${ROS_DISTRO}-cv-bridge \ + ros-${ROS_DISTRO}-vision-msgs \ + ros-${ROS_DISTRO}-pcl-conversions \ + libopencv-dev \ + libpcl-dev \ + python3-colcon-common-extensions \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN pip3 install cython + +# ---------------------------------------------------------------------------- +# Copy & Install Requirements +# ---------------------------------------------------------------------------- +COPY requirements.txt ${WORKSPACE}/requirements.txt +RUN pip3 install -r ${WORKSPACE}/requirements.txt + +# ---------------------------------------------------------------------------- +# Copy Workspace Files +# ---------------------------------------------------------------------------- +COPY . ${WORKSPACE} +RUN chown -R ${USER_ID}:${GROUP_ID} ${WORKSPACE} + +# ---------------------------------------------------------------------------- +# Install ROS dependencies +# ---------------------------------------------------------------------------- +RUN rosdep update && rosdep install --from-paths . --ignore-src -r -y + +# ---------------------------------------------------------------------------- +# User Configuration +# ---------------------------------------------------------------------------- +RUN echo "if [ -f /ros2_ws/scripts/bashrc_extra.sh ]; then source /ros2_ws/scripts/bashrc_extra.sh; fi" >> /home/${USERNAME}/.bashrc + +# Switch to the user +USER ${USERNAME} +WORKDIR /home/${USERNAME} + +CMD ["bash"] diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 0000000..b21da45 --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ------------------------------------------------------------------------------ +# Environment Variables +# ------------------------------------------------------------------------------ +IMAGE="vortex-image-segmentation:latest" # Docker image name/tag +BASE_IMAGE="ros:humble" # Base image for Docker builds + +# ------------------------------------------------------------------------------ +# Platform Detection +# ------------------------------------------------------------------------------ +ARCHITECTURE="$(uname -m)" +if [[ "$ARCHITECTURE" == "arm64" || "$ARCHITECTURE" == "aarch64" ]]; then + PLATFORM="linux/arm64" +elif [[ "$ARCHITECTURE" == "x86_64" ]]; then + PLATFORM="linux/amd64" +else + echo "Unsupported architecture: $ARCHITECTURE" >&2 + exit 1 +fi + +# ------------------------------------------------------------------------------ +# Locate Script and Workspace Root +# ------------------------------------------------------------------------------ +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +WORKSPACE="$(realpath "$SCRIPT_DIR/..")" + +# ------------------------------------------------------------------------------ +# Build Start Info +# ------------------------------------------------------------------------------ +echo "======================================================================" +echo " Building Docker Image" +echo " • PLATFORM: $PLATFORM" +echo " • BASE_IMAGE: $BASE_IMAGE" +echo " • IMAGE: $IMAGE" +echo " • BUILD CONTEXT: $WORKSPACE" +echo "======================================================================" +echo "" + +# ------------------------------------------------------------------------------ +# Build Docker Image with Buildx +# ------------------------------------------------------------------------------ +docker buildx build \ + --platform "$PLATFORM" \ + --build-arg BASE_IMAGE="$BASE_IMAGE" \ + --build-arg USER_ID="$(id -u)" \ + --build-arg GROUP_ID="$(id -g)" \ + --tag "$IMAGE" \ + --file "$SCRIPT_DIR/Dockerfile" \ + --load \ + "$WORKSPACE" + +echo "" +echo "======================================================================" +echo " Successfully built image '$IMAGE' for platform '$PLATFORM'" +echo "======================================================================" diff --git a/docker/run.sh b/docker/run.sh new file mode 100755 index 0000000..2aecefe --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ------------------------------------------------------------------------------ +# Image Configuration +# ------------------------------------------------------------------------------ +IMAGE="vortex-image-segmentation:latest" # Default Docker image name/tag + +# ------------------------------------------------------------------------------ +# Locate Script Directory and Workspace Root +# ------------------------------------------------------------------------------ +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +WORKSPACE="$(realpath "$SCRIPT_DIR/..")" + +echo "======================================================================" +echo " Running Container" +echo " • IMAGE: $IMAGE" +echo " • Volume mount: $WORKSPACE -> /ros2_ws" +echo "======================================================================" +echo "" + +# ------------------------------------------------------------------------------ +# Run Docker Container +# ------------------------------------------------------------------------------ +docker run -it --rm \ + --privileged \ + --network host \ + --ipc=host \ + -v "$WORKSPACE":/ros2_ws \ + -w /ros2_ws \ + "$IMAGE" \ + /bin/bash diff --git a/scripts/bashrc_extra.sh b/scripts/bashrc_extra.sh new file mode 100644 index 0000000..93c565e --- /dev/null +++ b/scripts/bashrc_extra.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# /ros2_ws/scripts/bashrc_extra.sh for ROS 2 container + +# Print actions for clarity +if [ -f /opt/ros/humble/setup.bash ]; then + echo "[bashrc_extra] Sourcing ROS 2 underlay: /opt/ros/humble/setup.bash" + source /opt/ros/humble/setup.bash +else + echo "[bashrc_extra] ROS 2 underlay not found: /opt/ros/humble/setup.bash" +fi + +if [ -f /ros2_ws/install/setup.bash ]; then + echo "[bashrc_extra] Sourcing workspace overlay: /ros2_ws/install/setup.bash" + source /ros2_ws/install/setup.bash +else + echo "[bashrc_extra] Workspace overlay not found: /ros2_ws/install/setup.bash" +fi + +# Add your custom shell commands, aliases, or environment variables below