├── templates ├── ros │ ├── .gitignore │ ├── docker │ │ ├── .env │ │ ├── docker-compose-nvidia.yml │ │ ├── docker-compose-gui-nvidia.yml │ │ ├── docker-compose-vscode.yml │ │ ├── docker-compose-gui.yml │ │ ├── docker-compose.yml │ │ └── Dockerfile │ ├── src │ │ └── .repos │ ├── .vscode │ │ ├── launch.json │ │ ├── c_cpp_properties.json │ │ └── tasks.json │ ├── .devcontainer │ │ └── devcontainer.json │ └── ReadMe.md ├── ros2 │ ├── .gitignore │ ├── .vscode │ │ ├── settings.json │ │ ├── launch.json │ │ ├── c_cpp_properties.json │ │ └── tasks.json │ ├── src │ │ └── .repos │ ├── docker │ │ ├── .env │ │ ├── docker-compose-nvidia.yml │ │ ├── docker-compose-gui-nvidia.yml │ │ ├── docker-compose-vscode.yml │ │ ├── docker-compose-gui.yml │ │ ├── docker-compose.yml │ │ └── Dockerfile │ ├── .devcontainer │ │ └── devcontainer.json │ ├── dds │ │ └── cyclone.xml │ └── ReadMe.md └── ReadMe.md ├── media ├── glxgears.png ├── rviz_mesa_bug.png ├── windows10_rviz.png ├── nvidia_x_server.png ├── ubuntu_software_and_updates.png ├── windows10_affordance_templates.png ├── ubuntu_jammy_affordance_templates.png ├── visual_studio_code_terminal_tasks.png ├── visual_studio_code_terminal_tasks_list.png ├── visual_studio_code_dev_containers_on_start.png ├── visual_studio_code_dev_containers_terminal.png ├── visual_studio_code_dev_containers_after_install.png ├── visual_studio_code_dev_containers_before_install.png └── visual_studio_code_dev_containers_reopen_in_container.png ├── examples ├── lpms-ros-docker │ ├── media │ │ └── preview.png │ ├── docker │ │ ├── docker-compose-nvidia.yml │ │ ├── docker-compose.yml │ │ ├── docker-compose-gui-nvidia.yml │ │ ├── docker-compose-gui.yml │ │ └── Dockerfile │ ├── .devcontainer │ │ └── devcontainer.json │ └── ReadMe.md ├── affordance-templates-ros-docker │ ├── media │ │ └── preview.png │ ├── docker │ │ ├── docker-compose.yml │ │ ├── docker-compose-gui.yml │ │ └── Dockerfile │ ├── .devcontainer │ │ └── devcontainer.json │ ├── src │ │ └── at_r2_bringup │ │ │ ├── CMakeLists.txt │ │ │ ├── launch │ │ │ └── demo.launch │ │ │ ├── package.xml │ │ │ └── config │ │ │ └── at_r2_moveit.rviz │ └── ReadMe.md └── ReadMe.md ├── .github └── workflows │ ├── build-ros.yml │ └── build-ros2.yml ├── License.md ├── .gitmodules ├── ReadMe.md └── doc ├── VisualStudioCodeSetup.md ├── Windows.md ├── WorkingWithHardware.md ├── AdvancedTopics.md ├── Motivation.md ├── Gui.md ├── Ros.md └── Introduction.md /templates/ros/.gitignore: -------------------------------------------------------------------------------- 1 | src/* 2 | !src/.repos 3 | -------------------------------------------------------------------------------- /templates/ros2/.gitignore: -------------------------------------------------------------------------------- 1 | src/* 2 | !src/.repos 3 | -------------------------------------------------------------------------------- /media/glxgears.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/glxgears.png -------------------------------------------------------------------------------- /media/rviz_mesa_bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/rviz_mesa_bug.png -------------------------------------------------------------------------------- /media/windows10_rviz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/windows10_rviz.png -------------------------------------------------------------------------------- /media/nvidia_x_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/nvidia_x_server.png -------------------------------------------------------------------------------- /media/ubuntu_software_and_updates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/ubuntu_software_and_updates.png -------------------------------------------------------------------------------- /media/windows10_affordance_templates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/windows10_affordance_templates.png -------------------------------------------------------------------------------- /examples/lpms-ros-docker/media/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/examples/lpms-ros-docker/media/preview.png -------------------------------------------------------------------------------- /media/ubuntu_jammy_affordance_templates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/ubuntu_jammy_affordance_templates.png -------------------------------------------------------------------------------- /media/visual_studio_code_terminal_tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/visual_studio_code_terminal_tasks.png -------------------------------------------------------------------------------- /templates/ros2/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "pylint.args": [ 3 | ], 4 | "mypy-type-checker.args": [ 5 | "--strict" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /templates/ros2/src/.repos: -------------------------------------------------------------------------------- 1 | repositories: 2 | examples: 3 | type: git 4 | url: https://github.com/ros2/examples.git 5 | version: humble 6 | -------------------------------------------------------------------------------- /media/visual_studio_code_terminal_tasks_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/visual_studio_code_terminal_tasks_list.png -------------------------------------------------------------------------------- /templates/ros/docker/.env: -------------------------------------------------------------------------------- 1 | CATKIN_WORKSPACE_DIR=/catkin_ws 2 | YOUR_IP=127.0.0.1 3 | ROBOT_IP=127.0.0.1 4 | ROBOT_HOSTNAME=P500 5 | UID=1000 6 | GID=1000 7 | -------------------------------------------------------------------------------- /templates/ros/src/.repos: -------------------------------------------------------------------------------- 1 | repositories: 2 | tutorials: 3 | type: git 4 | url: https://github.com/ros/ros_tutorials.git 5 | version: noetic-devel 6 | -------------------------------------------------------------------------------- /media/visual_studio_code_dev_containers_on_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/visual_studio_code_dev_containers_on_start.png -------------------------------------------------------------------------------- /media/visual_studio_code_dev_containers_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/visual_studio_code_dev_containers_terminal.png -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/media/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/examples/affordance-templates-ros-docker/media/preview.png -------------------------------------------------------------------------------- /media/visual_studio_code_dev_containers_after_install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/visual_studio_code_dev_containers_after_install.png -------------------------------------------------------------------------------- /media/visual_studio_code_dev_containers_before_install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/visual_studio_code_dev_containers_before_install.png -------------------------------------------------------------------------------- /templates/ros2/docker/.env: -------------------------------------------------------------------------------- 1 | AMENT_WORKSPACE_DIR=/ament_ws 2 | ROS_DOMAIN_ID=0 3 | YOUR_IP=127.0.0.1 4 | ROBOT_IP=127.0.0.1 5 | ROBOT_HOSTNAME=P500 6 | UID=1000 7 | GID=1000 8 | -------------------------------------------------------------------------------- /media/visual_studio_code_dev_containers_reopen_in_container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2b-t/docker-for-robotics/HEAD/media/visual_studio_code_dev_containers_reopen_in_container.png -------------------------------------------------------------------------------- /templates/ros/docker/docker-compose-nvidia.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros_docker: 4 | extends: 5 | file: docker-compose.yml 6 | service: ros_docker 7 | environment: 8 | - NVIDIA_VISIBLE_DEVICES=all 9 | runtime: nvidia 10 | 11 | -------------------------------------------------------------------------------- /examples/lpms-ros-docker/docker/docker-compose-nvidia.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | lpms_ros: 4 | extends: 5 | file: docker-compose.yml 6 | service: lpms_ros 7 | environment: 8 | - NVIDIA_VISIBLE_DEVICES=all 9 | runtime: nvidia 10 | -------------------------------------------------------------------------------- /templates/ros2/docker/docker-compose-nvidia.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros2_docker: 4 | extends: 5 | file: docker-compose.yml 6 | service: ros2_docker 7 | environment: 8 | - NVIDIA_VISIBLE_DEVICES=all 9 | runtime: nvidia 10 | 11 | -------------------------------------------------------------------------------- /examples/lpms-ros-docker/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | lpms_ros: 4 | build: 5 | context: .. 6 | dockerfile: docker/Dockerfile 7 | tty: true 8 | volumes: 9 | - /dev:/dev 10 | device_cgroup_rules: 11 | - 'c 188:* rmw' 12 | 13 | -------------------------------------------------------------------------------- /examples/lpms-ros-docker/docker/docker-compose-gui-nvidia.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | lpms_ros: 4 | extends: 5 | file: docker-compose-gui.yml 6 | service: lpms_ros 7 | environment: 8 | - NVIDIA_VISIBLE_DEVICES=all 9 | - NVIDIA_DRIVER_CAPABILITIES=all 10 | runtime: nvidia 11 | -------------------------------------------------------------------------------- /templates/ros/docker/docker-compose-gui-nvidia.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros_docker: 4 | extends: 5 | file: docker-compose-gui.yml 6 | service: ros_docker 7 | environment: 8 | - NVIDIA_VISIBLE_DEVICES=all 9 | - NVIDIA_DRIVER_CAPABILITIES=all 10 | runtime: nvidia 11 | 12 | -------------------------------------------------------------------------------- /templates/ros2/docker/docker-compose-gui-nvidia.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros2_docker: 4 | extends: 5 | file: docker-compose-gui.yml 6 | service: ros2_docker 7 | environment: 8 | - NVIDIA_VISIBLE_DEVICES=all 9 | - NVIDIA_DRIVER_CAPABILITIES=all 10 | runtime: nvidia 11 | 12 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | affordance_templates: 4 | build: 5 | context: .. 6 | dockerfile: docker/Dockerfile 7 | container_name: affordance_templates 8 | tty: true 9 | volumes: 10 | - ../src:/affordance_templates_ws/src 11 | 12 | -------------------------------------------------------------------------------- /templates/ros/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "ROS: Attach", 5 | "type": "ros", 6 | "request": "attach" 7 | }, 8 | { 9 | "name": "ROS: Attach to Python", 10 | "type": "ros", 11 | "request": "attach", 12 | "runtime": "Python" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /templates/ros2/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "ROS: Attach", 5 | "type": "ros", 6 | "request": "attach" 7 | }, 8 | { 9 | "name": "ROS: Attach to Python", 10 | "type": "ros", 11 | "request": "attach", 12 | "runtime": "Python" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /templates/ros/docker/docker-compose-vscode.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros_docker: 4 | extends: 5 | file: docker-compose-gui.yml 6 | service: ros_docker 7 | cap_add: 8 | # Required for GDB debugging with ROS extension 9 | - SYS_PTRACE 10 | volumes: 11 | - ../.vscode:${CATKIN_WORKSPACE_DIR}/.vscode 12 | 13 | -------------------------------------------------------------------------------- /templates/ros2/docker/docker-compose-vscode.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros2_docker: 4 | extends: 5 | file: docker-compose-gui.yml 6 | service: ros2_docker 7 | cap_add: 8 | # Required for GDB debugging with ROS extension 9 | - SYS_PTRACE 10 | volumes: 11 | - ../.vscode:${AMENT_WORKSPACE_DIR}/.vscode 12 | 13 | -------------------------------------------------------------------------------- /examples/lpms-ros-docker/docker/docker-compose-gui.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | lpms_ros: 4 | extends: 5 | file: docker-compose.yml 6 | service: lpms_ros 7 | environment: 8 | - DISPLAY=${DISPLAY} 9 | - QT_X11_NO_MITSHM=1 10 | volumes: 11 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 12 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw 13 | -------------------------------------------------------------------------------- /templates/ros/docker/docker-compose-gui.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros_docker: 4 | extends: 5 | file: docker-compose.yml 6 | service: ros_docker 7 | environment: 8 | - DISPLAY=${DISPLAY} 9 | - QT_X11_NO_MITSHM=1 10 | volumes: 11 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 12 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw 13 | 14 | -------------------------------------------------------------------------------- /templates/ros2/docker/docker-compose-gui.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros2_docker: 4 | extends: 5 | file: docker-compose.yml 6 | service: ros2_docker 7 | environment: 8 | - DISPLAY=${DISPLAY} 9 | - QT_X11_NO_MITSHM=1 10 | volumes: 11 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 12 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw 13 | 14 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Affordance templates Docker", 3 | "dockerComposeFile": [ 4 | "../docker/docker-compose-gui.yml" // Alternative: "../docker/docker-compose-gui.yml" 5 | ], 6 | "service": "affordance_templates", 7 | "workspaceFolder": "/affordance_templates_ws", 8 | "shutdownAction": "stopCompose" 9 | } 10 | -------------------------------------------------------------------------------- /examples/lpms-ros-docker/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Docker for LPMS IMU", 3 | "dockerComposeFile": [ 4 | "../docker/docker-compose-gui.yml" // Alternatives: "../docker/docker-compose-gui.yml", "../docker/docker-compose-gui-nvidia.yml" 5 | ], 6 | "service": "lpms_ros", 7 | "workspaceFolder": "/lpms_ws", 8 | "shutdownAction": "stopCompose", 9 | "extensions": [ 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/docker/docker-compose-gui.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | affordance_templates: 4 | extends: 5 | file: docker-compose.yml 6 | service: affordance_templates 7 | environment: 8 | - DISPLAY=${DISPLAY} 9 | - QT_X11_NO_MITSHM=1 10 | volumes: 11 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 12 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw 13 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/src/at_r2_bringup/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(at_r2_bringup) 3 | 4 | find_package(catkin REQUIRED COMPONENTS 5 | ) 6 | 7 | catkin_package( 8 | CATKIN_DEPENDS 9 | ) 10 | 11 | install(DIRECTORY config 12 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config 13 | ) 14 | 15 | install(DIRECTORY launch 16 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch 17 | ) 18 | 19 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/src/at_r2_bringup/launch/demo.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /templates/ros/.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "/opt/ros/${env:ROS_DISTRO}/include/**", 8 | "/usr/include/**" 9 | ], 10 | "defines": [], 11 | "compilerPath": "/usr/bin/g++", 12 | "cStandard": "c11", 13 | "cppStandard": "c++17", 14 | "intelliSenseMode": "gcc-x64" 15 | } 16 | ], 17 | "version": 4 18 | } 19 | -------------------------------------------------------------------------------- /templates/ros2/.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "/opt/ros/${env:ROS_DISTRO}/include/**", 8 | "/usr/include/**" 9 | ], 10 | "defines": [], 11 | "compilerPath": "/usr/bin/g++", 12 | "cStandard": "c11", 13 | "cppStandard": "c++17", 14 | "intelliSenseMode": "gcc-x64" 15 | } 16 | ], 17 | "version": 4 18 | } 19 | -------------------------------------------------------------------------------- /templates/ReadMe.md: -------------------------------------------------------------------------------- 1 | # ROS and ROS 2 Docker Templates 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2025) 4 | 5 | 6 | 7 | ## Overview 8 | 9 | This directory contains a **ROS Noetic** as well as a **ROS 2 Jazzy Docker workspace** template that should allow you to get started quickly with the best practices given in the documentation of this repository. The individual subdirectories contain a read-me that explains what settings can be made to the corresponding workspaces. 10 | -------------------------------------------------------------------------------- /templates/ros/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ROS Docker", 3 | "dockerComposeFile": [ 4 | "../docker/docker-compose-vscode.yml" 5 | ], 6 | "service": "ros_docker", 7 | "workspaceFolder": "/catkin_ws", 8 | "shutdownAction": "stopCompose", 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "ms-iot.vscode-ros", 13 | "ms-python.python", 14 | "ms-vscode.cmake-tools", 15 | "ms-vscode.cpptools" 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/build-ros.yml: -------------------------------------------------------------------------------- 1 | name: ROS Docker 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'templates/ros/docker/Dockerfile' 7 | - 'templates/ros/docker/docker-compose.yml' 8 | schedule: 9 | - cron: "0 12 1 * *" 10 | workflow_dispatch: 11 | 12 | jobs: 13 | docker-compose-build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | - name: Build the Dockerfile with Docker-Compose 19 | run: docker compose -f templates/ros/docker/docker-compose.yml build 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/build-ros2.yml: -------------------------------------------------------------------------------- 1 | name: ROS 2 Docker 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'templates/ros2/docker/Dockerfile' 7 | - 'templates/ros2/docker/docker-compose.yml' 8 | schedule: 9 | - cron: "0 12 1 * *" 10 | workflow_dispatch: 11 | 12 | jobs: 13 | docker-compose-build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | - name: Build the Dockerfile with Docker-Compose 19 | run: docker compose -f templates/ros2/docker/docker-compose.yml build 20 | 21 | -------------------------------------------------------------------------------- /templates/ros2/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ROS2 Docker", 3 | "dockerComposeFile": [ 4 | "../docker/docker-compose-vscode.yml" 5 | ], 6 | "service": "ros2_docker", 7 | "workspaceFolder": "/ament_ws", 8 | "shutdownAction": "stopCompose", 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "ms-iot.vscode-ros", 13 | "ms-python.mypy-type-checker", 14 | "ms-python.pylint", 15 | "ms-python.python", 16 | "ms-vscode.cmake-tools", 17 | "ms-vscode.cpptools" 18 | ] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/src/at_r2_bringup/package.xml: -------------------------------------------------------------------------------- 1 | 2 | at_r2_bringup 3 | 0.0.1 4 | Configuration and launch files for affordance-templates with the NASA Robonaut2 5 | Tobit Flatscher 6 | Tobit Flatscher 7 | MIT 8 | 9 | catkin 10 | affordance_template_server 11 | r2_gazebo 12 | r2_moveit_config 13 | 14 | -------------------------------------------------------------------------------- /examples/lpms-ros-docker/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ros:noetic-robot 2 | 3 | ENV WS_DIR="/lpms_ws" 4 | WORKDIR ${WS_DIR} 5 | 6 | SHELL ["/bin/bash", "-c"] 7 | 8 | ARG DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update \ 11 | && apt-get install -y \ 12 | build-essential \ 13 | cmake \ 14 | git-all \ 15 | software-properties-common \ 16 | && rm -rf /var/lib/apt/lists/* 17 | 18 | RUN apt-get update \ 19 | && apt-get install -y \ 20 | ros-${ROS_DISTRO}-openzen-sensor \ 21 | ros-${ROS_DISTRO}-rviz \ 22 | ros-${ROS_DISTRO}-rviz-imu-plugin \ 23 | ros-${ROS_DISTRO}-rviz-plugin-tutorials \ 24 | && rm -rf /var/lib/apt/lists/* 25 | 26 | ARG DEBIAN_FRONTEND=dialog 27 | -------------------------------------------------------------------------------- /templates/ros2/dds/cyclone.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | auto 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | true 17 | 18 | 19 | 20 | default 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /templates/ros/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros_docker: 4 | build: 5 | context: .. 6 | dockerfile: docker/Dockerfile 7 | target: dev 8 | args: 9 | - CATKIN_WORKSPACE_DIR=${CATKIN_WORKSPACE_DIR} 10 | - USERNAME=${USERNAME:-developer} 11 | - UID=${UID} 12 | - GID=${GID} 13 | container_name: ros_docker 14 | environment: 15 | - ROS_MASTER_URI=http://${ROBOT_IP}:11311 16 | - ROS_IP=${YOUR_IP} 17 | extra_hosts: 18 | - "${ROBOT_HOSTNAME}:${ROBOT_IP}" 19 | # Required for communicating over the network 20 | network_mode: "host" 21 | # Required for accessing hardware 22 | #privileged: true 23 | tty: true 24 | volumes: 25 | # Required for accessing hardware 26 | #- /dev:/dev 27 | # Required for accessing storage media 28 | #- /media:/media 29 | - ../src:${CATKIN_WORKSPACE_DIR}/src 30 | 31 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM osrf/ros:indigo-desktop-full 2 | 3 | ENV ROS_WS_DIR="/affordance_templates_ws" 4 | WORKDIR ${ROS_WS_DIR} 5 | 6 | SHELL ["/bin/bash", "-c"] 7 | 8 | ENV DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update \ 11 | && apt-get -y install \ 12 | git \ 13 | libboost-dev \ 14 | libdw-dev \ 15 | libqt5svg5-dev \ 16 | libzmq3-dev \ 17 | python-catkin-tools \ 18 | qtbase5-dev \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | RUN apt-get update \ 22 | && apt-get -y install \ 23 | ros-${ROS_DISTRO}-control* \ 24 | ros-${ROS_DISTRO}-gazebo-plugins \ 25 | ros-${ROS_DISTRO}-gazebo-ros-control* \ 26 | ros-${ROS_DISTRO}-moveit* \ 27 | ros-${ROS_DISTRO}-navigation \ 28 | ros-${ROS_DISTRO}-object-recognition-ros \ 29 | ros-${ROS_DISTRO}-octomap-rviz-plugins \ 30 | ros-${ROS_DISTRO}-orocos-kdl \ 31 | ros-${ROS_DISTRO}-ros-control* \ 32 | ros-${ROS_DISTRO}-rqt \ 33 | ros-${ROS_DISTRO}-simulators \ 34 | ros-${ROS_DISTRO}-trac-ik* \ 35 | && rm -rf /var/lib/apt/lists/* 36 | 37 | ENV DEBIAN_FRONTEND=dialog 38 | 39 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Tobit Flatscher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "examples/docker-realtime"] 2 | path = examples/docker-realtime 3 | url = https://github.com/2b-t/docker-realtime 4 | [submodule "examples/realsense-ros2-docker"] 5 | path = examples/realsense-ros2-docker 6 | url = https://github.com/2b-t/realsense-ros2-docker 7 | [submodule "examples/velodyne-ros2-docker"] 8 | path = examples/velodyne-ros2-docker 9 | url = https://github.com/2b-t/velodyne-ros2-docker 10 | [submodule "examples/affordance-templates-ros-docker/src/affordance_templates"] 11 | path = examples/affordance-templates-ros-docker/src/affordance_templates 12 | url = https://bitbucket.org/traclabs/affordance_templates.git 13 | [submodule "examples/affordance-templates-ros-docker/src/nasa_r2_common"] 14 | path = examples/affordance-templates-ros-docker/src/nasa_r2_common 15 | url = https://bitbucket.org/traclabs/nasa_r2_common.git 16 | [submodule "examples/affordance-templates-ros-docker/src/nasa_r2_simulator"] 17 | path = examples/affordance-templates-ros-docker/src/nasa_r2_simulator 18 | url = https://bitbucket.org/traclabs/nasa_r2_simulator.git 19 | [submodule "examples/affordance-templates-ros-docker/src/robot_interaction_tools"] 20 | path = examples/affordance-templates-ros-docker/src/robot_interaction_tools 21 | url = https://bitbucket.org/traclabs/robot_interaction_tools.git 22 | -------------------------------------------------------------------------------- /examples/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (March - May 2023) 4 | 5 | 6 | 7 | ## Overview 8 | 9 | This directory contains several examples of Docker in combination with ROS: 10 | 11 | - The ROS Indigo workspace [`affordance-templates-ros-docker`](./affordance-templates-ros-docker) shows how Docker can be used to **revive an old ROS workspace** that would require an outdated operating system to run. 12 | - The repository [`docker-realtime`](./docker-realtime) explains how to **set-up a computer with a real-time-patched operating systems** ([`PREEMPT_RT`-patch](https://archive.kernel.org/oldwiki/rt.wiki.kernel.org/index.php/CONFIG_PREEMPT_RT_Patch.html)) and how to run real-time capable code from inside a Docker container. 13 | - The workspace [`lpms-ros-docker`](./lpms-ros-docker) and the repository [`realsense-ros2-docker`](./realsense-ros2-docker) show how to give access to **external hardware connected via USB** to a Docker with examples for a [**Life Performance Research IMU**](https://www.lp-research.com/) as well as [**Intel Realsense sensors**](https://www.intelrealsense.com/), such as their depth cameras. 14 | - The repository [`velodyne-ros2-docker`](./velodyne-ros2-docker) shows how to give access to **devices connected over Ethernet** to a Docker using the example of a [**Velodyne 3D lidar**](https://velodynelidar.com/). 15 | -------------------------------------------------------------------------------- /templates/ros2/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | ros2_docker: 4 | build: 5 | context: .. 6 | dockerfile: docker/Dockerfile 7 | target: dev 8 | args: 9 | - AMENT_WORKSPACE_DIR=${AMENT_WORKSPACE_DIR} 10 | - USERNAME=${USERNAME:-developer} 11 | - UID=${UID} 12 | - GID=${GID} 13 | container_name: ros2_docker 14 | environment: 15 | - ROS_DOMAIN_ID=${ROS_DOMAIN_ID} 16 | # Limit ROS communication to local computer only 17 | #- ROS_LOCALHOST_ONLY=1 18 | - YOUR_IP=${YOUR_IP} 19 | - ROBOT_IP=${ROBOT_IP} 20 | - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp 21 | # Configure Cyclone with a custom configuration using the IPs above 22 | #- CYCLONEDDS_URI=${AMENT_WORKSPACE_DIR}/dds/cyclone.xml 23 | extra_hosts: 24 | - "${ROBOT_HOSTNAME}:${ROBOT_IP}" 25 | # Required for communicating over the network 26 | network_mode: "host" 27 | # Required for accessing hardware 28 | #privileged: true 29 | tty: true 30 | volumes: 31 | # Required for accessing hardware 32 | #- /dev:/dev 33 | # Required for accessing storage media 34 | #- /media:/media 35 | - ../src:${AMENT_WORKSPACE_DIR}/src 36 | - ../dds:${AMENT_WORKSPACE_DIR}/dds 37 | # Required for ROS 2 shared memory communication 38 | #- /dev/shm:/dev/shm 39 | 40 | -------------------------------------------------------------------------------- /examples/lpms-ros-docker/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Docker for LP-Research IMUs 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (May 2023) 4 | 5 | 6 | 7 | ## 0. Overview 8 | This repository contains a Docker and all the documentation required to launch a RS232/USB [Life Performance Research IMU](https://www.lp-research.com/lpms-inertial-measurement-unit-imu-series/) connected over USB with the [Robot Operating System ROS](http://wiki.ros.org/noetic). It was tested with a [LPMS-IG1](https://www.lp-research.com/9-axis-imu-with-gps-receiver-series/). 9 | 10 | ## 1. Creating a Docker 11 | It is then important to mount `/dev` as a volume so that the Docker can access the hardware and allow the Docker to access the corresponding allocated devices by supplying a corresponding [`device_cgroup_rules`](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/sec-devices). 12 | 13 | In the `docker-compose.yml` this is done with the options: 14 | 15 | ```yaml 16 | volumes: 17 | - /dev:/dev 18 | device_cgroup_rules: 19 | - 'c 188:* rmw' 20 | ``` 21 | 22 | ## 2. Launching 23 | Allow the container to display contents on your host machine by typing 24 | 25 | ```bash 26 | $ xhost +local:root 27 | ``` 28 | 29 | Then build the Docker container with 30 | 31 | ```shell 32 | $ docker compose -f docker-compose-gui.yml build 33 | ``` 34 | or directly with the [`devcontainer` in Visual Studio Code](https://code.visualstudio.com/docs/devcontainers/containers). For Nvidia graphic cards the file `docker-compose-gui-nvidia.yml` in combination with the [`nvidia-container-runtime`](https://nvidia.github.io/nvidia-container-runtime/) has to be used instead. 35 | After it is done building **connect the IMU**, start the container 36 | 37 | ```shell 38 | $ docker compose -f docker-compose-gui.yml up 39 | ``` 40 | Open a new console and start a ROS master with 41 | ```shell 42 | $ source /opt/ros/noetic/setup.bash 43 | $ roscore 44 | ``` 45 | Open another terminal and start the [**driver**](https://bitbucket.org/lpresearch/openzenros/src/master/) with 46 | ```shell 47 | $ source /opt/ros/noetic/setup.bash 48 | $ rosrun openzen_sensor openzen_sensor_node 49 | ``` 50 | Finally start the **visualization** from yet another terminal inside the Docker 51 | ```shell 52 | $ source /opt/ros/noetic/setup.bash 53 | $ rosrun rviz rviz 54 | ``` 55 | Set the fixed frame to `imu` and display the `/imu/data`: 56 | 57 | ![RViz preview](media/preview.png) 58 | 59 | -------------------------------------------------------------------------------- /templates/ros/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | ############## 2 | # Base image # 3 | ############## 4 | FROM ros:noetic-robot AS base 5 | 6 | ARG CATKIN_WORKSPACE_DIR="/catkin_ws" 7 | 8 | LABEL org.opencontainers.image.authors="tobit.flatscher@outlook.com" 9 | LABEL description="ROS Noetic Docker template" 10 | LABEL version="1.0" 11 | 12 | WORKDIR ${CATKIN_WORKSPACE_DIR} 13 | SHELL ["/bin/bash", "-c"] 14 | 15 | ENV DEBIAN_FRONTEND=noninteractive 16 | 17 | RUN apt-get update \ 18 | && apt-get -y install \ 19 | git \ 20 | python3-catkin-tools \ 21 | python3-osrf-pycommon \ 22 | && rm -rf /var/lib/apt/lists/* 23 | 24 | RUN apt-get update \ 25 | && apt-get -y install \ 26 | ros-${ROS_DISTRO}-compressed-image-transport \ 27 | ros-${ROS_DISTRO}-compressed-depth-image-transport \ 28 | ros-${ROS_DISTRO}-image-transport \ 29 | && rm -rf /var/lib/apt/lists/* 30 | 31 | # Add additional installation instructions here... 32 | 33 | ENV DEBIAN_FRONTEND=dialog 34 | 35 | 36 | ##################### 37 | # Development image # 38 | ##################### 39 | FROM base AS dev 40 | 41 | ARG CATKIN_WORKSPACE_DIR="/catkin_ws" 42 | ARG USERNAME="developer" 43 | ARG UID=1000 44 | ARG GID=1000 45 | 46 | ENV DEBIAN_FRONTEND=noninteractive 47 | 48 | RUN apt-get update \ 49 | && apt-get install -y \ 50 | ack \ 51 | bmon \ 52 | cloc \ 53 | gdb \ 54 | htop \ 55 | iperf3 \ 56 | iputils-ping \ 57 | mlocate \ 58 | net-tools \ 59 | psmisc \ 60 | tmux \ 61 | xterm \ 62 | && rm -rf /var/lib/apt/lists/* 63 | 64 | RUN apt-get update \ 65 | && apt-get install -y \ 66 | python3-vcstool \ 67 | ros-${ROS_DISTRO}-rqt-common-plugins \ 68 | ros-${ROS_DISTRO}-rqt-robot-plugins \ 69 | ros-${ROS_DISTRO}-rviz \ 70 | && rm -rf /var/lib/apt/lists/* 71 | 72 | # Install additional developer tools here... 73 | 74 | RUN apt-get update \ 75 | && apt-get install -y sudo \ 76 | && rm -rf /var/lib/apt/lists/* \ 77 | && addgroup --gid ${GID} ${USERNAME} \ 78 | && adduser --disabled-password --gecos '' --uid ${GID} --gid ${GID} ${USERNAME} \ 79 | && echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} \ 80 | && chown -R ${UID}:${GID} /home/${USERNAME} \ 81 | && chown -R ${UID}:${GID} ${CATKIN_WORKSPACE_DIR} 82 | 83 | ENV DEBIAN_FRONTEND=dialog 84 | 85 | RUN echo "alias rsource='source ${CATKIN_WORKSPACE_DIR}/devel/setup.bash'" >> /home/${USERNAME}/.bash_aliases \ 86 | && echo "alias rbuild='(cd ${CATKIN_WORKSPACE_DIR} && catkin build)'" >> /home/${USERNAME}/.bash_aliases \ 87 | && echo "alias rclean='(cd ${CATKIN_WORKSPACE_DIR} && catkin clean -y)'" >> /home/${USERNAME}/.bash_aliases \ 88 | && echo "rsource || source /opt/ros/${ROS_DISTRO}/setup.bash" >> /home/${USERNAME}/.bashrc 89 | 90 | USER ${USERNAME} 91 | 92 | -------------------------------------------------------------------------------- /templates/ros2/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Author: Tobit Flatscher - github.com/2b-t (2022) 2 | { 3 | // See https://go.microsoft.com/fwlink/?LinkId=733558 4 | // for the documentation about the tasks.json format 5 | "version": "2.0.0", 6 | "tasks": [ 7 | // Import repositories with vcs tool 8 | { 9 | "label": "vcs", 10 | "detail": "Import dependencies with vcs tool.", 11 | "type": "shell", 12 | "command": "vcs import < .repos", 13 | "options": { 14 | "cwd": "${workspaceFolder}/src" 15 | }, 16 | "problemMatcher": [] 17 | }, 18 | // Install ROS dependencies 19 | { 20 | "label": "install dependencies", 21 | "detail": "Install all dependencies specified in the workspaces package.xml files.", 22 | "type": "shell", 23 | "command": "sudo apt-get update -y && rosdep update && rosdep install --from-paths src --ignore-src -y", 24 | "options": { 25 | "cwd": "${workspaceFolder}" 26 | }, 27 | "problemMatcher": [] 28 | }, 29 | // Build tasks 30 | { 31 | "label": "build", 32 | "detail": "Build the workspace (release).", 33 | "type": "shell", 34 | "command": "colcon build --symlink-install --cmake-args '-DCMAKE_BUILD_TYPE=Release' -Wall -Wextra -Wpedantic", 35 | "options": { 36 | "cwd": "${workspaceFolder}" 37 | }, 38 | "group": { 39 | "kind": "build", 40 | "isDefault": true 41 | }, 42 | "problemMatcher": "$gcc" 43 | }, 44 | { 45 | "label": "build debug", 46 | "detail": "Build the workspace (debug).", 47 | "type": "shell", 48 | "command": "colcon build --symlink-install --cmake-args '-DCMAKE_BUILD_TYPE=Debug' -Wall -Wextra -Wpedantic", 49 | "options": { 50 | "cwd": "${workspaceFolder}" 51 | }, 52 | "group": "build", 53 | "problemMatcher": "$gcc" 54 | }, 55 | // Test tasks 56 | { 57 | "label": "test", 58 | "detail": "Run all unit tests and show results.", 59 | "type": "shell", 60 | "command": "colcon test", 61 | "options": { 62 | "cwd": "${workspaceFolder}" 63 | }, 64 | "group": { 65 | "kind": "test", 66 | "isDefault": true 67 | }, 68 | "problemMatcher": [] 69 | }, 70 | // Clean tasks 71 | { 72 | "label": "clean", 73 | "detail": "Run the clean target.", 74 | "type": "shell", 75 | "command": "colcon clean workspace --yes", 76 | "options": { 77 | "cwd": "${workspaceFolder}" 78 | }, 79 | "problemMatcher": [] 80 | }, 81 | { 82 | "label": "purge", 83 | "detail": "Purge workspace by deleting all generated files.", 84 | "type": "shell", 85 | "command": "rm -fr build install log && py3clean .", 86 | "options": { 87 | "cwd": "${workspaceFolder}" 88 | }, 89 | "problemMatcher": [] 90 | } 91 | ], 92 | "inputs": [ 93 | { 94 | "id": "package", 95 | "type": "promptString", 96 | "description": "Package name" 97 | } 98 | ] 99 | } 100 | -------------------------------------------------------------------------------- /templates/ros2/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | ############## 2 | # Base image # 3 | ############## 4 | FROM ros:jazzy-ros-base AS base 5 | 6 | ARG AMENT_WORKSPACE_DIR="/ament_ws" 7 | 8 | LABEL org.opencontainers.image.authors="tobit.flatscher@outlook.com" 9 | LABEL description="ROS 2 Jazzy Docker template" 10 | LABEL version="1.0" 11 | 12 | WORKDIR ${AMENT_WORKSPACE_DIR} 13 | SHELL ["/bin/bash", "-c"] 14 | 15 | ENV DEBIAN_FRONTEND=noninteractive 16 | 17 | RUN apt-get update \ 18 | && apt-get -y install \ 19 | git \ 20 | python3-colcon-clean \ 21 | python3-osrf-pycommon \ 22 | && rm -rf /var/lib/apt/lists/* 23 | 24 | RUN apt-get update \ 25 | && apt-get -y install \ 26 | ros-${ROS_DISTRO}-compressed-image-transport \ 27 | ros-${ROS_DISTRO}-compressed-depth-image-transport \ 28 | ros-${ROS_DISTRO}-image-transport \ 29 | ros-${ROS_DISTRO}-point-cloud-transport \ 30 | ros-${ROS_DISTRO}-point-cloud-transport-plugins \ 31 | ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \ 32 | && rm -rf /var/lib/apt/lists/* 33 | 34 | # Add additional installation instructions here... 35 | 36 | ENV DEBIAN_FRONTEND=dialog 37 | 38 | 39 | ##################### 40 | # Development image # 41 | ##################### 42 | FROM base AS dev 43 | 44 | ARG AMENT_WORKSPACE_DIR="/ament_ws" 45 | ARG USERNAME="developer" 46 | ARG UID=1000 47 | ARG GID=1000 48 | 49 | ENV DEBIAN_FRONTEND=noninteractive 50 | 51 | RUN apt-get update \ 52 | && apt-get install -y \ 53 | ack \ 54 | bmon \ 55 | cloc \ 56 | gdb \ 57 | htop \ 58 | iperf3 \ 59 | iputils-ping \ 60 | net-tools \ 61 | plocate \ 62 | psmisc \ 63 | tmux \ 64 | xterm \ 65 | && rm -rf /var/lib/apt/lists/* 66 | 67 | RUN apt-get update \ 68 | && apt-get install -y \ 69 | python3-vcstool \ 70 | ros-${ROS_DISTRO}-rqt-common-plugins \ 71 | ros-${ROS_DISTRO}-rqt-robot-steering \ 72 | ros-${ROS_DISTRO}-rqt-tf-tree \ 73 | ros-${ROS_DISTRO}-rviz2 \ 74 | && rm -rf /var/lib/apt/lists/* 75 | 76 | # Install additional developer tools here... 77 | 78 | RUN apt-get update \ 79 | && apt-get install -y sudo \ 80 | && rm -rf /var/lib/apt/lists/* \ 81 | # Remove user blocking UID 1000 on Ubuntu 24.04 and onwards: 82 | # See https://bugs.launchpad.net/cloud-images/+bug/2005129 and 83 | # https://github.com/devcontainers/images/issues/1056 84 | && userdel -r ubuntu || true \ 85 | && addgroup --gid ${GID} ${USERNAME} \ 86 | && adduser --disabled-password --gecos '' --uid ${GID} --gid ${GID} ${USERNAME} \ 87 | && echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} \ 88 | && chown -R ${UID}:${GID} /home/${USERNAME} \ 89 | && chown -R ${UID}:${GID} ${AMENT_WORKSPACE_DIR} 90 | 91 | ENV DEBIAN_FRONTEND=dialog 92 | 93 | RUN echo "alias rsource='source ${AMENT_WORKSPACE_DIR}/install/setup.bash'" >> /home/${USERNAME}/.bash_aliases \ 94 | && echo "alias rbuild='(cd ${AMENT_WORKSPACE_DIR} && colcon build)'" >> /home/${USERNAME}/.bash_aliases \ 95 | && echo "alias rclean='(cd ${AMENT_WORKSPACE_DIR} && colcon clean workspace -y)'" >> /home/${USERNAME}/.bash_aliases \ 96 | && echo "rsource || source /opt/ros/${ROS_DISTRO}/setup.bash" >> /home/${USERNAME}/.bashrc 97 | 98 | USER ${USERNAME} 99 | 100 | -------------------------------------------------------------------------------- /templates/ros/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Author: Tobit Flatscher - github.com/2b-t (2021) 2 | { 3 | // See https://go.microsoft.com/fwlink/?LinkId=733558 4 | // for the documentation about the tasks.json format 5 | "version": "2.0.0", 6 | "tasks": [ 7 | // Import repositories with vcs tool 8 | { 9 | "label": "vcs", 10 | "detail": "Import dependencies with vcs tool.", 11 | "type": "shell", 12 | "command": "vcs import < .repos", 13 | "options": { 14 | "cwd": "${workspaceFolder}/src" 15 | }, 16 | "problemMatcher": [] 17 | }, 18 | // Install ROS dependencies 19 | { 20 | "label": "install dependencies", 21 | "detail": "Install all dependencies specified in the workspaces package.xml files.", 22 | "type": "shell", 23 | "command": "sudo apt-get update && rosdep update && rosdep install --from-paths src --ignore-src -y", 24 | "options": { 25 | "cwd": "${workspaceFolder}" 26 | }, 27 | "problemMatcher": [] 28 | }, 29 | // Build tasks 30 | { 31 | "label": "build", 32 | "detail": "Build the workspace (default).", 33 | "type": "shell", 34 | "command": "catkin build --cmake-args '-DCMAKE_BUILD_TYPE=Release' -Wall -Wextra -Wpedantic", 35 | "options": { 36 | "cwd": "${workspaceFolder}" 37 | }, 38 | "group": { 39 | "kind": "build", 40 | "isDefault": true 41 | }, 42 | "problemMatcher": "$gcc" 43 | }, 44 | { 45 | "label": "build debug", 46 | "detail": "Build the workspace (debug).", 47 | "type": "shell", 48 | "command": "catkin build --cmake-args '-DCMAKE_BUILD_TYPE=Debug' -Wall -Wextra -Wpedantic", 49 | "options": { 50 | "cwd": "${workspaceFolder}" 51 | }, 52 | "group": "build", 53 | "problemMatcher": "$gcc" 54 | }, 55 | // Test tasks 56 | { 57 | "label": "test", 58 | "detail": "Run all unit tests and show results.", 59 | "type": "shell", 60 | "command": "catkin run_tests", 61 | "options": { 62 | "cwd": "${workspaceFolder}" 63 | }, 64 | "group": { 65 | "kind": "test", 66 | "isDefault": true 67 | }, 68 | "problemMatcher": [] 69 | }, 70 | // Clean 71 | { 72 | "label": "clean", 73 | "detail": "Run the clean target.", 74 | "type": "shell", 75 | "command": "catkin clean --yes", 76 | "options": { 77 | "cwd": "${workspaceFolder}" 78 | }, 79 | "problemMatcher": [] 80 | }, 81 | { 82 | "label": "purge", 83 | "detail": "Purge workspace by deleting all generated files.", 84 | "type": "shell", 85 | "command": "rm -fr .catkin_tools build install log && py3clean .", 86 | "options": { 87 | "cwd": "${workspaceFolder}" 88 | }, 89 | "problemMatcher": [] 90 | }, 91 | // Start ROS Master node 92 | { 93 | "label": "roscore", 94 | "detail": "Start the ROS master node.", 95 | "type": "shell", 96 | "command": "roscore", 97 | "options": { 98 | "cwd": "${workspaceFolder}" 99 | }, 100 | "problemMatcher": [] 101 | }, 102 | ], 103 | "inputs": [ 104 | { 105 | "id": "package", 106 | "type": "promptString", 107 | "description": "Package name" 108 | } 109 | ] 110 | } 111 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # Docker for Robotics with the Robot Operating System (ROS/ROS 2) 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2024) 4 | 5 | [![ROS Docker](https://github.com/2b-t/docker-for-robotics/actions/workflows/build-ros.yml/badge.svg)](https://github.com/2b-t/docker-for-robotics/actions/workflows/build-ros.yml) [![ROS 2 Docker](https://github.com/2b-t/docker-for-robotics/actions/workflows/build-ros2.yml/badge.svg?branch=main)](https://github.com/2b-t/docker-for-robotics/actions/workflows/build-ros2.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 6 | 7 | 8 | 9 | ## Overview 10 | 11 | This guide discusses best practices for **robotics development with the [Robot Operating System (ROS/ROS 2)](https://www.ros.org/) and Docker/Docker-Compose** on **Linux** as well as **Windows** operating systems. This includes displaying **graphic user interfaces**, working with hardware, **real-time capable code** and the **network set-up** for multiple machines. Additionally it walks you through the **set-up with Visual Studio Code**. 12 | 13 | This repository used to be part of [another guide](https://github.com/2b-t/docker-realtime) I have written on Docker and real-time applications. As the general Docker and ROS part has now become quite lengthy, I have decided to extract it and create a repository of its own for it. 14 | 15 | | ![Docker on Ubuntu](./media/ubuntu_jammy_affordance_templates.png) | ![Docker on Windows](./media/windows10_affordance_templates.png) | 16 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 17 | | ROS Indigo running from a Docker container on Ubuntu 22.04 | ROS Indigo running from a Docker container on Windows 10 with WSL2 | 18 | 19 | 20 | 21 | ## Structure of this guide 22 | 23 | This guide is structured in the following chapters: 24 | 25 | - [**Motivation**](./doc/Motivation.md): Tries to give you good reasons for why you should use Docker as a company or research institution. 26 | - [**Introduction to Docker and Docker-Compose**](./doc/Introduction.md): Introduces fundamental concepts of container-based development. 27 | - [**Set-up with Visual Studio Code**](./doc/VisualStudioCodeSetup.md): Walks you through the set-up of containers with Visual Studio Code. 28 | - [**Graphic user interfaces and Docker**](./doc/Gui.md): Discusses the challenges of using Docker with graphic user interfaces and presents workarounds. 29 | - [**ROS and Docker**](./doc/Ros.md): Discusses best-practices for Docker and ROS/ROS 2. 30 | - [**Docker on Windows**](./doc/Windows.md): Running Docker on Windows in WSL2 with graphic user interfaces. 31 | - [**Working with hardware**](./doc/WorkingWithHardware.md): Discusses best-practices when working with hardware. 32 | 33 | The folder [**`examples/`**](./examples) contains different ROS and ROS 2 examples (in simulation as well as with hardware access) while the folder [**`templates/`**](./templates) provides templates for ROS and ROS 2 that you can build your own workspace off. This guide is further extended by an external guide on **Docker for real-time applications with `PREEMPT_RT`** that can be found [here](https://github.com/2b-t/docker-realtime). 34 | 35 | 36 | 37 | ## Get a copy 38 | 39 | This workspace contains several other repositories as submodules. Therefore please clone it with the following command: 40 | 41 | ```bash 42 | $ git clone --recurse-submodules https://github.com/2b-t/docker-for-robotics.git 43 | ``` 44 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Example: Affordance templates workspace in ROS Indigo 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (March 2023) 4 | 5 | 6 | 7 | ## Overview 8 | 9 | Sometimes you come across some interesting old work that you would like to replicate. Sometimes a publication comes with open-source code but likely your ROS version will not necessarily match the one that was used in the publication. For me that was the case when reading the publication about [Affordance Templates](https://www.researchgate.net/publication/283668215_The_Affordance_Template_ROS_package_for_robot_task_programming) published by [Traclabs](https://traclabs.com/projects/affordance-templates/) (you might know them from [trac-ik](https://traclabs.com/projects/trac-ik/)) at [ICRA 2015](https://www.ieee-ras.org/component/rseventspro/event/400-icra-2015-ieee-international-conference-on-robotics-and-automation) (see image below). And even if you had an old computer with [ROS Indigo](http://wiki.ros.org/indigo) (released in 2014!) laying around you would not want to trash that computer with all the dependencies just for trying this one workspace out. This is again where Docker as a technology comes in really handy. 10 | 11 | ![Preview of the Affordance Templates workspace with the NASA Robonaut2](media/preview.png) 12 | 13 | The following example will shows how Docker can be useful for getting legacy code up and running on your machine. This example includes the packages from the [Traclabs Bitbucket](https://bitbucket.org/traclabs/) with the commits specified in [this workspace](https://github.com/yueyeyuniao/affordance_template). Potentially one could also get this workspace up and running in [ROS Fuerte](http://wiki.ros.org/fuerte) by following [this guide](https://bitbucket.org/nasa_ros_pkg/deprecated_misc/wiki/Home) and using the deprecated packages from the NASA Bitbucket ([`nasa_common`](https://bitbucket.org/nasa_ros_pkg/deprecated_nasa_common/src/master/), [`nasa_robodyn`](https://bitbucket.org/nasa_ros_pkg/deprecated_nasa_robodyn/src/master/), [`nasa_r2_simulator`](https://bitbucket.org/nasa_ros_pkg/deprecated_nasa_r2_simulator/src/master/) and [`nasa_r2_common`](https://bitbucket.org/nasa_ros_pkg/deprecated_nasa_r2_common/src/master/)). 14 | 15 | 16 | 17 | ## Installation 18 | 19 | Please make sure that you cloned this repository with the `--recurse-submodules` option as follows 20 | 21 | ```bash 22 | $ git clone --recurse-submodules https://github.com/2b-t/docker-for-robotics.git 23 | ``` 24 | 25 | else the modules from Traclabs will be empty. In case you did not you will have to run 26 | 27 | ```bash 28 | $ git submodule update --init 29 | ``` 30 | 31 | 32 | 33 | ## Running 34 | 35 | Open a terminal on your **host machine** and allow the user `root` to stream onto your display. This way the Docker (which is using `root` as a user) can open graphic user interface on your host machine: 36 | 37 | ```bash 38 | $ xhost +local:root 39 | ``` 40 | 41 | **Open your Docker** either manually or by using Visual Studio code as described in the main guide. Once inside the Docker perform the following steps: 42 | 43 | ```bash 44 | $ source /opt/ros/indigo/setup.bash 45 | $ catkin build 46 | $ source devel/setup.bash 47 | $ roslaunch at_r2_bringup demo.launch 48 | ``` 49 | 50 | This should open two new windows, one for the **Gazebo simulation**, the other for the **Rviz visualization** (see screenshot above). The Rviz visualization should contain two panels: The Moveit motion planning panel to the left and the affordance templates panel to the right. Crucial for the latter is the interactive marker that is displayed. Furthermore any object inserted into the scene should be visible from the Asus camera plug-in. 51 | 52 | Inside Moveit you can only plan for the head. To do so select a desired goal state from the section `Query` in the `Planning` tab. Then click `Update` and finally plan and execute the motion with `Plan and Execute`. 53 | 54 | The **affordance templates panel** on the right can be used for planning arm motions. As a first step click `Refresh All` in the `Server` tab. This should bring up all the available motion templates in the `Library` tab below. For inserting a new template double click on its icon. This will insert a virtual marker into the scene (if it does not appear make sure that you did not deactivate the interactive marker in the `Displays` panel!). You can adjust the parametrized motion by moving and rotating the interactive marker. This is crucial as the Robonaut will not be able to plan and execute a motion if it is out of reach. Finally in the `Controls` menu you can plan and execute the parametrized motion once inserted: The arrow buttons on the bottom allow you to plan the templates step by step. Click `Execute Plan` to then execute the planned motion. When activating the checkbox `Execute on Plan` stepping the motion will also result in the execution of the plan. 55 | -------------------------------------------------------------------------------- /templates/ros/ReadMe.md: -------------------------------------------------------------------------------- 1 | # ROS Noetic Docker Template 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2024) 4 | 5 | 6 | 7 | ## 0. Overview 8 | 9 | This repository contains a Docker workspace template for [**ROS Noetic**](http://wiki.ros.org/noetic). The idea is that a Docker is created for each project at Catkin workspace level. Dependencies that are not expected to change during the course of a project are installed from Debian packages inside the Dockerfile, while proprietary dependencies that are expected to change during a project are mounted into the container and version controlled with [**`vcstool`**](https://github.com/dirk-thomas/vcstool). Only selected folders such as `src/` are mounted into the container so that the workspace can be compiled on the host system as well as inside the container without interfering. 10 | 11 | Here is an overview of the structure of this repository: 12 | 13 | ```bash 14 | ros/ 15 | ├── docker/ # Docker and Docker-Compose configuration 16 | │ ├── docker-compose.yml # Base Docker-Compose file containing all the basic Docker set-up 17 | │ ├── docker-compose-gui.yml # Extends the base Docker-Compose file by X11-forwarding for graphic user interfaces 18 | │ ├── docker-compose-gui-nvidia.yml # Extends the graphic user interface Docker-Compose file with the Nvidia runtime 19 | │ ├── docker-compose-nvidia.yml # Extends the base Docker-Compose file with the Nvidia runtime for graphic acceleration 20 | │ ├── docker-compose-vscode.yml # Extends one of the other configurations with Visual Studio Code relevant settings 21 | │ ├── Dockerfile # Dockerfile containing ROS and the base dependencies 22 | │ └── .env # Environment variables to be considered by Docker Compose 23 | ├── src/ # Source folder mounted inside the Docker container 24 | │ └── .repos # VCS tool configuration file for version control 25 | ├── .devcontainer/ # Configuration files for containers in Visual Studio Code 26 | └── .vscode/ # Configuration files for Visual Studio Code 27 | ``` 28 | 29 | 30 | 31 | ## 1. Set-up 32 | 33 | After cloning this repository you will have to update the packages inside the workspace. For version control we use [`vcstool`](http://wiki.ros.org/vcstool) instead of Git submodules. In order to **pull the repositories** please import them with the following command (either inside the Docker or on the host): 34 | 35 | ``` 36 | $ cd src/ 37 | $ vcs import < .repos 38 | ``` 39 | 40 | This should clone the desired repositories given inside `.repos` into your workspace. They are excluded in the [`.gitignore`](./.gitignore) file so that they will not be part of your commits. 41 | 42 | The **configuration** is performed inside the [`docker/.env`](./docker/.env) file: 43 | 44 | ```bash 45 | CATKIN_WORKSPACE_DIR=/catkin_ws 46 | YOUR_IP=127.0.0.1 47 | ROBOT_IP=127.0.0.1 48 | ROBOT_HOSTNAME=P500 49 | UID=1000 50 | GID=1000 51 | ``` 52 | 53 | Here you can change the workspace name, network settings as well as user and group IDs. 54 | 55 | **Network set-up**: The parameter `YOUR_IP` corresponds to the IP that you are using, in case you are running a simulation set it to `127.0.0.1` while for working with a physical robot you will have to set it to the IP assigned to the network interface used for connecting to the robot shown by `$ ifconfig` from the `net-tools` package on your computer. The `ROBOT_IP` as well as the `ROBOT_HOSTNAME` are used to configure the `/etc/hosts` file as well as the `ROS_MASTER_URI`. They should correspond to the IP shown by `$ ifconfig` on the robot as well as to its `$ hostname` and can be set to `127.0.0.1` and an arbitrary hostname in case of the simulation. 56 | 57 | **User and group id**: These should be set identical to the user and group ID of the user running the container (see the output of `$ id`). On Debian system [anything below 1000 is generally reserved for system accounts](https://www.redhat.com/sysadmin/user-account-gid-uid) and the first UID `1000` is assigned to the first user of the system, which are the default values in our set-up. In case your user and group IDs differ, adjust them. 58 | 59 | 60 | 61 | ## 2. Running 62 | 63 | Either **run the Docker** manually with 64 | 65 | ```bash 66 | $ cd ros/ 67 | $ docker compose -f docker/docker-compose-gui.yml up 68 | ``` 69 | 70 | and then connect to the running Docker 71 | 72 | ```bash 73 | $ cd ros/ 74 | $ docker exec -it ros_docker bash 75 | ``` 76 | 77 | (or `docker/docker-compose-gui-nvidia.yml` in case you are running an Nvidia graphics cards and want to have hardware acceleration [with the Nvidia container runtime](https://nvidia.github.io/nvidia-container-runtime/)). Alternatively use the corresponding [**Visual Studio Code Dev Containers integration**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) as described [here](https://github.com/2b-t/docker-for-robotics/blob/main/doc/VisualStudioCodeSetup.md). In latter case the configuration can be adjusted in `docker/docker-compose-vscode.yml`. Using the Docker through Visual Studio Code is much easier and is therefore recommended! 78 | 79 | In order to be able to run **graphical user interfaces** from inside the Docker you might have to type 80 | 81 | ```bash 82 | $ xhost + 83 | ``` 84 | 85 | on the **host system**. When using a user with the same name, user and group id as the host system this should not be necessary. 86 | -------------------------------------------------------------------------------- /templates/ros2/ReadMe.md: -------------------------------------------------------------------------------- 1 | # ROS 2 Jazzy Docker Template 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2025) 4 | 5 | 6 | 7 | ## 0. Overview 8 | 9 | This repository contains a Docker workspace template for [**ROS 2 Jazzy**](https://docs.ros.org/en/jazzy/index.html). The idea is that a Docker is created for each project at Ament workspace level. Dependencies that are not expected to change during the course of a project are installed from Debian packages inside the Dockerfile, while proprietary dependencies that are expected to change during a project are mounted into the container and version controlled with [**`vcstool`**](https://github.com/dirk-thomas/vcstool). Only selected folders such as `dds/` and `src/` are mounted into the container so that the workspace can be compiled on the host system as well as inside the container without them interfering. 10 | 11 | Here is an overview of the structure of this repository: 12 | 13 | ```bash 14 | ros/ 15 | ├── dds/ # DDS middleware configuration 16 | ├── docker/ # Docker and Docker-Compose configuration 17 | │ ├── docker-compose.yml # Base Docker-Compose file containing all the basic Docker set-up 18 | │ ├── docker-compose-gui.yml # Extends the base Docker-Compose file by X11-forwarding for graphic user interfaces 19 | │ ├── docker-compose-gui-nvidia.yml # Extends the graphic user interface Docker-Compose file with the Nvidia runtime 20 | │ ├── docker-compose-nvidia.yml # Extends the base Docker-Compose file with the Nvidia runtime for graphic acceleration 21 | │ ├── docker-compose-vscode.yml # Extends one of the other configurations with Visual Studio Code relevant settings 22 | │ ├── Dockerfile # Dockerfile containing ROS 2 and the base dependencies 23 | │ └── .env # Environment variables to be considered by Docker Compose 24 | ├── src/ # Source folder mounted inside the Docker container 25 | │ └── .repos # VCS tool configuration file for version control 26 | ├── .devcontainer/ # Configuration files for containers in Visual Studio Code 27 | └── .vscode/ # Configuration files for Visual Studio Code 28 | ``` 29 | 30 | 31 | 32 | ## 1. Set-up 33 | 34 | After cloning this repository you will have to update the packages inside the workspace. For version control we use [`vcstool`](http://wiki.ros.org/vcstool) instead of Git submodules. In order to **pull the repositories** please import them with the following command (either inside the Docker or on the host): 35 | 36 | ``` 37 | $ cd src/ 38 | $ vcs import < .repos 39 | ``` 40 | 41 | This should clone the desired repositories given inside `.repos` into your workspace. They are excluded in the [`.gitignore`](./.gitignore) file so that they will not be part of your commits. 42 | 43 | The **configuration** is performed inside the [`docker/.env`](./docker/.env) file: 44 | 45 | ```bash 46 | AMENT_WORKSPACE_DIR=/ament_ws 47 | ROS_DOMAIN_ID=0 48 | YOUR_IP=127.0.0.1 49 | ROBOT_IP=127.0.0.1 50 | ROBOT_HOSTNAME=P500 51 | UID=1000 52 | GID=1000 53 | ``` 54 | 55 | Here you can change the workspace name, network settings as well as user and group IDs. 56 | 57 | **Network set-up**: The `ROS_DOMAIN_ID` is used for the ROS 2 DDS middleware configuration. The parameter `YOUR_IP` corresponds to the IP that you are using, in case you are running a simulation set it to `127.0.0.1` while for working with a physical robot you will have to set it to the IP assigned to the network interface used for connecting to the robot shown by `$ ifconfig` from the `net-tools` package on your computer. We use it for the DDS middleware configuration. The `ROBOT_IP` as well as the `ROBOT_HOSTNAME` are used to configure the `/etc/hosts` file as well as configuring the DDS middleware by IP. They should correspond to the IP shown by `$ ifconfig` on the robot as well as to its `$ hostname` and can be set to `127.0.0.1` and an arbitrary hostname in case of the simulation. 58 | 59 | **User and group id**: These should be set identical to the user and group ID of the user running the container (see the output of `$ id`). On Debian system [anything below 1000 is generally reserved for system accounts](https://www.redhat.com/sysadmin/user-account-gid-uid) and the first UID `1000` is assigned to the first user of the system, which are the default values in our set-up. In case your user and group IDs differ, adjust them. 60 | 61 | 62 | 63 | ## 2. Running 64 | 65 | Either **run the Docker** manually with 66 | 67 | ```bash 68 | $ cd ros2/ 69 | $ docker compose -f docker/docker-compose-gui.yml up 70 | ``` 71 | 72 | and then connect to the running Docker 73 | 74 | ```bash 75 | $ cd ros2/ 76 | $ docker exec -it ros2_docker bash 77 | ``` 78 | 79 | (or `docker/docker-compose-gui-nvidia.yml` in case you are running an Nvidia graphics cards and want to have hardware acceleration [with the Nvidia container runtime](https://nvidia.github.io/nvidia-container-runtime/)). Alternatively use the corresponding [**Visual Studio Code Dev Containers integration**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) as described [here](https://github.com/2b-t/docker-for-robotics/blob/main/doc/VisualStudioCodeSetup.md). In latter case the configuration can be adjusted in `docker/docker-compose-vscode.yml`. Using the Docker through Visual Studio Code is much easier and is therefore recommended! 80 | 81 | In order to be able to run **graphical user interfaces** from inside the Docker you might have to type 82 | 83 | ```bash 84 | $ xhost + 85 | ``` 86 | 87 | on the **host system**. When using a user with the same name, user and group id as the host system this should not be necessary. 88 | -------------------------------------------------------------------------------- /doc/VisualStudioCodeSetup.md: -------------------------------------------------------------------------------- 1 | # Docker and Visual Studio Code 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2023) 4 | 5 | 6 | 7 | ## 1. Docker in Visual Studio Code 8 | 9 | The following guide will walk you through the set-up for Docker inside Visual Studio Code. The integration of Docker with Visual Studio Code is excellent. I can only warmly recommend it for working with Visual Studio Code. 10 | 11 | ### 1.1 Installation 12 | 13 | If you do not have Visual Studio Code installed on your system then [install it](https://code.visualstudio.com/download) and follow the Docker post-installation steps given [here](https://docs.docker.com/engine/install/linux-postinstall/) so that you can run Docker without `sudo`. Finally install [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) and [**Remote - Containers**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) plugins inside Visual Studio Code and you should be ready to go. For installing the Remote Containers plug-in go the market place through the activity bar, browse the plug-in and install it as displayed in the screenshot below: 14 | 15 | ![Visual Studio Code before the Dev Containers installation](../media/visual_studio_code_dev_containers_before_install.png) 16 | 17 | After the successful installation you should see a small **green icon on the bottom left of your window** as displayed in the following screenshot: 18 | 19 | ![Visual Studio Code after the Dev Containers installation](../media/visual_studio_code_dev_containers_after_install.png) 20 | 21 | ### 1.2 Configuration 22 | 23 | Visual Studio Code generates two folders for your project, one called **`.devcontainer`** contains the Docker settings while the other, **`.vscode`**, contains the Visual Studio code preferences: 24 | 25 | ``` 26 | repository 27 | ├─ .devcontainer # Docker settings 28 | | └─ devcontainer.json 29 | └─ .vscode 30 | ``` 31 | 32 | #### 1.2.1 Devcontainer configuration 33 | 34 | The `.devcontainer` file let's Visual Studio Code know if it is dealing with [Docker](https://github.com/athackst/vscode_ros2_workspace/blob/foxy/.devcontainer/devcontainer.json) or [Docker Compose](https://github.com/devrt/ros-devcontainer-vscode/blob/master/.devcontainer/devcontainer.json). The contents of the Json configuration file `.devcontainer/devcontainers.json` might look as follows: 35 | 36 | ```json 37 | { 38 | "name": "ROS Docker", 39 | "dockerComposeFile": [ 40 | "../docker/docker-compose.yml" 41 | ], 42 | "service": "ros_docker", 43 | "workspaceFolder": "/benchmark", 44 | "shutdownAction": "stopCompose", 45 | "extensions": [ 46 | ] 47 | } 48 | ``` 49 | 50 | You can also [access local variables on the host system with `${localEnv:SOME_HOST_VAR}`](https://code.visualstudio.com/remote/advancedcontainers/environment-variables). 51 | 52 | #### 1.2.2 Configuring tasks 53 | 54 | The contents of `.vscode` depend on the programming language and the additional plug-ins you want to use, e.g. for Linting/static code analysis. One can configure for example tasks that can be executed with key shortcuts. 55 | 56 | Furthermore you can add a `tasks.json` that defines certain useful tasks that VS Code can run. My configurations for ROS and ROS 2 can be found in the corresponding folders [`/templates/ros/.vscode/tasks.json`](../templates/ros/.vscode/tasks.json) as well as [`/templates/ros2/.vscode/tasks.json`](../templates/ros2/.vscode/tasks.json). I configure tasks for importing repositories with [`vcs`](https://github.com/dirk-thomas/vcstool), installing dependencies with `rosdep`, building a workspace with `catkin` or `colcon`, running tests and finally cleaning the workspace. 57 | 58 | You can run these tasks by selecting `Terminal/Run Tasks...` and then selecting the desired task. This will open a subterminal and run this task in the corresponding subterminal. 59 | 60 | | ![Run tasks](../media/visual_studio_code_terminal_tasks.png) | ![Tasks list](../media/visual_studio_code_terminal_tasks_list.png) | 61 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 62 | 63 | ### 1.3 Usage 64 | 65 | After opening Visual Studio Code you can open the repository with **`File/Open Folder`**. When asked if you want to **`Reopen in container`** (see the left screenshot below) confirm. If this dialog does not appear click on the green symbol on the very left bottom of your window and select `Remote containers: Reopen in container` from the top center as shown in the bottom right picture). Depending on how many layers the Docker has, if they are already pre-cached and how good your internet connection is, it might take seconds or minutes to prepare your container for you. 66 | 67 | | ![](../media/visual_studio_code_dev_containers_on_start.png) | ![](../media/visual_studio_code_dev_containers_reopen_in_container.png) | 68 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 69 | 70 | In case you are terminated with the error message "Current user does not have permission to run 'docker'. Try adding the user to the 'docker' group." follow the advice given [here](https://stackoverflow.com/questions/57840395/permission-issue-using-remote-development-extension-to-attach-to-a-docker-image). Open a new terminal on your host machine, enter `$ sudo usermod -aG docker $USER`, reboot and then retry opening the container inside Visual Studio Code. 71 | 72 | As soon as you have entered the Docker you should be greeted by a terminal inside it and the green icon on the bottom left should state **`Dev Container`**. You can open a new terminal by selecting **`Terminal/New Terminal`** any time. You can now browse the Docker container just like a regular terminal and access the folders inside it as if they were on the host system (see the screenshot below). 73 | 74 | ![Visual Studio Code terminal inside the container](../media/visual_studio_code_dev_containers_terminal.png) 75 | 76 | In case you want to rebuild the image press **`Ctrl` + `Shift` + `P`**, type Rebuild and then select either **`DevContainers: Rebuild`** or `DevContainers: Rebuild without Cache`. Former will rebuild the image re-using existing layers while the latter will discard all the existing layers and rebuild the image from scratch. 77 | 78 | ### 1.4 Debugging 79 | 80 | It might happen that the Visual Studio Code integration might terminate and does not output much useful information. This might be the case if you are asking it to run a container with the `nvidia-container-runtime` but it is not installed on your system or your `devcontainer.json` mentions the wrong service and/or workspace. Similarly it happened in the past that the Visual Studio Code extension was not compatible with Docker itself. In this case you might have to up- or downgrade the Docker version you are using (see e.g. [here](https://github.com/microsoft/vscode-remote-release/issues/7958)). In case this emerges it is worth **checking the [VSC remote container issues on Github](https://github.com/microsoft/vscode-remote-release/issues)** and trying to **build your image without cache** as described in the section above. If all of this does not work it can be helpful to go back to the **Docker command line commands** and launch them manually to see if there are any issues with the Docker engine itself. 81 | -------------------------------------------------------------------------------- /doc/Windows.md: -------------------------------------------------------------------------------- 1 | # Docker on Windows 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2024) 4 | 5 | 6 | 7 | ## 0. Overview 8 | 9 | Docker can also be installed on Windows (with a WSL 2 backend) as is described in more detail [here](https://docs.docker.com/desktop/install/windows-install/). After installing Docker you can use the `docker` as well as `docker compose` commands from within PowerShell. Currently this standard approach does not allow you though to stream graphic user interfaces to the host system while using WSL directly does. 10 | 11 | [Since Windows 10 Build 19044+ or Windows 11 (January 2024) **Windows Subsystem for Linux 2 (WSL2)** supports Linux GUI applications](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps). This enables us to use Docker in the same way as we do on Ubuntu including our **graphic user interfaces**. If you want to check if your operating system supports it, check the version of your operating system as discussed [here](https://support.microsoft.com/en-us/windows/which-version-of-windows-operating-system-am-i-running-628bec99-476a-2c13-5296-9dd081cdd808). Potentially you will have to follow the following steps to [update](https://support.microsoft.com/en-us/windows/get-the-latest-windows-update-7d20e88c-0568-483a-37bc-c3885390d212) (Windows 10 to the corresponding build version) or [upgrade your operating system](https://support.microsoft.com/en-us/windows/upgrade-to-windows-10-faq-cce52341-7943-594e-72ce-e1cf00382445) (to either Windows 10 or 11). The following paragraphs describe how your Windows 10 or 11 system can then be configured so that you can use graphic user interfaces in the same way as on a Ubuntu system. 12 | 13 | As hardware (such as network interfaces) has to be shared between the Windows and the Linux subsystem WSL makes heavy use of virtualization that differs in between WSL and WSL 2 as discussed [here](https://learn.microsoft.com/en-us/windows/wsl/faq#can-wsl-2-use-networking-applications-). This can lead to **problems with hardware** such as e.g. [here](https://github.com/OpenEtherCATsociety/SOEM/issues/630). This makes WSL not very favourable for development or deployment (for ROS 2 it might be better to install it on the host system directly as described [here](https://docs.ros.org/en/humble/Installation/Windows-Install-Binary.html) and run at least the nodes that interface the hardware on the operating system without a container). In my opinion the main use cases for Docker on Windows are therefore the following: 14 | 15 | - **Getting started with robotics**: You do not have a Linux system but want to try ROS on your system. WSL allows you to work with ROS as well as ROS 2 at least in **simulation**. 16 | - **Data sharing**: You might need to interact with clients, partner companies and share holders that are either not familiar with Linux or are not allowed to use Linux due to security restructions (most companies strangely enough still allow WSL to be used though). They can then either work in simulation or from recorded ROS bag data. 17 | 18 | ![Docker on Windows](../media/windows10_rviz.png) 19 | 20 | ## 1. Windows Subsystem for Linux (WSL) Configuration 21 | 22 | The following paragraph will quickly walk you through the installation of [Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/install) as well as the [Windows Subsystem for Linux GUI (WSLg) extension](https://github.com/microsoft/wslg). The basic steps are listed [here](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) but I will elaborate them in more detail. First of all follow the steps to install WSL as outlined [here](https://learn.microsoft.com/en-us/windows/wsl/install). This basically involves opening a PowerShell and either typing `$ wsl --install` or 23 | 24 | ```powershell 25 | $ wsl --install -d Ubuntu 26 | ``` 27 | 28 | where the distribution `Ubuntu` can be replaced by any of the choices given by `$ wsl --list --online`. 29 | 30 | If you already had WSL installed you might need to update it as follows: 31 | 32 | ```powershell 33 | $ wsl --update 34 | $ wsl --shutdown 35 | ``` 36 | 37 | In the PowerShell check the version of WSL of your subsystem. There are two versions `1` and `2` which are different in a few relevant aspects (as discussed e.g. [here](https://learn.microsoft.com/en-gb/windows/wsl/compare-versions)). Make sure your subsystem is running **version 2** and switch as follows if necessary: 38 | 39 | ```powershell 40 | $ wsl -l -v 41 | NAME STATE VERSION 42 | * Ubuntu Running 1 43 | $ wsl —set-version Ubuntu 2 44 | For information on key differences with WSL 2 please visit https://aka.ms/wsl2 45 | Conversion in progress, this may take a few minutes... 46 | The operation completed successfully. 47 | ``` 48 | 49 | You can then open the Windows Subsystem for Linux by searching for **WSL** or Ubuntu inside the installed programs and running it. This will open a terminal that can be used like any other **Linux terminal**. 50 | 51 | Inside WSL check the `DISPLAY` variable: 52 | 53 | ```bash 54 | $ echo $DISPLAY 55 | :0 56 | ``` 57 | 58 | It should be set to `:0`. If it is not, make sure that you are using WSL 2 as discussed above and follow the debugging guide [here](https://github.com/microsoft/wslg/wiki/Diagnosing-%22cannot-open-display%22-type-issues-with-WSLg). 59 | 60 | Proceed to install and run any GUI-based program such as `gedit`: 61 | 62 | ```bash 63 | $ sudo apt install gedit 64 | $ gedit 65 | ``` 66 | 67 | This should bring up the graphic user interface on your host system. 68 | 69 | ### 1.1 Hardware acceleration 70 | 71 | Make sure you have graphics drivers for your graphics card installed. This is not strictly necessary but is useful for hardware acceleration (e.g. OpenGL). The Nvidia drivers can be downloaded [here](https://www.nvidia.com/Download/index.aspx?lang=en-us) by selecting your graphics card and the operating system. To see if the hardware acceleration is working in WSL, launch WSL and make sure that `$ nvidia-smi` detects your graphics card. 72 | 73 | ## 2. Running Docker with graphic user interfaces inside WSL 2 74 | 75 | **Graphic user interfaces in WSL 2 then work in the very same way as on Linux operating systems.** Follow the installation of Docker and Docker-Compose as discussed in [`Introduction.md`](./Introduction.md) as well as the set-up for graphic user interfaces in [`Gui.md`](./Gui.md), including the Nvidia container toolkit in case you want to run hardware acceleration. You can then use the regular `docker` and `docker compose` commands inside the WSL in combination with the templates found in [`templates/`](../templates). 76 | 77 | In the figure below you can see the output of running the [Affordance Templates workspace example](../examples/affordance-templates-ros-docker) on a Windows 10 operating system. For this purpose just clone this repository inside the subsystem for Linux 78 | 79 | ```bash 80 | $ git clone https://github.com/2b-t/docker-for-robotics.git 81 | $ cd docker-for-robotics/examples/affordance-templates-ros-docker 82 | $ docker compose -f docker/docker-compose-gui.yml up 83 | ``` 84 | 85 | Then open another terminal and attach to the container with 86 | 87 | ```bash 88 | $ docker exec -it affordance_templates bash 89 | ``` 90 | 91 | and there continue to build the workspace and run the main launch file of this example as discussed [here](../examples/affordance-templates-ros-docker/ReadMe.md). 92 | 93 | ![Docker on Windows](../media/windows10_affordance_templates.png) 94 | -------------------------------------------------------------------------------- /doc/WorkingWithHardware.md: -------------------------------------------------------------------------------- 1 | # Accessing hardware inside a container 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2023) 4 | 5 | 6 | 7 | ## 1. Working with hardware 8 | 9 | When working with **hardware that use the network interface** such as EtherCAT slaves one might have to **share the network** with the host or remap the individual ports manually. One can automate the generation of the entries in the `/etc/hosts` file inside the container as follows: 10 | 11 | ```yaml 12 | 9 network_mode: "host" 13 | 10 extra_hosts: 14 | 11 - "${REMOTE_HOSTNAME}:${REMOTE_IP}" 15 | ``` 16 | 17 | In this case the two environment variables are defined inside a `.env` file that is automatically passed to Docker Compose. 18 | 19 | When sharing **external devices** such as USB devices one will have to **share the `/dev` directory** with the host system as well as use [**device whitelisting**](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/sec-devices) as follows (for some applications Docker's [`--device`](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities) flag might be sufficient). An overview over the IDs of the Linux allocated devices can be found [here](https://www.kernel.org/doc/html/v4.15/admin-guide/devices.html). You will have to specify the [Linux device drivers major and minor number](https://www.oreilly.com/library/view/linux-device-drivers/0596000081/ch03s02.html). Inserting a `*` will give it access to all major/minor numbers. See e.g. what this would look like for the Intel Realsense depth cameras: 20 | 21 | ```yaml 22 | 9 volumes: 23 | 10 - /dev:/dev 24 | 11 device_cgroup_rules: 25 | 12 - 'c 81:* rmw' 26 | 13 - 'c 189:* rmw' 27 | ``` 28 | 29 | The association of these numbers and the devices is given in [`/proc/devices`](https://unix.stackexchange.com/questions/198950/how-to-get-a-list-of-major-number-driver-associations). 30 | 31 | You might also selectively mount only some USB devices: 32 | 33 | ```yaml 34 | 9 volumes: 35 | 10 - /dev/some_device:/dev/some_device 36 | 11 - /dev/another_device:/dev/another_device 37 | ``` 38 | 39 | In case you are not quite sure which group a device belongs to you might also run the container with extended privileges as [**`privileged`**](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities). Note that this is in **generally not recommended** as this basically removes all types of isolation and as such might pose a security risk in particular when being `root` inside the container. In some rare cases this can't be avoided though (e.g. in the case of a Realsense camera with IMU that currently needs [write access to `/sys` which is not possible in an unprivileged container](https://forums.docker.com/t/unable-to-mount-sys-inside-the-container-with-rw-access-in-unprivileged-mode/97043)). 40 | 41 | ### 1.1 Determining `device_cgroup_rules` for connected devices 42 | 43 | If we have no idea what `device_cgroup_rules` we might need for a particular device but we have the device at hand we might do the following to find out. 44 | 45 | In Linux differentiates between **busses** (the busses on the motherboard that a device is attached to, e.g. the output of `$ lsusb`) and **device files** (located inside `/dev` that are used to abstract standard devices and communicate with the corresponding physical or virtual devices). Depending on the type of the data that is exchange one differentiates between block `b` and character `c` devices (for more information see e.g. [here](https://www.baeldung.com/linux/dev-directory)). For the busses there exist readily available tools like `lsusb` that are able to translate the vendor and product codes into human-readable strings while I am not aware of such a tool for device files. 46 | 47 | So in order for finding out which device files (and as a consequence which device drivers major and minor numbers) belong to a device, you either have to plug the device in an out comparing the changes in device files or find out which device files belong to which bus. 48 | 49 | #### 1.1.1 Manually unplugging devices 50 | 51 | The easier way (that also works in some corner cases like virtual devices) is to simply read all devices files, plug the device in or out and read again all devices files and compare them to the ones prior: 52 | 53 | ```bash 54 | $ ls -l /dev > before.txt # After this command plug the device in 55 | $ ls -l /dev > after.txt 56 | $ diff before.txt after.txt 57 | ... 58 | crw-rw---- 1 root dialout 188, 0 Feb 4 16:00 ttyUSB0 59 | ... 60 | ``` 61 | 62 | This outputs directly the major (in this case 188) and minor (in this case 0) device driver numbers (in this case for a [Life Performance Research LPMS-IG1 IMU](https://www.lp-research.com/9-axis-imu-with-gps-receiver-series/)). 63 | 64 | Sometimes you can already guess from the given date which of the device files belong to your device. 65 | 66 | This means I will add a `device_cgroup_rule` that looks as follows: 67 | 68 | ```yaml 69 | 9 volumes: 70 | 10 - /dev:/dev 71 | 11 device_cgroup_rules: 72 | 12 - 'c 188:* rmw' 73 | ``` 74 | 75 | Do not consider the minor version as it might change depending on what other devices are connected. 76 | 77 | #### 1.2.1 Through `lsusb` 78 | 79 | Another way of doing so is to connect the information from `lsusb` to the device file using the vendor and product information. There are a couple of ways to associate a given device and its `/dev` path. 80 | 81 | The probably easiest way is to simply run [the following script](https://unix.stackexchange.com/a/144735) 82 | 83 | ```bash 84 | #!/bin/bash 85 | 86 | for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do 87 | ( 88 | syspath="${sysdevpath%/dev}" 89 | devname="$(udevadm info -q name -p $syspath)" 90 | [[ "$devname" == "bus/"* ]] && exit 91 | eval "$(udevadm info -q property --export -p $syspath)" 92 | [[ -z "$ID_SERIAL" ]] && exit 93 | echo "/dev/$devname - $ID_SERIAL" 94 | ) 95 | done 96 | ``` 97 | 98 | This should already output something like 99 | 100 | ```bash 101 | ... 102 | /dev/ttyUSB0 - Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_IG1232600680056 103 | ... 104 | ``` 105 | 106 | I normally do [the following](https://unix.stackexchange.com/questions/81754/how-to-match-a-ttyusbx-device-to-a-usb-serial-device) manually: I first check the connected devices with `lsusb`, potentially unplugging and plugging it in again to see which is which: 107 | 108 | ```bash 109 | $ lsusb -tvv 110 | ... 111 | /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/15p, 480M 112 | ID 1d6b:0002 Linux Foundation 2.0 root hub 113 | /sys/bus/usb/devices/usb3 /dev/bus/usb/003/001 114 | |__ Port 5: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M 115 | ID 17aa:1034 116 | /sys/bus/usb/devices/3-5 /dev/bus/usb/003/002 117 | |__ Port 4: Dev 8, If 0, Class=Vendor Specific Class, Driver=cp210x, 12M 118 | ID 10c4:ea60 Silicon Labs CP210x UART Bridge 119 | /sys/bus/usb/devices/3-5.4 /dev/bus/usb/003/008 120 | ... 121 | ``` 122 | 123 | You might be interested in more details about the device `$ lsusb -d 10c4:ea60 -v`. 124 | 125 | To see which `/dev` path is associated with it I will check the output of: 126 | 127 | ```bash 128 | $ ls -l /sys/bus/usb-serial/devices # And /sys/bus/usb/devices 129 | total 0 130 | lrwxrwxrwx 1 root root 0 Feb 4 16:00 ttyUSB0 -> ../../../devices/pci0000:00/0000:00:14.0/usb3/3-5/3-5.4/3-5.4:1.0/ttyUSB0 131 | $ grep PRODUCT= /sys/bus/usb-serial/devices/ttyUSB0/../uevent 132 | PRODUCT=10c4/ea60/100 133 | ``` 134 | 135 | This means that `ttyUSB0` is assocated to `10c4:ea60` which is the device we are looking for. 136 | 137 | Now I will check the associated major and minor number with: 138 | 139 | ```bash 140 | $ ls -l /dev 141 | ... 142 | crw-rw---- 1 root dialout 188, 0 Feb 4 16:00 ttyUSB0 143 | ... 144 | ``` 145 | 146 | In my case major `188`, minor `0` for `ttyUSB0`, which is my device `10c4:ea60`. Then proceed to add the major number to your `docker-compose.yml` like outlined above. 147 | 148 | ## 2. Storage devices 149 | 150 | For mounting storage devices such as USBs and external hard drives it is sufficient to **mount `/media` or one of its specific subfolders as a volume**: 151 | 152 | ```yaml 153 | 9 volumes: 154 | 10 - /media:/media 155 | ``` 156 | -------------------------------------------------------------------------------- /doc/AdvancedTopics.md: -------------------------------------------------------------------------------- 1 | # Advanced topics 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2024) 4 | 5 | 6 | 7 | ## Overview 8 | 9 | If you have followed this guide so far, then you should have understood the basics of Docker. There are still some topics I would like to discuss that might be helpful. This section links to the corresponding external documentation or accompanying documents. 10 | 11 | ## 1. Setting up Visual Studio Code 12 | 13 | In the last few years [Microsoft Visual Studio Code has become the most used editor](https://insights.stackoverflow.com/survey/2021), becoming the first Microsoft product to be widely accepted by programmers (which is quite remarkable as they have a history of developing toolchains highly criticized by developers :). The guide [`VisualStudioCodeSetup.md`](./VisualStudioCodeSetup.md) walks you through the set-up of a Docker with Visual Studio Code. 14 | 15 | ## 2. Graphic user interfaces 16 | 17 | As pointed out earlier Docker was never intended for graphic user interfaces and integrating them is slightly tricky as graphic user-interfaces are not part of the kernel but that does not mean that it can't be done. Graphic user interfaces are particularly vital when developing with ROS. The main disadvantage of graphic user interfaces with Docker is though that there is no real portable way of doing so. It highly depends on the operating system that you are using and the manufacturer of your graphics card. The document [`Gui.md`](./Gui.md) discusses a simple way of doing so for Linux operating systems. 18 | 19 | ## 3. ROS inside Docker 20 | 21 | Working with the Robot Operating System (ROS) or its successor ROS 2 might pose particular challenges, such as working with hardware and network discovery of other nodes. I have written down some notes of how I generally structure my Dockers in [`Ros.md`](./Ros.md). In particular this is concerned with working with hardware, multiple machines and time synchronization between them. 22 | 23 | ## 4. Docker on Windows 24 | 25 | Docker as a technology builds on the Linux operating system but can be run on other operating systems as well with a lightweight virtual machine in between. An interesting option is running it on Windows with WSL 2 which allows you also to visualize graphic user interfaces. This is discussed in more detail in [`Windows.md`](./Windows.md). 26 | 27 | ## 5. Users and safety 28 | 29 | A few problems emerge with user rights and shared volumes when working from a Docker as discussed [in this Stackoverflow post](https://stackoverflow.com/questions/68155641/should-i-run-things-inside-a-docker-container-as-non-root-for-safety) and in more detail [in this blog post](https://jtreminio.com/blog/running-docker-containers-as-current-host-user/). In particular it might be that the container might not be able to write to the shared volume or vice versa the host user can only delete folders created by the Docker user when being a super-user. As outlined in the latter, there are ways to work around this, passing the current user id and group as input arguments to the container. In analogy with Docker-Compose one might default to the root user or change to the current user if [arguments are supplied](https://stackoverflow.com/questions/34322631/how-to-pass-arguments-within-docker-compose). 30 | 31 | I personally use Dockers in particular for developing and I am not too bothered about being super-user inside the container. If you are, and depending on your use case you should be (in particular for security reasons), then have a look at the linked posts as well as the [Visual Studio Code guide on this](https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user). 32 | 33 | What I generally do is use the **environment variables `${USER}` or `${USERNAME}`**, if provided or else assume reasonable default values, pass them into the container as arguments. Most users will have a user id and a group id corresponding to `1000` as these values are given to the first user account. 34 | 35 | ```yaml 36 | version: "3.9" 37 | services: 38 | ros2_docker: 39 | build: 40 | context: .. 41 | dockerfile: docker/Dockerfile 42 | args: 43 | - USERNAME=${USERNAME:-developer} 44 | - UID=1000 45 | - GID=1000 46 | ``` 47 | 48 | and then create a corresponding user inside the Docker 49 | 50 | ```dockerfile 51 | RUN apt-get update \ 52 | && apt-get install -y \ 53 | sudo \ 54 | && rm -rf /var/lib/apt/lists/* 55 | RUN addgroup --gid ${GID} ${USERNAME} \ 56 | && adduser --disabled-password --gecos '' --uid ${GID} --gid ${GID} ${USERNAME} \ 57 | && echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} \ 58 | && chown -R ${UID}:${GID} /home/${USERNAME} 59 | 60 | USER ${USERNAME} 61 | ``` 62 | 63 | This results in the same user being used inside the Docker than on a Linux-based host system. 64 | 65 | You can also put the values for `UID` and `GID` into the environment file so that the user can modify them easily. 66 | 67 | ## 6. Multi-stage builds 68 | 69 | Another interesting topic for **slimming down the resulting containers** as mentioned before are [multi-stage builds](https://docs.docker.com/build/building/multi-stage/) where only the files necessary for running are kept and every unnecessary ballast is removed. It is one of those things that you might have a look at when trying to mastering [Docker best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/). 70 | 71 | What I generally use multi-stage builds for is stopping at a specific build stage. Inside my Dockerfile I have a base image for the basic ROS set-up as well as a developer image that adds developer tools on top of it: 72 | 73 | ```dockerfile 74 | ############## 75 | # Base image # 76 | ############## 77 | FROM ros:humble-ros-base as base 78 | 79 | # Here I install my basic packages, ROS packages and set up the middleware 80 | 81 | ##################### 82 | # Development image # 83 | ##################### 84 | FROM base as dev 85 | 86 | # Here I install developer tools for monitoring and visualization as well as create users 87 | ``` 88 | 89 | Then inside my `docker-compose` file I can stop either at the `base` or the `dev` stage as follows: 90 | 91 | ```yaml 92 | version: "3.9" 93 | services: 94 | ros2_docker: 95 | build: 96 | context: .. 97 | dockerfile: docker/Dockerfile 98 | target: dev 99 | ``` 100 | 101 | ## 7. Real-time code 102 | 103 | As mentioned another point that is often not discussed is what steps are necessary for running real-time code from inside a Docker. As outlined in [this IBM research report](https://domino.research.ibm.com/library/cyberdig.nsf/papers/0929052195DD819C85257D2300681E7B/$File/rc25482.pdf), the impact of Docker on the performance can be very low if launched with the correct options. After all you are using the kernel of the host system and the same scheduler. I have discussed this also in more detail in a [dedicated repository](https://github.com/2b-t/docker-realtime), in particular focussing on `PREEMPT_RT` which is likely the most relevant for robotics. 104 | 105 | ## 8. Deployment 106 | 107 | One might develop inside a container by mounting all necessary directories into the container. For simplicity one might be `root` inside the container. When deploying a container commonly a dedicated release image named e.g. `Dockerfile.release` will be created. This container might use the development image and instead of mounting the corresponding source code into the container the **required dependencies will be installed from Debian packages**. Ideally we have a CI-pipeline that produces these Debian packages (e.g. a Github Action in each repository such as [this](https://github.com/arkane-systems/apt-repo-update)) and another CI-pipeline that pushes the development image to our Docker registry (e.g. for Github Actions see [here](https://docs.github.com/en/actions/publishing-packages/publishing-docker-images)). Both of these can then trigger the generation of the release Dockerfile located in a different repository (e.g. for Github Actions see [here](https://github.com/marketplace/actions/trigger-external-workflow)). Additionally we will use another non-root user inside the Docker. 108 | 109 | ```dockerfile 110 | # We start from the development image or from the base stage if using multi-stage builds 111 | FROM some_user/some_repo:devel 112 | 113 | # We will install now packages as Debians instead of mounting the source code 114 | RUN echo "deb http://packages.awesome-robot.org/robot/ubuntu focal main" > /etc/apt/sources.list.d/awesome-latest.list 115 | RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 00000000000000000000000000000000 116 | RUN apt-get update \ 117 | && apt-get install -y --no-install-recommends \ 118 | some-awesome-robot-full=1.0.0 \ 119 | && rm -rf /var/lib/apt/lists/* 120 | 121 | # Set-up a new user without password inside the Docker (see also the dedicated section above) 122 | ARG USERNAME=some_user 123 | ARG UID=1000 124 | ARG GID=1000 125 | 126 | RUN apt-get update \ 127 | && apt-get install -y \ 128 | sudo \ 129 | && rm -rf /var/lib/apt/lists/* 130 | RUN addgroup --gid ${GID} ${USERNAME} \ 131 | && adduser --disabled-password --gecos '' --uid ${GID} --gid ${GID} ${USERNAME} \ 132 | && chown -R ${UID}:${GID} /home/${USERNAME} 133 | 134 | USER ${USERNAME} 135 | 136 | # Entrypoint script sources our workspace and launch the main launch file 137 | ENTRYPOINT["entrypoint.sh"] 138 | ``` 139 | 140 | -------------------------------------------------------------------------------- /doc/Motivation.md: -------------------------------------------------------------------------------- 1 | # Motivation 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2023) 4 | 5 | 6 | 7 | ## 1. Overview 8 | 9 | When I (as a robotics developer) tell people that none of my computers have ROS installed on them, at least not on the host system, I mostly get puzzled looks. But **using Docker as an isolated development environment is a strategy that is shared by most leading companies and research institutions in robotics**. First and foremost we have **PickNik robotics** (they have customers including Google, Amazon, Samsung, Intel and NASA), a consulting agency for robotics that employs arguably some of the most brilliant and respected robotics engineers, that recommend using Docker for development as well as deployment as [outlined in this presentation of theirs](https://picknik.ai/ros/robotics/docker/2021/07/20/Vatan-Aksoy-Tezer-Docker.html). **Open Robotics** (OSRF), the main driver behind ROS has been using Docker as the backbone of their [build infrastructure](https://github.com/ros-infrastructure/ros_buildfarm) almost ever since Docker came out in 2013. They also provide the [official ROS images on Dockerhub](https://github.com/osrf/docker_images) as well as tools such as [Rocker](https://github.com/osrf/rocker) for working with graphic user interfaces from inside a Docker in a portable way. The ROS Industrial industrial training uses Docker in certain parts of its tutorials such as for [cloud computing](https://industrial-training-master.readthedocs.io/en/melodic/_source/session6/Docker-AWS.html). [Pal Robotics](https://github.com/pal-robotics/pal_docker_utils) and [Stogl robotics](https://rtw.stoglrobotics.de/master/docker/index.html) offer utilities for developing robotic applications with Docker. Furthermore you will find workflows and tools for leading research Institutions like [**Fraunhofer IPA**](https://github.com/ct2034/dockeros), [**DFKI**](https://github.com/dfki-ric/docker_image_development), **IIT** [[1]](https://github.com/diegoferigo/development-iit) [[2]](https://github.com/diegoferigo/ros-kubernetes), [**INRIA**](https://gitlab.inria.fr/locolearn/public/docker_inria_wbc) and [**MIT CSAIL**](https://roboticseabass.com/2021/04/21/docker-and-ros/) online. And finally leading companies like **Boston Dynamics** [[3]](https://dev.bostondynamics.com/docs/payload/docker_containers#) [[4]](https://dev.bostondynamics.com/docs/payload/spot_core_portainer) and [**Sony**](https://github.com/fujitatomoya/ros_k8s) use it for deployment on commercial products. 10 | 11 | Over the last couple of years I have collaborated professionally with different companies and robotics research institutions and met quite a lot of people that would not understand the benefits or even worse would oppose the technology per se without actually having used it. But I managed convince most people so far to give it a go and they immediately see the advantages of Docker for robotics and implement it in their workflow as well. I have not yet quite understood why Docker as a technology has such a negative connotation. Maybe it is simply a lack of understanding (people have tried it and have failed in one way or the other), maybe this is historically grown. Anyways, my goal of this guide is to show best practices that I have found over the last couple of years (working with Docker for robotic software development and by examing workflows of people I worked with or what I could find online). In my opinion Docker as a technology is essential for developing robotics in an efficient and reliable manner. 12 | 13 | As said I do not have ROS installed on my development computers and do not plan to do so. Instead of running a **vanilla system with Docker and my Visual Studio Code IDE installed**. There are a few tools for power management and networking installed on my host machine but all project related-code is put inside a Docker. **Every single workspace has its own dedicated Docker**, I have Dockers for testing particular sensors and robot stacks, some in ROS1, others in ROS2, that all can be run on my host system (currently Ubuntu 22.04). This way I can continue to keep up with the most recent host system and might revive an old retired project at any point (e.g. I have used it to test [traclabs' Affordance Templates stack](https://traclabs.com/projects/affordance-templates/) for ROS Indigo) or try a different distribution. If I need a new container that uses this sensor or robot I either copy the relevant parts from the corresponding Dockerfile or I leverage multi-layer builds to generate the new image starting from the sensor and robot images. Furthermore I might [overlay different workspaces on top of each other](http://wiki.ros.org/catkin/Tutorials/workspace_overlaying) or orchestrate multiple workspaces with Docker-Compose. 14 | 15 | 16 | 17 | ## 2. Why should I use Docker when developing robotics software? 18 | 19 | - **Compatability**: 20 | - Working with robots in ROS generally requires working with **different Ubuntu distributions**. With Docker one can avoid having multiple partitions on the same system and instead **start different distributions from the same host system**. This way for example a ROS Indigo stack can still be run on a Ubuntu 22.04. This is very important as sooner or later robotic stacks have to be retired as they are not state-of-the-art anymore (sensors change, ROS gets replaced by ROS2) but nonetheless one should still be able to run this legacy code without having a legacy computer for every single distribution laying around. 21 | - Furthermore you can have a **non-Debian-based Linux host system** and nonetheless work with ROS if you prefer another Linux distribution over Ubuntu as your daily driver, yet have the convenience of working with Ubuntu when dealing with ROS. 22 | - **Replicability**: 23 | - Robotic stacks often involve a large amount of packages. A single person often won't accomplish much if the application is complex and/or should be deployed commercially. **Multiple people** working on the same workspace should have an **identical set-up with the same software versions**. At the same time each contributor should have a central point were IPs and other parameters can be modified (which do not have to be commited to the common repository everybody is working on together). 24 | - Working with **multiple robotic stacks** even on the same Ubuntu distribution often requires working with **different versions of the same library** for different projects. With Docker this is no issue. One can further perform version pinning, meaning enforce a certain version of a package to increase replicability on another computer. 25 | - As software engineers and researcher develop on a machine they will install an immense amount of software that often is not needed at all but is never uninstalled when not needed anymore. Even an experienced programmer under stress will simply search for a solution on Stackoverflow, take the post with the most upvotes - even if they do not fully understand it - and give it a go. This means no developers system is actually clean, most of them actually contain a lot of useless garbage that gets worse and worse over time. This useless software might impact other code, that might break it or is required to install other packages without the developer knowing, or is incompatible with other packages or certain versions. Working without a fresh system means always carrying this installation history across projects. This leads to situation where code compiles on one computer but does not compile for another person with a slightly different set-up ("But it compiles on my computer..."-situations). From my experience most of the time the reason for these situations are **implicit dependencies and restrictions** that the developer is not aware of and not the fault of the person trying to replicate the set-up. Therefore you as a programmer (or researcher) should be interested in using technologies such as Docker: After all it is your responsability to make your software project and research as replicable as possible, and isolate any previous modifications from your current project. 26 | - **Isolation**: 27 | - Working with different robotic stacks generally also means working on **different networks**. This means robotic developers will generally add new robots they need to communicate with inside their **`/etc/hosts`** configuration. This might lead to collision of IPs and results in different entries having to be commented or uncommented in order to be able to work with a particular robot. Similarly most people add certain definitions and aliases inside their **`.bashrc`** that they will comment and uncomment depending on the project they are currently working on. This is very inconvenient, cumbersome and error-prone. When working with a Docker these **configuration files are specific to a project** and do not leak into workspaces of other robots. 28 | - This isolation can also be very useful for parallelizing simulations. With Docker multiple ROS cores can be run in parallel on the same host system by letting each container have its own network and not exposing it to the other containers. 29 | - **Continuous integration**: Docker is an essential building stone of most continuous integration pipelines. Maintaining a description of the environment that code should be run in is essential for testing your code on a remote server. 30 | - **Fast deployment**: Instead of installing your code from source on a system, installing multiple Debian packages and configuring the network manually you can encapsulate all this in a Docker container and deploy the Docker container as a whole or orchestrate multiple Docker containers (e.g. one container for each node or group of nodes) on the same computer. This means that deploying might only reduce to pulling a single Docker image with the size of a couple of dozen megabytes. 31 | 32 | As guarantueeing these characteristics without the use of Docker is close to impossible, there are many companies and institutions where a robotic software stack only runs only on a particular computer. Nobody is allowed to touch (or at least make significant changes to) that system as if it breaks that robotic system would be rendered useless (or at least inoperable for some time). In my opinion such thing should never happen and is a strategic failure per se. Any robot should be replicable just from a set-up that can be found online in your version control system in a semi-automated fashion without having to go through a long manual set-up routine. A pipeline based on Docker can help with that. **Even if you do not deploy a robot with Docker you should maintain one as a back-up solution** because you never know, it is software. 33 | 34 | ## 3. Why is Docker important in particular for academic and research institutions? 35 | 36 | In particular research institutions are in desperate need for container-based solutions such as Docker - even more than companies in my opinion: 37 | 38 | A company usually is made of a **stable** workforce of **experienced** engineers that work together on a **few** homogeneous products. Any decent company will work towards **common tools** and will have **mechanisms** in place that should **guarantee code quality**. These products will be maintained until they reach their lifecycle after several year and are either retired or replaced, resulting in an overall small variability. 39 | 40 | Academic and research institutions are the complete opposite: Workers and students generally are **fluctuating**, might be motivated and brilliant but are at a start of their career, generally **lacking the experience** and might have very interdisciplinary backgrounds (which is in particular true for robotics where people might come from software, mechanical, electrical or biomedical engineering or might have an even more interdisciplinary background). Furthermore there are close to **no mechanisms in place that guarantee code quality**. The tools the students and research engineers will use are very **heterogeneous**. A large part of the developed code will **not be actively maintained** for an extended period as there are no resources for doing so after a project (and funding) ends. At a certain point projects have to be **retired** nonetheless they should be left **in a replicable state**. Many universities and research institutions fail to have mechanisms in place that help with this. I have already seen many projects die because the main developer left not only taking with themselves the know-how but also any chance of replicating his/her work as the code only worked on their machine. This is a fatal loss for any institution in my opinion as they lost the know-how and significantly reduced their chance of replicating the work (which means after all filling the gap and continuing in that research direction). Many research institutions I had to deal with suffer from a significant slow down due to this which significantly slows down their daily business and growth. 41 | 42 | If you start on a new project it is incredibly frustrating to take over a complex robotic project from somebody that lacks documentation. Even if you have access to their working computer you will likely have to modify their `.bashrc` and network set-up. If you further have to start over with another computer you will have to search for dependencies, fiddling with different versions of libraries and implicit undocumented dependencies. This **slows down and demotivates**. This is particularly true for Bachelor and Master students that are only with these institutions for a limited amount of time. Some might have certain constraints and want to finish their work in a certain limited time frame. This means if you are not able to get them started quickly with a project they will not only lose motivation but also lose valuable time that they could do on research for fixing set-up problems that are structural and actually none of their business. PhD students in robotics might have different backgrounds and might not be familiar with best-practices. Generally they leave after some time without anybody having a complete overview of what they did: After all their supervisor is mainly interested in the scientific output and might not have the time to have a look in detail at the state of the documentation. It is essential to familiarize them with a standard workflow that allows to replicate their work. After all one of the core idea of any research is making findings **replicable** and not only making findings. This is in particular important for medical research where [paradoxically most research findings are actually false](https://journals.plos.org/plosmedicine/article?id=10.1371/journal.pmed.0020124)! 43 | 44 | After all the time effort for setting up and maintaining a Docker is not bigger than installing the libraries by hand but it only works if you immediately introduce your students and junior researchers to these technologies and not only in the middle or towards the end of the project (nobody remembers what they installed half a year, let alone three or four years ago). Furthermore Docker allows you to reset quickly, go back to a previous state. This quickly pays off in particular if more than a single computer has to be used. And the gained time can be spent on research. 45 | 46 | Building this infrastructure and workflows also as an academic institution is a long-term investment, of similar importance to building frameworks rather than single purpose code for a project. 47 | 48 | 49 | 50 | ## 4. What are the drawbacks of Docker? 51 | 52 | For robotics **software development I do not see any drawbacks with using Docker**. After all Docker is a mature technology that is used successfully in many other fields. From my experience there are many prejudices surrounding Docker as a technology but graphic user interfaces, real-time capable code, working with hardware can all be worked around in a reliable and portable manner. This guide will explain how this can be done. 53 | 54 | The only messy thing that one has to watch out for is actually user rights. Giving root privileges to a Docker user is probably not a good idea if you deploy the container, as an intruder might gain access to the host system in particular when running a container as `privileged`. On the other hand using another user might result in problems when sharing volumes as pointed out later on. 55 | -------------------------------------------------------------------------------- /doc/Gui.md: -------------------------------------------------------------------------------- 1 | # Graphic user interfaces inside Docker 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2023) 4 | 5 | 6 | 7 | ## 1. Different approaches 8 | 9 | Running user interfaces from inside a Docker might not be its intended usage but as of now there are several options available. The problem with all of them is that most of them are specific to **Linux** operating systems (but can also be used in Windows under the **Windows Subsystem for Linux** (WSL 2). On the the [ROS Wiki](http://wiki.ros.org/docker/Tutorials/GUI) the different options are discussed in more detail: 10 | 11 | - In Linux there are several ways of connecting a containers output to a host's **X server** resulting in an output which is indistinguishable from a program running on the host directly. This is the approach chosen for this guide. It is quite portable but requires additional steps for graphics cards running with nVidia hardware acceleration rather than the Linux Nouveau display driver. OSRF has also released [Rocker](https://github.com/osrf/rocker) as a tool to support mounting folders and launching graphic user interfaces. I did not use it as I try to avoid introducing unnecessary dependencies. 12 | - Other common approaches are less elegant and often use some sort of **Virtual Network Computing (VNC)** which streams the entire desktop to the host over a dedicated window similar to connecting virtually to a remote machine. This is usually the approach chosen for other operating systems such as Windows and Macintosh but requires additional software and does not integrate as seemlessly. 13 | 14 | The rest of the guide will focus on graphic user interfaces on Linux by exploiting X-Server. This won't work with native Windows (but works with WSL 2 under Windows as discussed in [`Windows.md`](./Windows.md)) and Mac but I would not encourage using Docker on other operating systems other than Linux anyways. 15 | 16 | 17 | 18 | ## 2. Using X-Server 19 | 20 | As pointed out before this guide uses the Ubuntu X-Server for outputting dialogs from a Docker. The Docker-Compose file with and without Nvidia hardware acceleration look differently and Nvidia hardware acceleration requires a few additional setup steps. These differences are briefly outlined in the sections below. It is worth mentioning that **just having an Nvidia card does not necessitate the Nvidia setup** but instead what matters is the **driver** used for the graphics card. If you are using a Nouveau driver for an Nvidia card then a Docker-Compose file written for hardware acceleration won't work and instead you will have to turn to the Docker-Compose file without it. And vice versa, if your card is managed by the Nvidia driver then the first approach won't work for you. This fact is in particular important for the `PREEMPT_RT` patch: You won't be able to use your Nvidia driver when running the patch. Your operating system might mistakenly tell you that it is using the Nvidia driver but it might not. It is therefore important to check the output of `$ nvidia-smi`. If it outputs a managed graphics card, then you will have to go for the second approach with hardware acceleration. If it does not output anything or is not even installed go for the Nouveau driver setup. 21 | 22 | You can check in Software and Updates which graphics driver is currently used: 23 | 24 | ![Software & Updates](../media/ubuntu_software_and_updates.png) 25 | 26 | 27 | 28 | In any case before being able to **stream to the X-Server on the host system** you will have to run the following command inside the **host system**: 29 | 30 | ```bash 31 | $ xhost +local:root 32 | ``` 33 | 34 | where `root` corresponds to the user-name of the user used inside the Docker container. This command has to be **repeated after each restart** of the host system. 35 | 36 | If you do not execute this command before launching a graphic user interface the application will not be able to connect to the display. For Rviz for example this might look as follows: 37 | 38 | ```bash 39 | $ root@P500:/ros_ws# rosrun rviz rviz 40 | Authorization required, but no authorization protocol specified 41 | qt.qpa.xcb: could not connect to display :0 42 | qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. 43 | This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. 44 | 45 | Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, xcb. 46 | 47 | Aborted (core dumped) 48 | ``` 49 | 50 | In case graphic user interfaces do not open up correctly be sure to check the `DISPLAY` variable is set correctly. Output `$ echo ${DISPLAY}` on both, the host system as well as inside the container, and make sure they correspond. 51 | 52 | 53 | 54 | ### 2.1 Nouveau and AMD driver 55 | 56 | As pointed out in the second before this type of setup applies to any card that is not managed by an Nvidia driver, even if the card is an Nvidia card. In such a case it is sufficient to share the following few folders with the host system. The `docker-compose.yml` might look as follows: 57 | 58 | ```yaml 59 | version: "3.9" 60 | services: 61 | some_name: 62 | build: 63 | context: . 64 | dockerfile: Dockerfile 65 | tty: true 66 | environment: 67 | - DISPLAY=${DISPLAY} # Option for sharing the display 68 | - QT_X11_NO_MITSHM=1 # For Qt 69 | volumes: 70 | - /tmp/.X11-unix:/tmp/.X11-unix:rw # Share system folder 71 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw # Share system folder 72 | ``` 73 | 74 | ### 2.2 Hardware acceleration with Nvidia cards 75 | 76 | This section is only relevant for Nvidia graphic cards managed by the Nvidia driver or if you want to have hardware acceleration inside the Docker, e.g. for using CUDA or OpenGL. Graphic user interfaces that do not require it will work fine in any case. As also pointed out [in the ROS tutorial](http://wiki.ros.org/docker/Tutorials/Hardware%20Acceleration) having hardware acceleration is actually more tricky! Nvidia offers a dedicated [`nvidia-docker`](https://github.com/NVIDIA/nvidia-docker) (with two different options `nvidia-docker-1` and `nvidia-docker-2` which sightly differ) as well as the [`nvidia-container-runtime`](https://nvidia.github.io/nvidia-container-runtime/). Latter was chosen for this guide as it seems to be the way from now onwards and will be discussed below. 77 | 78 | #### 2.2.1 Installing the `nvidia-container-toolkit` 79 | 80 | The [`nvidia-container-runtime`](https://nvidia.github.io/nvidia-container-runtime/) (see installation instructions [here](https://stackoverflow.com/a/59008360)) is now deprecated and you should install the [`nvidia-container-toolkit`](https://github.com/NVIDIA/nvidia-container-toolkit) instead. Before following through with the installation make sure it is not already set-up on your system. For this check the `runtime` field from the output of `$ docker info`. If `nvidia` is available as an option already you should be already good to go. 81 | 82 | If it is not available you should be able to install it with the [following steps](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html): 83 | 84 | ```bash 85 | $ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ 86 | && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ 87 | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ 88 | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list 89 | $ sudo apt-get update 90 | $ sudo apt-get install -y nvidia-container-toolkit 91 | ``` 92 | 93 | and then [set-up the Docker runtime](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#configuration): 94 | 95 | ```bash 96 | $ sudo nvidia-ctk runtime configure --runtime=docker 97 | ``` 98 | 99 | After these steps you might will have to restart the system or at least the Docker daemon with `$ sudo systemctl daemon-reload` and `$ sudo systemctl restart docker`. Then `$ docker info` should output at least two different runtimes, the default `runc` as well as `nvidia`. This runtime can be set in the Docker-Compose file and one might have to set the `environment variables` `NVIDIA_VISIBLE_DEVICES=all` and `NVIDIA_DRIVER_CAPABILITIES=all`. Be aware that this will fail when launching it on other system without that runtime. You will need another dedicated Docker-Compose file for non-nVidia graphic cards! 100 | 101 | A Docker-Compose configuration for the Nvidia graphics cards with the Nvidia graphics driver looks as follows: 102 | 103 | ```yaml 104 | version: "3.9" 105 | services: 106 | some_name: 107 | build: 108 | context: . 109 | dockerfile: Dockerfile 110 | tty: true 111 | environment: 112 | - DISPLAY=${DISPLAY} 113 | - QT_X11_NO_MITSHM=1 114 | - NVIDIA_VISIBLE_DEVICES=all # Share devices of host system 115 | - NVIDIA_DRIVER_CAPABILITIES=all # This allows the guest system to use the GPU also for visualization 116 | runtime: nvidia # Specify runtime for container 117 | volumes: 118 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 119 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw 120 | ``` 121 | 122 | Depending on how your system is configured your computer might still decide to use the integrated Intel Graphics instead of your Nvidia card in order to save power. In this case I'd recommend you to switch the Nvidia X Server (that is automatically installed with the driver) to performance mode instead of on-demand as shown in the screenshot below. This way the Nvidia card should always be used instead of the Intel Graphics. 123 | 124 | ![Nvidia X Server configuration](../media/nvidia_x_server.png) 125 | 126 | 127 | 128 | #### 2.2.2 Testing the graphic acceleration inside your container 129 | 130 | After following above steps **make sure that inside your container you can use `nvidia-smi`** and it finds your card: 131 | 132 | ```bash 133 | $ nvidia-smi 134 | Wed Jun 21 00:01:46 2023 135 | +---------------------------------------------------------------------------------------+ 136 | | NVIDIA-SMI 530.41.03 Driver Version: 530.41.03 CUDA Version: 12.1 | 137 | |-----------------------------------------+----------------------+----------------------+ 138 | | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | 139 | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | 140 | | | | MIG M. | 141 | |=========================================+======================+======================| 142 | | 0 Quadro K2200 Off| 00000000:03:00.0 On | N/A | 143 | | 42% 39C P8 1W / 39W| 430MiB / 4096MiB | 10% Default | 144 | | | | N/A | 145 | +-----------------------------------------+----------------------+----------------------+ 146 | 147 | +---------------------------------------------------------------------------------------+ 148 | | Processes: | 149 | | GPU GI CI PID Type Process name GPU Memory | 150 | | ID ID Usage | 151 | |=======================================================================================| 152 | +---------------------------------------------------------------------------------------+ 153 | ``` 154 | 155 | In case the command is not recognized, make sure that you can run it successfully outside the Docker. In case it does not even work outside the Nvidia driver you are currently using is likely incompatible with your graphics card. In case it just does not work inside the Docker likely you made a mistake in your Docker-Compose file. 156 | 157 | Just seeing the card with `nvidia-smi` is though not sufficient. If you do not **set the environment variable `NVIDIA_DRIVER_CAPABILITIES`**, e.g. to `NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute` or **`NVIDIA_DRIVER_CAPABILITIES=all`** the graphic acceleration will not work properly. 158 | 159 | For testing if the graphic acceleration actually works inside the Docker you can use the **`glxgears`** application. Install it with 160 | 161 | ```bash 162 | $ sudo apt-get install mesa-utils 163 | ``` 164 | 165 | on your host system as well as inside the container and compare the two. 166 | 167 | Then run it with 168 | 169 | ```bash 170 | $ glxgears -info 171 | ``` 172 | 173 | This should visualize the following window and output the following information: 174 | 175 | ![glxgears application](../media/glxgears.png) 176 | 177 | ``` 178 | GL_RENDERER = Quadro K2200/PCIe/SSE2 179 | GL_VERSION = 4.6.0 NVIDIA 530.41.03 180 | GL_VENDOR = NVIDIA Corporation 181 | ``` 182 | 183 | as well as the current frames per second `8579 frames in 5.0 seconds = 1715.776 FPS` every couple of seconds. On a laptop with an additional integrated graphics card this already should tell you which of the two, the dedicated or the integrated one, is being used. 184 | 185 | In case you did not set `NVIDIA_DRIVER_CAPABILITIES` inside the container the output from `glxgears` will look as follows and you might observe stuttering in applications such as Gazebo: 186 | 187 | ``` 188 | GL_RENDERER = llvmpipe (LLVM 12.0.0, 256 bits) 189 | GL_VERSION = 3.1 Mesa 21.2.6 190 | GL_VENDOR = Mesa/X.org 191 | ``` 192 | 193 | 194 | 195 | #### 2.2.3 Hybrid graphics cards and power management 196 | 197 | On computers with an integrated graphics card (e.g. notebooks), you might run into issues where graphic acceleration might not work as power management will choose the integrated graphics card over the dedicated one. Run [`$ prime-select query`](https://github.com/linuxmint/nvidia-prime/blob/master/prime-select) to see what the output is (`nvidia`, `intel` or `on-demand`). Depending on the output the open-source or Nvidia version of libGL will be used. You can switch between them by executing `$ prime-select nvidia`. Similarly you can output the available graphic processors with `$ xrandr --listproviders`. In case you have an integrated and dedicated graphic card there should be two entries: `0` and `1` where the order depends on the setting of `prime-select`. 198 | 199 | You should be able to switch between the two with [**PRIME offloading**](https://wiki.archlinux.org/title/PRIME). Defining the environment variable `DRI_PRIME` allows you to use the discrete graphics card e.g. `DRI_PRIME=1 glxinfo`. Similarly Nvidia exposes the environment variable [`__NV_PRIME_RENDER_OFFLOAD`](https://download.nvidia.com/XFree86/Linux-x86_64/435.17/README/primerenderoffload.html) for this purpose, e.g. `$ __NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia glxinfo`. Finally you can use `prime-run` to force a program to offload to the dedicated Nvidia GPU: 200 | 201 | ```bash 202 | $ prime-run some_program 203 | ``` 204 | 205 | 206 | 207 | #### 2.2.4 Running containers as `privileged` 208 | 209 | In some rare instances with hybrid graphics cards, **hardware acceleration might not work correctly** resulting in e.g. [Rviz outputting the following](https://github.com/moby/moby/issues/38442): 210 | 211 | ```bash 212 | $ rviz 213 | dbus[97]: The last reference on a connection was dropped without closing the connection. This is a bug in an application. See dbus_connection_unref() documentation for details. 214 | Most likely, the application was supposed to call dbus_connection_close(), since this is a private connection. 215 | D-Bus not built with -rdynamic so unable to print a backtrace 216 | Aborted (core dumped) 217 | ``` 218 | 219 | In this case what might help is **running the container as `privileged`**. 220 | 221 | 222 | 223 | ### 2.3 Avoiding duplicate configurations 224 | 225 | You can already see that there are quite a few common options between the two configurations. While sadly Docker-Compose does not have conditional execution (yet) one might [override or extend an existing configuration file](https://github.com/Yelp/docker-compose/blob/master/docs/extends.md) (see also [`extends`](https://docs.docker.com/compose/extends/) as well this [Visual Studio Code guide](https://code.visualstudio.com/docs/remote/create-dev-container#_extend-your-docker-compose-file-for-development)). 226 | 227 | I normally start by creating a base Docker-Compose file `docker-compose.yml` that does not support graphic cards 228 | 229 | ```yaml 230 | version: "3.9" 231 | services: 232 | some_name: 233 | build: 234 | context: . 235 | dockerfile: Dockerfile 236 | tty: true 237 | ``` 238 | 239 | that is then extended for graphic user interfaces without Nvidia driver `docker-compose-gui.yml`, 240 | 241 | ```yaml 242 | version: "3.9" 243 | services: 244 | some_name: 245 | extends: 246 | file: docker-compose.yml 247 | service: some_name 248 | environment: 249 | - DISPLAY=${DISPLAY} 250 | - QT_X11_NO_MITSHM=1 251 | volumes: 252 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 253 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw 254 | ``` 255 | 256 | on top of that goes another Docker-Compose file with Nvidia acceleration `docker-compose-gui-nvidia.yml` 257 | 258 | ```yaml 259 | version: "3.9" 260 | services: 261 | some_name: 262 | extends: 263 | file: docker-compose-gui.yml 264 | service: some_name 265 | environment: 266 | - NVIDIA_VISIBLE_DEVICES=all 267 | - NVIDIA_DRIVER_CAPABILITIES=all 268 | runtime: nvidia 269 | ``` 270 | 271 | and finally I have yet another file which can be launched for hardware acceleration without graphic user interfaces `docker-compose-nvidia.yml` which might be used for computations and machine learning containers. 272 | 273 | ```yaml 274 | version: "3.9" 275 | services: 276 | some_name: 277 | extends: 278 | file: docker-compose.yml 279 | service: some_name 280 | environment: 281 | - NVIDIA_VISIBLE_DEVICES=all 282 | runtime: nvidia 283 | ``` 284 | 285 | This way if I need to add additional options, I only have to modify the base Docker-Compose file `docker-compose.yml` and the others will simply adapt. 286 | 287 | I can then specify which file should be launched to Docker-Compose with e.g. 288 | 289 | ```bash 290 | $ docker-compose -f docker-compose-gui-nvidia.yml up 291 | ``` 292 | 293 | 294 | 295 | ### 2.4 Known issues 296 | 297 | In certain versions of Linux you might run into the problem that **certain applications using hardware acceleration (e.g. Rviz and Gazebo) might not be displayed correctly**, instead black windows are displayed similar to the screenshot below: 298 | 299 | ![RViz hardware acceleration bug](../media/rviz_mesa_bug.png) 300 | 301 | This is a [known bug in the Mesa implementation of OpenGL present on e.g. Ubuntu 22.04](https://github.com/ros2/rviz/issues/948#issuecomment-1427569107) and can be resolved by **upgrading Mesa or by switching to Nvidia's implementation by using the Nvidia container runtime** (in case you have an Nvidia grapics card). 302 | 303 | The update can be performed by running the following commands inside the Docker container 304 | 305 | ```bash 306 | $ apt-get install software-properties-common 307 | $ add-apt-repository ppa:kisak/kisak-mesa 308 | $ apt-get update 309 | $ apt-get upgrade 310 | ``` 311 | 312 | or by adding an additional layer to your Dockerfile: 313 | 314 | ```dockerfile 315 | RUN apt-get update \ 316 | && apt-get install -y \ 317 | install software-properties-common \ 318 | && add-apt-repository ppa:kisak/kisak-mesa \ 319 | && apt-get update \ 320 | && apt-get upgrade -y \ 321 | && rm -rf /var/lib/apt/lists/* 322 | ``` 323 | -------------------------------------------------------------------------------- /doc/Ros.md: -------------------------------------------------------------------------------- 1 | # ROS inside Docker 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2023) 4 | 5 | 6 | 7 | ## 1. ROS/ROS 2 with Docker 8 | 9 | I personally think that Docker is a good choice for **developing** robotic applications as it allows you to quickly switch between different projects but **less so for deploying** software. Refer to [this Canonical article](https://ubuntu.com/blog/ros-docker) to more details about the drawbacks of deploying software with Docker, in particular regarding security. For the deployment I personally would rather turn to Debian or Snap packages (see e.g. [Bloom](http://wiki.ros.org/bloom/Tutorials/FirstTimeRelease)). But there are actually quite a few companies that I am aware of that actually use Docker for deployment as well, first and foremost [Boston Dynamics](https://dev.bostondynamics.com/docs/payload/docker_containers#). 10 | 11 | The ROS Wiki offers tutorials on ROS and Docker [here](http://wiki.ros.org/docker/Tutorials), there is also a very useful [tutorial paper](https://www.researchgate.net/publication/317751755_ROS_and_Docker) out there and another interesting article can be found [here](https://roboticseabass.com/2021/04/21/docker-and-ros/). Furthermore a list of important commands can be found [here](https://tuw-cpsg.github.io/tutorials/docker-ros/). After installing Docker one simply pulls an image of ROS, specifying the version tag: 12 | 13 | ```bash 14 | $ sudo docker pull ros 15 | ``` 16 | 17 | gives you the latest ROS 2 version whereas 18 | 19 | ```bash 20 | $ sudo docker pull ros:noetic-robot 21 | ``` 22 | 23 | will pull the latest version of ROS1. 24 | 25 | Finally you can run it with 26 | 27 | ```bash 28 | $ sudo docker run -it ros 29 | ``` 30 | 31 | (where `ros` should be replaced by the precise version tag e.g. `ros:noetic-robot`). 32 | 33 | The OSRF ROS Docker provides a readily available entrypoint script `ros_entrypoint.sh` that automatically sources `/opt/ros//setup.bash`. 34 | 35 | ### 1.1 Folder structure 36 | 37 | I generally structure Dockers for ROS in the following way: 38 | 39 | ``` 40 | ros_ws 41 | ├─ docker 42 | | ├─ Dockerfile 43 | | └─ docker-compose.yml # Context is chosen as .. 44 | └─ src # Only this folder is mounted into the Docker 45 | ├─ .repos # Configuration file for VCS tool 46 | └─ packages_as_submodules 47 | ``` 48 | 49 | Each ROS-package or a set of ROS packages are bundled together in a Git repository. These are then included as submodules in the `src` folder or even better by using [VCS tool](https://github.com/dirk-thomas/vcstool). Inside the `docker-compose.yml` file one then **mounts only the `src` folder as volume** so that it can be also accessed from within the container. This way the build and devel folders remain inside the Docker container and you can compile the code inside the Docker as well as outside (e.g. having two version of Ubuntu and ROS for testing in with different distributions). 50 | 51 | Generally I have more than a single `docker-compose.yml` as discussed in [`Gui.md`](./Gui.md) and I will add configuration folders for Visual Studio Code and a configuration for the Docker itself, as well as dedicated tasks. I usually work inside the container and install new software there first. I will keep then track of the installed software manually and add it to the Dockerfile as soon as it has proved useful. 52 | 53 | ### 1.2 Docker configurations 54 | 55 | You will find quite a few Docker configurations for ROS online, in particular [this one](https://github.com/athackst/vscode_ros2_workspace) for ROS 2 is quite well made. Another one for ROS comes with this repository. 56 | 57 | ### 1.4 Larger software stacks 58 | 59 | When working with larger software stacks tools like [Docker-Compose](https://docs.docker.com/compose/) and [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/) might be useful for **orchestration**, in particular when deploying with Docker. This is discussed in several separate repositories such as [this one](https://github.com/fujitatomoya/ros_k8s) by Tomoya Fujita, member of the Technical Steering Committee of ROS 2. 60 | 61 | ## 2. ROS 62 | 63 | This section will got into how selected ROS 1 configuration settings can be simplified with Docker, in particular the network set-up. 64 | 65 | ### 2.1 External ROS master 66 | 67 | Sometimes you want to run nodes inside the Docker and communicate with a ROS master outside of it. This can be done by adding the following **environment variables** to the `docker-compose.yml` file 68 | 69 | ```bash 70 | 9 environment: 71 | 10 - ROS_MASTER_URI=http://localhost:11311 72 | 11 - ROS_HOSTNAME=localhost 73 | ``` 74 | 75 | where in this case `localhost` stands for your local machine (the loop-back device `127.0.0.1`). 76 | 77 | #### 2.1.1 Multiple machines 78 | 79 | In case you want the Docker to communicate with another device on the network be sure to activate the option 80 | 81 | ```bash 82 | 15 network_mode: host 83 | 16 extra_hosts: 84 | 17 - "my_device:192.168.100.1" 85 | ``` 86 | 87 | as well, where `my_device` corresponds to the host name followed by its IP. The **`extra_hosts`** option basically adds another entry to your **`/etc/hosts` file inside the container**, similar to what you would do manually normally in the [ROS network setup guide](https://wiki.ros.org/ROS/NetworkSetup). This way the network set-up inside the Docker does not pollute the host system. 88 | 89 | Now make sure that pinging works **in both directions**. In case there was an issue with a firewall (or VPN) pinging might only work in one direction. If you would continue with your set-up you might be able to receive information (e.g. visualize the robot and its sensors) but not send it (e.g. command the robot). Furthermore ROS relies on the correct host name being set: If it does not correspond to the name of the remote computer the communication might also only work in one direction. For time synchronization of multiple machines it should be possible to run [`chrony`](https://robofoundry.medium.com/how-to-sync-time-between-robot-and-host-machine-for-ros2-ecbcff8aadc4) from inside a container without any issues. For how this can be done please refer to [cturra/ntp](https://github.com/cturra/docker-ntp) or alternatively to [this guide](http://www.freekb.net/Article?id=3292). After setting it up use `$ chronyc sources` as well as `$ chronyc tracking` to verify the correct set-up. 90 | 91 | You can test the communication between the two machines by sourcing the environment, launching a `roscore` on your local or remote computer, then launch the Docker source the local environment and see if you can see any topics inside `$ rostopic list`. Then you can start publishing a topic `$ rostopic pub /testing std_msgs/String "Testing..." -r 10` on one side (either Docker or host) and check if you receive the messages on the other side with `$ rostopic echo /testing`. If that works fine in both directions you should be ready to go. If it only works in one direction check your host configuration and your `ROS_MASTER_URI` and `ROS_HOSTNAME` environement variables. 92 | 93 | As a best practice I normally use a [`.env` file](https://vsupalov.com/docker-arg-env-variable-guide/) that I place in the same folder as the `Dockerfile` and the `docker-compose.yaml` containing the IPs: 94 | 95 | ```bash 96 | CATKIN_WORKSPACE_DIR="/catkin_ws" 97 | YOUR_IP="192.168.100.2" 98 | ROBOT_IP="192.168.100.1" 99 | ROBOT_HOSTNAME="some_host" 100 | ``` 101 | 102 | The IPs inside this file can then be modified and are used inside the Docker-Compose file to set-up the container: The `/etc/hosts` file as well as the `ROS_MASTER_URI` and the `ROS_HOSTNAME`: 103 | 104 | ```yaml 105 | version: "3.9" 106 | services: 107 | ros_docker: 108 | build: 109 | context: .. 110 | dockerfile: docker/Dockerfile 111 | environment: 112 | - ROS_MASTER_URI=http://${ROBOT_IP}:11311 113 | - ROS_IP=${YOUR_IP} 114 | network_mode: "host" 115 | extra_hosts: 116 | - "${ROBOT_HOSTNAME}:${ROBOT_IP}" 117 | tty: true 118 | volumes: 119 | - ../src:/${CATKIN_WORKSPACE_DIR}/src 120 | ``` 121 | 122 | In order to update the IPs though with this approach you will have to rebuild the container. As long as you did not make any modifications to the Dockerfile it should though use the cached layers and should be very quick. But any progress inside the container will be lost when switching IP! 123 | 124 | An example configuration can be found [here](../templates/ros/docker). 125 | 126 | #### 2.1.2 Combining different package and ROS versions 127 | 128 | Combining different ROS 1 versions is not officially supported but largely works as long as message definitions have not changed. This is problematic with constantly evolving packages such as [Moveit](https://moveit.ros.org/). The interface between the containers in this case has to be chosen wisely such that the used messages do not change across between the involved distributions. You can use [`rosmsg md5 `](https://wiki.ros.org/rosmsg#rosmsg_md5) in order to verify quickly if the message definitions have changed: If the two `md5` hashes are the same then the two distributions should be able to communicate via this message. And even if the message hashes are different you might go ahead and compile the message, as well as packages depending on it, from source (do not forget to uninstall the ones installed through Debian packages). This way both distributions will have again the same message definitions. 129 | 130 | ### 2.3 Healthcheck 131 | 132 | Docker gives you the possibility to [add a custom healthcheck to your container](https://docs.docker.com/engine/reference/builder/#healthcheck). This test should tell Docker whether your container is working correctly or not. Such a healthcheck can be defined from inside the Dockerfile or from a Docker-Compose file. 133 | 134 | In a Dockerfile it might look as follows: 135 | 136 | ```dockerfile 137 | HEALTHCHECK [OPTIONS] CMD command 138 | ``` 139 | 140 | such as 141 | 142 | ```dockerfile 143 | HEALTHCHECK CMD /ros_entrypoint.sh rostopic list || exit 1 144 | ``` 145 | 146 | or anything similar. 147 | 148 | While for [Docker-Compose](https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck) you might add something like: 149 | 150 | ```yaml 151 | 9 healthcheck: 152 | 10 test: /ros_entrypoint.sh rostopic list || exit 1 153 | 11 interval: 1m30s 154 | 12 timeout: 10s 155 | 13 retries: 3 156 | 14 start_period: 1m 157 | ``` 158 | 159 | ## 3. ROS 2 160 | 161 | [ROS 2](https://docs.ros.org/en/humble/index.html) was an important update to ROS that makes it much more suitable for industrial applications. It broke backwards compatability to fix some of the limitations of ROS and for this purpose followed a more thorough and structured code design that is largely documented [here](https://design.ros2.org/). One of the important changes was going away from a custom middleware for communication that is tightly integrated, such as is the case with ROS' [TCP](https://wiki.ros.org/ROS/TCPROS)/[UDP](https://wiki.ros.org/ROS/UDPROS) communication, towards an abstraction of the communication layer (see [here](https://design.ros2.org/articles/ros_middleware_interface.html)) and the introduction of [DDS](https://design.ros2.org/articles/ros_on_dds.html) as the primary communication layer in ROS 2. ROS 2 is primary intended to be used with DDS but also allows other middleware to be used, in particular [Zenoh in ROS 2 Iron](https://github.com/ros2/rmw_zenoh). Another example of such a custom middleware is `rmw_email` (see [here](https://christophebedard.com/ros-2-over-email/) and [here](https://github.com/christophebedard/rmw_email)). For wrapping a custom middleware one has to provide a wrapper for it, `rmw_*` that respects the [API](https://design.ros2.org/articles/ros_middleware_interface.html), and set the environment variable `RMW_IMPLEMENTATION` to the corresponding implementation. 162 | 163 | ### 3.1 DDS middleware configuration 164 | 165 | When using DDS as the middleware in ROS 2 the [`ROS_DOMAIN_ID`](https://docs.ros.org/en/humble/Concepts/About-Domain-ID.html) replaces the IP-based set-up. For a container this means one would create a `ROS_DOMAIN_ID` environment variable that again might be controlled by an [`.env` file](https://vsupalov.com/docker-arg-env-variable-guide/): 166 | 167 | ```yaml 168 | 9 environment: 169 | 10 - ROS_DOMAIN_ID=1 # Any number in the range of 0 and 101; 0 by default 170 | ``` 171 | 172 | Choosing a safe range for the Domain ID largely depends on the operating system and is described in more details in the [corresponding article](https://docs.ros.org/en/humble/Concepts/About-Domain-ID.html). There might be [additional settings for a DDS client such as telling it which interfaces to use](https://iroboteducation.github.io/create3_docs/setup/xml-config/). For this purpose it might make sense to mount the corresponding DDS configuration file into the Docker. 173 | 174 | When working on a network with several participats that use ROS (e.g. a company or research institution), you will have to make sure that people are using different `ROS_DOMAIN_ID`s. When only using ROS 2 locally, e.g. in simulation [set the variable `ROS_LOCALHOST_ONLY=1`](https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html#the-ros-localhost-only-variable). This restricts the network traffic to your local PC only. 175 | 176 | Another thing you might want to configure is the **DDS middleware** to be used. In ROS 2 one might choose between different (free or payment) middleware implementations such as FastDDS and CycloneDDS. This will be outlined in more detail in the next section. 177 | 178 | What I generally do is define the corresponding environment variables such as [`RMW_IMPLEMENTATION`](https://docs.ros.org/en/humble/How-To-Guides/Working-with-multiple-RMW-implementations.html) and [`CYCLONEDDS_URI`](https://cyclonedds.io/docs/cyclonedds/latest/config/index.html) in the case of cyclone and mount the dds configuration as a volume inside the container. 179 | 180 | ```yaml 181 | 9 environment: 182 | 10 - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp 183 | 11 - CYCLONEDDS_URI=${AMENT_WORKSPACE_DIR}/dds/cyclone.xml 184 | 12 network_mode: "host" 185 | 13 volumes: 186 | 14 - ../dds:${AMENT_WORKSPACE_DIR}/dds 187 | ``` 188 | 189 | For an example of what this configuration might look like have a look at [this folder](../templates/ros2/docker). 190 | 191 | #### 3.1.1 Intra-process communication over shared memory 192 | 193 | ROS 2 introduced some design changes that are aiming at drastically improving the communication speed in between nodes on the same computational unit. One such optimization is that [**intra-process communication** is left to the underlying middleware](https://design.ros2.org/articles/intraprocess_communications.html). This means it is down to the chosen middleware to use mechanisms like shared memory communication for nodes on the same computer. E.g. [FastDDS uses shared memory communication](https://fast-dds.docs.eprosima.com/en/v3.0.0/fastdds/transport/shared_memory/shared_memory.html) by default in case the environment variable [`ROS_LOCALHOST_ONLY`](https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html#the-ros-localhost-only-variable) is set to `1` and [CycloneDDS](https://cyclonedds.io/docs/cyclonedds/latest/shared_memory/shared_mem_config.html) lets you configure it through manually as described [here](https://github.com/ros2/rmw_cyclonedds/blob/humble/shared_memory_support.md). In Linux `/dev/shm` is used for **shared memory communication**. Therefore when communicating in between containers that set `ROS_LOCALHOST_ONLY` (or use shared memory explicitly) one might have to **mount `/dev/shm` into the containers**. For more information about shared memory and Docker refer to [this post](https://datawookie.dev/blog/2021/11/shared-memory-docker/). 194 | 195 | ### 3.2 Zenoh middleware configuration 196 | 197 | A new alternative to DDS-based communication in ROS 2 Iron is [Zenoh](https://zenoh.io/), implemented in [`rmw_zenoh`](https://github.com/ros2/rmw_zenoh). Similar to the `roscore` in ROS it relies on at least a single router that establishes the connection between different nodes running on different computers (it is also possible to do so without but this is not recommended). A good introduction to this can be found in this [video](https://www.youtube.com/watch?v=fS0_rbQ6KKA). I will add this configuration once `rmw_zenoh` becomes installable from Debian packages. 198 | 199 | ## 4. Bridging ROS 1 and ROS 2 200 | 201 | Setting the DDS middleware as described above is in particular important for cross-distro communication as **different ROS distros** ship with [**different default DDS implementations**](https://docs.ros.org/en/humble/Installation/DDS-Implementations.html). Neither communication between different DDS implementations nor different ROS 2 distributions is currently officially supported (generally it works but there can be problems with lower frequency etc., for more details see [here](https://github.com/ros2/ros2_documentation/issues/3288)) but similarly to ROS 1 if the **messages have not changed** (or you compile the messages as well as the packages using them from source) and you are **using the same DDS vendor across all involved distros** generally communication between the different distros can be achieved. This can also be useful for **bridging ROS 1 to ROS 2**. The last Ubuntu version to support both ROS 1 (Noetic) and ROS 2 (Galactic) is Ubuntu 20.04. You can use the corresponding [**Galactic ROS 1 bridge Docker**](https://hub.docker.com/layers/library/ros/galactic-ros1-bridge/images/sha256-a2f06953930b0a209295138745d606b1936f0b0564106df9230e2a6612b8b9a2?context=explore). In case message definitions have changed from Galactic to the distro that you are using (the ROS 2 API is not stable yet!) you might have to compile the corresponding messages from source. The main advantage over other solutions for having the two run alongside is that unlike to other solutions ([here](https://docs.ros.org/en/humble/How-To-Guides/Using-ros1_bridge-Jammy-upstream.html) or [here](https://github.com/TommyChangUMD/ros-humble-ros1-bridge-builder/tree/main)) you will have none or only very few repositories that have to be compiled from source and can't be installed from a Debian package. 202 | 203 | ## 5. CUDA and ROS 204 | 205 | When running CUDA inside a container make sure you are setting `runtime: nvidia`, as well as the environment variables `NVIDIA_VISIBLE_DEVICES=all` as well as `NVIDIA_DRIVER_CAPABILITIES=all` inside your Docker Compose file. 206 | 207 | For the image to use, you might find some online, e.g. [here](https://github.com/ika-rwth-aachen/docker-ros-ml-images) or for the Nvidia Jetson edge computing platforms [here](https://hub.docker.com/r/dustynv/ros/tags) and their Dockerfiles [here](https://github.com/dusty-nv/jetson-containers/tree/master/packages/ros). If you are not able to find an image that contains what you want, it is generally easier to start from an existing [`nvidia/cuda` image on the Dockerhub](https://hub.docker.com/r/nvidia/cuda) that uses the right version of Ubuntu (e.g. 20.04 for ROS Noetic or 22.04 for ROS 2 Humble) and install ROS on top of it by [copying the instructions from the official ROS Docker images](https://github.com/osrf/docker_images/blob/master/ros/noetic/ubuntu/focal/ros-base/Dockerfile). The other way around, starting from a ROS image and installing CUDA on top of it, is generally way more tricky! For the available Nvidia CUDA images browse the tags [here](https://hub.docker.com/r/nvidia/cuda/tags). By combining the two we can generate a custom image containing ROS and Nvidia as follows: 208 | 209 | ```dockerfile 210 | ARG UBUNTU_VERSION=20.04 211 | ARG NVIDIA_CUDA_VERSION=11.8.0 212 | 213 | ############## 214 | # Base image # 215 | ############## 216 | FROM nvidia/cuda:${NVIDIA_CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION} as base 217 | 218 | ARG ROS_DISTRO=noetic 219 | 220 | ENV DEBIAN_FRONTEND=noninteractive 221 | 222 | ENV ROS_DISTRO=${ROS_DISTRO} 223 | RUN apt-get update \ 224 | && apt-get install -y \ 225 | curl \ 226 | lsb-release \ 227 | && sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' \ 228 | && curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add - \ 229 | && apt-get update \ 230 | && apt-get install -y --no-install-recommends \ 231 | ros-${ROS_DISTRO}-ros-base \ 232 | && rm -rf /var/lib/apt/lists/* 233 | ``` 234 | 235 | -------------------------------------------------------------------------------- /doc/Introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction to Docker 2 | 3 | Author: [Tobit Flatscher](https://github.com/2b-t) (2021 - 2023) 4 | 5 | 6 | 7 | ## 1. Challenges in software deployment 8 | 9 | Deploying a piece of software in a portable manner is a non-trivial task. Clearly there are different operating system and different software architectures which require different binary code, but even if these match you have to make sure that the compiled code can be executed on another machine by supplying all its **dependencies**. 10 | 11 | Over the years several different packaging systems for different operating systems have emerged that provide methods for installing new dependencies and managing existing ones in an coherent manner. The low-level package manager for Debian-based Linux operating systems is [`dpkg`](https://wiki.debian.org/Teams/Dpkg), while for high-level package management, fetching packages from remote locations and resolving complex package relations, generally [`apt`](https://wiki.debian.org/Apt) is chosen. `apt` handles retrieving, configuring, installing as well as removing packages in an automated manner. When installing an `apt` package it checks the existing dependencies and installs only those that are not available yet on the system. The dependencies are shared, making the packages smaller but not allowing for multiple installations of the same library and potentially causing issues between applications requiring different versions of the same library. Contrary to this the popular package manager [`snap`](https://snapcraft.io/) uses self-contained packages which pack all the dependencies that a program requires to run, allowing for multiple installations of the same library. **Self-contained** boxes like these are called **containers**, as they do not pollute the rest of the system and might only have limited access to the host system. The main advantage of containers is that they provide clean and conistent environments as well as isolation from the hardware. 12 | 13 | 14 | 15 | ## 2. Docker to the rescue 16 | 17 | [**Docker**](https://www.docker.com/) is another **framework** for working with **containers**. A [Docker - contrary to `snap`](https://www.youtube.com/watch?v=0z3yusiCOCk) - is not integrated in terms of hardware and networking but instead has its own IP address, adding an extra layer of abstraction. A Docker container is similar to a virtual machine but the containers share the same kernel like the host system: Docker does not **virtualise** on a hardware level but on an **app level** (OS-level virtualisation). For this Docker builds on a virtualization feature of the Linux kernel, [namespaces](https://en.wikipedia.org/wiki/Linux_namespaces), that allows to selectivelty grant processes access to kernel resources. As such Docker has its own namespaces for `mnt`, `pid`, `net`, `ipc` as well as `usr` and its own root file system. As a Docker container uses the same kernel, and as a result also the same scheduler one might achieve native performance. At the same time this results in issues with graphic user interfaces as these are not part of the kernel itself and thus not shared between the container and the host system. These problems can be worked around though mostly. 18 | 19 | Using Docker brings a couple of advantages as it strongly leverages on the decoupling of the kernel and the rest of the operating system: 20 | 21 | - **Portability**: You can run code not intended for your particular Linux distribution (e.g packages for Ubuntu 20.04 on Ubuntu 18.04 and vice versa) and you can mix them, launching several containers with different requirements on the same host system by means of dedicated [orchestration tools](https://docs.docker.com/get-started/orchestration/) such as [Kubernetes](https://kubernetes.io/) or [Docker Swarm](https://docs.docker.com/engine/swarm/). This is a huge advantage for robotics applications as one can mix containers with different ROS distributions on the same computer running in parallel, all running on the same kernel of the host operating system, governed by the same scheduler. 22 | - **Performance**: Contrary to a virtual machine the performance penalty is very small and for most applications is indistinguishable from running code on the host system: After all it uses same kernel and scheduler as the host system. 23 | - Furthermore one can also run a **Linux container on a Windows or MacOS operating system**. This way you lose though a couple of advantages of Docker such as being able to run real-time code as there will be a light-weight virtual machine underneath emulating a Linux kernel. Furthermore you can also use it from the **Windows Subsystem for Linux** which allows you to stream graphic user interfaces onto the host system through X-Server. 24 | 25 | This way one can guarantee a **clean, consistent and standardised build environment** while maintaining encapsulation and achieving native performance. 26 | 27 | The core component of Docker are so called **images**, *immutable read-only templates*, that hold source code, libraries and dependencies. These can be layered over each other to form more complex images. **Containers** on the other hand are the *writable layer* on top of the read-only images. By starting an image you obtain a container: Images and containers are not opposing objects but they should rather be seen as different phases of building a containerised application. 28 | 29 | The Docker **daemon** software manages the different containers that are available on the system: The generation of an image can be described by a so called **`Dockerfile`**. A Dockerfile is like a recipe describing how an image can be created from scratch. This file might help also somebody reconstruct the steps required to get a code up and running on a vanilla host system without Docker. It is so to speak self-documenting and does not result in an additional burden like a wiki. Similarly one can recover the steps performed to generate an image with [`$ docker history --no-trunc `](https://docs.docker.com/engine/reference/commandline/history/). Dedicated servers, so calle **Docker registries** (such as the [Docker Hub](https://hub.docker.com/) or [Github's GHCR](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)), allow you to store and distribute your Docker images. These image repositories hold different images so that one does not have to go through the build process but instead can upload and download them directly, speeding up deployment. Uploads might also be triggered by a continuous integration workflow like outlined [here](https://docs.github.com/en/actions/publishing-packages/publishing-docker-images). 30 | 31 | On top of this there go other toolchains for managing the lifetime of containers and orchestration multiple of them such as [Docker-Compose](https://docs.docker.com/compose/), [Swarm](https://docs.docker.com/engine/swarm/) or [Kubernetes](https://kubernetes.io/). 32 | 33 | This makes Docker in particular suitable for **deploying source code in a replicable manner** and will likely speed-up your development workflow. Furthermore one can use the description to perform tests or compile the code on a remote machine in terms of [continuous integration](https://en.wikipedia.org/wiki/Continuous_integration). This means for most people working professional on code development it comes at virtually no cost. 34 | 35 | 36 | 37 | ## 3. Installing Docker 38 | 39 | Docker is installed pretty easily. The installation guide for **Ubuntu** can be found [here](https://docs.docker.com/engine/install/ubuntu/). It basically boils down to a five steps: 40 | 41 | ```bash 42 | $ sudo mkdir -m 0755 -p /etc/apt/keyrings 43 | $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 44 | $ echo \ 45 | "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ 46 | $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 47 | $ sudo apt-get update 48 | $ sudo apt-get install docker-ce docker-ce-cli containerd.io 49 | ``` 50 | 51 | After installation you will want to make sure that Docker can be **run without `sudo`** as described [here](https://docs.docker.com/engine/install/linux-postinstall/): 52 | 53 | ```bash 54 | $ sudo groupadd docker 55 | $ sudo usermod -aG docker $USER 56 | ``` 57 | 58 | Finally log out and log back in again. 59 | 60 | 61 | 62 | ## 4. Usage 63 | 64 | Similarly the usage is very simple, you need a few simple commands to get a Docker up and running which are discussed in the file below. 65 | 66 | ### 4.1 Launching a container from an image 67 | 68 | As discussed above you can pull an image from the [Dockerhub](https://hub.docker.com/) and launch it as a container. This can be done by opening a console and typing: 69 | 70 | ```bash 71 | $ docker run hello-world 72 | ``` 73 | 74 | `hello-world` is an image intended for testing purposes. After executing the command you should see some output to the console that does not contain any error messages. In case you are not able to run the command above, prepend it with `sudo` and retry. If this works please go back to the previous section and enable `sudo`less Docker as this will be crucial for e.g. the Visual Studio Code set-up. 75 | 76 | If you want to find out what other images you could start from just [browse the Dockerhub](https://hub.docker.com/), e.g. for [Ubuntu](https://hub.docker.com/_/ubuntu). You will see that there are different versions with corresponding tags available. For example to run a Docker with Ubuntu 20.04 installed you could use the tag `20.04` or `focal` resulting e.g. in the command 77 | 78 | ```bash 79 | $ docker run ubuntu:focal 80 | ``` 81 | 82 | This should not output anything and should immediately return. The reason for this is that each container has an [entrypoint](https://docs.docker.com/engine/reference/builder/#entrypoint). This script will be run and as soon as it terminates the container will return to the command line. This is actually the basic idea of a Docker container: A container should be responsible for a single service. Once this service stops it should return again. 83 | 84 | If you want to keep the container open you have to open it in **interactive** mode by specifying the flag `-i` and the `-t` for opening a terminal 85 | 86 | ```bash 87 | $ docker run -it ubuntu:focal 88 | ``` 89 | 90 | In case you need to run another command in parallel you might have to open a second terminal and connect to this Docker. In this case it is more convenient to relaunch the container with a specified `name` (or use the default one displayed by `docker run`) 91 | 92 | ```bash 93 | $ docker run -it --name ubuntu_test ubuntu:focal 94 | ``` 95 | 96 | Now we can connect to it from another console with 97 | 98 | ```bash 99 | $ docker exec -it ubuntu_test sh 100 | ``` 101 | 102 | The last command `sh` corresponds to the type of connection, in our case `shell`. 103 | 104 | With the `$ exit` command the Docker can be shut down. 105 | 106 | ### 4.2 Setting-up a `Dockerfile` 107 | 108 | Now that we have seen how to start a container from an existing image let us build a `Dockerfile` that defines steps that should be executed on the image: 109 | 110 | ```dockerfile 111 | # Base image 112 | FROM ubuntu:focal 113 | 114 | # Define the workspace folder (e.g. where to place your code) 115 | # We define a variable so that we can re-use it 116 | ENV WS_DIR="/code" 117 | WORKDIR ${WS_DIR} 118 | 119 | # Copy your code into the folder (see later for better alternatives!) 120 | COPY . WORKDIR 121 | 122 | # Use Bourne Again Shell as default shell 123 | SHELL ["/bin/bash", "-c"] 124 | 125 | # Disable user dialogs in apt installation messages 126 | ARG DEBIAN_FRONTEND=noninteractive 127 | 128 | # Commands to perform on base image 129 | RUN apt-get -y update \ 130 | && apt-get -y install some_package \ 131 | && git clone https://github.com/some_user/some_repository some_repo \ 132 | && cd some_repo \ 133 | && mkdir build \ 134 | && cd build \ 135 | && cmake .. \ 136 | && make -j$(nproc) \ 137 | && make install \ 138 | && rm -rf /var/lib/apt/lists/* 139 | 140 | # Enable apt user dialogs again 141 | ARG DEBIAN_FRONTEND=dialog 142 | 143 | # Define the script that should be launched upon start of the container 144 | ENTRYPOINT ["/code/src/my_script.sh"] 145 | ``` 146 | 147 | When saving this as `Dockerfile` (without a file ending) and type: 148 | 149 | ```bash 150 | $ docker build -f Dockerfile . 151 | ``` 152 | 153 | Then read the available images with 154 | 155 | ``` 156 | $ docker image ls 157 | REPOSITORY TAG IMAGE ID CREATED SIZE 158 | latest ... ... 159 | ``` 160 | 161 | You should see your newly created image. 162 | 163 | You can launch it with 164 | 165 | ```bash 166 | $ docker run -it 167 | ``` 168 | 169 | As soon as you starting building complex containers you will see that the compilation might be quite slow as a lot of data might have be to installed. If you want to execute it again though or you add a command to the `Dockerfile` the container will start pretty quickly. Docker itself caches the compiled images and re-uses them if possible. In fact each individual `RUN` etc. command forms a layer of its own that might be re-used. It is therefore crucial to avoid conflicts between different layers, e.g. by [introducing each `apt-get -y install` with an `apt-get update`](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run). They have to be combined in the same `RUN` command though to be effective. Similarly you can benefit from this caching by [ordering the different layers from less frequent to most frequently changed](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#use-multi-stage-builds). This way you might reduce the time you spend re-compiling significantly. 170 | 171 | At the same time it is also important to make the images as slim as possible removing all undesired artifacts from the images that are not necessary. For `apt` this means deleting the `apt` list after each layer again 172 | 173 | ```bash 174 | rm -rf /var/lib/apt/lists/* 175 | ``` 176 | 177 | A simple solution to this are [multi-stage builds](https://docs.docker.com/build/building/multi-stage/) where multiple `FROM` statements are used within the same Dockerfile and parts are selectively copied between the different stages. This way everything that is not needed can be left behind. 178 | 179 | Additionally one should set the `DEBIAN_FRONTEND` environment variable to `noninteractive` before installing any packages with `apt`. Else building the Dockerfile might fail! 180 | 181 | ### 4.3 Managing data 182 | 183 | As you have seen above we copied the data of the current directory into the container with the `COPY` command. This means though that our changes will not affect the local code, instead we are working on a copy of it. This is often not desirable. Most f the time you actually want to mount your folders and shared them between the host system and the container. 184 | 185 | There are several approaches for [managing data](https://docs.docker.com/storage/) with a Docker container. Generally one stores the relevant code outside the Docker on the host system, mounting files and directories into the container, while leaving any built files inside it. This way the files relevant to both systems can be accessed inside and outside the Docker. This is generally done with [volumes](https://docs.docker.com/storage/volumes/). This results in [additional flags](https://docs.docker.com/storage/volumes/) that have to be supplied when running the Docker: 186 | 187 | ```bash 188 | $ docker run -it --volume:: 189 | ``` 190 | 191 | ### 4.4 Build and run scripts 192 | 193 | As you can imagine when specifying start-up options like `-it`, mounting volumes, setting up the network configuration, display settings for graphic user interfaces, passing a user name to be used inside the Docker etc. the commands for building and running Docker containers can get pretty lengthy and complicated such as the one below: 194 | 195 | ```bash 196 | $ docker run -it --volume=../src:/code/src --name=my_container --env=DISPLAY \ 197 | --env=QT_X11_NO_MITSHM=1 --volume=/tmp/.X11-unix:/tmp/.X11-unix:rw \ 198 | --volume=/tmp/.docker.xauth:/tmp/.docker.xauth:rw --entrypoint='/bin/bash' 199 | ``` 200 | 201 | To simplify this process people often create bash scripts that store these arguments for them. Instead of typing a long command commonly one just call scripts like `build_image.bash` and `container_start.bash`. This can though be quite unintuitive for other users as there does not exist a common convention for doing so. Therefore tools like Docker-Compose, which is discussed in the next section, try to simplify this process by providing standardized configuration files for it. 202 | 203 | In any case try to avoid the `privileged` flag. If you run into any issue with not being able to do something, running the container as `privileged` will almost always solve it but there will be a more clean way. The `privileged` option breaks encapsulation and as such might pose a security risk. 204 | 205 | At the same time it makes sense to pass crucial information into the container by means of environment variables. 206 | 207 | ### 4.5 Using a Docker registry: Dockerhub 208 | 209 | Instead of creating our Docker image from a Docker file we might want to use a more complex existing one from a Docker registry. For this we will use the official one in the following example, the [Dockerhub](https://hub.docker.com/). 210 | 211 | Let's begin by logging in and pulling an existing image from an existing repository that you might have found [browsing the Dockerhub](https://hub.docker.com/search). 212 | 213 | ```bash 214 | $ docker login --username= --email= # If it is public we can pull also without logging in 215 | $ docker pull : # Pull an image from the server 216 | ``` 217 | 218 | This should give as a new image on our local computer that we can run 219 | 220 | ```bash 221 | $ docker images # List all locally available images 222 | REPOSITORY TAG IMAGE ID CREATED SIZE 223 | ... ... 224 | $ docker run -it : bin/bash # Run the image as a container 225 | @:/# 226 | ``` 227 | 228 | Now we can make changes to the container and finally exit it with `exit`. We should be able to see it with the following command: 229 | 230 | ```bash 231 | $ docker ps -a # Show all containers 232 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 233 | : ... ... ... ... ... 234 | ``` 235 | 236 | Finally we can commit our changes to a new image and push this image to the Dockerhub as follows: 237 | 238 | ```bash 239 | $ docker commit : # Commit container to new image 240 | $ docker images # List all available images 241 | REPOSITORY TAG IMAGE ID CREATED SIZE 242 | ... ... 243 | ... ... ... ... 244 | $ docker tag /: # Tag the image 245 | $ docker push / # Push the image to the server 246 | ``` 247 | 248 | ### 4.6 Exporting a Docker image to file 249 | 250 | Accessing most Docker registries will require internet access. Therefore when dealing with a slow network connection or an offline computer, sometimes it might be convenient to save a Docker image to the disk, copy them to the machine without internet access and load them onto that system: 251 | 252 | ```bash 253 | $ docker save : > # Save Docker to file 254 | $ docker load --input # Load Docker on other computer without internet access 255 | ``` 256 | 257 | 258 | 259 | ## 5. Docker-Compose 260 | 261 | There are different tools available that simplify the management and the orchestration of these Docker containers, such as [Docker-Compose](https://docs.docker.com/compose/reference/up/). As said supplying arguments to Docker for building and running a `Dockerfile` often results in lengthy `shell` scripts. One way of decreasing complexity and [tidying up the process](https://docs.docker.com/compose/) is by using [**Docker-Compose**](https://docs.docker.com/compose/). It is a tool that can be used for defining and running multi-container Docker applications but is also very useful for a single container. In a Yaml file such as **`docker-compose.yml`** one describes the services that an app consists of (see [here](https://github.com/compose-spec/compose-spec/blob/master/spec.md) for the syntax) and which options it should be started with. There are though a few corner cases where Docker-Compose is not powerful enough. For example it can't execute commands on the host system in order to obtain parameters that are then passed to the Docker. Parameters have to be supplied in the form of text or in the form of an environment file. 262 | 263 | ### 5.1 Installation 264 | 265 | Prior to Ubuntu 20.04 Docker-Compose had to be installed separately like described [here](https://docs.docker.com/compose/install/). For Ubuntu 20.04 onwards it should come with Docker directly. Depending on the version you will have to call it with 266 | 267 | ```bash 268 | $ docker compose --version 269 | ``` 270 | 271 | or `$ docker-compose --version`. 272 | 273 | ### 5.2 Writing and launching a Docker-Compose file 274 | 275 | For example the rather complicated Docker run command given before could be expressed in Docker-Compose with the hierarchical `yml` file, generally named `docker-compose.yml`: 276 | 277 | ```yaml 278 | version: "3.9" 279 | services: 280 | my_service: 281 | build: 282 | context: .. 283 | dockerfile: docker/Dockerfile 284 | container_name: my_container 285 | tty: true 286 | environment: 287 | - DISPLAY=${DISPLAY} 288 | - QT_X11_NO_MITSHM=1 289 | volumes: 290 | - ../src:/code/src 291 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 292 | - /tmp/.docker.xauth:/tmp/.docker.xauth:rw 293 | command: '/bin/bash' 294 | ``` 295 | 296 | After having created both a `Dockerfile` as well as a `docker-compose.yml` you can launch them with: 297 | 298 | ```bash 299 | $ docker compose -f docker-compose.yml build 300 | $ docker compose -f docker-compose.yml up 301 | ``` 302 | 303 | where with the option `-f` a Docker-Compose file with a different filename can be provided. If not given it will default to `docker-compose.yml`. 304 | 305 | More generally such a file might hold multiple services: 306 | 307 | ```yaml 308 | version: "3.9" 309 | services: 310 | some_service: # Name of the particular service (Equivalent to the Docker --name option) 311 | build: # Use Dockerfile to build image 312 | context: . # The folder that should be used as a reference for the Dockerfile and mounting volumes 313 | dockerfile: Dockerfile # The name of the Dockerfile 314 | container_name: some_container 315 | stdin_open: true # Equivalent to the Docker -i option 316 | tty: true # Equivalent to the Docker docker run -t option 317 | volumes: 318 | - /a_folder_on_the_host:/a_folder_inside_the_container # Source folder on host : Destination folder inside the container 319 | another_service: 320 | image: ubuntu/20.04 # Use a Docker image from Dockerhub 321 | container_name: another_container 322 | volumes: 323 | - /another_folder_on_the_host:/another_folder_inside_the_container 324 | volumes: 325 | - ../yet_another_folder_on_host:/a_folder_inside_both_containers # Another folder to be accessed by both images 326 | ``` 327 | 328 | If instead you wanted only to run a particular service you could do so with: 329 | 330 | ```bash 331 | $ docker compose -f docker-compose.yml run my_service 332 | ``` 333 | 334 | Then similarly to the previous section one is able to connect to the container from another console with 335 | 336 | ```bash 337 | $ docker compose exec sh 338 | ``` 339 | 340 | where `` is given by the name specified in the `docker-compose.yml` file and `sh` stands for the type of comand to be execute, in this case we open a `shell`. 341 | -------------------------------------------------------------------------------- /examples/affordance-templates-ros-docker/src/at_r2_bringup/config/at_r2_moveit.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 84 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /MotionPlanning1/Scene Robot1 9 | - /MotionPlanning1/Planning Request1 10 | - /MotionPlanning1/Planning Metrics1 11 | - /MotionPlanning1/Planned Path1 12 | - /Asus Camera1/Visibility1 13 | Splitter Ratio: 0.467146 14 | Tree Height: 143 15 | - Class: rviz/Help 16 | Name: Help 17 | - Class: rviz/Views 18 | Expanded: 19 | - /Current View1 20 | Name: Views 21 | Splitter Ratio: 0.5 22 | - Class: RVizInteractiveControlsPanel/RVizInteractiveControlsPanel 23 | Name: RVizInteractiveControlsPanel 24 | - Class: rviz_affordance_template_panel/RVizAffordanceTemplatePanel 25 | Name: RVizAffordanceTemplatePanel 26 | Visualization Manager: 27 | Class: "" 28 | Displays: 29 | - Alpha: 0.5 30 | Cell Size: 1 31 | Class: rviz/Grid 32 | Color: 160; 160; 164 33 | Enabled: true 34 | Line Style: 35 | Line Width: 0.03 36 | Value: Lines 37 | Name: Grid 38 | Normal Cell Count: 0 39 | Offset: 40 | X: 0 41 | Y: 0 42 | Z: 0 43 | Plane: XY 44 | Plane Cell Count: 10 45 | Reference Frame: 46 | Value: true 47 | - Class: moveit_rviz_plugin/MotionPlanning 48 | Enabled: true 49 | Move Group Namespace: "" 50 | MoveIt_Goal_Tolerance: 4 51 | MoveIt_Planning_Attempts: 10 52 | MoveIt_Planning_Time: 5 53 | MoveIt_Use_Constraint_Aware_IK: true 54 | MoveIt_Warehouse_Host: 127.0.0.1 55 | MoveIt_Warehouse_Port: 33829 56 | MoveIt_Workspace: 57 | Center: 58 | X: 0 59 | Y: 0 60 | Z: 0 61 | Size: 62 | X: 2 63 | Y: 2 64 | Z: 2 65 | Name: MotionPlanning 66 | Planned Path: 67 | Color Enabled: false 68 | Interrupt Display: false 69 | Links: 70 | All Links Enabled: true 71 | Expand Joint Details: false 72 | Expand Link Details: false 73 | Expand Tree: false 74 | Link Tree Style: Links in Alphabetic Order 75 | r2/asus_frame: 76 | Alpha: 1 77 | Show Axes: false 78 | Show Trail: false 79 | r2/backpack: 80 | Alpha: 1 81 | Show Axes: false 82 | Show Trail: false 83 | Value: true 84 | r2/baseplate: 85 | Alpha: 1 86 | Show Axes: false 87 | Show Trail: false 88 | Value: true 89 | r2/body_cover: 90 | Alpha: 1 91 | Show Axes: false 92 | Show Trail: false 93 | Value: true 94 | r2/chest_base: 95 | Alpha: 1 96 | Show Axes: false 97 | Show Trail: false 98 | r2/chest_center: 99 | Alpha: 1 100 | Show Axes: false 101 | Show Trail: false 102 | r2/left_camera_frame: 103 | Alpha: 1 104 | Show Axes: false 105 | Show Trail: false 106 | r2/left_camera_optical_frame: 107 | Alpha: 1 108 | Show Axes: false 109 | Show Trail: false 110 | r2/left_elbow: 111 | Alpha: 1 112 | Show Axes: false 113 | Show Trail: false 114 | Value: true 115 | r2/left_index_base: 116 | Alpha: 1 117 | Show Axes: false 118 | Show Trail: false 119 | r2/left_index_distal: 120 | Alpha: 1 121 | Show Axes: false 122 | Show Trail: false 123 | Value: true 124 | r2/left_index_medial: 125 | Alpha: 1 126 | Show Axes: false 127 | Show Trail: false 128 | Value: true 129 | r2/left_index_proximal: 130 | Alpha: 1 131 | Show Axes: false 132 | Show Trail: false 133 | Value: true 134 | r2/left_index_tip: 135 | Alpha: 1 136 | Show Axes: false 137 | Show Trail: false 138 | r2/left_index_yaw: 139 | Alpha: 1 140 | Show Axes: false 141 | Show Trail: false 142 | r2/left_little_distal: 143 | Alpha: 1 144 | Show Axes: false 145 | Show Trail: false 146 | Value: true 147 | r2/left_little_medial: 148 | Alpha: 1 149 | Show Axes: false 150 | Show Trail: false 151 | Value: true 152 | r2/left_little_proximal: 153 | Alpha: 1 154 | Show Axes: false 155 | Show Trail: false 156 | Value: true 157 | r2/left_little_tip: 158 | Alpha: 1 159 | Show Axes: false 160 | Show Trail: false 161 | r2/left_lower_arm: 162 | Alpha: 1 163 | Show Axes: false 164 | Show Trail: false 165 | Value: true 166 | r2/left_middle_base: 167 | Alpha: 1 168 | Show Axes: false 169 | Show Trail: false 170 | r2/left_middle_distal: 171 | Alpha: 1 172 | Show Axes: false 173 | Show Trail: false 174 | Value: true 175 | r2/left_middle_medial: 176 | Alpha: 1 177 | Show Axes: false 178 | Show Trail: false 179 | Value: true 180 | r2/left_middle_proximal: 181 | Alpha: 1 182 | Show Axes: false 183 | Show Trail: false 184 | Value: true 185 | r2/left_middle_tip: 186 | Alpha: 1 187 | Show Axes: false 188 | Show Trail: false 189 | r2/left_middle_yaw: 190 | Alpha: 1 191 | Show Axes: false 192 | Show Trail: false 193 | r2/left_palm: 194 | Alpha: 1 195 | Show Axes: false 196 | Show Trail: false 197 | Value: true 198 | r2/left_ring_distal: 199 | Alpha: 1 200 | Show Axes: false 201 | Show Trail: false 202 | Value: true 203 | r2/left_ring_medial: 204 | Alpha: 1 205 | Show Axes: false 206 | Show Trail: false 207 | Value: true 208 | r2/left_ring_proximal: 209 | Alpha: 1 210 | Show Axes: false 211 | Show Trail: false 212 | Value: true 213 | r2/left_ring_tip: 214 | Alpha: 1 215 | Show Axes: false 216 | Show Trail: false 217 | r2/left_shoulder_pitch: 218 | Alpha: 1 219 | Show Axes: false 220 | Show Trail: false 221 | Value: true 222 | r2/left_shoulder_roll: 223 | Alpha: 1 224 | Show Axes: false 225 | Show Trail: false 226 | Value: true 227 | r2/left_thumb_base: 228 | Alpha: 1 229 | Show Axes: false 230 | Show Trail: false 231 | r2/left_thumb_distal: 232 | Alpha: 1 233 | Show Axes: false 234 | Show Trail: false 235 | Value: true 236 | r2/left_thumb_medial: 237 | Alpha: 1 238 | Show Axes: false 239 | Show Trail: false 240 | Value: true 241 | r2/left_thumb_medial_prime: 242 | Alpha: 1 243 | Show Axes: false 244 | Show Trail: false 245 | Value: true 246 | r2/left_thumb_proximal: 247 | Alpha: 1 248 | Show Axes: false 249 | Show Trail: false 250 | Value: true 251 | r2/left_thumb_tip: 252 | Alpha: 1 253 | Show Axes: false 254 | Show Trail: false 255 | r2/left_upper_arm: 256 | Alpha: 1 257 | Show Axes: false 258 | Show Trail: false 259 | Value: true 260 | r2/left_wrist_pitch: 261 | Alpha: 1 262 | Show Axes: false 263 | Show Trail: false 264 | r2/left_wrist_yaw: 265 | Alpha: 1 266 | Show Axes: false 267 | Show Trail: false 268 | r2/neck_base: 269 | Alpha: 1 270 | Show Axes: false 271 | Show Trail: false 272 | Value: true 273 | r2/neck_lower_pitch: 274 | Alpha: 1 275 | Show Axes: false 276 | Show Trail: false 277 | Value: true 278 | r2/neck_roll: 279 | Alpha: 1 280 | Show Axes: false 281 | Show Trail: false 282 | Value: true 283 | r2/neck_upper_pitch: 284 | Alpha: 1 285 | Show Axes: false 286 | Show Trail: false 287 | r2/openni_depth_frame: 288 | Alpha: 1 289 | Show Axes: false 290 | Show Trail: false 291 | r2/right_camera_frame: 292 | Alpha: 1 293 | Show Axes: false 294 | Show Trail: false 295 | r2/right_camera_optical_frame: 296 | Alpha: 1 297 | Show Axes: false 298 | Show Trail: false 299 | r2/right_elbow: 300 | Alpha: 1 301 | Show Axes: false 302 | Show Trail: false 303 | Value: true 304 | r2/right_index_base: 305 | Alpha: 1 306 | Show Axes: false 307 | Show Trail: false 308 | r2/right_index_distal: 309 | Alpha: 1 310 | Show Axes: false 311 | Show Trail: false 312 | Value: true 313 | r2/right_index_medial: 314 | Alpha: 1 315 | Show Axes: false 316 | Show Trail: false 317 | Value: true 318 | r2/right_index_proximal: 319 | Alpha: 1 320 | Show Axes: false 321 | Show Trail: false 322 | Value: true 323 | r2/right_index_tip: 324 | Alpha: 1 325 | Show Axes: false 326 | Show Trail: false 327 | r2/right_index_yaw: 328 | Alpha: 1 329 | Show Axes: false 330 | Show Trail: false 331 | r2/right_little_distal: 332 | Alpha: 1 333 | Show Axes: false 334 | Show Trail: false 335 | Value: true 336 | r2/right_little_medial: 337 | Alpha: 1 338 | Show Axes: false 339 | Show Trail: false 340 | Value: true 341 | r2/right_little_proximal: 342 | Alpha: 1 343 | Show Axes: false 344 | Show Trail: false 345 | Value: true 346 | r2/right_little_tip: 347 | Alpha: 1 348 | Show Axes: false 349 | Show Trail: false 350 | r2/right_lower_arm: 351 | Alpha: 1 352 | Show Axes: false 353 | Show Trail: false 354 | Value: true 355 | r2/right_middle_base: 356 | Alpha: 1 357 | Show Axes: false 358 | Show Trail: false 359 | r2/right_middle_distal: 360 | Alpha: 1 361 | Show Axes: false 362 | Show Trail: false 363 | Value: true 364 | r2/right_middle_medial: 365 | Alpha: 1 366 | Show Axes: false 367 | Show Trail: false 368 | Value: true 369 | r2/right_middle_proximal: 370 | Alpha: 1 371 | Show Axes: false 372 | Show Trail: false 373 | Value: true 374 | r2/right_middle_tip: 375 | Alpha: 1 376 | Show Axes: false 377 | Show Trail: false 378 | r2/right_middle_yaw: 379 | Alpha: 1 380 | Show Axes: false 381 | Show Trail: false 382 | r2/right_palm: 383 | Alpha: 1 384 | Show Axes: false 385 | Show Trail: false 386 | Value: true 387 | r2/right_ring_distal: 388 | Alpha: 1 389 | Show Axes: false 390 | Show Trail: false 391 | Value: true 392 | r2/right_ring_medial: 393 | Alpha: 1 394 | Show Axes: false 395 | Show Trail: false 396 | Value: true 397 | r2/right_ring_proximal: 398 | Alpha: 1 399 | Show Axes: false 400 | Show Trail: false 401 | Value: true 402 | r2/right_ring_tip: 403 | Alpha: 1 404 | Show Axes: false 405 | Show Trail: false 406 | r2/right_shoulder_pitch: 407 | Alpha: 1 408 | Show Axes: false 409 | Show Trail: false 410 | Value: true 411 | r2/right_shoulder_roll: 412 | Alpha: 1 413 | Show Axes: false 414 | Show Trail: false 415 | Value: true 416 | r2/right_thumb_base: 417 | Alpha: 1 418 | Show Axes: false 419 | Show Trail: false 420 | r2/right_thumb_distal: 421 | Alpha: 1 422 | Show Axes: false 423 | Show Trail: false 424 | Value: true 425 | r2/right_thumb_medial: 426 | Alpha: 1 427 | Show Axes: false 428 | Show Trail: false 429 | Value: true 430 | r2/right_thumb_medial_prime: 431 | Alpha: 1 432 | Show Axes: false 433 | Show Trail: false 434 | Value: true 435 | r2/right_thumb_proximal: 436 | Alpha: 1 437 | Show Axes: false 438 | Show Trail: false 439 | Value: true 440 | r2/right_thumb_tip: 441 | Alpha: 1 442 | Show Axes: false 443 | Show Trail: false 444 | r2/right_upper_arm: 445 | Alpha: 1 446 | Show Axes: false 447 | Show Trail: false 448 | Value: true 449 | r2/right_wrist_pitch: 450 | Alpha: 1 451 | Show Axes: false 452 | Show Trail: false 453 | r2/right_wrist_yaw: 454 | Alpha: 1 455 | Show Axes: false 456 | Show Trail: false 457 | r2/robot_base: 458 | Alpha: 1 459 | Show Axes: false 460 | Show Trail: false 461 | r2/robot_reference: 462 | Alpha: 1 463 | Show Axes: false 464 | Show Trail: false 465 | r2/robot_world: 466 | Alpha: 1 467 | Show Axes: false 468 | Show Trail: false 469 | r2/simulated_asus_camera_frame: 470 | Alpha: 1 471 | Show Axes: false 472 | Show Trail: false 473 | r2/simulated_asus_depth_frame: 474 | Alpha: 1 475 | Show Axes: false 476 | Show Trail: false 477 | r2/stanchion: 478 | Alpha: 1 479 | Show Axes: false 480 | Show Trail: false 481 | Value: true 482 | r2/vision_center_frame: 483 | Alpha: 1 484 | Show Axes: false 485 | Show Trail: false 486 | r2/waist_center: 487 | Alpha: 1 488 | Show Axes: false 489 | Show Trail: false 490 | Value: true 491 | world: 492 | Alpha: 1 493 | Show Axes: false 494 | Show Trail: false 495 | Loop Animation: false 496 | Robot Alpha: 0.25 497 | Robot Color: 150; 50; 150 498 | Show Robot Collision: false 499 | Show Robot Visual: true 500 | Show Trail: false 501 | State Display Time: 0.05 s 502 | Trail Step Size: 1 503 | Trajectory Topic: /move_group/display_planned_path 504 | Planning Metrics: 505 | Payload: 1 506 | Show Joint Torques: false 507 | Show Manipulability: false 508 | Show Manipulability Index: false 509 | Show Weight Limit: false 510 | TextHeight: 0.08 511 | Planning Request: 512 | Colliding Link Color: 255; 0; 0 513 | Goal State Alpha: 1 514 | Goal State Color: 250; 128; 0 515 | Interactive Marker Size: 0.25 516 | Joint Violation Color: 255; 0; 255 517 | Planning Group: head 518 | Query Goal State: true 519 | Query Start State: false 520 | Show Workspace: false 521 | Start State Alpha: 1 522 | Start State Color: 0; 255; 0 523 | Planning Scene Topic: /move_group/monitored_planning_scene 524 | Robot Description: robot_description 525 | Scene Geometry: 526 | Scene Alpha: 1 527 | Scene Color: 50; 230; 50 528 | Scene Display Time: 0.2 529 | Show Scene Geometry: true 530 | Voxel Coloring: Z-Axis 531 | Voxel Rendering: Occupied Voxels 532 | Scene Robot: 533 | Attached Body Color: 150; 50; 150 534 | Links: 535 | All Links Enabled: true 536 | Expand Joint Details: false 537 | Expand Link Details: false 538 | Expand Tree: false 539 | Link Tree Style: Links in Alphabetic Order 540 | r2/asus_frame: 541 | Alpha: 1 542 | Show Axes: false 543 | Show Trail: false 544 | r2/backpack: 545 | Alpha: 1 546 | Show Axes: false 547 | Show Trail: false 548 | Value: true 549 | r2/baseplate: 550 | Alpha: 1 551 | Show Axes: false 552 | Show Trail: false 553 | Value: true 554 | r2/body_cover: 555 | Alpha: 1 556 | Show Axes: false 557 | Show Trail: false 558 | Value: true 559 | r2/chest_base: 560 | Alpha: 1 561 | Show Axes: false 562 | Show Trail: false 563 | r2/chest_center: 564 | Alpha: 1 565 | Show Axes: false 566 | Show Trail: false 567 | r2/left_camera_frame: 568 | Alpha: 1 569 | Show Axes: false 570 | Show Trail: false 571 | r2/left_camera_optical_frame: 572 | Alpha: 1 573 | Show Axes: false 574 | Show Trail: false 575 | r2/left_elbow: 576 | Alpha: 1 577 | Show Axes: false 578 | Show Trail: false 579 | Value: true 580 | r2/left_index_base: 581 | Alpha: 1 582 | Show Axes: false 583 | Show Trail: false 584 | r2/left_index_distal: 585 | Alpha: 1 586 | Show Axes: false 587 | Show Trail: false 588 | Value: true 589 | r2/left_index_medial: 590 | Alpha: 1 591 | Show Axes: false 592 | Show Trail: false 593 | Value: true 594 | r2/left_index_proximal: 595 | Alpha: 1 596 | Show Axes: false 597 | Show Trail: false 598 | Value: true 599 | r2/left_index_tip: 600 | Alpha: 1 601 | Show Axes: false 602 | Show Trail: false 603 | r2/left_index_yaw: 604 | Alpha: 1 605 | Show Axes: false 606 | Show Trail: false 607 | r2/left_little_distal: 608 | Alpha: 1 609 | Show Axes: false 610 | Show Trail: false 611 | Value: true 612 | r2/left_little_medial: 613 | Alpha: 1 614 | Show Axes: false 615 | Show Trail: false 616 | Value: true 617 | r2/left_little_proximal: 618 | Alpha: 1 619 | Show Axes: false 620 | Show Trail: false 621 | Value: true 622 | r2/left_little_tip: 623 | Alpha: 1 624 | Show Axes: false 625 | Show Trail: false 626 | r2/left_lower_arm: 627 | Alpha: 1 628 | Show Axes: false 629 | Show Trail: false 630 | Value: true 631 | r2/left_middle_base: 632 | Alpha: 1 633 | Show Axes: false 634 | Show Trail: false 635 | r2/left_middle_distal: 636 | Alpha: 1 637 | Show Axes: false 638 | Show Trail: false 639 | Value: true 640 | r2/left_middle_medial: 641 | Alpha: 1 642 | Show Axes: false 643 | Show Trail: false 644 | Value: true 645 | r2/left_middle_proximal: 646 | Alpha: 1 647 | Show Axes: false 648 | Show Trail: false 649 | Value: true 650 | r2/left_middle_tip: 651 | Alpha: 1 652 | Show Axes: false 653 | Show Trail: false 654 | r2/left_middle_yaw: 655 | Alpha: 1 656 | Show Axes: false 657 | Show Trail: false 658 | r2/left_palm: 659 | Alpha: 1 660 | Show Axes: false 661 | Show Trail: false 662 | Value: true 663 | r2/left_ring_distal: 664 | Alpha: 1 665 | Show Axes: false 666 | Show Trail: false 667 | Value: true 668 | r2/left_ring_medial: 669 | Alpha: 1 670 | Show Axes: false 671 | Show Trail: false 672 | Value: true 673 | r2/left_ring_proximal: 674 | Alpha: 1 675 | Show Axes: false 676 | Show Trail: false 677 | Value: true 678 | r2/left_ring_tip: 679 | Alpha: 1 680 | Show Axes: false 681 | Show Trail: false 682 | r2/left_shoulder_pitch: 683 | Alpha: 1 684 | Show Axes: false 685 | Show Trail: false 686 | Value: true 687 | r2/left_shoulder_roll: 688 | Alpha: 1 689 | Show Axes: false 690 | Show Trail: false 691 | Value: true 692 | r2/left_thumb_base: 693 | Alpha: 1 694 | Show Axes: false 695 | Show Trail: false 696 | r2/left_thumb_distal: 697 | Alpha: 1 698 | Show Axes: false 699 | Show Trail: false 700 | Value: true 701 | r2/left_thumb_medial: 702 | Alpha: 1 703 | Show Axes: false 704 | Show Trail: false 705 | Value: true 706 | r2/left_thumb_medial_prime: 707 | Alpha: 1 708 | Show Axes: false 709 | Show Trail: false 710 | Value: true 711 | r2/left_thumb_proximal: 712 | Alpha: 1 713 | Show Axes: false 714 | Show Trail: false 715 | Value: true 716 | r2/left_thumb_tip: 717 | Alpha: 1 718 | Show Axes: false 719 | Show Trail: false 720 | r2/left_upper_arm: 721 | Alpha: 1 722 | Show Axes: false 723 | Show Trail: false 724 | Value: true 725 | r2/left_wrist_pitch: 726 | Alpha: 1 727 | Show Axes: false 728 | Show Trail: false 729 | r2/left_wrist_yaw: 730 | Alpha: 1 731 | Show Axes: false 732 | Show Trail: false 733 | r2/neck_base: 734 | Alpha: 1 735 | Show Axes: false 736 | Show Trail: false 737 | Value: true 738 | r2/neck_lower_pitch: 739 | Alpha: 1 740 | Show Axes: false 741 | Show Trail: false 742 | Value: true 743 | r2/neck_roll: 744 | Alpha: 1 745 | Show Axes: false 746 | Show Trail: false 747 | Value: true 748 | r2/neck_upper_pitch: 749 | Alpha: 1 750 | Show Axes: false 751 | Show Trail: false 752 | r2/openni_depth_frame: 753 | Alpha: 1 754 | Show Axes: false 755 | Show Trail: false 756 | r2/right_camera_frame: 757 | Alpha: 1 758 | Show Axes: false 759 | Show Trail: false 760 | r2/right_camera_optical_frame: 761 | Alpha: 1 762 | Show Axes: false 763 | Show Trail: false 764 | r2/right_elbow: 765 | Alpha: 1 766 | Show Axes: false 767 | Show Trail: false 768 | Value: true 769 | r2/right_index_base: 770 | Alpha: 1 771 | Show Axes: false 772 | Show Trail: false 773 | r2/right_index_distal: 774 | Alpha: 1 775 | Show Axes: false 776 | Show Trail: false 777 | Value: true 778 | r2/right_index_medial: 779 | Alpha: 1 780 | Show Axes: false 781 | Show Trail: false 782 | Value: true 783 | r2/right_index_proximal: 784 | Alpha: 1 785 | Show Axes: false 786 | Show Trail: false 787 | Value: true 788 | r2/right_index_tip: 789 | Alpha: 1 790 | Show Axes: false 791 | Show Trail: false 792 | r2/right_index_yaw: 793 | Alpha: 1 794 | Show Axes: false 795 | Show Trail: false 796 | r2/right_little_distal: 797 | Alpha: 1 798 | Show Axes: false 799 | Show Trail: false 800 | Value: true 801 | r2/right_little_medial: 802 | Alpha: 1 803 | Show Axes: false 804 | Show Trail: false 805 | Value: true 806 | r2/right_little_proximal: 807 | Alpha: 1 808 | Show Axes: false 809 | Show Trail: false 810 | Value: true 811 | r2/right_little_tip: 812 | Alpha: 1 813 | Show Axes: false 814 | Show Trail: false 815 | r2/right_lower_arm: 816 | Alpha: 1 817 | Show Axes: false 818 | Show Trail: false 819 | Value: true 820 | r2/right_middle_base: 821 | Alpha: 1 822 | Show Axes: false 823 | Show Trail: false 824 | r2/right_middle_distal: 825 | Alpha: 1 826 | Show Axes: false 827 | Show Trail: false 828 | Value: true 829 | r2/right_middle_medial: 830 | Alpha: 1 831 | Show Axes: false 832 | Show Trail: false 833 | Value: true 834 | r2/right_middle_proximal: 835 | Alpha: 1 836 | Show Axes: false 837 | Show Trail: false 838 | Value: true 839 | r2/right_middle_tip: 840 | Alpha: 1 841 | Show Axes: false 842 | Show Trail: false 843 | r2/right_middle_yaw: 844 | Alpha: 1 845 | Show Axes: false 846 | Show Trail: false 847 | r2/right_palm: 848 | Alpha: 1 849 | Show Axes: false 850 | Show Trail: false 851 | Value: true 852 | r2/right_ring_distal: 853 | Alpha: 1 854 | Show Axes: false 855 | Show Trail: false 856 | Value: true 857 | r2/right_ring_medial: 858 | Alpha: 1 859 | Show Axes: false 860 | Show Trail: false 861 | Value: true 862 | r2/right_ring_proximal: 863 | Alpha: 1 864 | Show Axes: false 865 | Show Trail: false 866 | Value: true 867 | r2/right_ring_tip: 868 | Alpha: 1 869 | Show Axes: false 870 | Show Trail: false 871 | r2/right_shoulder_pitch: 872 | Alpha: 1 873 | Show Axes: false 874 | Show Trail: false 875 | Value: true 876 | r2/right_shoulder_roll: 877 | Alpha: 1 878 | Show Axes: false 879 | Show Trail: false 880 | Value: true 881 | r2/right_thumb_base: 882 | Alpha: 1 883 | Show Axes: false 884 | Show Trail: false 885 | r2/right_thumb_distal: 886 | Alpha: 1 887 | Show Axes: false 888 | Show Trail: false 889 | Value: true 890 | r2/right_thumb_medial: 891 | Alpha: 1 892 | Show Axes: false 893 | Show Trail: false 894 | Value: true 895 | r2/right_thumb_medial_prime: 896 | Alpha: 1 897 | Show Axes: false 898 | Show Trail: false 899 | Value: true 900 | r2/right_thumb_proximal: 901 | Alpha: 1 902 | Show Axes: false 903 | Show Trail: false 904 | Value: true 905 | r2/right_thumb_tip: 906 | Alpha: 1 907 | Show Axes: false 908 | Show Trail: false 909 | r2/right_upper_arm: 910 | Alpha: 1 911 | Show Axes: false 912 | Show Trail: false 913 | Value: true 914 | r2/right_wrist_pitch: 915 | Alpha: 1 916 | Show Axes: false 917 | Show Trail: false 918 | r2/right_wrist_yaw: 919 | Alpha: 1 920 | Show Axes: false 921 | Show Trail: false 922 | r2/robot_base: 923 | Alpha: 1 924 | Show Axes: false 925 | Show Trail: false 926 | r2/robot_reference: 927 | Alpha: 1 928 | Show Axes: false 929 | Show Trail: false 930 | r2/robot_world: 931 | Alpha: 1 932 | Show Axes: false 933 | Show Trail: false 934 | r2/simulated_asus_camera_frame: 935 | Alpha: 1 936 | Show Axes: false 937 | Show Trail: false 938 | r2/simulated_asus_depth_frame: 939 | Alpha: 1 940 | Show Axes: false 941 | Show Trail: false 942 | r2/stanchion: 943 | Alpha: 1 944 | Show Axes: false 945 | Show Trail: false 946 | Value: true 947 | r2/vision_center_frame: 948 | Alpha: 1 949 | Show Axes: false 950 | Show Trail: false 951 | r2/waist_center: 952 | Alpha: 1 953 | Show Axes: false 954 | Show Trail: false 955 | Value: true 956 | world: 957 | Alpha: 1 958 | Show Axes: false 959 | Show Trail: false 960 | Robot Alpha: 0.5 961 | Show Robot Collision: false 962 | Show Robot Visual: true 963 | Value: true 964 | - Alpha: 1 965 | Class: rviz/RobotModel 966 | Collision Enabled: false 967 | Enabled: true 968 | Links: 969 | All Links Enabled: true 970 | Expand Joint Details: false 971 | Expand Link Details: false 972 | Expand Tree: false 973 | Link Tree Style: Links in Alphabetic Order 974 | r2/asus_frame: 975 | Alpha: 1 976 | Show Axes: false 977 | Show Trail: false 978 | r2/backpack: 979 | Alpha: 1 980 | Show Axes: false 981 | Show Trail: false 982 | Value: true 983 | r2/baseplate: 984 | Alpha: 1 985 | Show Axes: false 986 | Show Trail: false 987 | Value: true 988 | r2/body_cover: 989 | Alpha: 1 990 | Show Axes: false 991 | Show Trail: false 992 | Value: true 993 | r2/chest_base: 994 | Alpha: 1 995 | Show Axes: false 996 | Show Trail: false 997 | r2/chest_center: 998 | Alpha: 1 999 | Show Axes: false 1000 | Show Trail: false 1001 | r2/left_camera_frame: 1002 | Alpha: 1 1003 | Show Axes: false 1004 | Show Trail: false 1005 | r2/left_camera_optical_frame: 1006 | Alpha: 1 1007 | Show Axes: false 1008 | Show Trail: false 1009 | r2/left_elbow: 1010 | Alpha: 1 1011 | Show Axes: false 1012 | Show Trail: false 1013 | Value: true 1014 | r2/left_index_base: 1015 | Alpha: 1 1016 | Show Axes: false 1017 | Show Trail: false 1018 | r2/left_index_distal: 1019 | Alpha: 1 1020 | Show Axes: false 1021 | Show Trail: false 1022 | Value: true 1023 | r2/left_index_medial: 1024 | Alpha: 1 1025 | Show Axes: false 1026 | Show Trail: false 1027 | Value: true 1028 | r2/left_index_proximal: 1029 | Alpha: 1 1030 | Show Axes: false 1031 | Show Trail: false 1032 | Value: true 1033 | r2/left_index_tip: 1034 | Alpha: 1 1035 | Show Axes: false 1036 | Show Trail: false 1037 | r2/left_index_yaw: 1038 | Alpha: 1 1039 | Show Axes: false 1040 | Show Trail: false 1041 | r2/left_little_distal: 1042 | Alpha: 1 1043 | Show Axes: false 1044 | Show Trail: false 1045 | Value: true 1046 | r2/left_little_medial: 1047 | Alpha: 1 1048 | Show Axes: false 1049 | Show Trail: false 1050 | Value: true 1051 | r2/left_little_proximal: 1052 | Alpha: 1 1053 | Show Axes: false 1054 | Show Trail: false 1055 | Value: true 1056 | r2/left_little_tip: 1057 | Alpha: 1 1058 | Show Axes: false 1059 | Show Trail: false 1060 | r2/left_lower_arm: 1061 | Alpha: 1 1062 | Show Axes: false 1063 | Show Trail: false 1064 | Value: true 1065 | r2/left_middle_base: 1066 | Alpha: 1 1067 | Show Axes: false 1068 | Show Trail: false 1069 | r2/left_middle_distal: 1070 | Alpha: 1 1071 | Show Axes: false 1072 | Show Trail: false 1073 | Value: true 1074 | r2/left_middle_medial: 1075 | Alpha: 1 1076 | Show Axes: false 1077 | Show Trail: false 1078 | Value: true 1079 | r2/left_middle_proximal: 1080 | Alpha: 1 1081 | Show Axes: false 1082 | Show Trail: false 1083 | Value: true 1084 | r2/left_middle_tip: 1085 | Alpha: 1 1086 | Show Axes: false 1087 | Show Trail: false 1088 | r2/left_middle_yaw: 1089 | Alpha: 1 1090 | Show Axes: false 1091 | Show Trail: false 1092 | r2/left_palm: 1093 | Alpha: 1 1094 | Show Axes: false 1095 | Show Trail: false 1096 | Value: true 1097 | r2/left_ring_distal: 1098 | Alpha: 1 1099 | Show Axes: false 1100 | Show Trail: false 1101 | Value: true 1102 | r2/left_ring_medial: 1103 | Alpha: 1 1104 | Show Axes: false 1105 | Show Trail: false 1106 | Value: true 1107 | r2/left_ring_proximal: 1108 | Alpha: 1 1109 | Show Axes: false 1110 | Show Trail: false 1111 | Value: true 1112 | r2/left_ring_tip: 1113 | Alpha: 1 1114 | Show Axes: false 1115 | Show Trail: false 1116 | r2/left_shoulder_pitch: 1117 | Alpha: 1 1118 | Show Axes: false 1119 | Show Trail: false 1120 | Value: true 1121 | r2/left_shoulder_roll: 1122 | Alpha: 1 1123 | Show Axes: false 1124 | Show Trail: false 1125 | Value: true 1126 | r2/left_thumb_base: 1127 | Alpha: 1 1128 | Show Axes: false 1129 | Show Trail: false 1130 | r2/left_thumb_distal: 1131 | Alpha: 1 1132 | Show Axes: false 1133 | Show Trail: false 1134 | Value: true 1135 | r2/left_thumb_medial: 1136 | Alpha: 1 1137 | Show Axes: false 1138 | Show Trail: false 1139 | Value: true 1140 | r2/left_thumb_medial_prime: 1141 | Alpha: 1 1142 | Show Axes: false 1143 | Show Trail: false 1144 | Value: true 1145 | r2/left_thumb_proximal: 1146 | Alpha: 1 1147 | Show Axes: false 1148 | Show Trail: false 1149 | Value: true 1150 | r2/left_thumb_tip: 1151 | Alpha: 1 1152 | Show Axes: false 1153 | Show Trail: false 1154 | r2/left_upper_arm: 1155 | Alpha: 1 1156 | Show Axes: false 1157 | Show Trail: false 1158 | Value: true 1159 | r2/left_wrist_pitch: 1160 | Alpha: 1 1161 | Show Axes: false 1162 | Show Trail: false 1163 | r2/left_wrist_yaw: 1164 | Alpha: 1 1165 | Show Axes: false 1166 | Show Trail: false 1167 | r2/neck_base: 1168 | Alpha: 1 1169 | Show Axes: false 1170 | Show Trail: false 1171 | Value: true 1172 | r2/neck_lower_pitch: 1173 | Alpha: 1 1174 | Show Axes: false 1175 | Show Trail: false 1176 | Value: true 1177 | r2/neck_roll: 1178 | Alpha: 1 1179 | Show Axes: false 1180 | Show Trail: false 1181 | Value: true 1182 | r2/neck_upper_pitch: 1183 | Alpha: 1 1184 | Show Axes: false 1185 | Show Trail: false 1186 | r2/openni_depth_frame: 1187 | Alpha: 1 1188 | Show Axes: false 1189 | Show Trail: false 1190 | r2/right_camera_frame: 1191 | Alpha: 1 1192 | Show Axes: false 1193 | Show Trail: false 1194 | r2/right_camera_optical_frame: 1195 | Alpha: 1 1196 | Show Axes: false 1197 | Show Trail: false 1198 | r2/right_elbow: 1199 | Alpha: 1 1200 | Show Axes: false 1201 | Show Trail: false 1202 | Value: true 1203 | r2/right_index_base: 1204 | Alpha: 1 1205 | Show Axes: false 1206 | Show Trail: false 1207 | r2/right_index_distal: 1208 | Alpha: 1 1209 | Show Axes: false 1210 | Show Trail: false 1211 | Value: true 1212 | r2/right_index_medial: 1213 | Alpha: 1 1214 | Show Axes: false 1215 | Show Trail: false 1216 | Value: true 1217 | r2/right_index_proximal: 1218 | Alpha: 1 1219 | Show Axes: false 1220 | Show Trail: false 1221 | Value: true 1222 | r2/right_index_tip: 1223 | Alpha: 1 1224 | Show Axes: false 1225 | Show Trail: false 1226 | r2/right_index_yaw: 1227 | Alpha: 1 1228 | Show Axes: false 1229 | Show Trail: false 1230 | r2/right_little_distal: 1231 | Alpha: 1 1232 | Show Axes: false 1233 | Show Trail: false 1234 | Value: true 1235 | r2/right_little_medial: 1236 | Alpha: 1 1237 | Show Axes: false 1238 | Show Trail: false 1239 | Value: true 1240 | r2/right_little_proximal: 1241 | Alpha: 1 1242 | Show Axes: false 1243 | Show Trail: false 1244 | Value: true 1245 | r2/right_little_tip: 1246 | Alpha: 1 1247 | Show Axes: false 1248 | Show Trail: false 1249 | r2/right_lower_arm: 1250 | Alpha: 1 1251 | Show Axes: false 1252 | Show Trail: false 1253 | Value: true 1254 | r2/right_middle_base: 1255 | Alpha: 1 1256 | Show Axes: false 1257 | Show Trail: false 1258 | r2/right_middle_distal: 1259 | Alpha: 1 1260 | Show Axes: false 1261 | Show Trail: false 1262 | Value: true 1263 | r2/right_middle_medial: 1264 | Alpha: 1 1265 | Show Axes: false 1266 | Show Trail: false 1267 | Value: true 1268 | r2/right_middle_proximal: 1269 | Alpha: 1 1270 | Show Axes: false 1271 | Show Trail: false 1272 | Value: true 1273 | r2/right_middle_tip: 1274 | Alpha: 1 1275 | Show Axes: false 1276 | Show Trail: false 1277 | r2/right_middle_yaw: 1278 | Alpha: 1 1279 | Show Axes: false 1280 | Show Trail: false 1281 | r2/right_palm: 1282 | Alpha: 1 1283 | Show Axes: false 1284 | Show Trail: false 1285 | Value: true 1286 | r2/right_ring_distal: 1287 | Alpha: 1 1288 | Show Axes: false 1289 | Show Trail: false 1290 | Value: true 1291 | r2/right_ring_medial: 1292 | Alpha: 1 1293 | Show Axes: false 1294 | Show Trail: false 1295 | Value: true 1296 | r2/right_ring_proximal: 1297 | Alpha: 1 1298 | Show Axes: false 1299 | Show Trail: false 1300 | Value: true 1301 | r2/right_ring_tip: 1302 | Alpha: 1 1303 | Show Axes: false 1304 | Show Trail: false 1305 | r2/right_shoulder_pitch: 1306 | Alpha: 1 1307 | Show Axes: false 1308 | Show Trail: false 1309 | Value: true 1310 | r2/right_shoulder_roll: 1311 | Alpha: 1 1312 | Show Axes: false 1313 | Show Trail: false 1314 | Value: true 1315 | r2/right_thumb_base: 1316 | Alpha: 1 1317 | Show Axes: false 1318 | Show Trail: false 1319 | r2/right_thumb_distal: 1320 | Alpha: 1 1321 | Show Axes: false 1322 | Show Trail: false 1323 | Value: true 1324 | r2/right_thumb_medial: 1325 | Alpha: 1 1326 | Show Axes: false 1327 | Show Trail: false 1328 | Value: true 1329 | r2/right_thumb_medial_prime: 1330 | Alpha: 1 1331 | Show Axes: false 1332 | Show Trail: false 1333 | Value: true 1334 | r2/right_thumb_proximal: 1335 | Alpha: 1 1336 | Show Axes: false 1337 | Show Trail: false 1338 | Value: true 1339 | r2/right_thumb_tip: 1340 | Alpha: 1 1341 | Show Axes: false 1342 | Show Trail: false 1343 | r2/right_upper_arm: 1344 | Alpha: 1 1345 | Show Axes: false 1346 | Show Trail: false 1347 | Value: true 1348 | r2/right_wrist_pitch: 1349 | Alpha: 1 1350 | Show Axes: false 1351 | Show Trail: false 1352 | r2/right_wrist_yaw: 1353 | Alpha: 1 1354 | Show Axes: false 1355 | Show Trail: false 1356 | r2/robot_base: 1357 | Alpha: 1 1358 | Show Axes: false 1359 | Show Trail: false 1360 | r2/robot_reference: 1361 | Alpha: 1 1362 | Show Axes: false 1363 | Show Trail: false 1364 | r2/robot_world: 1365 | Alpha: 1 1366 | Show Axes: false 1367 | Show Trail: false 1368 | r2/simulated_asus_camera_frame: 1369 | Alpha: 1 1370 | Show Axes: false 1371 | Show Trail: false 1372 | r2/simulated_asus_depth_frame: 1373 | Alpha: 1 1374 | Show Axes: false 1375 | Show Trail: false 1376 | r2/stanchion: 1377 | Alpha: 1 1378 | Show Axes: false 1379 | Show Trail: false 1380 | Value: true 1381 | r2/vision_center_frame: 1382 | Alpha: 1 1383 | Show Axes: false 1384 | Show Trail: false 1385 | r2/waist_center: 1386 | Alpha: 1 1387 | Show Axes: false 1388 | Show Trail: false 1389 | Value: true 1390 | world: 1391 | Alpha: 1 1392 | Show Axes: false 1393 | Show Trail: false 1394 | Name: RobotModel 1395 | Robot Description: robot_description 1396 | TF Prefix: "" 1397 | Update Interval: 0 1398 | Value: true 1399 | Visual Enabled: true 1400 | - Class: rviz/InteractiveMarkers 1401 | Enable Transparency: true 1402 | Enabled: true 1403 | Name: Teleop Markers 1404 | Show Axes: false 1405 | Show Descriptions: true 1406 | Show Visual Aids: false 1407 | Update Topic: /r2_teleop/update 1408 | Value: true 1409 | - Class: rviz/MarkerArray 1410 | Enabled: true 1411 | Marker Topic: /r2/move_group/planned_path_visualization 1412 | Name: Path Visualization 1413 | Namespaces: 1414 | {} 1415 | Queue Size: 100 1416 | Value: true 1417 | - Class: rviz/Camera 1418 | Enabled: false 1419 | Image Rendering: background and overlay 1420 | Image Topic: /r2/asus/rgb/image_raw 1421 | Name: Asus Camera 1422 | Overlay Alpha: 0.5 1423 | Queue Size: 2 1424 | Transport Hint: raw 1425 | Unreliable: false 1426 | Value: false 1427 | Visibility: 1428 | "": true 1429 | Asus: true 1430 | Grid: false 1431 | MotionPlanning: true 1432 | OccupancyGrid: true 1433 | Path Visualization: true 1434 | RobotModel: false 1435 | Teleop Markers: true 1436 | Value: true 1437 | Zoom Factor: 1 1438 | - Class: octomap_rviz_plugin/OccupancyGrid 1439 | Enabled: false 1440 | Max. Octree Depth: 16 1441 | Name: OccupancyGrid 1442 | Octomap Topic: /octomap_full 1443 | Queue Size: 5 1444 | Value: false 1445 | Voxel Coloring: Z-Axis 1446 | Voxel Rendering: Occupied Voxels 1447 | - Alpha: 1 1448 | Autocompute Intensity Bounds: true 1449 | Autocompute Value Bounds: 1450 | Max Value: 10 1451 | Min Value: -10 1452 | Value: true 1453 | Axis: Z 1454 | Channel Name: intensity 1455 | Class: rviz/PointCloud2 1456 | Color: 255; 255; 255 1457 | Color Transformer: RGB8 1458 | Decay Time: 0 1459 | Enabled: true 1460 | Invert Rainbow: false 1461 | Max Color: 255; 255; 255 1462 | Max Intensity: 4096 1463 | Min Color: 0; 0; 0 1464 | Min Intensity: 0 1465 | Name: Asus 1466 | Position Transformer: XYZ 1467 | Queue Size: 10 1468 | Selectable: true 1469 | Size (Pixels): 3 1470 | Size (m): 0.01 1471 | Style: Points 1472 | Topic: /r2/asus/depth/points 1473 | Unreliable: false 1474 | Use Fixed Frame: true 1475 | Use rainbow: true 1476 | Value: true 1477 | - Class: rviz/InteractiveMarkers 1478 | Enable Transparency: true 1479 | Enabled: true 1480 | Name: InteractiveMarkers 1481 | Show Axes: false 1482 | Show Descriptions: true 1483 | Show Visual Aids: false 1484 | Update Topic: /affordance_template_interactive_marker_server/update 1485 | Value: true 1486 | Enabled: true 1487 | Global Options: 1488 | Background Color: 0; 0; 0 1489 | Fixed Frame: world 1490 | Frame Rate: 30 1491 | Name: root 1492 | Tools: 1493 | - Class: rviz/Interact 1494 | Hide Inactive Objects: true 1495 | - Class: rviz/MoveCamera 1496 | - Class: rviz/Select 1497 | Value: true 1498 | Views: 1499 | Current: 1500 | Class: rviz/XYOrbit 1501 | Distance: 3.38274 1502 | Enable Stereo Rendering: 1503 | Stereo Eye Separation: 0.06 1504 | Stereo Focal Distance: 1 1505 | Swap Stereo Eyes: false 1506 | Value: false 1507 | Focal Point: 1508 | X: -0.140022 1509 | Y: -0.3995 1510 | Z: 2.19047e-06 1511 | Name: Current View 1512 | Near Clip Distance: 0.01 1513 | Pitch: 0.394796 1514 | Target Frame: world 1515 | Value: XYOrbit (rviz) 1516 | Yaw: 6.00102 1517 | Saved: ~ 1518 | Window Geometry: 1519 | Asus Camera: 1520 | collapsed: false 1521 | Displays: 1522 | collapsed: false 1523 | Height: 1016 1524 | Help: 1525 | collapsed: false 1526 | Hide Left Dock: false 1527 | Hide Right Dock: false 1528 | MotionPlanning: 1529 | collapsed: false 1530 | MotionPlanning - Slider: 1531 | collapsed: false 1532 | QMainWindow State: 000000ff00000000fd000000020000000000000258000003a8fc0200000007fb000000100044006900730070006c006100790073010000003600000120000000b700fffffffb0000001c004d006f00740069006f006e0050006c0061006e006e0069006e0067010000015c000002820000019800fffffffb0000000a0049006d00610067006500000002b7000001c00000000000000000fb0000000a0056006900650077007300000003b0000000b00000009b00fffffffb000000160041007300750073002000430061006d00650072006102000000a40000008f000003f900000302fc00000461000000160000000000fffffffa000000000100000002fb0000000c00430061006d0065007200610100000000ffffffff0000000000000000fb0000001e004d006f00740069006f006e00200050006c0061006e006e0069006e006700000000000000026f0000000000000000fb0000002e004d006f00740069006f006e0050006c0061006e006e0069006e00670020002d00200053006c00690064006500720000000000ffffffff0000004100ffffff0000000100000193000003a8fc0200000002fc00000036000003a80000030a00fffffffa000000000100000002fb00000036005200560069007a004100660066006f007200640061006e0063006500540065006d0070006c00610074006500500061006e0065006c0100000000ffffffff0000019300fffffffb0000000800480065006c007000000006fe000002b80000004f00fffffffb00000038005200560069007a0049006e0074006500720061006300740069007600650043006f006e00740072006f006c007300500061006e0065006c0000000036000002400000024000ffffff000005bf000003a800000001000000020000000100000002fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 1533 | RVizAffordanceTemplatePanel: 1534 | collapsed: false 1535 | RVizInteractiveControlsPanel: 1536 | collapsed: false 1537 | Views: 1538 | collapsed: false 1539 | Width: 2486 1540 | X: 73 1541 | Y: 26 1542 | --------------------------------------------------------------------------------