From ccb1605ed5d07c8c447d5b0e9dc1082b094a6fd5 Mon Sep 17 00:00:00 2001 From: Aaron Marburg Date: Wed, 7 Aug 2024 09:19:33 -0700 Subject: [PATCH] Initial commit --- .clang-format | 27 +++ .clang-tidy | 80 +++++++++ .devcontainer/nouveau/Dockerfile | 29 ++++ .devcontainer/nouveau/devcontainer.json | 41 +++++ .devcontainer/nvidia/Dockerfile | 29 ++++ .devcontainer/nvidia/devcontainer.json | 45 +++++ .docker/Dockerfile | 119 +++++++++++++ .dockerignore | 8 + .github/ISSUE_TEMPLATE/bug-report.yml | 62 +++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + .github/ISSUE_TEMPLATE/documentation.yml | 46 +++++ .github/ISSUE_TEMPLATE/feature-request.yml | 57 +++++++ .github/PULL_REQUEST_TEMPLATE.md | 15 ++ .github/dependabot.yml | 6 + .github/workflows/ci.yml | 44 +++++ .github/workflows/docker.yml | 186 +++++++++++++++++++++ .github/workflows/format.yml | 34 ++++ .gitignore | 4 + .pre-commit-config.yaml | 45 +++++ .ruff.toml | 1 + .vscode/c_cpp_properties.json | 14 ++ .vscode/settings.json | 75 +++++++++ .vscode/tasks.json | 43 +++++ LICENSE | 28 ++++ README.md | 39 +++++ example_pkg/CMakeLists.txt | 10 ++ example_pkg/LICENSE | 28 ++++ example_pkg/package.xml | 18 ++ requirements-dev.txt | 3 + ros2.repos | 7 + 30 files changed, 1144 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .devcontainer/nouveau/Dockerfile create mode 100644 .devcontainer/nouveau/devcontainer.json create mode 100644 .devcontainer/nvidia/Dockerfile create mode 100644 .devcontainer/nvidia/devcontainer.json create mode 100644 .docker/Dockerfile create mode 100644 .dockerignore create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/documentation.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docker.yml create mode 100644 .github/workflows/format.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .ruff.toml create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 LICENSE create mode 100644 README.md create mode 100644 example_pkg/CMakeLists.txt create mode 100644 example_pkg/LICENSE create mode 100644 example_pkg/package.xml create mode 100644 requirements-dev.txt create mode 100644 ros2.repos diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5e0792e --- /dev/null +++ b/.clang-format @@ -0,0 +1,27 @@ +--- +Language: Cpp +BasedOnStyle: Google +ColumnLimit: 100 +MaxEmptyLinesToKeep: 1 + +IndentWidth: 2 +TabWidth: 2 +UseTab: Never +AccessModifierOffset: -2 +AlignAfterOpenBracket: AlwaysBreak +ConstructorInitializerIndentWidth: 0 +ContinuationIndentWidth: 2 +DerivePointerAlignment: false +PointerAlignment: Middle +PackConstructorInitializers: Never + +# Configure brace wrapping cases +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..d235ad0 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,80 @@ +--- +Checks: > + -*, + abseil-*, + bugprone-*, + google-*, + misc-*, + modernize-*, + performance-*, + portability-*, + readability-*, + -google-readability-braces-around-statements, + -google-readability-namespace-comments, + -google-runtime-references, + -misc-non-private-member-variables-in-classes, + -modernize-return-braced-init-list, + -modernize-use-trailing-return-type, + -readability-braces-around-statements, + -readability-identifier-length, + -readability-magic-numbers, + -readability-named-parameter, + -readability-redundant-declaration, + -readability-function-cognitive-complexity, + -bugprone-narrowing-conversions, + -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, + -clang-diagnostic-error, + -bugprone-exception-escape +WarningsAsErrors: "*" +CheckOptions: + - key: readability-braces-around-statements.ShortStatementLines + value: "2" + - key: readability-identifier-naming.NamespaceCase + value: lower_case + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.StructCase + value: CamelCase + - key: readability-identifier-naming.TemplateParameterCase, + value: CamelCase, + - key: readability-identifier-naming.FunctionCase + value: camelBack + - key: readability-identifier-naming.MethodCase + value: camelBack + - key: readability-identifier-naming.VariableCase + value: lower_case + - key: readability-identifier-naming.ClassMemberCase + value: lower_case + - key: readability-identifier-naming.ClassMemberSuffix + value: _ + - key: readability-identifier-naming.PrivateMemberSuffix + value: _ + - key: readability-identifier-naming.ProtectedMemberSuffix + value: _ + - key: readability-identifier-naming.EnumConstantCase + value: CamelCase + - key: readability-identifier-naming.EnumConstantPrefix + value: k + - key: readability-identifier-naming.ConstexprVariableCase + value: CamelCase + - key: readability-identifier-naming.ConstexprVariablePrefix + value: k + - key: readability-identifier-naming.GlobalConstantCase + value: CamelCase + - key: readability-identifier-naming.GlobalConstantPrefix + value: k + - key: readability-identifier-naming.MemberConstantCase + value: CamelCase + - key: readability-identifier-naming.MemberConstantPrefix + value: k + - key: readability-identifier-naming.StaticConstantCase + value: CamelCase + - key: readability-identifier-naming.StaticConstantPrefix + value: k + - key: readability-implicit-bool-conversion.AllowIntegerConditions + value: 1 + - key: readability-implicit-bool-conversion.AllowPointerConditions + value: 1 + - key: readability-function-cognitive-complexity.IgnoreMacros + value: 1 diff --git a/.devcontainer/nouveau/Dockerfile b/.devcontainer/nouveau/Dockerfile new file mode 100644 index 0000000..eb09636 --- /dev/null +++ b/.devcontainer/nouveau/Dockerfile @@ -0,0 +1,29 @@ +FROM ghcr.io/robotic-decision-making-lab/ros-template:noetic-desktop + +# Install ROS dependencies +# This is done in a previous stage, but we include it again here in case anyone wants to +# add new dependencies during development +ENV USERNAME=ros +ENV USER_WORKSPACE=/home/$USERNAME/ws_ros +WORKDIR $USER_WORKSPACE + +COPY --chown=$USER_UID:$USER_GID . src/$PROJECT_NAME + +RUN ls src/$PROJECT_NAME + +RUN sudo apt-get -q update \ + && sudo apt-get -q -y upgrade \ + && rosdep update \ + && rosdep install -y --from-paths . --ignore-src -r --rosdistro ${ROS_DISTRO} \ + && sudo apt-get autoremove -y \ + && sudo apt-get clean -y \ + && sudo rm -rf /var/lib/apt/lists/* + +# Install debugging/linting Python packages +COPY --chown=$USER_UID:$USER_GID requirements-dev.txt . +RUN python3 -m pip install -r requirements-dev.txt \ + && rm -rf requirements-dev.txt + +# Disable the setuputils installation warning +# This prevents us from needing to pin the setuputils version (which doesn't always work) +ENV PYTHONWARNINGS="ignore" diff --git a/.devcontainer/nouveau/devcontainer.json b/.devcontainer/nouveau/devcontainer.json new file mode 100644 index 0000000..bdcb952 --- /dev/null +++ b/.devcontainer/nouveau/devcontainer.json @@ -0,0 +1,41 @@ +{ + "name": "ROS Dev Container", + "dockerFile": "Dockerfile", + "context": "../..", + "workspaceMount": "source=${localWorkspaceFolder},target=/home/ros/ws_ros/src/ros-template,type=bind", + "workspaceFolder": "/home/ros/ws_ros/src/ros-template", + "remoteUser": "ros", + "runArgs": [ + "--network=host", + "--cap-add=SYS_PTRACE", + "--security-opt=seccomp:unconfined", + "--security-opt=apparmor:unconfined", + "--volume=/dev:/dev", + "--privileged", + "--volume=/run/user/1000:/run/user/1000" + ], + "containerEnv": { + "DISPLAY": "${localEnv:DISPLAY}", + "WAYLAND_DISPLAY": "${localEnv:WAYLAND_DISPLAY}", + "XDG_RUNTIME_DIR": "${localEnv:XDG_RUNTIME_DIR}", + "PULSE_SERVER": "${localEnv:PULSE_SERVER}" + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-azuretools.vscode-docker", + "ms-python.python", + "njpwerner.autodocstring", + "ms-vscode.cpptools", + "redhat.vscode-xml", + "redhat.vscode-yaml", + "smilerobotics.urdf", + "DavidAnson.vscode-markdownlint", + "esbenp.prettier-vscode", + "xaver.clang-format", + "charliermarsh.ruff", + "ms-python.black-formatter" + ] + } + } +} diff --git a/.devcontainer/nvidia/Dockerfile b/.devcontainer/nvidia/Dockerfile new file mode 100644 index 0000000..1d2f330 --- /dev/null +++ b/.devcontainer/nvidia/Dockerfile @@ -0,0 +1,29 @@ +FROM ghcr.io/robotic-decision-making-lab/ros-template:noetic-desktop-nvidia + +# Install ROS dependencies +# This is done in a previous stage, but we include it again here in case anyone wants to +# add new dependencies during development +ENV USERNAME=ros +ENV USER_WORKSPACE=/home/$USERNAME/ws_ros +WORKDIR $USER_WORKSPACE + +COPY --chown=$USER_UID:$USER_GID . src/$PROJECT_NAME + +RUN ls src/$PROJECT_NAME + +RUN sudo apt-get -q update \ + && sudo apt-get -q -y upgrade \ + && rosdep update \ + && rosdep install -y --from-paths . --ignore-src -r --rosdistro ${ROS_DISTRO} \ + && sudo apt-get autoremove -y \ + && sudo apt-get clean -y \ + && sudo rm -rf /var/lib/apt/lists/* + +# Install debugging/linting Python packages +COPY --chown=$USER_UID:$USER_GID requirements-dev.txt . +RUN python3 -m pip install -r requirements-dev.txt \ + && rm -rf requirements-dev.txt + +# Disable the setuputils installation warning +# This prevents us from needing to pin the setuputils version (which doesn't always work) +ENV PYTHONWARNINGS="ignore" diff --git a/.devcontainer/nvidia/devcontainer.json b/.devcontainer/nvidia/devcontainer.json new file mode 100644 index 0000000..038ac6d --- /dev/null +++ b/.devcontainer/nvidia/devcontainer.json @@ -0,0 +1,45 @@ +{ + "name": "ROS NVIDIA Dev Container", + "dockerFile": "Dockerfile", + "context": "../..", + "workspaceMount": "source=${localWorkspaceFolder},target=/home/ros/ws_ros/src/ros-template,type=bind", + "workspaceFolder": "/home/ros/ws_ros/src/ros-template", + "remoteUser": "ros", + "runArgs": [ + "--network=host", + "--cap-add=SYS_PTRACE", + "--security-opt=seccomp:unconfined", + "--security-opt=apparmor:unconfined", + "--volume=/dev:/dev", + "--privileged", + "--volume=/tmp/.X11-unix:/tmp/.X11-unix", + "--volume=/mnt/wslg:/mnt/wslg", + "--gpus=all" + ], + "containerEnv": { + "DISPLAY": "${localEnv:DISPLAY}", + "WAYLAND_DISPLAY": "${localEnv:WAYLAND_DISPLAY}", + "XDG_RUNTIME_DIR": "${localEnv:XDG_RUNTIME_DIR}", + "PULSE_SERVER": "${localEnv:PULSE_SERVER}", + "LIBGL_ALWAYS_SOFTWARE": "1", + "QT_X11_NO_MITSHM": "1" + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-azuretools.vscode-docker", + "ms-python.python", + "njpwerner.autodocstring", + "ms-vscode.cpptools", + "redhat.vscode-xml", + "redhat.vscode-yaml", + "smilerobotics.urdf", + "DavidAnson.vscode-markdownlint", + "esbenp.prettier-vscode", + "xaver.clang-format", + "charliermarsh.ruff", + "ms-python.black-formatter" + ] + } + } +} diff --git a/.docker/Dockerfile b/.docker/Dockerfile new file mode 100644 index 0000000..de3296c --- /dev/null +++ b/.docker/Dockerfile @@ -0,0 +1,119 @@ +ARG ROS_DISTRO=noetic +FROM ros:$ROS_DISTRO-ros-base as ci + +ENV DEBIAN_FRONTEND=noninteractive +WORKDIR /root/ws_ros + +# Update to be your project's name +ENV PROJECT_NAME=ros-template + +COPY . src/$PROJECT_NAME + +# Install apt packages +RUN apt-get -q update \ + && apt-get -q -y upgrade \ + && apt-get -q install --no-install-recommends -y \ + git \ + sudo \ + clang \ + clang-format-12 \ + clang-tidy \ + clang-tools \ + python3-pip \ + python3-dev \ + apt-utils \ + software-properties-common \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +# Install all ROS dependencies needed for CI +RUN apt-get -q update \ + && apt-get -q -y upgrade \ + && rosdep update \ + && rosdep install -y --from-paths src --ignore-src --rosdistro ${ROS_DISTRO} --as-root=apt:false \ + && rm -rf src \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +FROM ci as robot + +# Configure a new non-root user +ARG USERNAME=ros +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + && usermod -a -G dialout $USERNAME \ + && echo "source /usr/share/bash-completion/completions/git" >> /home/$USERNAME/.bashrc + +# Switch to the non-root user +USER $USERNAME +ENV USER=$USERNAME + +ENV DEBIAN_FRONTEND=noninteractive +ENV USER_WORKSPACE=/home/$USERNAME/ws_ros +WORKDIR $USER_WORKSPACE + +COPY --chown=$USER_UID:$USER_GID . src/$PROJECT_NAME + +# Uncomment to download and install external repos used by the project +# RUN vcs import src < src/$PROJECT_NAME/ros2.repos + +# Install all ROS dependencies +WORKDIR $USER_WORKSPACE +RUN sudo apt-get -q update \ + && sudo apt-get -q -y upgrade \ + && rosdep update \ + && rosdep install -y --from-paths src --ignore-src -r --rosdistro ${ROS_DISTRO} \ + && sudo apt-get autoremove -y \ + && sudo apt-get clean -y \ + && sudo rm -rf /var/lib/apt/lists/* + +RUN . "/opt/ros/${ROS_DISTRO}/setup.sh" \ + && catkin_make \ + && sudo sed -i "s#/opt/ros/\$ROS_DISTRO/setup.bash#$USER_WORKSPACE/setup.sh#g" /ros_entrypoint.sh \ + && echo "source ${USER_WORKSPACE}/devel/setup.bash" >> /home/$USERNAME/.bashrc \ + && echo "if [ -f /opt/ros/${ROS_DISTRO}/setup.bash ]; then source /opt/ros/${ROS_DISTRO}/setup.bash; fi" >> /home/$USERNAME/.bashrc + +FROM robot as desktop + +ENV DEBIAN_FRONTEND=noninteractive +ENV USER_WORKSPACE=/home/$USERNAME/ws_ros +WORKDIR $USER_WORKSPACE + +# Install Gazebo packages +RUN sudo apt-get update \ + && sudo apt-get -q -y upgrade \ + && curl -sSL http://get.gazebosim.org | sh \ + && sudo apt-get -q install --no-install-recommends -y \ + ros-$ROS_DISTRO-gazebo-ros-pkgs \ + ros-$ROS_DISTRO-gazebo-ros-control \ + && sudo apt-get autoremove -y \ + && sudo apt-get clean -y \ + && sudo rm -rf /var/lib/apt/lists/* + +FROM desktop as desktop-nvidia + +# Install NVIDIA software +RUN sudo apt-get update \ + && sudo apt-get -q -y upgrade \ + && sudo apt-get install -y -qq --no-install-recommends \ + libglvnd0 \ + libgl1 \ + libglx0 \ + libegl1 \ + libxext6 \ + libx11-6 \ + && sudo apt-get autoremove -y \ + && sudo apt-get clean -y \ + && sudo rm -rf /var/lib/apt/lists/* + +# Env vars for the nvidia-container-runtime. +ENV NVIDIA_VISIBLE_DEVICES all +ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute +ENV QT_X11_NO_MITSHM 1 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4cbe360 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +# ignore everything +* + +# Except the following +!requirements-dev.txt + +# Allow your ROS packages here, e.g.: +!example_pkg diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..8ba16ae --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,62 @@ +name: Bug Report +description: Report a bug. +title: "[BUG]: " +labels: [bug, needs triage] + +body: + - type: markdown + attributes: + value: > + Thank you for taking the time to file a bug report! Before creating a new + issue, please make sure to take a few minutes to check the issue tracker + for existing issues about the bug. + + - type: textarea + attributes: + label: "Issue Description" + description: > + Please provide a clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + attributes: + label: "Steps to Reproduce" + description: > + Please provide the steps that should be taken to reproduce the bug. + validations: + required: true + + - type: textarea + attributes: + label: "Expected Behavior" + description: > + Please describe or show an example of the expected behavior. + validations: + required: true + + - type: textarea + attributes: + label: "Error Message" + description: > + Please include the full error message, if any. + placeholder: > + << Full traceback starting from `Traceback: ...` >> + render: bash + + - type: textarea + attributes: + label: "Runtime Environment" + description: > + Please provide a description of the environment in which the error + occurred. + placeholder: > + Raspberry Pi 4 running Ubuntu 22.04 natively. + validations: + required: true + + - type: textarea + attributes: + label: "Additional Context" + description: > + Please provide any additional context needed to understand the bug. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 0000000..3068ca4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,46 @@ +name: Documentation Improvement +description: Report an issue related to the project documentation. +title: "[DOC]: " +labels: [documentation, needs triage] + +body: + - type: markdown + attributes: + value: > + Thank you for taking the time to report a documentation issue! Before creating + a new issue, please make sure to take a few minutes to check the issue + tracker for existing issues similar to that being reported. + + - type: dropdown + attributes: + label: Documentation Change Type + description: Please indicate what type of documentation issue you are reporting. + options: + - Adding new documentation to the project + - Changing existing project documentation + - Removing existing project documentation + validations: + required: true + + - type: textarea + attributes: + label: Documentation Location + description: > + Please provide the location of the documentation that should be modified. + + - type: textarea + attributes: + label: Documentation Problem + description: > + Please provide a description of how the documentation needs to be improved. + validations: + required: true + + - type: textarea + attributes: + label: Suggested Change + description: > + Please provide a description of the proposed change and why the proposed change + improves the upon the existing documentation. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000..e9471bf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,57 @@ +name: Feature Request +description: Suggest a new idea for the project. +title: "[FEATURE]: " +labels: [enhancement, needs triage] + +body: + - type: markdown + attributes: + value: > + Thank you for taking the time to request a new feature! Before creating + a new issue, please make sure to take a few minutes to check the issue + tracker for existing issues similar to the proposed feature. + + - type: dropdown + attributes: + label: Feature Type + description: Please indicate what type of feature request you would like to propose. + options: + - Adding new functionality to the project + - Changing existing functionality in the project + - Removing existing functionality in the project + validations: + required: true + + - type: textarea + attributes: + label: "Problem Description" + description: > + Please provide a clear and concise description of what problem + the feature would solve. + validations: + required: true + + - type: textarea + attributes: + label: "Feature Description" + description: > + Please provide a description of the proposed feature, using pseudocode + if relevant. + validations: + required: true + + - type: textarea + attributes: + label: "Alternative Solutions" + description: > + Please provide a description of any alternative solutions or features + that would satisfy the feature request. + validations: + required: true + + - type: textarea + attributes: + label: "Additional Context" + description: > + Please provide any additional context (e.g., relevant GitHub issues, + code examples, or references) needed to understand the feature request. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..8d1f140 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +## Changes Made + +Please provide a description of all changes made in this PR and why the changes +are needed. + +## Associated Issues + +Please provide a list of all open issues that this PR will close or contribute +toward closing. + +- Fixes # (issue) + +## Testing + +Please provide a clear and concise description of the testing performed. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..79fc83a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8e167e2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: Continuous Integration + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +env: + CLANG_TIDY: true + +jobs: + test: + name: Test Implementation + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + env: + - IMAGE: noetic-ci + ROS_DISTRO: noetic + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Log into registry + uses: docker/login-action@v3.3.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Run ROS Industrial CI + uses: ros-industrial/industrial_ci@master + env: + DOCKER_IMAGE: ghcr.io/robotic-decision-making-lab/ros-template:${{ matrix.env.IMAGE }} + CXXFLAGS: >- + -Wall -Wextra -Wpedantic -Wwrite-strings -Wunreachable-code -Wpointer-arith -Wredundant-decls + CC: ${{ env.CLANG_TIDY && 'clang' }} + CXX: ${{ env.CLANG_TIDY && 'clang++' }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..f8fea74 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,186 @@ +name: Docker + +on: + push: + branches: + - main + pull_request: + paths: + - .docker/** + - .github/workflows/docker.yaml + workflow_dispatch: + +env: + PUSH: ${{ (github.event_name != 'pull_request') && (github.repository == 'robotic-decision-making-lab/ros-template') }} + +jobs: + ci: + strategy: + fail-fast: false + matrix: + ROS_DISTRO: [noetic] + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log into registry + if: env.PUSH == 'true' + uses: docker/login-action@v3.3.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + if: env.PUSH == 'true' + id: meta + uses: docker/metadata-action@v5.5.1 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=raw,value=${{ matrix.ROS_DISTRO }}-${{ github.job }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6.5.0 + with: + context: . + file: .docker/Dockerfile + build-args: ROS_DISTRO=${{ matrix.ROS_DISTRO }} + target: ${{ github.job }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: ${{ env.PUSH }} + + robot: + strategy: + fail-fast: false + matrix: + ROS_DISTRO: [noetic] + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.2.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log into registry + if: env.PUSH == 'true' + uses: docker/login-action@v3.3.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + if: env.PUSH == 'true' + id: meta + uses: docker/metadata-action@v5.5.1 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=raw,value=${{ matrix.ROS_DISTRO }}-${{ github.job }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6.5.0 + with: + context: . + file: .docker/Dockerfile + build-args: ROS_DISTRO=${{ matrix.ROS_DISTRO }} + target: ${{ github.job }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: ${{ env.PUSH }} + platforms: linux/amd64,linux/arm64 + + desktop: + strategy: + fail-fast: false + matrix: + ROS_DISTRO: [noetic] + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log into registry + if: env.PUSH == 'true' + uses: docker/login-action@v3.3.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + if: env.PUSH == 'true' + id: meta + uses: docker/metadata-action@v5.5.1 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=raw,value=${{ matrix.ROS_DISTRO }}-${{ github.job }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6.5.0 + with: + context: . + file: .docker/Dockerfile + build-args: ROS_DISTRO=${{ matrix.ROS_DISTRO }} + target: ${{ github.job }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: ${{ env.PUSH }} + + desktop-nvidia: + strategy: + fail-fast: false + matrix: + ROS_DISTRO: [noetic] + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log into registry + if: env.PUSH == 'true' + uses: docker/login-action@v3.3.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + if: env.PUSH == 'true' + id: meta + uses: docker/metadata-action@v5.5.1 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=raw,value=${{ matrix.ROS_DISTRO }}-${{ github.job }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6.5.0 + with: + context: . + file: .docker/Dockerfile + build-args: ROS_DISTRO=${{ matrix.ROS_DISTRO }} + target: ${{ github.job }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: ${{ env.PUSH }} diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000..2024987 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,34 @@ +name: Formatting (pre-commit) + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +jobs: + pre-commit: + name: Format + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install clang-format-14 + run: sudo apt-get install clang-format-14 + + - name: Run pre-commit + uses: pre-commit/action@v3.0.1 + id: precommit + + - name: Upload pre-commit changes + if: failure() && steps.precommit.outcome == 'failure' + uses: rhaschke/upload-git-patch-action@main + with: + name: pre-commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f087a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# ROS +devel +install +log diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3d7d5be --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,45 @@ +repos: + - repo: https://github.com/psf/black + rev: 23.1.0 + hooks: + - id: black + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.291 + hooks: + - id: ruff + args: ["--fix", "--exit-non-zero-on-fix"] + + - repo: https://github.com/codespell-project/codespell + rev: v2.2.4 + hooks: + - id: codespell + args: ["--write-changes"] + + - repo: local + hooks: + - id: clang-format + name: clang-format + description: Format files with ClangFormat. + entry: clang-format-14 + language: system + files: \.(c|cc|cxx|cpp|frag|glsl|h|hpp|hxx|ih|ispc|ipp|java|js|m|proto|vert)$ + args: ['-fallback-style=Google', '-i'] + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-json + - id: check-toml + - id: check-yaml + - id: check-xml + - id: check-merge-conflict + - id: check-symlinks + - id: debug-statements + - id: destroyed-symlinks + - id: detect-private-key + - id: end-of-file-fixer + - id: mixed-line-ending + - id: trailing-whitespace diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..23e428e --- /dev/null +++ b/.ruff.toml @@ -0,0 +1 @@ +target-version = "py38" diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..061335b --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,14 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": ["${workspaceFolder}/**", "/opt/ros/noetic/include/**"], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c99", + "cppStandard": "c++17", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6113c11 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,75 @@ +{ + "files.associations": { + "*.repos": "yaml", + "*.world": "xml", + "*.xacro": "xml", + "*.srdf": "xml", + "*.rviz": "yaml", + "*.config": "xml", + "*.sdf": "xml" + }, + "terminal.integrated.defaultProfile.linux": "bash", + "terminal.integrated.profiles.linux": { + "bash": { + "path": "bash", + "icon": "terminal-bash", + "args": ["-i"] + } + }, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "editor.formatOnSave": true, + "editor.tabSize": 2, + "autoDocstring.startOnNewLine": false, + "autoDocstring.docstringFormat": "google-notypes", + "python.autoComplete.extraPaths": [ + "/opt/ros/noetic/local/lib/python3/dist-packages/", + "${workspaceFolder}/src/" + ], + "python.analysis.extraPaths": [ + "/opt/ros/noetic/local/lib/python3/dist-packages/", + "${workspaceFolder}/src/" + ], + "C_Cpp.default.intelliSenseMode": "linux-gcc-x86", + "C_Cpp.clang_format_fallbackStyle": "Google", + "C_Cpp.codeAnalysis.clangTidy.enabled": true, + "C_Cpp.codeAnalysis.clangTidy.codeAction.formatFixes": true, + "clang-format.executable": "/usr/bin/clang-format-12", + "[cpp]": { + "editor.rulers": [100], + "editor.tabSize": 2, + "editor.defaultFormatter": "xaver.clang-format" + }, + "[python]": { + "editor.tabSize": 4, + "editor.rulers": [90], + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit" + }, + "editor.defaultFormatter": "ms-python.black-formatter" + }, + "[dockerfile]": { + "editor.quickSuggestions": { + "strings": true + }, + "editor.defaultFormatter": "ms-azuretools.vscode-docker", + "editor.tabSize": 4 + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[xml]": { + "editor.defaultFormatter": "redhat.vscode-xml" + }, + "[markdown]": { + "editor.rulers": [80], + "editor.defaultFormatter": "DavidAnson.vscode-markdownlint" + }, + "search.exclude": { + "**/build": true, + "**/install": true, + "**/log": true + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..1c722b7 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,43 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "ROS: Build", + "detail": "Build the workspace using catkin", + "type": "shell", + "command": "catkin_make", + "options": { + "cwd": "${workspaceFolder}/../.." + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": ["$gcc"] + }, + { + "label": "ROS: Source workspace", + "detail": "Source the ROS workspace", + "type": "shell", + "command": "source devel/setup.bash", + "options": { + "cwd": "${workspaceFolder}/../.." + }, + "problemMatcher": [] + }, + { + "label": "ROS: Create package", + "detail": "Create a new ROS package", + "type": "shell", + "command": "catkin_create_pkg ${input:packageName}", + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "packageName", + "type": "promptString", + "description": "Package name" + } + ] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5f74df8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, Robotic Decision Making Lab + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..71f5d92 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# ROS Project Template + +Setting up a new ROS project often requires a significant amount of +preparation and boilerplate configuration, costing you valuable robot +development time 🤖. Recognizing this, we have put together this template +repository configured with a ROS development environment, continuous +integration, and more. This project is the result of much trial and error +across many projects, and we hope that this helps you save some effort in +setting up your own projects. + +## Features + +The main features of this template are: + +- A development environment for Visual Studio Code including a [development container](https://code.visualstudio.com/docs/devcontainers/containers) +and configurations for linting and auto-formatting your code +- Docker images that support deployment to a variety of systems (e.g., arm64 +systems) +- Continuous integration and deployment pipelines using GitHub Actions +- GitHub Issue and Pull Request templates + +## Quick start + +Using this template is as easy as 1, 2, 3... + +1. Use this repository [as a template](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template) +for your project +2. Replace all instances of "ros-template" with your own project's name and all +instances of "robotic-decision-making-lab" with your own user's name +3. Replace the source code with your own project! + +Feel free to remove any unused configurations/pipelines and to adjust things as +you see fit for your project! + +## Getting help + +If you have questions regarding usage of this project or would like to +contribute, please ask a question on our [Discussions](https://github.com/Robotic-Decision-Making-Lab/ros-template/discussions) +board! diff --git a/example_pkg/CMakeLists.txt b/example_pkg/CMakeLists.txt new file mode 100644 index 0000000..af9e427 --- /dev/null +++ b/example_pkg/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.8) +project(example_pkg) + +set(THIS_PACKAGE_INCLUDE_DEPENDS + catkin +) + +foreach(Dependency IN ITEMS ${THIS_PACKAGE_INCLUDE_DEPENDS}) + find_package(${Dependency} REQUIRED) +endforeach() diff --git a/example_pkg/LICENSE b/example_pkg/LICENSE new file mode 100644 index 0000000..5f74df8 --- /dev/null +++ b/example_pkg/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, Robotic Decision Making Lab + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/example_pkg/package.xml b/example_pkg/package.xml new file mode 100644 index 0000000..ef5343d --- /dev/null +++ b/example_pkg/package.xml @@ -0,0 +1,18 @@ + + + + + example_pkg + 0.0.1 + A sample ROS package + + Evan Palmer + MIT + + https://github.com/Robotic-Decision-Making-Lab/ros-template.git + https://github.com/Robotic-Decision-Making-Lab/ros-template/issues + + Evan Palmer + + catkin + diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..a3bd924 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +# Development tools not required for project installation +pre-commit +mypy diff --git a/ros2.repos b/ros2.repos new file mode 100644 index 0000000..e40c57b --- /dev/null +++ b/ros2.repos @@ -0,0 +1,7 @@ +# Add external repositories that your project depends on here. For example, +# repositories: +# +# ros_gz: +# type: git +# url: https://github.com/gazebosim/ros_gz +# version: ros2