diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29bd8b034..ee04454c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - name: Install clang-format run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main' + sudo add-apt-repository 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble-18 main' sudo apt-get update sudo apt-get install -y clang-format-18 - name: Install shellcheck @@ -31,39 +31,54 @@ jobs: - name: Run Style Check run: ./style.sh - ci: - name: Build - runs-on: ubuntu-latest - needs: style + build-native: + name: Build (native Ubuntu 24) + runs-on: ubuntu-24.04 container: - image: umrover1/ros2-ci:jammy - # GitHub is silly and requires us to be running as root for their checkout action - # Our docker container exports the user mrover, so we have to specific this explicitly + image: umrover1/ros2-ci:noble + # by pass github's dubious ownership check options: --user root + needs: style + env: + # directory owned by mrover so CI can write to it and use caching + # this is new for ubuntu 24 + HOME: /home/mrover steps: - uses: actions/checkout@v7 - with: - # Re-enable when we put the simulator in the CI pipeline. - # lfs: "true" - # This makes sure that $GITHUB_WORKSPACE is the catkin workspace path - path: "src/mrover" + # Re-enable lfs: "true" when we put the simulator in the CI pipeline. - name: Compiler Cache - if: github.event.pull_request.draft == false uses: hendrikmuhs/ccache-action@v1.2.23 - name: Dawn Cache if: github.event.pull_request.draft == false uses: actions/cache@v6 with: - path: src/mrover/deps/dawn-prebuilt - key: dawn-${{ hashFiles('src/mrover/scripts/setup_dawn.sh') }} + path: deps/dawn-prebuilt + key: dawn-${{ hashFiles('scripts/setup_dawn.sh') }} - name: Setup Dawn - if: github.event.pull_request.draft == false run: ./scripts/setup_dawn.sh - working-directory: "${{ github.workspace }}/src/mrover" + - name: Manif Cache + uses: actions/cache@v6 + with: + path: deps/manif-src + key: manif-${{ hashFiles('scripts/setup_manif.sh') }} + - name: Setup Manif + run: ./scripts/setup_manif.sh + - name: Imgui Cache + uses: actions/cache@v6 + with: + path: deps/imgui-src + key: imgui-${{ hashFiles('scripts/setup_imgui.sh') }} + - name: Setup Imgui + run: ./scripts/setup_imgui.sh + - name: Pip Cache + uses: actions/cache@v6 + with: + path: /home/mrover/.cache/pip + key: pip-${{ hashFiles('pyproject.toml', 'esw/fw/tools/pyproject.toml') }} + restore-keys: | + pip- + - name: Compiler Cache + uses: hendrikmuhs/ccache-action@v1.2.23 - name: Build - if: github.event.pull_request.draft == false shell: bash - run: . /opt/ros/humble/setup.sh && . /home/mrover/ros2_ws/src/mrover/venv/bin/activate && cd $GITHUB_WORKSPACE/src/mrover/ && ./build.sh - # - name: Test - # if: github.event.pull_request.draft == false - # run: . /opt/ros/noetic/setup.sh && . /home/mrover/ros2_ws/src/mrover/venv/bin/activate && . $GITHUB_WORKSPACE/devel/setup.sh && catkin test && rostest mrover integration.test --text + run: source /opt/ros/jazzy/setup.bash && source /home/mrover/mrover-ros2/venv/bin/activate && ./build.sh Release diff --git a/.gitignore b/.gitignore index c5d292aed..2c84894a4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,8 @@ # Downloaded prebuilt dependencies /deps/dawn-prebuilt/ -/deps/.fetchcontent/ +/deps/manif-src/ +/deps/imgui-src/ # Common IDE's, ideally this should be in global gitignore per user .vscode/ @@ -55,4 +56,4 @@ data/raw-pano-images .dynamixel_sdk/ # Persistent esw mrover_can FetchContent cache (survives a clean build, not tracked) -/.cache/esw/ \ No newline at end of file +/deps/.fetchcontent/esw/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index cead30732..bf5f806e2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,14 +8,14 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/../../install/Debug/mrover/lib/mrover/${input:myStringInput}", + "program": "${workspaceFolder}/install/Debug/mrover/lib/mrover/${input:myStringInput}", "args": [], "stopAtEntry": false, "cwd": "${fileDirname}", "environment": [ { "name": "LD_LIBRARY_PATH", - "value": "${workspaceFolder}/../../install/Debug/mrover/lib:/opt/ros/humble/opt/rviz_ogre_vendor/lib:/opt/ros/humble/lib/aarch64-linux-gnu:/opt/ros/humble/lib/x86_64-linux-gnu:/opt/ros/humble/lib" + "value": "${workspaceFolder}/install/Debug/mrover/lib:/opt/ros/jazzy/opt/rviz_ogre_vendor/lib:/opt/ros/jazzy/lib/aarch64-linux-gnu:/opt/ros/jazzy/lib/x86_64-linux-gnu:/opt/ros/jazzy/lib" }, { "name": "ROS_DOMAIN_ID", @@ -44,7 +44,7 @@ "program": "${file}", "console": "integratedTerminal", "env": { - "LD_LIBRARY_PATH": "${workspaceFolder}/../../install/Debug/mrover/lib:/opt/ros/humble/opt/rviz_ogre_vendor/lib:/opt/ros/humble/lib/aarch64-linux-gnu:/opt/ros/humble/lib/x86_64-linux-gnu:/opt/ros/humble/lib", + "LD_LIBRARY_PATH": "${workspaceFolder}/install/Debug/mrover/lib:/opt/ros/jazzy/opt/rviz_ogre_vendor/lib:/opt/ros/jazzy/lib/aarch64-linux-gnu:/opt/ros/jazzy/lib/x86_64-linux-gnu:/opt/ros/jazzy/lib", "ROS_DOMAIN_ID": "5" } } @@ -56,7 +56,7 @@ "type": "command", "command": "file-selector.fileSelect", // exclude the absolute prefix path here - "args": "../../install/Debug/mrover/lib/mrover" + "args": "install/Debug/mrover/lib/mrover" } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 8feda2f95..bcd1e518c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,17 +6,17 @@ "python.analysis.inlayHints.variableTypes": true, "python.analysis.inlayHints.callArgumentNames": "all", "python.analysis.inlayHints.functionReturnTypes": true, - // ~/ros2_ws/install/{profile}/mrover/lib/python3.10/site-packages is already in PYTHONPATH, + // ~/mrover-ros2/install/{profile}/mrover/lib/python3.12/site-packages is already in PYTHONPATH, // but Pylance currently has a bug where it cannot handle the symlinks in it. // Below we are just putting directly where those symlinks go for all build profiles "python.analysis.extraPaths": [ - "/opt/ros/humble/lib/python3/dist-packages", - "../../install/Debug/mrover/lib/python3.10/site-packages", - "../../install/Release/mrover/lib/python3.10/site-packages", - "../../install/RelWithDebInfo/mrover/lib/python3.10/site-packages", - "../../build/Debug/mrover/rosidl_generator_py", - "../../build/Release/mrover/rosidl_generator_py", - "../../build/RelWithDebInfo/mrover/rosidl_generator_py", + "/opt/ros/jazzy/lib/python3/dist-packages", + "install/Debug/mrover/lib/python3.12/site-packages", + "install/Release/mrover/lib/python3.12/site-packages", + "install/RelWithDebInfo/mrover/lib/python3.12/site-packages", + "build/Debug/mrover/rosidl_generator_py", + "build/Release/mrover/rosidl_generator_py", + "build/RelWithDebInfo/mrover/rosidl_generator_py", ], "[python]": { "editor.defaultFormatter": "ms-python.black-formatter", diff --git a/CMakeLists.txt b/CMakeLists.txt index 12834dcd4..01b45d991 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25) project(mrover VERSION 2025.0.0 LANGUAGES C CXX) # Supress ROS CMake warning about Python. -cmake_policy(SET CMP0148 OLD) +cmake_policy(SET CMP0148 NEW) set(CMAKE_CXX_STANDARD 23) set(CXX_STANDARD_REQUIRED ON) @@ -31,9 +31,6 @@ if (APPLE) # Ensures that homebrew packages are never used over miniforge packages. # TODO (ali): Pretty sure this doesn't do anything on macs set(CMAKE_IGNORE_PATH /opt/homebrew) - # Find mamba python - find_package(PythonLibs REQUIRED) - # link_libraries(${PYTHON_LIBRARIES}) endif () if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -74,8 +71,10 @@ find_package(tf2 REQUIRED) find_package(tf2_ros REQUIRED) find_package(urdf REQUIRED) find_package(std_srvs REQUIRED) +find_package(ament_index_cpp REQUIRED) find_package(magic_enum REQUIRED) find_package(yaml_cpp_vendor REQUIRED) +find_package(yaml-cpp REQUIRED) find_package(dynamixel_sdk REQUIRED) if (MROVER_SIMULATOR) @@ -91,7 +90,7 @@ if (NOT APPLE) endif() if (MROVER_SIMULATOR) - set(Dawn_ROOT "${CMAKE_CURRENT_LIST_DIR}/deps/dawn-prebuilt") + list(PREPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}/deps/dawn-prebuilt") find_package(Dawn QUIET) if (NOT Dawn_FOUND) message(FATAL_ERROR "Dawn not found. Run 'scripts/setup_dawn.sh' before building.") @@ -99,21 +98,17 @@ if (MROVER_SIMULATOR) add_library(webgpu ALIAS dawn::webgpu_dawn) endif () -include(FetchContent) - -set(FETCHCONTENT_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}/deps/.fetchcontent") -set(FETCHCONTENT_UPDATES_DISCONNECTED ON) - -FetchContent_Declare(manif - GIT_REPOSITORY https://github.com/artivis/manif.git - GIT_TAG 0.0.5 - GIT_SHALLOW TRUE - SYSTEM -) -set(BUILD_TESTING_PREV ${BUILD_TESTING}) -set(BUILD_TESTING OFF) -FetchContent_MakeAvailable(manif) -set(BUILD_TESTING ${BUILD_TESTING_PREV}) +find_package(manif QUIET) +if (NOT manif_FOUND) + if (NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/deps/manif-src/CMakeLists.txt") + message(FATAL_ERROR "manif not found. Run 'scripts/setup_manif.sh' before building.") + endif () + set(BUILD_TESTING_PREV ${BUILD_TESTING}) + set(BUILD_TESTING OFF) + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/deps/manif-src" "${CMAKE_CURRENT_BINARY_DIR}/manif-build" EXCLUDE_FROM_ALL SYSTEM) + set(BUILD_TESTING ${BUILD_TESTING_PREV}) + add_library(MANIF::manif ALIAS manif) +endif () find_package(PkgConfig REQUIRED) pkg_search_module(NetLink libnl-3.0 IMPORTED_TARGET QUIET) @@ -123,13 +118,10 @@ pkg_search_module(GstApp gstreamer-app-1.0 IMPORTED_TARGET QUIET) pkg_search_module(LibUdev libudev IMPORTED_TARGET QUIET) if (MROVER_SIMULATOR) - FetchContent_Declare( - imgui - GIT_REPOSITORY https://github.com/ocornut/imgui.git - GIT_TAG v1.92.8 - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(imgui) + if (NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/deps/imgui-src/imgui.cpp") + message(FATAL_ERROR "imgui not found. Run 'scripts/setup_imgui.sh' before building.") + endif () + set(imgui_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/deps/imgui-src") # avoid fetching in imgui_demo.cpp and unnecessarily compiling it add_library(imgui STATIC ${imgui_SOURCE_DIR}/imgui.cpp @@ -205,7 +197,23 @@ rosidl_generate_interfaces(${PROJECT_NAME} DEPENDENCIES nav_msgs sensor_msgs geometry_msgs action_msgs ) -# Starter project +# rosidl sets raw source-prefixed paths on INTERFACE_INCLUDE_DIRECTORIES, which +# CMP0052 rejects. The policy explicitly permits such paths when wrapped in +# $, marking them as build-only (not exported). +if(TARGET ${PROJECT_NAME}__rosidl_generator_py) + get_target_property(_py_iid ${PROJECT_NAME}__rosidl_generator_py INTERFACE_INCLUDE_DIRECTORIES) + if(_py_iid) + set(_py_iid_wrapped "") + foreach(_dir IN LISTS _py_iid) + list(APPEND _py_iid_wrapped "$") + endforeach() + set_target_properties(${PROJECT_NAME}__rosidl_generator_py PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_py_iid_wrapped}" + ) + endif() +endif() + +# Starter project # TODO (ali): delete once AutonomyStarterProject.cmake is fixed mrover_add_node(starter_project_perception ${CMAKE_CURRENT_LIST_DIR}/starter_project/autonomy/src/*.cpp) target_link_libraries(starter_project_perception ${OpenCV_LIBS}) @@ -243,18 +251,23 @@ mrover_add_header_only_library(units units) mrover_add_header_only_library(loop_profiler loop_profiler) mrover_add_header_only_library(parameter_utils parameter_utils) mrover_add_header_only_library(gst_utils gst_utils) -target_link_libraries(gst_utils INTERFACE magic_enum::magic_enum PkgConfig::Gst PkgConfig::GstApp) +if (Gst_FOUND AND GstApp_FOUND) + target_link_libraries(gst_utils INTERFACE magic_enum::magic_enum PkgConfig::Gst PkgConfig::GstApp) +else () + target_link_libraries(gst_utils INTERFACE magic_enum::magic_enum) +endif () # Simulator if (MROVER_SIMULATOR) mrover_add_node(simulator simulator/*.cpp simulator simulator/pch.hpp) - ament_target_dependencies(simulator rclcpp rclcpp_components nav_msgs sensor_msgs geometry_msgs tf2 tf2_ros urdf yaml_cpp_vendor) + ament_target_dependencies(simulator rclcpp rclcpp_components nav_msgs sensor_msgs geometry_msgs tf2 tf2_ros urdf yaml_cpp_vendor ament_index_cpp) target_link_libraries(simulator assimp::assimp glfw3webgpu webgpu glfw webgpu_hpp imgui ${BULLET_LIBRARIES} lie Eigen3::Eigen opencv_core opencv_imgcodecs opencv_imgproc + yaml-cpp::yaml-cpp loop_profiler parameter_utils ) @@ -416,12 +429,12 @@ if (MROVER_BUILD_ESW AND NetLink_FOUND AND NetLinkRoute_FOUND) ament_target_dependencies(can_bridge rclcpp) endif () -# Teleop Qt5 Camera Client -find_package(Qt5 5.15 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets) +# Teleop Qt6 Camera Client +find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets) mrover_add_node(camera_client teleoperation/camera_client/*.*pp teleoperation/camera_client/include/pch.hpp) target_include_directories(camera_client PRIVATE teleoperation/camera_client/include) -target_link_libraries(camera_client gst_utils Qt::Widgets Qt::Multimedia Qt::MultimediaWidgets opencv_core opencv_imgcodecs) +target_link_libraries(camera_client gst_utils Qt6::Widgets Qt6::Multimedia Qt6::MultimediaWidgets opencv_core opencv_imgcodecs) ament_target_dependencies(camera_client rclcpp std_srvs sensor_msgs) set_target_properties(camera_client PROPERTIES AUTOMOC ON diff --git a/Dockerfile b/Dockerfile index 5430ce86c..da66bbfdf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:jammy +FROM ubuntu:noble # DEBIAN_FRONTEND=noninteractive prevents apt from asking for user input # software-properties-common is needed for apt-add-repository @@ -8,13 +8,13 @@ RUN apt-get update -y && apt-get install software-properties-common sudo -y RUN apt-add-repository ppa:ansible/ansible -y && apt-get install -y git git-lfs ansible RUN useradd --create-home --shell /bin/zsh mrover -# using per user rule over sudo group because a later group rule can require a -# password and beat an earlier NOPASSWD one for the same group +# using per user rule over sudo group because noble's default %sudo rule +# requires a password and beats a NOPASSWD one for the same group RUN echo 'mrover ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/mrover && chmod 0440 /etc/sudoers.d/mrover USER mrover -RUN mkdir -p /home/mrover/ros2_ws/src/mrover -WORKDIR /home/mrover/ros2_ws/src/mrover +RUN mkdir -p /home/mrover/mrover-ros2 +WORKDIR /home/mrover/mrover-ros2 # Defines the APT packages that need to be installed # rosdep is called from Ansible to install them ADD --chown=mrover:mrover ./package.xml . @@ -26,6 +26,7 @@ ADD --chown=mrover:mrover ./mrover ./mrover ADD --chown=mrover:mrover ./ansible ./ansible ADD --chown=mrover:mrover ./ansible.sh . ADD --chown=mrover:mrover ./pkg ./pkg +ADD --chown=mrover:mrover ./scripts ./scripts # clean in the same layer so apt cache/lists don't just get removed later and still count towards size RUN ./ansible.sh ci.yml && sudo apt-get clean && sudo rm -rf /var/lib/apt/lists/* diff --git a/ansible.sh b/ansible.sh index f85ce24c3..d05c389df 100755 --- a/ansible.sh +++ b/ansible.sh @@ -7,7 +7,6 @@ if [ "$#" -le 0 ]; then exit 1 fi -readonly MROVER_PATH=$(dirname "$0") -readonly ROS2_WS_PATH=$(realpath "${MROVER_PATH}"/../..) +readonly MROVER_PATH=$(dirname "$(realpath "$0")") -ansible-playbook -i "localhost," -c local -K "${MROVER_PATH}"/ansible/"$1" --extra-vars "ros2_workspace=${ROS2_WS_PATH} $2" +ansible-playbook -i "localhost," -c local -K "${MROVER_PATH}"/ansible/"$1" --extra-vars "mrover_repo=${MROVER_PATH}" ${2:+"$2"} diff --git a/ansible/basestation.yml b/ansible/basestation.yml index 7b468046d..100db349e 100644 --- a/ansible/basestation.yml +++ b/ansible/basestation.yml @@ -1,7 +1,7 @@ --- - hosts: all - vars: - ubuntu_release: focal + vars_files: + - vars/native.yml roles: # - dev - basestation_networks diff --git a/ansible/build.yml b/ansible/build.yml index 43f98c9ad..d8f18d67e 100644 --- a/ansible/build.yml +++ b/ansible/build.yml @@ -1,7 +1,6 @@ --- - hosts: all - vars: - ros_distro: humble - ubuntu_release: jammy + vars_files: + - vars/native.yml roles: - build diff --git a/ansible/ci.yml b/ansible/ci.yml index afcbed9e3..a3f13c51e 100644 --- a/ansible/ci.yml +++ b/ansible/ci.yml @@ -1,7 +1,6 @@ --- - hosts: all - vars: - ros_distro: humble - ubuntu_release: jammy + vars_files: + - vars/native.yml roles: - ci diff --git a/ansible/dev.yml b/ansible/dev.yml index 738e55bf9..22c1bb6c9 100644 --- a/ansible/dev.yml +++ b/ansible/dev.yml @@ -1,8 +1,7 @@ --- - hosts: all - vars: - ros_distro: humble - ubuntu_release: jammy + vars_files: + - vars/native.yml roles: - build - dev diff --git a/ansible/esw.yml b/ansible/esw.yml index 3743db0e3..0ec975565 100644 --- a/ansible/esw.yml +++ b/ansible/esw.yml @@ -1,7 +1,6 @@ --- - hosts: all - vars: - ros_distro: noetic - ubuntu_release: focal + vars_files: + - vars/native.yml roles: - esw diff --git a/ansible/jetson.yml b/ansible/jetson.yml index 4da65ff3a..e38901972 100644 --- a/ansible/jetson.yml +++ b/ansible/jetson.yml @@ -1,7 +1,6 @@ --- - hosts: all - vars: - ros_distro: noetic - ubuntu_release: focal + vars_files: + - vars/native.yml roles: - jetson_networks diff --git a/ansible/jetson_build.yml b/ansible/jetson_build.yml index 9d62181bc..0a100f3a1 100644 --- a/ansible/jetson_build.yml +++ b/ansible/jetson_build.yml @@ -1,8 +1,8 @@ --- - hosts: all + vars_files: + - vars/native.yml vars: - ros_distro: humble - ubuntu_release: jammy ifname: eth0 roles: - jetson_pre_build diff --git a/ansible/percep.yml b/ansible/percep.yml index 8ca278301..aa4d182c6 100644 --- a/ansible/percep.yml +++ b/ansible/percep.yml @@ -4,5 +4,4 @@ ros_distro: humble ubuntu_release: jammy roles: - - build - percep_build diff --git a/ansible/requirements.yml b/ansible/requirements.yml new file mode 100644 index 000000000..72fe72dfb --- /dev/null +++ b/ansible/requirements.yml @@ -0,0 +1,2 @@ +collections: + - name: community.general diff --git a/ansible/roles/basestation_networks/tasks/main.yml b/ansible/roles/basestation_networks/tasks/main.yml index 078a90b53..1602b119b 100644 --- a/ansible/roles/basestation_networks/tasks/main.yml +++ b/ansible/roles/basestation_networks/tasks/main.yml @@ -1,6 +1,6 @@ - name: Wired Connection - become: True - nmcli: + become: true + community.general.nmcli: conn_name: MRover state: present type: ethernet @@ -20,7 +20,7 @@ - name: Create MRover Group become: true - group: + ansible.builtin.group: name: "mrover" state: present diff --git a/ansible/roles/build/tasks/main.yml b/ansible/roles/build/tasks/main.yml index 8fc782dc7..27825247d 100644 --- a/ansible/roles/build/tasks/main.yml +++ b/ansible/roles/build/tasks/main.yml @@ -1,69 +1,31 @@ -# Allows us to install Python versions newer than 3.10 -- name: Add Python PPA Key - become: True - apt_key: - keyserver: keyserver.ubuntu.com - id: F23C5A6CF475977595C89F51BA6932366A755776 - keyring: /usr/share/keyrings/deadsnakes-ppa-keyring.gpg - -- name: Add Python PPA - become: True - apt_repository: - repo: deb [signed-by=/usr/share/keyrings/deadsnakes-ppa-keyring.gpg] http://ppa.launchpad.net/deadsnakes/ppa/ubuntu {{ ubuntu_release }} main - -# Allows us to install G++13, so we can use an updated libstdc++ which provides more standard library features (C++20) -- name: Add GCC PPA Key - become: True - apt_key: - keyserver: keyserver.ubuntu.com - id: 60C317803A41BA51845E371A1E9377A2BA9EF27F - keyring: /usr/share/keyrings/ubuntu-toolchain-r-ppa-keyring.gpg - -- name: Add GCC PPA - become: True - apt_repository: - repo: deb [signed-by=/usr/share/keyrings/ubuntu-toolchain-r-ppa-keyring.gpg] http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu {{ ubuntu_release }} main - -- name: Add LLVM APT Key - become: True - apt_key: - url: https://apt.llvm.org/llvm-snapshot.gpg.key - id: 6084F3CF814B57C1CF12EFD515CF4D18AF4F7421 - keyring: /usr/share/keyrings/llvm-archive-keyring.gpg +- name: Install python3-debian + become: true + ansible.builtin.apt: + name: python3-debian + state: present # Allows us to install LLVM tools -- name: Add LLVM APT List - become: True - apt_repository: - repo: deb [signed-by=/usr/share/keyrings/llvm-archive-keyring.gpg] https://apt.llvm.org/{{ ubuntu_release }}/ llvm-toolchain-{{ ubuntu_release }}-18 main - filename: llvm - -- name: Add CMake APT Key - become: True - apt_key: - url: https://apt.kitware.com/keys/kitware-archive-latest.asc - id: 4DBEBE3EEC96E7B8C6EC5BE99E92FDC6C5B9BA75 - keyring: /usr/share/keyrings/kitware-archive-keyring.gpg - -# Allows us to install CMake versions newer than 3.22 -- name: Add CMake APT List - become: True - apt_repository: - repo: deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ {{ ubuntu_release }} main - filename: kitware - -- name: Add ROS APT Key - become: True - apt_key: - url: https://raw.githubusercontent.com/ros/rosdistro/master/ros.key - id: C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 - keyring: /usr/share/keyrings/ros-archive-keyring.gpg - -- name: Add ROS APT List - become: True - apt_repository: - repo: deb [signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu {{ ubuntu_release }} main - filename: ros +- name: Add LLVM APT Repo + become: true + ansible.builtin.deb822_repository: + name: llvm + types: deb + uris: "https://apt.llvm.org/{{ ubuntu_release }}/" + suites: "llvm-toolchain-{{ ubuntu_release }}-18" + components: main + signed_by: https://apt.llvm.org/llvm-snapshot.gpg.key + register: llvm_repo + +- name: Add ROS APT Repo + become: true + ansible.builtin.deb822_repository: + name: ros + types: deb + uris: http://packages.ros.org/ros2/ubuntu + suites: "{{ ubuntu_release }}" + components: main + signed_by: https://raw.githubusercontent.com/ros/rosdistro/master/ros.key + register: ros_repo - name: Sync APT Preferences become: true @@ -72,18 +34,25 @@ dest: /etc/apt/preferences.d recursive: true +# deb822_repository doesn't call apt update, do so manually +- name: Update APT Cache if Repos Changed + become: true + ansible.builtin.apt: + update_cache: true + when: llvm_repo.changed or ros_repo.changed + - name: Upgrade APT Packages - become: True - apt: + become: true + ansible.builtin.apt: cache_valid_time: 604800 - state: latest + state: present upgrade: yes - name: Install APT Packages - become: True - apt: + become: true + ansible.builtin.apt: cache_valid_time: 604800 - state: latest + state: present name: - zsh - fzf @@ -122,51 +91,48 @@ - libgstreamer-plugins-base1.0-dev - vainfo - x264 - - ros-humble-ros-base - - ros-humble-rviz2 - - ros-humble-xacro - - ros-humble-magic-enum - - ros-humble-rtcm-msgs - - ros-humble-dynamixel-sdk + - ros-{{ ros_distro }}-ros-base + - ros-{{ ros_distro }}-rviz2 + - ros-{{ ros_distro }}-xacro + - ros-{{ ros_distro }}-magic-enum + - ros-{{ ros_distro }}-rtcm-msgs + - ros-{{ ros_distro }}-dynamixel-sdk # TODO (ali): why does this need to be installed manually - libboost-dev - - qtbase5-dev - - qtmultimedia5-dev - - libqt5multimedia5-plugins - - python3-pyqt5 - -# manif's build backend now requires packaging>=26.2, temp upgrade for ubuntu 22 -- name: Upgrade pip for manifpy build isolation - become: True - pip: - name: pip - state: latest + - qt6-base-dev + - qt6-multimedia-dev - name: Install manifpy - become: True - pip: - name: "git+https://github.com/artivis/manif.git@0.0.5" + become: true + ansible.builtin.command: pip install --break-system-packages "git+https://github.com/artivis/manif.git@0.0.5" - name: Download prebuilt Dawn - command: ./scripts/setup_dawn.sh + ansible.builtin.command: ./scripts/setup_dawn.sh + args: + chdir: "{{ mrover_repo }}" + +- name: Download manif source + ansible.builtin.command: ./scripts/setup_manif.sh + args: + chdir: "{{ mrover_repo }}" + +- name: Download imgui source + ansible.builtin.command: ./scripts/setup_imgui.sh args: - chdir: "{{ ansible_env.HOME }}/ros2_ws/src/mrover/" + chdir: "{{ mrover_repo }}" - name: Initialize rosdep - become: True - command: rosdep init + become: true + ansible.builtin.command: rosdep init args: # This command will be skipped if this file already exists creates: /etc/ros/rosdep/sources.list.d/20-default.list - name: Update rosdep - command: rosdep update - -# - name: Install ROS Packages -# # command: rosdep install --from-paths {{ ros2_workspace }}/src --ignore-src -y --rosdistro={{ ros_distro }} + ansible.builtin.command: rosdep update - name: Set G++ 13 as Default - become: True + become: true alternatives: name: g++ path: /usr/bin/g++-13 @@ -174,7 +140,7 @@ priority: 130 - name: Set GCC 13 as Default - become: True + become: true alternatives: name: gcc path: /usr/bin/gcc-13 @@ -182,7 +148,7 @@ priority: 130 - name: Set clang++18 as Default - become: True + become: true alternatives: name: clang++ path: /usr/bin/clang++-18 @@ -190,7 +156,7 @@ priority: 180 - name: Set clang-18 as Default - become: True + become: true alternatives: name: clang path: /usr/bin/clang-18 @@ -198,7 +164,7 @@ priority: 180 - name: Set clangd 18 as Default - become: True + become: true alternatives: name: clangd path: /usr/bin/clangd-18 @@ -206,7 +172,7 @@ priority: 180 - name: Set LLD 18 as Default - become: True + become: true alternatives: name: lld path: /usr/bin/lld-18 @@ -214,7 +180,7 @@ priority: 180 - name: Set clang-tidy 18 as Default - become: True + become: true alternatives: name: clang-tidy path: /usr/bin/clang-tidy-18 @@ -222,32 +188,32 @@ priority: 180 - name: Setup Python Virtual Environment - pip: + ansible.builtin.pip: name: # Installs from pyproject.toml - - "{{ ros2_workspace }}/src/mrover[dev]" - virtualenv: "{{ ros2_workspace }}/src/mrover/venv" - virtualenv_command: /usr/bin/python3.10 -m venv + - "{{ mrover_repo }}[dev]" + virtualenv: "{{ mrover_repo }}/venv" + virtualenv_command: /usr/bin/python3 -m venv - name: Install Chromium - become: True - snap: + become: true + ansible.builtin.snap: name: chromium - name: Download Bun installer - get_url: + ansible.builtin.get_url: url: https://bun.sh/install dest: /tmp/bun_install.sh - mode: '0755' + mode: "0755" - name: Install or Upgrade Bun - shell: /tmp/bun_install.sh + ansible.builtin.shell: /tmp/bun_install.sh args: executable: /bin/bash environment: BUN_INSTALL: "{{ ansible_env.HOME }}/.bun" - name: Install Bun Packages - command: "{{ ansible_env.HOME }}/.bun/bin/bun install" + ansible.builtin.command: "{{ ansible_env.HOME }}/.bun/bin/bun install" args: - chdir: "{{ ansible_env.HOME }}/ros2_ws/src/mrover/teleoperation/basestation_gui/frontend" + chdir: "{{ mrover_repo }}/teleoperation/basestation_gui/frontend" diff --git a/ansible/roles/ci/tasks/main.yml b/ansible/roles/ci/tasks/main.yml index 45899c6cb..6ec5a7d32 100644 --- a/ansible/roles/ci/tasks/main.yml +++ b/ansible/roles/ci/tasks/main.yml @@ -1,58 +1,41 @@ -# # Allows us to install Python versions newer than 3.10 (unused since Ubuntu 22 upgrade) -# - name: Add Python PPA -# become: True -# apt_repository: -# repo: ppa:deadsnakes/ppa - -# Allows us to install G++13, so we can use an updated libstdc++ which provides more standard library features (C++20) -- name: Add GCC PPA - become: True - apt_repository: - repo: ppa:ubuntu-toolchain-r/test - -- name: Add LLVM APT Key - become: True - ansible.builtin.get_url: - url: https://apt.llvm.org/llvm-snapshot.gpg.key - dest: /usr/share/keyrings/llvm-archive-keyring.asc - mode: '0644' +- name: Install python3-debian + become: true + ansible.builtin.apt: + name: python3-debian + state: present # Allows us to install LLVM tools -- name: Add LLVM APT List - become: True - apt_repository: - repo: "deb [signed-by=/usr/share/keyrings/llvm-archive-keyring.asc] https://apt.llvm.org/{{ ubuntu_release }}/ llvm-toolchain-{{ ubuntu_release }}-18 main" - filename: llvm - -- name: Add CMake APT Key - become: True - apt_key: - url: https://apt.kitware.com/keys/kitware-archive-latest.asc - keyring: /usr/share/keyrings/kitware-archive-keyring.gpg - -# Allows us to install CMake versions newer than 3.22 -- name: Add CMake APT List - become: True - apt_repository: - repo: deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ {{ ubuntu_release }} main - filename: kitware - -- name: Add ROS APT Key - become: True - ansible.builtin.get_url: - url: https://raw.githubusercontent.com/ros/rosdistro/master/ros.key - dest: /usr/share/keyrings/ros-archive-keyring.gpg - mode: '0644' - -- name: Add ROS APT List - become: True - apt_repository: - repo: "deb [signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu {{ ubuntu_release }} main" - filename: ros +- name: Add LLVM APT Repo + become: true + ansible.builtin.deb822_repository: + name: llvm + types: deb + uris: "https://apt.llvm.org/{{ ubuntu_release }}/" + suites: "llvm-toolchain-{{ ubuntu_release }}-18" + components: main + signed_by: https://apt.llvm.org/llvm-snapshot.gpg.key + register: llvm_repo + +- name: Add ROS APT Repo + become: true + ansible.builtin.deb822_repository: + name: ros + types: deb + uris: http://packages.ros.org/ros2/ubuntu + suites: "{{ ubuntu_release }}" + components: main + signed_by: https://raw.githubusercontent.com/ros/rosdistro/master/ros.key + register: ros_repo + +- name: Update APT Cache if Repos Changed + become: true + ansible.builtin.apt: + update_cache: true + when: llvm_repo.changed or ros_repo.changed - name: Install APT Packages - become: True - apt: + become: true + ansible.builtin.apt: cache_valid_time: 604800 state: present name: @@ -92,40 +75,49 @@ - libgstreamer-plugins-base1.0-dev # - vainfo # - x264 - - ros-humble-ros-base - - ros-humble-rviz2 - - ros-humble-xacro - - ros-humble-rtcm-msgs - - ros-humble-magic-enum - - ros-humble-dynamixel-sdk + - ros-{{ ros_distro }}-ros-base + - ros-{{ ros_distro }}-rviz2 + - ros-{{ ros_distro }}-xacro + - ros-{{ ros_distro }}-rtcm-msgs + - ros-{{ ros_distro }}-magic-enum + - ros-{{ ros_distro }}-dynamixel-sdk # TODO (ali): why does this need to be installed manually - libboost-dev - - qtmultimedia5-dev - -# manif's build backend now requires packaging>=26.2, upgrade it -- name: Upgrade pip for manifpy build isolation - become: True - pip: - name: pip - state: latest + - qt6-multimedia-dev - name: Install manifpy - become: True - pip: + become: true + ansible.builtin.pip: name: "git+https://github.com/artivis/manif.git@0.0.5" + extra_args: "--break-system-packages" + +- name: Download prebuilt Dawn + ansible.builtin.command: ./scripts/setup_dawn.sh + args: + chdir: "{{ mrover_repo }}" + +- name: Download manif source + ansible.builtin.command: ./scripts/setup_manif.sh + args: + chdir: "{{ mrover_repo }}" + +- name: Download imgui source + ansible.builtin.command: ./scripts/setup_imgui.sh + args: + chdir: "{{ mrover_repo }}" - name: Initialize rosdep - become: True - command: rosdep init + become: true + ansible.builtin.command: rosdep init args: # This command will be skipped if this file already exists creates: /etc/ros/rosdep/sources.list.d/20-default.list - name: Update rosdep - command: rosdep update + ansible.builtin.command: rosdep update - name: Set G++ 13 as Default - become: True + become: true alternatives: name: g++ path: /usr/bin/g++-13 @@ -133,7 +125,7 @@ priority: 130 - name: Set GCC 13 as Default - become: True + become: true alternatives: name: gcc path: /usr/bin/gcc-13 @@ -141,7 +133,7 @@ priority: 130 - name: Set clang++18 as Default - become: True + become: true alternatives: name: clang++ path: /usr/bin/clang++-18 @@ -149,7 +141,7 @@ priority: 180 - name: Set clang-18 as Default - become: True + become: true alternatives: name: clang path: /usr/bin/clang-18 @@ -165,7 +157,7 @@ # priority: 180 - name: Set LLD 18 as Default - become: True + become: true alternatives: name: lld path: /usr/bin/lld-18 @@ -173,7 +165,7 @@ priority: 180 - name: Set clang-tidy 18 as Default - become: True + become: true alternatives: name: clang-tidy path: /usr/bin/clang-tidy-18 @@ -181,9 +173,9 @@ priority: 180 - name: Setup Python Virtual Environment - pip: + ansible.builtin.pip: name: # Installs from pyproject.toml - - "{{ ros2_workspace }}/src/mrover[dev]" - virtualenv: "{{ ros2_workspace }}/src/mrover/venv" + - "{{ mrover_repo }}[dev]" + virtualenv: "{{ mrover_repo }}/venv" virtualenv_command: /usr/bin/python3 -m venv diff --git a/ansible/roles/dev/files/home/.oh-my-zsh/custom/themes/mrover.zsh-theme b/ansible/roles/dev/files/home/.oh-my-zsh/custom/themes/mrover.zsh-theme index 955a03d74..767f6b70d 100644 --- a/ansible/roles/dev/files/home/.oh-my-zsh/custom/themes/mrover.zsh-theme +++ b/ansible/roles/dev/files/home/.oh-my-zsh/custom/themes/mrover.zsh-theme @@ -1,9 +1,10 @@ function get_build_profile() { - if [[ -v MROVER_BUILD_PROFILE ]] && [[ "$PWD" == "${MROVER_ROS2_WS_PATH}/src/mrover" ]]; then + if [[ -v MROVER_BUILD_PROFILE ]] && [[ "$PWD" == "${MROVER_REPO}" ]]; then echo "%F{green}[${MROVER_BUILD_PROFILE}]%f " - fi + fi } + PROMPT="%(?:%{$fg_bold[green]%}➜ :%{$fg_bold[red]%}➜ ) %{$fg[yellow]%}%m %{$fg[gray]%}at %{$fg[yellow]%}%d%{$reset_color%}" PROMPT+=' $(git_prompt_info)' PROMPT+='$(get_build_profile)' diff --git a/ansible/roles/dev/files/home/.zshrc b/ansible/roles/dev/files/home/.zshrc index e1e581a6d..9e771ed4f 100644 --- a/ansible/roles/dev/files/home/.zshrc +++ b/ansible/roles/dev/files/home/.zshrc @@ -1,4 +1,4 @@ export ZSH="$HOME/.oh-my-zsh" ZSH_THEME="mrover" -plugins=(git virtualenvwrapper fzf zsh-autosuggestions zsh-syntax-highlighting) +plugins=(git fzf zsh-autosuggestions zsh-syntax-highlighting) source $ZSH/oh-my-zsh.sh diff --git a/ansible/roles/dev/tasks/apt.yml b/ansible/roles/dev/tasks/apt.yml new file mode 100644 index 000000000..955d8851d --- /dev/null +++ b/ansible/roles/dev/tasks/apt.yml @@ -0,0 +1,48 @@ +- name: Install python3-debian + become: true + ansible.builtin.apt: + name: python3-debian + state: present + +- name: Add GitHub CLI apt repo + become: true + ansible.builtin.deb822_repository: + name: github-cli + types: deb + uris: https://cli.github.com/packages + suites: stable + components: main + signed_by: https://cli.github.com/packages/githubcli-archive-keyring.gpg + register: github_cli_repo + +- name: Add VSCode apt repo + become: true + ansible.builtin.deb822_repository: + name: vscode + types: deb + uris: https://packages.microsoft.com/repos/code + suites: stable + components: main + architectures: [amd64, arm64, armhf] + signed_by: https://packages.microsoft.com/keys/microsoft.asc + register: vscode_repo + +- name: Update APT Cache if Repos Changed + become: true + ansible.builtin.apt: + update_cache: true + when: github_cli_repo.changed or vscode_repo.changed + +- name: Install apt packages + become: true + ansible.builtin.apt: + cache_valid_time: 3600 + state: present + name: + - zsh + - fzf + - tmux + - htop + - gh + - code + - git-lfs diff --git a/ansible/roles/dev/tasks/main.yml b/ansible/roles/dev/tasks/main.yml index 72483afbe..894b4f7bb 100644 --- a/ansible/roles/dev/tasks/main.yml +++ b/ansible/roles/dev/tasks/main.yml @@ -1,93 +1,86 @@ -- name: Oh-My-Zsh - git: +- name: Install platform-specific packages + # dnf5 hosts get the same tasks as dnf, no dnf5.yml needed + ansible.builtin.include_tasks: + file: "{{ 'dnf' if ansible_pkg_mgr == 'dnf5' else ansible_pkg_mgr }}.yml" + +- name: Install oh-my-zsh + ansible.builtin.git: repo: https://github.com/ohmyzsh/ohmyzsh.git dest: ~/.oh-my-zsh version: master -- name: Dotfiles - synchronize: - # The trailing slash is very important here - # It tells rsync to copy only the CONTENTS of the folder and not the folder itself - # This is vital to make sure this works will any usernames - src: files/home/ - dest: ~/ - recursive: true - # .zshrc is handled below instead of being overwritten outright, so a - # user's own customizations to it survive re-runs - rsync_opts: - - "--exclude=.zshrc" +- name: Install zsh-autosuggestions + ansible.builtin.git: + repo: https://github.com/zsh-users/zsh-autosuggestions + dest: ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions -- name: Source mrover tmux config - blockinfile: - path: ~/.tmux.conf - marker: "# {mark} MROVER" - block: source-file ~/.mrover.tmux.conf - create: true +- name: Install zsh-syntax-highlighting + ansible.builtin.git: + repo: https://github.com/zsh-users/zsh-syntax-highlighting + dest: ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting -- name: Source mrover zshenv - blockinfile: - path: ~/.zshenv - marker: "# {mark} MROVER" - block: source ~/ros2_ws/src/mrover/scripts/mrover.zshenv # hardcoded for now, change in re-arch - create: true +- name: Deploy mrover oh-my-zsh theme + ansible.builtin.copy: + src: files/home/.oh-my-zsh/custom/themes/mrover.zsh-theme + dest: ~/.oh-my-zsh/custom/themes/mrover.zsh-theme - name: Check for existing zshrc - stat: + ansible.builtin.stat: path: ~/.zshrc register: zshrc_stat - name: Deploy default oh-my-zsh zshrc for fresh installs - copy: + ansible.builtin.copy: src: files/home/.zshrc dest: ~/.zshrc when: not zshrc_stat.stat.exists -- name: ZSH Automatic Suggestions Plugin - git: - repo: https://github.com/zsh-users/zsh-autosuggestions - dest: ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions - -- name: ZSH Syntax Highlighting Plugin - git: - repo: https://github.com/zsh-users/zsh-syntax-highlighting - dest: ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting +- name: Wire mrover shell env + ansible.builtin.blockinfile: + path: ~/.zshrc + marker: "# {mark} MROVER" + block: | + export MROVER_REPO="{{ mrover_repo }}" + source "${MROVER_REPO}/scripts/mrover.zshenv" + create: true -- name: Use ZSH as a default shell - become: true - command: chsh --shell /usr/bin/zsh {{ ansible_user_id }} +- name: Deploy mrover tmux config + ansible.builtin.copy: + src: files/home/.mrover.tmux.conf + dest: ~/.mrover.tmux.conf -- name: GitHub CLI APT Key - become: True - apt_key: - url: https://cli.github.com/packages/githubcli-archive-keyring.gpg - keyring: /usr/share/keyrings/githubcli-archive-keyring.gpg +- name: Source mrover tmux config + ansible.builtin.blockinfile: + path: ~/.tmux.conf + marker: "# {mark} MROVER" + block: source-file ~/.mrover.tmux.conf + create: true -- name: GitHub APT List - become: True - apt_repository: - repo: deb [signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main - filename: github-cli +- name: Locate zsh binary + ansible.builtin.command: which zsh + register: zsh_path + changed_when: false -- name: Add VSCode APT Key +- name: Set zsh as default shell become: true - apt_key: - url: https://packages.microsoft.com/keys/microsoft.asc - keyring: /usr/share/keyrings/packages.microsoft.gpg + ansible.builtin.user: + name: "{{ ansible_facts['user_id'] }}" + shell: "{{ zsh_path.stdout }}" -- name: Add VSCode APT List - become: true - apt_repository: - filename: vscode - repo: "deb [arch=amd64,arm64,armhf signed-by=/usr/share/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" +- name: Initialize Git LFS + ansible.builtin.command: git lfs install + args: + chdir: "{{ mrover_repo }}" -- name: Install APT Packages - become: true - apt: - cache_valid_time: 604800 - state: latest - name: - - gh - - code +- name: Pull Git LFS objects + ansible.builtin.command: git lfs pull + args: + chdir: "{{ mrover_repo }}" + +- name: Initialize Git submodules + ansible.builtin.command: git submodule update --init --recursive + args: + chdir: "{{ mrover_repo }}" -- name: Install vscode debugger extension - command: code --install-extension ../pkg/file-selector-0.0.1.vsix +- name: Install VSCode extension + ansible.builtin.command: code --install-extension {{ mrover_repo }}/pkg/file-selector-0.0.1.vsix diff --git a/ansible/roles/jetson_build/tasks/main.yml b/ansible/roles/jetson_build/tasks/main.yml index c2acd26ff..55de439dc 100644 --- a/ansible/roles/jetson_build/tasks/main.yml +++ b/ansible/roles/jetson_build/tasks/main.yml @@ -5,7 +5,7 @@ - name: Download CUDA Keyring get_url: - url: https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/arm64/cuda-keyring_1.1-1_all.deb + url: https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/arm64/cuda-keyring_1.1-1_all.deb dest: /tmp/cuda-keyring_1.1-1_all.deb - name: Install CUDA Keyring @@ -25,13 +25,13 @@ - name: ZED SDK Download get_url: - url: https://download.stereolabs.com/zedsdk/5.1/l4t36.4/jetsons - dest: /tmp/ZED_SDK_Tegra_L4T36.4_v5.1.2.zstd.run + url: https://download.stereolabs.com/zedsdk/5.4/l4t39.2/jetsons + dest: /tmp/ZED_SDK_Tegra_L4T39.2_v5.4.1.zstd.run mode: 0755 - name: ZED SDK Install # Silent mode prevents any user input prompting - command: /tmp/ZED_SDK_Tegra_L4T36.4_v5.1.2.zstd.run -- silent + command: /tmp/ZED_SDK_Tegra_L4T39.2_v5.4.1.zstd.run -- silent args: creates: /usr/local/zed @@ -61,7 +61,7 @@ become: true command: ./ansible/roles/jetson_build/files/scripts/build_opencv.sh args: - chdir: "{{ ansible_env.HOME }}/ros2_ws/src/mrover/" + chdir: "{{ mrover_repo }}" creates: /usr/local/include/opencv4 - name: Sync Bin diff --git a/ansible/roles/jetson_flash/tasks/main.yml b/ansible/roles/jetson_flash/tasks/main.yml index 2608a449a..ef8c789d8 100644 --- a/ansible/roles/jetson_flash/tasks/main.yml +++ b/ansible/roles/jetson_flash/tasks/main.yml @@ -106,14 +106,14 @@ command: ./ansible/roles/jetson_flash/files/scripts/build_jetson_kernel.sh failed_when: False # this is not ideal args: - chdir: "{{ ansible_env.HOME }}/ros2_ws/src/mrover/" + chdir: "{{ mrover_repo }}" # no creates here because it is always desired to recompile the kernel if running this ansible - name: Build PCAN become: true command: ./ansible/roles/jetson_flash/files/scripts/build_pcan_drivers.sh {{ pcan_version_major }} {{ pcan_version_minor }} {{ pcan_version_patch }} args: - chdir: "{{ ansible_env.HOME }}/ros2_ws/src/mrover/" + chdir: "{{ mrover_repo }}" # no creates here because we always rebuild - name: Flash Jetson diff --git a/ansible/roles/jetson_networks/tasks/main.yml b/ansible/roles/jetson_networks/tasks/main.yml index 5ef3e5e06..a0e2ee4bc 100644 --- a/ansible/roles/jetson_networks/tasks/main.yml +++ b/ansible/roles/jetson_networks/tasks/main.yml @@ -1,6 +1,6 @@ - name: Wired Connection - become: True - nmcli: + become: true + community.general.nmcli: conn_name: MRover state: present type: ethernet diff --git a/ansible/roles/percep_build/tasks/main.yml b/ansible/roles/percep_build/tasks/main.yml index 075627ec4..f6fb094c8 100644 --- a/ansible/roles/percep_build/tasks/main.yml +++ b/ansible/roles/percep_build/tasks/main.yml @@ -3,34 +3,45 @@ # apt: # name: nvidia-driver-{{driver_edition}} # +- name: Check NVIDIA Driver Install + ansible.builtin.command: nvidia-smi + register: nvidia_smi_output + ignore_errors: true + changed_when: false + +- name: Check Driver Status + ansible.builtin.fail: + msg: "NVIDIA driver is not installed or nvidia-smi is not in PATH. Install nvidia drivers before running this playbook" + when: nvidia_smi_output.rc != 0 + - name: Download CUDA Keyring get_url: - url: https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb + url: https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb dest: /tmp/cuda-keyring_1.1-1_all.deb - name: Install CUDA Keyring become: true - apt: + ansible.builtin.apt: deb: /tmp/cuda-keyring_1.1-1_all.deb - name: Install APT Packages - become: True - apt: + become: true + ansible.builtin.apt: update_cache: true state: latest name: - - cuda-12-3 + - cuda-toolkit-13-2 - g++-9 - zstd # Required to unpack ZED installer - name: ZED SDK Download get_url: - url: https://download.stereolabs.com/zedsdk/4.1/cu121/ubuntu22 - dest: /tmp/ZED_SDK_Ubuntu22_cuda12.1_v4.1.4.zstd.run + url: https://download.stereolabs.com/zedsdk/5.4/cu13/ubuntu24 + dest: ~/Downloads/ZED_SDK_Ubuntu24_cuda13.0_tensorrt10.13_v5.4.1.zstd.run mode: 0755 - name: ZED SDK Install # Silent mode prevents any user input prompting - command: /tmp/ZED_SDK_Ubuntu22_cuda12.1_v4.1.4.zstd.run -- silent + command: ~/Downloads/ZED_SDK_Ubuntu24_cuda13.0_tensorrt10.13_v5.4.1.zstd.run args: creates: /usr/local/zed diff --git a/ansible/roles/science_networks/tasks/main.yml b/ansible/roles/science_networks/tasks/main.yml index 6042dbfa7..33c61fbc5 100644 --- a/ansible/roles/science_networks/tasks/main.yml +++ b/ansible/roles/science_networks/tasks/main.yml @@ -1,6 +1,6 @@ - name: Wired Connection - become: True - nmcli: + become: true + community.general.nmcli: conn_name: MRover state: present type: ethernet diff --git a/ansible/science.yml b/ansible/science.yml index b03381daa..67d693e1e 100644 --- a/ansible/science.yml +++ b/ansible/science.yml @@ -1,7 +1,7 @@ --- - hosts: all - vars: - ubuntu_release: focal + vars_files: + - vars/native.yml roles: # - dev - science_networks diff --git a/ansible/vars/native.yml b/ansible/vars/native.yml new file mode 100644 index 000000000..fce641ae3 --- /dev/null +++ b/ansible/vars/native.yml @@ -0,0 +1,2 @@ +ros_distro: jazzy +ubuntu_release: noble diff --git a/bootstrap.sh b/bootstrap.sh index e44322998..b95f39355 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,67 +1,39 @@ #!/usr/bin/env bash - -# Run on a fresh Ubuntu 22 install. -# Installs Ansible and Git, then clones the mrover repo -# Ansible will be used to finish configuring the system +# First-time native Ubuntu 24 setup. +# Ensures git is installed, clones the repo, then runs setup.sh. +# If you already have the repo, just run setup.sh directly. # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ set -Eeuo pipefail readonly RED_BOLD='\033[1;31m' -readonly BLUE_BOLD='\033[1;34m' readonly GREY_BOLD='\033[1;30m' -readonly YELLOW_BOLD='\033[1;33m' readonly NC='\033[0m' +if ! grep -q '^VERSION_CODENAME=noble' /etc/os-release 2>/dev/null; then + echo -e "${RED_BOLD}This script requires Ubuntu 24.04.${NC}" + exit 1 +fi + echo -e "${GREY_BOLD}Ensuring SSH keys are set up ...${NC}" if [ ! -f ~/.ssh/id_ed25519 ] && [ ! -f ~/.ssh/id_rsa ]; then echo -e "${RED_BOLD}Please see: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent${NC}" exit 1 fi -PPAS=( - ansible/ansible - git-core/ppa -) -NEED_APT_UPDATE=false -for PPA in "${PPAS[@]}"; do - if ! grep -q "^deb .*${PPA}" /etc/apt/sources.list /etc/apt/sources.list.d/*; - then - echo -e "${GREY_BOLD}Adding PPA: ${PPA}${NC}" - sudo apt-add-repository ppa:"${PPA}" -y - NEED_APT_UPDATE=true - fi -done - -if [ "${NEED_APT_UPDATE}" = true ]; then - sudo apt update -fi -sudo apt install -y ansible git git-lfs - -readonly DEFAULT_CATKIN_PATH=~/ros2_ws - -echo -e "${BLUE_BOLD}[ADVANCED] Enter path to ROS workspace... [leave blank for ${DEFAULT_CATKIN_PATH}]:${NC}" -read -r CATKIN_PATH -if [ -z "${CATKIN_PATH}" ]; then - CATKIN_PATH=${DEFAULT_CATKIN_PATH} +# git via PPA +if ! grep -rq "^deb .*git-core/ppa" /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null; then + echo -e "${GREY_BOLD}Adding PPA: git-core/ppa${NC}" + sudo apt-add-repository ppa:git-core/ppa -y + sudo apt update fi -echo -e "${GREY_BOLD}Using ${CATKIN_PATH} as ROS workspace${NC}" +sudo apt install -y git git-lfs -readonly MROVER_PATH=${CATKIN_PATH}/src/mrover -FIRST_TIME_SETUP=false +readonly MROVER_PATH=~/mrover-ros2 -if [ ! -d "${MROVER_PATH}" ]; then - echo -e "${GREY_BOLD}Creating ROS workspace ...${NC}" - mkdir -p "${CATKIN_PATH}"/src - git clone git@github.com:umrover/mrover-ros2 "${CATKIN_PATH}"/src/mrover - cd "${CATKIN_PATH}"/src/mrover - FIRST_TIME_SETUP=true +if [ ! -d "${MROVER_PATH}/.git" ]; then + echo -e "${GREY_BOLD}Cloning mrover-ros2 ...${NC}" + git clone git@github.com:umrover/mrover-ros2 "${MROVER_PATH}" fi -echo -e "${GREY_BOLD}Using Ansible to finish up ...${NC}" -"${MROVER_PATH}"/ansible.sh dev.yml - -if [ "${FIRST_TIME_SETUP}" ]; then - echo -e "${GREY_BOLD}All done! Welcome to MRover!${NC}" - echo -e "${YELLOW_BOLD}Please log out and back in!${NC}" -fi +exec "${MROVER_PATH}/setup.sh" diff --git a/build.sh b/build.sh index 00500639a..76aa6d075 100755 --- a/build.sh +++ b/build.sh @@ -16,9 +16,6 @@ fi echo "Using build profile: $build_profile" -# Build in the colcon workspace, not the package -pushd ../.. - # Set C/C++ compilers export CC=clang export CXX=clang++ @@ -37,4 +34,4 @@ COLCON_EXTENSION_BLOCKLIST=colcon_core.event_handler.desktop_notification colcon rm -rf "$(pwd)/build/$build_profile/mrover/.cmake/api" -ln -sf "$(pwd)/build/$build_profile/compile_commands.json" "$(pwd)/src/mrover/compile_commands.json" +ln -sf "$(pwd)/build/$build_profile/mrover/compile_commands.json" "$(pwd)/compile_commands.json" diff --git a/clean.sh b/clean.sh index 2b3e7d5db..d10f34f85 100755 --- a/clean.sh +++ b/clean.sh @@ -7,6 +7,4 @@ if [[ "${1:-}" == "--esw" ]]; then rm -rf deps/.fetchcontent/esw fi -pushd ../.. - -rm -rf build install log +rm -rf build install log compile_commands.json diff --git a/perception/panorama.py b/perception/panorama.py index 934041f64..065f643bd 100755 --- a/perception/panorama.py +++ b/perception/panorama.py @@ -2,7 +2,6 @@ import rclpy from rclpy.node import Node -from ament_index_python import get_package_share_directory from sensor_msgs.msg import PointCloud2, Image from std_msgs.msg import Header @@ -285,8 +284,8 @@ def end_callback(self, _, response): # Save the images unique_id = "{date:%Y-%m-%d_%H:%M:%S}".format(date=datetime.datetime.now()) - share_dir = get_package_share_directory("mrover") - new_path = f"{share_dir}/../../../../../src/mrover/data/raw-pano-images/{unique_id}/" + mrover_repo = os.environ.get("MROVER_REPO", os.path.expanduser("~/mrover-ros2")) + new_path = f"{mrover_repo}/data/raw-pano-images/{unique_id}/" os.mkdir(new_path) for i, img in enumerate(self.img_list): name = f"{new_path}/{str(i).zfill(2)}.png" # TODO: pathlib diff --git a/scripts/fix_sudo_become.sh b/scripts/fix_sudo_become.sh new file mode 100755 index 000000000..7795a9f62 --- /dev/null +++ b/scripts/fix_sudo_become.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Run this manually if ./ansible.sh prompts for the become password more +# than once during a single run: https://github.com/ansible/ansible/issues/85536 + +set -Eeuo pipefail + +readonly SUDOERS_FILE="/etc/sudoers.d/mrover-timestamp-type" + +echo "Defaults timestamp_type=global" | sudo tee "${SUDOERS_FILE}" >/dev/null +sudo chmod 0440 "${SUDOERS_FILE}" +sudo visudo -c diff --git a/scripts/mrover.zshenv b/scripts/mrover.zshenv index 9a43b57fa..69ea7625d 100644 --- a/scripts/mrover.zshenv +++ b/scripts/mrover.zshenv @@ -1,17 +1,18 @@ # MRover ROS -readonly MROVER_ROS2_WS_PATH="$HOME/ros2_ws" +export MROVER_REPO="${MROVER_REPO:-$HOME/mrover-ros2}" +readonly MROVER_REPO -source /opt/ros/humble/setup.zsh +source /opt/ros/jazzy/setup.zsh export ROS_DOMAIN_ID=5 export COLCON_TRACE=0 -remove_ros2_ws_from_path(){ - export ${1}="$(echo ${(P)1} | tr ':' '\n' | grep -v "ros2_ws" | paste -s -d ':')" +remove_mrover_from_path(){ + export ${1}="$(echo ${(P)1} | tr ':' '\n' | grep -vF "${MROVER_REPO}" | paste -s -d ':')" } source_mrover_overlay(){ - source ~/ros2_ws/src/mrover/venv/bin/activate + source "${MROVER_REPO}/venv/bin/activate" build_profiles=("RelWithDebInfo" "Release" "Debug") unset MROVER_BUILD_PROFILE @@ -19,7 +20,7 @@ source_mrover_overlay(){ target_file="" for profile in "${build_profiles[@]}"; do - file="${MROVER_ROS2_WS_PATH}/install/${profile}/setup.zsh" + file="${MROVER_REPO}/install/${profile}/setup.zsh" if [ -f "${file}" ]; then if [[ -z "${target_file}" ]]; then @@ -33,15 +34,17 @@ source_mrover_overlay(){ done # clean up current ROS environment - remove_ros2_ws_from_path LD_LIBRARY_PATH - remove_ros2_ws_from_path AMENT_PREFIX_PATH - remove_ros2_ws_from_path PYTHONPATH - remove_ros2_ws_from_path COLCON_PREFIX_PATH - remove_ros2_ws_from_path CMAKE_PREFIX_PATH + remove_mrover_from_path LD_LIBRARY_PATH + remove_mrover_from_path AMENT_PREFIX_PATH + remove_mrover_from_path PYTHONPATH + remove_mrover_from_path COLCON_PREFIX_PATH + remove_mrover_from_path CMAKE_PREFIX_PATH if [ -f "${target_file}" ]; then source "${target_file}" >> /dev/null fi + + command -v register-python-argcomplete3 &>/dev/null && command -v colcon &>/dev/null && eval "$(register-python-argcomplete3 colcon)" } # cuda @@ -53,14 +56,15 @@ export BUN_INSTALL="$HOME/.bun" export PATH="$BUN_INSTALL/bin:$PATH" [ -s "$BUN_INSTALL/_bun" ] && source "$BUN_INSTALL/_bun" -alias mrover="cd ~/ros2_ws/src/mrover && source_mrover_overlay" -function build_mrover() { - ./build.sh ${1} && mrover +alias mrover="cd ${MROVER_REPO} && source_mrover_overlay" + +build_mrover(){ + cd "${MROVER_REPO}" && ./build.sh "${1}" && mrover } -alias clean_mrover="./clean.sh && mrover" -# ros2 completions +alias clean_mrover="cd ${MROVER_REPO} && ./clean.sh && mrover" + if command -v register-python-argcomplete3 &>/dev/null; then eval "$(register-python-argcomplete3 ros2)" - eval "$(register-python-argcomplete3 colcon)" + command -v colcon &>/dev/null && eval "$(register-python-argcomplete3 colcon)" fi diff --git a/scripts/pano-copy.sh b/scripts/pano-copy.sh index 6e6e6ba09..2ee07861a 100755 --- a/scripts/pano-copy.sh +++ b/scripts/pano-copy.sh @@ -7,7 +7,7 @@ FOLDER=~/Desktop/science_$(date +%Y-%m-%d_%H-%M-%S) mkdir $FOLDER # shellcheck disable=SC2086 -scp -r jetson:/home/mrover/ros2_ws/src/mrover/data/raw-pano-images $FOLDER +scp -r jetson:/home/mrover/mrover-ros2/data/raw-pano-images $FOLDER now_secs=$(date +%s) today=$(date +%Y-%m-%d) diff --git a/scripts/setup_dawn.sh b/scripts/setup_dawn.sh index 447fbe72b..371cca353 100755 --- a/scripts/setup_dawn.sh +++ b/scripts/setup_dawn.sh @@ -40,6 +40,7 @@ if [ -d "${tmpdir}/dawn/lib64" ] && [ ! -e "${tmpdir}/dawn/lib" ]; then fi rm -rf "${DEST}" +mkdir -p "$(dirname "${DEST}")" mv "${tmpdir}/dawn" "${DEST}" echo "${DAWN_SHA}" > "${VERSION_FILE}" diff --git a/scripts/setup_imgui.sh b/scripts/setup_imgui.sh new file mode 100755 index 000000000..c529cc0ee --- /dev/null +++ b/scripts/setup_imgui.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Clones the imgui source to deps/imgui-src/ so build.sh never needs network access. + +set -Eeuo pipefail + +readonly IMGUI_TAG="v1.92.8" + +readonly REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +readonly DEST="${REPO_ROOT}/deps/imgui-src" +readonly VERSION_FILE="${DEST}/.version" + +if [ -f "${VERSION_FILE}" ] && [ "$(cat "${VERSION_FILE}")" = "${IMGUI_TAG}" ]; then + exit 0 +fi + +tmpdir=$(mktemp -d) +trap 'rm -rf "${tmpdir}"' EXIT + +echo "Cloning imgui ${IMGUI_TAG}..." +git clone --quiet --depth 1 --branch "${IMGUI_TAG}" https://github.com/ocornut/imgui.git "${tmpdir}/imgui" + +rm -rf "${DEST}" +mkdir -p "$(dirname "${DEST}")" +mv "${tmpdir}/imgui" "${DEST}" + +echo "${IMGUI_TAG}" > "${VERSION_FILE}" +echo "imgui ${IMGUI_TAG} installed." diff --git a/scripts/setup_manif.sh b/scripts/setup_manif.sh new file mode 100755 index 000000000..0f529990a --- /dev/null +++ b/scripts/setup_manif.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Clones the manif source to deps/manif-src/ so build.sh never needs network access. + +set -Eeuo pipefail + +readonly MANIF_TAG="0.0.5" + +readonly REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +readonly DEST="${REPO_ROOT}/deps/manif-src" +readonly VERSION_FILE="${DEST}/.version" + +if [ -f "${VERSION_FILE}" ] && [ "$(cat "${VERSION_FILE}")" = "${MANIF_TAG}" ]; then + exit 0 +fi + +tmpdir=$(mktemp -d) +trap 'rm -rf "${tmpdir}"' EXIT + +echo "Cloning manif ${MANIF_TAG}..." +git clone --quiet --depth 1 --branch "${MANIF_TAG}" https://github.com/artivis/manif.git "${tmpdir}/manif" + +rm -rf "${DEST}" +mkdir -p "$(dirname "${DEST}")" +mv "${tmpdir}/manif" "${DEST}" + +echo "${MANIF_TAG}" > "${VERSION_FILE}" +echo "manif ${MANIF_TAG} installed." diff --git a/setup.sh b/setup.sh new file mode 100755 index 000000000..274f82913 --- /dev/null +++ b/setup.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Native Ubuntu 24 setup. Run after cloning. + +set -Eeuo pipefail + +readonly CYAN='\033[1;36m' +readonly GREEN='\033[1;32m' +readonly RED='\033[1;31m' +readonly NC='\033[0m' + +if ! grep -q '^VERSION_CODENAME=noble' /etc/os-release 2>/dev/null; then + echo -e "${RED}This script requires Ubuntu 24.${NC}" >&2 + exit 1 +fi + +if ! command -v ansible-playbook >/dev/null 2>&1; then + echo -e "${CYAN}Installing Ansible ...${NC}" + if ! grep -rq "^deb .*ansible/ansible" /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null; then + sudo apt-add-repository ppa:ansible/ansible -y + sudo apt update + fi + sudo apt install -y ansible +fi + +if ! command -v git-lfs >/dev/null 2>&1; then + echo -e "${CYAN}Installing git-lfs ...${NC}" + sudo apt install -y git-lfs +fi + +readonly MROVER_PATH=$(dirname "$(realpath "$0")") +cd "${MROVER_PATH}" + +echo -e "${CYAN}Installing Ansible collections ...${NC}" +ansible-galaxy collection install -r ansible/requirements.yml + +echo -e "${CYAN}Running Ansible ...${NC}" +"${MROVER_PATH}/ansible.sh" dev.yml + +echo "" +echo -e "${GREEN}================================================================${NC}" +echo -e "${GREEN} Done! Log out and back in to apply shell changes.${NC}" +echo -e "${GREEN}================================================================${NC}" +echo "" diff --git a/teleoperation/camera_client/src/GstVideoWidgets.cpp b/teleoperation/camera_client/src/GstVideoWidgets.cpp index 09a49e828..205d870e4 100644 --- a/teleoperation/camera_client/src/GstVideoWidgets.cpp +++ b/teleoperation/camera_client/src/GstVideoWidgets.cpp @@ -70,7 +70,7 @@ auto GstVideoWidget::applyPipeline() -> void { flipElement = " ! videoflip method=counterclockwise"; } - mPlayer->setMedia(QUrl(std::format("gst-pipeline: {} ! videoconvert ! xvimagesink name=\"qtvideosink\" sync=false", mBasePipeline, flipElement).c_str())); + mPlayer->setSource(QUrl(std::format("gst-pipeline: {} ! videoconvert ! xvimagesink name=\"qtvideosink\" sync=false", mBasePipeline, flipElement).c_str())); play(); }