diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 64887d8..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -FROM ros:humble -ENV DEBIAN_FRONTEND=noninteractive -SHELL ["/bin/bash", "-c"] -RUN apt-get update && apt-get install -y -qq --no-install-recommends \ - libglvnd-dev \ - libgl1-mesa-dev \ - libegl1-mesa-dev \ - libgles2-mesa-dev \ - libxext6 \ - libx11-6 \ - freeglut3-dev \ - git \ - python3-pip \ - ros-humble-rmw-cyclonedds-cpp ros-humble-rosidl-generator-dds-idl \ - libyaml-cpp-dev \ - ros-humble-xacro \ - libboost-all-dev\ - build-essential \ - cmake \ - && rm -rf /var/lib/apt/lists/* - - -RUN pip3 install mujoco pin matplotlib - -RUN cd / && git clone https://github.com/unitreerobotics/unitree_ros2 && cd /unitree_ros2/cyclonedds_ws/src && \ -git clone https://github.com/ros2/rmw_cyclonedds -b humble && git clone https://github.com/eclipse-cyclonedds/cyclonedds -b releases/0.10.x &&\ -cd .. && colcon build --packages-select cyclonedds && source /opt/ros/humble/setup.bash && colcon build - -# Env vars for the nvidia-container-runtime. -ENV NVIDIA_VISIBLE_DEVICES all -ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 14e7378..02bdfc8 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,13 +1,65 @@ -// https://containers.dev/implementors/json_reference/ { - "name": "go2py", - "dockerComposeFile": "docker-compose.yaml", - "workspaceFolder": "/home/Go2Py", - "service": "go2py-dev", - "remoteUser": "root", - "customizations": { - "vscode": { - "extensions": ["dbaeumer.vscode-eslint"] + "name": "go2-devcontainer", + "build": { + "context": "..", + "dockerfile": "../docker/build.sh" + }, + "containerEnv": { + "DISPLAY": "unix:0", + "ROS_LOCALHOST_ONLY": "0", + "ROS_AUTOMATIC_DISCOVERY_RANGE": "SUBNET", + "ROS_DOMAIN_ID": "0", + "SHELL": "/bin/bash" + }, + "runArgs": [ + "--privileged", + "--gpus", + "all", + "-v", + "/dev:/dev", + "--net=host", + "-e", + "DISPLAY=${env:DISPLAY}", + "--ulimit=core=-1" + ], + "mounts": [ + "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached", + "source=/dev/dri,target=/dev/dri,type=bind,consistency=cached", + "source=${localEnv:HOME}/go2-devcontainer/logging/,target=/workspace/logging,type=bind,consistency=cached", + "source=${localEnv:HOME}/go2-devcontainer/.bash_history,target=/home/dev/.bash_history,type=bind,consistency=cached", + ], + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace/go2-devcontainer/src/go2-devcontainer,type=bind", + "workspaceFolder": "/workspace/go2-devcontainer/src", + "customizations": { + "vscode": { + "settings": { + "extensions.verifySignature": false + }, + "extensions": [ + "cheshirekow.cmake-format", + "llvm-vs-code-extensions.vscode-clangd", + "ms-azuretools.vscode-docker", + "ms-iot.vscode-ros", + "ms-python.black-formatter", + "ms-python.flake8", + "ms-python.isort", + "ms-python.pylint", + "ms-python.python", + "ms-toolsai.jupyter", + "ms-vscode.cmake-tools", + "mutantdino.resourcemonitor", + "vadimcn.vscode-lldb", + "xaver.clang-format" + ] + } + }, + "forwardPorts": [ + 3000 + ], + "portsAttributes": { + "3000": { + "label": "Application", + "onAutoForward": "notify" + } } - } } \ No newline at end of file diff --git a/.devcontainer/docker-compose.yaml b/.devcontainer/docker-compose.yaml deleted file mode 100644 index 54d71e4..0000000 --- a/.devcontainer/docker-compose.yaml +++ /dev/null @@ -1,17 +0,0 @@ -version: "3.9" -services: - go2py-dev: - build: . - container_name: go2py-dev - network_mode: host - privileged: true - command: bash - volumes: - - /tmp/.X11-unix:/tmp/.X11-unix - - ..:/home/Go2Py - environment: - - DISPLAY=${DISPLAY} - - QT_X11_NO_MITSHM=1 - runtime: nvidia - stdin_open: true - tty: true \ No newline at end of file diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..bf750d2 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 99 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..43751c6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +*.dae filter=lfs diff=lfs merge=lfs -text +*.jpeg filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.obj filter=lfs diff=lfs merge=lfs -text +*.pcd filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.so filter=lfs diff=lfs merge=lfs -text +*.so.* filter=lfs diff=lfs merge=lfs -text +*.stl filter=lfs diff=lfs merge=lfs -text +*.STL filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/container_provisioning/README.md b/container_provisioning/README.md new file mode 100644 index 0000000..1a97807 --- /dev/null +++ b/container_provisioning/README.md @@ -0,0 +1,6 @@ +# Container Provisioning + +Container provisioning contains scripts to set up a PC ready for deployment. + +- System environemnt setup +- Logging directory creation diff --git a/container_provisioning/scripts/init-directory.sh b/container_provisioning/scripts/init-directory.sh new file mode 100755 index 0000000..4079bfa --- /dev/null +++ b/container_provisioning/scripts/init-directory.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +REQUIRED_DIRS=( + "$HOME/go2-devcontainer/logging/coredump" + "$HOME/go2-devcontainer/logging/logs" + "$HOME/go2-devcontainer/logging/data" + "$HOME/go2-devcontainer/logging/plan/data/scene" + "$HOME/go2-devcontainer/logging/plan/data/plan_results" + "$HOME/go2-devcontainer/models/yolov8" +) + +for dir in "${REQUIRED_DIRS[@]}"; do + if [ ! -d "$dir" ]; then + echo "Creating directory $dir" + mkdir -p $dir + fi +done + +if [ ! -f "$HOME/go2-devcontainer/.bash_history" ]; then + echo "Creating file $HOME/go2-devcontainer/.bash_history" + touch $HOME/go2-devcontainer/.bash_history +fi \ No newline at end of file diff --git a/container_provisioning/scripts/install-docker.sh b/container_provisioning/scripts/install-docker.sh new file mode 100755 index 0000000..a0e61c9 --- /dev/null +++ b/container_provisioning/scripts/install-docker.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -e + +if ! [ -x "$(command -v curl)" ]; then + sudo apt-get install curl +fi + +# If docker is not installed, install it +if ! [ -x "$(command -v docker)" ]; then + echo "Docker is not installed. Installing Docker" + curl -fsSL https://get.docker.com -o get-docker.sh + sudo sh get-docker.sh + + # Post-installation steps: https://docs.docker.com/engine/install/linux-postinstall/ + if ! [ $(getent group docker) ]; then + sudo groupadd docker + fi + sudo usermod -aG docker $USER + + echo "==============================================" + echo "Docker installed. Please restart your computer." + echo "==============================================" + exit 1 +fi + +# Check if docker is running +if ! systemctl is-active --quiet docker; then + echo "Docker is not running. Please start Docker and run this script again." + exit 1 +fi + +# If nvidia-container-toolkit is not installed, install it +# Follow https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#installing-with-apt +if ! [ -x "$(command -v nvidia-container-toolkit)" ]; then + # Install nvidia-container-toolkit + curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ + && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ + sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ + sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list + sudo apt-get update + sudo apt-get install -y nvidia-container-toolkit + # Configure nvidia-container-toolkit + sudo nvidia-ctk runtime configure --runtime=docker + sudo systemctl restart docker + nvidia-ctk runtime configure --runtime=docker --config=$HOME/.config/docker/daemon.json + systemctl --user restart docker + sudo nvidia-ctk config --set nvidia-container-cli.no-cgroups --in-place +fi \ No newline at end of file diff --git a/container_provisioning/scripts/install-nvidia-driver.sh b/container_provisioning/scripts/install-nvidia-driver.sh new file mode 100755 index 0000000..951ce5d --- /dev/null +++ b/container_provisioning/scripts/install-nvidia-driver.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +if ! command -v nvidia-smi &> /dev/null +then + echo "Installing NVIDIA driver" +else + echo "NVIDIA driver is already installed" + exit 0 +fi + +# Prompt user to confirm to install NVIDIA driver 535 +NVIDIA_DRIVER_VERSION=535 +while true; do + read -p "Do you want to install NVIDIA driver ${NVIDIA_DRIVER_VERSION}? (y/n)" yn + case $yn in + [Yy]* ) break;; + [Nn]* ) echo "Please install NVIDIA driver manually!"; exit 1;; + * ) echo "Please answer yes or no.";; + esac +done + +sudo apt-get update +sudo apt-get install -y nvidia-driver-${NVIDIA_DRIVER_VERSION} \ No newline at end of file diff --git a/container_provisioning/scripts/install-tools.sh b/container_provisioning/scripts/install-tools.sh new file mode 100755 index 0000000..b0085d7 --- /dev/null +++ b/container_provisioning/scripts/install-tools.sh @@ -0,0 +1,34 @@ +#!/bin/bash +set -e + +if ! command -v git-lfs &> /dev/null +then + echo "Installing git-lfs" + sudo apt-get update + sudo apt-get install \ + git-lfs + echo "==============================================" + echo "git-lfs is installed. Please remove cloned go2-devcontainer and re-clone it." + echo "==============================================" + exit 1 +else + echo "git-lfs is already installed" +fi + +# # If foxglove-studio is not installed, install it +# if ! command -v foxglove-studio &> /dev/null +# then +# echo "Installing foxglove-studio" +# sudo snap install foxglove-studio +# else +# echo "foxglove-studio is already installed" +# fi + +# If VSCode is not installed, install it +if ! command -v code &> /dev/null +then + echo "Installing VSCode" + sudo snap install code --classic +else + echo "VSCode is already installed" +fi diff --git a/container_provisioning/system-setup.sh b/container_provisioning/system-setup.sh new file mode 100755 index 0000000..4e2538b --- /dev/null +++ b/container_provisioning/system-setup.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +${SCRIPT_DIR}/scripts/install-tools.sh +${SCRIPT_DIR}/scripts/install-nvidia-driver.sh +${SCRIPT_DIR}/scripts/install-docker.sh +${SCRIPT_DIR}/scripts/init-directory.sh \ No newline at end of file diff --git a/docker/Dockerfile.x86 b/docker/Dockerfile.x86 new file mode 100644 index 0000000..d7e3b95 --- /dev/null +++ b/docker/Dockerfile.x86 @@ -0,0 +1,65 @@ +FROM nvidia/cuda:12.1.1-devel-ubuntu22.04 + +SHELL ["/bin/bash", "-c"] + +# Install dependencies +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=bind,source=docker/scripts/install-tools.sh,target=/tmp/install-tools.sh \ + bash /tmp/install-tools.sh +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=bind,source=docker/scripts/install-ros2.sh,target=/tmp/install-ros2.sh \ + bash /tmp/install-ros2.sh +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=bind,source=docker/scripts/install-clang.sh,target=/tmp/install-clang.sh \ + bash /tmp/install-clang.sh +RUN --mount=type=cache,target=/root/.cache/pip \ + --mount=type=bind,source=docker/scripts/install-python-requirements.sh,target=/tmp/install-python-requirements.sh \ + bash /tmp/install-python-requirements.sh +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=bind,source=docker/scripts/install-3rdparty.sh,target=/tmp/install-3rdparty.sh \ + bash /tmp/install-3rdparty.sh + +# Last installation layer as we update ROS dependencies often +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=bind,source=.,target=/tmp/ros_ws \ + /tmp/ros_ws/docker/scripts/install-rosdep.sh + +# Clean cache +RUN apt-get autoremove -y \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Create a non-root user +ARG USERNAME=dev +ARG USER_UID=1000 +ARG USER_GID=$USER_UID +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ + && apt-get update \ + && apt-get install -y sudo \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + && apt-get autoremove -y \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Create a workspace directory +RUN mkdir -p /workspace/go2-devcontainer/src/go2-devcontainer \ + && cd /workspace/go2-devcontainer \ + && chown -R $USERNAME:$USERNAME /workspace/go2-devcontainer/ + +RUN --mount=type=bind,source=docker/config/docker.bashrc,target=/tmp/docker.bashrc \ + cat /tmp/docker.bashrc >> /home/$USERNAME/.bashrc + +# Clone unitree_ros2 +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=bind,source=docker/scripts/install-unitree-ros2.sh,target=/tmp/install-unitree-ros2.sh \ + bash /tmp/install-unitree-ros2.sh + +# NVIDIA-related environment variables +ENV NVIDIA_VISIBLE_DEVICES \ + ${NVIDIA_VISIBLE_DEVICES:-all} +ENV NVIDIA_DRIVER_CAPABILITIES \ + ${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics + +USER $USERNAME \ No newline at end of file diff --git a/docker/build.sh b/docker/build.sh new file mode 100644 index 0000000..5a96e03 --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash +ARCH=$(uname -m) +if [ "$ARCH" = "x86_64" ]; then + DOCKERFILE_PATH="docker/Dockerfile.x86" +elif [ "$ARCH" = "aarch64" ]; then + DOCKERFILE_PATH="docker/Dockerfile.arm64" +else + echo "Unsupported architecture: $ARCH" + exit 1 +fi + +docker build --file $DOCKERFILE_PATH --tag go2py-container . diff --git a/docker/config/docker.bashrc b/docker/config/docker.bashrc new file mode 100644 index 0000000..ec7a490 --- /dev/null +++ b/docker/config/docker.bashrc @@ -0,0 +1,149 @@ +############################################## +## Bash Script +############################################## + +PROMPT_COMMAND='history -a' +HISTFILE=/home/dev/.bash_history +LOG_WORKSPACE=/workspace/logging +ROS_WORKSPACE=/workspace/go2-devcontainer + +export CC=clang +export CXX=clang++ +export MAKEFLAGS="-j 8" + +export RCUTILS_COLORIZED_OUTPUT=1 +export ROS_LOG_DIR=/workspace/logging/logs +export ROS_DATA_DIR=/workspace/logging/data +export ROS_BAG_MAX_SIZE=1073741824 +export RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity}] [{time}] [{name}:{line_number}]: {message}" + +# unitree_ros2 +export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp +export CYCLONEDDS_URI=' + + ' + +# https://github.com/ament/ament_cmake/issues/382 +PYTHONWARNINGS="ignore:easy_install command is deprecated,ignore:setup.py install is deprecated" +export PYTHONWARNINGS + +echo '/workspace/logging/coredump/core.%e.%p.%h.%t' | sudo tee /proc/sys/kernel/core_pattern >/dev/null + +_show_workspace_logging_usage() { + # For each dir under logging workspace, show disk usages. + echo "===================================================" + echo "Disk usage for each directory under $LOG_WORKSPACE:" + for dir in $(find $LOG_WORKSPACE -maxdepth 1 -mindepth 1 -type d); do + du -sh $dir + done + echo "Make sure to clean up old logs to save disk space." + echo "===================================================" +} + +_update_dependencies() { + source /opt/ros/humble/setup.bash + sudo apt-get update + cd $ROS_WORKSPACE \ + && rosdep update \ + && rosdep install --from-paths src --ignore-src -y +} + +_ensure_not_in_workspace_src() { + # If current dir ends with "src", prompt user to switch to workspace dir. + # colcon build will stupidly build inside src folder. + if [[ "$(basename "$(pwd)")" == "src" ]]; then + echo "It looks like you're in a 'src' directory. Please switch to ${ROS_WORKSPACE}." + return 1 + fi + return 0 +} + +COMMON_CMAKE_ARGS="\ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -GNinja \ + -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld \ + -DCMAKE_MODULE_LINKER_FLAGS=-fuse-ld=lld \ + -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld + " +COMMON_COLCON_ARGS="--symlink-install --event-handlers console_cohesion+" +RELEASE_CMAKE_ARGS="$COMMON_CMAKE_ARGS -DCMAKE_BUILD_TYPE=RelWithDebInfo" +DEBUG_CMAKE_ARGS="$COMMON_CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug" + +_colcon_release_build() { + _ensure_not_in_workspace_src || return 1 + + # Run 'colcon build' with passed arguments + colcon build \ + ${COMMON_COLCON_ARGS} \ + --cmake-args $RELEASE_CMAKE_ARGS \ + "$@" +} + +_colcon_debug_build() { + _ensure_not_in_workspace_src || return 1 + + # Run 'colcon build' with passed arguments + colcon build \ + ${COMMON_COLCON_ARGS} \ + --cmake-args $DEBUG_CMAKE_ARGS \ + "$@" +} + +_colcon_test() { + _ensure_not_in_workspace_src || return 1 + + # Run 'colcon test' with passed arguments + colcon test --event-handlers console_cohesion+ "$@" +} + +_remove_directories() { + if [ -d "build" ]; then + rm -r build + fi + if [ -d "install" ]; then + rm -r install + fi + if [ -d "log" ]; then + rm -r log + fi +} + +colcon_clean() { + _ensure_not_in_workspace_src || return 1 + + if [ -d "build" ] || [ -d "install" ] || [ -d "log" ]; then + while true; do + read -p "Do you wish to remove build, install, and log directories? [y/n] " yn + case $yn in + [Yy]* ) _remove_directories; break;; + [Nn]* ) break;; + * ) echo "Please answer yes or no.";; + esac + done + fi +} + +# Colcon build aliases +alias update_dep=_update_dependencies +alias source_ws='source install/setup.bash' +alias colcon_build='_colcon_release_build' +alias colcon_debug_build='_colcon_debug_build' +alias colcon_build_package='_colcon_release_build --packages-select' +alias colcon_debug_build_package='_colcon_debug_build --packages-select' +alias colcon_build_up_to='_colcon_release_build --packages-up-to' +alias colcon_debug_build_up_to='_colcon_debug_build --packages-up-to' +alias colcon_test='_colcon_test' +alias colcon_test_package='_colcon_test --packages-select' +alias colcon_test_up_to='_colcon_test --packages-up-to' + +source /opt/ros/humble/setup.bash +# Source ROS workspace if it exists +if [ -f "/workspace/go2-devcontainer/install/setup.bash" ]; then + source /workspace/go2-devcontainer/install/setup.bash +fi + +# colcon_cd +source /usr/share/colcon_cd/function/colcon_cd.sh +export _colcon_cd_root=/opt/ros/humble/ + +_show_workspace_logging_usage \ No newline at end of file diff --git a/docker/scripts/build-librealsense.sh b/docker/scripts/build-librealsense.sh new file mode 100644 index 0000000..67fab42 --- /dev/null +++ b/docker/scripts/build-librealsense.sh @@ -0,0 +1,188 @@ +#!/bin/bash +# Builds the Intel Realsense library librealsense on a Jetson Nano Development Kit +# Copyright (c) 2016-21 Jetsonhacks +# MIT License + +LIBREALSENSE_DIRECTORY=${HOME}/librealsense +INSTALL_DIR=$PWD +NVCC_PATH=/usr/local/cuda/bin/nvcc + +USE_CUDA=true + +function usage () +{ + echo "Usage: ./build-librealsense.sh [-n | -no_cuda] [-v | -version ] [-j | --jobs ] [-h | --help] " + echo "-n | --no_cuda Build with no CUDA (Defaults to with CUDA)" + echo "-v | --version Version of librealsense to build + (defaults to latest release)" + echo "-j | --jobs Number of concurrent jobs (Default 1 on <= 4GB RAM + #of cores-1 otherwise)" + echo "-h | --help This message" + exit 2 +} + +PARSED_ARGUMENTS=$(getopt -a -n build-librealsense.sh -o nv:j:h --longoptions version:,no_cuda,jobs:,help -- "$@" ) +VALID_ARGUMENTS=$? + +if [ "$VALID_ARGUMENTS" != "0" ]; then + echo "" + usage +fi + +eval set -- "$PARSED_ARGUMENTS" + +LIBREALSENSE_VERSION="" +USE_CUDA=true +NUM_PROCS="" + +while : +do + case "$1" in + -n | --build_no_cuda) USE_CUDA=false ; shift ;; + -v | --version ) LIBREALSENSE_VERSION="$2" ; shift 2 ;; + -j | --jobs) NUM_PROCS="$2" ; + shift 2 ; + re_isanum='^[0-9]+$' + if ! [[ $NUM_PROCS =~ $re_isanum ]] ; then + echo "Number of jobs must be a positive, whole number" + usage + else + if [ $NUM_PROCS -eq "0" ]; then + echo "Number of jobs must be a positive, whole number" + fi + fi ; + ;; + -h | --help ) usage ; shift ;; + # -- means the end of arguments + --) shift; break ;; + esac +done + +# From lukechilds gist discussion: https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c +# We use wget instead of curl here +# Sample usage: +# VERSION_STRINGS=$(get_latest_release IntelRealSense/librealsense) + +function get_latest_release () { + # redirect wget to standard out and grep out the tag_name + wget -qO- https://api.github.com/repos/$1/releases/latest | + grep -Po '"tag_name": "\K.*?(?=")' +} + +if [[ $LIBREALSENSE_VERSION == "" ]] ; then + echo "Getting latest librealsense version number" + LIBREALSENSE_VERSION=$(get_latest_release IntelRealSense/librealsense) +fi + +echo "Build with CUDA: "$USE_CUDA +echo "Librealsense Version: $LIBREALSENSE_VERSION" + +red=`tput setaf 1` +green=`tput setaf 2` +reset=`tput sgr0` +# e.g. echo "${red}The red tail hawk ${green}loves the green grass${reset}" + +if [ ! -d "$LIBREALSENSE_DIRECTORY" ] ; then + # clone librealsense + cd ${HOME} + echo "${green}Cloning librealsense${reset}" + git clone https://github.com/IntelRealSense/librealsense.git +fi + +# Is the version of librealsense current enough? +cd $LIBREALSENSE_DIRECTORY +VERSION_TAG=$(git tag -l $LIBREALSENSE_VERSION) +if [ ! $VERSION_TAG ] ; then + echo "" + tput setaf 1 + echo "==== librealsense Version Mismatch! =============" + tput sgr0 + echo "" + echo "The installed version of librealsense is not current enough for these scripts." + echo "This script needs librealsense tag version: "$LIBREALSENSE_VERSION "but it is not available." + echo "Please upgrade librealsense or remove the librealsense folder before attempting to install again." + echo "" + exit 1 +fi + +# Checkout version the last tested version of librealsense +git checkout $LIBREALSENSE_VERSION + +# Install the dependencies +cd $INSTALL_DIR + +cd $LIBREALSENSE_DIRECTORY +git checkout $LIBREALSENSE_VERSION + +# Now compile librealsense and install +mkdir build +cd build +# Build examples, including graphical ones +echo "${green}Configuring Make system${reset}" +# Build with CUDA (default), the CUDA flag is USE_CUDA, ie -DUSE_CUDA=true +export CUDACXX=$NVCC_PATH +export PATH=${PATH}:/usr/local/cuda/bin +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda/lib64 + +/usr/bin/cmake ../ -DBUILD_EXAMPLES=true -DFORCE_RSUSB_BACKEND=true -DBUILD_WITH_CUDA="$USE_CUDA" -DCMAKE_BUILD_TYPE=release -DBUILD_PYTHON_BINDINGS=bool:true + +# The library will be installed in /usr/local/lib, header files in /usr/local/include +# The demos, tutorials and tests will located in /usr/local/bin. +echo "${green}Building librealsense, headers, tools and demos${reset}" + +# If user didn't set # of jobs and we have > 4GB memory then +# set # of jobs to # of cores-1, otherwise 1 +if [[ $NUM_PROCS == "" ]] ; then + TOTAL_MEMORY=$(free | awk '/Mem\:/ { print $2 }') + if [ $TOTAL_MEMORY -gt 4051048 ] ; then + NUM_CPU=$(nproc) + NUM_PROCS=$(($NUM_CPU - 1)) + else + NUM_PROCS=1 + fi +fi + +time make -j$NUM_PROCS +if [ $? -eq 0 ] ; then + echo "librealsense make successful" +else + # Try to make again; Sometimes there are issues with the build + # because of lack of resources or concurrency issues + echo "librealsense did not build " >&2 + echo "Retrying ... " + # Single thread this time + time make + if [ $? -eq 0 ] ; then + echo "librealsense make successful" + else + # Try to make again + echo "librealsense did not successfully build" >&2 + echo "Please fix issues and retry build" + exit 1 + fi +fi +echo "${green}Installing librealsense, headers, tools and demos${reset}" +sudo make install + +if grep -Fxq 'export PYTHONPATH=$PYTHONPATH:/usr/local/lib' ~/.bashrc ; then + echo "PYTHONPATH already exists in .bashrc file" +else + echo 'export PYTHONPATH=$PYTHONPATH:/usr/local/lib' >> ~/.bashrc + echo "PYTHONPATH added to ~/.bashrc. Pyhon wrapper is now available for importing pyrealsense2" +fi + +cd $LIBREALSENSE_DIRECTORY +echo "${green}Applying udev rules${reset}" +# Copy over the udev rules so that camera can be run from user space +sudo cp config/99-realsense-libusb.rules /etc/udev/rules.d/ +sudo udevadm control --reload-rules && udevadm trigger + +echo "${green}Library Installed${reset}" +echo " " +echo " -----------------------------------------" +echo "The library is installed in /usr/local/lib" +echo "The header files are in /usr/local/include" +echo "The demos and tools are located in /usr/local/bin" +echo " " +echo " -----------------------------------------" +echo " " diff --git a/docker/scripts/hotplug-realsense.sh b/docker/scripts/hotplug-realsense.sh new file mode 100755 index 0000000..7d515e5 --- /dev/null +++ b/docker/scripts/hotplug-realsense.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + + +# This script is triggered when a corresponding udev rule is matched with action +function usage() { + echo "Usage: hotplug-realsense.sh -a -d [options]" + echo "-a | --action Action determines whether the device has been added or removed. Valid values are 'add' or 'remove'." + echo "-d | --dev-path Device path that will be used to mount the device." + echo "-M | --major-version The kernel major number for the device. This will be used when action=add." + echo "-m | --minor-version The kernel minor number for the device. This will be used when action=add." + echo "-p | --parent-path Parent node path of the device pointed by the -d flag." + echo "-h | --help Display this message." +} + +function check_mandatory_param() { +VAR=$1 +MSG=$2 +if [[ -z ${VAR} ]] ; then + echo "${MSG}" + usage + exit 1 +fi +} + +function timestamp() { + echo [$EPOCHREALTIME] [$(date)] +} + +ARGUMENTS=$(getopt -n hotplug-realsense.sh -o a:d:M:m:p:h -l action:,dev-path:,major-version:,minor-version:,parent-path:,help -- "$@" ) + +if [[ $? -ne 0 ]]; then + usage +fi + +eval set -- "$ARGUMENTS" + +while [ : ]; do + case "$1" in + -a | --action) + ACTION=$2 ; shift 2 ;; + -d | --dev-path) + DEV_PATH=$2 ; shift 2 ;; + -M | --major-version) + MAJOR_VERSION=$2 ; shift 2 ;; + -m | --minor-version) + MINOR_VERSION=$2 ; shift 2 ;; + -p | --parent-path) + PARENT_PATH=/dev/$2 ; shift 2 ;; + -h | --help) + usage ; shift ;; + --) shift; break ;; + esac +done + +check_mandatory_param ${ACTION:-""} "Please provide valid value for action" +check_mandatory_param ${DEV_PATH:-""} "Please provide valid value for device path" + +if [[ "${ACTION}" == "add" ]]; then + check_mandatory_param ${MAJOR_VERSION:-""} "Please provide valid value for major number" + check_mandatory_param ${MINOR_VERSION:-""} "Please provide valid value for minor number" + sudo mknod -m a=rw ${DEV_PATH} c ${MAJOR_VERSION} ${MINOR_VERSION} + sudo chown root:plugdev ${DEV_PATH} + echo $(timestamp) "Added ${DEV_PATH} with major version: ${MAJOR_VERSION} and minor version: ${MINOR_VERSION} to docker" >> /tmp/docker_usb.log +elif [[ "$ACTION" == "remove" ]]; then + sudo rm ${DEV_PATH} ${PARENT_PATH} + echo $(timestamp) "Removed ${DEV_PATH} ${PARENT_PATH} from docker" >> /tmp/docker_usb.log +else + echo "Cannot recognize action=${ACTION}" + usage + exit 1 +fi diff --git a/docker/scripts/install-3rdparty.sh b/docker/scripts/install-3rdparty.sh new file mode 100644 index 0000000..d01902b --- /dev/null +++ b/docker/scripts/install-3rdparty.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +set -e + +# Install thirdparty libraries that CANNOT be installed using rosdep +# Perfer to use rosdep to install thirdparty libraries if possible + +mkdir -p /workspace/thirdparty +cd /workspace/thirdparty + +export CC=clang +export CXX=clang++ +apt-get update + +# ============================================ +# Install magic_enum v0.9.5 +# For some reason, ros-humble-magic-enum doesn't work +cd /workspace/thirdparty +git clone https://github.com/Neargye/magic_enum.git +cd magic_enum && git checkout v0.9.5 +mkdir build && cd build +cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DMAGIC_ENUM_OPT_BUILD_TESTS=OFF \ + -DMAGIC_ENUM_OPT_BUILD_EXAMPLES=OFF \ + .. +make -j$(nproc) +make install +cd /workspace/thirdparty && rm -rf magic_enum + +# ============================================ +# Install Open3D v.0.18.0 +# The libopen3d-dev package is too old (0.14.0). +# cd /workspace/thirdparty +# git clone https://github.com/isl-org/Open3D.git +# cd Open3D && git checkout v0.18.0 +# apt-get install -y libc++-dev libc++abi-dev +# mkdir build && cd build +# cmake \ +# -DCMAKE_BUILD_TYPE=Release \ +# -DBUILD_SHARED_LIBS=ON \ +# -DBUILD_EXAMPLES=OFF \ +# -DBUILD_PYTHON_MODULE=OFF \ +# .. +# make -j$(nproc) +# make install +# cd /workspace/thirdparty && rm -rf Open3D + + +# ============================================ +# Install google-glog v.0.7.0 +# Some packages depend on it and we can't use libgoogle-glog-dev due to +# https://github.com/isl-org/Open3D/discussions/6515 +cd /workspace/thirdparty +git clone https://github.com/google/glog.git +cd glog && git checkout v0.7.0 +cmake -S . -B build -G "Unix Makefiles" +cmake --build build +cmake --build build --target install +cd /workspace/thirdparty && rm -rf glog + +# ============================================ +# Install librealsense2 +apt-get install -y --no-install-recommends \ + ros-humble-librealsense2* \ + ros-humble-realsense2-* + +# ============================================ +# Install unitree_sdk2 +cd /workspace/thirdparty +git clone https://github.com/unitreerobotics/unitree_sdk2.git +cd unitree_sdk2 +./install.sh +cd /workspace/thirdparty && rm -rf unitree_sdk2 \ No newline at end of file diff --git a/docker/scripts/install-clang.sh b/docker/scripts/install-clang.sh new file mode 100644 index 0000000..e9fb069 --- /dev/null +++ b/docker/scripts/install-clang.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +# Install LLVM family: compiler, formatter, debugger, etc + +apt-get update +apt-get install -y --no-install-recommends \ + clangd-15 \ + clang-15 \ + clang-format-15 \ + lld-15 \ + lldb-15 +update-alternatives --install /usr/bin/clang clang /usr/bin/clang-15 100 +update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-15 100 +update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-15 100 +update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100 +update-alternatives --install /usr/bin/lld lld /usr/bin/lld-15 100 +update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-15 100 +update-alternatives --install /usr/bin/lldb-server lldb-server /usr/bin/lldb-server-15 100 + +# Fix https://github.com/llvm/llvm-project/issues/55575 +ln -s /usr/lib/llvm-15/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/ \ No newline at end of file diff --git a/docker/scripts/install-python-requirements.sh b/docker/scripts/install-python-requirements.sh new file mode 100644 index 0000000..1fc9c58 --- /dev/null +++ b/docker/scripts/install-python-requirements.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +pip install \ + "torch==2.2.1" \ + "torchvision==0.17.1" \ + "numpy>=1.26.4" \ + "pybullet>=3.2.6" \ + "proxsuite==0.6.3" \ + "ipykernel==6.29.3" \ + "open3d==0.18.0" \ No newline at end of file diff --git a/docker/scripts/install-realsense-dependencies.sh b/docker/scripts/install-realsense-dependencies.sh new file mode 100644 index 0000000..db81a0c --- /dev/null +++ b/docker/scripts/install-realsense-dependencies.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# install-realsense-dependencies.sh +# Install dependencies for the Intel Realsense library librealsense2 on a Jetson Nano Developer Kit +# Copyright (c) 2016-19 Jetsonhacks +# MIT License + +red=`tput setaf 1` +green=`tput setaf 2` +reset=`tput sgr0` +# e.g. echo "${red}red text ${green}green text${reset}" +echo "${green}Adding Universe repository and updating${reset}" +apt-add-repository universe +apt-get update +echo "${green}Adding dependencies, graphics libraries and tools${reset}" +apt-get install libssl-dev libusb-1.0-0-dev pkg-config -y + +# Graphics libraries - for SDK's OpenGL-enabled examples +apt-get install libgtk-3-dev libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev -y + +# QtCreator for development; not required for librealsense core library +apt-get install qtcreator -y + +# Add Python 3 support +apt-get install -y python3 python3-dev diff --git a/docker/scripts/install-ros2.sh b/docker/scripts/install-ros2.sh new file mode 100644 index 0000000..2aa3f8a --- /dev/null +++ b/docker/scripts/install-ros2.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +set -e + +export DEBIAN_FRONTEND=noninteractive +apt-get update && apt-get install -y locales +locale-gen en_US en_US.UTF-8 +update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +export LANG=en_US.UTF-8 + +curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg +echo "deb [arch=amd64 signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu jammy main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null + +apt-get update && apt-get install -y --no-install-recommends \ + ros-humble-desktop \ + ros-dev-tools \ + python3-colcon-common-extensions \ + python3-flake8-docstrings \ + python3-pip \ + python3-pytest-cov \ + ros-dev-tools \ + python3-flake8-blind-except \ + python3-flake8-builtins \ + python3-flake8-class-newline \ + python3-flake8-comprehensions \ + python3-flake8-deprecated \ + python3-flake8-import-order \ + python3-flake8-quotes \ + python3-pytest-repeat \ + python3-pytest-rerunfailures \ + ros-humble-rmw-cyclonedds-cpp \ + ros-humble-rosidl-generator-dds-idl \ No newline at end of file diff --git a/docker/scripts/install-rosdep.sh b/docker/scripts/install-rosdep.sh new file mode 100755 index 0000000..d9aa47e --- /dev/null +++ b/docker/scripts/install-rosdep.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +# Make sure workspace is mounted in /tmp/ros_ws +source /opt/ros/humble/setup.bash +apt-get update +rosdep init +rosdep update +rosdep install --from-paths /tmp/ros_ws --ignore-src -y \ No newline at end of file diff --git a/docker/scripts/install-tools.sh b/docker/scripts/install-tools.sh new file mode 100644 index 0000000..7b4a7d3 --- /dev/null +++ b/docker/scripts/install-tools.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +# Install tools, utilities, and etc. + +apt-get update +apt-get install -y --no-install-recommends \ + curl \ + git-lfs \ + ninja-build \ + psmisc \ + python3-pip \ + software-properties-common \ + unzip \ + usbutils \ + vim \ + wget \ + net-tools \ + iputils-ping + +pip3 install \ + cmakelang==0.6.13 \ No newline at end of file diff --git a/docker/scripts/install-unitree-ros2.sh b/docker/scripts/install-unitree-ros2.sh new file mode 100644 index 0000000..ed9ac8c --- /dev/null +++ b/docker/scripts/install-unitree-ros2.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +# clone unitree_ros2 +cd /workspace/go2-devcontainer/src +git clone https://github.com/unitreerobotics/unitree_ros2 + +# clone cyclonedds related packaged +cd /workspace/go2-devcontainer/src/unitree_ros2/cyclonedds_ws/src +git clone https://github.com/ros2/rmw_cyclonedds -b humble +git clone https://github.com/eclipse-cyclonedds/cyclonedds -b releases/0.10.x + +# build cyclonedds +cd /workspace/go2-devcontainer/src/unitree_ros2/cyclonedds_ws +colcon build --packages-select cyclonedds \ No newline at end of file diff --git a/docker/scripts/workspace-entrypoint.sh b/docker/scripts/workspace-entrypoint.sh new file mode 100755 index 0000000..466cd88 --- /dev/null +++ b/docker/scripts/workspace-entrypoint.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +# Build ROS dependency +echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc +source /opt/ros/${ROS_DISTRO}/setup.bash + +sudo apt-get update +rosdep update + +# Restart udev daemon +sudo service udev restart + +$@ diff --git a/docker/tao/tao-converter-aarch64-tensorrt8.4.zip b/docker/tao/tao-converter-aarch64-tensorrt8.4.zip new file mode 100644 index 0000000..94e8c6b Binary files /dev/null and b/docker/tao/tao-converter-aarch64-tensorrt8.4.zip differ diff --git a/docker/udev_rules/99-realsense-libusb-custom.rules b/docker/udev_rules/99-realsense-libusb-custom.rules new file mode 100644 index 0000000..9279e0d --- /dev/null +++ b/docker/udev_rules/99-realsense-libusb-custom.rules @@ -0,0 +1,11 @@ +##Version=0.1## +# Device rules for Intel RealSense devices (D435 D435i D455) +# For D435 +ACTION=="add" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b07", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a add -d '%N' -M '%M' -m '%m'" +ACTION=="remove" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b07", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a remove -d '%N' -p '%P'" +# For D435i +ACTION=="add" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b3a", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a add -d '%N' -M '%M' -m '%m'" +ACTION=="remove" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b3a", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a remove -d '%N' -p '%P'" +# For D455 +ACTION=="add" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b5c", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a add -d '%N' -M '%M' -m '%m'" +ACTION=="remove" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b5c", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a remove -d '%N' -p '%P'"