From e62d5fe807052693cbfc8710742afd00585b546e Mon Sep 17 00:00:00 2001 From: Esteve Fernandez Date: Fri, 15 May 2026 17:47:03 +0100 Subject: [PATCH] chore: add TurtleBot 4 packages Signed-off-by: Esteve Fernandez --- packages-ignore.yaml | 4 + patch/dependencies.yaml | 2 + patch/ros-jazzy-depthai.patch | 133 +++++++++++++++++++ patch/ros-jazzy-turtlebot4-base.patch | 179 ++++++++++++++++++++++++++ robostack.yaml | 10 ++ vinca.yaml | 20 +++ 6 files changed, 348 insertions(+) create mode 100644 patch/ros-jazzy-depthai.patch create mode 100644 patch/ros-jazzy-turtlebot4-base.patch diff --git a/packages-ignore.yaml b/packages-ignore.yaml index eb1a61627..3c398a2c4 100644 --- a/packages-ignore.yaml +++ b/packages-ignore.yaml @@ -2,6 +2,10 @@ rti-connext-dds-5.3.1: conda-forge: [] +# System service/runtime package used by TurtleBot 4 setup. +network-manager: + robostack: [] + # rmw_cyclonedds_cpp: # conda-forge: [] # rviz_ogre_vendor: diff --git a/patch/dependencies.yaml b/patch/dependencies.yaml index 22bf71c77..6f114cecc 100644 --- a/patch/dependencies.yaml +++ b/patch/dependencies.yaml @@ -92,6 +92,8 @@ backward_ros: # binutils is added only on linux to avoid the -liberty library not found in macos # see https://github.com/RoboStack/ros-jazzy/pull/95#issuecomment-3113166166 add_host: ["${{ 'binutils' if linux }}", "${{ 'elfutils' if linux }}", "ros-jazzy-ament-cmake-libraries"] +depthai: + add_host: ["${{ 'elfutils' if linux }}"] nav2_smac_planner: add_build: ["${{ 'llvm-openmp' if osx }}"] add_host: ["${{ 'llvm-openmp' if osx }}", "ompl", "libode"] diff --git a/patch/ros-jazzy-depthai.patch b/patch/ros-jazzy-depthai.patch new file mode 100644 index 000000000..34ed73b2a --- /dev/null +++ b/patch/ros-jazzy-depthai.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Esteve Fernandez +Date: Tue, 12 May 2026 14:01:42 +0100 +Subject: [PATCH] fix(depthai): make conda builds use bundled release sources + +Signed-off-by: Esteve Fernandez + +--- + CMakeLists.txt | 2 ++ + shared/depthai-bootloader-shared.cmake | 37 ++++++++++++++++++---------------- + shared/depthai-shared.cmake | 35 +++++++++++++++++--------------- + 3 files changed, 41 insertions(+), 33 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 109d9da..24d9aff 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -60,6 +60,8 @@ else() + message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}") + endif() + ++set(HUNTER_ROOT "${CMAKE_BINARY_DIR}/.hunter" CACHE PATH "Hunter package cache") ++set(DEPTHAI_ENABLE_CURL OFF CACHE BOOL "Enable CURL support" FORCE) + include("cmake/HunterGate.cmake") + HunterGate( + URL "https://github.com/cpp-pm/hunter/archive/9d9242b60d5236269f894efd3ddd60a9ca83dd7f.tar.gz" +diff --git a/shared/depthai-bootloader-shared.cmake b/shared/depthai-bootloader-shared.cmake +index d0db905..3bdb1b0 100644 +--- a/shared/depthai-bootloader-shared.cmake ++++ b/shared/depthai-bootloader-shared.cmake +@@ -29,25 +29,28 @@ if(GIT_FOUND AND NOT DEPTHAI_DOWNLOADED_SOURCES) + OUTPUT_VARIABLE statusCommit + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE + ) +- string(SUBSTRING ${statusCommit} 0 1 status) +- if("${status}" STREQUAL "-") +- message(FATAL_ERROR "Submodule 'depthai-bootloader-shared' not initialized/updated. Run 'git submodule update --init --recursive' first") ++ if(statusCommit) ++ string(SUBSTRING "${statusCommit}" 0 1 status) ++ if("${status}" STREQUAL "-") ++ message(FATAL_ERROR "Submodule 'depthai-bootloader-shared' not initialized/updated. Run 'git submodule update --init --recursive' first") ++ endif() + endif() + endif() + +- # Get depthai-bootloader-shared current commit +- execute_process( +- COMMAND ${GIT_EXECUTABLE} rev-parse HEAD +- WORKING_DIRECTORY ${DEPTHAI_BOOTLOADER_SHARED_FOLDER} +- RESULT_VARIABLE DEPTHAI_BOOTLOADER_SHARED_COMMIT_RESULT +- OUTPUT_VARIABLE DEPTHAI_BOOTLOADER_SHARED_COMMIT_HASH +- ERROR_QUIET +- OUTPUT_STRIP_TRAILING_WHITESPACE +- ) +- if(${DEPTHAI_BOOTLOADER_SHARED_COMMIT_RESULT} EQUAL 0) +- set(DEPTHAI_BOOTLOADER_SHARED_COMMIT_FOUND TRUE) +- else() +- set(DEPTHAI_BOOTLOADER_SHARED_COMMIT_FOUND FALSE) ++ set(DEPTHAI_BOOTLOADER_SHARED_COMMIT_FOUND FALSE) ++ if(EXISTS "${DEPTHAI_BOOTLOADER_SHARED_FOLDER}/.git") ++ # Release archives include shared sources without a nested Git checkout. ++ execute_process( ++ COMMAND ${GIT_EXECUTABLE} rev-parse HEAD ++ WORKING_DIRECTORY ${DEPTHAI_BOOTLOADER_SHARED_FOLDER} ++ RESULT_VARIABLE DEPTHAI_BOOTLOADER_SHARED_COMMIT_RESULT ++ OUTPUT_VARIABLE DEPTHAI_BOOTLOADER_SHARED_COMMIT_HASH ++ ERROR_QUIET ++ OUTPUT_STRIP_TRAILING_WHITESPACE ++ ) ++ if(DEPTHAI_BOOTLOADER_SHARED_COMMIT_RESULT EQUAL 0) ++ set(DEPTHAI_BOOTLOADER_SHARED_COMMIT_FOUND TRUE) ++ endif() + endif() + endif() + +@@ -56,4 +59,4 @@ foreach(source_file ${DEPTHAI_BOOTLOADER_SHARED_SOURCES}) + if(NOT EXISTS ${source_file}) + message(FATAL_ERROR "depthai-bootloader-shared submodule files missing. Make sure to download prepackaged release instead of \"Source code\" on GitHub. Example: depthai-core-vX.Y.Z.tar.gz") + endif() +-endforeach() +\ No newline at end of file ++endforeach() +diff --git a/shared/depthai-shared.cmake b/shared/depthai-shared.cmake +index 414e1eb..94a007d 100644 +--- a/shared/depthai-shared.cmake ++++ b/shared/depthai-shared.cmake +@@ -35,25 +35,28 @@ if(GIT_FOUND AND NOT DEPTHAI_DOWNLOADED_SOURCES) + OUTPUT_VARIABLE statusCommit + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE + ) +- string(SUBSTRING ${statusCommit} 0 1 status) +- if("${status}" STREQUAL "-") +- message(FATAL_ERROR "Submodule 'depthai-shared' not initialized/updated. Run 'git submodule update --init --recursive' first") ++ if(statusCommit) ++ string(SUBSTRING "${statusCommit}" 0 1 status) ++ if("${status}" STREQUAL "-") ++ message(FATAL_ERROR "Submodule 'depthai-shared' not initialized/updated. Run 'git submodule update --init --recursive' first") ++ endif() + endif() + endif() + +- # Get depthai-shared current commit +- execute_process( +- COMMAND ${GIT_EXECUTABLE} rev-parse HEAD +- WORKING_DIRECTORY ${DEPTHAI_SHARED_FOLDER} +- RESULT_VARIABLE DEPTHAI_SHARED_COMMIT_RESULT +- OUTPUT_VARIABLE DEPTHAI_SHARED_COMMIT_HASH +- ERROR_QUIET +- OUTPUT_STRIP_TRAILING_WHITESPACE +- ) +- if(${DEPTHAI_SHARED_COMMIT_RESULT} EQUAL 0) +- set(DEPTHAI_SHARED_COMMIT_FOUND TRUE) +- else() +- set(DEPTHAI_SHARED_COMMIT_FOUND FALSE) ++ set(DEPTHAI_SHARED_COMMIT_FOUND FALSE) ++ if(EXISTS "${DEPTHAI_SHARED_FOLDER}/.git") ++ # Release archives include shared sources without a nested Git checkout. ++ execute_process( ++ COMMAND ${GIT_EXECUTABLE} rev-parse HEAD ++ WORKING_DIRECTORY ${DEPTHAI_SHARED_FOLDER} ++ RESULT_VARIABLE DEPTHAI_SHARED_COMMIT_RESULT ++ OUTPUT_VARIABLE DEPTHAI_SHARED_COMMIT_HASH ++ ERROR_QUIET ++ OUTPUT_STRIP_TRAILING_WHITESPACE ++ ) ++ if(DEPTHAI_SHARED_COMMIT_RESULT EQUAL 0) ++ set(DEPTHAI_SHARED_COMMIT_FOUND TRUE) ++ endif() + endif() + endif() + +-- +2.54.0 diff --git a/patch/ros-jazzy-turtlebot4-base.patch b/patch/ros-jazzy-turtlebot4-base.patch new file mode 100644 index 000000000..d2da6a8cf --- /dev/null +++ b/patch/ros-jazzy-turtlebot4-base.patch @@ -0,0 +1,179 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Esteve Fernandez +Date: Tue, 12 May 2026 14:02:58 +0100 +Subject: [PATCH] fix(turtlebot4-base): support both libgpiod 1 and 2 + +Signed-off-by: Esteve Fernandez + +--- + CMakeLists.txt | 7 ++++ + include/turtlebot4_base/gpio_interface.hpp | 5 ++- + src/gpio_interface.cpp | 66 ++++++++++++++++++++++++++++++ + 3 files changed, 77 insertions(+), 1 deletion(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 6aeeea9..aeb64b4 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -25,6 +25,12 @@ find_package(std_msgs REQUIRED) + find_package(sensor_msgs REQUIRED) + find_package(turtlebot4_msgs REQUIRED) + find_package(turtlebot4_node REQUIRED) ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(GPIOD REQUIRED libgpiod) ++ ++if(NOT GPIOD_VERSION VERSION_LESS 2.0) ++ add_definitions(-DTURTLEBOT4_BASE_GPIOD_V2) ++endif() + + find_library(gpiod_library NAMES libgpiod.so) + +@@ -32,6 +38,7 @@ find_library(gpiod_library NAMES libgpiod.so) + + include_directories( + include ++ ${GPIOD_INCLUDE_DIRS} + ) + + add_library(${PROJECT_NAME}_lib +diff --git a/include/turtlebot4_base/gpio_interface.hpp b/include/turtlebot4_base/gpio_interface.hpp +index c25317e..b1b27a3 100644 +--- a/include/turtlebot4_base/gpio_interface.hpp ++++ b/include/turtlebot4_base/gpio_interface.hpp +@@ -19,7 +19,6 @@ + #ifndef TURTLEBOT4_BASE__GPIO_INTERFACE_HPP_ + #define TURTLEBOT4_BASE__GPIO_INTERFACE_HPP_ + +-#include + #include + + #include +@@ -56,7 +55,11 @@ private: + + gpiod_chip * chip_; + ++#ifdef TURTLEBOT4_BASE_GPIOD_V2 ++ std::map lines_; ++#else + std::map lines_; ++#endif + }; + + } // namespace turtlebot4_base +diff --git a/src/gpio_interface.cpp b/src/gpio_interface.cpp +index 3127ba3..a21b977 100644 +--- a/src/gpio_interface.cpp ++++ b/src/gpio_interface.cpp +@@ -50,7 +50,16 @@ GpioInterface::GpioInterface(const uint8_t & gpio_chip_number) + */ + void GpioInterface::open_chip() + { ++#ifdef TURTLEBOT4_BASE_GPIOD_V2 ++ std::string gpio_chip_path = gpio_chip_; ++ if (gpio_chip_path.empty() || gpio_chip_path.front() != '/') { ++ gpio_chip_path = "/dev/" + gpio_chip_path; ++ } ++ ++ chip_ = gpiod_chip_open(gpio_chip_path.c_str()); ++#else + chip_ = gpiod_chip_open_by_name(gpio_chip_.c_str()); ++#endif + } + + /** +@@ -59,7 +68,11 @@ void GpioInterface::open_chip() + void GpioInterface::close_chip() + { + for (auto line : lines_) { ++#ifdef TURTLEBOT4_BASE_GPIOD_V2 ++ gpiod_line_request_release(line.second); ++#else + gpiod_line_release(line.second); ++#endif + } + + gpiod_chip_close(chip_); +@@ -70,6 +83,47 @@ void GpioInterface::close_chip() + */ + void GpioInterface::add_line(uint8_t line, GpioInterfaceLineDirection direction) + { ++#ifdef TURTLEBOT4_BASE_GPIOD_V2 ++ unsigned int offset = line; ++ gpiod_request_config * request_config = gpiod_request_config_new(); ++ gpiod_line_config * line_config = gpiod_line_config_new(); ++ gpiod_line_settings * line_settings = gpiod_line_settings_new(); ++ ++ if (request_config == nullptr || line_config == nullptr || line_settings == nullptr) { ++ gpiod_request_config_free(request_config); ++ gpiod_line_config_free(line_config); ++ gpiod_line_settings_free(line_settings); ++ std::cerr << "Failed to configure GPIO Line" << std::endl; ++ return; ++ } ++ ++ if (direction != LINE_DIRECTION_INPUT && direction != LINE_DIRECTION_OUTPUT) { ++ gpiod_request_config_free(request_config); ++ gpiod_line_config_free(line_config); ++ gpiod_line_settings_free(line_settings); ++ std::cerr << "Invalid GPIO Line Direction" << std::endl; ++ return; ++ } ++ ++ gpiod_request_config_set_consumer(request_config, "Turtlebot4"); ++ gpiod_line_settings_set_direction(line_settings, static_cast(direction)); ++ if (direction == LINE_DIRECTION_OUTPUT) { ++ gpiod_line_settings_set_output_value(line_settings, GPIOD_LINE_VALUE_INACTIVE); ++ } ++ gpiod_line_config_add_line_settings(line_config, &offset, 1, line_settings); ++ ++ gpiod_line_request * gpio_line = gpiod_chip_request_lines(chip_, request_config, line_config); ++ ++ gpiod_request_config_free(request_config); ++ gpiod_line_config_free(line_config); ++ gpiod_line_settings_free(line_settings); ++ ++ if (gpio_line != nullptr) { ++ lines_.insert(std::pair(line, gpio_line)); ++ } else { ++ std::cerr << "Invalid GPIO Line" << std::endl; ++ } ++#else + gpiod_line * gpio_line = gpiod_chip_get_line(chip_, line); + + if (gpio_line != nullptr) { +@@ -86,6 +140,7 @@ void GpioInterface::add_line(uint8_t line, GpioInterfaceLineDirection direction) + } else { + std::cerr << "Invalid GPIO Line Direction" << std::endl; + } ++#endif + } + + /** +@@ -93,7 +148,14 @@ void GpioInterface::add_line(uint8_t line, GpioInterfaceLineDirection direction) + */ + void GpioInterface::write(uint8_t line, uint8_t value) + { ++#ifdef TURTLEBOT4_BASE_GPIOD_V2 ++ gpiod_line_request_set_value( ++ lines_[line], ++ line, ++ value ? GPIOD_LINE_VALUE_ACTIVE : GPIOD_LINE_VALUE_INACTIVE); ++#else + gpiod_line_set_value(lines_[line], value); ++#endif + } + + /** +@@ -101,5 +163,9 @@ void GpioInterface::write(uint8_t line, uint8_t value) + */ + uint8_t GpioInterface::read(uint8_t line) + { ++#ifdef TURTLEBOT4_BASE_GPIOD_V2 ++ return static_cast(gpiod_line_request_get_value(lines_[line], line)); ++#else + return gpiod_line_get_value(lines_[line]); ++#endif + } + +-- +2.54.0 diff --git a/robostack.yaml b/robostack.yaml index 7f82f287e..c9f18c2f3 100644 --- a/robostack.yaml +++ b/robostack.yaml @@ -321,6 +321,11 @@ libgeos++-dev: robostack: [geos] libgflags-dev: robostack: [gflags] +libgpiod-dev: + robostack: + linux: [libgpiod] + osx: [] + win64: [] libglew-dev: robostack: [glew] libglfw3-dev: @@ -1015,6 +1020,11 @@ python3-yaml: robostack: [pyyaml] python3-zmq: robostack: [pyzmq] +qml-module-qtquick-extras: + robostack: + linux: [qt-main, libopengl-devel, libgl-devel] + osx: [qt-main] + win64: [qt-main] qt5-image-formats-plugins: robostack: linux: [qt-main, libopengl-devel, libgl-devel] diff --git a/vinca.yaml b/vinca.yaml index d50eff8f3..c11772c48 100644 --- a/vinca.yaml +++ b/vinca.yaml @@ -82,6 +82,26 @@ packages_select_by_deps: - turtlebot3 - turtlebot3_simulations + # TurtleBot 4 officially supports Linux only. + - if: linux + then: + - turtlebot4_base + - turtlebot4_bringup + - turtlebot4_description + - turtlebot4_desktop + - turtlebot4_diagnostics + - turtlebot4_gz_bringup + - turtlebot4_gz_gui_plugins + - turtlebot4_gz_toolbox + - turtlebot4_msgs + - turtlebot4_navigation + - turtlebot4_node + - turtlebot4_robot + - turtlebot4_setup + - turtlebot4_simulator + - turtlebot4_tests + - turtlebot4_viz + - ackermann-msgs - sbg_driver