Skip to content

Commit

Permalink
Merge pull request #44 from j3soon/refactor/template-ws
Browse files Browse the repository at this point in the history
Refactor `template_ws`
  • Loading branch information
j3soon authored Aug 21, 2024
2 parents 443c2bb + 4852dfe commit aae39be
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 93 deletions.
2 changes: 0 additions & 2 deletions scripts/create_workspace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ cp -r "${TEMPLATE_WS_DIR}" "${NEW_WS_DIR}"
rm -rf "${NEW_WS_DIR}/.vscode"
rm -rf "${NEW_WS_DIR}/build" "${NEW_WS_DIR}/install" "${NEW_WS_DIR}/log"
rm -rf "${NEW_WS_DIR}/README.md"
rm -rf "${NEW_WS_DIR}/docker/cache/.gazebo/*"
touch "${NEW_WS_DIR}/docker/cache/.gazebo/.gitkeep"
echo "# ${NEW_WS_NAME_UNDERSCORE}" > "${NEW_WS_DIR}/README.md"

# Replace the "template_ws" with new workspace name in each file.
Expand Down
6 changes: 2 additions & 4 deletions template_ws/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"dockerComposeFile": "../docker/compose.yaml",
"service": "template-ws",
// workspace settings
"workspaceFolder": "/home/ros2-agv-essentials/template_ws",
"workspaceFolder": "/home/ros2-essentials/template_ws",
// Vscode extensions
"customizations": {
"vscode": {
Expand All @@ -19,7 +19,5 @@
"ms-iot.vscode-ros"
]
}
},
// Lifecycle scripts
"postCreateCommand": "${containerWorkspaceFolder}/.devcontainer/postCreateCommand.sh"
}
}
6 changes: 0 additions & 6 deletions template_ws/.devcontainer/postCreateCommand.sh

This file was deleted.

8 changes: 1 addition & 7 deletions template_ws/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,4 @@
# ROS2 basic directories
/build
/install
/log

