From 84d03f79ff96618df1693a5fab8e29c377e82140 Mon Sep 17 00:00:00 2001 From: Lennart Reiher Date: Tue, 10 Sep 2024 20:47:28 +0000 Subject: [PATCH] add file and folder structure for ros2_python_pkg template --- copier.yml | 26 ++++++------ .../CMakeLists.txt.jinja | 12 ++++++ .../action/Fibonacci.action | 5 +++ .../package.xml.jinja | 24 +++++++++++ .../{{ package_name }}/package.xml.jinja | 22 ++++++++++ .../resource/{{ package_name }}.jinja | 0 .../{{ package_name }}/setup.cfg.jinja | 4 ++ .../{{ package_name }}/setup.py.jinja | 29 +++++++++++++ ...cker_ros %}.gitlab-ci.yml{% endif %}.jinja | 8 ++++ ...{{ node_name }}_launch.py{% endif %}.jinja | 42 +++++++++++++++++++ ...{ node_name }}_launch.xml{% endif %}.jinja | 12 ++++++ ...{ node_name }}_launch.yml{% endif %}.jinja | 20 +++++++++ .../params.yml.jinja | 3 ++ .../{{ package_name }}/__init__.py | 0 .../{{ node_name }}.py.jinja | 19 +++++++++ 15 files changed, 213 insertions(+), 13 deletions(-) create mode 100644 templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/CMakeLists.txt.jinja create mode 100644 templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/action/Fibonacci.action create mode 100644 templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/package.xml.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/package.xml.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/resource/{{ package_name }}.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/setup.cfg.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/setup.py.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/{% if has_docker_ros %}.gitlab-ci.yml{% endif %}.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'py' %}{{ node_name }}_launch.py{% endif %}.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'xml' %}{{ node_name }}_launch.xml{% endif %}.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'yml' %}{{ node_name }}_launch.yml{% endif %}.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/{% if has_params %}config{% endif %}/params.yml.jinja create mode 100644 templates/ros2_python_pkg/{{ package_name }}/{{ package_name }}/__init__.py create mode 100644 templates/ros2_python_pkg/{{ package_name }}/{{ package_name }}/{{ node_name }}.py.jinja diff --git a/copier.yml b/copier.yml index 887d50c..5e92e79 100644 --- a/copier.yml +++ b/copier.yml @@ -12,12 +12,12 @@ template: help: Template type: str default: ros2_cpp_pkg - choices: [ros2_cpp_pkg, ros2_interfaces_pkg] + choices: [ros2_cpp_pkg, ros2_interfaces_pkg, ros2_python_pkg] package_name: help: Package name type: str - placeholder: ros2_cpp_pkg + placeholder: "{{ template }}" validator: "{% if not package_name %}Package name is required{% endif %}" description: @@ -53,13 +53,13 @@ license: node_name: help: Node name - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: str default: "{{ package_name }}" node_class_name: help: Class name of node - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: str default: "{{ node_name | to_camel }}" @@ -77,56 +77,56 @@ is_lifecycle: has_launch_file: help: Add a launch file? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: bool default: true launch_file_type: help: Type of launch file - when: "{{ template == 'ros2_cpp_pkg' and has_launch_file }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: str default: py choices: [py, xml, yml] has_params: help: Add parameter loading? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: bool default: true has_subscriber: help: Add a subscriber? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: bool default: true has_publisher: help: Add a publisher? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: bool default: true has_service_server: help: Add a service server? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: bool default: false has_action_server: help: Add an action server? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: bool default: false has_timer: help: Add a timer callback? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" type: bool default: false auto_shutdown: help: Automatically shutdown the node after launch (useful in CI/CD)? - when: "{{ template == 'ros2_cpp_pkg' }}" + when: "{{ template == 'ros2_cpp_pkg' or template == 'ros2_python_pkg' }}" when: false type: bool default: false diff --git a/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/CMakeLists.txt.jinja b/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/CMakeLists.txt.jinja new file mode 100644 index 0000000..d66679b --- /dev/null +++ b/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/CMakeLists.txt.jinja @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.8) +project({{ package_name }}_interfaces) + +find_package(rosidl_default_generators REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + action/Fibonacci.action +) + +ament_export_dependencies(rosidl_default_runtime) + +ament_package() diff --git a/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/action/Fibonacci.action b/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/action/Fibonacci.action new file mode 100644 index 0000000..32b18f2 --- /dev/null +++ b/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/action/Fibonacci.action @@ -0,0 +1,5 @@ +int32 order +--- +int32[] sequence +--- +int32[] partial_sequence \ No newline at end of file diff --git a/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/package.xml.jinja b/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/package.xml.jinja new file mode 100644 index 0000000..f7d17ba --- /dev/null +++ b/templates/ros2_python_pkg/{% if has_action_server %}{{ package_name }}_interfaces{% endif %}/package.xml.jinja @@ -0,0 +1,24 @@ + + + + + {{ package_name }}_interfaces + 0.0.0 + ROS interface definitions for {{ package_name }} + + {{ maintainer }} + {{ author }} + + {{ license }} + + ament_cmake + rosidl_default_generators + rosidl_default_runtime + + rosidl_interface_packages + + + ament_cmake + + + diff --git a/templates/ros2_python_pkg/{{ package_name }}/package.xml.jinja b/templates/ros2_python_pkg/{{ package_name }}/package.xml.jinja new file mode 100644 index 0000000..234e93f --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/package.xml.jinja @@ -0,0 +1,22 @@ + + + + + {{ package_name }} + 0.0.0 + {{ description }} + + {{ maintainer }} + {{ author }} + + {{ license }} + + ament_python + + rclpy + + + ament_python + + + diff --git a/templates/ros2_python_pkg/{{ package_name }}/resource/{{ package_name }}.jinja b/templates/ros2_python_pkg/{{ package_name }}/resource/{{ package_name }}.jinja new file mode 100644 index 0000000..e69de29 diff --git a/templates/ros2_python_pkg/{{ package_name }}/setup.cfg.jinja b/templates/ros2_python_pkg/{{ package_name }}/setup.cfg.jinja new file mode 100644 index 0000000..e35a7b9 --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/setup.cfg.jinja @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/{{ package_name }} +[install] +install_scripts=$base/lib/{{ package_name }} diff --git a/templates/ros2_python_pkg/{{ package_name }}/setup.py.jinja b/templates/ros2_python_pkg/{{ package_name }}/setup.py.jinja new file mode 100644 index 0000000..6f65446 --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/setup.py.jinja @@ -0,0 +1,29 @@ +import os +from glob import glob +from setuptools import setup + +package_name = '{{ package_name }}' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + (os.path.join('share', package_name), ['package.xml']), + (os.path.join('share', package_name, + 'launch'), glob('launch/*launch.[pxy][yma]*')), + (os.path.join('share', package_name, + 'config'), glob('config/*.yaml'))], + install_requires=['setuptools'], + zip_safe=True, + maintainer='root', + maintainer_email='root@todo.todo', + description='TODO: Package description', + license='TODO: License declaration', + tests_require=['pytest'], + entry_points={ + 'console_scripts': + ['{{ node_name }} = {{ package_name }}.{{ node_name }}:main'], + }, +) diff --git a/templates/ros2_python_pkg/{{ package_name }}/{% if has_docker_ros %}.gitlab-ci.yml{% endif %}.jinja b/templates/ros2_python_pkg/{{ package_name }}/{% if has_docker_ros %}.gitlab-ci.yml{% endif %}.jinja new file mode 100644 index 0000000..c01306a --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/{% if has_docker_ros %}.gitlab-ci.yml{% endif %}.jinja @@ -0,0 +1,8 @@ +include: + - remote: https://raw.githubusercontent.com/ika-rwth-aachen/docker-ros/main/.gitlab-ci/docker-ros.yml + +variables: + PLATFORM: amd64,arm64 + TARGET: dev,run + BASE_IMAGE: rwthika/ros2:latest + COMMAND: ros2 run {{ package_name }} {{ node_name }} diff --git a/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'py' %}{{ node_name }}_launch.py{% endif %}.jinja b/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'py' %}{{ node_name }}_launch.py{% endif %}.jinja new file mode 100644 index 0000000..8fbd350 --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'py' %}{{ node_name }}_launch.py{% endif %}.jinja @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import os + +from ament_index_python import get_package_share_directory +from launch import LaunchDescription +{% if is_lifecycle %} +from launch.actions import DeclareLaunchArgument, GroupAction +from launch.conditions import LaunchConfigurationNotEquals +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import LifecycleNode, SetParameter +{% else %} +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +{% endif %} + + +def generate_launch_description(): + + arg_name = DeclareLaunchArgument("name", default_value="{{ node_name }}", description="node name") + arg_namespace = DeclareLaunchArgument("namespace", default_value="", description="node namespace") + + node = Node( + package="{{ package_name }}", + executable="{{ node_name }}", + namespace=LaunchConfiguration("namespace"), + name=LaunchConfiguration("name"), +{% if has_params %} + parameters=[ + os.path.join(get_package_share_directory("{{ package_name }}"), "config", "params.yml"), + ], +{% endif %} + output="screen", + emulate_tty=True, + ) + + return LaunchDescription([ + arg_name, + arg_namespace, + node + ]) diff --git a/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'xml' %}{{ node_name }}_launch.xml{% endif %}.jinja b/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'xml' %}{{ node_name }}_launch.xml{% endif %}.jinja new file mode 100644 index 0000000..745aea4 --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'xml' %}{{ node_name }}_launch.xml{% endif %}.jinja @@ -0,0 +1,12 @@ + + + + + + +{% if has_params %} + +{% endif %} + + + diff --git a/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'yml' %}{{ node_name }}_launch.yml{% endif %}.jinja b/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'yml' %}{{ node_name }}_launch.yml{% endif %}.jinja new file mode 100644 index 0000000..3216122 --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/{% if has_launch_file %}launch{% endif %}/{% if launch_file_type == 'yml' %}{{ node_name }}_launch.yml{% endif %}.jinja @@ -0,0 +1,20 @@ +launch: + - arg: + name: name + default: {{ node_name }} + description: node name + - arg: + name: namespace + default: "" + description: node namespace + - node: + pkg: {{ package_name }} + exec: {{ node_name }} + namespace: "$(var namespace)" + name: "$(var name)" + output: screen +{% if has_params %} + param: + - name: param + value: 1.0 +{% endif %} diff --git a/templates/ros2_python_pkg/{{ package_name }}/{% if has_params %}config{% endif %}/params.yml.jinja b/templates/ros2_python_pkg/{{ package_name }}/{% if has_params %}config{% endif %}/params.yml.jinja new file mode 100644 index 0000000..809c91b --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/{% if has_params %}config{% endif %}/params.yml.jinja @@ -0,0 +1,3 @@ +/**/*: + ros__parameters: + param: 1.0 \ No newline at end of file diff --git a/templates/ros2_python_pkg/{{ package_name }}/{{ package_name }}/__init__.py b/templates/ros2_python_pkg/{{ package_name }}/{{ package_name }}/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/templates/ros2_python_pkg/{{ package_name }}/{{ package_name }}/{{ node_name }}.py.jinja b/templates/ros2_python_pkg/{{ package_name }}/{{ package_name }}/{{ node_name }}.py.jinja new file mode 100644 index 0000000..c52c018 --- /dev/null +++ b/templates/ros2_python_pkg/{{ package_name }}/{{ package_name }}/{{ node_name }}.py.jinja @@ -0,0 +1,19 @@ +import rclpy + +from rclpy import Node + + +class {{ node_class_name }}(Node): + def __init__(self): + pass + + +def main(): + + rclpy.init() + rclpy.spin({{ node_class_name }}()) + rclpy.shutdown() + + +if __name__ == "__main__": + main()