diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..f1bd146
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,13 @@
+# See: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#about-the-dependabotyml-file
+version: 2
+
+updates:
+ # Configure check for outdated GitHub Actions actions in workflows.
+ # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/dependabot/README.md
+ # See: https://docs.github.com/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
+ - package-ecosystem: github-actions
+ directory: / # Check the repository's workflows under /.github/workflows/
+ schedule:
+ interval: daily
+ labels:
+ - "topic: ci"
diff --git a/.github/workflows/ros2.yml b/.github/workflows/ros2.yml
new file mode 100644
index 0000000..9ec1f6b
--- /dev/null
+++ b/.github/workflows/ros2.yml
@@ -0,0 +1,52 @@
+name: ros2
+
+on:
+ push:
+ paths:
+ - ".github/workflows/ros2.yml"
+ - "include/**"
+ - "launch/**"
+ - "src/**"
+ - "CMakeLists.txt"
+ - "package.xml"
+ pull_request:
+ paths:
+ - ".github/workflows/ros2.yml"
+ - "include/**"
+ - "launch/**"
+ - "src/**"
+ - "CMakeLists.txt"
+ - "package.xml"
+
+env:
+ BUILD_TYPE: Release
+
+jobs:
+ build:
+ name: Build on ros2 ${{ matrix.ros_distro }}
+ runs-on: ubuntu-22.04
+ strategy:
+ matrix:
+ ros_distro: [ humble ]
+
+ steps:
+ - uses: ros-tooling/setup-ros@v0.7
+ with:
+ required-ros-distributions: ${{ matrix.ros_distro }}
+
+ - name: Setup ros2 workspace
+ run: |
+ source /opt/ros/${{ matrix.ros_distro }}/setup.bash
+ mkdir -p ${{github.workspace}}/ros2_ws/src
+ cd ${{github.workspace}}/ros2_ws
+ colcon build
+
+ - uses: actions/checkout@v4
+ with:
+ path: 'ros2_ws/src/t07_ros'
+
+ - name: colcon build
+ run: |
+ source /opt/ros/${{ matrix.ros_distro }}/setup.bash
+ cd ${{github.workspace}}/ros2_ws
+ colcon build --event-handlers console_direct+
diff --git a/.github/workflows/spell-check.yml b/.github/workflows/spell-check.yml
new file mode 100644
index 0000000..5552860
--- /dev/null
+++ b/.github/workflows/spell-check.yml
@@ -0,0 +1,26 @@
+# Source: https://github.com/per1234/.github/blob/main/workflow-templates/spell-check.md
+name: Spell Check
+
+# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
+on:
+ push:
+ pull_request:
+ schedule:
+ # Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates.
+ - cron: "0 8 * * TUE"
+ workflow_dispatch:
+ repository_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ spellcheck:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Spell check
+ uses: codespell-project/actions-codespell@master
diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml
new file mode 100644
index 0000000..b580030
--- /dev/null
+++ b/.github/workflows/sync-labels.yml
@@ -0,0 +1,132 @@
+# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md
+name: Sync Labels
+
+# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
+on:
+ push:
+ paths:
+ - ".github/workflows/sync-labels.ya?ml"
+ - ".github/label-configuration-files/*.ya?ml"
+ pull_request:
+ paths:
+ - ".github/workflows/sync-labels.ya?ml"
+ - ".github/label-configuration-files/*.ya?ml"
+ schedule:
+ # run every Tuesday at 3 AM UTC
+ - cron: "0 3 * * 2"
+ workflow_dispatch:
+ repository_dispatch:
+
+env:
+ CONFIGURATIONS_FOLDER: .github/label-configuration-files
+ CONFIGURATIONS_ARTIFACT: label-configuration-files
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Download JSON schema for labels configuration file
+ id: download-schema
+ uses: carlosperate/download-file-action@v2.0.1
+ with:
+ file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json
+ location: ${{ runner.temp }}/label-configuration-schema
+
+ - name: Install JSON schema validator
+ run: |
+ sudo npm install \
+ --global \
+ ajv-cli \
+ ajv-formats
+
+ - name: Validate local labels configuration
+ run: |
+ # See: https://github.com/ajv-validator/ajv-cli#readme
+ ajv validate \
+ --all-errors \
+ -c ajv-formats \
+ -s "${{ steps.download-schema.outputs.file-path }}" \
+ -d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}"
+
+ download:
+ needs: check
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ filename:
+ # Filenames of the shared configurations to apply to the repository in addition to the local configuration.
+ # https://github.com/107-systems/.github/blob/main/workflow-templates/assets/sync-labels
+ - universal.yml
+
+ steps:
+ - name: Download
+ uses: carlosperate/download-file-action@v2.0.1
+ with:
+ file-url: https://raw.githubusercontent.com/107-systems/.github/main/workflow-templates/assets/sync-labels/${{ matrix.filename }}
+
+ - name: Pass configuration files to next job via workflow artifact
+ uses: actions/upload-artifact@v3
+ with:
+ path: |
+ *.yaml
+ *.yml
+ if-no-files-found: error
+ name: ${{ env.CONFIGURATIONS_ARTIFACT }}
+
+ sync:
+ needs: download
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Set environment variables
+ run: |
+ # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
+ echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV"
+
+ - name: Determine whether to dry run
+ id: dry-run
+ if: >
+ github.event == 'pull_request' ||
+ github.ref != format('refs/heads/{0}', github.event.repository.default_branch)
+ run: |
+ # Use of this flag in the github-label-sync command will cause it to only check the validity of the
+ # configuration.
+ echo "::set-output name=flag::--dry-run"
+
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Download configuration files artifact
+ uses: actions/download-artifact@v3
+ with:
+ name: ${{ env.CONFIGURATIONS_ARTIFACT }}
+ path: ${{ env.CONFIGURATIONS_FOLDER }}
+
+ - name: Remove unneeded artifact
+ uses: geekyeggo/delete-artifact@v2
+ with:
+ name: ${{ env.CONFIGURATIONS_ARTIFACT }}
+
+ - name: Merge label configuration files
+ run: |
+ # Merge all configuration files
+ shopt -s extglob
+ cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}"
+
+ - name: Install github-label-sync
+ run: sudo npm install --global github-label-sync
+
+ - name: Sync labels
+ env:
+ GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ # See: https://github.com/Financial-Times/github-label-sync
+ github-label-sync \
+ --labels "${{ env.MERGED_CONFIGURATION_PATH }}" \
+ ${{ steps.dry-run.outputs.flag }} \
+ ${{ github.repository }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..86cc9ec
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+build
+log
+install
+**/__pycache__
+.vscode
+.idea/
+cmake-build-debug/
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..fc9ff97
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,40 @@
+#######################################################################################
+cmake_minimum_required(VERSION 3.8)
+#######################################################################################
+project(t07_ros)
+set(T07_ROS_TARGET ${PROJECT_NAME}_node)
+#######################################################################################
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ add_compile_options(-Wall -Wextra -Wpedantic)
+endif()
+#######################################################################################
+# find dependencies
+find_package(ament_cmake REQUIRED)
+find_package(rclcpp REQUIRED)
+#######################################################################################
+include_directories(
+ include
+)
+#######################################################################################
+add_executable(${T07_ROS_TARGET}
+ src/Node.cpp
+ src/main.cpp
+)
+#######################################################################################
+target_compile_features(${T07_ROS_TARGET} PRIVATE cxx_std_17)
+ament_target_dependencies(${T07_ROS_TARGET} rclcpp)
+#######################################################################################
+if(BUILD_TESTING)
+ find_package(ament_lint_auto REQUIRED)
+ # the following line skips the linter which checks for copyrights
+ # comment the line when a copyright and license is added to all source files
+ set(ament_cmake_copyright_FOUND TRUE)
+ # the following line skips cpplint (only works in a git repo)
+ # comment the line when this package is in a git repo and when
+ # a copyright and license is added to all source files
+ set(ament_cmake_cpplint_FOUND TRUE)
+ ament_lint_auto_find_test_dependencies()
+endif()
+#######################################################################################
+ament_package()
+#######################################################################################
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..b154e47
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Alexander Entinger, MSc / LXRobotics GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8548d6f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+
+:floppy_disk: `t07_ros`
+=======================
+[![Build Status](https://github.com/107-systems/l3xz_joy/actions/workflows/ros2.yml/badge.svg)](https://github.com/107-systems/l3xz_joy/actions/workflows/ros2.yml)
+[![Spell Check status](https://github.com/107-systems/l3xz_joy/actions/workflows/spell-check.yml/badge.svg)](https://github.com/107-systems/l3xz_joy/actions/workflows/spell-check.yml)
+
+ROS control code for the [T07](https://github.com/107-systems/T07) robot.
+
+#### How-to-build
+```bash
+cd $COLCON_WS/src
+git clone https://github.com/107-systems/t07_ros
+cd $COLCON_WS
+source /opt/ros/humble/setup.bash
+colcon build --packages-select t07_ros
+```
+
+#### How-to-run
+```bash
+cd $COLCON_WS
+. install/setup.bash
+ros2 launch t07_ros t07.py
+```
+
+#### Interface Documentation
+##### Published Topics
+| Default name | Type |
+|:------------:|:------------------------------------------------------------------------------:|
+
+##### Parameters
+| Name | Default | Description |
+|:-------------------------------------:|:----------------:|-----------------------------------------------------------------------------------------------|
diff --git a/include/t07_ros/Node.h b/include/t07_ros/Node.h
new file mode 100644
index 0000000..a7a8dd3
--- /dev/null
+++ b/include/t07_ros/Node.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2023 LXRobotics GmbH.
+ * Author: Alexander Entinger
+ * Contributors: https://github.com/107-systems/t07_ros/graphs/contributors.
+ */
+
+#pragma once
+
+/**************************************************************************************
+ * INCLUDE
+ **************************************************************************************/
+
+#include
+
+/**************************************************************************************
+ * NAMESPACE
+ **************************************************************************************/
+
+namespace t07
+{
+
+/**************************************************************************************
+ * CLASS DECLARATION
+ **************************************************************************************/
+
+class Node : public rclcpp::Node
+{
+public:
+ Node();
+ ~Node();
+
+private:
+};
+
+/**************************************************************************************
+ * NAMESPACE
+ **************************************************************************************/
+
+} /* t07 */
diff --git a/launch/t07.py b/launch/t07.py
new file mode 100644
index 0000000..ee894c5
--- /dev/null
+++ b/launch/t07.py
@@ -0,0 +1,16 @@
+from launch import LaunchDescription
+from launch_ros.actions import Node
+
+def generate_launch_description():
+ return LaunchDescription([
+ Node(
+ package='t07_ros',
+ executable='t07_ros_node',
+ name='t07_ros',
+ namespace='t07',
+ output='screen',
+ emulate_tty=True,
+ parameters=[
+ ]
+ )
+ ])
diff --git a/package.xml b/package.xml
new file mode 100644
index 0000000..e5bab6b
--- /dev/null
+++ b/package.xml
@@ -0,0 +1,20 @@
+
+
+
+ t07_ros
+ 1.0.0
+ ROS control code for the T07 robot.
+ alex
+ MIT
+
+ ament_cmake
+
+ rclcpp
+
+ ament_lint_auto
+ ament_lint_common
+
+
+ ament_cmake
+
+
diff --git a/src/Node.cpp b/src/Node.cpp
new file mode 100644
index 0000000..d486780
--- /dev/null
+++ b/src/Node.cpp
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2023 LXRobotics GmbH.
+ * Author: Alexander Entinger
+ * Contributors: https://github.com/107-systems/t07_ros/graphs/contributors.
+ */
+
+/**************************************************************************************
+ * INCLUDE
+ **************************************************************************************/
+
+#include
+
+/**************************************************************************************
+ * NAMESPACE
+ **************************************************************************************/
+
+namespace t07
+{
+
+/**************************************************************************************
+ * CTOR/DTOR
+ **************************************************************************************/
+
+Node::Node()
+: rclcpp::Node("t07_ros_node")
+{
+}
+
+Node::~Node()
+{
+}
+
+/**************************************************************************************
+ * PRIVATE MEMBER FUNCTIONS
+ **************************************************************************************/
+
+/**************************************************************************************
+ * NAMESPACE
+ **************************************************************************************/
+
+} /* t07 */
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..11324d6
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2023 LXRobotics GmbH.
+ * Author: Alexander Entinger
+ * Contributors: https://github.com/107-systems/t07_ros/graphs/contributors.
+ */
+
+/**************************************************************************************
+ * INCLUDE
+ **************************************************************************************/
+
+#include
+
+#include
+
+/**************************************************************************************
+ * MAIN
+ **************************************************************************************/
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = std::make_shared();
+
+ try
+ {
+ rclcpp::spin(node);
+ rclcpp::shutdown();
+ return EXIT_SUCCESS;
+ }
+ catch (std::runtime_error const & err)
+ {
+ RCLCPP_ERROR(rclcpp::get_logger(node->get_name()), "Exception (std::runtime_error) caught: %s\nTerminating ...", err.what());
+ return EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ RCLCPP_ERROR(rclcpp::get_logger(node->get_name()), "Unhandled exception caught.\nTerminating ...");
+ return EXIT_FAILURE;
+ }
+}