# Gazebo cache
docker/cache/*
!docker/cache/.gazebo
docker/cache/.gazebo/*
!docker/cache/.gazebo/.gitkeep
/log
41 changes: 22 additions & 19 deletions template_ws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ This template will help you set up a ROS-Humble environment quickly.
Here is the structure of this template:

```
ros2-agv-essentials
ros2-essentials
├── scripts
| └── create_workspace.sh
├── template_ws
| ├── .devcontainer
| | ├── devcontainer.json
| | └── postCreateCommand.sh
| | └── devcontainer.json
| ├── docker
| | ├── cache
| | | └── .gazebo
| | ├── .bashrc
| | ├── .dockerignore
| | ├── compose.yaml
| | └── Dockerfile
| ├── install
Expand All @@ -34,7 +32,6 @@ ros2-agv-essentials
```

- `build` / `install` / `log` folders will appear once you've built the packages.
- `minimal_pkg` is the ROS2 package used to create a publisher and subscriber in both Python and C++. You can remove it if you don't need it.

## 🚩 How to use this template 🚩

Expand All @@ -43,25 +40,27 @@ ros2-agv-essentials
We have provided a script to create a new workspace. Please use it to avoid potential issues.

```bash
# Open a terminal, and change the directory to ros2-agv-essentials.
# Open a terminal, and change the directory to ros2-essentials.
./scripts/create_workspace.sh <new_workspace_name>
```

> To unify the naming style, we will modify the string `<new_workspace_name>` in some files.
### 2. Configure Docker settings.
### 2. Configure settings.

> To help you easily find where changes are needed, we have marked most of the areas you need to adjust with `# TODO:`. Usually, you only need to modify the configurations without removing anything. If you really need to remove something, make sure you clearly understand your goal and proceed with caution.
- `docker/Dockerfile`
- Check whether the default Dockerfile meets your requirements. If not, feel free to modify the contents. In most cases, you may want to install additional tools for ROS packages.
- Add the packages you need according to the comments inside.
- `docker/compose.yaml`
- By default, the Docker image is built according to your current computer's architecture. If you need to cross-compile, please modify the `platforms` parameter to your desired architecture and set up the basic environment.
- If you want to access the GPU in the container, please uncomment the lines accordingly.
- If you want to add any environment variables in the container, you can include them in the `environment` section, or you can use `export VARIABLE=/the/value` in `docker/.bashrc`.
- `.devcontainer/devcontainer.json`
- Update the `name` to match your project.
- Add any extensions you want in the `Vscode extensions`.
- If you change the service name in `compose.yaml`, please update the setting in the `service` section accordingly.
- `.devcontainer/postCreateCommand.sh`
- This script will be executed after the container-building process. Feel free to add any desired commands here.
- `docker/.bashrc`
- We will automatically compile the workspace in .bashrc. If you don't want this to happen, feel free to remove it. If you’re okay with it, remember to adjust the compilation commands according to your packages.
- `src`
- Add the ros packages you need here.
- `minimal_pkg` is the ROS2 package used to create a publisher and subscriber in both Python and C++. You can remove it if you don't need it.

### 3. Open the workspace folder using Visual Studio Code.

Expand All @@ -70,13 +69,14 @@ We have provided a script to create a new workspace. Please use it to avoid pote
> Please refer to the tutorial provided by Visual Studio Code first.
> You can find it here: [https://code.visualstudio.com/docs/devcontainers/containers](https://code.visualstudio.com/docs/devcontainers/containers)
Spotting the workspace folder within your Explorer indicates that you've selected the wrong folder.
You should only observe the `.devcontainer`, `docker` and `src` folders there.
> We recommend using `VScode` + `devcontainer` for development. This plugin can significantly reduce development costs and can be used on local computers, remote servers, and even embedded systems. If you don't want to use `devcontainer`, you can still use Docker commands for development, such as `docker compose up` and `docker exec`.
**Note**: Alternatively, you can use `docker compose` instead of `devcontainer` if you are not using VSCode.
Open the workspace folder using Visual Studio Code, spotting the workspace folder within your Explorer indicates that you've selected the wrong folder. You should only observe the `.devcontainer`, `docker` and `src` folders there.

### 4. Build the container.

> We have pre-built some Docker images on Docker Hub. If the building time is too long, you might consider downloading them from Docker Hub instead. For more information, please refer to the `README.md` on the repository's main page.
Press `F1` and enter `> Dev Containers: Rebuild Container`.
Building the images and container will take some time. Please be patient.

Expand All @@ -86,6 +86,8 @@ You should see the output below.
Done. Press any key to close the terminal.
```

> For non-devcontainer users, please navigate to the `docker` folder and use `docker compose build` to build the container. We have moved all commands that need to be executed into the `.bashrc` file. No further action is needed after creating the Docker container.
### 5. Start to develop with ROS.

You've successfully completed all the instructions.
Expand All @@ -94,4 +96,5 @@ Wishing you a productive and successful journey in your ROS development !
## ⚠️ Warning ⚠️

- Do not place your files in any folder named `build`, `install`, or `log`. These folders will not be tracked by Git.
- If you encounter an error when opening Gazebo, consider closing the container and deleting the cache in the `docker/cache` directory. Please note that you should only delete the files inside the folder and not the entire cache folder.
- If you encounter an error when opening Gazebo, consider closing the container and reopen it. Alternatively, you can check the log output in `~/.gazebo`, which may contain relevant error messages. The most common issue is using a duplicate port, which prevents Gazebo from starting. You can use `lsof -i:11345` to identify which process is using the port and then use `kill -9` to terminate it.
- `xhost +local:docker` is required if the container is not in privileged mode.
26 changes: 25 additions & 1 deletion template_ws/docker/.bashrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
# Source global ROS2 environment
source /opt/ros/$ROS_DISTRO/setup.bash
# Optionally perform apt update if it has not been executed yet
if [ -z "$( ls -A '/var/lib/apt/lists' )" ]; then
echo "apt-get update has not been executed yet. Running sudo apt-get update..."
sudo apt-get update
fi
# Optionally perform rosdep update if it has not been executed yet
if [ ! -d $HOME/.ros/rosdep/sources.cache ]; then
echo "rosdep update has not been executed yet. Running rosdep update..."
rosdep update
fi
# Optionally build the workspace if it has not been built yet
if [ ! -f $ROS2_WS/install/setup.bash ]; then
echo "Workspace has not been built yet. Building workspace..."
cd $ROS2_WS
# Ref: https://docs.ros.org/en/humble/Tutorials/Intermediate/Rosdep.html
rosdep install --from-paths src --ignore-src -y -r
# TODO: If command `arch` outputs `aarch64`, consider adding `--packages-ignore <package>` to ignore x86 packages
# Ref: https://docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html
if [ $(arch) == "aarch64" ]; then
colcon build --symlink-install
else
colcon build --symlink-install
fi
echo "Workspace built."
fi
# Source workspace environment
# Note: If you have not built your workspace yet, the following command will fail
source $ROS2_WS/install/setup.bash
96 changes: 68 additions & 28 deletions template_ws/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,52 +1,92 @@
# Base Image : https://hub.docker.com/r/osrf/ros/tags?page=1&name=humble
FROM osrf/ros:humble-desktop-full
FROM osrf/ros:humble-desktop-full AS amd64
# Base Image : https://hub.docker.com/r/arm64v8/ros/tags?page=1&name=humble
FROM arm64v8/ros:humble AS arm64

LABEL org.opencontainers.image.authors="[email protected]"
# Use docker automatic platform args to select the base image.
# It may be `arm64` or `amd64` depending on the platform.
# Ref: https://docs.docker.com/reference/dockerfile/#automatic-platform-args-in-the-global-scope
FROM $TARGETARCH

# Arguments for the default user
ARG USERNAME=user
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
#
# [Optional] Add sudo support. Omit if you don't need to install software after connecting.
&& apt-get update \
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get upgrade -y \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y python3-pip \

# Keep downloaded packages for caching purposes
# Ref: https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#example-cache-apt-packages
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache

# Upgrade packages
# Ref: https://pythonspeed.com/articles/security-updates-in-docker/
# Ref: https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#example-cache-apt-packages
# Ref: https://github.com/moby/buildkit/issues/1673#issuecomment-1264502398
# Ref: https://github.com/moby/buildkit/issues/1673#issuecomment-1987107404
RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
apt-get update && apt-get upgrade -y \
&& rm -rf /var/lib/apt/lists/*
ENV SHELL /bin/bash

# ********************************************************
# * Anything else you want to do like clean up goes here *
# ********************************************************
# Install sudo and create a user with sudo privileges
# Ref: https://stackoverflow.com/a/65434659
RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
apt-get update && apt-get install -y sudo \
&& useradd -m -s /bin/bash -u $USER_UID -G sudo $USERNAME \
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
&& rm -rf /var/lib/apt/lists/*

# Install common tools
RUN apt-get update && apt-get install -y \
RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
apt-get update && apt-get install -y \
curl \
git \
git-extras \
htop \
iputils-ping \
nano \
net-tools \
tmux \
tree \
unzip \
vim \
wget \
zip \
&& rm -rf /var/lib/apt/lists/*

# Install Python pip
RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
apt-get update && apt-get install -y \
python3-pip \
&& rm -rf /var/lib/apt/lists/*

# Install custom tools
RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
apt-get update && apt-get install -y \
git-extras \
&& rm -rf /var/lib/apt/lists/*

# Install ROS2 RVIZ and Gazebo
RUN apt-get update && apt-get install -y \
ros-$ROS_DISTRO-gazebo-ros-pkgs \
# Install ROS2 Gazebo packages for amd64
RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
if [ "$TARGETARCH" = "amd64" ]; then \
apt-get update && apt-get install -y \
ros-$ROS_DISTRO-gazebo-ros-pkgs \
ros-$ROS_DISTRO-gazebo-ros2-control \
&& rm -rf /var/lib/apt/lists/*; \
fi

# Install ROS2 RVIZ and other custom ROS2 packages
RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
apt-get update && apt-get install -y \
ros-$ROS_DISTRO-rviz2 \
&& rm -rf /var/lib/apt/lists/*

COPY .bashrc /home/$USERNAME/.bashrc
# TODO: Add more commands here
# For example, to install additional packages, uncomment the following lines and add the package names
# RUN --mount=type=cache,target=/var/cache/apt,sharing=private \
# apt-get update && apt-get install -y \
# $OTHER_PACKAGES \
# && rm -rf /var/lib/apt/lists/*

# [Optional] Set the default user. Omit if you want to keep the default as root.
USER $USERNAME
COPY .bashrc /home/$USERNAME/.bashrc
# Create Gazebo cache directory with correct ownership to avoid permission issues after volume mount
RUN mkdir /home/$USERNAME/.gazebo
ENTRYPOINT []
CMD ["/bin/bash"]
Empty file.
65 changes: 39 additions & 26 deletions template_ws/docker/compose.yaml
Original file line number Diff line number Diff line change
@@ -1,53 +1,66 @@
services:
template-ws:
build: .
build:
context: .
dockerfile: Dockerfile
# TODO: Specify the target platform to build the image, otherwise it will build for the host platform.
# Reference: https://docs.docker.com/compose/compose-file/build/#platforms
# platforms:
# - "linux/arm64"
image: j3soon/ros2-template-ws
container_name: ros2-template-ws
stdin_open: true
tty: true
# TODO: Comment the line below if the workspace don't need to communicate through `/dev/*` devices.
privileged: true
command: /bin/bash
network_mode: host
working_dir: /home/ros2-agv-essentials/template_ws
working_dir: /home/ros2-essentials/template_ws
environment:
- DISPLAY=${DISPLAY}
# Set ros2 environment variables.
# Set X11 server environment variable for existing display.
- DISPLAY=$DISPLAY
# TODO: Set ros2 environment variables.
# References:
# - https://docs.ros.org/en/humble/Concepts/Intermediate/About-Domain-ID.html
# - https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html
# - https://docs.ros.org/en/humble/Tutorials/Demos/Logging-and-logger-configuration.html#console-output-colorizing
- ROS_LOCALHOST_ONLY=1
- ROS_DOMAIN_ID=42
- ROS2_WS=/home/ros2-agv-essentials/template_ws
- ROS_LOCALHOST_ONLY=0
# Localhost only is disabled by default to allow communication with external devices.
- ROS_DOMAIN_ID=0
# Domain ID is set to 0 to allow communication through ros1_bridge.
- RCUTILS_COLORIZED_OUTPUT=1
# If you want to access GPU, please uncomment the lines below.
# Reference : https://docs.docker.com/compose/gpu-support/
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [ gpu ]
- ROS2_WS=/home/ros2-essentials/template_ws
# TODO: Uncomment the lines below to enable GPU support.
# deploy:
# # Reference : https://docs.docker.com/compose/gpu-support/
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [ gpu ]
volumes:
# Mount local timezone into container. ( Readonly )
# Mount local timezone into container.
# Reference: https://stackoverflow.com/questions/57607381/how-do-i-change-timezone-in-a-docker-container
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
# Mount X11 server
- /tmp/.X11-unix:/tmp/.X11-unix
# X11-unix is mounted to allow GUI applications to display on host.
- $HOME/.Xauthority:/home/user/.Xauthority
# Direct Rendering Infrastructure
# Xauthority is mounted to allow X11 forwarding for remote display.
# Mount Direct Rendering Infrastructure (DRI) for hardware acceleration support such as OpenGL.
- /dev/dri:/dev/dri
# Mount sound card to prevent Gazebo warning.
- /dev/snd:/dev/snd
# Uncomment the line below and comment out the two entries above to enable USB support.
# - /dev:/dev
# Mount Gazebo models directory to reuse models downloaded during first launch.
# Reference: https://answers.ros.org/question/365658
- ./cache/.gazebo:/home/user/.gazebo
# Mounting the following directories will forbid direct deletion.
# Consider mount these directories only if the build process is slow.
# "source=${localWorkspaceFolder}/../cache/humble/build,target=/home/ws/build,type=bind",
# "source=${localWorkspaceFolder}/../cache/humble/install,target=/home/ws/install,type=bind",
# "source=${localWorkspaceFolder}/../cache/humble/log,target=/home/ws/log,type=bind"
# Mount workspace
- ../..:/home/ros2-agv-essentials
# Note that this volume is shared among all workspaces.
- gazebo-cache:/home/user/.gazebo
# Mount root workspace to allow easy access to all workspaces.
- ../..:/home/ros2-essentials
volumes:
gazebo-cache:
name: ros2-gazebo-cache

0 comments on commit aae39be

Please sign in to comment.