├── .github └── workflows │ └── sync-dua-template.yaml ├── .gitignore ├── .vscode ├── .gitignore ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── bin ├── dua-templates │ ├── Dockerfile.macos.template │ ├── Dockerfile.template │ ├── context │ │ ├── aliases.sh │ │ ├── bashrc │ │ ├── colcon-defaults.yaml.template │ │ ├── commands.sh │ │ ├── dua_submod.sh │ │ ├── dua_subtree.sh │ │ ├── gitignore-zsh_history │ │ ├── nanorc │ │ ├── p10k.zsh │ │ ├── ros2.sh │ │ ├── vimrc │ │ └── zshrc │ ├── devcontainer.json.template │ ├── docker-compose.yaml.macos.template │ ├── docker-compose.yaml.nvidia.template │ └── docker-compose.yaml.template ├── dua_setup.sh └── ros2_jazzy_install.sh ├── components.md ├── config ├── .gitkeep └── ros2_cmds.sh ├── docker ├── .gitkeep ├── container-armv8-dev │ ├── .devcontainer │ │ ├── devcontainer.json │ │ └── docker-compose.yaml │ ├── Dockerfile │ ├── aliases.sh │ ├── bashrc │ ├── colcon-defaults.yaml │ ├── commands.sh │ ├── dua_submod.sh │ ├── dua_subtree.sh │ ├── nanorc │ ├── p10k.zsh │ ├── ros2.sh │ ├── vimrc │ ├── zsh_history │ │ └── .gitignore │ └── zshrc ├── container-x86-cudev │ ├── .devcontainer │ │ ├── devcontainer.json │ │ └── docker-compose.yaml │ ├── Dockerfile │ ├── aliases.sh │ ├── bashrc │ ├── colcon-defaults.yaml │ ├── commands.sh │ ├── dua_submod.sh │ ├── dua_subtree.sh │ ├── nanorc │ ├── p10k.zsh │ ├── ros2.sh │ ├── vimrc │ ├── zsh_history │ │ └── .gitignore │ └── zshrc └── container-x86-dev │ ├── .devcontainer │ ├── devcontainer.json │ └── docker-compose.yaml │ ├── Dockerfile │ ├── aliases.sh │ ├── bashrc │ ├── colcon-defaults.yaml │ ├── commands.sh │ ├── dua_submod.sh │ ├── dua_subtree.sh │ ├── nanorc │ ├── p10k.zsh │ ├── ros2.sh │ ├── vimrc │ ├── zsh_history │ └── .gitignore │ └── zshrc ├── dua-template.md ├── interfaces.md ├── launch_files.md ├── logs └── .gitignore ├── ros2_cli_cheat_sheet.pdf ├── src ├── .gitkeep ├── cpp │ ├── actions_example_cpp │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── actions_example_cpp │ │ │ │ ├── fib_client.hpp │ │ │ │ └── fib_server.hpp │ │ ├── package.xml │ │ └── src │ │ │ ├── client_main.cpp │ │ │ ├── fib_client.cpp │ │ │ ├── fib_server.cpp │ │ │ └── server_main.cpp │ ├── advanced │ │ ├── complete_actions_cpp │ │ │ ├── CMakeLists.txt │ │ │ ├── include │ │ │ │ └── complete_actions_cpp │ │ │ │ │ ├── fib_client.hpp │ │ │ │ │ └── fib_server.hpp │ │ │ ├── package.xml │ │ │ └── src │ │ │ │ ├── client_main.cpp │ │ │ │ ├── fib_client.cpp │ │ │ │ ├── fib_server.cpp │ │ │ │ └── server_main.cpp │ │ ├── namespaces_examples │ │ │ ├── CMakeLists.txt │ │ │ ├── COLCON_IGNORE │ │ │ ├── include │ │ │ │ └── namespaces_examples │ │ │ │ │ └── topic_ns │ │ │ │ │ └── pub_srv.hpp │ │ │ ├── launch │ │ │ │ └── topics_ns.launch.py │ │ │ ├── package.xml │ │ │ └── src │ │ │ │ └── topics_ns │ │ │ │ ├── pub_srv.cpp │ │ │ │ └── topics_ns.cpp │ │ ├── ros2_examples_headers │ │ │ ├── CMakeLists.txt │ │ │ ├── include │ │ │ │ └── ros2_examples_headers │ │ │ │ │ └── signal_handler │ │ │ │ │ └── signal_handler.hpp │ │ │ └── package.xml │ │ └── smp_example │ │ │ ├── CMakeLists.txt │ │ │ ├── COLCON_IGNORE │ │ │ ├── include │ │ │ └── smp_example │ │ │ │ └── smp_example.hpp │ │ │ ├── package.xml │ │ │ └── src │ │ │ ├── pub_node.cpp │ │ │ ├── smp_example.cpp │ │ │ └── smp_node.cpp │ ├── custom_topic_cpp │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── custom_topic_cpp │ │ │ │ ├── pub.hpp │ │ │ │ └── sub.hpp │ │ ├── package.xml │ │ └── src │ │ │ ├── pub.cpp │ │ │ └── sub.cpp │ ├── image_processing │ │ ├── aruco_detector │ │ │ ├── CMakeLists.txt │ │ │ ├── config │ │ │ │ ├── bottom_detector.yaml │ │ │ │ ├── front_detector.yaml │ │ │ │ └── tilted_detector.yaml │ │ │ ├── include │ │ │ │ └── aruco_detector │ │ │ │ │ └── aruco_detector.hpp │ │ │ ├── launch │ │ │ │ ├── bottom_detector.launch.py │ │ │ │ ├── front_detector.launch.py │ │ │ │ └── tilted_detector.launch.py │ │ │ ├── package.xml │ │ │ └── src │ │ │ │ ├── aruco_detector │ │ │ │ ├── ad_services.cpp │ │ │ │ ├── ad_subscriptions.cpp │ │ │ │ ├── ad_utils.cpp │ │ │ │ └── aruco_detector.cpp │ │ │ │ └── aruco_detector_app.cpp │ │ ├── ros2_usb_camera │ │ │ ├── CMakeLists.txt │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── config │ │ │ │ ├── camera.yaml │ │ │ │ └── config.yaml │ │ │ ├── include │ │ │ │ └── usb_camera_driver │ │ │ │ │ └── usb_camera_driver.hpp │ │ │ ├── launch │ │ │ │ └── usb_camera_driver_app.launch.py │ │ │ ├── package.xml │ │ │ └── src │ │ │ │ ├── ucd_app.cpp │ │ │ │ └── usb_camera_driver │ │ │ │ ├── ucd_utils.cpp │ │ │ │ └── usb_camera_driver.cpp │ │ └── rqt_image_view │ │ │ ├── CHANGELOG.rst │ │ │ ├── CMakeLists.txt │ │ │ ├── include │ │ │ └── rqt_image_view │ │ │ │ ├── image_view.h │ │ │ │ └── ratio_layouted_frame.h │ │ │ ├── mainpage.dox │ │ │ ├── package.xml │ │ │ ├── plugin.xml │ │ │ ├── resource │ │ │ └── lena.png │ │ │ ├── scripts │ │ │ ├── image_publisher │ │ │ └── rqt_image_view │ │ │ ├── setup.py │ │ │ └── src │ │ │ └── rqt_image_view │ │ │ ├── image_view.cpp │ │ │ ├── image_view.ui │ │ │ └── ratio_layouted_frame.cpp │ ├── parameters_example_cpp │ │ ├── CMakeLists.txt │ │ ├── config │ │ │ └── node_parameters.yaml │ │ ├── include │ │ │ └── parameters_example │ │ │ │ └── parametric_node.hpp │ │ ├── launch │ │ │ ├── launch_param_dict.launch.py │ │ │ └── launch_param_example.launch.py │ │ ├── package.xml │ │ └── src │ │ │ ├── parametric_node.cpp │ │ │ └── parametric_pub.cpp │ ├── plugins_demo │ │ ├── polygon_base │ │ │ ├── CMakeLists.txt │ │ │ ├── include │ │ │ │ └── polygon_base │ │ │ │ │ └── polygon.hpp │ │ │ └── package.xml │ │ ├── polygons │ │ │ ├── CMakeLists.txt │ │ │ ├── include │ │ │ │ └── polygons │ │ │ │ │ ├── square.hpp │ │ │ │ │ ├── triangle.hpp │ │ │ │ │ └── visibility_control.h │ │ │ ├── package.xml │ │ │ ├── plugins.xml │ │ │ └── src │ │ │ │ ├── square.cpp │ │ │ │ └── triangle.cpp │ │ └── polygons_tester │ │ │ ├── CMakeLists.txt │ │ │ ├── package.xml │ │ │ └── src │ │ │ └── polygons_tester.cpp │ ├── pub_sub_components │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── pub_sub_components │ │ │ │ ├── pub.hpp │ │ │ │ └── sub.hpp │ │ ├── launch │ │ │ └── pub_sub_components.launch.py │ │ ├── package.xml │ │ └── src │ │ │ ├── pub.cpp │ │ │ ├── pub_main.cpp │ │ │ ├── sub.cpp │ │ │ └── sub_main.cpp │ ├── simple_service_cpp │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── simple_service_cpp │ │ │ │ └── simple_service.hpp │ │ ├── package.xml │ │ └── src │ │ │ ├── client.cpp │ │ │ └── server.cpp │ └── topic_pubsub_cpp │ │ ├── CMakeLists.txt │ │ ├── include │ │ └── topic_pubsub │ │ │ ├── pub.hpp │ │ │ └── sub.hpp │ │ ├── package.xml │ │ └── src │ │ ├── pub.cpp │ │ ├── resetting_sub.cpp │ │ └── sub.cpp ├── python │ ├── advanced │ │ └── .gitkeep │ └── topic_pubsub_py │ │ ├── package.xml │ │ ├── resource │ │ └── topic_pubsub_py │ │ ├── setup.cfg │ │ ├── setup.py │ │ ├── test │ │ ├── test_copyright.py │ │ ├── test_flake8.py │ │ └── test_pep257.py │ │ └── topic_pubsub_py │ │ ├── .gitignore │ │ ├── __init__.py │ │ ├── pub.py │ │ └── sub.py ├── ros2_examples_bringup │ ├── CMakeLists.txt │ ├── launch │ │ ├── image_processing_pipeline.launch.py │ │ ├── service_params.launch.py │ │ └── topic_params.launch.py │ └── package.xml └── ros2_examples_interfaces │ ├── CMakeLists.txt │ ├── action │ └── Fibonacci.action │ ├── msg │ └── String.msg │ ├── package.xml │ └── srv │ └── AddTwoInts.srv ├── tools ├── .gitkeep └── COLCON_IGNORE └── vscode_cheat_sheet_linux.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # ROS 2 workspace folders 2 | build/* 3 | install/* 4 | log/* 5 | 6 | # Uncomment the following to avoid pushing personal configurations 7 | # .vscode/ 8 | 9 | -------------------------------------------------------------------------------- /.vscode/.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliSense database files 2 | *.vc.db* 3 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "browse": { 6 | "databaseFilename": "${workspaceFolder}/.vscode/browse.vc.db", 7 | "limitSymbolsToIncludedHeaders": false 8 | }, 9 | "includePath": [ 10 | "${default}", 11 | "${workspaceFolder}/**", 12 | "/opt/ros/jazzy/include/**", 13 | "${workspaceFolder}/install/**", 14 | "/opt/ros/dua-utils/install/**", 15 | // Add subdirectories of install here to include interfaces, 16 | // headers, plugin base headers and everything else you need 17 | "/usr/local/**", 18 | "/usr/local/include" 19 | ], 20 | "defines": [], 21 | "compilerPath": "/usr/bin/g++", 22 | "cStandard": "c99", 23 | "cppStandard": "c++17", 24 | "intelliSenseMode": "linux-gcc-x64" 25 | } 26 | ], 27 | "version": 4 28 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | // Example launch of a python file 5 | { 6 | "name": "Python: Current File", 7 | "type": "python", 8 | "request": "launch", 9 | "program": "${file}", 10 | "console": "integratedTerminal", 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /bin/dua-templates/Dockerfile.template: -------------------------------------------------------------------------------- 1 | # DUA environment image. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | FROM dotxautomation/dua-foundation:TARGET 22 | 23 | # Change this if you encounter problems with the default user 24 | ARG USER_UID=1000 25 | 26 | ENV DEBIAN_FRONTEND=noninteractive 27 | 28 | # IMAGE SETUP START # 29 | # IMAGE SETUP END # 30 | 31 | # Create a user with Zsh as shell, hashed password, and add it to the sudoers 32 | # To generate the hashed password, run: 33 | # mkpasswd -m sha-512 PASSWORD duatemplate 34 | RUN (getent passwd ${USER_UID} || true) && userdel -r $(getent passwd ${USER_UID} | cut -d: -f1) 2>/dev/null || true; \ 35 | useradd -r -m -s /usr/bin/zsh -u ${USER_UID} -G adm,dialout,internal,plugdev,sudo,tty,video -p 'HPSW' neo 36 | ENV HOME=/home/neo 37 | 38 | # Create workspace directory: host workspaces will be mounted here 39 | RUN mkdir ${HOME}/workspace && \ 40 | chown neo:neo ${HOME}/workspace 41 | 42 | # Create directory for shell history file 43 | RUN mkdir ${HOME}/zsh_history && \ 44 | chown neo:neo ${HOME}/zsh_history 45 | 46 | # Create SSH directory for user 47 | RUN mkdir ${HOME}/.ssh 48 | 49 | # Create mount point for remote filesystems 50 | RUN mkdir -p /mnt/remote && \ 51 | chown neo:neo /mnt/remote 52 | 53 | # Switch to internal user 54 | USER neo 55 | WORKDIR ${HOME} 56 | 57 | # Copy user configuration files 58 | COPY --chown=neo:neo ./aliases.sh ./.aliases.sh 59 | COPY --chown=neo:neo ./bashrc ./.bashrc 60 | COPY --chown=neo:neo ./colcon-defaults.yaml /home/neo/.colcon/defaults.yaml 61 | COPY --chown=neo:neo ./commands.sh ./.commands.sh 62 | COPY --chown=neo:neo ./nanorc ./.nanorc 63 | COPY --chown=neo:neo ./ros2.sh ./.ros2.sh 64 | COPY --chown=neo:neo ./vimrc ./.vimrc 65 | 66 | # Configure Zsh for internal user 67 | ENV ZSH=${HOME}/.oh-my-zsh 68 | ENV ZSH_CUSTOM=${ZSH}/custom 69 | ENV ZSH_PLUGINS=${ZSH_CUSTOM}/plugins 70 | ENV ZSH_THEMES=${ZSH_CUSTOM}/themes 71 | RUN wget -qO- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | zsh || true 72 | RUN git clone --single-branch --branch 'master' --depth 1 https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_PLUGINS}/zsh-syntax-highlighting \ 73 | && git clone --single-branch --branch 'master' --depth 1 https://github.com/zsh-users/zsh-autosuggestions ${ZSH_PLUGINS}/zsh-autosuggestions \ 74 | && git clone --single-branch --depth 1 https://github.com/romkatv/powerlevel10k.git ${ZSH_THEMES}/powerlevel10k 75 | COPY --chown=neo:neo ./p10k.zsh ./.p10k.zsh 76 | COPY --chown=neo:neo ./zshrc ./.zshrc 77 | 78 | ENV DEBIAN_FRONTEND=dialog 79 | 80 | # By default, start a basic shell 81 | CMD ["bash"] 82 | -------------------------------------------------------------------------------- /bin/dua-templates/context/aliases.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Custom aliases for container internal shell. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add custom, general-purpose aliases here. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | alias ls='ls --color=auto' 27 | alias ll='ls -lah' 28 | alias valgrind-check='valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind.out' 29 | 30 | # Source DUA commands 31 | source ~/.dua_submod.sh 32 | source ~/.dua_subtree.sh 33 | 34 | # Routine to convert an angle in degrees [-180° +180°] to radians [-PI +PI]. 35 | function degrad { 36 | local angle_in_degrees="$1" 37 | angle_in_radians=$(python3 -c "import sys, math; angle=float(sys.argv[1]); print(math.radians((angle + 180) % 360 - 180))" "$angle_in_degrees") 38 | echo "$angle_in_radians" 39 | } 40 | 41 | # Routine to update dua-utils. 42 | function utils-update { 43 | local repos_file 44 | 45 | # Get the current shell 46 | local curr_shell 47 | curr_shell=$(ps -p $$ | awk 'NR==2 {print $4}') 48 | 49 | # Download new repos file 50 | if [ -f /opt/dua-utils_repos_base.yaml ]; then 51 | wget -O /opt/dua-utils_repos_base.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_base.yaml 52 | repos_file=/opt/dua-utils_repos_base.yaml 53 | elif [ -f /opt/dua-utils_repos_dev.yaml ]; then 54 | wget -O /opt/dua-utils_repos_dev.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_dev.yaml 55 | repos_file=/opt/dua-utils_repos_dev.yaml 56 | else 57 | echo >&2 "No repos file found." 58 | return 1 59 | fi 60 | 61 | # Perform updates 62 | if [ -x /opt/build_dua_utils.sh ]; then 63 | echo "Cloning and building dua-utils from $repos_file ..." 64 | sh -c "rm -rf /opt/ros/dua-utils/*" 65 | sh -c "/opt/build_dua_utils.sh jazzy $repos_file" 66 | else 67 | echo >&2 "No build script found." 68 | return 1 69 | fi 70 | 71 | # Source new installation 72 | source "/opt/ros/dua-utils/install/local_setup.$curr_shell" 73 | } 74 | 75 | # Routine to configure Cyclone DDS to use specific network interfaces. 76 | function cyclonedds-configure { 77 | local cyclonedds_uri='' 78 | for interface in "$@"; do 79 | cyclonedds_uri+="" 80 | done 81 | cyclonedds_uri+='' 82 | export CYCLONEDDS_URI="$cyclonedds_uri" 83 | } 84 | -------------------------------------------------------------------------------- /bin/dua-templates/context/colcon-defaults.yaml.template: -------------------------------------------------------------------------------- 1 | # Set options to configure colcon build environments for the current target 2 | { 3 | "build": { 4 | "packages-ignore": [] 5 | }, 6 | "test": { 7 | "packages-ignore": [] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /bin/dua-templates/context/commands.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Project-specific shell functions and commands. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add yours, some convenient ones are provided below. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | # shellcheck disable=SC1090 27 | -------------------------------------------------------------------------------- /bin/dua-templates/context/dua_submod.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # DUA submodules management function. 4 | # 5 | # Roberto Masocco 6 | # Alessandro Tenaglia 7 | # 8 | # June 14, 2024 9 | 10 | # Copyright 2024 dotX Automation s.r.l. 11 | # 12 | # Licensed under the Apache License, Version 2.0 (the "License"); 13 | # you may not use this file except in compliance with the License. 14 | # You may obtain a copy of the License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the License is distributed on an "AS IS" BASIS, 20 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | # See the License for the specific language governing permissions and 22 | # limitations under the License. 23 | 24 | function dua-submod { 25 | function usage { 26 | echo >&2 "Usage:" 27 | echo >&2 " dua-submod [update|status]" 28 | echo >&2 "See dua-template.md for more info." 29 | } 30 | 31 | if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then 32 | usage 33 | return 1 34 | fi 35 | 36 | # Function to update the submodules. 37 | function update { 38 | git submodule update --init --recursive 39 | } 40 | 41 | # Function to check the status of the submodules. 42 | function status { 43 | git submodule status --recursive 44 | } 45 | 46 | # Check if we have a command and run the specified function. 47 | case "${1-}" in 48 | update) 49 | shift 50 | update 51 | ;; 52 | status) 53 | shift 54 | status 55 | ;; 56 | *) 57 | echo >&2 "Unknown command: ${1-}" 58 | usage 59 | return 1 60 | ;; 61 | esac 62 | } 63 | -------------------------------------------------------------------------------- /bin/dua-templates/context/gitignore-zsh_history: -------------------------------------------------------------------------------- 1 | # Ignore all but this file 2 | * 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /bin/dua-templates/context/nanorc: -------------------------------------------------------------------------------- 1 | set tabsize 2 2 | set tabstospaces 3 | set linenumbers 4 | set titlecolor brightwhite,blue 5 | set numbercolor cyan 6 | set keycolor cyan 7 | set functioncolor green 8 | include "/usr/share/nano/*.nanorc" 9 | -------------------------------------------------------------------------------- /bin/dua-templates/context/vimrc: -------------------------------------------------------------------------------- 1 | " All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by 2 | " the call to :runtime you can find below. If you wish to change any of those 3 | " settings, you should do it in this file (/etc/vim/vimrc), since debian.vim 4 | " will be overwritten everytime an upgrade of the vim packages is performed. 5 | " It is recommended to make changes after sourcing debian.vim since it alters 6 | " the value of the 'compatible' option. 7 | 8 | " This line should not be removed as it ensures that various options are 9 | " properly set to work with the Vim-related packages available in Debian. 10 | runtime! debian.vim 11 | 12 | " Uncomment the next line to make Vim more Vi-compatible 13 | " NOTE: debian.vim sets 'nocompatible'. Setting 'compatible' changes numerous 14 | " options, so any other options should be set AFTER setting 'compatible'. 15 | "set compatible 16 | 17 | " Vim5 and later versions support syntax highlighting. Uncommenting the next 18 | " line enables syntax highlighting by default. 19 | if has("syntax") 20 | syntax on 21 | endif 22 | 23 | " If using a dark background within the editing area and syntax highlighting 24 | " turn on this option as well 25 | set background=dark 26 | 27 | " Uncomment the following to have Vim jump to the last position when 28 | " reopening a file 29 | "if has("autocmd") 30 | " au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif 31 | "endif 32 | 33 | " Uncomment the following to have Vim load indentation rules and plugins 34 | " according to the detected filetype. 35 | if has("autocmd") 36 | filetype plugin indent on 37 | endif 38 | 39 | " The following are commented out as they cause vim to behave a lot 40 | " differently from regular Vi. They are highly recommended though. 41 | set showcmd " Show (partial) command in status line. 42 | set showmatch " Show matching brackets. 43 | "set ignorecase " Do case insensitive matching 44 | set smartcase " Do smart case matching 45 | set incsearch " Incremental search 46 | "set autowrite " Automatically save before commands like :next and :make 47 | "set hidden " Hide buffers when they are abandoned 48 | set mouse=a " Enable mouse usage (all modes) 49 | 50 | " Source a global configuration file if available 51 | "if filereadable("/etc/vim/vimrc.local") 52 | "source /etc/vim/vimrc.local 53 | "endif 54 | 55 | " User commands and preferences. 56 | set tabstop=2 57 | set nu 58 | set colorcolumn=80 59 | set ruler 60 | -------------------------------------------------------------------------------- /bin/dua-templates/docker-compose.yaml.macos.template: -------------------------------------------------------------------------------- 1 | # DUA environment container management settings. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | services: 22 | SERVICE: 23 | build: 24 | context: ../ 25 | network: host 26 | dockerfile: Dockerfile 27 | args: 28 | - USER_UID=1000 29 | image: NAME:TARGET 30 | environment: 31 | TERM: xterm-256color 32 | DISPLAY: host.docker.internal:0 33 | SHELL: /usr/bin/zsh 34 | user: neo 35 | network_mode: "host" 36 | privileged: true 37 | ipc: host 38 | init: true 39 | stdin_open: false 40 | tty: true 41 | working_dir: /home/neo/workspace 42 | command: 43 | [ 44 | "/bin/bash", 45 | "-c", 46 | "trap 'exit 0' TERM; sleep infinity & wait" 47 | ] 48 | volumes: 49 | - ../../../:/home/neo/workspace 50 | - ../aliases.sh:/home/neo/.aliases.sh:rw 51 | - ../bashrc:/home/neo/.bashrc:rw 52 | - ../colcon-defaults.yaml:/home/neo/.colcon/defaults.yaml:rw 53 | - ../commands.sh:/home/neo/.commands.sh:rw 54 | - ../dua_submod.sh:/home/neo/.dua_submod.sh:rw 55 | - ../dua_subtree.sh:/home/neo/.dua_subtree.sh:rw 56 | - ../p10k.zsh:/home/neo/.p10k.zsh:rw 57 | - ../ros2.sh:/home/neo/.ros2.sh:rw 58 | - ../zshrc:/home/neo/.zshrc:rw 59 | - ../zsh_history:/home/neo/zsh_history 60 | - ~/.ssh:/home/neo/.ssh 61 | - ~/.gitconfig:/home/neo/.gitconfig 62 | - ~/.Xauthority:/home/neo/.Xauthority:rw 63 | - /dev:/dev 64 | - /sys:/sys 65 | - /etc/localtime:/etc/localtime:ro 66 | - /etc/timezone:/etc/timezone:ro 67 | -------------------------------------------------------------------------------- /bin/dua-templates/docker-compose.yaml.nvidia.template: -------------------------------------------------------------------------------- 1 | # DUA environment container management settings. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | services: 22 | SERVICE: 23 | build: 24 | context: ../ 25 | network: host 26 | dockerfile: Dockerfile 27 | args: 28 | - USER_UID=1000 29 | image: NAME:TARGET 30 | environment: 31 | TERM: xterm-256color 32 | DISPLAY: 33 | SHELL: /usr/bin/zsh 34 | user: neo 35 | network_mode: "host" 36 | privileged: true 37 | ipc: host 38 | init: true 39 | stdin_open: false 40 | tty: true 41 | working_dir: /home/neo/workspace 42 | command: 43 | [ 44 | "/bin/bash", 45 | "-c", 46 | "trap 'exit 0' TERM; sleep infinity & wait" 47 | ] 48 | volumes: 49 | - ../../../:/home/neo/workspace 50 | - ../aliases.sh:/home/neo/.aliases.sh:rw 51 | - ../bashrc:/home/neo/.bashrc:rw 52 | - ../colcon-defaults.yaml:/home/neo/.colcon/defaults.yaml:rw 53 | - ../commands.sh:/home/neo/.commands.sh:rw 54 | - ../dua_submod.sh:/home/neo/.dua_submod.sh:rw 55 | - ../dua_subtree.sh:/home/neo/.dua_subtree.sh:rw 56 | - ../p10k.zsh:/home/neo/.p10k.zsh:rw 57 | - ../ros2.sh:/home/neo/.ros2.sh:rw 58 | - ../zshrc:/home/neo/.zshrc:rw 59 | - ../zsh_history:/home/neo/zsh_history 60 | - ~/.ssh:/home/neo/.ssh 61 | - ~/.gitconfig:/home/neo/.gitconfig 62 | - ~/.Xauthority:/home/neo/.Xauthority:rw 63 | - /dev:/dev 64 | - /sys:/sys 65 | - /etc/localtime:/etc/localtime:ro 66 | - /etc/timezone:/etc/timezone:ro 67 | deploy: 68 | resources: 69 | reservations: 70 | devices: 71 | - driver: nvidia 72 | count: all 73 | capabilities: [ gpu ] 74 | -------------------------------------------------------------------------------- /bin/dua-templates/docker-compose.yaml.template: -------------------------------------------------------------------------------- 1 | # DUA environment container management settings. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | services: 22 | SERVICE: 23 | build: 24 | context: ../ 25 | network: host 26 | dockerfile: Dockerfile 27 | args: 28 | - USER_UID=1000 29 | image: NAME:TARGET 30 | environment: 31 | TERM: xterm-256color 32 | DISPLAY: 33 | SHELL: /usr/bin/zsh 34 | user: neo 35 | network_mode: "host" 36 | privileged: true 37 | ipc: host 38 | init: true 39 | stdin_open: false 40 | tty: true 41 | working_dir: /home/neo/workspace 42 | command: 43 | [ 44 | "/bin/bash", 45 | "-c", 46 | "trap 'exit 0' TERM; sleep infinity & wait" 47 | ] 48 | volumes: 49 | - ../../../:/home/neo/workspace 50 | - ../aliases.sh:/home/neo/.aliases.sh:rw 51 | - ../bashrc:/home/neo/.bashrc:rw 52 | - ../colcon-defaults.yaml:/home/neo/.colcon/defaults.yaml:rw 53 | - ../commands.sh:/home/neo/.commands.sh:rw 54 | - ../dua_submod.sh:/home/neo/.dua_submod.sh:rw 55 | - ../dua_subtree.sh:/home/neo/.dua_subtree.sh:rw 56 | - ../p10k.zsh:/home/neo/.p10k.zsh:rw 57 | - ../ros2.sh:/home/neo/.ros2.sh:rw 58 | - ../zshrc:/home/neo/.zshrc:rw 59 | - ../zsh_history:/home/neo/zsh_history 60 | - ~/.ssh:/home/neo/.ssh 61 | - ~/.gitconfig:/home/neo/.gitconfig 62 | - ~/.Xauthority:/home/neo/.Xauthority:rw 63 | - /dev:/dev 64 | - /sys:/sys 65 | - /etc/localtime:/etc/localtime:ro 66 | - /etc/timezone:/etc/timezone:ro 67 | -------------------------------------------------------------------------------- /bin/ros2_jazzy_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ROS 2 Jazzy Jalisco installation script. 4 | # Roberto Masocco 5 | # April 23, 2025 6 | # Copyright (c) 2025 Roberto Masocco 7 | 8 | set -o errexit 9 | set -o nounset 10 | set -o pipefail 11 | if [[ "${TRACE-0}" == "1" ]]; then set -o xtrace; fi 12 | 13 | if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then 14 | echo >&2 "Usage:" 15 | echo >&2 " ros2_jazzy_install.sh" 16 | exit 1 17 | fi 18 | 19 | echo "Checking Universe repository..." 20 | if ! apt-cache policy | grep -q 'universe'; then 21 | sudo apt install software-properties-common 22 | sudo add-apt-repository universe 23 | fi 24 | 25 | echo "Adding ROS 2 apt repository..." 26 | sudo apt update && sudo apt install -y curl gnupg lsb-release python3 python3-pip 27 | sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg 28 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu noble main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null 29 | sudo apt update 30 | 31 | echo "Installing ROS 2 main packages..." 32 | sudo apt install -y \ 33 | ros-dev-tools \ 34 | ros-jazzy-actuator-msgs \ 35 | ros-jazzy-ament-lint \ 36 | ros-jazzy-angles \ 37 | ros-jazzy-cv-bridge \ 38 | ros-jazzy-diagnostic-msgs \ 39 | ros-jazzy-diagnostic-updater \ 40 | ros-jazzy-eigen3-cmake-module \ 41 | ros-jazzy-filters \ 42 | ros-jazzy-geographic-msgs \ 43 | ros-jazzy-geographic-info \ 44 | ros-jazzy-gps-msgs \ 45 | ros-jazzy-gps-tools \ 46 | ros-jazzy-gps-umd \ 47 | ros-jazzy-gpsd-client \ 48 | ros-jazzy-image-common \ 49 | ros-jazzy-image-geometry \ 50 | ros-jazzy-image-pipeline \ 51 | ros-jazzy-image-transport \ 52 | ros-jazzy-image-transport-plugins \ 53 | ros-jazzy-joint-state-publisher \ 54 | ros-jazzy-laser-filters \ 55 | ros-jazzy-launch-testing \ 56 | ros-jazzy-launch-testing-ament-cmake \ 57 | ros-jazzy-launch-testing-ros \ 58 | ros-jazzy-perception \ 59 | ros-jazzy-perception-pcl \ 60 | ros-jazzy-rmw-cyclonedds-cpp \ 61 | ros-jazzy-rmw-fastrtps-cpp \ 62 | ros-jazzy-rmw-zenoh-cpp \ 63 | ros-jazzy-robot-state-publisher \ 64 | ros-jazzy-desktop \ 65 | ros-jazzy-rosidl-generator-dds-idl \ 66 | ros-jazzy-rqt-robot-steering \ 67 | ros-jazzy-vision-msgs \ 68 | ros-jazzy-vision-opencv \ 69 | ros-jazzy-xacro 70 | -------------------------------------------------------------------------------- /config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/config/.gitkeep -------------------------------------------------------------------------------- /config/ros2_cmds.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Useful functions and stuff to manage ROS 2 from the shell. 4 | # Roberto Masocco 5 | # January 31, 2023 6 | # Copyright (c) 2025 Roberto Masocco 7 | 8 | # Initialize ROS 2 Jazzy Jalisco according to the shell 9 | if [[ $# -ne 0 ]]; then 10 | export ROS_DOMAIN_ID=$1 11 | fi 12 | export ROS_VERSION=2 13 | export ROS_PYTHON_VERSION=3 14 | if [[ ! -d /opt/ros/jazzy ]]; then 15 | echo >&2 "No ROS 2 distribution installed!" 16 | return 1 17 | fi 18 | export ROS_DISTRO=jazzy 19 | export RMW_IMPLEMENTATION=rmw_fastrtps_cpp 20 | current_shell=$(ps -p $$ | awk 'NR==2 {print $4}') 21 | 22 | # Source the ROS 2 installation according to the current shell 23 | if echo "$current_shell" | grep -q 'bash'; then 24 | source /opt/ros/$ROS_DISTRO/setup.bash 25 | source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash 26 | elif echo "$current_shell" | grep -q 'zsh'; then 27 | source /opt/ros/$ROS_DISTRO/setup.zsh 28 | source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.zsh 29 | # echo "Remember to source install/local_setup.zsh in your workspaces!" 30 | else 31 | source /opt/ros/$ROS_DISTRO/setup.sh 32 | fi 33 | -------------------------------------------------------------------------------- /docker/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/docker/.gitkeep -------------------------------------------------------------------------------- /docker/container-armv8-dev/.devcontainer/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # DUA environment container management settings. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | services: 22 | ros2-examples-armv8-dev: 23 | build: 24 | context: ../ 25 | network: host 26 | dockerfile: Dockerfile 27 | args: 28 | - USER_UID=1000 29 | image: ros2-examples:armv8-dev 30 | environment: 31 | TERM: xterm-256color 32 | DISPLAY: 33 | SHELL: /usr/bin/zsh 34 | user: neo 35 | network_mode: "host" 36 | privileged: true 37 | ipc: host 38 | init: true 39 | stdin_open: false 40 | tty: true 41 | working_dir: /home/neo/workspace 42 | command: 43 | [ 44 | "/bin/bash", 45 | "-c", 46 | "trap 'exit 0' TERM; sleep infinity & wait" 47 | ] 48 | volumes: 49 | - ../../../:/home/neo/workspace 50 | - ../aliases.sh:/home/neo/.aliases.sh:rw 51 | - ../bashrc:/home/neo/.bashrc:rw 52 | - ../colcon-defaults.yaml:/home/neo/.colcon/defaults.yaml:rw 53 | - ../commands.sh:/home/neo/.commands.sh:rw 54 | - ../dua_submod.sh:/home/neo/.dua_submod.sh:rw 55 | - ../dua_subtree.sh:/home/neo/.dua_subtree.sh:rw 56 | - ../p10k.zsh:/home/neo/.p10k.zsh:rw 57 | - ../ros2.sh:/home/neo/.ros2.sh:rw 58 | - ../zshrc:/home/neo/.zshrc:rw 59 | - ../zsh_history:/home/neo/zsh_history 60 | - ~/.ssh:/home/neo/.ssh 61 | - ~/.gitconfig:/home/neo/.gitconfig 62 | - ~/.Xauthority:/home/neo/.Xauthority:rw 63 | - /dev:/dev 64 | - /sys:/sys 65 | - /etc/localtime:/etc/localtime:ro 66 | - /etc/timezone:/etc/timezone:ro 67 | -------------------------------------------------------------------------------- /docker/container-armv8-dev/aliases.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Custom aliases for container internal shell. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add custom, general-purpose aliases here. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | alias ls='ls --color=auto' 27 | alias ll='ls -lah' 28 | alias valgrind-check='valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind.out' 29 | 30 | # Source DUA commands 31 | source ~/.dua_submod.sh 32 | source ~/.dua_subtree.sh 33 | 34 | # Routine to convert an angle in degrees [-180° +180°] to radians [-PI +PI]. 35 | function degrad { 36 | local angle_in_degrees="$1" 37 | angle_in_radians=$(python3 -c "import sys, math; angle=float(sys.argv[1]); print(math.radians((angle + 180) % 360 - 180))" "$angle_in_degrees") 38 | echo "$angle_in_radians" 39 | } 40 | 41 | # Routine to update dua-utils. 42 | function utils-update { 43 | local repos_file 44 | 45 | # Get the current shell 46 | local curr_shell 47 | curr_shell=$(ps -p $$ | awk 'NR==2 {print $4}') 48 | 49 | # Download new repos file 50 | if [ -f /opt/dua-utils_repos_base.yaml ]; then 51 | wget -O /opt/dua-utils_repos_base.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_base.yaml 52 | repos_file=/opt/dua-utils_repos_base.yaml 53 | elif [ -f /opt/dua-utils_repos_dev.yaml ]; then 54 | wget -O /opt/dua-utils_repos_dev.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_dev.yaml 55 | repos_file=/opt/dua-utils_repos_dev.yaml 56 | else 57 | echo >&2 "No repos file found." 58 | return 1 59 | fi 60 | 61 | # Perform updates 62 | if [ -x /opt/build_dua_utils.sh ]; then 63 | echo "Cloning and building dua-utils from $repos_file ..." 64 | sh -c "rm -rf /opt/ros/dua-utils/*" 65 | sh -c "/opt/build_dua_utils.sh jazzy $repos_file" 66 | else 67 | echo >&2 "No build script found." 68 | return 1 69 | fi 70 | 71 | # Source new installation 72 | source "/opt/ros/dua-utils/install/local_setup.$curr_shell" 73 | } 74 | 75 | # Routine to configure Cyclone DDS to use specific network interfaces. 76 | function cyclonedds-configure { 77 | local cyclonedds_uri='' 78 | for interface in "$@"; do 79 | cyclonedds_uri+="" 80 | done 81 | cyclonedds_uri+='' 82 | export CYCLONEDDS_URI="$cyclonedds_uri" 83 | } 84 | -------------------------------------------------------------------------------- /docker/container-armv8-dev/colcon-defaults.yaml: -------------------------------------------------------------------------------- 1 | # Set options to configure colcon build environments for the current target 2 | { 3 | "build": { 4 | "packages-ignore": [] 5 | }, 6 | "test": { 7 | "packages-ignore": [] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docker/container-armv8-dev/commands.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Project-specific shell functions and commands. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add yours, some convenient ones are provided below. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | # shellcheck disable=SC1090 27 | -------------------------------------------------------------------------------- /docker/container-armv8-dev/dua_submod.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # DUA submodules management function. 4 | # 5 | # Roberto Masocco 6 | # Alessandro Tenaglia 7 | # 8 | # June 14, 2024 9 | 10 | # Copyright 2024 dotX Automation s.r.l. 11 | # 12 | # Licensed under the Apache License, Version 2.0 (the "License"); 13 | # you may not use this file except in compliance with the License. 14 | # You may obtain a copy of the License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the License is distributed on an "AS IS" BASIS, 20 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | # See the License for the specific language governing permissions and 22 | # limitations under the License. 23 | 24 | function dua-submod { 25 | function usage { 26 | echo >&2 "Usage:" 27 | echo >&2 " dua-submod [update|status]" 28 | echo >&2 "See dua-template.md for more info." 29 | } 30 | 31 | if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then 32 | usage 33 | return 1 34 | fi 35 | 36 | # Function to update the submodules. 37 | function update { 38 | git submodule update --init --recursive 39 | } 40 | 41 | # Function to check the status of the submodules. 42 | function status { 43 | git submodule status --recursive 44 | } 45 | 46 | # Check if we have a command and run the specified function. 47 | case "${1-}" in 48 | update) 49 | shift 50 | update 51 | ;; 52 | status) 53 | shift 54 | status 55 | ;; 56 | *) 57 | echo >&2 "Unknown command: ${1-}" 58 | usage 59 | return 1 60 | ;; 61 | esac 62 | } 63 | -------------------------------------------------------------------------------- /docker/container-armv8-dev/nanorc: -------------------------------------------------------------------------------- 1 | set tabsize 2 2 | set tabstospaces 3 | set linenumbers 4 | set titlecolor brightwhite,blue 5 | set numbercolor cyan 6 | set keycolor cyan 7 | set functioncolor green 8 | include "/usr/share/nano/*.nanorc" 9 | -------------------------------------------------------------------------------- /docker/container-armv8-dev/vimrc: -------------------------------------------------------------------------------- 1 | " All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by 2 | " the call to :runtime you can find below. If you wish to change any of those 3 | " settings, you should do it in this file (/etc/vim/vimrc), since debian.vim 4 | " will be overwritten everytime an upgrade of the vim packages is performed. 5 | " It is recommended to make changes after sourcing debian.vim since it alters 6 | " the value of the 'compatible' option. 7 | 8 | " This line should not be removed as it ensures that various options are 9 | " properly set to work with the Vim-related packages available in Debian. 10 | runtime! debian.vim 11 | 12 | " Uncomment the next line to make Vim more Vi-compatible 13 | " NOTE: debian.vim sets 'nocompatible'. Setting 'compatible' changes numerous 14 | " options, so any other options should be set AFTER setting 'compatible'. 15 | "set compatible 16 | 17 | " Vim5 and later versions support syntax highlighting. Uncommenting the next 18 | " line enables syntax highlighting by default. 19 | if has("syntax") 20 | syntax on 21 | endif 22 | 23 | " If using a dark background within the editing area and syntax highlighting 24 | " turn on this option as well 25 | set background=dark 26 | 27 | " Uncomment the following to have Vim jump to the last position when 28 | " reopening a file 29 | "if has("autocmd") 30 | " au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif 31 | "endif 32 | 33 | " Uncomment the following to have Vim load indentation rules and plugins 34 | " according to the detected filetype. 35 | if has("autocmd") 36 | filetype plugin indent on 37 | endif 38 | 39 | " The following are commented out as they cause vim to behave a lot 40 | " differently from regular Vi. They are highly recommended though. 41 | set showcmd " Show (partial) command in status line. 42 | set showmatch " Show matching brackets. 43 | "set ignorecase " Do case insensitive matching 44 | set smartcase " Do smart case matching 45 | set incsearch " Incremental search 46 | "set autowrite " Automatically save before commands like :next and :make 47 | "set hidden " Hide buffers when they are abandoned 48 | set mouse=a " Enable mouse usage (all modes) 49 | 50 | " Source a global configuration file if available 51 | "if filereadable("/etc/vim/vimrc.local") 52 | "source /etc/vim/vimrc.local 53 | "endif 54 | 55 | " User commands and preferences. 56 | set tabstop=2 57 | set nu 58 | set colorcolumn=80 59 | set ruler 60 | -------------------------------------------------------------------------------- /docker/container-armv8-dev/zsh_history/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all but this file 2 | * 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/.devcontainer/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # DUA environment container management settings. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | services: 22 | ros2-examples-x86-cudev: 23 | build: 24 | context: ../ 25 | network: host 26 | dockerfile: Dockerfile 27 | args: 28 | - USER_UID=1000 29 | image: ros2-examples:x86-cudev 30 | environment: 31 | TERM: xterm-256color 32 | DISPLAY: 33 | SHELL: /usr/bin/zsh 34 | user: neo 35 | network_mode: "host" 36 | privileged: true 37 | ipc: host 38 | init: true 39 | stdin_open: false 40 | tty: true 41 | working_dir: /home/neo/workspace 42 | command: 43 | [ 44 | "/bin/bash", 45 | "-c", 46 | "trap 'exit 0' TERM; sleep infinity & wait" 47 | ] 48 | volumes: 49 | - ../../../:/home/neo/workspace 50 | - ../aliases.sh:/home/neo/.aliases.sh:rw 51 | - ../bashrc:/home/neo/.bashrc:rw 52 | - ../colcon-defaults.yaml:/home/neo/.colcon/defaults.yaml:rw 53 | - ../commands.sh:/home/neo/.commands.sh:rw 54 | - ../dua_submod.sh:/home/neo/.dua_submod.sh:rw 55 | - ../dua_subtree.sh:/home/neo/.dua_subtree.sh:rw 56 | - ../p10k.zsh:/home/neo/.p10k.zsh:rw 57 | - ../ros2.sh:/home/neo/.ros2.sh:rw 58 | - ../zshrc:/home/neo/.zshrc:rw 59 | - ../zsh_history:/home/neo/zsh_history 60 | - ~/.ssh:/home/neo/.ssh 61 | - ~/.gitconfig:/home/neo/.gitconfig 62 | - ~/.Xauthority:/home/neo/.Xauthority:rw 63 | - /dev:/dev 64 | - /sys:/sys 65 | - /etc/localtime:/etc/localtime:ro 66 | - /etc/timezone:/etc/timezone:ro 67 | deploy: 68 | resources: 69 | reservations: 70 | devices: 71 | - driver: nvidia 72 | count: all 73 | capabilities: [ gpu ] 74 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/aliases.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Custom aliases for container internal shell. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add custom, general-purpose aliases here. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | alias ls='ls --color=auto' 27 | alias ll='ls -lah' 28 | alias valgrind-check='valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind.out' 29 | 30 | # Source DUA commands 31 | source ~/.dua_submod.sh 32 | source ~/.dua_subtree.sh 33 | 34 | # Routine to convert an angle in degrees [-180° +180°] to radians [-PI +PI]. 35 | function degrad { 36 | local angle_in_degrees="$1" 37 | angle_in_radians=$(python3 -c "import sys, math; angle=float(sys.argv[1]); print(math.radians((angle + 180) % 360 - 180))" "$angle_in_degrees") 38 | echo "$angle_in_radians" 39 | } 40 | 41 | # Routine to update dua-utils. 42 | function utils-update { 43 | local repos_file 44 | 45 | # Get the current shell 46 | local curr_shell 47 | curr_shell=$(ps -p $$ | awk 'NR==2 {print $4}') 48 | 49 | # Download new repos file 50 | if [ -f /opt/dua-utils_repos_base.yaml ]; then 51 | wget -O /opt/dua-utils_repos_base.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_base.yaml 52 | repos_file=/opt/dua-utils_repos_base.yaml 53 | elif [ -f /opt/dua-utils_repos_dev.yaml ]; then 54 | wget -O /opt/dua-utils_repos_dev.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_dev.yaml 55 | repos_file=/opt/dua-utils_repos_dev.yaml 56 | else 57 | echo >&2 "No repos file found." 58 | return 1 59 | fi 60 | 61 | # Perform updates 62 | if [ -x /opt/build_dua_utils.sh ]; then 63 | echo "Cloning and building dua-utils from $repos_file ..." 64 | sh -c "rm -rf /opt/ros/dua-utils/*" 65 | sh -c "/opt/build_dua_utils.sh jazzy $repos_file" 66 | else 67 | echo >&2 "No build script found." 68 | return 1 69 | fi 70 | 71 | # Source new installation 72 | source "/opt/ros/dua-utils/install/local_setup.$curr_shell" 73 | } 74 | 75 | # Routine to configure Cyclone DDS to use specific network interfaces. 76 | function cyclonedds-configure { 77 | local cyclonedds_uri='' 78 | for interface in "$@"; do 79 | cyclonedds_uri+="" 80 | done 81 | cyclonedds_uri+='' 82 | export CYCLONEDDS_URI="$cyclonedds_uri" 83 | } 84 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/colcon-defaults.yaml: -------------------------------------------------------------------------------- 1 | # Set options to configure colcon build environments for the current target 2 | { 3 | "build": { 4 | "packages-ignore": [] 5 | }, 6 | "test": { 7 | "packages-ignore": [] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/commands.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Project-specific shell functions and commands. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add yours, some convenient ones are provided below. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | # shellcheck disable=SC1090 27 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/dua_submod.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # DUA submodules management function. 4 | # 5 | # Roberto Masocco 6 | # Alessandro Tenaglia 7 | # 8 | # June 14, 2024 9 | 10 | # Copyright 2024 dotX Automation s.r.l. 11 | # 12 | # Licensed under the Apache License, Version 2.0 (the "License"); 13 | # you may not use this file except in compliance with the License. 14 | # You may obtain a copy of the License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the License is distributed on an "AS IS" BASIS, 20 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | # See the License for the specific language governing permissions and 22 | # limitations under the License. 23 | 24 | function dua-submod { 25 | function usage { 26 | echo >&2 "Usage:" 27 | echo >&2 " dua-submod [update|status]" 28 | echo >&2 "See dua-template.md for more info." 29 | } 30 | 31 | if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then 32 | usage 33 | return 1 34 | fi 35 | 36 | # Function to update the submodules. 37 | function update { 38 | git submodule update --init --recursive 39 | } 40 | 41 | # Function to check the status of the submodules. 42 | function status { 43 | git submodule status --recursive 44 | } 45 | 46 | # Check if we have a command and run the specified function. 47 | case "${1-}" in 48 | update) 49 | shift 50 | update 51 | ;; 52 | status) 53 | shift 54 | status 55 | ;; 56 | *) 57 | echo >&2 "Unknown command: ${1-}" 58 | usage 59 | return 1 60 | ;; 61 | esac 62 | } 63 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/nanorc: -------------------------------------------------------------------------------- 1 | set tabsize 2 2 | set tabstospaces 3 | set linenumbers 4 | set titlecolor brightwhite,blue 5 | set numbercolor cyan 6 | set keycolor cyan 7 | set functioncolor green 8 | include "/usr/share/nano/*.nanorc" 9 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/vimrc: -------------------------------------------------------------------------------- 1 | " All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by 2 | " the call to :runtime you can find below. If you wish to change any of those 3 | " settings, you should do it in this file (/etc/vim/vimrc), since debian.vim 4 | " will be overwritten everytime an upgrade of the vim packages is performed. 5 | " It is recommended to make changes after sourcing debian.vim since it alters 6 | " the value of the 'compatible' option. 7 | 8 | " This line should not be removed as it ensures that various options are 9 | " properly set to work with the Vim-related packages available in Debian. 10 | runtime! debian.vim 11 | 12 | " Uncomment the next line to make Vim more Vi-compatible 13 | " NOTE: debian.vim sets 'nocompatible'. Setting 'compatible' changes numerous 14 | " options, so any other options should be set AFTER setting 'compatible'. 15 | "set compatible 16 | 17 | " Vim5 and later versions support syntax highlighting. Uncommenting the next 18 | " line enables syntax highlighting by default. 19 | if has("syntax") 20 | syntax on 21 | endif 22 | 23 | " If using a dark background within the editing area and syntax highlighting 24 | " turn on this option as well 25 | set background=dark 26 | 27 | " Uncomment the following to have Vim jump to the last position when 28 | " reopening a file 29 | "if has("autocmd") 30 | " au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif 31 | "endif 32 | 33 | " Uncomment the following to have Vim load indentation rules and plugins 34 | " according to the detected filetype. 35 | if has("autocmd") 36 | filetype plugin indent on 37 | endif 38 | 39 | " The following are commented out as they cause vim to behave a lot 40 | " differently from regular Vi. They are highly recommended though. 41 | set showcmd " Show (partial) command in status line. 42 | set showmatch " Show matching brackets. 43 | "set ignorecase " Do case insensitive matching 44 | set smartcase " Do smart case matching 45 | set incsearch " Incremental search 46 | "set autowrite " Automatically save before commands like :next and :make 47 | "set hidden " Hide buffers when they are abandoned 48 | set mouse=a " Enable mouse usage (all modes) 49 | 50 | " Source a global configuration file if available 51 | "if filereadable("/etc/vim/vimrc.local") 52 | "source /etc/vim/vimrc.local 53 | "endif 54 | 55 | " User commands and preferences. 56 | set tabstop=2 57 | set nu 58 | set colorcolumn=80 59 | set ruler 60 | -------------------------------------------------------------------------------- /docker/container-x86-cudev/zsh_history/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all but this file 2 | * 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /docker/container-x86-dev/.devcontainer/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # DUA environment container management settings. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | services: 22 | ros2-examples-x86-dev: 23 | build: 24 | context: ../ 25 | network: host 26 | dockerfile: Dockerfile 27 | args: 28 | - USER_UID=1000 29 | image: ros2-examples:x86-dev 30 | environment: 31 | TERM: xterm-256color 32 | DISPLAY: 33 | SHELL: /usr/bin/zsh 34 | user: neo 35 | network_mode: "host" 36 | privileged: true 37 | ipc: host 38 | init: true 39 | stdin_open: false 40 | tty: true 41 | working_dir: /home/neo/workspace 42 | command: 43 | [ 44 | "/bin/bash", 45 | "-c", 46 | "trap 'exit 0' TERM; sleep infinity & wait" 47 | ] 48 | volumes: 49 | - ../../../:/home/neo/workspace 50 | - ../aliases.sh:/home/neo/.aliases.sh:rw 51 | - ../bashrc:/home/neo/.bashrc:rw 52 | - ../colcon-defaults.yaml:/home/neo/.colcon/defaults.yaml:rw 53 | - ../commands.sh:/home/neo/.commands.sh:rw 54 | - ../dua_submod.sh:/home/neo/.dua_submod.sh:rw 55 | - ../dua_subtree.sh:/home/neo/.dua_subtree.sh:rw 56 | - ../p10k.zsh:/home/neo/.p10k.zsh:rw 57 | - ../ros2.sh:/home/neo/.ros2.sh:rw 58 | - ../zshrc:/home/neo/.zshrc:rw 59 | - ../zsh_history:/home/neo/zsh_history 60 | - ~/.ssh:/home/neo/.ssh 61 | - ~/.gitconfig:/home/neo/.gitconfig 62 | - ~/.Xauthority:/home/neo/.Xauthority:rw 63 | - /dev:/dev 64 | - /sys:/sys 65 | - /etc/localtime:/etc/localtime:ro 66 | - /etc/timezone:/etc/timezone:ro 67 | -------------------------------------------------------------------------------- /docker/container-x86-dev/Dockerfile: -------------------------------------------------------------------------------- 1 | # DUA environment image. 2 | # 3 | # Roberto Masocco 4 | # 5 | # June 13, 2024 6 | 7 | # Copyright 2024 dotX Automation s.r.l. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | 21 | FROM dotxautomation/dua-foundation:x86-dev 22 | 23 | # Change this if you encounter problems with the default user 24 | ARG USER_UID=1000 25 | 26 | ENV DEBIAN_FRONTEND=noninteractive 27 | 28 | # IMAGE SETUP START # 29 | # IMAGE SETUP END # 30 | 31 | # Create a user with Zsh as shell, hashed password, and add it to the sudoers 32 | # To generate the hashed password, run: 33 | # mkpasswd -m sha-512 PASSWORD duatemplate 34 | RUN (getent passwd ${USER_UID} || true) && userdel -r $(getent passwd ${USER_UID} | cut -d: -f1) 2>/dev/null || true; \ 35 | useradd -r -m -s /usr/bin/zsh -u ${USER_UID} -G adm,dialout,internal,plugdev,sudo,tty,video -p '$6$duatemplate$EJUVqtbTQ7tR5d4245UWTesne/lplPqbjZMQ6hGX0raV4UePE6D/T/qfkWh82VvtpMJV6cDtyXFJYRhlh7syO.' neo 36 | ENV HOME=/home/neo 37 | 38 | # Create workspace directory: host workspaces will be mounted here 39 | RUN mkdir ${HOME}/workspace && \ 40 | chown neo:neo ${HOME}/workspace 41 | 42 | # Create directory for shell history file 43 | RUN mkdir ${HOME}/zsh_history && \ 44 | chown neo:neo ${HOME}/zsh_history 45 | 46 | # Create SSH directory for user 47 | RUN mkdir ${HOME}/.ssh 48 | 49 | # Create mount point for remote filesystems 50 | RUN mkdir -p /mnt/remote && \ 51 | chown neo:neo /mnt/remote 52 | 53 | # Switch to internal user 54 | USER neo 55 | WORKDIR ${HOME} 56 | 57 | # Copy user configuration files 58 | COPY --chown=neo:neo ./aliases.sh ./.aliases.sh 59 | COPY --chown=neo:neo ./bashrc ./.bashrc 60 | COPY --chown=neo:neo ./colcon-defaults.yaml /home/neo/.colcon/defaults.yaml 61 | COPY --chown=neo:neo ./commands.sh ./.commands.sh 62 | COPY --chown=neo:neo ./nanorc ./.nanorc 63 | COPY --chown=neo:neo ./ros2.sh ./.ros2.sh 64 | COPY --chown=neo:neo ./vimrc ./.vimrc 65 | 66 | # Configure Zsh for internal user 67 | ENV ZSH=${HOME}/.oh-my-zsh 68 | ENV ZSH_CUSTOM=${ZSH}/custom 69 | ENV ZSH_PLUGINS=${ZSH_CUSTOM}/plugins 70 | ENV ZSH_THEMES=${ZSH_CUSTOM}/themes 71 | RUN wget -qO- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | zsh || true 72 | RUN git clone --single-branch --branch 'master' --depth 1 https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_PLUGINS}/zsh-syntax-highlighting \ 73 | && git clone --single-branch --branch 'master' --depth 1 https://github.com/zsh-users/zsh-autosuggestions ${ZSH_PLUGINS}/zsh-autosuggestions \ 74 | && git clone --single-branch --depth 1 https://github.com/romkatv/powerlevel10k.git ${ZSH_THEMES}/powerlevel10k 75 | COPY --chown=neo:neo ./p10k.zsh ./.p10k.zsh 76 | COPY --chown=neo:neo ./zshrc ./.zshrc 77 | 78 | ENV DEBIAN_FRONTEND=dialog 79 | 80 | # By default, start a basic shell 81 | CMD ["bash"] 82 | -------------------------------------------------------------------------------- /docker/container-x86-dev/aliases.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Custom aliases for container internal shell. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add custom, general-purpose aliases here. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | alias ls='ls --color=auto' 27 | alias ll='ls -lah' 28 | alias valgrind-check='valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind.out' 29 | 30 | # Source DUA commands 31 | source ~/.dua_submod.sh 32 | source ~/.dua_subtree.sh 33 | 34 | # Routine to convert an angle in degrees [-180° +180°] to radians [-PI +PI]. 35 | function degrad { 36 | local angle_in_degrees="$1" 37 | angle_in_radians=$(python3 -c "import sys, math; angle=float(sys.argv[1]); print(math.radians((angle + 180) % 360 - 180))" "$angle_in_degrees") 38 | echo "$angle_in_radians" 39 | } 40 | 41 | # Routine to update dua-utils. 42 | function utils-update { 43 | local repos_file 44 | 45 | # Get the current shell 46 | local curr_shell 47 | curr_shell=$(ps -p $$ | awk 'NR==2 {print $4}') 48 | 49 | # Download new repos file 50 | if [ -f /opt/dua-utils_repos_base.yaml ]; then 51 | wget -O /opt/dua-utils_repos_base.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_base.yaml 52 | repos_file=/opt/dua-utils_repos_base.yaml 53 | elif [ -f /opt/dua-utils_repos_dev.yaml ]; then 54 | wget -O /opt/dua-utils_repos_dev.yaml https://raw.githubusercontent.com/dotX-Automation/dua-foundation/refs/heads/master/scripts/ros2/dua-utils_repos_dev.yaml 55 | repos_file=/opt/dua-utils_repos_dev.yaml 56 | else 57 | echo >&2 "No repos file found." 58 | return 1 59 | fi 60 | 61 | # Perform updates 62 | if [ -x /opt/build_dua_utils.sh ]; then 63 | echo "Cloning and building dua-utils from $repos_file ..." 64 | sh -c "rm -rf /opt/ros/dua-utils/*" 65 | sh -c "/opt/build_dua_utils.sh jazzy $repos_file" 66 | else 67 | echo >&2 "No build script found." 68 | return 1 69 | fi 70 | 71 | # Source new installation 72 | source "/opt/ros/dua-utils/install/local_setup.$curr_shell" 73 | } 74 | 75 | # Routine to configure Cyclone DDS to use specific network interfaces. 76 | function cyclonedds-configure { 77 | local cyclonedds_uri='' 78 | for interface in "$@"; do 79 | cyclonedds_uri+="" 80 | done 81 | cyclonedds_uri+='' 82 | export CYCLONEDDS_URI="$cyclonedds_uri" 83 | } 84 | -------------------------------------------------------------------------------- /docker/container-x86-dev/colcon-defaults.yaml: -------------------------------------------------------------------------------- 1 | # Set options to configure colcon build environments for the current target 2 | { 3 | "build": { 4 | "packages-ignore": [] 5 | }, 6 | "test": { 7 | "packages-ignore": [] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docker/container-x86-dev/commands.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Project-specific shell functions and commands. 4 | # 5 | # Roberto Masocco 6 | # 7 | # June 13, 2024 8 | 9 | # Copyright 2024 dotX Automation s.r.l. 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | # Add yours, some convenient ones are provided below. 24 | # You can also source other files from sub-units included by this project. 25 | 26 | # shellcheck disable=SC1090 27 | -------------------------------------------------------------------------------- /docker/container-x86-dev/dua_submod.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # DUA submodules management function. 4 | # 5 | # Roberto Masocco 6 | # Alessandro Tenaglia 7 | # 8 | # June 14, 2024 9 | 10 | # Copyright 2024 dotX Automation s.r.l. 11 | # 12 | # Licensed under the Apache License, Version 2.0 (the "License"); 13 | # you may not use this file except in compliance with the License. 14 | # You may obtain a copy of the License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the License is distributed on an "AS IS" BASIS, 20 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | # See the License for the specific language governing permissions and 22 | # limitations under the License. 23 | 24 | function dua-submod { 25 | function usage { 26 | echo >&2 "Usage:" 27 | echo >&2 " dua-submod [update|status]" 28 | echo >&2 "See dua-template.md for more info." 29 | } 30 | 31 | if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then 32 | usage 33 | return 1 34 | fi 35 | 36 | # Function to update the submodules. 37 | function update { 38 | git submodule update --init --recursive 39 | } 40 | 41 | # Function to check the status of the submodules. 42 | function status { 43 | git submodule status --recursive 44 | } 45 | 46 | # Check if we have a command and run the specified function. 47 | case "${1-}" in 48 | update) 49 | shift 50 | update 51 | ;; 52 | status) 53 | shift 54 | status 55 | ;; 56 | *) 57 | echo >&2 "Unknown command: ${1-}" 58 | usage 59 | return 1 60 | ;; 61 | esac 62 | } 63 | -------------------------------------------------------------------------------- /docker/container-x86-dev/nanorc: -------------------------------------------------------------------------------- 1 | set tabsize 2 2 | set tabstospaces 3 | set linenumbers 4 | set titlecolor brightwhite,blue 5 | set numbercolor cyan 6 | set keycolor cyan 7 | set functioncolor green 8 | include "/usr/share/nano/*.nanorc" 9 | -------------------------------------------------------------------------------- /docker/container-x86-dev/vimrc: -------------------------------------------------------------------------------- 1 | " All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by 2 | " the call to :runtime you can find below. If you wish to change any of those 3 | " settings, you should do it in this file (/etc/vim/vimrc), since debian.vim 4 | " will be overwritten everytime an upgrade of the vim packages is performed. 5 | " It is recommended to make changes after sourcing debian.vim since it alters 6 | " the value of the 'compatible' option. 7 | 8 | " This line should not be removed as it ensures that various options are 9 | " properly set to work with the Vim-related packages available in Debian. 10 | runtime! debian.vim 11 | 12 | " Uncomment the next line to make Vim more Vi-compatible 13 | " NOTE: debian.vim sets 'nocompatible'. Setting 'compatible' changes numerous 14 | " options, so any other options should be set AFTER setting 'compatible'. 15 | "set compatible 16 | 17 | " Vim5 and later versions support syntax highlighting. Uncommenting the next 18 | " line enables syntax highlighting by default. 19 | if has("syntax") 20 | syntax on 21 | endif 22 | 23 | " If using a dark background within the editing area and syntax highlighting 24 | " turn on this option as well 25 | set background=dark 26 | 27 | " Uncomment the following to have Vim jump to the last position when 28 | " reopening a file 29 | "if has("autocmd") 30 | " au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif 31 | "endif 32 | 33 | " Uncomment the following to have Vim load indentation rules and plugins 34 | " according to the detected filetype. 35 | if has("autocmd") 36 | filetype plugin indent on 37 | endif 38 | 39 | " The following are commented out as they cause vim to behave a lot 40 | " differently from regular Vi. They are highly recommended though. 41 | set showcmd " Show (partial) command in status line. 42 | set showmatch " Show matching brackets. 43 | "set ignorecase " Do case insensitive matching 44 | set smartcase " Do smart case matching 45 | set incsearch " Incremental search 46 | "set autowrite " Automatically save before commands like :next and :make 47 | "set hidden " Hide buffers when they are abandoned 48 | set mouse=a " Enable mouse usage (all modes) 49 | 50 | " Source a global configuration file if available 51 | "if filereadable("/etc/vim/vimrc.local") 52 | "source /etc/vim/vimrc.local 53 | "endif 54 | 55 | " User commands and preferences. 56 | set tabstop=2 57 | set nu 58 | set colorcolumn=80 59 | set ruler 60 | -------------------------------------------------------------------------------- /docker/container-x86-dev/zsh_history/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all but this file 2 | * 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /logs/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this folder except this file 2 | # This is the default, feel free to add other exceptions 3 | * 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /ros2_cli_cheat_sheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/ros2_cli_cheat_sheet.pdf -------------------------------------------------------------------------------- /src/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/src/.gitkeep -------------------------------------------------------------------------------- /src/cpp/actions_example_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(actions_example_cpp) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | # Default to C99 7 | if(NOT CMAKE_C_STANDARD) 8 | set(CMAKE_C_STANDARD 99) 9 | endif() 10 | 11 | # Default to C++17 12 | if(NOT CMAKE_CXX_STANDARD) 13 | set(CMAKE_CXX_STANDARD 17) 14 | endif() 15 | 16 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 17 | add_compile_options(-Wall -Wextra -Wpedantic) 18 | endif() 19 | 20 | # Find dependencies 21 | find_package(ament_cmake REQUIRED) 22 | find_package(rclcpp REQUIRED) 23 | find_package(rclcpp_action REQUIRED) 24 | find_package(ros2_examples_interfaces REQUIRED) 25 | 26 | # Server 27 | add_executable(fib_server src/fib_server.cpp src/server_main.cpp) 28 | target_include_directories(fib_server PUBLIC 29 | $ 30 | $) 31 | target_compile_features(fib_server PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 32 | ament_target_dependencies( 33 | fib_server 34 | rclcpp 35 | rclcpp_action 36 | ros2_examples_interfaces) 37 | 38 | # Client 39 | add_executable(fib_client src/fib_client.cpp src/client_main.cpp) 40 | target_include_directories(fib_client PUBLIC 41 | $ 42 | $) 43 | target_compile_features(fib_client PUBLIC c_std_99 cxx_std_17) 44 | ament_target_dependencies( 45 | fib_client 46 | rclcpp 47 | rclcpp_action 48 | ros2_examples_interfaces) 49 | 50 | # Install executables 51 | install(TARGETS fib_server 52 | DESTINATION lib/${PROJECT_NAME}) 53 | install(TARGETS fib_client 54 | DESTINATION lib/${PROJECT_NAME}) 55 | 56 | if(BUILD_TESTING) 57 | find_package(ament_lint_auto REQUIRED) 58 | # the following line skips the linter which checks for copyrights 59 | # uncomment the line when a copyright and license is not present in all source files 60 | #set(ament_cmake_copyright_FOUND TRUE) 61 | # the following line skips cpplint (only works in a git repo) 62 | # uncomment the line when this package is not in a git repo 63 | #set(ament_cmake_cpplint_FOUND TRUE) 64 | ament_lint_auto_find_test_dependencies() 65 | endif() 66 | 67 | ament_package() 68 | -------------------------------------------------------------------------------- /src/cpp/actions_example_cpp/include/actions_example_cpp/fib_client.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Fibonacci computation action client. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 10, 2022 7 | */ 8 | 9 | #include 10 | 11 | //! Service calls will all handle futures 12 | #include 13 | 14 | //! Necessary to define pointers to addres many action-related objects 15 | #include 16 | 17 | #include 18 | #include //! Necessary to use actions 19 | 20 | //! Our interfaces 21 | #include 22 | 23 | //! Again, let's make our life easier 24 | using Fibonacci = ros2_examples_interfaces::action::Fibonacci; 25 | using FibonacciGoalHandle = rclcpp_action::ClientGoalHandle; 26 | using FibonacciGoalHandleSharedPtr = FibonacciGoalHandle::SharedPtr; 27 | using CancelResponse = action_msgs::srv::CancelGoal::Response; 28 | using CancelResponseSharedPtr = CancelResponse::SharedPtr; 29 | 30 | /** 31 | * Sends a request to compute the Fibonacci sequence up to a given number. 32 | */ 33 | class FibonacciClient : public rclcpp::Node 34 | { 35 | public: 36 | FibonacciClient(); 37 | std::string get_result_str(); 38 | 39 | //! These are just for us, to wrap operations on the (private) back-end 40 | std::shared_future send_goal(int order); 41 | std::shared_future request_result( 42 | FibonacciGoalHandleSharedPtr goal_handle); 43 | std::shared_future request_cancel( 44 | FibonacciGoalHandleSharedPtr goal_handle); 45 | 46 | private: 47 | std::stringstream result_ss_; 48 | 49 | //! Client goes with options needed to send goal requests 50 | rclcpp_action::Client::SharedPtr client_; 51 | rclcpp_action::Client::SendGoalOptions client_opts_; 52 | 53 | //! Name of the following callbacks says it all, but pay attention to their 54 | //! signatures and argument types! 55 | void goal_response_clbk(FibonacciGoalHandleSharedPtr goal_handle); 56 | void feedback_callback( 57 | FibonacciGoalHandleSharedPtr goal_handle, 58 | const std::shared_ptr feedback); 59 | void result_callback(const FibonacciGoalHandle::WrappedResult & result); 60 | void cancel_callback(CancelResponseSharedPtr cancel_resp); 61 | }; 62 | -------------------------------------------------------------------------------- /src/cpp/actions_example_cpp/include/actions_example_cpp/fib_server.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Example Fibonacci computation action server. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 10, 2022 7 | */ 8 | 9 | #ifndef FIB_SERVER_HPP 10 | #define FIB_SERVER_HPP 11 | 12 | //! Required to handle all the following shared pointers 13 | #include 14 | 15 | //! Required to handle thread generation when accepting goals 16 | #include 17 | 18 | #include 19 | #include //! Required when handling actions 20 | #include //! Fibonacci action definition 21 | 22 | //! Action-related types can get quite long, so let's simplify 23 | using Fibonacci = ros2_examples_interfaces::action::Fibonacci; 24 | using FibonacciGoalHandle = rclcpp_action::ServerGoalHandle; 25 | 26 | //! Define these manually to enforce const here and in the following 27 | using FibonacciGoalSharedPtr = std::shared_ptr; 28 | using FibonacciGoalHandleSharedPtr = std::shared_ptr; 29 | 30 | //! Pay attention to the types hell... 31 | 32 | /** 33 | * Action server that computes the Fibonacci sequence up to a point. 34 | */ 35 | class FibonacciComputer : public rclcpp::Node 36 | { 37 | public: 38 | FibonacciComputer(); 39 | 40 | private: 41 | //! Action server (like for services) 42 | rclcpp_action::Server::SharedPtr fib_server_; 43 | 44 | //! Following 3 routines are required by the API, first 2 return from enums 45 | //! Goal request handler routine 46 | rclcpp_action::GoalResponse handle_goal( 47 | const rclcpp_action::GoalUUID & uuid, 48 | FibonacciGoalSharedPtr goal); 49 | 50 | //! Goal cancellation request handler routine 51 | rclcpp_action::CancelResponse handle_cancel(const FibonacciGoalHandleSharedPtr goal_handle); 52 | 53 | //! Goal acceptance handler routine 54 | void handle_accepted(const FibonacciGoalHandleSharedPtr goal_handle); 55 | 56 | //! Computation routine 57 | void compute(const FibonacciGoalHandleSharedPtr goal_handle); 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/cpp/actions_example_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | actions_example_cpp 5 | 0.0.0 6 | Example about ROS 2 actions. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | rclcpp_action 14 | ros2_examples_interfaces 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/cpp/actions_example_cpp/src/server_main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Fibonacci computer action server main source file. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 10, 2022 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char ** argv) 15 | { 16 | std::cout << "Starting Fibonacci Computer action server..." << std::endl; 17 | rclcpp::init(argc, argv); 18 | auto server_node = std::make_shared(); 19 | rclcpp::spin(server_node); 20 | rclcpp::shutdown(); 21 | exit(EXIT_SUCCESS); 22 | } 23 | -------------------------------------------------------------------------------- /src/cpp/advanced/complete_actions_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(complete_actions_cpp) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | # Default to C99 7 | if(NOT CMAKE_C_STANDARD) 8 | set(CMAKE_C_STANDARD 99) 9 | endif() 10 | 11 | # Default to C++17 12 | if(NOT CMAKE_CXX_STANDARD) 13 | set(CMAKE_CXX_STANDARD 17) 14 | endif() 15 | 16 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 17 | add_compile_options(-Wall -Wextra -Wpedantic) 18 | endif() 19 | 20 | # Find dependencies 21 | find_package(ament_cmake REQUIRED) 22 | find_package(rclcpp REQUIRED) 23 | find_package(rclcpp_action REQUIRED) 24 | find_package(ros2_examples_interfaces REQUIRED) 25 | 26 | # Server 27 | add_executable(fib_server src/fib_server.cpp src/server_main.cpp) 28 | target_include_directories(fib_server PUBLIC 29 | $ 30 | $) 31 | target_compile_features(fib_server PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 32 | ament_target_dependencies( 33 | fib_server 34 | rclcpp 35 | rclcpp_action 36 | ros2_examples_interfaces) 37 | 38 | # Client 39 | add_executable(fib_client src/fib_client.cpp src/client_main.cpp) 40 | target_include_directories(fib_client PUBLIC 41 | $ 42 | $) 43 | target_compile_features(fib_client PUBLIC c_std_99 cxx_std_17) 44 | ament_target_dependencies( 45 | fib_client 46 | rclcpp 47 | rclcpp_action 48 | ros2_examples_interfaces) 49 | 50 | # Install executables 51 | install(TARGETS fib_server 52 | DESTINATION lib/${PROJECT_NAME}) 53 | install(TARGETS fib_client 54 | DESTINATION lib/${PROJECT_NAME}) 55 | 56 | if(BUILD_TESTING) 57 | find_package(ament_lint_auto REQUIRED) 58 | # the following line skips the linter which checks for copyrights 59 | # uncomment the line when a copyright and license is not present in all source files 60 | #set(ament_cmake_copyright_FOUND TRUE) 61 | # the following line skips cpplint (only works in a git repo) 62 | # uncomment the line when this package is not in a git repo 63 | #set(ament_cmake_cpplint_FOUND TRUE) 64 | ament_lint_auto_find_test_dependencies() 65 | endif() 66 | 67 | ament_package() 68 | -------------------------------------------------------------------------------- /src/cpp/advanced/complete_actions_cpp/include/complete_actions_cpp/fib_client.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Fibonacci computation action client. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 10, 2022 7 | */ 8 | 9 | #include 10 | 11 | //! Service calls will all handle futures 12 | #include 13 | 14 | //! Necessary to define pointers to addres many action-related objects 15 | #include 16 | 17 | #include 18 | #include //! Necessary to use actions 19 | 20 | //! Our interfaces 21 | #include 22 | 23 | //! Again, let's make our life easier 24 | using Fibonacci = ros2_examples_interfaces::action::Fibonacci; 25 | using FibonacciGoalHandle = rclcpp_action::ClientGoalHandle; 26 | using FibonacciGoalHandleSharedPtr = FibonacciGoalHandle::SharedPtr; 27 | using CancelResponse = action_msgs::srv::CancelGoal::Response; 28 | using CancelResponseSharedPtr = CancelResponse::SharedPtr; 29 | 30 | /** 31 | * Sends a request to compute the Fibonacci sequence up to a given number. 32 | */ 33 | class FibonacciClient : public rclcpp::Node 34 | { 35 | public: 36 | FibonacciClient(); 37 | std::string get_result_str(); 38 | 39 | //! These are required to wrap operations on the (private) back-end 40 | std::shared_future send_goal(int order); 41 | std::shared_future request_result( 42 | FibonacciGoalHandleSharedPtr goal_handle); 43 | std::shared_future request_cancel( 44 | FibonacciGoalHandleSharedPtr goal_handle); 45 | 46 | private: 47 | std::stringstream result_ss_; 48 | 49 | rclcpp::CallbackGroup::SharedPtr client_clbk_group_; 50 | rcl_action_client_options_t action_client_opts_{}; 51 | 52 | //! Client goes with options needed to send goal requests 53 | rclcpp_action::Client::SharedPtr client_; 54 | rclcpp_action::Client::SendGoalOptions client_opts_; 55 | 56 | //! Name of the following callbacks says it all, but pay attention to their 57 | //! signatures and argument types! 58 | void goal_response_clbk( 59 | FibonacciGoalHandleSharedPtr goal_handle); 60 | void feedback_callback( 61 | FibonacciGoalHandleSharedPtr goal_handle, 62 | const std::shared_ptr feedback); 63 | void result_callback(const FibonacciGoalHandle::WrappedResult & result); 64 | void cancel_callback(CancelResponseSharedPtr cancel_resp); 65 | }; 66 | -------------------------------------------------------------------------------- /src/cpp/advanced/complete_actions_cpp/include/complete_actions_cpp/fib_server.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Example Fibonacci computation action server. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 10, 2022 7 | */ 8 | 9 | #ifndef FIB_SERVER_HPP 10 | #define FIB_SERVER_HPP 11 | 12 | //! Required to handle all the following shared pointers 13 | #include 14 | 15 | //! Required to handle thread generation when accepting goals 16 | #include 17 | 18 | #include 19 | #include //! Required when handling actions 20 | #include //! Fibonacci action definition 21 | 22 | //! Action-related types can get quite long, so let's simplify 23 | using Fibonacci = ros2_examples_interfaces::action::Fibonacci; 24 | using FibonacciGoalHandle = rclcpp_action::ServerGoalHandle; 25 | 26 | //! Define these manually to enforce const here and in the following 27 | using FibonacciGoalSharedPtr = std::shared_ptr; 28 | using FibonacciGoalHandleSharedPtr = std::shared_ptr; 29 | 30 | //! Pay attention to the types hell... 31 | 32 | /** 33 | * Action server that computes the Fibonacci sequence up to a point. 34 | */ 35 | class FibonacciComputer : public rclcpp::Node 36 | { 37 | public: 38 | FibonacciComputer(); 39 | 40 | private: 41 | //! Action server (like for services) 42 | rclcpp_action::Server::SharedPtr fib_server_; 43 | 44 | rclcpp::CallbackGroup::SharedPtr server_clbk_group_; 45 | rcl_action_server_options_t server_opts_{}; 46 | rclcpp::TimerBase::SharedPtr work_timer_; 47 | void work_activation_clbk(); 48 | FibonacciGoalHandleSharedPtr new_goal_ = nullptr; 49 | 50 | //! Following 3 routines are required by the API, first 2 return from enums 51 | //! Goal request handler routine 52 | rclcpp_action::GoalResponse handle_goal( 53 | const rclcpp_action::GoalUUID & uuid, 54 | FibonacciGoalSharedPtr goal); 55 | 56 | //! Goal cancellation request handler routine 57 | rclcpp_action::CancelResponse handle_cancel(const FibonacciGoalHandleSharedPtr goal_handle); 58 | 59 | //! Goal acceptance handler routine 60 | void handle_accepted(const FibonacciGoalHandleSharedPtr goal_handle); 61 | 62 | //! Computation routine 63 | void compute(const FibonacciGoalHandleSharedPtr goal_handle); 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/cpp/advanced/complete_actions_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | complete_actions_cpp 5 | 0.0.0 6 | Example about ROS 2 actions. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | rclcpp_action 14 | ros2_examples_interfaces 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/cpp/advanced/complete_actions_cpp/src/server_main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Fibonacci computer action server main source file. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 10, 2022 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | int main(int argc, char ** argv) 16 | { 17 | std::cout << "Starting Fibonacci Computer action server..." << std::endl; 18 | rclcpp::init(argc, argv); 19 | auto server_node = std::make_shared(); 20 | 21 | //! We need a MTExecutor for this 22 | rclcpp::executors::MultiThreadedExecutor smp_executor; 23 | smp_executor.add_node(server_node); 24 | smp_executor.spin(); 25 | 26 | rclcpp::shutdown(); 27 | exit(EXIT_SUCCESS); 28 | } 29 | -------------------------------------------------------------------------------- /src/cpp/advanced/namespaces_examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(namespaces_examples) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(rclcpp REQUIRED) 11 | find_package(std_msgs REQUIRED) 12 | find_package(example_interfaces REQUIRED) 13 | 14 | # install launch files 15 | install(DIRECTORY launch 16 | DESTINATION share/${PROJECT_NAME}) 17 | 18 | # example about ROS 2 DDS topics naming mechanisms 19 | add_executable(topics_ns 20 | src/topics_ns/topics_ns.cpp 21 | src/topics_ns/pub_srv.cpp) 22 | target_include_directories(topics_ns PUBLIC 23 | $ 24 | $) 25 | target_compile_features(topics_ns PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 26 | ament_target_dependencies( 27 | topics_ns 28 | "rclcpp" 29 | "std_msgs" 30 | "example_interfaces" 31 | ) 32 | 33 | install(TARGETS topics_ns 34 | DESTINATION lib/${PROJECT_NAME}) 35 | 36 | if(BUILD_TESTING) 37 | find_package(ament_lint_auto REQUIRED) 38 | # the following line skips the linter which checks for copyrights 39 | # uncomment the line when a copyright and license is not present in all source files 40 | #set(ament_cmake_copyright_FOUND TRUE) 41 | # the following line skips cpplint (only works in a git repo) 42 | # uncomment the line when this package is not in a git repo 43 | #set(ament_cmake_cpplint_FOUND TRUE) 44 | ament_lint_auto_find_test_dependencies() 45 | endif() 46 | 47 | ament_package() 48 | -------------------------------------------------------------------------------- /src/cpp/advanced/namespaces_examples/COLCON_IGNORE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/src/cpp/advanced/namespaces_examples/COLCON_IGNORE -------------------------------------------------------------------------------- /src/cpp/advanced/namespaces_examples/include/namespaces_examples/topic_ns/pub_srv.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Dummy publisher/server. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 9, 2022 7 | */ 8 | 9 | #ifndef PUBSRV_HPP 10 | #define PUBSRV_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std_msgs::msg; 17 | using namespace example_interfaces::srv; 18 | 19 | /** 20 | * Dummy publisher/server node. 21 | */ 22 | class DummyPubSrv : public rclcpp::Node 23 | { 24 | public: 25 | DummyPubSrv(); 26 | 27 | private: 28 | rclcpp::Publisher::SharedPtr pub_; 29 | rclcpp::Service::SharedPtr server_; 30 | void server_clbk( 31 | Trigger::Request::SharedPtr req, 32 | Trigger::Response::SharedPtr resp); 33 | }; 34 | 35 | #endif -------------------------------------------------------------------------------- /src/cpp/advanced/namespaces_examples/launch/topics_ns.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Launch file to show some remapping features. 3 | 4 | Roberto Masocco 5 | 6 | January 9, 2022 7 | """ 8 | 9 | from launch import LaunchDescription 10 | from launch_ros.actions import Node 11 | 12 | """Generates a launch description for the given module""" 13 | 14 | 15 | def generate_launch_description(): 16 | ld = LaunchDescription() 17 | 18 | #! Here we'll remap everything: node, topics, namespaces 19 | 20 | # Create publisher/server launch definition 21 | pub_srv = Node( 22 | package='namespaces_examples', 23 | executable='topics_ns', 24 | name='test_node', #! This overrides the node name 25 | namespace='topics_ns', #! This overrides the default namespace 26 | shell=True, 27 | emulate_tty=True, 28 | output='both', 29 | log_cmd=True, 30 | remappings=[ #! These'll override topic and service names 31 | ('rosservice://~/dummy_srv', '~/trigger'), 32 | ('rostopic://~/dummy_topic', '~/bool') 33 | ] #! Notice the URL-like matching rule, necessary for topic/service names 34 | #! to make matching more explicit when such names are complex 35 | ) 36 | ld.add_action(pub_srv) 37 | 38 | return ld 39 | -------------------------------------------------------------------------------- /src/cpp/advanced/namespaces_examples/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | namespaces_examples 5 | 0.0.0 6 | Collection of namespaces remapping examples. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | std_msgs 14 | example_interfaces 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/cpp/advanced/namespaces_examples/src/topics_ns/pub_srv.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Dummy publisher/server source code. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 9, 2022 7 | */ 8 | 9 | #include "../../include/namespaces_examples/topic_ns/pub_srv.hpp" 10 | 11 | #define UNUSED(arg) (void)(arg) 12 | 13 | /** 14 | * @brief Creates a new dummy publisher/server. 15 | */ 16 | DummyPubSrv::DummyPubSrv() 17 | : Node("dummy_node") 18 | { 19 | //! If we put no additional characters in a topic/service name, it'll 20 | //! be considered as a "relative name" and put directly in the outermost 21 | //! namespace (see docs) 22 | //! Instead, here we explicitly require placing topics and services in the 23 | //! "private namespace" by prepending "~/", and the expansion will be: 24 | //! /DEFAULT_NAMESPACE (if any)/NODE/name 25 | pub_ = this->create_publisher( 26 | "~/dummy_topic", 27 | rclcpp::QoS(10) 28 | ); 29 | //! For the sake of this example, we'll never need to publish on this topic 30 | 31 | server_ = this->create_service( 32 | "~/dummy_srv", 33 | std::bind( 34 | &DummyPubSrv::server_clbk, 35 | this, 36 | std::placeholders::_1, 37 | std::placeholders::_2) 38 | ); 39 | } 40 | 41 | /** 42 | * @brief Dummy server callback. 43 | * 44 | * @param req Request to parse. 45 | * @param resp Response to populate. 46 | */ 47 | void DummyPubSrv::server_clbk( 48 | Trigger::Request::SharedPtr req, 49 | Trigger::Response::SharedPtr resp) 50 | { 51 | UNUSED(req); 52 | resp->set__success(true); 53 | resp->set__message("Service was called"); 54 | } 55 | -------------------------------------------------------------------------------- /src/cpp/advanced/namespaces_examples/src/topics_ns/topics_ns.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Node names, topic names, and default namespaces remapping example. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 9, 2022 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include "../../include/namespaces_examples/topic_ns/pub_srv.hpp" 13 | 14 | int main(int argc, char ** argv) 15 | { 16 | rclcpp::init(argc, argv); 17 | std::cout << "Initializing dummy node..." << std::endl; 18 | auto node = std::make_shared(); 19 | rclcpp::spin(node); 20 | rclcpp::shutdown(); 21 | exit(EXIT_SUCCESS); 22 | } 23 | 24 | //! Start this normally with ros2 run and query active topics and services, 25 | //! then go have a look at the launch/topics_ns.launch.py launch file 26 | //! You'll see many remapping rules, and their syntax for launch files 27 | //! If you start it, have a look at the log: at the beginning there'll be 28 | //! the very long command line necessary to achieve the same remappings 29 | //! Such line can be given to ros2 run too, and will be parsed by rclcpp::init 30 | //! as anything that comes after --ros-args 31 | //! Remapping rules can be complex, for more info have a look at: 32 | //! https://design.ros2.org/articles/static_remapping.html 33 | //! http://design.ros2.org/articles/topic_and_service_names.html 34 | -------------------------------------------------------------------------------- /src/cpp/advanced/ros2_examples_headers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(ros2_examples_headers) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | 11 | if(BUILD_TESTING) 12 | find_package(ament_lint_auto REQUIRED) 13 | # the following line skips the linter which checks for copyrights 14 | # uncomment the line when a copyright and license is not present in all source files 15 | #set(ament_cmake_copyright_FOUND TRUE) 16 | # the following line skips cpplint (only works in a git repo) 17 | # uncomment the line when this package is not in a git repo 18 | #set(ament_cmake_cpplint_FOUND TRUE) 19 | ament_lint_auto_find_test_dependencies() 20 | endif() 21 | 22 | # install headers 23 | #! this package exists just for this 24 | install(DIRECTORY include/ 25 | DESTINATION include) 26 | 27 | # export headers for ament 28 | #! don't forget this step or hell will be break loose 29 | ament_export_include_directories( 30 | include 31 | ) 32 | 33 | ament_package() 34 | -------------------------------------------------------------------------------- /src/cpp/advanced/ros2_examples_headers/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ros2_examples_headers 5 | 0.0.0 6 | Example headers-only package. 7 | Roberto Masocco 8 | TODO: License declaration 9 | 10 | ament_cmake 11 | 12 | ament_lint_auto 13 | ament_lint_common 14 | 15 | 16 | ament_cmake 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/cpp/advanced/smp_example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(smp_example) 3 | 4 | # Default to C99 5 | if(NOT CMAKE_C_STANDARD) 6 | set(CMAKE_C_STANDARD 99) 7 | endif() 8 | 9 | # Default to C++14 10 | if(NOT CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 14) 12 | endif() 13 | 14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 15 | add_compile_options(-Wall -Wextra -Wpedantic) 16 | endif() 17 | 18 | # find dependencies 19 | find_package(ament_cmake REQUIRED) 20 | find_package(rclcpp REQUIRED) 21 | find_package(std_msgs REQUIRED) 22 | 23 | add_executable(smp_example src/smp_node.cpp 24 | src/smp_example.cpp 25 | src/pub_node.cpp) 26 | target_include_directories(smp_example PUBLIC 27 | $ 28 | $) 29 | ament_target_dependencies( 30 | smp_example 31 | "rclcpp" 32 | ) 33 | 34 | install(TARGETS smp_example 35 | DESTINATION lib/${PROJECT_NAME}) 36 | 37 | if(BUILD_TESTING) 38 | find_package(ament_lint_auto REQUIRED) 39 | # the following line skips the linter which checks for copyrights 40 | # uncomment the line when a copyright and license is not present in all source files 41 | #set(ament_cmake_copyright_FOUND TRUE) 42 | # the following line skips cpplint (only works in a git repo) 43 | # uncomment the line when this package is not in a git repo 44 | #set(ament_cmake_cpplint_FOUND TRUE) 45 | ament_lint_auto_find_test_dependencies() 46 | endif() 47 | 48 | ament_package() 49 | -------------------------------------------------------------------------------- /src/cpp/advanced/smp_example/COLCON_IGNORE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/src/cpp/advanced/smp_example/COLCON_IGNORE -------------------------------------------------------------------------------- /src/cpp/advanced/smp_example/include/smp_example/smp_example.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definitions of nodes for this example. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 26, 2021 7 | */ 8 | 9 | #ifndef SMP_EXAMPLE_HPP 10 | #define SMP_EXAMPLE_HPP 11 | 12 | #include 13 | #include 14 | 15 | /** 16 | * Simple node with two subscribers, which callbacks will be executed on 17 | * different threads. 18 | */ 19 | class SMPNode : public rclcpp::Node 20 | { 21 | public: 22 | SMPNode(); 23 | 24 | private: 25 | //! The main difference is the necessity to create callback groups, 26 | //! intended as separate queues from which call 27 | rclcpp::CallbackGroup::SharedPtr clbk_group_1_; 28 | rclcpp::CallbackGroup::SharedPtr clbk_group_2_; 29 | 30 | rclcpp::Subscription::SharedPtr sub_1_; 31 | rclcpp::Subscription::SharedPtr sub_2_; 32 | 33 | void sub_1_clbk(const std_msgs::msg::UInt64::SharedPtr msg); 34 | void sub_2_clbk(const std_msgs::msg::UInt64::SharedPtr msg); 35 | }; 36 | 37 | /** 38 | * Publisher node for this example. 39 | */ 40 | class PubNode : public rclcpp::Node 41 | { 42 | public: 43 | PubNode(unsigned int period); 44 | 45 | private: 46 | rclcpp::Publisher::SharedPtr count_pub_; 47 | 48 | rclcpp::TimerBase::SharedPtr pub_timer_; 49 | 50 | void timer_clbk_(void); 51 | 52 | unsigned long int count_; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/cpp/advanced/smp_example/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | smp_example 5 | 0.0.0 6 | Multithreaded executors example. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | std_msgs 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cpp/advanced/smp_example/src/pub_node.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Publisher node for this example. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 26, 2021 7 | */ 8 | 9 | #include 10 | 11 | #include "../include/smp_example/smp_example.hpp" 12 | 13 | /** 14 | * @brief Creates a PubNode. 15 | * 16 | * @param period Publishing timer time period. 17 | */ 18 | PubNode::PubNode(unsigned int period) 19 | : Node("pub_node"), 20 | count_(0) 21 | { 22 | count_pub_ = this->create_publisher( 23 | "/ros2_examples/smp_topic", 24 | rclcpp::QoS(10) 25 | ); 26 | pub_timer_ = this->create_wall_timer( 27 | std::chrono::milliseconds(period), 28 | std::bind( 29 | &PubNode::timer_clbk_, 30 | this 31 | ) 32 | ); 33 | RCLCPP_INFO(this->get_logger(), "Node initialized"); 34 | } 35 | 36 | /** 37 | * @brief Publishes a new message. 38 | */ 39 | void PubNode::timer_clbk_(void) 40 | { 41 | count_++; 42 | std_msgs::msg::UInt64 new_msg{}; 43 | new_msg.set__data(count_); 44 | count_pub_->publish(new_msg); 45 | } 46 | -------------------------------------------------------------------------------- /src/cpp/advanced/smp_example/src/smp_example.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Multithreaded executors example. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 26, 2021 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "../include/smp_example/smp_example.hpp" 14 | 15 | int main(int argc, char ** argv) 16 | { 17 | if (argc < 2) { 18 | std::cerr << "Usage:\n\tsmp_example PERIOD[ms]" << std::endl; 19 | exit(EXIT_FAILURE); 20 | } 21 | unsigned int T = std::atoi(argv[1]); 22 | 23 | rclcpp::init(argc, argv); 24 | 25 | //! This type of executor is needed to handle multithreaded workloads 26 | //! coming from nodes 27 | rclcpp::executors::MultiThreadedExecutor smp_executor; 28 | 29 | //! So we explicitly need to add nodes to it 30 | auto smp_node = std::make_shared(); 31 | auto pub_node = std::make_shared(T); 32 | smp_executor.add_node(smp_node); 33 | smp_executor.add_node(pub_node); 34 | 35 | //! And then call its spin method directly 36 | smp_executor.spin(); 37 | 38 | rclcpp::shutdown(); 39 | exit(EXIT_SUCCESS); 40 | } 41 | -------------------------------------------------------------------------------- /src/cpp/advanced/smp_example/src/smp_node.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Multithreaded node code. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 26, 2021 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "../include/smp_example/smp_example.hpp" 13 | 14 | /** 15 | * @brief Creates an SMPNode. 16 | */ 17 | SMPNode::SMPNode() 18 | : Node("smp_node") 19 | { 20 | //! Callback groups (i.e. pointers to-) must be initialized in this way 21 | //! They can be mutually exclusive or reentrant 22 | clbk_group_1_ = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); 23 | clbk_group_2_ = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); 24 | 25 | //! When creating timers, the callback group must be passed to the API 26 | //! This is also true for services, whereas in topic subscriptions an 27 | //! appropriate object named "subscription option" must be populated and then 28 | //! passed to the API, like this: 29 | //! 30 | //! auto SUB_OPTS_OBJ = rclcpp::SubscriptionOptions(); 31 | //! SUB_OPTS_OBJ.callback_group = CLBK_GRP_OBJ; 32 | //! 33 | //! and this is exactly our case 34 | rclcpp::SubscriptionOptions sub_opts_1, sub_opts_2; 35 | sub_opts_1.callback_group = clbk_group_1_; 36 | sub_opts_2.callback_group = clbk_group_2_; 37 | 38 | sub_1_ = this->create_subscription( 39 | "/ros2_examples/smp_topic", 40 | rclcpp::QoS(10), 41 | std::bind( 42 | &SMPNode::sub_1_clbk, 43 | this, 44 | std::placeholders::_1 45 | ), 46 | sub_opts_1 47 | ); 48 | sub_2_ = this->create_subscription( 49 | "/ros2_examples/smp_topic", 50 | rclcpp::QoS(10), 51 | std::bind( 52 | &SMPNode::sub_2_clbk, 53 | this, 54 | std::placeholders::_1 55 | ), 56 | sub_opts_2 57 | ); 58 | 59 | RCLCPP_INFO(this->get_logger(), "Node initialized"); 60 | } 61 | 62 | //! Notice below the usage of the RCLCPP_*_STREAM macros, to directly 63 | //! access the underlying logging output stream. 64 | /** 65 | * @brief First subscriber callback. 66 | * 67 | * @param msg Message received. 68 | */ 69 | void SMPNode::sub_1_clbk(const std_msgs::msg::UInt64::SharedPtr msg) 70 | { 71 | RCLCPP_WARN_STREAM( 72 | this->get_logger(), 73 | "Hello " << msg->data << " from thread " << std::this_thread::get_id() << " (1)" 74 | ); 75 | } 76 | 77 | /** 78 | * @brief Second subscriber callback. 79 | * 80 | * @param msg Message received. 81 | */ 82 | void SMPNode::sub_2_clbk(const std_msgs::msg::UInt64::SharedPtr msg) 83 | { 84 | RCLCPP_WARN_STREAM( 85 | this->get_logger(), 86 | "Hello " << msg->data << " from thread " << std::this_thread::get_id() << " (2)" 87 | ); 88 | } 89 | -------------------------------------------------------------------------------- /src/cpp/custom_topic_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(custom_topic_cpp) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | # Default to C99 7 | if(NOT CMAKE_C_STANDARD) 8 | set(CMAKE_C_STANDARD 99) 9 | endif() 10 | 11 | # Default to C++14 12 | if(NOT CMAKE_CXX_STANDARD) 13 | set(CMAKE_CXX_STANDARD 17) 14 | endif() 15 | 16 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 17 | add_compile_options(-Wall -Wextra -Wpedantic) 18 | endif() 19 | 20 | # Find dependencies 21 | find_package(ament_cmake REQUIRED) 22 | find_package(rclcpp REQUIRED) 23 | find_package(ros2_examples_interfaces REQUIRED) 24 | 25 | # Publisher 26 | add_executable(pub src/pub.cpp) 27 | target_include_directories(pub PUBLIC 28 | $ 29 | $) 30 | ament_target_dependencies( 31 | pub 32 | rclcpp 33 | ros2_examples_interfaces) 34 | 35 | # Subscriber 36 | add_executable(sub src/sub.cpp) 37 | target_include_directories(sub PUBLIC 38 | $ 39 | $) 40 | ament_target_dependencies( 41 | sub 42 | rclcpp 43 | ros2_examples_interfaces) 44 | 45 | install(TARGETS pub 46 | DESTINATION lib/${PROJECT_NAME}) 47 | 48 | install(TARGETS sub 49 | DESTINATION lib/${PROJECT_NAME}) 50 | 51 | if(BUILD_TESTING) 52 | find_package(ament_lint_auto REQUIRED) 53 | # the following line skips the linter which checks for copyrights 54 | # uncomment the line when a copyright and license is not present in all source files 55 | #set(ament_cmake_copyright_FOUND TRUE) 56 | # the following line skips cpplint (only works in a git repo) 57 | # uncomment the line when this package is not in a git repo 58 | #set(ament_cmake_cpplint_FOUND TRUE) 59 | ament_lint_auto_find_test_dependencies() 60 | endif() 61 | 62 | ament_package() 63 | -------------------------------------------------------------------------------- /src/cpp/custom_topic_cpp/include/custom_topic_cpp/pub.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Publisher definition. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #ifndef PUB_HPP 10 | #define PUB_HPP 11 | 12 | #include //! rclcpp base library 13 | 14 | #include //! This time we use our own 15 | 16 | #define PUB_PERIOD 300 // Publisher transmission time period [ms] 17 | 18 | /** 19 | * Simple publisher node: transmits strings on a topic. 20 | */ 21 | //! Every node must extend publicly the Node base class 22 | class Pub : public rclcpp::Node 23 | { 24 | public: 25 | //! There must always be a constructor, with arbitrary input arguments 26 | Pub(); 27 | 28 | //! ROS-specific members better be private 29 | private: 30 | //! DDS endpoint, acting as a publisher 31 | //! Syntax is: rclcpp::Publisher::SharedPtr OBJ; 32 | rclcpp::Publisher::SharedPtr publisher_; 33 | 34 | 35 | //! ROS-2 managed timer: enables one to set up a periodic job 36 | //! The job is coded in a callback, which better be a private method 37 | //! Syntax is: rclcpp::TimerBase::SharedPtr OBJ; 38 | //! Callback signature must be: void FUNC_NAME(void); 39 | rclcpp::TimerBase::SharedPtr pub_timer_; 40 | void pub_timer_callback(void); 41 | 42 | unsigned long pub_cnt_; // Marks messages 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/cpp/custom_topic_cpp/include/custom_topic_cpp/sub.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Subscriber definition. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #ifndef SUB_HPP 10 | #define SUB_HPP 11 | 12 | #include //! rclcpp base library 13 | 14 | #include //! This time we use our own 15 | 16 | /** 17 | * Simple subscriber node: receives and prints strings transmitted on a topic. 18 | */ 19 | //! Every node must extend publicly the Node base class 20 | class Sub : public rclcpp::Node 21 | { 22 | public: 23 | //! There must always be a constructor, with arbitrary input arguments 24 | Sub(); 25 | 26 | //! ROS-specific members better be private 27 | private: 28 | //! DDS endpoint, acting as a subscriber 29 | //! When a message is received, a callback job is issued, which better be a private method 30 | //! Syntax is: rclcpp::Subscription::SharedPtr OBJ; 31 | //! Callback signature must be: 32 | //! void FUNC_NAME(const INTERFACE_TYPE::SharedPtr ARG_NAME); 33 | rclcpp::Subscription::SharedPtr subscriber_; 34 | void msg_callback(const ros2_examples_interfaces::msg::String::SharedPtr msg); 35 | 36 | //! Nothing else is necessary to receive messages 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/cpp/custom_topic_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | custom_topic_cpp 5 | 0.0.0 6 | Example of package that uses custom interfaces. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | ros2_examples_interfaces 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cpp/custom_topic_cpp/src/sub.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Subscriber definition and implementation. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | /** 14 | * @brief Creates a Sub node. 15 | */ 16 | //! Call the base class constructor providing a string embedding the node name 17 | //! Initialize other members at will 18 | Sub::Sub() 19 | : Node("subscriber_node") 20 | { 21 | //! This time we use an explicit QoS policy by creaitng a QoS object 22 | //! Syntax is: rclcpp::QoS obj_name(QUEUE_DEPTH) 23 | //! Then, we modify the individual parameters using the setter methods and the enums 24 | //! For a complete reference see the qos.hpp header from rclcpp (try to open it via VS Code!) 25 | rclcpp::QoS topic_qos(rclcpp::KeepLast(1)); 26 | topic_qos.best_effort(); //! Equivalenty: topic_qos.reliability(rclcpp::ReliabilityPolicy::Reliable); 27 | topic_qos.durability_volatile(); //! Equivalenty: topic_qos.durability(rclcpp::DurabilityPolicy::Volatile); 28 | 29 | //! Initialize a subscriber with create_subscription from the base class: 30 | //! this->create_subscription( 31 | //! TOPIC_NAME [string], 32 | //! SUBSCRIPTION_QoS (...), 33 | //! CALLBACK_WRAPPER (with captures and argument placeholders) 34 | //! (...) 35 | //! ); 36 | subscriber_ = this->create_subscription( 37 | "/publisher_node/examples/test_topic", 38 | topic_qos, 39 | std::bind( 40 | &Sub::msg_callback, 41 | this, 42 | std::placeholders::_1)); 43 | 44 | //! Logging macro used to deliver a message to the logging subsystem, INFO level 45 | RCLCPP_INFO(this->get_logger(), "Subscriber initialized"); 46 | } 47 | 48 | /** 49 | * @brief Echoes a new message. 50 | * 51 | * @param msg New message. 52 | */ 53 | void Sub::msg_callback(const ros2_examples_interfaces::msg::String::SharedPtr msg) 54 | { 55 | //! Get the data simply by accessing the object member as the interface specifies 56 | RCLCPP_INFO(this->get_logger(), msg->data.c_str()); 57 | } 58 | 59 | int main(int argc, char ** argv) 60 | { 61 | //! This automatically creates the global context->DDS participant for this application 62 | //! and parses all ROS-specific input arguments eventually passed to the new process 63 | //! (and installs signal handlers) 64 | rclcpp::init(argc, argv); 65 | 66 | //! Since it's all made of shared pointers, initialize the new node as such 67 | //! (note: here we're calling an actual constructor but obtaining a smart pointer 68 | //! to the new object) 69 | auto sub_node = std::make_shared(); 70 | 71 | //! This automatically creates a default, single-threaded executor, adds to it 72 | //! the jobs defined by the new node, and makes the current thread tend to that 73 | rclcpp::spin(sub_node); 74 | 75 | //! Whatever happens now, does so only after rclcpp::spin has returned 76 | 77 | //! Shut down the global context, the DDS participant and all its 78 | //! endpoints, effectively terminating the connection to the DDS layer 79 | //! (note: this doesn't necessarily destroy the corresponding objects) 80 | rclcpp::shutdown(); 81 | 82 | // Just exit 83 | std::cout << "Subscriber terminated" << std::endl; 84 | exit(EXIT_SUCCESS); 85 | } 86 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/config/bottom_detector.yaml: -------------------------------------------------------------------------------- 1 | /bottom_detector: 2 | ros__parameters: 3 | aruco_side: 0.15 4 | camera_offset: 0.08 5 | centering_width: 150 6 | compute_position: false 7 | error_min: 0.1 8 | rotate_image: false 9 | target_ids: 10 | - 1 11 | - 666 12 | - 69 13 | transport: compressed 14 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/config/front_detector.yaml: -------------------------------------------------------------------------------- 1 | /front_detector: 2 | ros__parameters: 3 | centering_width: 150 4 | compute_position: false 5 | rotate_image: false 6 | target_ids: 7 | - 15 8 | - 42 9 | - 666 10 | transport: compressed 11 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/config/tilted_detector.yaml: -------------------------------------------------------------------------------- 1 | /tilted_detector: 2 | ros__parameters: 3 | centering_width: 150 4 | compute_position: false 5 | rotate_image: false 6 | target_ids: 7 | - 15 8 | - 42 9 | - 666 10 | transport: compressed 11 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/launch/bottom_detector.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Bottom Aruco Detector launch file. 3 | 4 | Roberto Masocco 5 | Lorenzo Bianchi 6 | Intelligent Systems Lab 7 | 8 | August 18, 2022 9 | """ 10 | 11 | import os 12 | from ament_index_python.packages import get_package_share_directory 13 | 14 | from launch import LaunchDescription 15 | from launch_ros.actions import Node 16 | 17 | 18 | def generate_launch_description(): 19 | """Builds a LaunchDescription for the bottom Detector""" 20 | ld = LaunchDescription() 21 | 22 | # Build config file path 23 | config_file = os.path.join( 24 | get_package_share_directory('aruco_detector'), 25 | 'config', 26 | 'bottom_detector.yaml' 27 | ) 28 | 29 | # Create node launch description 30 | node = Node( 31 | package='aruco_detector', 32 | executable='aruco_detector', 33 | exec_name='bottom_detector', 34 | name='bottom_detector', 35 | shell=True, 36 | emulate_tty=True, 37 | output='both', 38 | log_cmd=True, 39 | parameters=[ 40 | config_file, 41 | { 42 | 'camera_topic': '/usb_camera_driver/camera/image_color', 43 | 'focal_length': 500 44 | } 45 | ] 46 | ) 47 | 48 | ld.add_action(node) 49 | 50 | return ld 51 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/launch/front_detector.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Front Aruco Detector launch file. 3 | 4 | Roberto Masocco 5 | Lorenzo Bianchi 6 | Intelligent Systems Lab 7 | 8 | August 18, 2022 9 | """ 10 | 11 | import os 12 | from ament_index_python.packages import get_package_share_directory 13 | 14 | from launch import LaunchDescription 15 | from launch_ros.actions import Node 16 | 17 | 18 | def generate_launch_description(): 19 | """Builds a LaunchDescription for the front Detector""" 20 | ld = LaunchDescription() 21 | 22 | # Build config file path 23 | config_file = os.path.join( 24 | get_package_share_directory('aruco_detector'), 25 | 'config', 26 | 'front_detector.yaml' 27 | ) 28 | 29 | # Create node launch description 30 | node = Node( 31 | package='aruco_detector', 32 | executable='aruco_detector', 33 | exec_name='front_detector', 34 | name='front_detector', 35 | shell=True, 36 | emulate_tty=True, 37 | output='both', 38 | log_cmd=True, 39 | parameters=[ 40 | config_file, 41 | {'camera_topic': '/zed_mini_driver/left/image_rect_color'} 42 | ] 43 | ) 44 | 45 | ld.add_action(node) 46 | 47 | return ld 48 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/launch/tilted_detector.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tilted Aruco Detector launch file. 3 | 4 | Roberto Masocco 5 | Lorenzo Bianchi 6 | Intelligent Systems Lab 7 | 8 | August 18, 2022 9 | """ 10 | 11 | import os 12 | from ament_index_python.packages import get_package_share_directory 13 | 14 | from launch import LaunchDescription 15 | from launch_ros.actions import Node 16 | 17 | 18 | def generate_launch_description(): 19 | """Builds a LaunchDescription for the tilted Detector""" 20 | ld = LaunchDescription() 21 | 22 | # Build config file path 23 | config_file = os.path.join( 24 | get_package_share_directory('aruco_detector'), 25 | 'config', 26 | 'tilted_detector.yaml' 27 | ) 28 | 29 | # Create node launch description 30 | node = Node( 31 | package='aruco_detector', 32 | executable='aruco_detector', 33 | exec_name='tilted_detector', 34 | name='tilted_detector', 35 | shell=True, 36 | emulate_tty=True, 37 | output='both', 38 | log_cmd=True, 39 | parameters=[ 40 | config_file, 41 | {'camera_topic': '/tilted_camera_driver/camera/image_rect_color'} 42 | ] 43 | ) 44 | 45 | ld.add_action(node) 46 | 47 | return ld 48 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | aruco_detector 5 | 1.0.0 6 | Target detection module. 7 | Intelligent Systems Lab 8 | GNU GPL v3.0 9 | 10 | ament_cmake 11 | 12 | image_transport 13 | rclcpp 14 | rclcpp_components 15 | sensor_msgs 16 | 18 | std_msgs 19 | std_srvs 20 | 21 | ament_lint_auto 22 | ament_lint_common 23 | 24 | 25 | ament_cmake 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/src/aruco_detector/ad_services.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Aruco Detector node service callbacks. 3 | * 4 | * Roberto Masocco 5 | * Lorenzo Bianchi 6 | * Intelligent Systems Lab 7 | * 8 | * August 16, 2022 9 | */ 10 | 11 | /** 12 | * This is free software. 13 | * You can redistribute it and/or modify this file under the 14 | * terms of the GNU General Public License as published by the Free Software 15 | * Foundation; either version 3 of the License, or (at your option) any later 16 | * version. 17 | * 18 | * This file is distributed in the hope that it will be useful, but WITHOUT ANY 19 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 20 | * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License along with 23 | * this file; if not, write to the Free Software Foundation, Inc., 24 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 25 | */ 26 | 27 | #include 28 | 29 | namespace ArucoDetector 30 | { 31 | 32 | /** 33 | * @brief Toggles target detection. 34 | * 35 | * @param req Service request to parse. 36 | * @param rest Service response to populate. 37 | */ 38 | void ArucoDetectorNode::enable_callback( 39 | SetBool::Request::SharedPtr req, 40 | SetBool::Response::SharedPtr resp) 41 | { 42 | if (req->data) { 43 | if (!is_on_) { 44 | camera_sub_ = image_transport::create_subscription( 45 | this, 46 | camera_topic_, 47 | std::bind( 48 | &ArucoDetectorNode::camera_callback, 49 | this, 50 | std::placeholders::_1), 51 | transport_, 52 | rmw_qos_profile_sensor_data); 53 | is_on_ = true; 54 | RCLCPP_WARN(this->get_logger(), "Detector ACTIVATED"); 55 | } 56 | resp->set__success(true); 57 | resp->set__message(""); 58 | } else { 59 | if (is_on_) { 60 | camera_sub_.shutdown(); 61 | is_on_ = false; 62 | RCLCPP_WARN(this->get_logger(), "Detector DEACTIVATED"); 63 | } 64 | resp->set__success(true); 65 | resp->set__message(""); 66 | } 67 | } 68 | 69 | } // namespace ArucoDetector 70 | -------------------------------------------------------------------------------- /src/cpp/image_processing/aruco_detector/src/aruco_detector_app.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Aruco Detector standalone application. 3 | * 4 | * Roberto Masocco 5 | * Lorenzo Bianchi 6 | * Intelligent Systems Lab 7 | * 8 | * August 16, 2022 9 | */ 10 | 11 | /** 12 | * This is free software. 13 | * You can redistribute it and/or modify this file under the 14 | * terms of the GNU General Public License as published by the Free Software 15 | * Foundation; either version 3 of the License, or (at your option) any later 16 | * version. 17 | * 18 | * This file is distributed in the hope that it will be useful, but WITHOUT ANY 19 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 20 | * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License along with 23 | * this file; if not, write to the Free Software Foundation, Inc., 24 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 25 | */ 26 | 27 | #define MODULE_NAME "aruco_detector_app" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include 39 | 40 | using namespace ArucoDetector; 41 | 42 | int main(int argc, char ** argv) 43 | { 44 | // Disable I/O buffering 45 | if (setvbuf(stdout, NULL, _IONBF, 0)) { 46 | RCLCPP_FATAL( 47 | rclcpp::get_logger(MODULE_NAME), 48 | "Failed to set I/O buffering"); 49 | exit(EXIT_FAILURE); 50 | } 51 | 52 | // Create and initialize ROS 2 context 53 | rclcpp::init(argc, argv); 54 | 55 | // Initialize ROS 2 node 56 | auto ad_node = std::make_shared(); 57 | 58 | // Create and configure executor 59 | auto executor = std::make_shared(); 60 | executor->add_node(ad_node); 61 | 62 | RCLCPP_WARN( 63 | rclcpp::get_logger(MODULE_NAME), 64 | "(%d) " MODULE_NAME " online", 65 | getpid()); 66 | 67 | // Spin the executor 68 | executor->spin(); 69 | 70 | // Destroy ROS 2 node and context 71 | ad_node.reset(); 72 | rclcpp::shutdown(); 73 | 74 | exit(EXIT_SUCCESS); 75 | } 76 | -------------------------------------------------------------------------------- /src/cpp/image_processing/ros2_usb_camera/config/camera.yaml: -------------------------------------------------------------------------------- 1 | image_width: 640 2 | image_height: 480 3 | camera_name: camera 4 | camera_matrix: 5 | rows: 3 6 | cols: 3 7 | data: 8 | [ 9 | 632.566858, 10 | 0.000000, 11 | 351.454440, 12 | 0.000000, 13 | 658.598474, 14 | 217.547643, 15 | 0.000000, 16 | 0.000000, 17 | 1.000000, 18 | ] 19 | distortion_model: plumb_bob 20 | distortion_coefficients: 21 | rows: 1 22 | cols: 5 23 | data: [-0.420743, 0.195264, -0.000420, -0.000531, 0.000000] 24 | rectification_matrix: 25 | rows: 3 26 | cols: 3 27 | data: 28 | [ 29 | 1.000000, 30 | 0.000000, 31 | 0.000000, 32 | 0.000000, 33 | 1.000000, 34 | 0.000000, 35 | 0.000000, 36 | 0.000000, 37 | 1.000000, 38 | ] 39 | projection_matrix: 40 | rows: 3 41 | cols: 4 42 | data: 43 | [ 44 | 554.981445, 45 | 0.000000, 46 | 359.055802, 47 | 0.000000, 48 | 0.000000, 49 | 616.663513, 50 | 214.051434, 51 | 0.000000, 52 | 0.000000, 53 | 0.000000, 54 | 1.000000, 55 | 0.000000, 56 | ] 57 | -------------------------------------------------------------------------------- /src/cpp/image_processing/ros2_usb_camera/config/config.yaml: -------------------------------------------------------------------------------- 1 | /usb_camera_driver: 2 | ros__parameters: 3 | base_topic_name: camera 4 | best_effort_qos: true 5 | brightness: 0.0 6 | camera_calibration_file: file://config/camera.yaml 7 | camera_id: 0 8 | camera_name: camera 9 | exposure: 0.0 10 | fps: 20 11 | frame_id: usb_camera 12 | image_height: 480 13 | image_width: 640 14 | is_flipped: false 15 | wb_temperature: 0.0 16 | # image_transport parameters 17 | usb_camera_driver: 18 | camera: 19 | image_color: 20 | format: jpeg 21 | jpeg_quality: 95 22 | png_level: 3 23 | image_rect_color: 24 | format: jpeg 25 | jpeg_quality: 95 26 | png_level: 3 27 | -------------------------------------------------------------------------------- /src/cpp/image_processing/ros2_usb_camera/launch/usb_camera_driver_app.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | ROS 2 USB Camera Driver app launch file. 3 | 4 | Roberto Masocco 5 | Lorenzo Bianchi 6 | Intelligent Systems Lab 7 | 8 | June 4, 2022 9 | """ 10 | 11 | import os 12 | from ament_index_python.packages import get_package_share_directory 13 | 14 | from launch import LaunchDescription 15 | from launch_ros.actions import Node 16 | 17 | 18 | def generate_launch_description(): 19 | """Builds a LaunchDescription for the ROS 2 USB Camera Driver app""" 20 | ld = LaunchDescription() 21 | 22 | # Build config file path 23 | config_file = os.path.join( 24 | get_package_share_directory('ros2_usb_camera'), 25 | 'config', 26 | 'config.yaml' 27 | ) 28 | 29 | # Create node launch description 30 | node = Node( 31 | package='ros2_usb_camera', 32 | executable='usb_camera_app', 33 | exec_name='usb_camera_app', 34 | shell=True, 35 | emulate_tty=True, 36 | output='both', 37 | log_cmd=True, 38 | parameters=[config_file] 39 | ) 40 | 41 | ld.add_action(node) 42 | 43 | return ld 44 | -------------------------------------------------------------------------------- /src/cpp/image_processing/ros2_usb_camera/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ros2_usb_camera 5 | 1.0.0 6 | Package containing a simple web camera setup 7 | Intelligent Systems Lab 8 | GNU GPL v3.0 9 | 10 | ament_cmake 11 | 12 | camera_calibration_parsers 13 | camera_info_manager 14 | image_transport 15 | libopencv-dev 16 | rclcpp 17 | rclcpp_components 18 | sensor_msgs 19 | std_msgs 20 | std_srvs 21 | 22 | ament_lint_auto 23 | 24 | 25 | ament_cmake 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/cpp/image_processing/ros2_usb_camera/src/ucd_app.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * ROS 2 USB Camera standalone application. 3 | * 4 | * Roberto Masocco 5 | * Lorenzo Bianchi 6 | * Intelligent Systems Lab 7 | * 8 | * June 4, 2022 9 | */ 10 | 11 | /** 12 | * Copyright © 2022 Intelligent Systems Lab 13 | */ 14 | 15 | /** 16 | * This is free software. 17 | * You can redistribute it and/or modify this file under the 18 | * terms of the GNU General Public License as published by the Free Software 19 | * Foundation; either version 3 of the License, or (at your option) any later 20 | * version. 21 | * 22 | * This file is distributed in the hope that it will be useful, but WITHOUT ANY 23 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 24 | * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 25 | * 26 | * You should have received a copy of the GNU General Public License along with 27 | * this file; if not, write to the Free Software Foundation, Inc., 28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 29 | */ 30 | 31 | #define MODULE_NAME "usb_camera_app" 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include 43 | 44 | using namespace USBCameraDriver; 45 | 46 | int main(int argc, char ** argv) 47 | { 48 | // Disable I/O buffering 49 | if (setvbuf(stdout, NULL, _IONBF, 0)) { 50 | RCLCPP_FATAL( 51 | rclcpp::get_logger(MODULE_NAME), 52 | "Failed to set I/O buffering"); 53 | exit(EXIT_FAILURE); 54 | } 55 | 56 | // Initialize ROS 2 context 57 | rclcpp::init(argc, argv); 58 | 59 | // Initialize ROS 2 node 60 | auto usb_camera_driver_node = std::make_shared(); 61 | 62 | RCLCPP_WARN( 63 | rclcpp::get_logger(MODULE_NAME), 64 | "(%d) " MODULE_NAME " online", 65 | getpid()); 66 | 67 | // Spin on the node 68 | rclcpp::spin(usb_camera_driver_node); 69 | 70 | // Terminate node and application 71 | usb_camera_driver_node.reset(); 72 | rclcpp::shutdown(); 73 | exit(EXIT_SUCCESS); 74 | } 75 | -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(rqt_image_view) 4 | 5 | find_package(ament_cmake REQUIRED) 6 | 7 | if(WIN32) 8 | message(STATUS "rqt_image_view is not yet supported on Windows. Package will not be built.") 9 | ament_package() 10 | return() 11 | endif() 12 | 13 | # Find includes in corresponding build directories 14 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 15 | 16 | # Default to C++14 17 | if(NOT CMAKE_CXX_STANDARD) 18 | set(CMAKE_CXX_STANDARD 14) 19 | endif() 20 | 21 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 22 | add_compile_options(-Wall -Wextra -Wpedantic) 23 | endif() 24 | 25 | find_package(rclcpp REQUIRED) 26 | find_package(qt_gui_cpp REQUIRED) 27 | find_package(rqt_gui_cpp REQUIRED) 28 | find_package(image_transport REQUIRED) 29 | find_package(sensor_msgs REQUIRED) 30 | find_package(geometry_msgs REQUIRED) 31 | find_package(cv_bridge REQUIRED) 32 | find_package(Qt5Widgets REQUIRED) 33 | find_package(ament_cmake_python REQUIRED) 34 | 35 | set(rqt_image_view_SRCS 36 | src/rqt_image_view/image_view.cpp 37 | src/rqt_image_view/ratio_layouted_frame.cpp 38 | ) 39 | 40 | set(rqt_image_view_HDRS 41 | include/rqt_image_view/image_view.h 42 | include/rqt_image_view/ratio_layouted_frame.h 43 | ) 44 | 45 | set(rqt_image_view_UIS 46 | src/rqt_image_view/image_view.ui 47 | ) 48 | 49 | qt5_wrap_cpp(rqt_image_view_MOCS ${rqt_image_view_HDRS}) 50 | 51 | qt5_wrap_ui(rqt_image_view_UIS_H ${rqt_image_view_UIS}) 52 | 53 | add_library(${PROJECT_NAME} SHARED 54 | ${rqt_image_view_SRCS} 55 | ${rqt_image_view_MOCS} 56 | ${rqt_image_view_UIS_H} 57 | ) 58 | 59 | target_include_directories(${PROJECT_NAME} PUBLIC 60 | "$" 61 | "$") 62 | 63 | target_link_libraries(${PROJECT_NAME} PUBLIC 64 | ${rclcpp_TARGETS} 65 | ${qt_gui_cpp_TARGETS} 66 | ${rqt_gui_cpp_TARGETS} 67 | image_transport::image_transport 68 | ${sensor_msgs_TARGETS} 69 | ${geometry_msgs_TARGETS} 70 | Qt5::Widgets 71 | ) 72 | target_link_libraries(${PROJECT_NAME} PRIVATE 73 | cv_bridge::cv_bridge) 74 | 75 | install( 76 | TARGETS ${PROJECT_NAME} 77 | EXPORT ${PROJECT_NAME} 78 | ARCHIVE DESTINATION lib/${PROJECT_NAME} 79 | LIBRARY DESTINATION lib/${PROJECT_NAME} 80 | RUNTIME DESTINATION bin/${PROJECT_NAME}) 81 | 82 | install(PROGRAMS scripts/rqt_image_view 83 | DESTINATION lib/${PROJECT_NAME} 84 | ) 85 | 86 | install(PROGRAMS scripts/image_publisher 87 | DESTINATION lib/${PROJECT_NAME} 88 | ) 89 | 90 | install( 91 | DIRECTORY include/ 92 | DESTINATION include/${PROJECT_NAME} 93 | ) 94 | 95 | install(FILES plugin.xml 96 | DESTINATION share/${PROJECT_NAME} 97 | ) 98 | 99 | install(DIRECTORY resource 100 | DESTINATION share/${PROJECT_NAME} 101 | ) 102 | 103 | pluginlib_export_plugin_description_file(rqt_gui "plugin.xml") 104 | 105 | # Export old-style CMake variables 106 | ament_export_include_directories("include/${PROJECT_NAME}") 107 | ament_export_libraries(${PROJECT_NAME}) 108 | 109 | # Export new-style CMake variables 110 | ament_export_targets(${PROJECT_NAME}) 111 | 112 | ament_package() 113 | -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/mainpage.dox: -------------------------------------------------------------------------------- 1 | /** 2 | \mainpage 3 | \htmlinclude manifest.html 4 | 5 | \b rqt_image_view provides a GUI plugin for displaying images using image_transport. 6 | */ 7 | -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/package.xml: -------------------------------------------------------------------------------- 1 | 2 | rqt_image_view 3 | 1.2.0 4 | rqt_image_view provides a GUI plugin for displaying images using image_transport. 5 | Mabel Zhang 6 | 7 | BSD 8 | 9 | http://wiki.ros.org/rqt_image_view 10 | https://github.com/ros-visualization/rqt_image_view 11 | https://github.com/ros-visualization/rqt_image_view/issues 12 | 13 | Dirk Thomas 14 | 15 | ament_cmake 16 | 17 | rclcpp 18 | 19 | cv_bridge 20 | geometry_msgs 21 | image_transport 22 | qtbase5-dev 23 | rqt_gui 24 | rqt_gui_cpp 25 | qt_gui_cpp 26 | sensor_msgs 27 | 28 | cv_bridge 29 | geometry_msgs 30 | image_transport 31 | rqt_gui 32 | rqt_gui_cpp 33 | qt_gui_cpp 34 | sensor_msgs 35 | 36 | 37 | ament_cmake 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A GUI plugin to view a sensor_msgs/Image topic. 5 | 6 | 7 | 8 | 9 | folder 10 | Plugins related to visualization. 11 | 12 | 13 | image-x-generic 14 | A GUI plugin for viewing sensor_msgs/Image topics. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/resource/lena.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/src/cpp/image_processing/rqt_image_view/resource/lena.png -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/scripts/image_publisher: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2016 Open Source Robotics Foundation, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import os 18 | import sys 19 | 20 | from copy import deepcopy 21 | 22 | from ament_index_python.resources import get_resource 23 | 24 | from cv2 import imread 25 | 26 | import rclpy 27 | from rclpy.node import Node 28 | from rclpy.qos import QoSProfile 29 | 30 | from sensor_msgs.msg import Image 31 | 32 | 33 | class ImagePublisher(Node): 34 | 35 | def __init__(self): 36 | super().__init__('image_publisher') 37 | self.i = 0 38 | qos_profile = QoSProfile(depth=1) 39 | 40 | self.pub = self.create_publisher(Image, 'images', qos_profile=qos_profile) 41 | timer_period = 0.10 42 | self.tmr = self.create_timer(timer_period, self.timer_callback) 43 | _, package_path = get_resource('packages', 'rqt_image_view') 44 | example_image_file = os.path.join( 45 | package_path, 'share', 'rqt_image_view', 'resource', 'lena.png') 46 | 47 | self.img = imread(example_image_file) 48 | self.msg = Image() 49 | self.msg.data = [int(b) for b in list(self.img.flatten())] 50 | self.msg.height = self.img.shape[0] 51 | self.msg.width = self.img.shape[1] 52 | self.msg.encoding = 'rgb8' 53 | self.msg.step = self.img.shape[1] * self.img.shape[2] 54 | 55 | def timer_callback(self): 56 | self.i += 1 57 | self.get_logger().info('Publishing Lena: "{0}"'.format(self.i)) 58 | self.msg.data = self.msg.data[2:] + self.msg.data[:2] 59 | self.pub.publish(self.msg) 60 | 61 | 62 | def main(args=None): 63 | if args is None: 64 | args = sys.argv 65 | 66 | rclpy.init(args=args) 67 | 68 | node = ImagePublisher() 69 | 70 | rclpy.spin(node) 71 | 72 | node.destroy_node() 73 | rclpy.shutdown() 74 | 75 | 76 | if __name__ == '__main__': 77 | main() 78 | -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/scripts/rqt_image_view: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | from rqt_gui.main import Main 6 | 7 | 8 | def add_arguments(parser): 9 | group = parser.add_argument_group('Options for rqt_image_view plugin') 10 | group.add_argument('topic', nargs='?', help='The topic name to subscribe to') 11 | 12 | main = Main() 13 | sys.exit(main.main( 14 | sys.argv, 15 | standalone='rqt_image_view/ImageView', 16 | plugin_argument_provider=add_arguments)) 17 | -------------------------------------------------------------------------------- /src/cpp/image_processing/rqt_image_view/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from distutils.core import setup 4 | from catkin_pkg.python_setup import generate_distutils_setup 5 | 6 | d = generate_distutils_setup( 7 | packages=['rqt_image_view'], 8 | package_dir={'': 'src'}, 9 | scripts=['scripts/rqt_image_view'] 10 | ) 11 | 12 | setup(**d) 13 | -------------------------------------------------------------------------------- /src/cpp/parameters_example_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(parameters_example_cpp) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | # Default to C99 7 | if(NOT CMAKE_C_STANDARD) 8 | set(CMAKE_C_STANDARD 99) 9 | endif() 10 | 11 | # Default to C++17 12 | if(NOT CMAKE_CXX_STANDARD) 13 | set(CMAKE_CXX_STANDARD 17) 14 | endif() 15 | 16 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 17 | add_compile_options(-Wall -Wextra -Wpedantic) 18 | endif() 19 | 20 | # Find dependencies 21 | find_package(ament_cmake REQUIRED) 22 | find_package(rclcpp REQUIRED) 23 | find_package(std_msgs REQUIRED) 24 | 25 | # Parametric publisher 26 | add_executable(parametric_pub 27 | src/parametric_pub.cpp 28 | src/parametric_node.cpp) 29 | target_include_directories(parametric_pub PUBLIC 30 | $ 31 | $) 32 | target_compile_features(parametric_pub PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 33 | ament_target_dependencies( 34 | parametric_pub 35 | rclcpp 36 | std_msgs) 37 | 38 | # Install executable 39 | install(TARGETS parametric_pub 40 | DESTINATION lib/${PROJECT_NAME}) 41 | 42 | # Install config files 43 | install(DIRECTORY config 44 | DESTINATION share/${PROJECT_NAME}) 45 | 46 | # Install launch files 47 | install(DIRECTORY launch 48 | DESTINATION share/${PROJECT_NAME}) 49 | 50 | if(BUILD_TESTING) 51 | find_package(ament_lint_auto REQUIRED) 52 | # the following line skips the linter which checks for copyrights 53 | # uncomment the line when a copyright and license is not present in all source files 54 | #set(ament_cmake_copyright_FOUND TRUE) 55 | # the following line skips cpplint (only works in a git repo) 56 | # uncomment the line when this package is not in a git repo 57 | #set(ament_cmake_cpplint_FOUND TRUE) 58 | ament_lint_auto_find_test_dependencies() 59 | endif() 60 | 61 | ament_package() 62 | -------------------------------------------------------------------------------- /src/cpp/parameters_example_cpp/config/node_parameters.yaml: -------------------------------------------------------------------------------- 1 | # Example parameter config file 2 | # Roberto Masocco 3 | # January 6, 2022 4 | 5 | # This completely embeds the basic structure of a YAML parameter file. 6 | # Note that this could be used for multiple nodes at once: just repeat the following block! 7 | # Eventual namespaces would have to be prepended. 8 | # A comprehensive guide can be found at: https://roboticsbackend.com/ros2-yaml-params/ 9 | # Don't forget slashes in names, otherwise stuff won't work! 10 | 11 | /parametric_pub: 12 | ros__parameters: 13 | number: 10 14 | -------------------------------------------------------------------------------- /src/cpp/parameters_example_cpp/include/parameters_example/parametric_node.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Parametric publisher definition. 3 | * 4 | * Roberto Masocco 5 | * 6 | * December 3, 2021 7 | */ 8 | 9 | #ifndef PARAMETRIC_PUB_HPP 10 | #define PARAMETRIC_PUB_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | using namespace std_msgs::msg; 17 | 18 | /** 19 | * Node that publishes a number, which can be set by a parameter. 20 | */ 21 | class ParametricPub : public rclcpp::Node 22 | { 23 | public: 24 | ParametricPub(); 25 | 26 | private: 27 | int pub_num_; //! Number to be published 28 | rcl_interfaces::msg::ParameterDescriptor param_descriptor_; //! Number parameter descriptor 29 | 30 | rclcpp::Publisher::SharedPtr num_publisher_; 31 | 32 | //! There has to be, if needed, a single parameter set callback, with this syntax 33 | OnSetParametersCallbackHandle::SharedPtr param_clbk_handle_; 34 | rcl_interfaces::msg::SetParametersResult param_clbk(const std::vector ¶ms); 35 | 36 | rclcpp::TimerBase::SharedPtr pub_timer_; 37 | void pub_routine(); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/cpp/parameters_example_cpp/launch/launch_param_dict.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of a launch file for a node with parameters. 3 | 4 | Roberto Masocco 5 | 6 | January 6, 2022 7 | """ 8 | 9 | #! These are necessary to build the launch description 10 | from launch import LaunchDescription 11 | from launch_ros.actions import Node 12 | 13 | 14 | def generate_launch_description(): 15 | ld = LaunchDescription() 16 | 17 | #! Here the configuration is given as a Python dictionary 18 | config = { 19 | "number": 3 20 | } 21 | 22 | # Create node launch description 23 | node = Node( 24 | package='parameters_example_cpp', 25 | name='parametric_pub', 26 | executable='parametric_pub', 27 | parameters=[config] # ! We could specify more than one source here 28 | ) 29 | 30 | # Finalize launch description 31 | ld.add_action(node) 32 | return ld 33 | -------------------------------------------------------------------------------- /src/cpp/parameters_example_cpp/launch/launch_param_example.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of a launch file for a node with parameters. 3 | 4 | Roberto Masocco 5 | 6 | January 6, 2022 7 | """ 8 | 9 | # Necessary to build config file path 10 | #! We follow a standard convention that requires it to be placed in: 11 | #! install/PACKAGE/share/PACKAGE/config/ 12 | import os 13 | from ament_index_python.packages import get_package_share_directory 14 | 15 | #! These are necessary to build the launch description 16 | from launch import LaunchDescription 17 | from launch_ros.actions import Node 18 | 19 | def generate_launch_description(): 20 | ld = LaunchDescription() 21 | 22 | # Build config file path 23 | config = os.path.join( 24 | get_package_share_directory('parameters_example_cpp'), 25 | 'config', 26 | 'node_parameters.yaml' 27 | ) 28 | 29 | # Create node launch description 30 | node = Node( 31 | package='parameters_example_cpp', 32 | name='parametric_pub', 33 | executable='parametric_pub', 34 | parameters=[config] #! We could specify more than one source here 35 | ) 36 | 37 | # Finalize launch description 38 | ld.add_action(node) 39 | return ld 40 | -------------------------------------------------------------------------------- /src/cpp/parameters_example_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | parameters_example_cpp 5 | 0.0.0 6 | Simple node parameters example. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | std_msgs 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cpp/parameters_example_cpp/src/parametric_pub.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Node parameters example. 3 | * 4 | * Roberto Masocco 5 | * 6 | * December 3, 2021 7 | */ 8 | 9 | #include 10 | 11 | #include "../include/parameters_example/parametric_node.hpp" 12 | 13 | //! No special setup is required here, you only have to start this with: 14 | //! ros2 run parameters_examples parametric_pub --ros-args -p number:=... 15 | //! or load the parameter file with: 16 | //! ros2 run parameters_example parametric_pub --ros-args --params-file PATH_TO_FILE 17 | //! Test with: 18 | //! ros2 param list [...] 19 | //! ros2 param describe [...] 20 | //! ros2 param get 21 | //! ros2 param set 22 | //! ros2 param dump 23 | //! ros2 param load 24 | //! Note how there's autocompletion for everything! 25 | //! For more APIs (some will be shown later) see documentation of class rclcpp::Node 26 | int main(int argc, char ** argv) 27 | { 28 | rclcpp::init(argc, argv); //! Parameter specification arguments will be parsed here 29 | auto node_ptr = std::make_shared(); 30 | rclcpp::spin(node_ptr); 31 | rclcpp::shutdown(); 32 | exit(EXIT_SUCCESS); 33 | } 34 | 35 | //! Note that all the functionalities that CLI tools offer can also be achieved 36 | //! at runtime by other nodes, which can interact with each other by querying and 37 | //! setting parameters 38 | //! Just run "ros2 service list -t" after this application is up to notice that 39 | //! every node offers specific services to interact with parameters 40 | //! You can use those services via CLI as well as from another node's code 41 | //! Alternatively, there's the native "AsyncParametersClient" object that 42 | //! offers APIs to do more or less that 43 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygon_base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(polygon_base) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 7 | add_compile_options(-Wall -Wextra -Wpedantic) 8 | endif() 9 | 10 | # install base headers 11 | #! this package exists just for this 12 | install(DIRECTORY include/ 13 | DESTINATION include) 14 | 15 | # find dependencies 16 | find_package(ament_cmake REQUIRED) 17 | find_package(pluginlib REQUIRED) 18 | 19 | if(BUILD_TESTING) 20 | find_package(ament_lint_auto REQUIRED) 21 | # the following line skips the linter which checks for copyrights 22 | # uncomment the line when a copyright and license is not present in all source files 23 | #set(ament_cmake_copyright_FOUND TRUE) 24 | # the following line skips cpplint (only works in a git repo) 25 | # uncomment the line when this package is not in a git repo 26 | #set(ament_cmake_cpplint_FOUND TRUE) 27 | ament_lint_auto_find_test_dependencies() 28 | endif() 29 | 30 | # export headers for ament 31 | ament_export_include_directories(include) 32 | 33 | ament_package() 34 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygon_base/include/polygon_base/polygon.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Polygon abstract base class. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 28, 2022 7 | */ 8 | 9 | #ifndef POLYGON_BASE_POLYGON_HPP_ 10 | #define POLYGON_BASE_POLYGON_HPP_ 11 | 12 | //! All must be enclosed in a namespace for pluginlib to work 13 | namespace PolygonBase 14 | { 15 | 16 | /** 17 | * Generic regular polygon. 18 | */ 19 | //! We want this to be an abstract class 20 | class Polygon 21 | { 22 | public: 23 | //! Necessary since constructor can't have parameters! 24 | virtual void init(double side_length) = 0; 25 | virtual double area() = 0; 26 | //! If necessary, add a fini method 27 | 28 | //! Has to be virtual to comply with C++ specification 29 | virtual ~Polygon() {} 30 | 31 | protected: 32 | //! This costructor signature is required by pluginlib 33 | Polygon() {} 34 | }; 35 | 36 | } // namespace PolygonBase 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygon_base/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | polygon_base 5 | 0.0.0 6 | Example plugin base package. 7 | Roberto Masocco 8 | TODO: License declaration 9 | 10 | ament_cmake 11 | 12 | pluginlib 13 | 14 | ament_lint_auto 15 | ament_lint_common 16 | 17 | 18 | ament_cmake 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(polygons) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | #! it's highly suggested to generate this with colcon by specifying --library-name 7 | 8 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 9 | add_compile_options(-Wall -Wextra -Wpedantic -fvisibility=hidden) #! notice the last flag, for DSOs 10 | endif() 11 | 12 | # find dependencies 13 | find_package(ament_cmake REQUIRED) 14 | find_package(ament_cmake_ros REQUIRED) 15 | find_package(pluginlib REQUIRED) 16 | find_package(polygon_base REQUIRED) 17 | 18 | # triangle library 19 | add_library(triangle src/triangle.cpp) 20 | target_compile_features(triangle PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 21 | target_compile_definitions(triangle PRIVATE "POLYGONS_BUILDING_LIBRARY") 22 | target_include_directories(triangle PUBLIC 23 | $ 24 | $) 25 | ament_target_dependencies( 26 | triangle 27 | pluginlib 28 | polygon_base) 29 | 30 | # square library 31 | add_library(square src/square.cpp) 32 | target_compile_features(square PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 33 | target_compile_definitions(square PRIVATE "POLYGONS_BUILDING_LIBRARY") 34 | target_include_directories(square PUBLIC 35 | $ 36 | $) 37 | ament_target_dependencies( 38 | square 39 | pluginlib 40 | polygon_base) 41 | 42 | #! link plugins with base class for pluginlib 43 | pluginlib_export_plugin_description_file(polygon_base plugins.xml) 44 | 45 | # install library headers 46 | install( 47 | DIRECTORY include/ 48 | DESTINATION include) 49 | 50 | # install library binaries 51 | install( 52 | TARGETS triangle 53 | EXPORT export_${PROJECT_NAME} 54 | ARCHIVE DESTINATION lib 55 | LIBRARY DESTINATION lib 56 | RUNTIME DESTINATION bin) 57 | install( 58 | TARGETS square 59 | EXPORT export_${PROJECT_NAME} 60 | ARCHIVE DESTINATION lib 61 | LIBRARY DESTINATION lib 62 | RUNTIME DESTINATION bin) 63 | 64 | if(BUILD_TESTING) 65 | find_package(ament_lint_auto REQUIRED) 66 | # the following line skips the linter which checks for copyrights 67 | # uncomment the line when a copyright and license is not present in all source files 68 | #set(ament_cmake_copyright_FOUND TRUE) 69 | # the following line skips cpplint (only works in a git repo) 70 | # uncomment the line when this package is not in a git repo 71 | #set(ament_cmake_cpplint_FOUND TRUE) 72 | ament_lint_auto_find_test_dependencies() 73 | endif() 74 | 75 | #! export headers and binaries for ament 76 | ament_export_include_directories( 77 | include) 78 | ament_export_libraries( 79 | triangle 80 | square) 81 | ament_export_targets( 82 | export_${PROJECT_NAME}) 83 | 84 | ament_package() 85 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/include/polygons/square.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Square plugin structure. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 29, 2022 7 | */ 8 | 9 | #ifndef POLYGONS__SQUARE_HPP_ 10 | #define POLYGONS__SQUARE_HPP_ 11 | 12 | //! Include base class header and visibility control macros 13 | #include 14 | #include 15 | 16 | //! Namespaces must reflect what is written in plugins.xml! 17 | namespace Polygons 18 | { 19 | 20 | /** 21 | * Regular polygon with four sides. 22 | */ 23 | class POLYGONS_PUBLIC Square : public PolygonBase::Polygon 24 | { 25 | //! Stuff in here must be like in the base class: virtual methods must be 26 | //! defined, then one can add whatever one wants, but only what is defined 27 | //! in the base class will be visible! 28 | //! Member functions from the base class must be overridden, since we'll 29 | //! access them through a pointer to the base class 30 | public: 31 | void init(double side_length) override; 32 | double area() override; 33 | 34 | //! There must not be any private members 35 | protected: 36 | double side_length_; 37 | }; 38 | 39 | } // namespace Polygons 40 | 41 | #endif // POLYGONS__SQUARE_HPP_ 42 | 43 | //! Necessary to register plugin classes with pluginlib 44 | #include 45 | 46 | //! Register this class for pluginlib, providing derived and base fully 47 | //! qualified names 48 | PLUGINLIB_EXPORT_CLASS(Polygons::Square, PolygonBase::Polygon) 49 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/include/polygons/triangle.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Triangle plugin structure. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 29, 2022 7 | */ 8 | 9 | #ifndef POLYGONS__TRIANGLE_HPP_ 10 | #define POLYGONS__TRIANGLE_HPP_ 11 | 12 | //! Include base class header and visibility control macros 13 | #include 14 | #include 15 | 16 | //! Namespaces must reflect what is written in plugins.xml! 17 | namespace Polygons 18 | { 19 | 20 | /** 21 | * Regular polygon with three sides. 22 | */ 23 | class POLYGONS_PUBLIC Triangle : public PolygonBase::Polygon 24 | { 25 | //! Stuff in here must be like in the base class: virtual methods must be 26 | //! defined, then one can add whatever one wants, but only what is defined 27 | //! in the base class will be visible! 28 | //! Member functions from the base class must be overridden, since we'll 29 | //! access them through a pointer to the base class 30 | public: 31 | void init(double side_length) override; 32 | double area() override; 33 | 34 | //! There must not be any private members 35 | protected: 36 | double POLYGONS_LOCAL compute_height(); 37 | double side_length_; 38 | }; 39 | 40 | } // namespace Polygons 41 | 42 | #endif // POLYGONS__TRIANGLE_HPP_ 43 | 44 | //! Necessary to register plugin classes with pluginlib 45 | #include 46 | 47 | //! Register this class for pluginlib, providing derived and base fully 48 | //! qualified names 49 | PLUGINLIB_EXPORT_CLASS(Polygons::Triangle, PolygonBase::Polygon) 50 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/include/polygons/visibility_control.h: -------------------------------------------------------------------------------- 1 | #ifndef POLYGONS__VISIBILITY_CONTROL_H_ 2 | #define POLYGONS__VISIBILITY_CONTROL_H_ 3 | 4 | // This logic was borrowed (then namespaced) from the examples on the gcc wiki: 5 | // https://gcc.gnu.org/wiki/Visibility 6 | //! See that reference to understand why these macros are necessary to optimize 7 | //! both code and generated binaries 8 | 9 | #if defined _WIN32 || defined __CYGWIN__ 10 | #ifdef __GNUC__ 11 | #define POLYGONS_EXPORT __attribute__ ((dllexport)) 12 | #define POLYGONS_IMPORT __attribute__ ((dllimport)) 13 | #else 14 | #define POLYGONS_EXPORT __declspec(dllexport) 15 | #define POLYGONS_IMPORT __declspec(dllimport) 16 | #endif 17 | #ifdef POLYGONS_BUILDING_LIBRARY 18 | #define POLYGONS_PUBLIC POLYGONS_EXPORT 19 | #else 20 | #define POLYGONS_PUBLIC POLYGONS_IMPORT 21 | #endif 22 | #define POLYGONS_PUBLIC_TYPE POLYGONS_PUBLIC 23 | #define POLYGONS_LOCAL 24 | #else 25 | //! In declarations, you'd use these two when building the library, and 26 | //! when using it from outside (including its header which includes this) 27 | #define POLYGONS_EXPORT __attribute__ ((visibility("default"))) 28 | #define POLYGONS_IMPORT 29 | #if __GNUC__ >= 4 30 | //! In definitions, while writing the library code, you'd use these 31 | //! to mark stuff that must be visible from outside the DSO and stuff that 32 | //! must not be so 33 | #define POLYGONS_PUBLIC __attribute__ ((visibility("default"))) 34 | #define POLYGONS_LOCAL __attribute__ ((visibility("hidden"))) 35 | #else 36 | #define POLYGONS_PUBLIC 37 | #define POLYGONS_LOCAL 38 | #endif 39 | #define POLYGONS_PUBLIC_TYPE 40 | #endif 41 | 42 | #endif // POLYGONS__VISIBILITY_CONTROL_H_ 43 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | polygons 5 | 0.0.0 6 | Example plugins package. 7 | Roberto Masocco 8 | TODO: License declaration 9 | 10 | ament_cmake_ros 11 | 12 | pluginlib 13 | polygon_base 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This is a triangle plugin. 5 | 6 | 7 | 8 | 9 | This is a square plugin. 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/src/square.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Square plugin implementation. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 29, 2022 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | namespace Polygons 14 | { 15 | 16 | /** 17 | * @brief Initializes a Square object. 18 | * 19 | * @param side_length Side length to store. 20 | */ 21 | void POLYGONS_EXPORT Square::init(double side_length) 22 | { 23 | side_length_ = side_length; 24 | } 25 | 26 | /** 27 | * @brief Returns the area of the current Square. 28 | * 29 | * @return Square area. 30 | */ 31 | double POLYGONS_EXPORT Square::area() 32 | { 33 | return pow(side_length_, 2.0); 34 | } 35 | 36 | } // namespace Polygons 37 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons/src/triangle.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Triangle plugin implementation. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 29, 2022 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | namespace Polygons 14 | { 15 | 16 | /** 17 | * @brief Initializes a Triangle object. 18 | * 19 | * @param side_length Side length to store. 20 | */ 21 | void POLYGONS_EXPORT Triangle::init(double side_length) 22 | { 23 | side_length_ = side_length; 24 | } 25 | 26 | /** 27 | * @brief Returns the area of the current Triangle. 28 | * 29 | * @return Triangle area. 30 | */ 31 | double POLYGONS_EXPORT Triangle::area() 32 | { 33 | return 0.5 * side_length_ * compute_height(); 34 | } 35 | 36 | /** 37 | * @brief Computes the height of the current Triangle. 38 | * 39 | * @return Triangle height. 40 | */ 41 | double POLYGONS_IMPORT Triangle::compute_height() 42 | { 43 | return sqrt((side_length_ * side_length_) - ((side_length_ / 2.0) * (side_length_ / 2.0))); 44 | } 45 | 46 | } // namespace Polygons 47 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons_tester/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(polygons_tester) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 7 | add_compile_options(-Wall -Wextra -Wpedantic) 8 | endif() 9 | 10 | # find dependencies 11 | find_package(ament_cmake REQUIRED) 12 | find_package(pluginlib REQUIRED) 13 | find_package(polygon_base REQUIRED) 14 | 15 | add_executable(polygons_tester src/polygons_tester.cpp) 16 | target_include_directories(polygons_tester PUBLIC 17 | $ 18 | $) 19 | target_compile_features(polygons_tester PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 20 | ament_target_dependencies( 21 | polygons_tester 22 | pluginlib 23 | polygon_base) 24 | 25 | install(TARGETS polygons_tester 26 | DESTINATION lib/${PROJECT_NAME}) 27 | 28 | if(BUILD_TESTING) 29 | find_package(ament_lint_auto REQUIRED) 30 | # the following line skips the linter which checks for copyrights 31 | # uncomment the line when a copyright and license is not present in all source files 32 | #set(ament_cmake_copyright_FOUND TRUE) 33 | # the following line skips cpplint (only works in a git repo) 34 | # uncomment the line when this package is not in a git repo 35 | #set(ament_cmake_cpplint_FOUND TRUE) 36 | ament_lint_auto_find_test_dependencies() 37 | endif() 38 | 39 | ament_package() 40 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons_tester/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | polygons_tester 5 | 0.0.0 6 | Plugins tester package. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | pluginlib 13 | polygon_base 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cpp/plugins_demo/polygons_tester/src/polygons_tester.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Polygons plugins test program. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 29, 2022 7 | */ 8 | 9 | #include 10 | 11 | //! Include pluginlib headers and base class header 12 | #include 13 | #include 14 | 15 | #define UNUSED(arg) (void)(arg) 16 | 17 | int main(int argc, char ** argv) 18 | { 19 | UNUSED(argc); 20 | UNUSED(argv); 21 | 22 | //! pluginlib throws exceptions when something fails 23 | try 24 | { 25 | //! First, create a ClassLoader providing package name and fully qualified 26 | //! base name 27 | pluginlib::ClassLoader loader("polygon_base", "PolygonBase::Polygon"); 28 | 29 | //! Then, initialize different objects as shared pointers to base class 30 | //! (other initializers are also possible, see the API) 31 | //! Specify the derived fully qualified name 32 | std::shared_ptr triangle = loader.createSharedInstance("Polygons::Triangle"); 33 | std::shared_ptr square = loader.createSharedInstance("Polygons::Square"); 34 | //! These wrap dlopen & co. 35 | 36 | //! Now you can do whatever you want with the objects! 37 | triangle->init(10.0); 38 | square->init(10.0); 39 | std::cout << "Triangle area: " << triangle->area() << std::endl; 40 | std::cout << "Square area: " << square->area() << std::endl; 41 | } 42 | catch(const pluginlib::PluginlibException & e) 43 | { 44 | std::cerr << e.what() << std::endl; 45 | exit(EXIT_FAILURE); 46 | } 47 | //! Unfortunately exceptions may be thrown from the loader's creation going on, 48 | //! so this try-catch must wrap the code almost entirely 49 | //! If you don't do this and keep using objects outside then the loader will 50 | //! go out of scope outside the try block, and its destructor will attempt to 51 | //! unload the libraries, but it won't be able to since objects from them 52 | //! will still be around, so pluginlib will strongly complain 53 | 54 | exit(EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/include/pub_sub_components/pub.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Publisher component declaration. 3 | * 4 | * Roberto Masocco 5 | * 6 | * May 23, 2024 7 | */ 8 | 9 | #ifndef PUB_HPP 10 | #define PUB_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | #define PUB_PERIOD 300 // Publisher transmission time period [ms] 17 | 18 | //! There has to be a namespace when declaring a component class, 19 | //! in order to avoid plugin name clashes with other components. 20 | //! The name of the namespace should be the name of the package. 21 | namespace pub_sub_components 22 | { 23 | 24 | /** 25 | * Simple publisher node: transmits strings on a topic. 26 | */ 27 | class Publisher : public rclcpp::Node 28 | { 29 | public: 30 | //! To be compatible with component containers, the constructor must have only this argument! 31 | Publisher(const rclcpp::NodeOptions & node_opts); 32 | 33 | private: 34 | rclcpp::Publisher::SharedPtr publisher_; 35 | 36 | rclcpp::TimerBase::SharedPtr pub_timer_; 37 | void pub_timer_callback(void); 38 | 39 | unsigned long pub_cnt_; // Marks messages 40 | }; 41 | 42 | } // namespace pub_sub_components 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/include/pub_sub_components/sub.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Subscriber component declaration. 3 | * 4 | * Roberto Masocco 5 | * 6 | * May 23, 2024 7 | */ 8 | 9 | #ifndef SUB_HPP 10 | #define SUB_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | //! There has to be a namespace when declaring a component class, 17 | //! in order to avoid plugin name clashes with other components. 18 | //! The name of the namespace should be the name of the package. 19 | namespace pub_sub_components 20 | { 21 | 22 | /** 23 | * Simple subscriber node: receives and prints strings transmitted on a topic. 24 | */ 25 | class Subscriber : public rclcpp::Node 26 | { 27 | public: 28 | //! To be compatible with component containers, the constructor must have only this argument! 29 | Subscriber(const rclcpp::NodeOptions & node_opts); 30 | 31 | private: 32 | rclcpp::Subscription::SharedPtr subscriber_; 33 | void msg_callback(const std_msgs::msg::String::SharedPtr msg); 34 | }; 35 | 36 | } // namespace pub_sub_components 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/launch/pub_sub_components.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Component example launch file. 3 | 4 | Roberto Masocco 5 | 6 | May 23, 2024 7 | """ 8 | 9 | from launch import LaunchDescription 10 | from launch_ros.actions import ComposableNodeContainer 11 | from launch_ros.descriptions import ComposableNode 12 | 13 | 14 | def generate_launch_description(): 15 | """Builds an example of LaunchDescription for a component container.""" 16 | ld = LaunchDescription() 17 | 18 | #! Create a ComposableNodeContainer, then add ComposableNode instances to it. 19 | #! Do not forget the use_intra_process_comms argument! 20 | container = ComposableNodeContainer( 21 | name='pub_sub_container', 22 | namespace='pub_sub_components', 23 | package='rclcpp_components', 24 | executable='component_container', 25 | emulate_tty=True, 26 | output='both', 27 | log_cmd=True, 28 | composable_node_descriptions=[ 29 | ComposableNode( 30 | package='pub_sub_components', 31 | plugin='pub_sub_components::Publisher', 32 | name='publisher_node', 33 | namespace='pub_sub_components', 34 | parameters=[], 35 | extra_arguments=[{'use_intra_process_comms': True}]), 36 | ComposableNode( 37 | package='pub_sub_components', 38 | plugin='pub_sub_components::Subscriber', 39 | name='subscriber_node', 40 | namespace='pub_sub_components', 41 | parameters=[], 42 | extra_arguments=[{'use_intra_process_comms': True}]) 43 | ] 44 | ) 45 | ld.add_action(container) 46 | 47 | return ld 48 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pub_sub_components 5 | 0.0.0 6 | Composable nodes demonstration package. 7 | Roberto Masocco 8 | GPL-3.0-only 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | rclcpp_components 14 | std_msgs 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/src/pub.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Publisher component definition. 3 | * 4 | * Roberto Masocco 5 | * 6 | * May 23, 2024 7 | */ 8 | 9 | #include 10 | 11 | //! There has to be a namespace when declaring a component class, 12 | //! in order to avoid plugin name clashes with other components. 13 | //! The name of the namespace should be the name of the package. 14 | namespace pub_sub_components 15 | { 16 | 17 | /** 18 | * @brief Creates a Publisher node. 19 | */ 20 | Publisher::Publisher(const rclcpp::NodeOptions & node_opts) 21 | : Node("publisher_node", node_opts), 22 | pub_cnt_(0) 23 | { 24 | publisher_ = this->create_publisher( 25 | "/examples/test_topic", 26 | rclcpp::QoS(10)); 27 | 28 | pub_timer_ = this->create_wall_timer( 29 | std::chrono::milliseconds(PUB_PERIOD), 30 | std::bind( 31 | &Publisher::pub_timer_callback, 32 | this)); 33 | 34 | RCLCPP_INFO(this->get_logger(), "Publisher initialized"); 35 | } 36 | 37 | /** 38 | * @brief Publishes a message on timer occurrence. 39 | */ 40 | void Publisher::pub_timer_callback(void) 41 | { 42 | // Build the new message 43 | std::string new_data = "Hello "; 44 | new_data.append(std::to_string(pub_cnt_) + "."); 45 | 46 | std_msgs::msg::String new_msg{}; 47 | 48 | new_msg.set__data(new_data); 49 | 50 | publisher_->publish(new_msg); 51 | 52 | // Log something 53 | pub_cnt_++; 54 | RCLCPP_INFO(this->get_logger(), "Published message %lu", pub_cnt_); 55 | } 56 | 57 | } // namespace pub_sub_components 58 | 59 | //! Must do this at the end of one source file where your class definition is to generate the plugin. 60 | #include 61 | RCLCPP_COMPONENTS_REGISTER_NODE(pub_sub_components::Publisher) 62 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/src/pub_main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Publisher application. 3 | * 4 | * Roberto Masocco 5 | * 6 | * May 23, 2024 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | int main(int argc, char ** argv) 14 | { 15 | rclcpp::init(argc, argv); 16 | //! For the options, we pass a default-constructed rvalue. 17 | auto sub_node = std::make_shared(rclcpp::NodeOptions()); 18 | rclcpp::spin(sub_node); 19 | rclcpp::shutdown(); 20 | exit(EXIT_SUCCESS); 21 | } 22 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/src/sub.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Subscriber component definition. 3 | * 4 | * Roberto Masocco 5 | * 6 | * May 23, 2024 7 | */ 8 | 9 | #include 10 | 11 | //! There has to be a namespace when declaring a component class, 12 | //! in order to avoid plugin name clashes with other components. 13 | //! The name of the namespace should be the name of the package. 14 | namespace pub_sub_components 15 | { 16 | 17 | /** 18 | * @brief Creates a Subscriber node. 19 | */ 20 | Subscriber::Subscriber(const rclcpp::NodeOptions & node_opts) 21 | : Node("subscriber_node", node_opts) 22 | { 23 | subscriber_ = this->create_subscription( 24 | "/examples/test_topic", 25 | rclcpp::QoS(10), 26 | std::bind( 27 | &Subscriber::msg_callback, 28 | this, 29 | std::placeholders::_1)); 30 | 31 | RCLCPP_INFO(this->get_logger(), "Subscriber initialized"); 32 | } 33 | 34 | /** 35 | * @brief Echoes a new message. 36 | * 37 | * @param msg New message. 38 | */ 39 | void Subscriber::msg_callback(const std_msgs::msg::String::SharedPtr msg) 40 | { 41 | RCLCPP_INFO(this->get_logger(), msg->data.c_str()); 42 | } 43 | 44 | } // namespace pub_sub_components 45 | 46 | //! Must do this at the end of one source file where your class definition is to generate the plugin. 47 | #include 48 | RCLCPP_COMPONENTS_REGISTER_NODE(pub_sub_components::Subscriber) 49 | -------------------------------------------------------------------------------- /src/cpp/pub_sub_components/src/sub_main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Subscriber application. 3 | * 4 | * Roberto Masocco 5 | * 6 | * May 23, 2024 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | int main(int argc, char ** argv) 14 | { 15 | rclcpp::init(argc, argv); 16 | //! For the options, we pass a default-constructed rvalue. 17 | auto sub_node = std::make_shared(rclcpp::NodeOptions()); 18 | rclcpp::spin(sub_node); 19 | rclcpp::shutdown(); 20 | exit(EXIT_SUCCESS); 21 | } 22 | -------------------------------------------------------------------------------- /src/cpp/simple_service_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(simple_service_cpp) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | # Default to C99 7 | if(NOT CMAKE_C_STANDARD) 8 | set(CMAKE_C_STANDARD 99) 9 | endif() 10 | 11 | # Default to C++17 12 | if(NOT CMAKE_CXX_STANDARD) 13 | set(CMAKE_CXX_STANDARD 17) 14 | endif() 15 | 16 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 17 | add_compile_options(-Wall -Wextra -Wpedantic) 18 | endif() 19 | 20 | # Find dependencies 21 | find_package(ament_cmake REQUIRED) 22 | find_package(rclcpp REQUIRED) 23 | find_package(ros2_examples_interfaces REQUIRED) 24 | 25 | # Server 26 | add_executable(server src/server.cpp) 27 | target_include_directories(server PUBLIC 28 | $ 29 | $) 30 | ament_target_dependencies( 31 | server 32 | rclcpp 33 | ros2_examples_interfaces) 34 | 35 | # Client 36 | add_executable(client src/client.cpp) 37 | target_include_directories(client PUBLIC 38 | $ 39 | $) 40 | ament_target_dependencies( 41 | client 42 | rclcpp 43 | ros2_examples_interfaces) 44 | 45 | # Install executables 46 | install(TARGETS server 47 | DESTINATION lib/${PROJECT_NAME}) 48 | install(TARGETS client 49 | DESTINATION lib/${PROJECT_NAME}) 50 | 51 | if(BUILD_TESTING) 52 | find_package(ament_lint_auto REQUIRED) 53 | # the following line skips the linter which checks for copyrights 54 | # uncomment the line when a copyright and license is not present in all source files 55 | #set(ament_cmake_copyright_FOUND TRUE) 56 | # the following line skips cpplint (only works in a git repo) 57 | # uncomment the line when this package is not in a git repo 58 | #set(ament_cmake_cpplint_FOUND TRUE) 59 | ament_lint_auto_find_test_dependencies() 60 | endif() 61 | 62 | ament_package() 63 | -------------------------------------------------------------------------------- /src/cpp/simple_service_cpp/include/simple_service_cpp/simple_service.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * AddTwoInts server and client nodes. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #ifndef SIMPLE_SERVICE_HPP 10 | #define SIMPLE_SERVICE_HPP 11 | 12 | #include 13 | 14 | #include 15 | //! ALWAYS INCLUDE THE INTERFACE .hpp HEADER! 16 | 17 | //! Let's make things a little bit simpler here 18 | using namespace ros2_examples_interfaces::srv; 19 | 20 | /** 21 | * AddTwoInts server node. 22 | */ 23 | class AddTwoIntsServer : public rclcpp::Node 24 | { 25 | public: 26 | AddTwoIntsServer(); 27 | 28 | private: 29 | //! This object is a modified DDS endpoint that receives requests and, 30 | //! in addition, implements the ROS 2 server semantics to send responses 31 | //! The job to execute upon arrival must be coded in a related callback 32 | //! The syntax is: 33 | //! rclcpp::Service::SharedPtr OBJ; 34 | rclcpp::Service::SharedPtr server_; 35 | 36 | //! Service callback signature must be: 37 | //! void FUNC_NAME(const INTERFACE_TYPE::Request::SharedPtr ARG1, 38 | //! const INTERFACE_TYPE::Response::SharedPtr ARG2); 39 | void add_two_ints_clbk( 40 | const AddTwoInts::Request::SharedPtr request, 41 | const AddTwoInts::Response::SharedPtr response); 42 | }; 43 | 44 | /** 45 | * AddTwoInts client node. 46 | */ 47 | class AddTwoIntsClient : public rclcpp::Node 48 | { 49 | public: 50 | AddTwoIntsClient(); 51 | 52 | //! This is just for us, not ROS-related, i.e. we could do without it (see below) 53 | void call_srv(int a, int b); 54 | 55 | private: 56 | //! This object is a modified DDS endpoint that sends requests and, 57 | //! in addition, implements the ROS 2 client semantics to receive responses 58 | //! The syntax is: 59 | //! rclcpp::Client::SharedPtr OBJ; 60 | rclcpp::Client::SharedPtr client_; 61 | }; 62 | //! We could do without this: if our only intent is to call a ROS 2 service from an application, 63 | //! we could just create a node, a service client, and call the service synchronously from 64 | //! our 'main' function or wherever else we want 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/cpp/simple_service_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | simple_service_cpp 5 | 0.0.0 6 | Example service server and client. 7 | Roberto Masocco 8 | TODO: License declaration 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | ros2_examples_interfaces 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cpp/simple_service_cpp/src/server.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * AddTwoInts service server node. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | /** 14 | * @brief AddTwoInts server constructor. 15 | */ 16 | AddTwoIntsServer::AddTwoIntsServer() 17 | : Node("server") 18 | { 19 | //! Create a server object with create_service from the base class: 20 | //! this->create_service( 21 | //! SERVICE_NAME [string], 22 | //! CALLBACK_WRAPPER, 23 | //! ... 24 | //! ); 25 | //! Note: we could have a '~' here, too, we just omit it for the sake of this example 26 | server_ = this->create_service( 27 | "/examples/add_two_ints", 28 | //! Why do we need two placeholders this time? ... 29 | std::bind( 30 | &AddTwoIntsServer::add_two_ints_clbk, 31 | this, 32 | std::placeholders::_1, 33 | std::placeholders::_2)); 34 | 35 | RCLCPP_INFO(this->get_logger(), "Server initialized"); 36 | } 37 | 38 | /** 39 | * @brief Adds two given integers and returns the sum. 40 | * 41 | * @param request Message with the two integers to add. 42 | * @param response Response message to populate. 43 | */ 44 | void AddTwoIntsServer::add_two_ints_clbk( 45 | const AddTwoInts::Request::SharedPtr request, 46 | const AddTwoInts::Response::SharedPtr response) 47 | { 48 | //! Note that this has void return type: all that has to be done is to populate 49 | //! the appropriate fields in the response message 50 | response->set__sum(request->a + request->b); 51 | 52 | RCLCPP_INFO( 53 | this->get_logger(), "%ld + %ld = %ld", 54 | request->a, 55 | request->b, 56 | response->sum); 57 | } 58 | 59 | int main(int argc, char ** argv) 60 | { 61 | rclcpp::init(argc, argv); 62 | auto server_node = std::make_shared(); 63 | rclcpp::spin(server_node); 64 | rclcpp::shutdown(); 65 | exit(EXIT_SUCCESS); 66 | } 67 | -------------------------------------------------------------------------------- /src/cpp/topic_pubsub_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(topic_pubsub_cpp) 3 | 4 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 5 | 6 | # Default to C99 7 | if(NOT CMAKE_C_STANDARD) 8 | set(CMAKE_C_STANDARD 99) 9 | endif() 10 | 11 | # Default to C++17 12 | if(NOT CMAKE_CXX_STANDARD) 13 | set(CMAKE_CXX_STANDARD 17) 14 | endif() 15 | 16 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 17 | add_compile_options(-Wall -Wextra -Wpedantic) 18 | endif() 19 | 20 | # Find dependencies 21 | find_package(ament_cmake REQUIRED) 22 | find_package(rclcpp REQUIRED) 23 | find_package(std_msgs REQUIRED) 24 | 25 | # Publisher 26 | add_executable(pub src/pub.cpp) 27 | target_compile_features(pub PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 28 | target_include_directories(pub PUBLIC 29 | $ 30 | $) 31 | ament_target_dependencies( 32 | pub 33 | rclcpp 34 | std_msgs) 35 | 36 | # Subscriber 37 | add_executable(sub src/sub.cpp) 38 | target_compile_features(sub PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 39 | target_include_directories(sub PUBLIC 40 | $ 41 | $) 42 | ament_target_dependencies( 43 | sub 44 | rclcpp 45 | std_msgs) 46 | 47 | # Resetting subscriber 48 | add_executable(resetting_sub src/resetting_sub.cpp) 49 | target_compile_features(resetting_sub PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 50 | target_include_directories(resetting_sub PUBLIC 51 | $ 52 | $) 53 | ament_target_dependencies( 54 | resetting_sub 55 | rclcpp 56 | std_msgs) 57 | 58 | # Install executables 59 | install(TARGETS pub 60 | DESTINATION lib/${PROJECT_NAME}) 61 | install(TARGETS sub 62 | DESTINATION lib/${PROJECT_NAME}) 63 | install(TARGETS resetting_sub 64 | DESTINATION lib/${PROJECT_NAME}) 65 | 66 | if(BUILD_TESTING) 67 | find_package(ament_lint_auto REQUIRED) 68 | # the following line skips the linter which checks for copyrights 69 | # uncomment the line when a copyright and license is not present in all source files 70 | #set(ament_cmake_copyright_FOUND TRUE) 71 | # the following line skips cpplint (only works in a git repo) 72 | # uncomment the line when this package is not in a git repo 73 | #set(ament_cmake_cpplint_FOUND TRUE) 74 | ament_lint_auto_find_test_dependencies() 75 | endif() 76 | 77 | ament_package() 78 | -------------------------------------------------------------------------------- /src/cpp/topic_pubsub_cpp/include/topic_pubsub/pub.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Publisher definition. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #ifndef PUB_HPP 10 | #define PUB_HPP 11 | 12 | #include //! rclcpp base library 13 | 14 | #include //! Interface library that we'll use 15 | 16 | //! We'll see how to properly manage this kind of "parameters" 17 | #define PUB_PERIOD 300 // Publisher transmission time period [ms] 18 | 19 | /** 20 | * Simple publisher node: transmits strings on a topic. 21 | */ 22 | //! Every node must extend publicly the Node base class 23 | class Pub : public rclcpp::Node 24 | { 25 | public: 26 | //! There must always be a constructor, with arbitrary input arguments 27 | Pub(); 28 | 29 | //! ROS-specific members better be private 30 | private: 31 | //! DDS endpoint, acting as a publisher 32 | //! Syntax is: rclcpp::Publisher::SharedPtr OBJ; 33 | rclcpp::Publisher::SharedPtr publisher_; 34 | 35 | //! ROS-2 managed timer: enables one to set up a periodic job 36 | //! The job is coded in a callback, which better be a private method 37 | //! Syntax is: rclcpp::TimerBase::SharedPtr OBJ; 38 | //! Callback signature must be: void FUNC_NAME(void); 39 | rclcpp::TimerBase::SharedPtr pub_timer_; 40 | void pub_timer_callback(void); 41 | 42 | unsigned long pub_cnt_; // Marks messages 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/cpp/topic_pubsub_cpp/include/topic_pubsub/sub.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Subscriber definition. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #ifndef SUB_HPP 10 | #define SUB_HPP 11 | 12 | #include //! rclcpp base library 13 | 14 | #include //! Interface library that we'll use 15 | 16 | /** 17 | * Simple subscriber node: receives and prints strings transmitted on a topic. 18 | */ 19 | //! Every node must extend publicly the Node base class 20 | class Sub : public rclcpp::Node 21 | { 22 | public: 23 | //! There must always be a constructor, with arbitrary input arguments 24 | Sub(); 25 | 26 | //! ROS-specific members better be private 27 | private: 28 | //! DDS endpoint, acting as a subscriber 29 | //! When a message is received, a callback job is issued, which better be a private method 30 | //! Syntax is: rclcpp::Subscription::SharedPtr OBJ; 31 | //! Callback signature must be: 32 | //! void FUNC_NAME(const INTERFACE_TYPE::SharedPtr ARG_NAME); 33 | rclcpp::Subscription::SharedPtr subscriber_; 34 | void msg_callback(const std_msgs::msg::String::SharedPtr msg); 35 | 36 | //! Nothing else is necessary to receive messages 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/cpp/topic_pubsub_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | topic_pubsub_cpp 5 | 0.0.0 6 | Topic publish/subscribe test. 7 | Roberto Masocco 8 | GPL-3.0-only 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | std_msgs 14 | 15 | ament_lint_auto 16 | ament_lint_common 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cpp/topic_pubsub_cpp/src/resetting_sub.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Dynamic subscriber example. 3 | * 4 | * Roberto Masocco 5 | * 6 | * January 15, 2022 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | using namespace std_msgs::msg; 15 | using namespace std::chrono_literals; 16 | 17 | /** 18 | * Subscriber node that dynamically resubscribes to a given topic. 19 | * Run this alongside this package's publisher. 20 | */ 21 | //! For the sake of simplicity we'll write everything in here this time 22 | class ResettingSub : public rclcpp::Node 23 | { 24 | public: 25 | ResettingSub() 26 | : Node("resetting_subscriber") 27 | { 28 | //! We just have to initialize the timer 29 | sub_timer_ = this->create_wall_timer( 30 | 5s, 31 | [this]() -> void { 32 | //! This just has to toggle topic subscription 33 | if (sub_) { //! Operator checks if it is nullptr 34 | RCLCPP_WARN(this->get_logger(), "De-subscribing from topic"); 35 | //! Resetting the shared_ptr will make the Subscription fall out of 36 | //! scope, thus being destroyed 37 | //! ref.: https://answers.ros.org/question/354792/rclcpp-how-to-unsubscribe-from-a-topic/ 38 | sub_.reset(); 39 | } else { 40 | RCLCPP_WARN(this->get_logger(), "Re-subscribing to topic"); 41 | //! We just create a new Subscription 42 | sub_ = this->create_subscription( 43 | "/examples/test_topic", 44 | rclcpp::QoS(10), 45 | [this](String::SharedPtr msg) -> void { 46 | RCLCPP_INFO(this->get_logger(), msg->data.c_str()); 47 | }); 48 | //! And that's it. The same could be done with a Publisher, 49 | //! but being it asynchronous by default it's usually less important 50 | } 51 | }); 52 | 53 | RCLCPP_INFO(this->get_logger(), "Node initialized"); 54 | } 55 | 56 | private: 57 | //! Note that this, apart from the type wrapping, is a classic shared_ptr 58 | rclcpp::Subscription::SharedPtr sub_; 59 | 60 | rclcpp::TimerBase::SharedPtr sub_timer_; 61 | }; 62 | 63 | int main(int argc, char ** argv) { 64 | rclcpp::init(argc, argv); 65 | auto sub_node = std::make_shared(); 66 | rclcpp::spin(sub_node); 67 | rclcpp::shutdown(); 68 | exit(EXIT_SUCCESS); 69 | } 70 | -------------------------------------------------------------------------------- /src/cpp/topic_pubsub_cpp/src/sub.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Subscriber definition and implementation. 3 | * 4 | * Roberto Masocco 5 | * 6 | * November 22, 2021 7 | */ 8 | 9 | #include 10 | 11 | #include "../include/topic_pubsub/sub.hpp" 12 | 13 | /** 14 | * @brief Creates a Sub node. 15 | */ 16 | //! Call the base class constructor providing a string embedding the node name 17 | //! Initialize other members at will 18 | Sub::Sub() 19 | : Node("subscriber_node") 20 | { 21 | //! Initialize a subscriber with create_subscription from the base class: 22 | //! this->create_subscription( 23 | //! TOPIC_NAME [string], 24 | //! SUBSCRIPTION_QoS (...), 25 | //! CALLBACK_WRAPPER (with captures and argument placeholders) 26 | //! (...) 27 | //! ); 28 | subscriber_ = this->create_subscription( 29 | "/examples/test_topic", 30 | rclcpp::QoS(10), 31 | std::bind( 32 | &Sub::msg_callback, 33 | this, 34 | std::placeholders::_1)); 35 | 36 | //! Logging macro used to deliver a message to the logging subsystem, INFO level 37 | RCLCPP_INFO(this->get_logger(), "Subscriber initialized"); 38 | } 39 | 40 | /** 41 | * @brief Echoes a new message. 42 | * 43 | * @param msg New message. 44 | */ 45 | void Sub::msg_callback(const std_msgs::msg::String::SharedPtr msg) 46 | { 47 | //! Get the data simply by accessing the object member as the interface specifies 48 | RCLCPP_INFO(this->get_logger(), msg->data.c_str()); 49 | } 50 | 51 | int main(int argc, char ** argv) 52 | { 53 | //! This automatically creates the global context->DDS participant for this application 54 | //! and parses all ROS-specific input arguments eventually passed to the new process 55 | //! (and installs signal handlers) 56 | rclcpp::init(argc, argv); 57 | 58 | //! Since it's all made of shared pointers, initialize the new node as such 59 | //! (note: here we're calling an actual constructor but obtaining a smart pointer 60 | //! to the new object) 61 | auto sub_node = std::make_shared(); 62 | 63 | //! This automatically creates a default, single-threaded executor, adds to it 64 | //! the jobs defined by the new node, and makes the current thread tend to that 65 | rclcpp::spin(sub_node); 66 | 67 | //! Whatever happens now, does so only after rclcpp::spin has returned 68 | 69 | //! Shut down the global context, the DDS participant and all its 70 | //! endpoints, effectively terminating the connection to the DDS layer 71 | //! (note: this doesn't necessarily destroy the corresponding objects) 72 | rclcpp::shutdown(); 73 | 74 | // Just exit 75 | std::cout << "Subscriber terminated" << std::endl; 76 | exit(EXIT_SUCCESS); 77 | } 78 | -------------------------------------------------------------------------------- /src/python/advanced/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/src/python/advanced/.gitkeep -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | topic_pubsub_py 5 | 0.0.0 6 | Topic publisher/subscriber example. 7 | Roberto Masocco 8 | GPL-3.0-only 9 | 10 | rclpy 11 | ros2_examples_interfaces 12 | 13 | ament_copyright 14 | ament_flake8 15 | ament_pep257 16 | python3-pytest 17 | 18 | 19 | ament_python 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/resource/topic_pubsub_py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/src/python/topic_pubsub_py/resource/topic_pubsub_py -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/topic_pubsub_py 3 | [install] 4 | install_scripts=$base/lib/topic_pubsub_py 5 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | package_name = 'topic_pubsub_py' 4 | 5 | setup( 6 | name=package_name, 7 | version='0.0.0', 8 | packages=[package_name], 9 | data_files=[ 10 | ('share/ament_index/resource_index/packages', 11 | ['resource/' + package_name]), 12 | ('share/' + package_name, ['package.xml']), 13 | ], 14 | install_requires=['setuptools'], 15 | zip_safe=True, 16 | maintainer='Roberto Masocco', 17 | maintainer_email='robmasocco@gmail.com', 18 | description='Topic publisher/subscriber example.', 19 | license='GPL-3.0-only', 20 | tests_require=['pytest'], 21 | entry_points={ 22 | 'console_scripts': [ 23 | 'sub = topic_pubsub_py.sub:main', 24 | 'pub = topic_pubsub_py.pub:main' 25 | ], 26 | }, 27 | ) 28 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/topic_pubsub_py/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Python cache 2 | __pycache__/ 3 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/topic_pubsub_py/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/src/python/topic_pubsub_py/topic_pubsub_py/__init__.py -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/topic_pubsub_py/pub.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of a Python module with a ROS 2 topic publisher. 3 | 4 | Roberto Masocco 5 | Intelligent Systems Lab 6 | 7 | May 22, 2023 8 | """ 9 | 10 | #! Import Python client library for ROS 2 11 | import rclpy 12 | from rclpy.node import Node 13 | 14 | #! QoS profile class 15 | import rclpy.qos 16 | 17 | #! Our interface definition, which is a class in Python 18 | from ros2_examples_interfaces.msg import String 19 | 20 | #! To define a node, we need to inherit from the Node class 21 | 22 | 23 | class Pub(Node): 24 | """Example ROS 2 node with a subscriber to a custom topic.""" 25 | 26 | def __init__(self) -> None: 27 | """ 28 | Creates a new Sub node. 29 | """ 30 | #! We need to call the base Node constructor 31 | super().__init__('publisher_node') 32 | 33 | #! Create a custom, best-effort QoS profile 34 | qos_profile = rclpy.qos.QoSProfile( 35 | depth=1, 36 | history=rclpy.qos.HistoryPolicy.KEEP_LAST, 37 | reliability=rclpy.qos.ReliabilityPolicy.BEST_EFFORT, 38 | durability=rclpy.qos.DurabilityPolicy.VOLATILE) 39 | 40 | #! Create a publisher to the custom topic 41 | #! Note that this is Python: we are defining the publiser attribute as we 42 | #! create it 43 | self._pub = self.create_publisher( 44 | String, 45 | '~/examples/test_topic', 46 | qos_profile) 47 | 48 | #! Create a timer to publish a message every second 49 | self._timer = self.create_timer( 50 | 0.5, 51 | self.timer_callback) 52 | 53 | # This will be used to fill messages 54 | self._cnt = 0 55 | 56 | self.get_logger().info('Node initialized') 57 | 58 | #! Callback functions are methods here too, and are passed message objects 59 | def timer_callback(self) -> None: 60 | """ 61 | Timer callback function. 62 | """ 63 | #! Create a message object, fill it, and publish it 64 | msg = String() 65 | msg.data = 'Hello %d' % self._cnt 66 | self._pub.publish(msg) 67 | self._cnt += 1 68 | 69 | self.get_logger().info('Published message: %s' % msg.data) 70 | 71 | 72 | def main(args=None): 73 | #! Initialize the ROS 2 client library and context 74 | rclpy.init(args=args) 75 | 76 | #! Initialize ROS 2 node 77 | node = Pub() 78 | 79 | #! Spin the node in a basic executor 80 | try: 81 | rclpy.spin(node) 82 | except: 83 | pass 84 | #! If you press Ctrl-C, the handler will call rclpy.shutdown() for us 85 | node.destroy_node() 86 | # rclpy.shutdown() 87 | 88 | print('Publisher terminated') 89 | 90 | 91 | #! This is required in Python to execute a script 92 | if __name__ == '__main__': 93 | main() 94 | -------------------------------------------------------------------------------- /src/python/topic_pubsub_py/topic_pubsub_py/sub.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of a Python module with a ROS 2 topic subscriber. 3 | 4 | Roberto Masocco 5 | Intelligent Systems Lab 6 | 7 | May 22, 2023 8 | """ 9 | 10 | import sys 11 | 12 | #! Import Python client library for ROS 2 13 | import rclpy 14 | from rclpy.node import Node 15 | 16 | #! QoS profile classes and enums 17 | import rclpy.qos 18 | 19 | #! Our interface definition, which is a class in Python 20 | from ros2_examples_interfaces.msg import String 21 | 22 | #! To define a node, we need to inherit from the Node class 23 | 24 | 25 | class Sub(rclpy.node.Node): 26 | """Example ROS 2 node with a subscriber to a custom topic.""" 27 | 28 | def __init__(self) -> None: 29 | """ 30 | Creates a new Sub node. 31 | """ 32 | #! We need to call the base Node constructor 33 | super().__init__('subscriber_node') 34 | 35 | #! Create a custom, best-effort QoS profile 36 | qos_profile = rclpy.qos.QoSProfile( 37 | depth=1, 38 | history=rclpy.qos.HistoryPolicy.KEEP_LAST, 39 | reliability=rclpy.qos.ReliabilityPolicy.BEST_EFFORT, 40 | durability=rclpy.qos.DurabilityPolicy.VOLATILE) 41 | 42 | #! Create a subscriber to the custom topic 43 | #! Note that this is Python: we are defining the subscriber attribute as we 44 | #! create it 45 | self._sub = self.create_subscription( 46 | String, 47 | '/publisher_node/examples/test_topic', 48 | self.sub_callback, 49 | qos_profile) 50 | 51 | self.get_logger().info('Node initialized') 52 | 53 | #! Callback functions are methods here too, and are passed message objects 54 | def sub_callback(self, msg: String) -> None: 55 | """ 56 | Subscriber callback function. 57 | 58 | :param msg: String message to parse. 59 | """ 60 | self.get_logger().info('Received message: %s' % msg.data) 61 | 62 | 63 | def main(): 64 | #! Initialize the ROS 2 client library and context 65 | rclpy.init(args=sys.argv) 66 | 67 | #! Initialize ROS 2 node 68 | node = Sub() 69 | 70 | #! Spin the node in a basic executor 71 | try: 72 | rclpy.spin(node) 73 | except: 74 | pass 75 | #! If you press Ctrl-C, the handler will call rclpy.shutdown() for us 76 | node.destroy_node() 77 | # rclpy.shutdown() 78 | 79 | print('Subscriber terminated') 80 | 81 | 82 | #! This is required in Python to execute a script 83 | if __name__ == '__main__': 84 | main() 85 | -------------------------------------------------------------------------------- /src/ros2_examples_bringup/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(ros2_examples_bringup) 3 | 4 | # Find dependencies 5 | find_package(ament_cmake REQUIRED) 6 | 7 | # Install launch files 8 | install(DIRECTORY launch 9 | DESTINATION share/${PROJECT_NAME}) 10 | 11 | ament_package() 12 | -------------------------------------------------------------------------------- /src/ros2_examples_bringup/launch/image_processing_pipeline.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Image processing pipeline example launch file. 3 | 4 | Roberto Masocco 5 | Intelligent Systems Lab 6 | 7 | June 5, 2023 8 | """ 9 | 10 | import os 11 | from ament_index_python.packages import get_package_share_directory 12 | 13 | from launch import LaunchDescription 14 | from launch_ros.actions import ComposableNodeContainer 15 | from launch_ros.descriptions import ComposableNode 16 | 17 | 18 | def generate_launch_description(): 19 | """Builds a LaunchDescription for the image processing pipeline example.""" 20 | ld = LaunchDescription() 21 | 22 | # Build config files path 23 | #! In the following, it's either YAML files OR parameter dictionaries 24 | #! That's a weird API inconsistency... 25 | camera_driver_config_file = os.path.join( 26 | get_package_share_directory('ros2_usb_camera'), 27 | 'config', 28 | 'config.yaml' 29 | ) 30 | camera_config_file = 'file://' + os.path.join( 31 | get_package_share_directory('ros2_usb_camera'), 32 | 'config', 33 | 'camera.yaml' 34 | ) 35 | detector_config_file = os.path.join( 36 | get_package_share_directory('aruco_detector'), 37 | 'config', 38 | 'bottom_detector.yaml' 39 | ) 40 | 41 | container = ComposableNodeContainer( 42 | name='image_processing_pipeline_container', 43 | namespace='image_processing_pipeline', 44 | package='rclcpp_components', 45 | executable='component_container_mt', 46 | emulate_tty=True, 47 | output='both', 48 | log_cmd=True, 49 | composable_node_descriptions=[ 50 | ComposableNode( 51 | package='ros2_usb_camera', 52 | plugin='USBCameraDriver::CameraDriverNode', 53 | name='usb_camera_driver', 54 | namespace='image_processing_pipeline', 55 | parameters=[ 56 | { 57 | 'camera_calibration_file': camera_config_file, 58 | 'fps': 20 59 | } 60 | ], 61 | extra_arguments=[{'use_intra_process_comms': True}]), 62 | ComposableNode( 63 | package='aruco_detector', 64 | plugin='ArucoDetector::ArucoDetectorNode', 65 | name='aruco_detector', 66 | namespace='image_processing_pipeline', 67 | parameters=[ 68 | { 69 | 'camera_topic': '/image_processing_pipeline/usb_camera_driver/camera/image_color', 70 | 'target_ids': [15, 69, 666] 71 | } 72 | ], 73 | extra_arguments=[{'use_intra_process_comms': True}]) 74 | ] 75 | ) 76 | 77 | ld.add_action(container) 78 | return ld 79 | -------------------------------------------------------------------------------- /src/ros2_examples_bringup/launch/service_params.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example launch file for server and parametric nodes. 3 | 4 | Roberto Masocco 5 | 6 | January 7, 2022 7 | """ 8 | 9 | from launch import LaunchDescription 10 | from launch_ros.actions import Node 11 | from launch.actions import DeclareLaunchArgument 12 | from launch.substitutions import LaunchConfiguration 13 | 14 | # For parametric node (see its launch file for details) 15 | import os 16 | from ament_index_python.packages import get_package_share_directory 17 | 18 | def generate_launch_description(): 19 | """Generates a launch description for server and parametric nodes.""" 20 | ld = LaunchDescription() 21 | 22 | # Set arguments for service clients 23 | client_a = DeclareLaunchArgument( 24 | 'client_a', 25 | description='a value for service client', 26 | default_value='0') 27 | ld.add_action(client_a) 28 | client_b = DeclareLaunchArgument( 29 | 'client_b', 30 | description='b value for service client', 31 | default_value='0') 32 | ld.add_action(client_b) 33 | 34 | # Configure service server node 35 | server = Node( 36 | package='simple_service_cpp', 37 | executable='server', 38 | name='server', 39 | shell=True, 40 | emulate_tty=True, 41 | output='both', 42 | log_cmd=True) 43 | ld.add_action(server) 44 | 45 | # Configure service client node 46 | client = Node( 47 | package='simple_service_cpp', 48 | executable='client', 49 | name='client', 50 | shell=True, 51 | emulate_tty=True, 52 | output='both', 53 | log_cmd=True, 54 | arguments=[ 55 | LaunchConfiguration('client_a'), 56 | LaunchConfiguration('client_b')]) 57 | ld.add_action(client) 58 | 59 | return ld 60 | -------------------------------------------------------------------------------- /src/ros2_examples_bringup/launch/topic_params.launch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example launch file for publisher, subscriber and parametric nodes. 3 | 4 | Roberto Masocco 5 | 6 | January 7, 2022 7 | """ 8 | 9 | from launch import LaunchDescription 10 | from launch_ros.actions import Node 11 | from launch.actions import IncludeLaunchDescription 12 | from launch.actions import LogInfo 13 | from launch.launch_description_sources import PythonLaunchDescriptionSource 14 | 15 | # For parametric node (see its launch file for details) 16 | import os 17 | from ament_index_python.packages import get_package_share_directory 18 | 19 | def generate_launch_description(): 20 | """Generates a launch description for server and parametric nodes.""" 21 | ld = LaunchDescription() 22 | 23 | # Configure topic publisher node 24 | pub = Node( 25 | package='custom_topic_cpp', 26 | executable='pub', 27 | name='pub', 28 | shell=True, 29 | emulate_tty=True, 30 | output='both', 31 | log_cmd=True, 32 | remappings=[ 33 | ('/pub/examples/test_topic', '/publisher_node/examples/test_topic')]) 34 | ld.add_action(pub) 35 | 36 | # Configure topic subscriber node 37 | sub = Node( 38 | package='topic_pubsub_py', 39 | executable='sub', 40 | name='sub', 41 | shell=True, 42 | emulate_tty=True, 43 | output='both', 44 | log_cmd=True) 45 | ld.add_action(sub) 46 | 47 | # Include Parametric Publisher launch file 48 | #! Pay attention to the syntax and path conventions 49 | parametric_pub_launch_dir = os.path.join( 50 | get_package_share_directory('parameters_example_cpp'), 51 | 'launch') 52 | ld.add_action(LogInfo(msg=[ 53 | 'Including launch file: ', parametric_pub_launch_dir, '/launch_param_example.launch.py'])) 54 | ld.add_action(IncludeLaunchDescription( 55 | PythonLaunchDescriptionSource([parametric_pub_launch_dir, '/launch_param_example.launch.py']))) 56 | 57 | return ld 58 | -------------------------------------------------------------------------------- /src/ros2_examples_bringup/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ros2_examples_bringup 5 | 0.0.0 6 | Example bringup package. 7 | Roberto Masocco 8 | TODO: License declaration 9 | 10 | ament_cmake 11 | 12 | custom_topic_cpp 13 | simple_service_cpp 14 | parameters_example_cpp 15 | topic_pubsub_py 16 | 17 | ament_lint_auto 18 | ament_lint_common 19 | 20 | 21 | ament_cmake 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/ros2_examples_interfaces/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(ros2_examples_interfaces) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # Find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(rclcpp REQUIRED) 11 | find_package(rosidl_default_generators REQUIRED) 12 | 13 | #Glob together all the message files 14 | set(MSG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/msg") 15 | file(GLOB MSG_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${MSG_DIR}/*.msg") 16 | 17 | # Glob together all the service files 18 | set(SRV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/srv") 19 | file(GLOB SRV_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${SRV_DIR}/*.srv") 20 | 21 | # Glob together all the action files 22 | set(ACT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/action") 23 | file(GLOB ACT_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${ACT_DIR}/*.action") 24 | 25 | rosidl_generate_interfaces(${PROJECT_NAME} 26 | ${MSG_FILES} 27 | ${SRV_FILES} 28 | ${ACT_FILES}) 29 | 30 | if(BUILD_TESTING) 31 | find_package(ament_lint_auto REQUIRED) 32 | # the following line skips the linter which checks for copyrights 33 | # uncomment the line when a copyright and license is not present in all source files 34 | #set(ament_cmake_copyright_FOUND TRUE) 35 | # the following line skips cpplint (only works in a git repo) 36 | # uncomment the line when this package is not in a git repo 37 | #set(ament_cmake_cpplint_FOUND TRUE) 38 | ament_lint_auto_find_test_dependencies() 39 | endif() 40 | 41 | ament_package() 42 | -------------------------------------------------------------------------------- /src/ros2_examples_interfaces/action/Fibonacci.action: -------------------------------------------------------------------------------- 1 | # Example ROS 2 action to compute the Fibonacci sequence. 2 | # Roberto Masocco 3 | # January 10, 2022 4 | 5 | # ref.: https://docs.ros.org/en/foxy/Tutorials/Actions/Creating-an-Action.html 6 | 7 | # GOAL 8 | int32 order # Compute the sequence up to this 9 | --- 10 | # RESULT 11 | int32[] sequence # Computed sequence 12 | --- 13 | # FEEDBACK 14 | int32[] partial_sequence # Computation status 15 | -------------------------------------------------------------------------------- /src/ros2_examples_interfaces/msg/String.msg: -------------------------------------------------------------------------------- 1 | # Example ROS 2 message specification. 2 | # Roberto Masocco 3 | # January 5, 2022 4 | 5 | # Just one field storing a string 6 | string data 7 | -------------------------------------------------------------------------------- /src/ros2_examples_interfaces/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ros2_examples_interfaces 5 | 0.0.0 6 | ROS 2 example interfaces package. 7 | Roberto Masocco 8 | TODO 9 | 10 | ament_cmake 11 | 12 | rosidl_default_generators 13 | rosidl_default_runtime 14 | action_msgs 15 | rosidl_interface_packages 16 | 17 | ament_lint_auto 18 | ament_lint_common 19 | 20 | 21 | ament_cmake 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/ros2_examples_interfaces/srv/AddTwoInts.srv: -------------------------------------------------------------------------------- 1 | # Example ROS 2 service specification. 2 | # Roberto Masocco 3 | # January 5, 2022 4 | 5 | # This is totally compatible with the example_interfaces/AddTwoInts service 6 | # Note that the request could as well be empty, just meant to trigger something! 7 | # See example_interfaces/Trigger 8 | 9 | int64 a 10 | int64 b 11 | --- 12 | int64 sum 13 | -------------------------------------------------------------------------------- /tools/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/tools/.gitkeep -------------------------------------------------------------------------------- /tools/COLCON_IGNORE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/tools/COLCON_IGNORE -------------------------------------------------------------------------------- /vscode_cheat_sheet_linux.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelligentSystemsLabUTV/ros2-examples/a83af4d7808d683810123b89ef50d5ebc00f75f2/vscode_cheat_sheet_linux.pdf --------------------------------------------------------------------------------