From c94bc3942b76c5fd7e22de54118838ee3257f568 Mon Sep 17 00:00:00 2001 From: Barrett Date: Sun, 15 Feb 2026 21:35:15 -0600 Subject: [PATCH 01/20] feat(lidar): add `soro_lidar` package btw... there's already a package called "lidar" in ROS 2, so i added the "soro" prefix --- pixi.lock | 1755 ++++++++++++++++- pixi.toml | 8 +- src/soro_lidar/CMakeLists.txt | 67 + .../include/unitree_lidar_protocol.h | 415 ++++ src/soro_lidar/include/unitree_lidar_ros2.h | 251 +++ src/soro_lidar/include/unitree_lidar_sdk.h | 145 ++ .../include/unitree_lidar_sdk_config.h | 4 + .../include/unitree_lidar_sdk_pcl.h | 83 + .../include/unitree_lidar_utilities.h | 307 +++ src/soro_lidar/launch/launch.py | 57 + .../lib/aarch64/libunitree_lidar_sdk.a | Bin 0 -> 234344 bytes .../lib/x86_64/libunitree_lidar_sdk.a | Bin 0 -> 252836 bytes src/soro_lidar/package.xml | 29 + src/soro_lidar/rviz/view.rviz | 182 ++ .../src/unitree_lidar_ros2_node.cpp | 14 + 15 files changed, 3279 insertions(+), 38 deletions(-) create mode 100644 src/soro_lidar/CMakeLists.txt create mode 100644 src/soro_lidar/include/unitree_lidar_protocol.h create mode 100644 src/soro_lidar/include/unitree_lidar_ros2.h create mode 100644 src/soro_lidar/include/unitree_lidar_sdk.h create mode 100644 src/soro_lidar/include/unitree_lidar_sdk_config.h create mode 100644 src/soro_lidar/include/unitree_lidar_sdk_pcl.h create mode 100644 src/soro_lidar/include/unitree_lidar_utilities.h create mode 100644 src/soro_lidar/launch/launch.py create mode 100644 src/soro_lidar/lib/aarch64/libunitree_lidar_sdk.a create mode 100644 src/soro_lidar/lib/x86_64/libunitree_lidar_sdk.a create mode 100644 src/soro_lidar/package.xml create mode 100644 src/soro_lidar/rviz/view.rviz create mode 100644 src/soro_lidar/src/unitree_lidar_ros2_node.cpp diff --git a/pixi.lock b/pixi.lock index ec3fa8ee..d85d5b0b 100644 --- a/pixi.lock +++ b/pixi.lock @@ -6,11 +6,16 @@ environments: - url: https://conda.anaconda.org/robostack-humble/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/adwaita-icon-theme-48.1-unix_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.13.3-py311h55b9665_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.14-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argcomplete-3.6.2-pyhd8ed1ab_0.conda @@ -19,12 +24,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-h04ea711_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/basedpyright-1.31.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/benchmark-1.9.4-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.44-h4852527_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.44-h4bf12b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.44-h4852527_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-34_h1ea3ea9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bullet-cpp-3.25-h7db5c69_4.conda @@ -89,6 +96,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/empy-3.3.4-pyh9f0ad1d_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/epoxy-1.5.10-h166bdaf_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.1-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fcl-0.7.0-h543440a_8.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-7.1.1-gpl_h127656b_906.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/flann-1.9.2-hc299af7_5.conda @@ -106,6 +114,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h3a85593_22.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.13.3-ha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.7.0-py311h52bc045_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc-14.3.0-h76bdaa0_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-hd9e9e21_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-14.3.0-h1382650_11.conda @@ -118,6 +127,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/gh-2.78.0-h76a2195_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ghostscript-10.04.0-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.84.3-h89d24bf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.84.3-hf516916_0.conda @@ -137,10 +147,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-he663afc_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-14.3.0-ha7acb78_11.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.4.1-h15599e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h6e4c0c1_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.1.12-h7955e40_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda @@ -213,10 +225,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.1.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.84.3-hf39c6af_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.3-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.55-h3f2d84a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.12.1-default_h3d81e11_1000.conda @@ -245,6 +259,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-devel-5.8.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.2-hc2fc477_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h21f7587_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda @@ -253,6 +268,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopencv-4.11.0-qt6_py311h58ab8b7_609.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-devel-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2025.0.0-hdc3f47d_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2025.0.0-h4d9b6c2_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2025.0.0-h4d9b6c2_3.conda @@ -311,6 +327,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h7a3aeb2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/loguru-0.7.3-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lxml-6.0.0-py311hbd2c71b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda @@ -320,6 +337,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/metis-5.1.0-hd0bcaf9_1007.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h90cbb55_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py311hdf67eae_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/multidict-6.7.0-py311h3778330_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/netifaces-0.11.0-py311h9ecbd09_3.conda @@ -342,10 +361,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h55fea9a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-he970967_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.2-h26f9b46_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openvdb-12.0.1-py311heb7b8bb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/orocos-kdl-1.5.1-h5888daf_8.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.24.1-hc5aa10d_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hadf4263_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pcl-1.15.0-hd1363f8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.45-hc749103_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-11.3.0-py311h1322bbf_0.conda @@ -354,6 +375,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.6.2-h18fbb6c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/propcache-0.3.1-py311h2dc5d0c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.0.0-py311h9ecbd09_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pugixml-1.15-h3f63f65_0.conda @@ -540,9 +562,12 @@ environments: - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-nav2-waypoint-follower-1.1.18-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-navigation2-1.1.18-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-ompl-1.7.0-py311h2a035b9_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-openvdb-vendor-2.3.4-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-orocos-kdl-vendor-0.2.5-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-osrf-pycommon-2.1.6-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-parameter-traits-0.5.0-np126py311hbc2a38a_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pcl-conversions-2.4.5-np126py311hbc2a38a_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pcl-msgs-1.0.0-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pid-controller-2.48.0-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pluginlib-5.1.0-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pointcloud-to-laserscan-2.0.1-np126py311hbc2a38a_13.conda @@ -658,6 +683,7 @@ environments: - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-shape-msgs-4.9.0-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-slam-toolbox-2.6.10-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-smclib-4.1.2-np126py311hbc2a38a_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-spatio-temporal-voxel-layer-2.3.4-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-spdlog-vendor-1.3.1-np126py311h11365e7_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-sros2-0.10.6-np126py311hbc2a38a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-statistics-msgs-1.2.1-np126py311hbc2a38a_13.conda @@ -738,9 +764,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-16.0.0-py311h9ecbd09_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/urdfdom-4.0.1-hae71d53_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/urdfdom_headers-1.0.6-h924138e_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.09-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.8.11-heb9285d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-9.4.2-h94a02a8_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.4.2-py311hc26c8ec_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.4.2-h5554b43_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.45-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/x265-3.5-h924138e_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda @@ -778,6 +809,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/xtl-0.8.0-h84d6215_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.22.0-py311h3778330_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h3b0a872_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda @@ -789,7 +821,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/d0/13/ff61c421eb72c74e82d5c3c9927e96434479f2ce6bea086332966a017dcb/colcon_ros_cargo-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9f/5a/a26132406f1f40cf51ea349a5f11b0a46cec02a2031ff82e391c2537247a/geographiclib-2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/15/cf2a69ade4b194aa524ac75112d5caac37414b20a3a03e6865dfe0bd1539/geopy-2.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/13/756b13b8d5d417a0b4c3bf6ceafb59df0ed05cec7fedc2490bbbf5e60ebc/opencv_contrib_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl @@ -801,6 +832,9 @@ environments: linux-aarch64: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/adwaita-icon-theme-48.1-unix_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/aiohttp-3.13.3-py311hf076524_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/alsa-lib-1.2.14-h86ecc28_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/aom-3.9.1-hcccb83c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argcomplete-3.6.2-pyhd8ed1ab_0.conda @@ -809,12 +843,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/at-spi2-core-2.40.3-h1f2db35_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/atk-1.0-2.38.0-hedc4a1f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/attr-2.5.1-h4e544f5_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/basedpyright-1.31.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/benchmark-1.9.4-h5ad3122_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils-2.44-hf1166c9_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.44-h4c662bb_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_linux-aarch64-2.44-hf1166c9_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/blas-devel-3.9.0-34_h9678261_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/blosc-1.21.6-hb4dfabd_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-1.1.0-h86ecc28_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-bin-1.1.0-h86ecc28_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bullet-cpp-3.25-py311h848c333_4.conda @@ -879,6 +915,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/empy-3.3.4-pyh9f0ad1d_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/epoxy-1.5.10-h4e544f5_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.7.1-hfae3067_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fcl-0.7.0-h841ecf2_8.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ffmpeg-7.1.1-gpl_h30b7fc1_906.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/flann-1.9.2-h8b5e525_5.conda @@ -896,6 +933,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/freeimage-3.18.0-h6cb32c8_22.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/freetype-2.13.3-h8af1aa0_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fribidi-1.0.10-hb9de7d4_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozenlist-1.7.0-py311h91c1192_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc-14.3.0-h7408ef6_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_impl_linux-aarch64-14.3.0-h2b96704_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_linux-aarch64-14.3.0-h39d9346_11.conda @@ -907,6 +945,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gh-2.78.0-h94b2740_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ghostscript-10.04.0-h5ad3122_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/giflib-5.2.2-h31becfc_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gl2ps-1.4.2-hedfd65a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/glew-2.1.0-h01db608_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/glib-2.84.3-h701fa2e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/glib-tools-2.84.3-hc87f4d4_0.conda @@ -926,10 +965,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_impl_linux-aarch64-14.3.0-h72695c8_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_linux-aarch64-14.3.0-h83defb1_11.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/harfbuzz-11.4.1-he4899c9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/hdf4-4.2.15-hb6ba311_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/hdf5-1.14.6-nompi_h587839b_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/hicolor-icon-theme-0.17-h8af1aa0_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-75.1-hf9b3779_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/imath-3.1.12-hf428078_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda @@ -1001,10 +1042,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.1.0-he9431aa_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.1.0-hbc25352_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgl-1.7.0-hd24410f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgl-devel-1.7.0-hd24410f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.84.3-h75d4a95_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglu-9.0.3-h5ad3122_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglvnd-1.7.0-hd24410f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglx-1.7.0-hd24410f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglx-devel-1.7.0-hd24410f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.1.0-he277a41_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgpg-error-1.55-h5ad3122_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libhwloc-2.12.1-default_h6f258fa_1000.conda @@ -1033,6 +1076,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.1-h86ecc28_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-devel-5.8.1-h86ecc28_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmicrohttpd-1.0.2-h3543b8c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnetcdf-4.9.2-nompi_hb193ca5_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.64.0-hc8609a4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h86ecc28_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libntlm-1.4-hf897c2e_1002.tar.bz2 @@ -1041,6 +1085,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopencv-4.11.0-qt6_py311h9691740_609.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopengl-1.7.0-hd24410f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopengl-devel-1.7.0-hd24410f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenvino-2025.0.0-hd63d6c0_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenvino-arm-cpu-plugin-2025.0.0-hd63d6c0_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenvino-auto-batch-plugin-2025.0.0-hf15766e_3.conda @@ -1096,6 +1141,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxslt-1.1.43-h4552c8e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzip-1.11.2-h3e8f909_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/loguru-0.7.3-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lxml-6.0.0-py311h3bfafd0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda @@ -1105,6 +1151,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/metis-5.1.0-h670dfbf_1007.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mpfr-4.2.1-h2305555_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mpg123-1.32.9-h65af167_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py311hfca10b7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/multidict-6.7.0-py311h164a683_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/netifaces-0.11.0-py311ha879c10_3.conda @@ -1125,10 +1173,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.3-h5da879a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openldap-2.6.10-h30c48ee_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.5.2-h8e36d6e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openvdb-12.0.1-py311h29547a6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/orocos-kdl-1.5.1-h5ad3122_8.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/p11-kit-0.24.1-h9f2702f_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pango-1.56.4-he55ef5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pcl-1.15.0-h462c444_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pcre2-10.45-hf4ec17f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-11.3.0-py311ha4eaa5e_0.conda @@ -1137,6 +1187,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/proj-9.6.2-h561be74_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/propcache-0.3.1-py311h58d527c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/psutil-7.0.0-py311ha879c10_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pugixml-1.15-h6ef32b0_0.conda @@ -1323,9 +1374,12 @@ environments: - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-nav2-waypoint-follower-1.1.18-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-navigation2-1.1.18-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-ompl-1.7.0-py311h5f9095d_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-openvdb-vendor-2.3.4-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-orocos-kdl-vendor-0.2.5-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-osrf-pycommon-2.1.6-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-parameter-traits-0.5.0-np126py311hbdd918e_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-pcl-conversions-2.4.5-np126py311hbdd918e_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-pcl-msgs-1.0.0-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-pid-controller-2.48.0-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-pluginlib-5.1.0-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-pointcloud-to-laserscan-2.0.1-np126py311hbdd918e_13.conda @@ -1441,6 +1495,7 @@ environments: - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-shape-msgs-4.9.0-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-slam-toolbox-2.6.10-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-smclib-4.1.2-np126py311hbdd918e_13.conda + - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-spatio-temporal-voxel-layer-2.3.4-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-spdlog-vendor-1.3.1-np126py311h5f8052a_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-sros2-0.10.6-np126py311hbdd918e_13.conda - conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-statistics-msgs-1.2.1-np126py311hbdd918e_13.conda @@ -1520,8 +1575,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/unicodedata2-16.0.0-py311ha879c10_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/urdfdom-4.0.1-hdac3a21_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/urdfdom_headers-1.0.6-hdd96247_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/utfcpp-4.09-h8af1aa0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/uv-0.8.11-hc9499e0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-9.4.2-h98dbe00_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-base-9.4.2-py311h06be8d0_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-io-ffmpeg-9.4.2-hc80fd1f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/wayland-1.24.0-h698ed42_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/x264-1!164.3095-h4e544f5_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/x265-3.5-hdd96247_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xcb-util-0.4.1-hca56bd8_2.conda @@ -1558,6 +1618,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xtl-0.8.0-h17cf362_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yarl-1.22.0-py311h164a683_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zeromq-4.3.5-h5efb499_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-1.3.1-h86ecc28_2.conda @@ -1569,7 +1630,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/d0/13/ff61c421eb72c74e82d5c3c9927e96434479f2ce6bea086332966a017dcb/colcon_ros_cargo-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9f/5a/a26132406f1f40cf51ea349a5f11b0a46cec02a2031ff82e391c2537247a/geographiclib-2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/15/cf2a69ade4b194aa524ac75112d5caac37414b20a3a03e6865dfe0bd1539/geopy-2.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ae/7b/7e1471aa92f9f3c1bd8dbe624622b62add6f734db34fbbb9974e2ec70c34/opencv_contrib_python-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl @@ -1580,13 +1640,18 @@ environments: - pypi: https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl osx-64: - conda: https://conda.anaconda.org/conda-forge/noarch/adwaita-icon-theme-48.1-unix_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aiohttp-3.13.3-py311h2ed03ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/aom-3.9.1-hf036a51_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argcomplete-3.6.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/assimp-5.4.3-hf9fe5ce_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/atk-1.0-2.38.0-h4bec284_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/basedpyright-1.31.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/benchmark-1.9.4-h240833e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/blas-devel-3.9.0-34_hbf4f893_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/blosc-1.21.6-hd145fbb_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-1.1.0-h6e16a3a_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-bin-1.1.0-h6e16a3a_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/bullet-cpp-3.25-hcf53e2f_4.conda @@ -1657,6 +1722,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/empy-3.3.4-pyh9f0ad1d_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-64/epoxy-1.5.10-h5eb16cf_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/expat-2.7.1-h21dd04a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/fcl-0.7.0-h229c9af_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ffmpeg-7.1.1-gpl_h7f5d84f_106.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/flann-1.9.2-hff71165_5.conda @@ -1673,6 +1739,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/freeimage-3.18.0-h7cd8ba8_22.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.13.3-h694c41f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/fribidi-1.0.10-hbcb3906_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/frozenlist-1.7.0-py311h7a2b322_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/gdbm-1.18-h8a0c380_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-64/gdk-pixbuf-2.42.12-h5720e38_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/geographiclib-cpp-2.5-h9275861_0.conda @@ -1697,10 +1764,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/gtk3-3.24.43-h70b172e_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/gts-0.7.6-h53e17e3_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/harfbuzz-11.4.1-h0ffbb26_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf4-4.2.15-h8138101_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/hicolor-icon-theme-0.17-h694c41f_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/imath-3.1.12-h2016aa1_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda @@ -1791,6 +1860,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-hc29ff6c_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm20-20.1.8-h9b4ebcc_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-devel-5.8.1-hd471939_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libnetcdf-4.9.2-nompi_h6054f6d_118.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.64.0-hc7306c3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libntlm-1.8-h6e16a3a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libode-0.16.5-h4289cef_0.conda @@ -1840,6 +1911,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-20.1.8-hf4e0ed4_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-he90a8e3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-h3fe3016_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/loguru-0.7.3-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lxml-6.0.0-py311h91cdd00_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.10.0-h240833e_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lzo-2.10-h4132b18_1002.conda @@ -1848,6 +1920,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.10.5-py311h249d4ed_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/metis-5.1.0-h3023b02_1007.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py311haec20ae_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/multidict-6.7.0-py311h24ee9f8_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/netifaces-0.11.0-py311h3336109_3.conda @@ -1870,6 +1944,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/orocos-kdl-1.5.1-h97d8b74_8.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pango-1.56.4-h6ef8af8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pcl-1.15.0-h1b4601b_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pcre2-10.45-hf733adb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-64/pillow-11.3.0-py311h25da234_0.conda @@ -1878,6 +1953,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/proj-9.6.2-h8462e38_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/propcache-0.3.1-py311ha3cf9ac_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/psutil-7.0.0-py311h4d7f069_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pthread-stubs-0.4-h00291cd_1002.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pugixml-1.15-h46091d4_0.conda @@ -2064,6 +2140,8 @@ environments: - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-orocos-kdl-vendor-0.2.5-np126py311h3f9c716_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-osrf-pycommon-2.1.6-np126py311h3f9c716_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-parameter-traits-0.5.0-np126py311h3f9c716_13.conda + - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-pcl-conversions-2.4.5-np126py311h3f9c716_13.conda + - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-pcl-msgs-1.0.0-np126py311h3f9c716_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-pid-controller-2.48.0-np126py311h3f9c716_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-pluginlib-5.1.0-np126py311h3f9c716_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-pointcloud-to-laserscan-2.0.1-np126py311h3f9c716_13.conda @@ -2259,7 +2337,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/unicodedata2-16.0.0-py311h4d7f069_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/urdfdom-4.0.1-hdeef459_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/urdfdom_headers-1.0.6-hbb4e6a2_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/utfcpp-4.09-h694c41f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/uv-0.8.11-hfa71dfd_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/vtk-9.4.2-h3d6103e_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/vtk-base-9.4.2-py311h1f8269a_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/vtk-io-ffmpeg-9.4.2-h0ddcc0c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/x264-1!164.3095-h775f41a_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-64/x265-3.5-hbb4e6a2_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-64/xorg-libice-1.1.2-h6e16a3a_0.conda @@ -2280,6 +2363,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/xtl-0.8.0-h9275861_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-cpp-0.8.0-h92383a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/yarl-1.22.0-py311he13f9b5_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zeromq-4.3.5-h7130eaa_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda @@ -2291,7 +2375,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/d0/13/ff61c421eb72c74e82d5c3c9927e96434479f2ce6bea086332966a017dcb/colcon_ros_cargo-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9f/5a/a26132406f1f40cf51ea349a5f11b0a46cec02a2031ff82e391c2537247a/geographiclib-2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/15/cf2a69ade4b194aa524ac75112d5caac37414b20a3a03e6865dfe0bd1539/geopy-2.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8c/07/68e0b24217671b65c23e105bb7afd4ef4fd01507670cf5e61373d9efd6b5/opencv_contrib_python-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl @@ -2302,13 +2385,18 @@ environments: - pypi: https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/adwaita-icon-theme-48.1-unix_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aiohttp-3.13.3-py311h6771f6e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aom-3.9.1-h7bae524_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argcomplete-3.6.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/assimp-5.4.3-ha9c0b8d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/atk-1.0-2.38.0-hd03087b_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/basedpyright-1.31.3-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/benchmark-1.9.4-h286801f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/blas-devel-3.9.0-34_h11c0a38_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/blosc-1.21.6-h7dd00d9_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-1.1.0-h5505292_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-bin-1.1.0-h5505292_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bullet-cpp-3.25-py311hca32420_4.conda @@ -2379,6 +2467,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/empy-3.3.4-pyh9f0ad1d_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/epoxy-1.5.10-h1c322ee_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/expat-2.7.1-hec049ff_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fcl-0.7.0-h64af606_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ffmpeg-7.1.1-gpl_h20db955_106.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/flann-1.9.2-hb343761_5.conda @@ -2395,6 +2484,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/freeimage-3.18.0-h2e169f6_22.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/freetype-2.13.3-hce30654_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fribidi-1.0.10-h27ca646_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/frozenlist-1.7.0-py311h8740443_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gdk-pixbuf-2.42.12-h7af3d76_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/geographiclib-cpp-2.5-ha393de7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gettext-0.25.1-h3dcc1bd_0.conda @@ -2418,10 +2508,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gtk3-3.24.43-h07173f4_5.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gts-0.7.6-he42f4ea_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/harfbuzz-11.4.1-hf4e55d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf4-4.2.15-h2ee6834_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf5-1.14.6-nompi_he65715a_103.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/hicolor-icon-theme-0.17-hce30654_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/imath-3.1.12-h025cafa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda @@ -2512,6 +2604,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm19-19.1.7-hc4b4ae8_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm20-20.1.8-h846d351_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-devel-5.8.1-h39f12f2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnetcdf-4.9.2-nompi_h2d3d5cf_118.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.64.0-h6d7220d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libntlm-1.8-h5505292_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libode-0.16.5-py311ha78afcb_0.conda @@ -2561,6 +2655,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-20.1.8-hbb9b287_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19-19.1.7-h87a4c7e_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19.1.7-hd2aecb6_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/loguru-0.7.3-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-6.0.0-py311hfcb965d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda @@ -2569,6 +2664,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-base-3.10.5-py311h66dac5a_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/metis-5.1.0-h15f6cfe_1007.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/mpfr-4.2.1-hb693164_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.1.2-py311h5a5e7c7_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/multidict-6.7.0-py311h97ccca8_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/netifaces-0.11.0-py311h460d6c5_3.conda @@ -2591,6 +2688,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/orocos-kdl-1.5.1-h5833ebf_8.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pango-1.56.4-h875632e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcl-1.15.0-hae97317_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.45-ha881caa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-11.3.0-py311hb9ba9e9_0.conda @@ -2599,6 +2697,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/proj-9.6.2-hdbeaa80_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/propcache-0.3.1-py311h4921393_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.0.0-py311h917b07b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pthread-stubs-0.4-hd74edd7_1002.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pugixml-1.15-hd3d436d_0.conda @@ -2785,6 +2884,8 @@ environments: - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-orocos-kdl-vendor-0.2.5-np126py311h2a51a2c_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-osrf-pycommon-2.1.6-np126py311h2a51a2c_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-parameter-traits-0.5.0-np126py311h2a51a2c_13.conda + - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-pcl-conversions-2.4.5-np126py311h2a51a2c_13.conda + - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-pcl-msgs-1.0.0-np126py311h2a51a2c_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-pid-controller-2.48.0-np126py311h2a51a2c_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-pluginlib-5.1.0-np126py311h2a51a2c_13.conda - conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-pointcloud-to-laserscan-2.0.1-np126py311h2a51a2c_13.conda @@ -2980,7 +3081,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/unicodedata2-16.0.0-py311h917b07b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/urdfdom-4.0.1-h48bab5a_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/urdfdom_headers-1.0.6-h3e96240_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/utfcpp-4.09-hce30654_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.8.11-hb521335_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/vtk-9.4.2-h4dfd180_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/vtk-base-9.4.2-py311h48cd792_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/vtk-io-ffmpeg-9.4.2-h142d020_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/x264-1!164.3095-h57fd34a_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/x265-3.5-hbc6ce65_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libice-1.1.2-h5505292_0.conda @@ -3001,6 +3107,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xtl-0.8.0-ha393de7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-cpp-0.8.0-ha1acc90_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.22.0-py311ha9b3269_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-hc1bb282_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda @@ -3012,7 +3119,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/d0/13/ff61c421eb72c74e82d5c3c9927e96434479f2ce6bea086332966a017dcb/colcon_ros_cargo-0.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9f/5a/a26132406f1f40cf51ea349a5f11b0a46cec02a2031ff82e391c2537247a/geographiclib-2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/15/cf2a69ade4b194aa524ac75112d5caac37414b20a3a03e6865dfe0bd1539/geopy-2.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/78/b504ca8f7a312918d184e0b8093c62bc9a110d8154f658b591ef5c020d65/opencv_contrib_python-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl @@ -3068,6 +3174,113 @@ packages: purls: [] size: 619606 timestamp: 1750236493212 +- conda: https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.6.1-pyhd8ed1ab_0.conda + sha256: 7842ddc678e77868ba7b92a726b437575b23aaec293bca0d40826f1026d90e27 + md5: 18fd895e0e775622906cdabfc3cf0fb4 + depends: + - python >=3.9 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/aiohappyeyeballs?source=hash-mapping + size: 19750 + timestamp: 1741775303303 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.13.3-py311h55b9665_0.conda + sha256: 6ba089f4030fdf139acae5fbf6d20907c53f8506110ec9ab242dcf6efa18f267 + md5: 13edfe8c425132c74b038144f603d6d3 + depends: + - __glibc >=2.17,<3.0.a0 + - aiohappyeyeballs >=2.5.0 + - aiosignal >=1.4.0 + - attrs >=17.3.0 + - frozenlist >=1.1.1 + - libgcc >=14 + - multidict >=4.5,<7.0 + - propcache >=0.2.0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - yarl >=1.17.0,<2.0 + license: MIT AND Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/aiohttp?source=hash-mapping + size: 1025327 + timestamp: 1767524683938 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/aiohttp-3.13.3-py311hf076524_0.conda + sha256: ef22fd5746d97db09c6d6e4f788786181c71e30eae5f0f66f3cfaa2cd0cbc9a7 + md5: dfd8c1d0a8ab0a13e3e885d6a50690e8 + depends: + - aiohappyeyeballs >=2.5.0 + - aiosignal >=1.4.0 + - attrs >=17.3.0 + - frozenlist >=1.1.1 + - libgcc >=14 + - multidict >=4.5,<7.0 + - propcache >=0.2.0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - yarl >=1.17.0,<2.0 + license: MIT AND Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/aiohttp?source=hash-mapping + size: 1014726 + timestamp: 1767524880586 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aiohttp-3.13.3-py311h2ed03ae_0.conda + sha256: 9a2389f9c42e0360f047a56911f31eda49b57717b9b9b2ce92bf66cb50623efd + md5: f9955fbdfd271db256a33b6c41e0f78c + depends: + - __osx >=10.13 + - aiohappyeyeballs >=2.5.0 + - aiosignal >=1.4.0 + - attrs >=17.3.0 + - frozenlist >=1.1.1 + - multidict >=4.5,<7.0 + - propcache >=0.2.0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - yarl >=1.17.0,<2.0 + license: MIT AND Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/aiohttp?source=hash-mapping + size: 991724 + timestamp: 1767524965965 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aiohttp-3.13.3-py311h6771f6e_0.conda + sha256: 1ed398d29af3a63808730a402ee78683b183a8dc3438078e6c5c706e63332855 + md5: a0656f0447843f80851254a94aecd2f8 + depends: + - __osx >=11.0 + - aiohappyeyeballs >=2.5.0 + - aiosignal >=1.4.0 + - attrs >=17.3.0 + - frozenlist >=1.1.1 + - multidict >=4.5,<7.0 + - propcache >=0.2.0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - yarl >=1.17.0,<2.0 + license: MIT AND Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/aiohttp?source=hash-mapping + size: 993194 + timestamp: 1767525030810 +- conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda + sha256: 8dc149a6828d19bf104ea96382a9d04dae185d4a03cc6beb1bc7b84c428e3ca2 + md5: 421a865222cd0c9d83ff08bc78bf3a61 + depends: + - frozenlist >=1.1.0 + - python >=3.9 + - typing_extensions >=4.2 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/aiosignal?source=hash-mapping + size: 13688 + timestamp: 1751626573984 - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.14-hb9d3cd8_0.conda sha256: b9214bc17e89bf2b691fad50d952b7f029f6148f4ac4fe7c60c08f093efdf745 md5: 76df83c2a9035c54df5d04ff81bcc02d @@ -3337,6 +3550,18 @@ packages: purls: [] size: 74992 timestamp: 1660065534958 +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyhcf101f3_1.conda + sha256: c13d5e42d187b1d0255f591b7ce91201d4ed8a5370f0d986707a802c20c9d32f + md5: 537296d57ea995666c68c821b00e360b + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/attrs?source=compressed-mapping + size: 64759 + timestamp: 1764875182184 - conda: https://conda.anaconda.org/conda-forge/noarch/basedpyright-1.31.3-pyhcf101f3_0.conda sha256: a3e2a890fc7f54d6627284c0c41f4a1d229460fdef1a72c94bd8d13189afa07e md5: 20fcfaa93843fdcb1789269dc48bddb6 @@ -3516,6 +3741,67 @@ packages: purls: [] size: 19515 timestamp: 1754679000436 +- conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda + sha256: e7af5d1183b06a206192ff440e08db1c4e8b2ca1f8376ee45fb2f3a85d4ee45d + md5: 2c2fae981fd2afd00812c92ac47d023d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - snappy >=1.2.1,<1.3.0a0 + - zstd >=1.5.6,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 48427 + timestamp: 1733513201413 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/blosc-1.21.6-hb4dfabd_1.conda + sha256: f1e408fc32e1fda8dee9c3fceee5650fd622526e4dc6fa1f1926f497b5508d13 + md5: 2cbbd6264ad58887c40aab37f2abdaba + depends: + - libgcc >=13 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - snappy >=1.2.1,<1.3.0a0 + - zstd >=1.5.6,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 36414 + timestamp: 1733513501944 +- conda: https://conda.anaconda.org/conda-forge/osx-64/blosc-1.21.6-hd145fbb_1.conda + sha256: 876bdb1947644b4408f498ac91c61f1f4987d2c57eb47c0aba0d5ee822cd7da9 + md5: 717852102c68a082992ce13a53403f9d + depends: + - __osx >=10.13 + - libcxx >=18 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - snappy >=1.2.1,<1.3.0a0 + - zstd >=1.5.6,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 46990 + timestamp: 1733513422834 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/blosc-1.21.6-h7dd00d9_1.conda + sha256: c3fe902114b9a3ac837e1a32408cc2142c147ec054c1038d37aec6814343f48a + md5: 925acfb50a750aa178f7a0aced77f351 + depends: + - __osx >=11.0 + - libcxx >=18 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - snappy >=1.2.1,<1.3.0a0 + - zstd >=1.5.6,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 33602 + timestamp: 1733513285902 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_3.conda sha256: c969baaa5d7a21afb5ed4b8dd830f82b78e425caaa13d717766ed07a61630bec md5: 5d08a0ac29e6a5a984817584775d4131 @@ -6038,6 +6324,51 @@ packages: - pkg:pypi/exceptiongroup?source=hash-mapping size: 21284 timestamp: 1746947398083 +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.1-hecca717_0.conda + sha256: e981cf62a722f0eb4631ac7b786c288c03883fbc241fa98a276308fb69cb2c59 + md5: 6033d8c2bb9b460929d00ba54154614c + depends: + - __glibc >=2.17,<3.0.a0 + - libexpat 2.7.1 hecca717_0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 140948 + timestamp: 1752719584725 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.7.1-hfae3067_0.conda + sha256: ec9296114a52c2d1c5f9f5409b90f16f6ef71319ef58fd4c89fd6c459c2a6ac1 + md5: 97a25989c55f2cc3a2cfdd17bb1bf510 + depends: + - libexpat 2.7.1 hfae3067_0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 134362 + timestamp: 1752719773039 +- conda: https://conda.anaconda.org/conda-forge/osx-64/expat-2.7.1-h21dd04a_0.conda + sha256: 40eed995c99513a7b83b11a9ca90e234c5595acd398ae475c1fe6e9004f01ad7 + md5: 20db53ab3b929f972b2ef6c7bad34eec + depends: + - __osx >=10.13 + - libexpat 2.7.1 h21dd04a_0 + license: MIT + license_family: MIT + purls: [] + size: 131911 + timestamp: 1752719761287 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/expat-2.7.1-hec049ff_0.conda + sha256: 8f2d1faeff1da40e66285711934e0d310d768720552452daa89b099aa8f82f29 + md5: 7888ca1ed7f0abef9442620dcf926e17 + depends: + - __osx >=11.0 + - libexpat 2.7.1 hec049ff_0 + license: MIT + license_family: MIT + purls: [] + size: 127524 + timestamp: 1752719671694 - conda: https://conda.anaconda.org/conda-forge/linux-64/fcl-0.7.0-h543440a_8.conda sha256: b082e91c7309ffed0aa01d97aa7c7acc8deddad152211153dce381817a4ef4f6 md5: eb7214feba07f44bff77a3ad510231a9 @@ -6810,6 +7141,65 @@ packages: purls: [] size: 60255 timestamp: 1604417405528 +- conda: https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.7.0-py311h52bc045_0.conda + sha256: cc7ec26db5d61078057da6e24e23abdd973414a065311fe0547a7620dd98e6b8 + md5: d9be554be03e3f2012655012314167d6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/frozenlist?source=hash-mapping + size: 55258 + timestamp: 1752167340913 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozenlist-1.7.0-py311h91c1192_0.conda + sha256: 1e022a44bf00c99eda4ab2c997950f8ac72ffc1e177efb9013be0e1c6876de1d + md5: 283efb3474356970eaf5d479c02afaf1 + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/frozenlist?source=hash-mapping + size: 55559 + timestamp: 1752167410138 +- conda: https://conda.anaconda.org/conda-forge/osx-64/frozenlist-1.7.0-py311h7a2b322_0.conda + sha256: ba999aa4f91a53d1104cf5aa78e318be3323936e5446a26ad1c5f59c85098b10 + md5: ad0e6d1df18292f15eab2dee54518d5c + depends: + - __osx >=10.13 + - libcxx >=19 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/frozenlist?source=hash-mapping + size: 50739 + timestamp: 1752167403997 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/frozenlist-1.7.0-py311h8740443_0.conda + sha256: b0b21e436d52d15cd29996ddbaa9eff04151b57330e35f436aab6ba303601ae8 + md5: e15cfa88d7671c12a25a574b63f63d9d + depends: + - __osx >=11.0 + - libcxx >=19 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/frozenlist?source=hash-mapping + size: 51115 + timestamp: 1752167450180 - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc-14.3.0-h76bdaa0_4.conda sha256: ded010fa43178225054436cfc24c1cc74e1f17303f39442b5254422e2f8a0b2d md5: 7e8d408ed45953d8a9fd5e9c5d44ab2d @@ -7332,6 +7722,30 @@ packages: purls: [] size: 71613 timestamp: 1712692611426 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda + sha256: 68f071ea25e79ee427c0d6c35ccc137d66f093a37660a4e41bafe0c49d64f2d6 + md5: 00e642ec191a19bf806a3915800e9524 + depends: + - libgcc-ng >=12 + - libpng >=1.6.43,<1.7.0a0 + - libzlib >=1.3.1,<2.0a0 + license: LGPL-2.0-or-later + license_family: LGPL + purls: [] + size: 74102 + timestamp: 1718542981099 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gl2ps-1.4.2-hedfd65a_1.conda + sha256: e6500b15fd2dbd776df204556702bb2c90d037523c18cd0a111c7c0f0d314aa2 + md5: 6a087dc84254035cbde984f2c010c9ef + depends: + - libgcc-ng >=12 + - libpng >=1.6.43,<1.7.0a0 + - libzlib >=1.3.1,<2.0a0 + license: LGPL-2.0-or-later + license_family: LGPL + purls: [] + size: 72023 + timestamp: 1718542978037 - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2 sha256: 86f5484e38f4604f7694b14f64238e932e8fd8d7364e86557f4911eded2843ae md5: fb05eb5c47590b247658243d27fc32f1 @@ -8436,6 +8850,56 @@ packages: purls: [] size: 1529358 timestamp: 1755172770535 +- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda + sha256: 0d09b6dc1ce5c4005ae1c6a19dc10767932ef9a5e9c755cfdbb5189ac8fb0684 + md5: bd77f8da987968ec3927990495dc22e4 + depends: + - libgcc-ng >=12 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libstdcxx-ng >=12 + - libzlib >=1.2.13,<2.0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 756742 + timestamp: 1695661547874 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/hdf4-4.2.15-hb6ba311_7.conda + sha256: 70d1e2d3e0b9ae1b149a31a4270adfbb5a4ceb2f8c36d17feffcd7bcb6208022 + md5: e1b6676b77b9690d07ea25de48aed97e + depends: + - libgcc-ng >=12 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libstdcxx-ng >=12 + - libzlib >=1.2.13,<2.0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 773862 + timestamp: 1695661552544 +- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf4-4.2.15-h8138101_7.conda + sha256: 8c767cc71226e9eb62649c903c68ba73c5f5e7e3696ec0319d1f90586cebec7d + md5: 7ce543bf38dbfae0de9af112ee178af2 + depends: + - libcxx >=15.0.7 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libzlib >=1.2.13,<2.0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 724103 + timestamp: 1695661907511 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf4-4.2.15-h2ee6834_7.conda + sha256: c3b01e3c3fe4ca1c4d28c287eaa5168a4f2fd3ffd76690082ac919244c22fa90 + md5: ff5d749fd711dc7759e127db38005924 + depends: + - libcxx >=15.0.7 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libzlib >=1.2.13,<2.0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 762257 + timestamp: 1695661864625 - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h6e4c0c1_103.conda sha256: 4f173af9e2299de7eee1af3d79e851bca28ee71e7426b377e841648b51d48614 md5: c74d83614aec66227ae5199d98852aaf @@ -8594,6 +9058,17 @@ packages: purls: [] size: 11857802 timestamp: 1720853997952 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 + md5: 53abe63df7e10a6ba605dc5f9f961d36 + depends: + - python >=3.10 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/idna?source=hash-mapping + size: 50721 + timestamp: 1760286526795 - conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.1.12-h7955e40_0.conda sha256: 4d8d07a4d5079d198168b44556fb86d094e6a716e8979b25a9f6c9c610e9fe56 md5: 37f5e1ab0db3691929f37dee78335d1b @@ -11720,6 +12195,27 @@ packages: purls: [] size: 145442 timestamp: 1731331005019 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda + sha256: e281356c0975751f478c53e14f3efea6cd1e23c3069406d10708d6c409525260 + md5: 53e7cbb2beb03d69a478631e23e340e9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgl 1.7.0 ha4b6fd6_2 + - libglx-devel 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + purls: [] + size: 113911 + timestamp: 1731331012126 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgl-devel-1.7.0-hd24410f_2.conda + sha256: ec5c3125b38295bad8acc80f793b8ee217ccb194338d73858be278db50ea82f1 + md5: 5d8323dff6a93596fb6f985cf6e8521a + depends: + - libgl 1.7.0 hd24410f_2 + - libglx-devel 1.7.0 hd24410f_2 + license: LicenseRef-libglvnd + purls: [] + size: 113925 + timestamp: 1731331014056 - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.84.3-hf39c6af_0.conda sha256: e1ad3d9ddaa18f95ff5d244587fd1a37aca6401707f85a37f7d9b5002fcf16d0 md5: 467f23819b1ea2b89c3fc94d65082301 @@ -11843,6 +12339,29 @@ packages: purls: [] size: 77736 timestamp: 1731330998960 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda + sha256: 0a930e0148ab6e61089bbcdba25a2e17ee383e7de82e7af10cc5c12c82c580f3 + md5: 27ac5ae872a21375d980bd4a6f99edf3 + depends: + - __glibc >=2.17,<3.0.a0 + - libglx 1.7.0 ha4b6fd6_2 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-xorgproto + license: LicenseRef-libglvnd + purls: [] + size: 26388 + timestamp: 1731331003255 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglx-devel-1.7.0-hd24410f_2.conda + sha256: 4bc28ecc38f30ca1ac66a8fb6c5703f4d888381ec46d3938b7c3383210061ec5 + md5: 1f9ddbb175a63401662d1c6222cef6ff + depends: + - libglx 1.7.0 hd24410f_2 + - xorg-libx11 >=1.8.9,<2.0a0 + - xorg-xorgproto + license: LicenseRef-libglvnd + purls: [] + size: 26362 + timestamp: 1731331008489 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_4.conda sha256: e0487a8fec78802ac04da0ac1139c3510992bc58a58cde66619dde3b363c2933 md5: 3baf8976c96134738bba224e9ef6b1e5 @@ -13569,6 +14088,26 @@ packages: purls: [] size: 440873 timestamp: 1749232400775 +- conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-devel-5.8.1-hd471939_2.conda + sha256: a020ad9f1e27d4f7a522cbbb9613b99f64a5cc41f80caf62b9fdd1cf818acf18 + md5: 2e16f5b4f6c92b96f6a346f98adc4e3e + depends: + - __osx >=10.13 + - liblzma 5.8.1 hd471939_2 + license: 0BSD + purls: [] + size: 116356 + timestamp: 1749230171181 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-devel-5.8.1-h39f12f2_2.conda + sha256: 974804430e24f0b00f3a48b67ec10c9f5441c9bb3d82cc0af51ba45b8a75a241 + md5: 1201137f1a5ec9556032ffc04dcdde8d + depends: + - __osx >=11.0 + - liblzma 5.8.1 h39f12f2_2 + license: 0BSD + purls: [] + size: 116244 + timestamp: 1749230297170 - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.2-hc2fc477_0.conda sha256: 6b21e0f3d1577bbe10f27003212f0b8c9a881d99faa01a83476311730aed5c9d md5: a02cb80c806b7b768e1d60170f63375d @@ -13592,6 +14131,99 @@ packages: purls: [] size: 294158 timestamp: 1752566632023 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h21f7587_118.conda + sha256: ad260036929255d8089f748db0dce193d0d588ad7f88c06027dd9d8662cc1cc6 + md5: 5f05af73150f62adab1492ab2d18d573 + depends: + - __glibc >=2.17,<3.0.a0 + - blosc >=1.21.6,<2.0a0 + - bzip2 >=1.0.8,<2.0a0 + - hdf4 >=4.2.15,<4.2.16.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - libaec >=1.1.4,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libxml2 >=2.13.8,<2.14.0a0 + - libzip >=1.11.2,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.1,<4.0a0 + - zlib + - zstd >=1.5.7,<1.6.0a0 + license: MIT + license_family: MIT + purls: [] + size: 844115 + timestamp: 1754055003755 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnetcdf-4.9.2-nompi_hb193ca5_118.conda + sha256: 016f9991ac2a9d87bd1852789458a8ec8e83575fb14407df892c92ff6866c77b + md5: 4343a5d9883201aaa63f7daee8c5d170 + depends: + - blosc >=1.21.6,<2.0a0 + - bzip2 >=1.0.8,<2.0a0 + - hdf4 >=4.2.15,<4.2.16.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - libaec >=1.1.4,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libxml2 >=2.13.8,<2.14.0a0 + - libzip >=1.11.2,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.1,<4.0a0 + - zlib + - zstd >=1.5.7,<1.6.0a0 + license: MIT + license_family: MIT + purls: [] + size: 867935 + timestamp: 1754055448646 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libnetcdf-4.9.2-nompi_h6054f6d_118.conda + sha256: 6145bccbc484d069938a9bad162f573c0421ccbf7a8ac9d34228d1706956af4d + md5: c92aa5e0a14b8381e7aaf78714a03ff6 + depends: + - __osx >=10.13 + - blosc >=1.21.6,<2.0a0 + - bzip2 >=1.0.8,<2.0a0 + - hdf4 >=4.2.15,<4.2.16.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - libaec >=1.1.4,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libcxx >=19 + - libxml2 >=2.13.8,<2.14.0a0 + - libzip >=1.11.2,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.1,<4.0a0 + - zlib + - zstd >=1.5.7,<1.6.0a0 + license: MIT + license_family: MIT + purls: [] + size: 727390 + timestamp: 1754055079231 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnetcdf-4.9.2-nompi_h2d3d5cf_118.conda + sha256: e7ca7726e94ef56e96ef7e5a89b23971188b2b54e1b660ed1c200593cc0ae055 + md5: ed5b74ff627e6cb6d7ab1c3ef7e3baf8 + depends: + - __osx >=11.0 + - blosc >=1.21.6,<2.0a0 + - bzip2 >=1.0.8,<2.0a0 + - hdf4 >=4.2.15,<4.2.16.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - libaec >=1.1.4,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libcxx >=19 + - libxml2 >=2.13.8,<2.14.0a0 + - libzip >=1.11.2,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.1,<4.0a0 + - zlib + - zstd >=1.5.7,<1.6.0a0 + license: MIT + license_family: MIT + purls: [] + size: 683396 + timestamp: 1754055262589 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda sha256: b0f2b3695b13a989f75d8fd7f4778e1c7aabe3b36db83f0fe80b2cd812c0e975 md5: 19e57602824042dfd0446292ef90488b @@ -14094,6 +14726,25 @@ packages: purls: [] size: 56355 timestamp: 1731331001820 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-devel-1.7.0-ha4b6fd6_2.conda + sha256: b347798eba61ce8d7a65372cf0cf6066c328e5717ab69ae251c6822e6f664f23 + md5: 75b039b1e51525f4572f828be8441970 + depends: + - __glibc >=2.17,<3.0.a0 + - libopengl 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + purls: [] + size: 15460 + timestamp: 1731331007610 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopengl-devel-1.7.0-hd24410f_2.conda + sha256: 1b108b3ea9b0b9ae2b14638702ca391f89d9f2ffcd1772cfe704007221f6e9d9 + md5: c758a285b03a6d339911347f2b03728d + depends: + - libopengl 1.7.0 hd24410f_2 + license: LicenseRef-libglvnd + purls: [] + size: 15554 + timestamp: 1731331011229 - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2025.0.0-hdc3f47d_3.conda sha256: fe0e184141a3563d4c97134a1b7a60c66302cf0e2692d15d49c41382cdf61648 md5: 3a88245058baa9d18ef4ea6df18ff63e @@ -16635,39 +17286,18 @@ packages: purls: [] size: 16079459 timestamp: 1737781718971 -- pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl - name: loguru - version: 0.7.3 - sha256: 31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c - requires_dist: - - colorama>=0.3.4 ; sys_platform == 'win32' - - aiocontextvars>=0.2.0 ; python_full_version < '3.7' - - win32-setctime>=1.0.0 ; sys_platform == 'win32' - - pre-commit==4.0.1 ; python_full_version >= '3.9' and extra == 'dev' - - tox==3.27.1 ; python_full_version < '3.8' and extra == 'dev' - - tox==4.23.2 ; python_full_version >= '3.8' and extra == 'dev' - - pytest==6.1.2 ; python_full_version < '3.8' and extra == 'dev' - - pytest==8.3.2 ; python_full_version >= '3.8' and extra == 'dev' - - pytest-cov==2.12.1 ; python_full_version < '3.8' and extra == 'dev' - - pytest-cov==5.0.0 ; python_full_version == '3.8.*' and extra == 'dev' - - pytest-cov==6.0.0 ; python_full_version >= '3.9' and extra == 'dev' - - pytest-mypy-plugins==1.9.3 ; python_full_version >= '3.6' and python_full_version < '3.8' and extra == 'dev' - - pytest-mypy-plugins==3.1.0 ; python_full_version >= '3.8' and extra == 'dev' - - colorama==0.4.5 ; python_full_version < '3.8' and extra == 'dev' - - colorama==0.4.6 ; python_full_version >= '3.8' and extra == 'dev' - - freezegun==1.1.0 ; python_full_version < '3.8' and extra == 'dev' - - freezegun==1.5.0 ; python_full_version >= '3.8' and extra == 'dev' - - exceptiongroup==1.1.3 ; python_full_version >= '3.7' and python_full_version < '3.11' and extra == 'dev' - - mypy==0.910 ; python_full_version < '3.6' and extra == 'dev' - - mypy==0.971 ; python_full_version == '3.6.*' and extra == 'dev' - - mypy==1.4.1 ; python_full_version == '3.7.*' and extra == 'dev' - - mypy==1.13.0 ; python_full_version >= '3.8' and extra == 'dev' - - sphinx==8.1.3 ; python_full_version >= '3.11' and extra == 'dev' - - sphinx-rtd-theme==3.0.2 ; python_full_version >= '3.11' and extra == 'dev' - - myst-parser==4.0.0 ; python_full_version >= '3.11' and extra == 'dev' - - build==1.2.2 ; python_full_version >= '3.11' and extra == 'dev' - - twine==6.0.1 ; python_full_version >= '3.11' and extra == 'dev' - requires_python: '>=3.5,<4.0' +- conda: https://conda.anaconda.org/conda-forge/noarch/loguru-0.7.3-pyh707e725_0.conda + sha256: e4a07f357a4cf195a2345dabd98deab80f4d53574abe712a9cc7f22d3f2cc2c3 + md5: 49647ac1de4d1e4b49124aedf3934e02 + depends: + - __unix + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/loguru?source=hash-mapping + size: 59696 + timestamp: 1746634858826 - conda: https://conda.anaconda.org/conda-forge/linux-64/lxml-6.0.0-py311hbd2c71b_0.conda sha256: 0c8783524bd51f8e9d6ec1322e74fdd200036e994b331d8a37aa28759e15b595 md5: 3fee70825164281b54d6c3aba97e619c @@ -17186,6 +17816,120 @@ packages: purls: [] size: 558708 timestamp: 1730581372400 +- conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py311hdf67eae_1.conda + sha256: 8c81a6208def64afc3e208326d78d7af60bcbc32d44afe1269b332df84084f29 + md5: c1153b2cb3318889ce624a3b4f0db7f7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 102979 + timestamp: 1762504186626 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py311hfca10b7_1.conda + sha256: 35a36e3062bf84a70c0105b1553a1aa7b16a1dad19a97945efeea2b92ca95f23 + md5: 560e361fc9aff96fdd179e7e5d41471e + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 100340 + timestamp: 1762504276815 +- conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py311haec20ae_1.conda + sha256: 841eb48c3b3d4ca2d84b836a9cb63d5d752a630697829f944183260547fc8cea + md5: 7496bce5e71b8c6c71aef95c1feaeee5 + depends: + - __osx >=10.13 + - libcxx >=19 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 90578 + timestamp: 1762504498634 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.1.2-py311h5a5e7c7_1.conda + sha256: 4da7ec2bf4b7bf1cc5d394f7b44265538a78a8f0fac52483c288a69d2032aabd + md5: 123b3c15746ccfbfd8bf1c30c79f2ba6 + depends: + - __osx >=11.0 + - libcxx >=19 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 91099 + timestamp: 1762504394543 +- conda: https://conda.anaconda.org/conda-forge/linux-64/multidict-6.7.0-py311h3778330_0.conda + sha256: f7465baba01062bc02c725fa580d6ad2b3843ea6eef6a80210e45fcf3894a325 + md5: 77f6c8f28e9feb6d578cd7215604d1c7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/multidict?source=hash-mapping + size: 100179 + timestamp: 1765460902635 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/multidict-6.7.0-py311h164a683_0.conda + sha256: 6e8500bb86bcf248d31cbdfc9767e5e7b440e09acb271e16f19a89ccf6cc3a3a + md5: d2911436592330f3422ecf9830eb083b + depends: + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/multidict?source=hash-mapping + size: 103037 + timestamp: 1765460512504 +- conda: https://conda.anaconda.org/conda-forge/osx-64/multidict-6.7.0-py311h24ee9f8_0.conda + sha256: 09d80da8bd97fd524e35b1ad0ef48e87711d7bc1347bd6a72c3f156222b44279 + md5: ea361b0d2d4b2dfc276d2202f05bcb9f + depends: + - __osx >=10.13 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/multidict?source=hash-mapping + size: 89403 + timestamp: 1765460907935 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/multidict-6.7.0-py311h97ccca8_0.conda + sha256: 0102c92ed235fc94c9de67a2c4cbc95244dd3d21f95bc80a56211ed31cac4824 + md5: 3b8cb75e379ce0326595dc31c420ee4e + depends: + - __osx >=11.0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/multidict?source=hash-mapping + size: 88386 + timestamp: 1765460744715 - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda sha256: d09c47c2cf456de5c09fa66d2c3c5035aa1fa228a1983a433c47b876aa16ce90 md5: 37293a85a0f4f77bbd9cf7aaefc62609 @@ -18275,6 +19019,46 @@ packages: purls: [] size: 3074848 timestamp: 1754465710470 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openvdb-12.0.1-py311heb7b8bb_0.conda + sha256: d7b2f49630c3263baf3c8f571ec4e8c5a12a3dfeb8a0160a40fa6ed5a61c13bf + md5: 9c70e3da1edcac39ab8280aedf7c9765 + depends: + - python + - numpy + - libstdcxx >=13 + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + - libboost >=1.86.0,<1.87.0a0 + - blosc >=1.21.6,<2.0a0 + - python_abi 3.11.* *_cp311 + - numpy >=1.21,<3 + - tbb >=2021.13.0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 2523509 + timestamp: 1743704965108 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openvdb-12.0.1-py311h29547a6_0.conda + sha256: 96671b612a34a8b5e9981067c55040ade0ae08f9689691c649202da6e1f3ec1d + md5: 7ad8a1e7936d7b58f5587816f412c67b + depends: + - python + - numpy + - libstdcxx >=13 + - libgcc >=13 + - python 3.11.* *_cpython + - python_abi 3.11.* *_cp311 + - tbb >=2021.13.0 + - numpy >=1.21,<3 + - libboost >=1.86.0,<1.87.0a0 + - libzlib >=1.3.1,<2.0a0 + - blosc >=1.21.6,<2.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 2488475 + timestamp: 1743704945673 - conda: https://conda.anaconda.org/conda-forge/linux-64/orocos-kdl-1.5.1-h5888daf_8.conda sha256: 2c32fc459cabed3b272b3d41c63a869de3bee69636dee39519005fbc3e9c7b64 md5: 81554d1604c59c8eabf592eacd1f561a @@ -18441,6 +19225,95 @@ packages: purls: [] size: 426931 timestamp: 1751292636271 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pcl-1.15.0-hd1363f8_2.conda + sha256: e6d5fe4a022229fe15ed7fe5226716893375deb3b3ef65e6a5caabe9fb76015b + md5: 2065962ae1fc02ce98a73e8ef9ba0591 + depends: + - __glibc >=2.17,<3.0.a0 + - eigen + - flann >=1.9.2,<1.9.3.0a0 + - glew >=2.1.0,<2.2.0a0 + - libboost >=1.86.0,<1.87.0a0 + - libboost-devel + - libgcc >=13 + - libgl >=1.7.0,<2.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libstdcxx >=13 + - qhull >=2020.2,<2020.3.0a0 + - qt6-main >=6.9.0,<6.10.0a0 + - vtk + - vtk-base >=9.4.2,<9.4.3.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18080330 + timestamp: 1748340656265 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pcl-1.15.0-h462c444_2.conda + sha256: 468994d7796fd420ee2e9f0cc31a89832fcef03fb20af5e68c5d6633b1c30f67 + md5: 32c47026ad63f97508b424c41e701995 + depends: + - eigen + - flann >=1.9.2,<1.9.3.0a0 + - glew >=2.1.0,<2.2.0a0 + - libboost >=1.86.0,<1.87.0a0 + - libboost-devel + - libgcc >=13 + - libgl >=1.7.0,<2.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libstdcxx >=13 + - qhull >=2020.2,<2020.3.0a0 + - qt6-main >=6.9.0,<6.10.0a0 + - vtk + - vtk-base >=9.4.2,<9.4.3.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17230683 + timestamp: 1748339138592 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pcl-1.15.0-h1b4601b_2.conda + sha256: 9580dd8b71e1f069688007bcc6c181943a5c2e5be1c9074f638eb6d6afac19ee + md5: 102b3737666437540423ea83e1de7790 + depends: + - __osx >=11.0 + - eigen + - flann >=1.9.2,<1.9.3.0a0 + - glew >=2.1.0,<2.2.0a0 + - libboost >=1.86.0,<1.87.0a0 + - libboost-devel + - libcxx >=18 + - libpng >=1.6.47,<1.7.0a0 + - qhull >=2020.2,<2020.3.0a0 + - qt6-main >=6.9.0,<6.10.0a0 + - vtk + - vtk-base >=9.4.2,<9.4.3.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 13676418 + timestamp: 1748339598584 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcl-1.15.0-hae97317_2.conda + sha256: 2ccfed736fabf25646e0a0fd42bf691cb8571cef451147bd821ace3b2a728a4c + md5: def9239db09d106e2c5f35b6ed46bf61 + depends: + - __osx >=11.0 + - eigen + - flann >=1.9.2,<1.9.3.0a0 + - glew >=2.1.0,<2.2.0a0 + - libboost >=1.86.0,<1.87.0a0 + - libboost-devel + - libcxx >=18 + - libpng >=1.6.47,<1.7.0a0 + - qhull >=2020.2,<2020.3.0a0 + - qt6-main >=6.9.0,<6.10.0a0 + - vtk + - vtk-base >=9.4.2,<9.4.3.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 13240094 + timestamp: 1748339721490 - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.45-hc749103_0.conda sha256: 27c4014f616326240dcce17b5f3baca3953b6bc5f245ceb49c3fa1e6320571eb md5: b90bece58b4c2bf25969b70f3be42d25 @@ -18775,6 +19648,61 @@ packages: purls: [] size: 2787374 timestamp: 1754927844772 +- conda: https://conda.anaconda.org/conda-forge/linux-64/propcache-0.3.1-py311h2dc5d0c_0.conda + sha256: 38ef315508a4c6c96985a990b172964a8ed737fe4e991d82ad9d2a77c45add1f + md5: c75eb8c91d69fe0385fce584f3ce193a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/propcache?source=hash-mapping + size: 54558 + timestamp: 1744525097548 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/propcache-0.3.1-py311h58d527c_0.conda + sha256: 65d0f979c9f3e3972dc8ef178c5fbb0bf6858cd82521ec9e6be5b563c18756c3 + md5: 872b336081fdbcd407ba6eef96f6651a + depends: + - libgcc >=13 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/propcache?source=hash-mapping + size: 54289 + timestamp: 1744525129299 +- conda: https://conda.anaconda.org/conda-forge/osx-64/propcache-0.3.1-py311ha3cf9ac_0.conda + sha256: 5245afac67313565159345ff12fee41f91183a46f46b84e7a94a6d3a6bafaa90 + md5: 8fd57bbb0bdb21497cc53129a2f94e91 + depends: + - __osx >=10.13 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/propcache?source=hash-mapping + size: 49875 + timestamp: 1744525202139 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/propcache-0.3.1-py311h4921393_0.conda + sha256: 559f330cc40372422f8d9d5068b905b80d6762a8c2c7aeb4886a98ed7023c686 + md5: 667f23d757cbfa63e8b3ecc7e7d34b18 + depends: + - __osx >=11.0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/propcache?source=hash-mapping + size: 51291 + timestamp: 1744525140418 - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.0.0-py311h9ecbd09_0.conda sha256: 50d0944b59a9c6dfa6b99cc2632bf8bc9bef9c7c93710390ded6eac953f0182d md5: 1a390a54b2752169f5ba4ada5a8108e4 @@ -33581,6 +34509,54 @@ packages: license: BSD-3-Clause size: 10216 timestamp: 1753307987408 +- conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-openvdb-vendor-2.3.4-np126py311hbc2a38a_13.conda + sha256: d1835fbbdddeba76bf3cc03529699f971e7ef5ec38e269944dd4f34082d710be + md5: 6d74856076c2244182c201efe80a9c5a + depends: + - libboost-devel + - python + - ros-humble-ros-workspace + - ros2-distro-mutex 0.7.* humble_* + - tbb + - tbb-devel + - zlib + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - libgcc >=13 + - tbb >=2022.2.0 + - python_abi 3.11.* *_cp311 + - libboost >=1.86.0,<1.87.0a0 + - libzlib >=1.3.1,<2.0a0 + - numpy >=1.26.4,<2.0a0 + - openvdb >=12.0.1,<13.0a0 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + license: BSD-3-Clause + size: 25073 + timestamp: 1753308411845 +- conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-openvdb-vendor-2.3.4-np126py311hbdd918e_13.conda + sha256: 1284fc38853fcef956a71d508ea24d11cc78aec19d13aae2bdfd8b0c78dbd9c7 + md5: 41607c41b30d0876e691301dec51e401 + depends: + - libboost-devel + - python + - ros-humble-ros-workspace + - ros2-distro-mutex 0.7.* humble_* + - tbb + - tbb-devel + - zlib + - libstdcxx >=13 + - libgcc >=13 + - libboost >=1.86.0,<1.87.0a0 + - openvdb >=12.0.1,<13.0a0 + - tbb >=2022.2.0 + - numpy >=1.26.4,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + size: 24983 + timestamp: 1753308528275 - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-orocos-kdl-vendor-0.2.5-np126py311hbc2a38a_13.conda sha256: de46a2167d484f48c194054a1c03c933c0828070c7c4608102aaf7c5b13934c5 md5: 62f2e860f99ce1163d32027820e0c49a @@ -33816,6 +34792,211 @@ packages: license: BSD-3-Clause size: 42367 timestamp: 1753313440771 +- conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pcl-conversions-2.4.5-np126py311hbc2a38a_13.conda + sha256: 459e2dc8d0e71ea230ccc893b640383ac1b84c14907140f5aa93a564690189f0 + md5: 367b3edafd744b10d1df2797ee754ef1 + depends: + - eigen + - libboost-devel + - pcl + - python + - ros-humble-message-filters + - ros-humble-pcl-msgs + - ros-humble-rclcpp + - ros-humble-ros-workspace + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - vtk-base + - xorg-libx11 + - xorg-libxext + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=13 + - libgcc >=13 + - numpy >=1.26.4,<2.0a0 + - pcl >=1.15.0,<1.15.1.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - vtk-base >=9.4.2,<9.4.3.0a0 + - libgl >=1.7.0,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - python_abi 3.11.* *_cp311 + - libboost >=1.86.0,<1.87.0a0 + - libopengl >=1.7.0,<2.0a0 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + license: BSD-3-Clause + size: 65127 + timestamp: 1753313898103 +- conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-pcl-conversions-2.4.5-np126py311hbdd918e_13.conda + sha256: ea48268804bf2f278b34127da85b4a026b3cd4e93a790318d5ec96c5602ab6d1 + md5: 5f623e1ffcb70ca8e5aad9e8ac3c26a4 + depends: + - eigen + - libboost-devel + - pcl + - python + - ros-humble-message-filters + - ros-humble-pcl-msgs + - ros-humble-rclcpp + - ros-humble-ros-workspace + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - vtk-base + - xorg-libx11 + - xorg-libxext + - libstdcxx >=13 + - libgcc >=13 + - vtk-base >=9.4.2,<9.4.3.0a0 + - pcl >=1.15.0,<1.15.1.0a0 + - python_abi 3.11.* *_cp311 + - libboost >=1.86.0,<1.87.0a0 + - libopengl >=1.7.0,<2.0a0 + - libgl >=1.7.0,<2.0a0 + - numpy >=1.26.4,<2.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + license: BSD-3-Clause + size: 63988 + timestamp: 1753314002656 +- conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-pcl-conversions-2.4.5-np126py311h3f9c716_13.conda + sha256: 7aa842d0224e53dd3771de2e5c5c86d31b1e44d8932314a602fcbcb4772a12a4 + md5: 6b7b730054356eb9b1c2eb4c9efeb2b9 + depends: + - eigen + - libboost-devel + - pcl + - python + - ros-humble-message-filters + - ros-humble-pcl-msgs + - ros-humble-rclcpp + - ros-humble-ros-workspace + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - vtk-base + - __osx >=10.14 + - xorg-libx11 + - xorg-libxext + - libcxx >=18 + - __osx >=10.13 + - vtk-base >=9.4.2,<9.4.3.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - libboost >=1.86.0,<1.87.0a0 + - numpy >=1.26.4,<2.0a0 + - pcl >=1.15.0,<1.15.1.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - python_abi 3.11.* *_cp311 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + license: BSD-3-Clause + size: 57774 + timestamp: 1753321890813 +- conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-pcl-conversions-2.4.5-np126py311h2a51a2c_13.conda + sha256: 24db6c685b1dd8d4c1dd70860f8c60a7974705658da8569c3474523dbf3bbddf + md5: 5041e31ee2cb411b0d82f352bf710a0a + depends: + - eigen + - libboost-devel + - pcl + - python + - ros-humble-message-filters + - ros-humble-pcl-msgs + - ros-humble-rclcpp + - ros-humble-ros-workspace + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - vtk-base + - xorg-libx11 + - xorg-libxext + - __osx >=11.0 + - libcxx >=18 + - pcl >=1.15.0,<1.15.1.0a0 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - numpy >=1.26.4,<2.0a0 + - vtk-base >=9.4.2,<9.4.3.0a0 + - libboost >=1.86.0,<1.87.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - python_abi 3.11.* *_cp311 + - xorg-libxext >=1.3.6,<2.0a0 + license: BSD-3-Clause + size: 57711 + timestamp: 1753313983514 +- conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pcl-msgs-1.0.0-np126py311hbc2a38a_13.conda + sha256: 311415fe80325620ff0b6323d2a92dd564b902c5fef6e4cc40ed01eed8e5b691 + md5: b7674a58a6ffab3725a7ebcb57c49bfa + depends: + - python + - ros-humble-ros-workspace + - ros-humble-rosidl-default-runtime + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - libgcc >=13 + - libstdcxx >=13 + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + - python_abi 3.11.* *_cp311 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - numpy >=1.26.4,<2.0a0 + license: BSD-3-Clause + size: 131397 + timestamp: 1753312449946 +- conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-pcl-msgs-1.0.0-np126py311hbdd918e_13.conda + sha256: 816920239384790d78f0e1c8a5a986cb65f03f315e545a77d5de16fcb7bfe29a + md5: 21c35c2c80473db9ba5cfb1b047fe419 + depends: + - python + - ros-humble-ros-workspace + - ros-humble-rosidl-default-runtime + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - libstdcxx >=13 + - libgcc >=13 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - numpy >=1.26.4,<2.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + size: 135831 + timestamp: 1753312832366 +- conda: https://conda.anaconda.org/robostack-humble/osx-64/ros-humble-pcl-msgs-1.0.0-np126py311h3f9c716_13.conda + sha256: 6fbb6bdfde9384d0f2dd1da39c393ee3347efab2a10ee8a853590f940ec73f31 + md5: 6f07d7944cf0d30578c473b888919228 + depends: + - python + - ros-humble-ros-workspace + - ros-humble-rosidl-default-runtime + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - __osx >=10.14 + - libcxx >=18 + - __osx >=10.13 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - python_abi 3.11.* *_cp311 + - numpy >=1.26.4,<2.0a0 + license: BSD-3-Clause + size: 121257 + timestamp: 1753317980446 +- conda: https://conda.anaconda.org/robostack-humble/osx-arm64/ros-humble-pcl-msgs-1.0.0-np126py311h2a51a2c_13.conda + sha256: 1e4b069a09ab6a03002062a37b563b1404d9f5a2765f6454aa0fc513f0c62c19 + md5: 46790719199fd4d8bd68d9926b25703e + depends: + - python + - ros-humble-ros-workspace + - ros-humble-rosidl-default-runtime + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros2-distro-mutex 0.7.* humble_* + - libcxx >=18 + - __osx >=11.0 + - numpy >=1.26.4,<2.0a0 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + size: 119877 + timestamp: 1753312187808 - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-pid-controller-2.48.0-np126py311hbc2a38a_13.conda sha256: c90979b6eab1699f3d33df3e8433c7445caf91e25e0638e8a6d9051e0ad768d2 md5: 1cbbfee81a4b1f72b029a1e90179198d @@ -44519,6 +45700,89 @@ packages: license: BSD-3-Clause size: 36522 timestamp: 1753310146520 +- conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-spatio-temporal-voxel-layer-2.3.4-np126py311hbc2a38a_13.conda + sha256: 7849166fc2d854bb96727ede125634e95ea3626ea8d23ff7d6a7e497483394de + md5: 9131a9705d68f7a3592e56514b112246 + depends: + - pcl + - python + - ros-humble-builtin-interfaces + - ros-humble-geometry-msgs + - ros-humble-laser-geometry + - ros-humble-message-filters + - ros-humble-nav2-costmap-2d + - ros-humble-openvdb-vendor + - ros-humble-pcl-conversions + - ros-humble-pluginlib + - ros-humble-rclcpp + - ros-humble-ros-workspace + - ros-humble-rosidl-default-runtime + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros-humble-std-srvs + - ros-humble-tf2-geometry-msgs + - ros-humble-tf2-ros + - ros-humble-tf2-sensor-msgs + - ros-humble-visualization-msgs + - ros2-distro-mutex 0.7.* humble_* + - xorg-libx11 + - xorg-libxext + - libstdcxx >=13 + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libxext >=1.3.6,<2.0a0 + - numpy >=1.26.4,<2.0a0 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - libgl >=1.7.0,<2.0a0 + - python_abi 3.11.* *_cp311 + - xorg-libx11 >=1.8.12,<2.0a0 + - libopengl >=1.7.0,<2.0a0 + - pcl >=1.15.0,<1.15.1.0a0 + license: BSD-3-Clause + size: 581468 + timestamp: 1753315837152 +- conda: https://conda.anaconda.org/robostack-humble/linux-aarch64/ros-humble-spatio-temporal-voxel-layer-2.3.4-np126py311hbdd918e_13.conda + sha256: 309150ec278539ac1e6e155abcf3c0e1d0a35ef1ee4ca74a90d0b8c9606133c8 + md5: 48f21fc90245bf44ea993058ceb6aad4 + depends: + - pcl + - python + - ros-humble-builtin-interfaces + - ros-humble-geometry-msgs + - ros-humble-laser-geometry + - ros-humble-message-filters + - ros-humble-nav2-costmap-2d + - ros-humble-openvdb-vendor + - ros-humble-pcl-conversions + - ros-humble-pluginlib + - ros-humble-rclcpp + - ros-humble-ros-workspace + - ros-humble-rosidl-default-runtime + - ros-humble-sensor-msgs + - ros-humble-std-msgs + - ros-humble-std-srvs + - ros-humble-tf2-geometry-msgs + - ros-humble-tf2-ros + - ros-humble-tf2-sensor-msgs + - ros-humble-visualization-msgs + - ros2-distro-mutex 0.7.* humble_* + - xorg-libx11 + - xorg-libxext + - libgcc >=13 + - libstdcxx >=13 + - libgcc >=13 + - ros2-distro-mutex >=0.7.0,<0.8.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - numpy >=1.26.4,<2.0a0 + - libopengl >=1.7.0,<2.0a0 + - python_abi 3.11.* *_cp311 + - libgl >=1.7.0,<2.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - pcl >=1.15.0,<1.15.1.0a0 + license: BSD-3-Clause + size: 582426 + timestamp: 1753315600218 - conda: https://conda.anaconda.org/robostack-humble/linux-64/ros-humble-spdlog-vendor-1.3.1-np126py311h11365e7_13.conda sha256: ea5aada82ffde9e73df2933bb8c5292132cdd8c0bb39b428620e0009643f8bbd md5: 2326efbd7109deeb4c2226478b2459ab @@ -49730,6 +50994,34 @@ packages: purls: [] size: 18531 timestamp: 1649177151464 +- conda: https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.09-ha770c72_0.conda + sha256: 18f84366d84b83bb4b2a6e0ac4487a5b4ee33c531faa2d822027fddf8225eed5 + md5: 99884244028fe76046e3914f90d4ad05 + license: BSL-1.0 + purls: [] + size: 14226 + timestamp: 1767012219987 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/utfcpp-4.09-h8af1aa0_0.conda + sha256: be28ea1049025975253f04875195b52d1a7b755a38d8f0039f072b9fa05499b5 + md5: daa98fd6d175e72d65c353b6b7504971 + license: BSL-1.0 + purls: [] + size: 14197 + timestamp: 1767012435525 +- conda: https://conda.anaconda.org/conda-forge/osx-64/utfcpp-4.09-h694c41f_0.conda + sha256: 05ba7c7a03d9bb8c58813c08f68419e48298dde839623c3ef9d86695cb613e04 + md5: 6cd5227f7138e460302f97d1a1549d84 + license: BSL-1.0 + purls: [] + size: 14226 + timestamp: 1767012401783 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/utfcpp-4.09-hce30654_0.conda + sha256: 598a2c7c38a8b3495efd354e5903a693059f0ee0d1b6af1a339ec09a7839737a + md5: bf5e569456f850071049b692fe7ab755 + license: BSL-1.0 + purls: [] + size: 14174 + timestamp: 1767012345273 - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.8.11-heb9285d_0.conda sha256: 8a15d1c1a208ea5d0934d7d072e3ab256ae64504f7675cdfa4a739b2d37af528 md5: 54a1d1beaa19fd2edf0cf7a61a9a28dc @@ -49781,6 +51073,315 @@ packages: purls: [] size: 13572756 timestamp: 1755263859325 +- conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-9.4.2-h94a02a8_4.conda + sha256: fef5f550dea59151e6146f6e804e31e618f9f6e46f9628f97026f5b16597b938 + md5: 155c7b2ca23d41b4b4f185df9d2c8446 + depends: + - eigen + - expat + - libboost-devel + - libgl-devel + - liblzma-devel + - libopengl-devel + - python_abi 3.11.* *_cp311 + - tbb-devel + - vtk-base >=9.4.2,<9.4.3.0a0 + - vtk-io-ffmpeg >=9.4.2,<9.4.3.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28390 + timestamp: 1757095910083 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-9.4.2-h98dbe00_4.conda + sha256: 9898d431c49242e1b325645256154dd096158a051b77657162f38c015223a4a7 + md5: 9e36ac3903c7b37c4540e9e09ed61b24 + depends: + - eigen + - expat + - libboost-devel + - libgl-devel + - liblzma-devel + - libopengl-devel + - python_abi 3.11.* *_cp311 + - tbb-devel + - vtk-base >=9.4.2,<9.4.3.0a0 + - vtk-io-ffmpeg >=9.4.2,<9.4.3.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28579 + timestamp: 1757097080248 +- conda: https://conda.anaconda.org/conda-forge/osx-64/vtk-9.4.2-h3d6103e_4.conda + sha256: 56a109318cda438daae03b6ed0d6437ebd215a7c86f577e875543a5350dbab73 + md5: 21885cac5b7b505283dce1c611d01a75 + depends: + - eigen + - expat + - libboost-devel + - liblzma-devel + - python_abi 3.11.* *_cp311 + - tbb-devel + - vtk-base >=9.4.2,<9.4.3.0a0 + - vtk-io-ffmpeg >=9.4.2,<9.4.3.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28633 + timestamp: 1757093912327 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/vtk-9.4.2-h4dfd180_4.conda + sha256: 01940168d3c7b08f8b271a9bbfeba626450ca5fd251862b0bce41c38690e8302 + md5: 03074c80a220202bc950d5590c91d6ed + depends: + - eigen + - expat + - libboost-devel + - liblzma-devel + - python_abi 3.11.* *_cp311 + - tbb-devel + - vtk-base >=9.4.2,<9.4.3.0a0 + - vtk-io-ffmpeg >=9.4.2,<9.4.3.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28711 + timestamp: 1757094269417 +- conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.4.2-py311hc26c8ec_1.conda + sha256: 7fee36c221332efa4a427b8518ea0ee0a8397569921c577e97d8494457654438 + md5: a7c42afeb9208906fef1dd9017a3f429 + depends: + - __glibc >=2.17,<3.0.a0 + - double-conversion >=3.3.1,<3.4.0a0 + - gl2ps >=1.4.2,<1.4.3.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - jsoncpp >=1.9.6,<1.9.7.0a0 + - libexpat >=2.7.0,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libgcc >=13 + - libglvnd >=1.7.0,<2.0a0 + - libglx >=1.7.0,<2.0a0 + - libjpeg-turbo >=3.1.0,<4.0a0 + - liblzma >=5.8.1,<6.0a0 + - libnetcdf >=4.9.2,<4.9.3.0a0 + - libogg >=1.3.5,<1.4.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libsqlite >=3.49.2,<4.0a0 + - libstdcxx >=13 + - libtheora >=1.1.1,<1.2.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libxml2 >=2.13.8,<2.14.0a0 + - libzlib >=1.3.1,<2.0a0 + - loguru + - lz4-c >=1.10.0,<1.11.0a0 + - matplotlib-base >=2.0.0 + - nlohmann_json + - numpy + - proj >=9.6.0,<9.7.0a0 + - pugixml >=1.15,<1.16.0a0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - qt6-main >=6.9.0,<6.10.0a0 + - tbb >=2021.13.0 + - utfcpp + - wslink + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 + constrains: + - paraview ==9999999999 + - libboost-headers >=1.86.0,<1.87.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/vtk?source=hash-mapping + size: 57450902 + timestamp: 1747922263624 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-base-9.4.2-py311h06be8d0_1.conda + sha256: 45fcd6ce969e5d1b34b93be36286d3c23a06e6fa4f80600c70340b00bd9e09dd + md5: 5a9b7185d8a421ebbecb2749d9803548 + depends: + - double-conversion >=3.3.1,<3.4.0a0 + - gl2ps >=1.4.2,<1.4.3.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - jsoncpp >=1.9.6,<1.9.7.0a0 + - libexpat >=2.7.0,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libgcc >=13 + - libglvnd >=1.7.0,<2.0a0 + - libglx >=1.7.0,<2.0a0 + - libjpeg-turbo >=3.1.0,<4.0a0 + - liblzma >=5.8.1,<6.0a0 + - libnetcdf >=4.9.2,<4.9.3.0a0 + - libogg >=1.3.5,<1.4.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libsqlite >=3.49.2,<4.0a0 + - libstdcxx >=13 + - libtheora >=1.1.1,<1.2.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libxml2 >=2.13.8,<2.14.0a0 + - libzlib >=1.3.1,<2.0a0 + - loguru + - lz4-c >=1.10.0,<1.11.0a0 + - matplotlib-base >=2.0.0 + - nlohmann_json + - numpy + - proj >=9.6.0,<9.7.0a0 + - pugixml >=1.15,<1.16.0a0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - qt6-main >=6.9.0,<6.10.0a0 + - tbb >=2021.13.0 + - utfcpp + - wslink + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 + constrains: + - paraview ==9999999999 + - libboost-headers >=1.86.0,<1.87.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/vtk?source=hash-mapping + size: 53026948 + timestamp: 1747924661502 +- conda: https://conda.anaconda.org/conda-forge/osx-64/vtk-base-9.4.2-py311h1f8269a_1.conda + sha256: 7ed156d9afcae13f54d4ebf604f76917bf11be4c9ed5d0040723d2adef0ebe59 + md5: 8dc0d8a4e5677d43479bf4fe47969e25 + depends: + - __osx >=11.0 + - double-conversion >=3.3.1,<3.4.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - jsoncpp >=1.9.6,<1.9.7.0a0 + - libcxx >=18 + - libexpat >=2.7.0,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libjpeg-turbo >=3.1.0,<4.0a0 + - liblzma >=5.8.1,<6.0a0 + - libnetcdf >=4.9.2,<4.9.3.0a0 + - libogg >=1.3.5,<1.4.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libsqlite >=3.49.2,<4.0a0 + - libtheora >=1.1.1,<1.2.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libxml2 >=2.13.8,<2.14.0a0 + - libzlib >=1.3.1,<2.0a0 + - loguru + - lz4-c >=1.10.0,<1.11.0a0 + - matplotlib-base >=2.0.0 + - nlohmann_json + - numpy + - proj >=9.6.0,<9.7.0a0 + - pugixml >=1.15,<1.16.0a0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - qt6-main >=6.9.0,<6.10.0a0 + - tbb >=2021.13.0 + - utfcpp + - wslink + constrains: + - paraview ==9999999999 + - libboost-headers >=1.86.0,<1.87.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/vtk?source=hash-mapping + size: 44088883 + timestamp: 1747923552011 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/vtk-base-9.4.2-py311h48cd792_1.conda + sha256: fd8433dde7f2030cc7b7e80f19710097b0c264bda5ee892cfad8e65dc9b4e7e6 + md5: 253230023cb3df1aefd28d101cc331bd + depends: + - __osx >=11.0 + - double-conversion >=3.3.1,<3.4.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - jsoncpp >=1.9.6,<1.9.7.0a0 + - libcxx >=18 + - libexpat >=2.7.0,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libjpeg-turbo >=3.1.0,<4.0a0 + - liblzma >=5.8.1,<6.0a0 + - libnetcdf >=4.9.2,<4.9.3.0a0 + - libogg >=1.3.5,<1.4.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libsqlite >=3.49.2,<4.0a0 + - libtheora >=1.1.1,<1.2.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libxml2 >=2.13.8,<2.14.0a0 + - libzlib >=1.3.1,<2.0a0 + - loguru + - lz4-c >=1.10.0,<1.11.0a0 + - matplotlib-base >=2.0.0 + - nlohmann_json + - numpy + - proj >=9.6.0,<9.7.0a0 + - pugixml >=1.15,<1.16.0a0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - qt6-main >=6.9.0,<6.10.0a0 + - tbb >=2021.13.0 + - utfcpp + - wslink + constrains: + - libboost-headers >=1.86.0,<1.87.0a0 + - paraview ==9999999999 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/vtk?source=hash-mapping + size: 42203426 + timestamp: 1747922992646 +- conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.4.2-h5554b43_1.conda + sha256: 55ef549c39d9fe33cfa70fb06c5693f0ed8d3cd3c0fd6dfb3538dd28b3bbd97d + md5: e696e8e95bd8c35d8c2a2e5159a8377e + depends: + - ffmpeg >=7.1.1,<8.0a0 + - python_abi 3.11.* *_cp311 + - vtk-base 9.4.2 py311hc26c8ec_1 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 90456 + timestamp: 1747922459755 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-io-ffmpeg-9.4.2-hc80fd1f_1.conda + sha256: 6286752d302b620a7f785924db3682d9fe3f2614066bc8e874f3bdccb9fb42a3 + md5: aab93e3640ecd255db6e0f56fee8f0ea + depends: + - ffmpeg >=7.1.1,<8.0a0 + - python_abi 3.11.* *_cp311 + - vtk-base 9.4.2 py311h06be8d0_1 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 90124 + timestamp: 1747924876940 +- conda: https://conda.anaconda.org/conda-forge/osx-64/vtk-io-ffmpeg-9.4.2-h0ddcc0c_1.conda + sha256: ce22e4d62055cdb2ce8da8dc6a6538f45576c01ff656f0677cdd5a1ddb90f425 + md5: 2a75404a4eedcd618c6aa074120d05c9 + depends: + - ffmpeg >=7.1.1,<8.0a0 + - python_abi 3.11.* *_cp311 + - vtk-base 9.4.2 py311h1f8269a_1 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 79153 + timestamp: 1747923713314 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/vtk-io-ffmpeg-9.4.2-h142d020_1.conda + sha256: 02bc1f8c06844c614aef6ab62b97160d739f5238b20fb94a0ea36306ca053cfb + md5: e72427890d724f624acb5d2a2dd790f6 + depends: + - ffmpeg >=7.1.1,<8.0a0 + - python_abi 3.11.* *_cp311 + - vtk-base 9.4.2 py311h48cd792_1 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 78960 + timestamp: 1747923134837 - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda sha256: ba673427dcd480cfa9bbc262fd04a9b1ad2ed59a159bd8f7e750d4c52282f34c md5: 0f2ca7906bf166247d1d760c3422cb8a @@ -49816,6 +51417,19 @@ packages: purls: [] size: 138011 timestamp: 1749836220507 +- conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.0-pyhd8ed1ab_0.conda + sha256: e9ac3caa3b17bed9bc301a67d3950f84fa37fb34002d2878c46cafb87978401d + md5: 8fa415e696acd9af59ce0a4425fd1b38 + depends: + - aiohttp <4 + - msgpack-python >=1,<2 + - python >=3.10 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/wslink?source=hash-mapping + size: 35839 + timestamp: 1760984848678 - conda: https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2 sha256: 175315eb3d6ea1f64a6ce470be00fa2ee59980108f246d3072ab8b977cb048a5 md5: 6c99772d483f566d59e25037fea2c4b1 @@ -51168,6 +52782,73 @@ packages: purls: [] size: 136222 timestamp: 1745308075886 +- conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.22.0-py311h3778330_0.conda + sha256: 6cddfbe838aab2d374a22f0c202f473a1d81c43e8fda25c5aa18fdcbc4f61679 + md5: c8213cef4057bc5a733d68d36e9b6366 + depends: + - __glibc >=2.17,<3.0.a0 + - idna >=2.0 + - libgcc >=14 + - multidict >=4.0 + - propcache >=0.2.1 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/yarl?source=hash-mapping + size: 152996 + timestamp: 1761337321513 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yarl-1.22.0-py311h164a683_0.conda + sha256: 50caf5593f0db7eabab68819c39d5f89dd4bade9b587d1c61f4551106f82e131 + md5: 6f83bfd8189962301680966c37aecd7e + depends: + - idna >=2.0 + - libgcc >=14 + - multidict >=4.0 + - propcache >=0.2.1 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/yarl?source=hash-mapping + size: 150887 + timestamp: 1761337088312 +- conda: https://conda.anaconda.org/conda-forge/osx-64/yarl-1.22.0-py311he13f9b5_0.conda + sha256: fa010bc1a5ea9b1b29298b580c906297a828c184e830d0d70a29959ddd705a7c + md5: 05b0b6020bb63e433b79f690a24502c9 + depends: + - __osx >=10.13 + - idna >=2.0 + - multidict >=4.0 + - propcache >=0.2.1 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/yarl?source=hash-mapping + size: 145231 + timestamp: 1761337113297 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.22.0-py311ha9b3269_0.conda + sha256: d3965276ec50b14787368baa662782c785a9af12cf150e60df7b33610611f4ec + md5: 05c7080043fb3c433a7d0c38a9617076 + depends: + - __osx >=11.0 + - idna >=2.0 + - multidict >=4.0 + - propcache >=0.2.1 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/yarl?source=hash-mapping + size: 144890 + timestamp: 1761337612760 - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h3b0a872_7.conda sha256: a4dc72c96848f764bb5a5176aa93dd1e9b9e52804137b99daeebba277b31ea10 md5: 3947a35e916fcc6b9825449affbf4214 diff --git a/pixi.toml b/pixi.toml index 4abc16fb..c51d2d4a 100644 --- a/pixi.toml +++ b/pixi.toml @@ -162,9 +162,15 @@ ros-humble-rviz2 = { channel = "robostack-humble" } ros-humble-rviz-default-plugins = { channel = "robostack-humble" } ros-humble-xacro = { channel = "robostack-humble" } -# note: we can only depend on `video4linux`... on Linux. lol +# required by LiDAR +ros-humble-pcl-conversions = { channel = "robostack-humble" } +pcl = { channel = "conda-forge" } + [target.linux.dependencies] +# note: we can only depend on `video4linux`... on Linux. lol ros-humble-v4l2-camera = { channel = "robostack-humble" } +# and yea this only runs on linux for one reason or another +ros-humble-spatio-temporal-voxel-layer = { channel = "robostack-humble" } [pypi-dependencies] colcon-ros-cargo = ">=0.2.0" diff --git a/src/soro_lidar/CMakeLists.txt b/src/soro_lidar/CMakeLists.txt new file mode 100644 index 00000000..b88ef5eb --- /dev/null +++ b/src/soro_lidar/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 3.5) +project(soro_lidar) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +find_package(ament_cmake REQUIRED) +find_package(rclcpp REQUIRED) +find_package(std_msgs REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(pcl_conversions REQUIRED) +find_package(PCL REQUIRED) +find_package(tf2_ros REQUIRED) +find_package(sensor_msgs REQUIRED) + +include_directories( + ${PCL_INCLUDE_DIRS} + include +) + +link_directories( + ${PCL_LIBRARY_DIRS} + lib/${CMAKE_SYSTEM_PROCESSOR} + # ../../../unitree_lidar_sdk/lib/${CMAKE_SYSTEM_PROCESSOR} +) + +add_definitions(${PCL_DEFINITIONS}) + +add_executable(unitree_lidar_ros2_node src/unitree_lidar_ros2_node.cpp) + +target_link_libraries( unitree_lidar_ros2_node + ${Boost_SYSTEM_LIBRARY} + ${PCL_LIBRARIES} + libunitree_lidar_sdk.a +) + +ament_target_dependencies( + unitree_lidar_ros2_node + rclcpp std_msgs + sensor_msgs + geometry_msgs + tf2_ros + pcl_conversions +) + +install(TARGETS +unitree_lidar_ros2_node + DESTINATION lib/${PROJECT_NAME} +) + +# install rviz file and launch file +install(FILES rviz/view.rviz launch/launch.py + DESTINATION share/${PROJECT_NAME} +) + +ament_package() diff --git a/src/soro_lidar/include/unitree_lidar_protocol.h b/src/soro_lidar/include/unitree_lidar_protocol.h new file mode 100644 index 00000000..9b8c704a --- /dev/null +++ b/src/soro_lidar/include/unitree_lidar_protocol.h @@ -0,0 +1,415 @@ +/********************************************************************** + Copyright (c) 2020-2024, Unitree Robotics.Co.Ltd. All rights reserved. +***********************************************************************/ + +#ifndef UNITREE_LIDAR_PROTOCOL_HEADER +#define UNITREE_LIDAR_PROTOCOL_HEADER + +#include +#include +#include + +#ifndef __EXTERN_C__ +namespace unitree_lidar_sdk{ +#endif + +/////////////////////////////////////////////////////////////////////////////// +// MACRO DEFINITION +/////////////////////////////////////////////////////////////////////////////// + +#define FRAME_HEADER_ARRAY_0 0x55 +#define FRAME_HEADER_ARRAY_1 0xAA +#define FRAME_HEADER_ARRAY_2 0x05 +#define FRAME_HEADER_ARRAY_3 0x0A + +#define FRAME_TAIL_ARRAY_0 0x00 +#define FRAME_TAIL_ARRAY_1 0xFF + +#define LIDAR_USER_CMD_PACKET_TYPE 100 +#define LIDAR_ACK_DATA_PACKET_TYPE 101 +#define LIDAR_POINT_DATA_PACKET_TYPE 102 +#define LIDAR_2D_POINT_DATA_PACKET_TYPE 103 +#define LIDAR_IMU_DATA_PACKET_TYPE 104 +#define LIDAR_VERSION_PACKET_TYPE 105 +#define LIDAR_TIME_STAMP_PACKET_TYPE 106 +#define LIDAR_WORK_MODE_CONFIG_PACKET_TYPE 107 +#define LIDAR_IP_ADDRESS_CONFIG_PACKET_TYPE 108 +#define LIDAR_MAC_ADDRESS_CONFIG_PACKET_TYPE 109 + +#define LIDAR_COMMAND_PACKET_TYPE 2000 +#define LIDAR_PARAM_DATA_PACKET_TYPE 2001 + +#define CMD_RESET_TYPE 1 +#define CMD_PARAM_SAVE 2 +#define CMD_PARAM_GET 3 +#define CMD_VERSION_GET 4 +#define CMD_STANDBY_TYPE 5 +#define CMD_LATENCY_TYPE 6 +#define CMD_CONFIG_RESET 7 + +#define USER_CMD_RESET_TYPE 1 +#define USER_CMD_STANDBY_TYPE 2 // value 0: start; value 1: standby +#define USER_CMD_VERSION_GET 3 +#define USER_CMD_LATENCY_TYPE 4 +#define USER_CMD_CONFIG_RESET 5 +#define USER_CMD_CONFIG_GET 6 + +#define ACK_SUCCESS 1 +#define ACK_CRC_ERROR 2 +#define ACK_HEADER_ERROR 3 +#define ACK_BLOCK_ERROR 4 +#define ACK_WAIT_ERROR 5 // data is not ready + +/////////////////////////////////////////////////////////////////////////////// +// FRAME HEADER & FRAME TAIL +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Frame Header + * @note 12 bytes + */ +typedef struct +{ + uint8_t header[4]; // Head: 0x55 0xAA 0x05 0x0A + uint32_t packet_type; // packet type + uint32_t packet_size; // packet size - total bytes of the whole packet +}FrameHeader; + +/** + * @brief Frame Tail + * @note 12 bytes + */ +typedef struct +{ + uint32_t crc32; // crc check of head and data + uint32_t msg_type_check; // msg ack for lidar + uint8_t reserve[2]; // reserve + uint8_t tail[2]; // Tail: 0x00 0xFF +}FrameTail; + +/////////////////////////////////////////////////////////////////////////////// +// TIMESTAMP & DATA INFO +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Time stamp + * @note 8 bytes + */ +typedef struct +{ + uint32_t sec; // time stamp of second + uint32_t nsec; // time stamp of nsecond +}TimeStamp; + +/** + * @brief Data Info + * @note 16 bytes + */ +typedef struct +{ + uint32_t seq; // packet sequence id, consecutively increasing + uint32_t payload_size; // Packet Size + TimeStamp stamp; // timestamp +}DataInfo; + +/** + * @brief Lidar calib param + */ +typedef struct +{ + float a_axis_dist; // unit: m + float b_axis_dist; // unit: m + float theta_angle_bias; // unit: rad + float alpha_angle_bias; // unit: rad + float beta_angle; // unit: rad + float xi_angle; // unit: rad + float range_bias; // unit: mm + float range_scale; // unit: 1 +}LidarCalibParam; + +/** + * @brief Lidar Inside State + */ +typedef struct +{ + uint32_t sys_rotation_period; // Up motor rotation period + uint32_t com_rotation_period; // Down motor rotation period + float dirty_index; + float packet_lost_up; + float packet_lost_down; + float apd_temperature; + float apd_voltage; + float laser_voltage; + float imu_temperature; +}LidarInsideState; + +/////////////////////////////////////////////////////////////////////////////// +// LIDAR POINT DATA PACKET +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar Point Data + * @note 1012 bytes + */ +typedef struct +{ + // Packet Info + DataInfo info; + + // Lidar inside state + LidarInsideState state; + + // Lidar calib param + LidarCalibParam param; + + // Line info + float com_horizontal_angle_start; // Horizontal Start Angle + float com_horizontal_angle_step; // Horizontal Angle Step + float scan_period; // Scan period [second] + float range_min; // Minimum range value [m] + float range_max; // Maximum range value [m] + float angle_min; // First Angle [rad] + float angle_increment; // Angle Step [rad] + float time_increment; // Time step [second] + uint32_t point_num; // Point Number + uint16_t ranges[300]; // Point Distance [mm] + uint8_t intensities[300]; // Point Reflect [0-255] +}LidarPointData; + +/** + * @brief Lidar Point Data Packet + * @note 1036 bytes + */ +typedef struct +{ + FrameHeader header; + LidarPointData data; + FrameTail tail; +}LidarPointDataPacket; + +/////////////////////////////////////////////////////////////////////////////// +// LIDAR 2D POINT DATA PACKET +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar 2D Point Data + * @note 5504 bytes + */ +typedef struct +{ + // Packet Info + DataInfo info; + + // Lidar inside state + LidarInsideState state; + + // Lidar calib param + LidarCalibParam param; + + // Line info + float scan_period; // scan period [second] + float range_min; // minimum range value [m] + float range_max; // maximum range value [m] + float angle_min; // First Angle [rad] + float angle_increment; // Angle Step [rad] + float time_increment; // point time step + uint32_t point_num; // Point Number + uint16_t ranges[1800]; // Point Distance Data + uint8_t intensities[1800]; // Point Reflect Data +}Lidar2DPointData; + +/** + * @brief Lidar Point Data Packet + * @note 5528 bytes + */ +typedef struct +{ + FrameHeader header; + Lidar2DPointData data; + FrameTail tail; +}Lidar2DPointDataPacket; + + +/////////////////////////////////////////////////////////////////////////////// +// TIME STAMP PACKET +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar Time Stamp Packet + * @note 32 bytes + */ +typedef struct +{ + FrameHeader header; + TimeStamp data; + FrameTail tail; +}LidarTimeStampPacket; + +/////////////////////////////////////////////////////////////////////////////// +// IMU DATA PACKET +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar IMU Data + * @note 132 bytes + */ +typedef struct +{ + DataInfo info; + float quaternion[4]; // Quaternion Array. + float angular_velocity[3]; // Three-axis angular velocity values. + float linear_acceleration[3]; // Three-axis acceleration values. +}LidarImuData; + +/** + * @brief Lidar IMU Data Packet + * @note 156 bytes + */ +typedef struct +{ + FrameHeader header; + LidarImuData data; + FrameTail tail; +}LidarImuDataPacket; + +/////////////////////////////////////////////////////////////////////////////// +// ACK PACKET +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief ACK + * @note Lidar will respond with an ack packet if it receive a packet from user + * @note 16 bytes + */ +typedef struct +{ + uint32_t packet_type; // packet type received by lidar + uint32_t cmd_type; // cmd type received by lidar + uint32_t cmd_value; // cmd value received by lidar + uint32_t status; // execute result +}LidarAckData; + +/** + * @brief ACK command Packet + * @note 40 bytes + */ +typedef struct +{ + FrameHeader header; + LidarAckData data; + FrameTail tail; +}LidarAckDataPacket; + +/////////////////////////////////////////////////////////////////////////////// +// LIDAR VERSION PACKET +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar version + * @note 80 bytes +*/ +typedef struct +{ + uint8_t hw_version[4]; // hardware version + uint8_t sw_version[4]; // software version + uint8_t name[24]; // device name + uint8_t date[8]; // device compile date + uint8_t reserve[40]; +}LidarVersionData; + +/** + * @brief Lidar version + * @note 104 bytes +*/ +typedef struct +{ + FrameHeader header; + LidarVersionData data; + FrameTail tail; +}LidarVersionDataPacket; + +///////////////////////////////////////////////////////////////////////// +// IP CONFIG PACKET +///////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar IP Config + * @note 16 bytes + */ +typedef struct +{ + uint8_t lidar_ip[4]; // UDP local ip + uint8_t user_ip[4]; // UDP remote ip + uint16_t lidar_port; // UDP local port + uint16_t user_port; // UDP remote port +}LidarIpAddressConfig; + +/** + * @brief Lidar IP config packet + * @note 40 bytes + */ +typedef struct +{ + FrameHeader header; + LidarIpAddressConfig data; + FrameTail tail; +}LidarIpAddressConfigPacket; + + +///////////////////////////////////////////////////////////////////////// +// WORK MODE PACKET +///////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar Work Mode +* @note 4 bytes +*/ +typedef struct +{ + uint32_t mode; +}LidarWorkModeConfig; + +/** + * @brief Lidar Work Mode Packet +* @note 28 bytes +*/ +typedef struct +{ + FrameHeader header; + LidarWorkModeConfig data; + FrameTail tail; +}LidarWorkModeConfigPacket; + +///////////////////////////////////////////////////////////////////////// +// USER CONTROL COMMAND PACKET +///////////////////////////////////////////////////////////////////////// + +/** + * @brief Lidar User Control Command + * @note 8 bytes + */ +typedef struct +{ + uint32_t cmd_type; // 0:null, 1:standby + uint32_t cmd_value; +}LidarUserCtrlCmd; + +/** + * @brief Lidar User Control Command Packet + * @note 32 bytes + */ +typedef struct +{ + FrameHeader header; + LidarUserCtrlCmd data; + FrameTail tail; +}LidarUserCtrlCmdPacket; + + + +#ifndef __EXTERN_C__ +} +#endif + +#endif + diff --git a/src/soro_lidar/include/unitree_lidar_ros2.h b/src/soro_lidar/include/unitree_lidar_ros2.h new file mode 100644 index 00000000..cabcab9c --- /dev/null +++ b/src/soro_lidar/include/unitree_lidar_ros2.h @@ -0,0 +1,251 @@ +/********************************************************************** + Copyright (c) 2020-2024, Unitree Robotics.Co.Ltd. All rights reserved. +***********************************************************************/ + +#pragma once + +#define BOOST_BIND_NO_PLACEHOLDERS + +#include "geometry_msgs/msg/transform_stamped.hpp" +#include "iostream" +#include "rclcpp/rclcpp.hpp" +#include "rclcpp/time.hpp" +#include "sensor_msgs/msg/imu.hpp" +#include "sensor_msgs/msg/point_cloud2.hpp" +#include "std_msgs/msg/header.hpp" +#include "tf2/LinearMath/Quaternion.h" +#include "tf2_ros/transform_broadcaster.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// SDK +#include "unitree_lidar_sdk_pcl.h" + +using std::placeholders::_1; + +class UnitreeLidarSDKNode: public rclcpp::Node { + public: + explicit UnitreeLidarSDKNode( + const rclcpp::NodeOptions& options = rclcpp::NodeOptions() + ); + + ~UnitreeLidarSDKNode() {}; + + void timer_callback(); + + protected: + // ROS + rclcpp::Publisher::SharedPtr pub_cloud_; + rclcpp::Publisher::SharedPtr pub_imu_; + rclcpp::TimerBase::SharedPtr timer_; + std::shared_ptr broadcaster_; + + // Unitree Lidar Reader + UnitreeLidarReader* lsdk_; + + // Config params + int work_mode_; + int initialize_type_; + int local_port_; + std::string local_ip_; + int lidar_port_; + std::string lidar_ip_; + std::string serial_port_; + int baudrate_; + + int cloud_scan_num_; + bool use_system_timestamp_; + double range_min_; + double range_max_; + + std::string cloud_frame_; + std::string cloud_topic_; + + std::string imu_frame_; + std::string imu_topic_; +}; + +/////////////////////////////////////////////////////////////////// + +UnitreeLidarSDKNode::UnitreeLidarSDKNode(const rclcpp::NodeOptions& options) : + Node("unitre_lidar_sdk_node", options) { + // load config parameters + declare_parameter("initialize_type", 2); + declare_parameter("work_mode", 0); + declare_parameter("use_system_timestamp", true); + declare_parameter("range_min", 0); + declare_parameter("range_max", 50); + declare_parameter("cloud_scan_num", 18); + + declare_parameter("serial_port", "/dev/ttyACM0"); + declare_parameter("baudrate", 4000000); + + declare_parameter("lidar_port", 6101); + declare_parameter("lidar_ip", "192.168.1.2"); + declare_parameter("local_port", 6201); + declare_parameter("local_ip", "192.168.1.62"); + + declare_parameter("cloud_frame", "unilidar_lidar"); + declare_parameter("cloud_topic", "unilidar/cloud"); + + declare_parameter("imu_frame", "unilidar_imu"); + declare_parameter("imu_topic", "unilidar/imu"); + + work_mode_ = get_parameter("work_mode").as_int(); + initialize_type_ = get_parameter("initialize_type").as_int(); + + serial_port_ = get_parameter("serial_port").as_string(); + baudrate_ = get_parameter("baudrate").as_int(); + + lidar_port_ = get_parameter("lidar_port").as_int(); + lidar_ip_ = get_parameter("lidar_ip").as_string(); + local_port_ = get_parameter("local_port").as_int(); + local_ip_ = get_parameter("local_ip").as_string(); + + cloud_scan_num_ = get_parameter("cloud_scan_num").as_int(); + use_system_timestamp_ = get_parameter("use_system_timestamp").as_bool(); + range_max_ = get_parameter("range_max").as_double(); + range_min_ = get_parameter("range_min").as_double(); + + cloud_frame_ = get_parameter("cloud_frame").as_string(); + cloud_topic_ = get_parameter("cloud_topic").as_string(); + + imu_frame_ = get_parameter("imu_frame").as_string(); + imu_topic_ = get_parameter("imu_topic").as_string(); + + // Initialize UnitreeLidarReader + lsdk_ = createUnitreeLidarReader(); + + std::cout << "initialize_type_ = " << initialize_type_ << std::endl; + + if (initialize_type_ == 1) { + lsdk_->initializeSerial( + serial_port_, + baudrate_, + cloud_scan_num_, + use_system_timestamp_, + range_min_, + range_max_ + ); + } else if (initialize_type_ == 2) { + lsdk_->initializeUDP( + lidar_port_, + lidar_ip_, + local_port_, + local_ip_, + cloud_scan_num_, + use_system_timestamp_, + range_min_, + range_max_ + ); + } else { + std::cout << "initialize_type is not right! exit now ...\n"; + exit(0); + } + + lsdk_->setLidarWorkMode(work_mode_); + + // ROS2 + broadcaster_ = std::make_shared(*this); + pub_cloud_ = + this->create_publisher(cloud_topic_, 10); + pub_imu_ = this->create_publisher(imu_topic_, 10); + timer_ = this->create_wall_timer( + std::chrono::milliseconds(1), + std::bind(&UnitreeLidarSDKNode::timer_callback, this) + ); +} + +void UnitreeLidarSDKNode::timer_callback() { + int result = lsdk_->runParse(); + static pcl::PointCloud::Ptr cloudOut( + new pcl::PointCloud() + ); + + // RCLCPP_INFO(this->get_logger(), "result = %d", result); + + if (result == LIDAR_IMU_DATA_PACKET_TYPE) { + LidarImuData imu; + lsdk_->getImuData(imu); + + if (lsdk_->getImuData(imu)) { + // publish imu message + rclcpp::Time timestamp(imu.info.stamp.sec, imu.info.stamp.nsec); + + sensor_msgs::msg::Imu imuMsg; + imuMsg.header.frame_id = imu_frame_; + imuMsg.header.stamp = timestamp; + + imuMsg.orientation.x = imu.quaternion[0]; + imuMsg.orientation.y = imu.quaternion[1]; + imuMsg.orientation.z = imu.quaternion[2]; + imuMsg.orientation.w = imu.quaternion[3]; + + imuMsg.angular_velocity.x = imu.angular_velocity[0]; + imuMsg.angular_velocity.y = imu.angular_velocity[1]; + imuMsg.angular_velocity.z = imu.angular_velocity[2]; + + imuMsg.linear_acceleration.x = imu.linear_acceleration[0]; + imuMsg.linear_acceleration.y = imu.linear_acceleration[1]; + imuMsg.linear_acceleration.z = imu.linear_acceleration[2]; + + pub_imu_->publish(imuMsg); + + // publish tf from initial imu to real-time imu + geometry_msgs::msg::TransformStamped transformStamped; + transformStamped.header.stamp = this->now(); // 使用当前时间 + transformStamped.header.frame_id = + imu_frame_ + "_initial"; // 父坐标系 + transformStamped.child_frame_id = imu_frame_; // 子坐标系 + transformStamped.transform.translation.x = 0; + transformStamped.transform.translation.y = 0; + transformStamped.transform.translation.z = 0; + transformStamped.transform.rotation.x = imu.quaternion[1]; + transformStamped.transform.rotation.y = imu.quaternion[2]; + transformStamped.transform.rotation.z = imu.quaternion[3]; + transformStamped.transform.rotation.w = imu.quaternion[0]; + broadcaster_->sendTransform(transformStamped); + + // publish tf from imu to lidar + transformStamped.header.frame_id = imu_frame_; // 父坐标系 + transformStamped.child_frame_id = cloud_frame_; // 子坐标系 + transformStamped.transform.translation.x = 0.007698; + transformStamped.transform.translation.y = 0.014655; + transformStamped.transform.translation.z = -0.00667; + transformStamped.transform.rotation.x = 0; + transformStamped.transform.rotation.y = 0; + transformStamped.transform.rotation.z = 0; + transformStamped.transform.rotation.w = 1; + broadcaster_->sendTransform(transformStamped); + } + } else if (result == LIDAR_POINT_DATA_PACKET_TYPE) { + // RCLCPP_INFO(this->get_logger(), "POINT_CLOUD"); + PointCloudUnitree cloud; + if (lsdk_->getPointCloud(cloud)) { + transformUnitreeCloudToPCL(cloud, cloudOut); + + rclcpp::Time timestamp( + static_cast(cloud.stamp), + static_cast( + (cloud.stamp - static_cast(cloud.stamp)) * 1e9 + ) + ); + + sensor_msgs::msg::PointCloud2 cloud_msg; + pcl::toROSMsg(*cloudOut, cloud_msg); + cloud_msg.header.frame_id = cloud_frame_; + cloud_msg.header.stamp = timestamp; + + pub_cloud_->publish(cloud_msg); + } + } +} diff --git a/src/soro_lidar/include/unitree_lidar_sdk.h b/src/soro_lidar/include/unitree_lidar_sdk.h new file mode 100644 index 00000000..a0fe31db --- /dev/null +++ b/src/soro_lidar/include/unitree_lidar_sdk.h @@ -0,0 +1,145 @@ +/********************************************************************** + Copyright (c) 2020-2024, Unitree Robotics.Co.Ltd. All rights reserved. +***********************************************************************/ + +#pragma once +#include "unitree_lidar_utilities.h" + +namespace unitree_lidar_sdk{ + +/** + * @brief Unitree Lidar Reader + */ +class UnitreeLidarReader +{ + +public: + /** + * @brief Initialize + * @return Return 0 if the serial port is opened successfully; + * return -1 if we failed to open the serial port. + */ + virtual int initializeSerial( + std::string port = "/dev/ttyACM0", + uint32_t baudrate = 4000000, + uint16_t cloud_scan_num = 18, + bool use_system_timestamp = true, + float range_min = 0, + float range_max = 100 + ) = 0; + + /** + * @brief Initialize for UDP board + */ + virtual int initializeUDP( + unsigned short lidar_port = 6101, + std::string lidar_ip = "192.168.1.62", + unsigned short local_port = 6201, + std::string local_ip = "192.168.1.2", + uint16_t cloud_scan_num = 18, + bool use_system_timestamp = true, + float range_min = 0, + float range_max = 100 + ) = 0; + + /** + * @brief Close Serial connection + */ + virtual bool closeSerial() = 0; + + /** + * @brief Close UDP connection + */ + virtual bool closeUDP() = 0; + + /** + * @brief Try to parse a message from the serial buffer once. + * @note This is the main entrance of this class + * @return the data packet type id, eg. + * 0 if no valid message parsed + * LIDAR_POINT_DATA_PACKET_TYPE 102 + * LIDAR_2D_POINT_DATA_PACKET_TYPE 103 + * LIDAR_IMU_DATA_PACKET_TYPE 104 + * LIDAR_VERSION_PACKET_TYPE 105 + */ + virtual int runParse() = 0; + + /** + * @brief Clear buffer + */ + virtual void clearBuffer() = 0; + + virtual const LidarPointDataPacket &getLidarPointDataPacket() const = 0; + + virtual const Lidar2DPointDataPacket &getLidar2DPointDataPacket() const = 0; + + virtual const LidarImuDataPacket &getLidarImuDataPacket() const = 0; + + virtual const LidarVersionDataPacket &getLidarVersionDataPacket() const = 0; + + /** + * @brief Get parsed point cloud data + */ + virtual bool getPointCloud(PointCloudUnitree &cloud) const = 0; + + /** + * @brief Get IMU data + */ + virtual bool getImuData(LidarImuData &imu) const = 0; + + /** + * @brief Get the Version of Lidar SDK + */ + virtual bool getVersionOfSDK(std::string &version) const = 0; + + /** + * @brief Get Version of lidar firmware + */ + virtual bool getVersionOfLidarFirmware(std::string &version) const = 0; + + /** + * @brief Get Version of lidar hardware + */ + virtual bool getVersionOfLidarHardware(std::string &version) const = 0; + + /** + * @brief Get time delay of one-way data transmission in second. + */ + virtual bool getTimeDelay(double &delay) const = 0; + + /** + * @brief Get the removal percentage of points due to the dirt on the protection cover + * @return the percentage of removed dirty points + */ + virtual bool getDirtyPercentage(float &percentage) const = 0; + + /** + * @brief Set lidar work mode + */ + virtual void setLidarWorkMode(uint32_t mode) = 0; + + /** + * @brief Sync lidar timestamp with system timestamp + * @param stamp_sec second + * @param stamp_nsec nanosecond + */ + virtual void syncLidarTimeStamp() = 0; + + /** + * @brief Stop lidar rotation + */ + virtual void stopLidarRotation() = 0; + + /** + * @brief Start lidar rotation + */ + virtual void startLidarRotation() = 0; +}; + +/** + * @brief Create a Unitree Lidar Reader object + * @return UnitreeLidarReader* + */ +UnitreeLidarReader *createUnitreeLidarReader(); + +} // end of namespace unitree_lidar_sdk \ No newline at end of file diff --git a/src/soro_lidar/include/unitree_lidar_sdk_config.h b/src/soro_lidar/include/unitree_lidar_sdk_config.h new file mode 100644 index 00000000..b5416cda --- /dev/null +++ b/src/soro_lidar/include/unitree_lidar_sdk_config.h @@ -0,0 +1,4 @@ +#define unitree_lidar_sdk_VERSION "2.0.4" +#define unitree_lidar_sdk_VERSION_MAJOR 2 +#define unitree_lidar_sdk_VERSION_MINOR 0 +#define unitree_lidar_sdk_VERSION_PATCH 4 diff --git a/src/soro_lidar/include/unitree_lidar_sdk_pcl.h b/src/soro_lidar/include/unitree_lidar_sdk_pcl.h new file mode 100644 index 00000000..5b74397d --- /dev/null +++ b/src/soro_lidar/include/unitree_lidar_sdk_pcl.h @@ -0,0 +1,83 @@ +/********************************************************************** + Copyright (c) 2020-2024, Unitree Robotics.Co.Ltd. All rights reserved. +***********************************************************************/ + +#pragma once + +#ifndef PCL_NO_PRECOMPILE +#define PCL_NO_PRECOMPILE +#endif + +// PCL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Eigen +#include +#include + +#include "unitree_lidar_sdk.h" + +using namespace unitree_lidar_sdk; + +/** + * @brief PCL Point Type + */ +struct EIGEN_ALIGN16 PointType { + PCL_ADD_POINT4D; + PCL_ADD_INTENSITY; + std::uint16_t ring; + float time; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + }; +POINT_CLOUD_REGISTER_POINT_STRUCT(PointType, + (float, x, x)(float, y, y)(float, z, z)(float, intensity, intensity)(std::uint16_t, ring, ring)(float, time, time)) + +PCL_INSTANTIATE(VoxelGrid, PointType) +PCL_INSTANTIATE(KdTree, PointType) +PCL_INSTANTIATE(RadiusOutlierRemoval, PointType) + +/** + * @brief Transform a Unitree cloud to PCL cloud + * + * @param cloudIn + * @param cloudOut + */ +void transformUnitreeCloudToPCL(const PointCloudUnitree &cloudIn, pcl::PointCloud::Ptr cloudOut) +{ + cloudOut->clear(); + PointType pt; + for (size_t i = 0; i < cloudIn.points.size(); i++) + { + pt.x = cloudIn.points[i].x; + pt.y = cloudIn.points[i].y; + pt.z = cloudIn.points[i].z; + pt.intensity = cloudIn.points[i].intensity; + pt.time = cloudIn.points[i].time; + pt.ring = cloudIn.points[i].ring; + cloudOut->push_back(pt); + } +} \ No newline at end of file diff --git a/src/soro_lidar/include/unitree_lidar_utilities.h b/src/soro_lidar/include/unitree_lidar_utilities.h new file mode 100644 index 00000000..c5f82f06 --- /dev/null +++ b/src/soro_lidar/include/unitree_lidar_utilities.h @@ -0,0 +1,307 @@ +/********************************************************************** + Copyright (c) 2020-2024, Unitree Robotics.Co.Ltd. All rights reserved. +***********************************************************************/ + +#pragma once + +#if defined(_WIN32) && !defined(__MINGW32__) +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; // NOLINT +typedef unsigned short uint16_t; // NOLINT +typedef int int32_t; +typedef unsigned int uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +// intptr_t and friends are defined in crtdefs.h through stdio.h. +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "unitree_lidar_sdk_config.h" +#include "unitree_lidar_protocol.h" + +namespace unitree_lidar_sdk{ + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS +/////////////////////////////////////////////////////////////////////////////// +const float DEGREE_TO_RADIAN = M_PI / 180.0; +const float RADIAN_TO_DEGREE = 180.0 / M_PI; + +/////////////////////////////////////////////////////////////////////////////// +// TYPES +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Point Type + */ +typedef struct +{ + float x; + float y; + float z; + float intensity; + float time; // relative time of this point from cloud stamp + uint32_t ring; // ring +} PointUnitree; + +/** + * @brief Point Cloud Type + */ +typedef struct +{ + double stamp; // cloud start timestamp, the point timestamp is relative to this + uint32_t id; // sequence id + uint32_t ringNum; // number of rings + std::vector points; +} PointCloudUnitree; + +/////////////////////////////////////////////////////////////////////////////// +// FUNCTIONS +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Get system timestamp + */ +inline void getSystemTimeStamp(TimeStamp ×tamp) +{ + struct timespec time1 = {0, 0}; + clock_gettime(CLOCK_REALTIME, &time1); + timestamp.sec = time1.tv_sec; + timestamp.nsec = time1.tv_nsec; +} + +/** + * @brief Get system timestamp + */ +inline double getSystemTimeStamp() +{ + struct timespec time1 = {0, 0}; + clock_gettime(CLOCK_REALTIME, &time1); + return time1.tv_sec + time1.tv_nsec / 1.0e9; +} + +/** + * @brief crc32 check + * @param buf + * @param len + * @return uint32_t + */ +inline uint32_t crc32(const uint8_t *buf, uint32_t len) +{ + uint8_t i; + uint32_t crc = 0xFFFFFFFF; + while (len--) + { + crc ^= *buf++; + for (i = 0; i < 8; ++i) + { + if (crc & 1) + crc = (crc >> 1) ^ 0xEDB88320; + else + crc = (crc >> 1); + } + } + return ~crc; +} + +/** + * @brief Parse from a point packet to a 3D point cloud + * @param[out] cloud + * @param[in] packet lidar point data packet + * @param[in] use_system_timestamp use system timestamp, otherwise use lidar hardware timestamp + * @param[in] range_min allowed minimum point range in meters + * @param[in] range_max allowed maximum point range in meters + */ +inline void parseFromPacketToPointCloud( + PointCloudUnitree &cloud, + const LidarPointDataPacket &packet, + bool use_system_timestamp = true, + float range_min = 0, + float range_max = 100) +{ + // scan info + const int num_of_points = packet.data.point_num; + const float time_step = packet.data.time_increment; + const float scan_period = packet.data.scan_period; + + // intermediate variables + const float sin_beta = sin(packet.data.param.beta_angle); + const float cos_beta = cos(packet.data.param.beta_angle); + const float sin_xi = sin(packet.data.param.xi_angle); + const float cos_xi = cos(packet.data.param.xi_angle); + const float cos_beta_sin_xi = cos_beta * sin_xi; + const float sin_beta_cos_xi = sin_beta * cos_xi; + const float sin_beta_sin_xi = sin_beta * sin_xi; + const float cos_beta_cos_xi = cos_beta * cos_xi; + + // cloud init + if (use_system_timestamp) + { + cloud.stamp = getSystemTimeStamp() - scan_period; + }else{ + cloud.stamp = packet.data.info.stamp.sec + packet.data.info.stamp.nsec / 1.0e9; + } + cloud.id = 1; + cloud.ringNum = 1; + cloud.points.clear(); + cloud.points.reserve(300); + + // transform raw data to a pointcloud + auto &ranges = packet.data.ranges; + auto &intensities = packet.data.intensities; + + float time_relative = 0; + float alpha_cur = packet.data.angle_min + packet.data.param.alpha_angle_bias; + float alpha_step = packet.data.angle_increment; + float theta_cur = packet.data.com_horizontal_angle_start + packet.data.param.theta_angle_bias; + float theta_step = packet.data.com_horizontal_angle_step; + + float range_float; + float sin_alpha, cos_alpha, sin_theta, cos_theta; + float A, B, C; + + PointUnitree point3d; + point3d.ring = 1; + // std::cout << "packet.data.param.range_scale = " << packet.data.param.range_scale << std::endl; + + for (int j = 0; j < num_of_points; j += 1, alpha_cur += alpha_step, + theta_cur += theta_step, time_relative += time_step) + { + // jump invalid points + if (ranges[j] < 1) + { + continue; + } + + // calculate point range in float type + range_float = packet.data.param.range_scale * ((float)ranges[j] + packet.data.param.range_bias); + + // jump points beyond range limit + if ( range_float < packet.data.range_min || range_float > packet.data.range_max) + { + continue; + } + + // jump points beyond range limit + if (range_float < range_min || range_float > range_max) + { + continue; + } + + // transform to XYZ coordinate + sin_alpha = sin(alpha_cur); + cos_alpha = cos(alpha_cur); + sin_theta = sin(theta_cur); + cos_theta = cos(theta_cur); + + A = (-cos_beta_sin_xi + sin_beta_cos_xi * sin_alpha) * range_float + packet.data.param.b_axis_dist; + B = cos_alpha * cos_xi * range_float; + C = (sin_beta_sin_xi + cos_beta_cos_xi * sin_alpha) * range_float; + + point3d.x = cos_theta * A - sin_theta * B; + point3d.y = sin_theta * A + cos_theta * B; + point3d.z = C + packet.data.param.a_axis_dist; + + // push back this point to cloud + point3d.intensity = intensities[j]; + point3d.time = time_relative; + cloud.points.push_back(point3d); + } +} + +/** + * @brief Parse from a packet to a 2D LaserScan + * @param[out] cloud + * @param[in] packet lidar point data packet + * @param[in] use_system_timestamp use system timestamp, otherwise use lidar hardware timestamp + * @param[in] range_min allowed minimum point range in meters + * @param[in] range_max allowed maximum point range in meters + */ +inline void parseFromPacketPointCloud2D( + PointCloudUnitree &cloud, + const Lidar2DPointDataPacket &packet, + bool use_system_timestamp = true, + float range_min = 0, + float range_max = 100) +{ + // scan info + const int num_of_points = packet.data.point_num; + const float time_step = packet.data.time_increment; + const float scan_period = packet.data.scan_period; + + // cloud init + if (use_system_timestamp) + { + cloud.stamp = getSystemTimeStamp() - scan_period; + }else{ + cloud.stamp = packet.data.info.stamp.sec + packet.data.info.stamp.nsec / 1.0e9; + } + cloud.id = 1; + cloud.ringNum = 1; + cloud.points.clear(); + cloud.points.reserve(300); + + // transform raw data to a pointcloud + auto &ranges = packet.data.ranges; + auto &intensities = packet.data.intensities; + + float time_relative = 0; + float alpha_cur = packet.data.angle_min + packet.data.param.alpha_angle_bias; + float alpha_step = packet.data.angle_increment; + + float range_float; + float sin_alpha, cos_alpha; + + PointUnitree point3d; + point3d.ring = 1; + + for (int j = 0; j < num_of_points; j += 1, alpha_cur += alpha_step, time_relative += time_step) + { + // jump invalid points + if (ranges[j] < 1) + { + continue; + } + + // calculate point range in float type + range_float = packet.data.param.range_scale * (ranges[j] + packet.data.param.range_bias); + + // jump points beyond range limit + if (range_float < packet.data.range_min || range_float > packet.data.range_max) + { + continue; + } + + // jump points beyond range limit + if (range_float < range_min || range_float > range_max) + { + continue; + } + + // transform to XYZ coordinate + sin_alpha = sin(alpha_cur); + cos_alpha = cos(alpha_cur); + point3d.x = 0; + point3d.y = cos_alpha * range_float; + point3d.z = sin_alpha * range_float + packet.data.param.a_axis_dist; + + // push back this point to cloud + point3d.intensity = intensities[j]; + point3d.time = time_relative; + cloud.points.push_back(point3d); + } +} + +} \ No newline at end of file diff --git a/src/soro_lidar/launch/launch.py b/src/soro_lidar/launch/launch.py new file mode 100644 index 00000000..6c6de827 --- /dev/null +++ b/src/soro_lidar/launch/launch.py @@ -0,0 +1,57 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.conditions import IfCondition +from launch.substitutions import LaunchConfiguration, PathJoinSubstitution +from launch_ros.actions import Node +from launch_ros.substitutions import FindPackageShare + + +def generate_launch_description(): + launch_rviz = LaunchConfiguration("launch_rviz") + + # Run unitree lidar + node1 = Node( + package="soro_lidar", + executable="unitree_lidar_ros2_node", + name="unitree_lidar_ros2_node", + output="screen", + parameters=[ + {"initialize_type": 2}, + {"work_mode": 0}, + {"use_system_timestamp": True}, + {"range_min": 0.0}, + {"range_max": 100.0}, + {"cloud_scan_num": 18}, + {"serial_port": "/dev/ttyACM0"}, + {"baudrate": 4000000}, + {"lidar_port": 6101}, + {"lidar_ip": "192.168.1.62"}, + {"local_port": 6201}, + {"local_ip": "192.168.1.2"}, + {"cloud_frame": "unilidar_lidar"}, + {"cloud_topic": "unilidar/cloud"}, + {"imu_frame": "unilidar_imu"}, + {"imu_topic": "unilidar/imu"}, + ], + ) + + # Run RViz only when explicitly requested. + rviz_node = Node( + package="rviz2", + executable="rviz2", + name="rviz2", + arguments=[ + "-d", + PathJoinSubstitution([FindPackageShare("soro_lidar"), "rviz", "view.rviz"]), + ], + output="log", + condition=IfCondition(launch_rviz), + ) + + return LaunchDescription( + [ + DeclareLaunchArgument("launch_rviz", default_value="false"), + node1, + rviz_node, + ] + ) diff --git a/src/soro_lidar/lib/aarch64/libunitree_lidar_sdk.a b/src/soro_lidar/lib/aarch64/libunitree_lidar_sdk.a new file mode 100644 index 0000000000000000000000000000000000000000..d5430122a556e0217493c4c813391a6c1d9d2cbf GIT binary patch literal 234344 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 literal 0 HcmV?d00001 diff --git a/src/soro_lidar/package.xml b/src/soro_lidar/package.xml new file mode 100644 index 00000000..68fc4260 --- /dev/null +++ b/src/soro_lidar/package.xml @@ -0,0 +1,29 @@ + + + + soro_lidar + 1.0.0 + unitree lidar ros2 + jo + Barrett Ray + GPLv3 + + ament_cmake + + ament_lint_auto + ament_lint_common + + rclcpp + std_msgs + sensor_msgs + + pcl_conversions + pcl + + geometry_msgs + tf2_ros + + + ament_cmake + + diff --git a/src/soro_lidar/rviz/view.rviz b/src/soro_lidar/rviz/view.rviz new file mode 100644 index 00000000..fd241461 --- /dev/null +++ b/src/soro_lidar/rviz/view.rviz @@ -0,0 +1,182 @@ +Panels: + - Class: rviz_common/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + - /PointCloud21 + - /TF1 + - /TF1/Frames1 + Splitter Ratio: 0.5 + Tree Height: 607 + - Class: rviz_common/Selection + Name: Selection + - Class: rviz_common/Tool Properties + Expanded: + - /2D Goal Pose1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz_common/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz_default_plugins/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 3.4900152683258057 + Min Value: 0 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz_default_plugins/PointCloud2 + Color: 255; 255; 255 + Color Transformer: AxisColor + Decay Time: 1 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Max Intensity: 85 + Min Color: 0; 0; 0 + Min Intensity: 0 + Name: PointCloud2 + Position Transformer: XYZ + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /unilidar/cloud + Use Fixed Frame: true + Use rainbow: true + Value: true + - Class: rviz_default_plugins/TF + Enabled: true + Frame Timeout: 15 + Frames: + All Enabled: true + unilidar_imu: + Value: true + unilidar_imu_initial: + Value: true + unilidar_lidar: + Value: true + Marker Scale: 1 + Name: TF + Show Arrows: true + Show Axes: true + Show Names: false + Tree: + unilidar_imu_initial: + unilidar_imu: + unilidar_lidar: + {} + Update Interval: 0 + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Fixed Frame: unilidar_lidar + Frame Rate: 30 + Name: root + Tools: + - Class: rviz_default_plugins/Interact + Hide Inactive Objects: true + - Class: rviz_default_plugins/MoveCamera + - Class: rviz_default_plugins/Select + - Class: rviz_default_plugins/FocusCamera + - Class: rviz_default_plugins/Measure + Line color: 128; 128; 0 + - Class: rviz_default_plugins/SetInitialPose + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /initialpose + - Class: rviz_default_plugins/SetGoal + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /goal_pose + - Class: rviz_default_plugins/PublishPoint + Single click: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /clicked_point + Transformation: + Current: + Class: rviz_default_plugins/TF + Value: true + Views: + Current: + Class: rviz_default_plugins/Orbit + Distance: 14.384671211242676 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: 0 + Y: 0 + Z: 0 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.5603978037834167 + Target Frame: + Value: Orbit (rviz) + Yaw: 0.785398006439209 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 836 + Hide Left Dock: false + Hide Right Dock: true + QMainWindow State: 000000ff00000000fd000000040000000000000156000002eafc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002ea000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002eafc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d000002ea000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d006501000000000000045000000000000000000000049c000002ea00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: true + Width: 1528 + X: 72 + Y: 27 diff --git a/src/soro_lidar/src/unitree_lidar_ros2_node.cpp b/src/soro_lidar/src/unitree_lidar_ros2_node.cpp new file mode 100644 index 00000000..074efb61 --- /dev/null +++ b/src/soro_lidar/src/unitree_lidar_ros2_node.cpp @@ -0,0 +1,14 @@ +/********************************************************************** + Copyright (c) 2020-2024, Unitree Robotics.Co.Ltd. All rights reserved. +***********************************************************************/ + +#include "unitree_lidar_ros2.h" + +int main(int argc, char *argv[]) +{ + const rclcpp::NodeOptions options; + rclcpp::init(argc, argv); + rclcpp::spin(std::make_shared()); + rclcpp::shutdown(); + return 0; +} \ No newline at end of file From c546f39492b95c5ba2cc375a8c8772b6b1a23c5a Mon Sep 17 00:00:00 2001 From: Barrett Date: Sun, 15 Feb 2026 21:36:26 -0600 Subject: [PATCH 02/20] feat(drive): configure nav2 for lidar --- src/drive_launcher/params/nav2.yaml | 116 +++++++++++++++++++++------- 1 file changed, 90 insertions(+), 26 deletions(-) diff --git a/src/drive_launcher/params/nav2.yaml b/src/drive_launcher/params/nav2.yaml index f2b60a37..32a1ec32 100644 --- a/src/drive_launcher/params/nav2.yaml +++ b/src/drive_launcher/params/nav2.yaml @@ -129,23 +129,56 @@ controller_server: always_send_full_costmap: false # and finally, we get to the important stuff - observation_sources: "scan" - scan: - topic: "/scan" - data_type: "LaserScan" - marking: true - clearing: true - obstacle_min_range: 0.3 - obstacle_max_range: 10.0 - raytrace_max_range: 10.0 # say what plugins to use explicitly. # # otherwise, we get the `static_layer`, which SUCKS because it messes # with our `/tf:map` frame... - plugins: ["obstacle_layer", "inflation_layer"] - obstacle_layer: - plugin: "nav2_costmap_2d::ObstacleLayer" + plugins: ["stvl_layer", "inflation_layer"] + stvl_layer: + plugin: "spatio_temporal_voxel_layer/SpatioTemporalVoxelLayer" + enabled: true + voxel_decay: 10.0 + decay_model: 0 + voxel_size: 0.1 + track_unknown_space: true + observation_persistence: 0.0 + max_obstacle_height: 2.5 + min_obstacle_height: 0.05 + mark_threshold: 0 + update_footprint_enabled: true + combination_method: 1 + obstacle_range: 20.0 + origin_z: 0.0 + publish_voxel_map: false + transform_tolerance: 0.2 + mapping_mode: false + observation_sources: "lidar_mark lidar_clear" + lidar_mark: + data_type: PointCloud2 + topic: /unilidar/cloud + marking: true + clearing: false + min_obstacle_height: 0.05 + max_obstacle_height: 2.5 + expected_update_rate: 0.0 + observation_persistence: 0.0 + clear_after_reading: true + filter: "voxel" + voxel_min_points: 0 + lidar_clear: + enabled: true + data_type: PointCloud2 + topic: /unilidar/cloud + marking: false + clearing: true + min_z: -0.5 + max_z: 3.0 + vertical_fov_angle: 1.57 + vertical_fov_offset: 0.0 + horizontal_fov_angle: 6.283185307 + decay_acceleration: 1.0 + model_type: 1 inflation_layer: plugin: "nav2_costmap_2d::InflationLayer" inflation_radius: 0.4 @@ -173,21 +206,52 @@ controller_server: # allow higher latency from sensors transform_tolerance: 2.0 - # important: faked laser scan - observation_sources: "scan" - scan: - topic: "/scan" - data_type: "LaserScan" - marking: true - clearing: true - obstacle_min_range: 0.3 - obstacle_max_range: 10.0 - raytrace_max_range: 10.0 - # say what plugins to use explicitly. (see `local_costmap` for more info) - plugins: ["obstacle_layer", "inflation_layer"] - obstacle_layer: - plugin: "nav2_costmap_2d::ObstacleLayer" + plugins: ["stvl_layer", "inflation_layer"] + stvl_layer: + plugin: "spatio_temporal_voxel_layer/SpatioTemporalVoxelLayer" + enabled: true + voxel_decay: 30.0 + decay_model: 0 + voxel_size: 0.1 + track_unknown_space: true + observation_persistence: 0.0 + max_obstacle_height: 2.5 + min_obstacle_height: 0.05 + mark_threshold: 0 + update_footprint_enabled: true + combination_method: 1 + obstacle_range: 40.0 + origin_z: 0.0 + publish_voxel_map: false + transform_tolerance: 0.2 + mapping_mode: false + observation_sources: "lidar_mark lidar_clear" + lidar_mark: + data_type: PointCloud2 + topic: /unilidar/cloud + marking: true + clearing: false + min_obstacle_height: 0.05 + max_obstacle_height: 2.5 + expected_update_rate: 0.0 + observation_persistence: 0.0 + clear_after_reading: true + filter: "voxel" + voxel_min_points: 0 + lidar_clear: + enabled: true + data_type: PointCloud2 + topic: /unilidar/cloud + marking: false + clearing: true + min_z: -0.5 + max_z: 3.0 + vertical_fov_angle: 1.57 + vertical_fov_offset: 0.0 + horizontal_fov_angle: 6.283185307 + decay_acceleration: 1.0 + model_type: 1 inflation_layer: plugin: "nav2_costmap_2d::InflationLayer" inflation_radius: 0.4 From 0cecc0ce0369a9bc7f7705cdad9c9c26ae13f0be Mon Sep 17 00:00:00 2001 From: Barrett Date: Sun, 15 Feb 2026 21:37:21 -0600 Subject: [PATCH 03/20] refactor(drive): remove old depth camera stuff --- .../helpers/depthimage_to_laserscan.launch.py | 65 ------------------- .../launch/helpers/slam_toolbox.launch.py | 26 -------- src/drive_launcher/launch/rover.launch.py | 12 ---- 3 files changed, 103 deletions(-) delete mode 100644 src/drive_launcher/launch/helpers/depthimage_to_laserscan.launch.py diff --git a/src/drive_launcher/launch/helpers/depthimage_to_laserscan.launch.py b/src/drive_launcher/launch/helpers/depthimage_to_laserscan.launch.py deleted file mode 100644 index 0bc98691..00000000 --- a/src/drive_launcher/launch/helpers/depthimage_to_laserscan.launch.py +++ /dev/null @@ -1,65 +0,0 @@ -from launch import LaunchDescription -from launch.actions import DeclareLaunchArgument -from launch.frontend.parse_substitution import get_package_share_directory -from launch.substitutions import LaunchConfiguration, PathJoinSubstitution -from launch_ros.actions import Node - - -def generate_launch_description() -> LaunchDescription: - """ - Nav2, the toolkit that provides path-planning capabilities to the Rover, - takes a selection of inputs. However, the most important for performing - object avoidance (i.e., not running into things) is the LiDAR scanner. - - LiDAR is essential for good SLAM algorithms, as it provides information - about where things in the environment are. - - We don't have LiDAR on the Rover. - - So, to make up for this, we can use the `depthimage_to_laserscan_node` to - 'fake' this functionality by using depth camera data (which is different). - - It publishes `sensor_msgs::LaserScan` messages, which `slam_toolkit` then - gets to utilize and send over to Nav2. This setup allows us to utilize - SLAM without LiDAR, while still getting similar benefits to using LiDAR! - """ - pkg_drive_launcher: str = get_package_share_directory("drive_launcher") - use_sim_time = LaunchConfiguration("use_sim_time") - - depth_image_to_laser_scan_node: Node = Node( - executable="depthimage_to_laserscan_node", - package="depthimage_to_laserscan", - arguments=[ - PathJoinSubstitution( - [ - pkg_drive_launcher, - "params", - "depthimage_to_laserscan.yaml", - ] - ) - ], - parameters=[ - { - "scan_time": 0.033, # seconds - "range_min": 0.02, # meters - "range_max": 35.0, # also in meters - "scan_height": 1, - "output_frame": "camera_depth_frame", - "use_sim_time": use_sim_time, - }, - ], - remappings=[ - ("/depth_camera_info", "/sensors/depth_image/camera_info"), - ("/depth", "/sensors/depth_image"), - ("scan", "/scan"), # otherwise, it outputs locally - ], - ) - - return LaunchDescription( - [ - DeclareLaunchArgument( - "use_sim_time", - ), - depth_image_to_laser_scan_node, - ] - ) diff --git a/src/drive_launcher/launch/helpers/slam_toolbox.launch.py b/src/drive_launcher/launch/helpers/slam_toolbox.launch.py index a9e6d95b..2e69294c 100644 --- a/src/drive_launcher/launch/helpers/slam_toolbox.launch.py +++ b/src/drive_launcher/launch/helpers/slam_toolbox.launch.py @@ -13,10 +13,6 @@ def generate_launch_description() -> LaunchDescription: "use_sim_time", default="false" ) - # we need this little node to make a link between `camera_link` and - # `camera_depth_frame` - camera_chain: Node = _make_camera_depth_frame_link_node(use_sim_time) - slam_toolbox = Node( package="slam_toolbox", executable="async_slam_toolbox_node", @@ -33,7 +29,6 @@ def generate_launch_description() -> LaunchDescription: DeclareLaunchArgument( "use_sim_time", ), - camera_chain, slam_toolbox, ] ) @@ -47,24 +42,3 @@ def _get_conf() -> PathJoinSubstitution: "slam_toolbox.yaml", ] ) - - -def _make_camera_depth_frame_link_node( - use_sim_time: LaunchConfiguration, -) -> Node: - return Node( - name="tf2_publish_camera_depth_frame_link_node", - package="tf2_ros", - executable="static_transform_publisher", - arguments=[ - "0", # x - "0", # y - "0", # z - "0", # rx - "0", # ry - "0", # rz - "camera_link", # parent frame - "camera_depth_frame", # subframe - ], - parameters=[{"use_sim_time": use_sim_time}], - ) diff --git a/src/drive_launcher/launch/rover.launch.py b/src/drive_launcher/launch/rover.launch.py index 334e9d55..8a4a5a40 100644 --- a/src/drive_launcher/launch/rover.launch.py +++ b/src/drive_launcher/launch/rover.launch.py @@ -53,17 +53,6 @@ def generate_launch_description() -> LaunchDescription: # directly by our Navigator). robot_localization: IncludeLaunchDescription = _robot_localization(use_sim_time) - # the `depthimage_to_laserscan::depthimage_to_laserscan_node` gives us - # another source of `/tf:map` data. - # - # it converts our depth camera data (from the Zed 2i) into usable point - # clouds, which you'd otherwise have to get from a laser scanner. - # - # our Rover doesn't have one of those..! so, for object avoidance, we use - # this node to add boundaries to our map. - depthimage_to_laserscan: IncludeLaunchDescription = _depthimage_to_laserscan( - use_sim_time - ) # ok, so this part launches a few different things... # @@ -122,7 +111,6 @@ def generate_launch_description() -> LaunchDescription: utm_conversion_node, robot_state_publisher, robot_localization, - depthimage_to_laserscan, navigation_stack, ros2_control, Node( From 6176821aa4774bffcff8d452f44d46f292510bee Mon Sep 17 00:00:00 2001 From: Barrett Date: Sun, 15 Feb 2026 21:38:02 -0600 Subject: [PATCH 04/20] feat(drive): add "lidar_to_laserscan" node --- src/drive_launcher/launch/ebox.launch.py | 48 +++++++++++++---- .../helpers/lidar_to_laserscan.launch.py | 53 +++++++++++++++++++ src/drive_launcher/launch/rover.launch.py | 8 ++- 3 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 src/drive_launcher/launch/helpers/lidar_to_laserscan.launch.py diff --git a/src/drive_launcher/launch/ebox.launch.py b/src/drive_launcher/launch/ebox.launch.py index ecd42fa3..4ee964ae 100644 --- a/src/drive_launcher/launch/ebox.launch.py +++ b/src/drive_launcher/launch/ebox.launch.py @@ -2,11 +2,12 @@ This file runs all required nodes to speak with the Ebox. """ +from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription -from launch.actions import OpaqueFunction +from launch.actions import IncludeLaunchDescription +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import PathJoinSubstitution from launch_ros.actions.node import Node -from rclpy.impl.rcutils_logger import RcutilsLogger -from rclpy.node import get_logger def generate_launch_description() -> LaunchDescription: @@ -38,13 +39,38 @@ def generate_launch_description() -> LaunchDescription: executable="sensors_node", ) - # TODO: implement the camera launch files, then replace this! - camera_warning: OpaqueFunction = OpaqueFunction(function=_warn_about_camera_todos) - - return LaunchDescription([wheels_node, lights_node, sensors_node, camera_warning]) + # Unitree L2 LiDAR bridge package. + pkg_soro_lidar: str = get_package_share_directory("soro_lidar") + lidar_launch: IncludeLaunchDescription = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [ + PathJoinSubstitution( + [ + pkg_soro_lidar, + "launch", + "launch.py", + ] + ) + ] + ) + ) + # See3CAM color stream for ArUco marker detection. + pkg_see3cam: str = get_package_share_directory("see3cam") + see3cam_launch: IncludeLaunchDescription = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [ + PathJoinSubstitution( + [ + pkg_see3cam, + "launch", + "see3cam.launch.py", + ] + ) + ] + ) + ) -def _warn_about_camera_todos(_): - # we'll emit a diagnostic to remind ourselves lol - logger: RcutilsLogger = get_logger("ebox.launch.py") - _ = logger.error("TODO: implement cameras in launch file!") + return LaunchDescription( + [wheels_node, lights_node, sensors_node, lidar_launch, see3cam_launch] + ) diff --git a/src/drive_launcher/launch/helpers/lidar_to_laserscan.launch.py b/src/drive_launcher/launch/helpers/lidar_to_laserscan.launch.py new file mode 100644 index 00000000..02b92087 --- /dev/null +++ b/src/drive_launcher/launch/helpers/lidar_to_laserscan.launch.py @@ -0,0 +1,53 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import ComposableNodeContainer +from launch_ros.descriptions import ComposableNode + + +def generate_launch_description() -> LaunchDescription: + use_sim_time: LaunchConfiguration = LaunchConfiguration( + "use_sim_time", default="false" + ) + + pointcloud_to_laserscan: ComposableNode = ComposableNode( + name="lidar_pointcloud_to_laserscan", + package="pointcloud_to_laserscan", + plugin="pointcloud_to_laserscan::PointCloudToLaserScanNode", + remappings=[ + ("cloud_in", "/unilidar/cloud"), + ("scan", "/scan"), + ], + parameters=[ + { + "use_sim_time": use_sim_time, + "target_frame": "base_link", + "transform_tolerance": 0.2, + "min_height": -0.5, + "max_height": 2.5, + "angle_min": -3.1415926535, + "angle_max": 3.1415926535, + "angle_increment": 0.0058, + "scan_time": 0.1, + "range_min": 0.3, + "range_max": 100.0, + "use_inf": True, + } + ], + ) + + container: ComposableNodeContainer = ComposableNodeContainer( + name="lidar_scan_container", + namespace="", + package="rclcpp_components", + executable="component_container_mt", + composable_node_descriptions=[pointcloud_to_laserscan], + output="screen", + ) + + return LaunchDescription( + [ + DeclareLaunchArgument("use_sim_time", default_value="false"), + container, + ] + ) diff --git a/src/drive_launcher/launch/rover.launch.py b/src/drive_launcher/launch/rover.launch.py index 8a4a5a40..3b5cfc1e 100644 --- a/src/drive_launcher/launch/rover.launch.py +++ b/src/drive_launcher/launch/rover.launch.py @@ -53,6 +53,9 @@ def generate_launch_description() -> LaunchDescription: # directly by our Navigator). robot_localization: IncludeLaunchDescription = _robot_localization(use_sim_time) + # Convert Unitree LiDAR point clouds into LaserScan for scan-based nodes + # (e.g., slam_toolbox and collision monitor). + lidar_to_laserscan: IncludeLaunchDescription = _lidar_to_laserscan(use_sim_time) # ok, so this part launches a few different things... # @@ -111,6 +114,7 @@ def generate_launch_description() -> LaunchDescription: utm_conversion_node, robot_state_publisher, robot_localization, + lidar_to_laserscan, navigation_stack, ros2_control, Node( @@ -187,7 +191,7 @@ def _navigation_bringup( ) -def _depthimage_to_laserscan( +def _lidar_to_laserscan( use_sim_time: LaunchConfiguration, ) -> IncludeLaunchDescription: pkg_drive_launcher: str = get_package_share_directory("drive_launcher") @@ -199,7 +203,7 @@ def _depthimage_to_laserscan( pkg_drive_launcher, "launch", "helpers", - "depthimage_to_laserscan.launch.py", + "lidar_to_laserscan.launch.py", ] ) ] From a715ccfcd6c82e2ceef027ddf7b754d2dd38a898 Mon Sep 17 00:00:00 2001 From: Barrett Date: Mon, 16 Feb 2026 15:56:33 -0600 Subject: [PATCH 05/20] feat(sim): add lidar to the chassis --- src/simulator/resource/rover.urdf.xacro.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/simulator/resource/rover.urdf.xacro.xml b/src/simulator/resource/rover.urdf.xacro.xml index 7fb984e5..52b1f6f1 100644 --- a/src/simulator/resource/rover.urdf.xacro.xml +++ b/src/simulator/resource/rover.urdf.xacro.xml @@ -231,6 +231,21 @@ makes a wheel joint for ros2_control. + + + + + + + + + + + + + + + 0 0 0.2 0 0 0 From 18697238cb97200a1ba473ff7b124b3ced826509 Mon Sep 17 00:00:00 2001 From: Barrett Date: Mon, 16 Feb 2026 15:57:08 -0600 Subject: [PATCH 06/20] test(sim): chassis tf tree layout w/ lidar the lidar should show up in the tf tree after these changes :D --- src/simulator/CMakeLists.txt | 6 ++++++ src/simulator/test/test_tf_tree.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/simulator/test/test_tf_tree.py diff --git a/src/simulator/CMakeLists.txt b/src/simulator/CMakeLists.txt index 7746a467..dc524208 100644 --- a/src/simulator/CMakeLists.txt +++ b/src/simulator/CMakeLists.txt @@ -31,8 +31,14 @@ install(CODE "execute_process(COMMAND chmod +x \${CMAKE_INSTALL_PREFIX}/lib/${PR # test stuff if(BUILD_TESTING) + find_package(Python3 REQUIRED COMPONENTS Interpreter) find_package(launch_testing_ament_cmake) + add_launch_test(test/test_launch_sim_works.py) + add_test( + NAME simulator_test_tf_tree + COMMAND ${Python3_EXECUTABLE} -m pytest -q ${CMAKE_CURRENT_SOURCE_DIR}/test/test_tf_tree.py + ) endif() ament_package() diff --git a/src/simulator/test/test_tf_tree.py b/src/simulator/test/test_tf_tree.py new file mode 100644 index 00000000..486d757c --- /dev/null +++ b/src/simulator/test/test_tf_tree.py @@ -0,0 +1,28 @@ +import xml.etree.ElementTree as ET +from pathlib import Path + + +def _robot_tree() -> ET.Element: + urdf_xacro = ( + Path(__file__).resolve().parents[1] / "resource" / "rover.urdf.xacro.xml" + ) + return ET.parse(urdf_xacro).getroot() + + +def test_lidar_frames_attached_to_chassis_tf_tree() -> None: + root: ET.Element[str] = _robot_tree() + + links: set[str] = {link.attrib["name"] for link in root.findall("link")} + assert "unilidar_imu" in links + assert "unilidar_lidar" in links + + parent_by_child: dict[str, str] = {} + for joint in root.findall("joint"): + parent: ET.Element[str] | None = joint.find("parent") + child: ET.Element[str] | None = joint.find("child") + if parent is None or child is None: + continue + parent_by_child[child.attrib["link"]] = parent.attrib["link"] + + assert parent_by_child.get("unilidar_imu") == "chassis" + assert parent_by_child.get("unilidar_lidar") == "unilidar_imu" From ca8db7f066d18c66388d88a89a06f21a419f9a51 Mon Sep 17 00:00:00 2001 From: Barrett Date: Mon, 16 Feb 2026 15:58:20 -0600 Subject: [PATCH 07/20] refactor(sim): remove depth camera from chassis --- src/simulator/resource/rover.urdf.xacro.xml | 30 --------------------- 1 file changed, 30 deletions(-) diff --git a/src/simulator/resource/rover.urdf.xacro.xml b/src/simulator/resource/rover.urdf.xacro.xml index 52b1f6f1..b4a654d8 100644 --- a/src/simulator/resource/rover.urdf.xacro.xml +++ b/src/simulator/resource/rover.urdf.xacro.xml @@ -331,36 +331,6 @@ makes a wheel joint for ros2_control. - - - - true - ${depth_camera_refresh_speed} - ${depth_camera_topic} - true - - - ${depth_camera_fov} - - - ${depth_camera_info_topic} - - - ${depth_camera_frame_width} - ${depth_camera_frame_height} - R_FLOAT32 - - - 0.1 - 150.0 - - - - camera_link - - - gz_ros2_control/GazeboSimSystem From 09b109e1d7e7f4488ee880cdbb286a4492a10363 Mon Sep 17 00:00:00 2001 From: Barrett Date: Mon, 16 Feb 2026 17:02:44 -0600 Subject: [PATCH 08/20] docs(soro_lidar): add a README.md --- src/soro_lidar/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/soro_lidar/README.md diff --git a/src/soro_lidar/README.md b/src/soro_lidar/README.md new file mode 100644 index 00000000..98871193 --- /dev/null +++ b/src/soro_lidar/README.md @@ -0,0 +1,17 @@ +# soro_lidar + +A package that providers LiDAR functionality on the Rover. + +## Usage + +Launch LiDAR only: + +```bash +ros2 launch soro_lidar launch.py +``` + +Launch LiDAR + RViz2: + +```bash +ros2 launch soro_lidar launch.py launch_rviz:=true +``` From b6c2d8a52c984305d26ec802c88db5181bda5860 Mon Sep 17 00:00:00 2001 From: Barrett Date: Mon, 16 Feb 2026 17:03:08 -0600 Subject: [PATCH 09/20] fix(soro_lidar): config lidar launch to use serial --- src/soro_lidar/launch/launch.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/soro_lidar/launch/launch.py b/src/soro_lidar/launch/launch.py index 6c6de827..19d99a86 100644 --- a/src/soro_lidar/launch/launch.py +++ b/src/soro_lidar/launch/launch.py @@ -16,13 +16,15 @@ def generate_launch_description(): name="unitree_lidar_ros2_node", output="screen", parameters=[ - {"initialize_type": 2}, + {"initialize_type": 1}, {"work_mode": 0}, {"use_system_timestamp": True}, {"range_min": 0.0}, {"range_max": 100.0}, {"cloud_scan_num": 18}, - {"serial_port": "/dev/ttyACM0"}, + { + "serial_port": "/dev/serial/by-id/usb-1a86_USB_Single_Serial_5A64013752-if00" + }, {"baudrate": 4000000}, {"lidar_port": 6101}, {"lidar_ip": "192.168.1.62"}, From a91f36397430f975468eb2e4ce31a6be27bbbb6b Mon Sep 17 00:00:00 2001 From: Barrett Date: Mon, 16 Feb 2026 17:03:37 -0600 Subject: [PATCH 10/20] fix(soro_lidar): show rviz correctly got the path wrong before. whoops --- src/soro_lidar/launch/launch.py | 2 +- src/soro_lidar/rviz/view.rviz | 70 +++++++++++++-------------------- 2 files changed, 29 insertions(+), 43 deletions(-) diff --git a/src/soro_lidar/launch/launch.py b/src/soro_lidar/launch/launch.py index 19d99a86..ede50876 100644 --- a/src/soro_lidar/launch/launch.py +++ b/src/soro_lidar/launch/launch.py @@ -44,7 +44,7 @@ def generate_launch_description(): name="rviz2", arguments=[ "-d", - PathJoinSubstitution([FindPackageShare("soro_lidar"), "rviz", "view.rviz"]), + PathJoinSubstitution([FindPackageShare("soro_lidar"), "view.rviz"]), ], output="log", condition=IfCondition(launch_rviz), diff --git a/src/soro_lidar/rviz/view.rviz b/src/soro_lidar/rviz/view.rviz index fd241461..3544980b 100644 --- a/src/soro_lidar/rviz/view.rviz +++ b/src/soro_lidar/rviz/view.rviz @@ -7,10 +7,8 @@ Panels: - /Global Options1 - /Status1 - /PointCloud21 - - /TF1 - - /TF1/Frames1 Splitter Ratio: 0.5 - Tree Height: 607 + Tree Height: 845 - Class: rviz_common/Selection Name: Selection - Class: rviz_common/Tool Properties @@ -24,6 +22,11 @@ Panels: - /Current View1 Name: Views Splitter Ratio: 0.5 + - Class: rviz_common/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: PointCloud2 Visualization Manager: Class: "" Displays: @@ -48,59 +51,37 @@ Visualization Manager: - Alpha: 1 Autocompute Intensity Bounds: true Autocompute Value Bounds: - Max Value: 3.4900152683258057 - Min Value: 0 + Max Value: 10 + Min Value: -10 Value: true Axis: Z Channel Name: intensity Class: rviz_default_plugins/PointCloud2 Color: 255; 255; 255 - Color Transformer: AxisColor - Decay Time: 1 + Color Transformer: Intensity + Decay Time: 5 Enabled: true Invert Rainbow: false Max Color: 255; 255; 255 - Max Intensity: 85 + Max Intensity: 255 Min Color: 0; 0; 0 Min Intensity: 0 Name: PointCloud2 Position Transformer: XYZ Selectable: true Size (Pixels): 3 - Size (m): 0.009999999776482582 - Style: Points + Size (m): 0.10000000149011612 + Style: Flat Squares Topic: Depth: 5 Durability Policy: Volatile + Filter size: 10 History Policy: Keep Last Reliability Policy: Reliable Value: /unilidar/cloud Use Fixed Frame: true Use rainbow: true Value: true - - Class: rviz_default_plugins/TF - Enabled: true - Frame Timeout: 15 - Frames: - All Enabled: true - unilidar_imu: - Value: true - unilidar_imu_initial: - Value: true - unilidar_lidar: - Value: true - Marker Scale: 1 - Name: TF - Show Arrows: true - Show Axes: true - Show Names: false - Tree: - unilidar_imu_initial: - unilidar_imu: - unilidar_lidar: - {} - Update Interval: 0 - Value: true Enabled: true Global Options: Background Color: 48; 48; 48 @@ -116,6 +97,9 @@ Visualization Manager: - Class: rviz_default_plugins/Measure Line color: 128; 128; 0 - Class: rviz_default_plugins/SetInitialPose + Covariance x: 0.25 + Covariance y: 0.25 + Covariance yaw: 0.06853891909122467 Topic: Depth: 5 Durability Policy: Volatile @@ -144,7 +128,7 @@ Visualization Manager: Views: Current: Class: rviz_default_plugins/Orbit - Distance: 14.384671211242676 + Distance: 9.122121810913086 Enable Stereo Rendering: Stereo Eye Separation: 0.05999999865889549 Stereo Focal Distance: 1 @@ -159,24 +143,26 @@ Visualization Manager: Invert Z Axis: false Name: Current View Near Clip Distance: 0.009999999776482582 - Pitch: 0.5603978037834167 + Pitch: 0.4853978455066681 Target Frame: Value: Orbit (rviz) - Yaw: 0.785398006439209 + Yaw: 2.893608331680298 Saved: ~ Window Geometry: Displays: collapsed: false - Height: 836 + Height: 1136 Hide Left Dock: false - Hide Right Dock: true - QMainWindow State: 000000ff00000000fd000000040000000000000156000002eafc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002ea000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002eafc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d000002ea000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d006501000000000000045000000000000000000000049c000002ea00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Hide Right Dock: false + QMainWindow State: 000000ff00000000fd000000040000000000000156000003d6fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000003d6000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000003d6fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b000003d6000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073a0000003efc0100000002fb0000000800540069006d006501000000000000073a0000025300fffffffb0000000800540069006d00650100000000000004500000000000000000000004c9000003d600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false + Time: + collapsed: false Tool Properties: collapsed: false Views: - collapsed: true - Width: 1528 - X: 72 + collapsed: false + Width: 1850 + X: 70 Y: 27 From c7e25741cd9a8d97e9f7cacbaef48a90931b9e50 Mon Sep 17 00:00:00 2001 From: Barrett Date: Wed, 18 Feb 2026 15:27:47 -0600 Subject: [PATCH 11/20] fix(drive): add missing arg in nested launch file --- src/drive_launcher/launch/drive.launch.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/drive_launcher/launch/drive.launch.py b/src/drive_launcher/launch/drive.launch.py index 7fe2b9de..1ff1293c 100644 --- a/src/drive_launcher/launch/drive.launch.py +++ b/src/drive_launcher/launch/drive.launch.py @@ -5,17 +5,19 @@ """ from launch import LaunchDescription -from launch.actions import IncludeLaunchDescription +from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource -from launch.substitutions import PathJoinSubstitution +from launch.substitutions import LaunchConfiguration, PathJoinSubstitution from launch_ros.substitutions.find_package import get_package_share_directory def generate_launch_description() -> LaunchDescription: pkg_drive_launcher: str = get_package_share_directory("drive_launcher") + use_sim_time = LaunchConfiguration("use_sim_time") return LaunchDescription( [ + DeclareLaunchArgument("use_sim_time", default_value="false"), # `rover.launch.py` is the ros 2 side of things. # # it includes stuff like Nav2 and `slam_toolbox` for interpreting @@ -31,7 +33,8 @@ def generate_launch_description() -> LaunchDescription: ] ) ] - ) + ), + launch_arguments=[("use_sim_time", use_sim_time)], ), # # and `ebox.launch.py` is the ebox <=> autonomous communication From dc7e262d36531fe8b9535eeae298028efcb0f846 Mon Sep 17 00:00:00 2001 From: Barrett Date: Wed, 18 Feb 2026 17:25:41 -0600 Subject: [PATCH 12/20] fix(launch): ebox launch file wrong install path --- src/drive_launcher/launch/ebox.launch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/drive_launcher/launch/ebox.launch.py b/src/drive_launcher/launch/ebox.launch.py index 4ee964ae..55a519a9 100644 --- a/src/drive_launcher/launch/ebox.launch.py +++ b/src/drive_launcher/launch/ebox.launch.py @@ -47,7 +47,6 @@ def generate_launch_description() -> LaunchDescription: PathJoinSubstitution( [ pkg_soro_lidar, - "launch", "launch.py", ] ) From c1a8b35f7f82e427bd301af340453531521ba55e Mon Sep 17 00:00:00 2001 From: Barrett Date: Wed, 18 Feb 2026 17:26:56 -0600 Subject: [PATCH 13/20] fix: cfg out gz_ros2_control when not in simulator --- .../helpers/robot_state_publisher.launch.py | 26 ++++++++- .../launch/helpers/ros2_control.launch.py | 56 +++++++++++++++++-- src/drive_launcher/launch/rover.launch.py | 35 ++++++++++-- src/simulator/launch/sim.launch.py | 7 ++- src/simulator/resource/rover.urdf.xacro.xml | 18 +++--- 5 files changed, 122 insertions(+), 20 deletions(-) diff --git a/src/drive_launcher/launch/helpers/robot_state_publisher.launch.py b/src/drive_launcher/launch/helpers/robot_state_publisher.launch.py index 2bd1215b..cdc772f4 100644 --- a/src/drive_launcher/launch/helpers/robot_state_publisher.launch.py +++ b/src/drive_launcher/launch/helpers/robot_state_publisher.launch.py @@ -16,9 +16,14 @@ def generate_launch_description() -> LaunchDescription: starts the `robot_state_publisher::robot_state_publisher` node. """ use_sim_time = LaunchConfiguration("use_sim_time") + ros2_control_plugin = LaunchConfiguration("ros2_control_plugin") + use_gazebo_ros2_control = LaunchConfiguration("use_gazebo_ros2_control") # grab the rover's udrf - robot_desc: dict[str, ParameterValue] = _grab_robot_description() + robot_desc: dict[str, ParameterValue] = _grab_robot_description( + ros2_control_plugin=ros2_control_plugin, + use_gazebo_ros2_control=use_gazebo_ros2_control, + ) # the `robot_state_publisher` node basically takes the various transform # differences defined in a URDF file and tells other nodes where stuff on @@ -40,12 +45,23 @@ def generate_launch_description() -> LaunchDescription: DeclareLaunchArgument( "use_sim_time", ), + DeclareLaunchArgument( + "ros2_control_plugin", + default_value="fake_components/GenericSystem", + ), + DeclareLaunchArgument( + "use_gazebo_ros2_control", + default_value="false", + ), rover_state_publisher_node, ] ) -def _grab_robot_description() -> dict[str, ParameterValue]: +def _grab_robot_description( + ros2_control_plugin: LaunchConfiguration, + use_gazebo_ros2_control: LaunchConfiguration, +) -> dict[str, ParameterValue]: """grabs the robot desc.""" # make the description @@ -60,6 +76,12 @@ def _grab_robot_description() -> dict[str, ParameterValue]: "rover.urdf.xacro.xml", ] ), + " ", + "ros2_control_plugin:=", + ros2_control_plugin, + " ", + "use_gazebo_ros2_control:=", + use_gazebo_ros2_control, ] ) diff --git a/src/drive_launcher/launch/helpers/ros2_control.launch.py b/src/drive_launcher/launch/helpers/ros2_control.launch.py index 012be1fd..d4ad3efb 100644 --- a/src/drive_launcher/launch/helpers/ros2_control.launch.py +++ b/src/drive_launcher/launch/helpers/ros2_control.launch.py @@ -9,8 +9,10 @@ from launch.actions import ( DeclareLaunchArgument, RegisterEventHandler, + TimerAction, ) -from launch.event_handlers import OnProcessExit, OnProcessStart +from launch.conditions import IfCondition, UnlessCondition +from launch.event_handlers import OnProcessStart from launch.substitutions import ( LaunchConfiguration, PathJoinSubstitution, @@ -21,8 +23,22 @@ def generate_launch_description() -> LaunchDescription: use_sim_time = LaunchConfiguration("use_sim_time") + start_controller_manager = LaunchConfiguration("start_controller_manager") controllers_conf: PathJoinSubstitution = _get_controllers_conf() + controller_manager = Node( + package="controller_manager", + executable="ros2_control_node", + parameters=[ + controllers_conf, + {"use_sim_time": use_sim_time}, + ], + remappings=[ + ("~/robot_description", "/robot_description"), + ], + condition=IfCondition(start_controller_manager), + ) + # unfortunately, this dumb Node has to exist until we upgrade to Jazzy or # Kilted due to limitations in the Humble version of the # `controller_manager::spawner` Node. @@ -49,6 +65,8 @@ def generate_launch_description() -> LaunchDescription: executable="spawner", arguments=[ "joint_state_broadcaster", + "--controller-manager", + "/controller_manager", ], parameters=[ {"use_sim_time": use_sim_time}, @@ -60,6 +78,8 @@ def generate_launch_description() -> LaunchDescription: executable="spawner", arguments=[ "diff_drive_controller", + "--controller-manager", + "/controller_manager", "--param-file", controllers_conf, ], @@ -78,19 +98,43 @@ def generate_launch_description() -> LaunchDescription: DeclareLaunchArgument( "use_sim_time", ), - spawn_joint_state_broadcaster, + DeclareLaunchArgument( + "start_controller_manager", + default_value="true", + ), + controller_manager, + TimerAction( + period=0.0, + actions=[spawn_joint_state_broadcaster], + condition=UnlessCondition(start_controller_manager), + ), # - # very important! only spawn controllers when the broadcast guy is up + # spawn controllers only when controller manager is up. + RegisterEventHandler( + event_handler=OnProcessStart( + target_action=controller_manager, + on_start=[spawn_joint_state_broadcaster], + ), + condition=IfCondition(start_controller_manager), + ), RegisterEventHandler( - event_handler=OnProcessExit( + event_handler=OnProcessStart( target_action=spawn_joint_state_broadcaster, - on_exit=[cmd_vel_remapping_relay], - ) + on_start=[spawn_diff_drive], + ), + condition=IfCondition(start_controller_manager), ), RegisterEventHandler( event_handler=OnProcessStart( target_action=spawn_joint_state_broadcaster, on_start=[spawn_diff_drive], + ), + condition=UnlessCondition(start_controller_manager), + ), + RegisterEventHandler( + event_handler=OnProcessStart( + target_action=spawn_diff_drive, + on_start=[cmd_vel_remapping_relay], ) ), ] diff --git a/src/drive_launcher/launch/rover.launch.py b/src/drive_launcher/launch/rover.launch.py index 3b5cfc1e..08db369b 100644 --- a/src/drive_launcher/launch/rover.launch.py +++ b/src/drive_launcher/launch/rover.launch.py @@ -18,6 +18,9 @@ def generate_launch_description() -> LaunchDescription: # whether or not we'll launch using sim time. use_sim_time = LaunchConfiguration("use_sim_time") + ros2_control_plugin = LaunchConfiguration("ros2_control_plugin") + use_gazebo_ros2_control = LaunchConfiguration("use_gazebo_ros2_control") + start_controller_manager = LaunchConfiguration("start_controller_manager") # start the utm conversion node. # @@ -83,7 +86,7 @@ def generate_launch_description() -> LaunchDescription: # is required for consistent mapping, good navigation, and object # avoidance. robot_state_publisher: IncludeLaunchDescription = _robot_state_publisher( - use_sim_time + use_sim_time, ros2_control_plugin, use_gazebo_ros2_control ) # `ros2_control` is a collection of nodes that we use to control the Rover. @@ -104,13 +107,27 @@ def generate_launch_description() -> LaunchDescription: # there are no cross-platform networking APIs in the C++ stdlib. note that # `boost` could be an option in the future if future Autonomous members9 # would like to move toward a `ros2_control`-based approach. - ros2_control: IncludeLaunchDescription = _ros2_control(use_sim_time) + ros2_control: IncludeLaunchDescription = _ros2_control( + use_sim_time, start_controller_manager + ) return LaunchDescription( [ DeclareLaunchArgument( "use_sim_time", ), + DeclareLaunchArgument( + "ros2_control_plugin", + default_value="fake_components/GenericSystem", + ), + DeclareLaunchArgument( + "use_gazebo_ros2_control", + default_value="false", + ), + DeclareLaunchArgument( + "start_controller_manager", + default_value="true", + ), utm_conversion_node, robot_state_publisher, robot_localization, @@ -150,6 +167,8 @@ def _robot_localization( def _robot_state_publisher( use_sim_time: LaunchConfiguration, + ros2_control_plugin: LaunchConfiguration, + use_gazebo_ros2_control: LaunchConfiguration, ) -> IncludeLaunchDescription: pkg_drive_launcher: str = get_package_share_directory("drive_launcher") @@ -166,7 +185,11 @@ def _robot_state_publisher( ) ] ), - launch_arguments=[("use_sim_time", (use_sim_time))], + launch_arguments=[ + ("use_sim_time", use_sim_time), + ("ros2_control_plugin", ros2_control_plugin), + ("use_gazebo_ros2_control", use_gazebo_ros2_control), + ], ) @@ -214,6 +237,7 @@ def _lidar_to_laserscan( def _ros2_control( use_sim_time: LaunchConfiguration, + start_controller_manager: LaunchConfiguration, ) -> IncludeLaunchDescription: pkg_drive_launcher: str = get_package_share_directory("drive_launcher") @@ -230,5 +254,8 @@ def _ros2_control( ) ] ), - launch_arguments=[("use_sim_time", use_sim_time)], + launch_arguments=[ + ("use_sim_time", use_sim_time), + ("start_controller_manager", start_controller_manager), + ], ) diff --git a/src/simulator/launch/sim.launch.py b/src/simulator/launch/sim.launch.py index e65c9dbc..c0f0816e 100644 --- a/src/simulator/launch/sim.launch.py +++ b/src/simulator/launch/sim.launch.py @@ -30,7 +30,12 @@ def generate_launch_description(): ) ], ), - launch_arguments=[("use_sim_time", use_sim_time)], + launch_arguments=[ + ("use_sim_time", use_sim_time), + ("ros2_control_plugin", "gz_ros2_control/GazeboSimSystem"), + ("use_gazebo_ros2_control", "true"), + ("start_controller_manager", "false"), + ], ) # launch all the gazebo stuff diff --git a/src/simulator/resource/rover.urdf.xacro.xml b/src/simulator/resource/rover.urdf.xacro.xml index b4a654d8..8c13a907 100644 --- a/src/simulator/resource/rover.urdf.xacro.xml +++ b/src/simulator/resource/rover.urdf.xacro.xml @@ -1,5 +1,7 @@ + +