Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions dave_interfaces/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(gz-cmake3 REQUIRED)
find_package(gz-msgs10 REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
"msg/UsblCommand.msg"
Expand Down
84 changes: 84 additions & 0 deletions gazebo/DEMO_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Multibeam Sonar Demo Guide

Build and run the GPU multibeam sonar demo. The plugin supports wgpu (Vulkan), CUDA (NVIDIA), and CPU backends—pick one at launch without recompiling.

## Setup

**Prerequisites:**
- Ubuntu 24.04
- ROS 2 Rolling
- Gazebo Jetty (gz-sim 10)
- Rust/Cargo
- Vulkan driver
- CUDA 12+ (if using the CUDA backend)

Clone and check out the branch:
```bash
git clone https://github.com/naitikpahwa18/dave.git
cd dave
git checkout wgpu_integration
```

## Build

Build in two steps on a fresh clone (the Rust library must be ready before the plugin can link to it):

```bash
source /opt/ros/rolling/setup.bash

# Step 1: build and install the Rust library
colcon build --packages-select wgpu_vendor
source install/setup.bash

# Step 2: build the plugin and everything else
colcon build --packages-select dave_demos dave_worlds dave_interfaces multibeam_sonar multibeam_sonar_system dave_multibeam_sonar_demo dave_sensor_models
source install/setup.bash
```

On subsequent builds, you can run all packages in one command.

## Run

```bash
ros2 launch dave_multibeam_sonar_demo multibeam_sonar_demo.launch.py compute_backend:=wgpu
```

Use `compute_backend:=cuda` for CUDA, `compute_backend:=cpu` for CPU, or `compute_backend:=auto` to pick the best available (tries wgpu -> cuda -> cpu).

You'll see RViz2 launch with a point cloud display. The sonar fan should update in real time. Check the terminal for initialization messages and per-frame timing.

## Troubleshooting

**`Could not find wgpu_vendorConfig.cmake`** -> You skipped Step 1. Build `wgpu_vendor` first, source install, then build the rest.

**`Another world of the same name is running`** -> Kill stale Gazebo with `pkill -9 -f gz` and try again.

**CUDA backend won't initialize** -> Run `nvidia-smi` to check if the driver is loaded. If not, reinstall or reload with `sudo modprobe nvidia`.


## How It Works

Each frame, Gazebo renders depth and surface normals. The sonar plugin reads these and runs acoustic physics on your selected backend. The wgpu backend dispatches four compute shaders: backscatter (acoustic return per ray), convert (fixed-point i32 -> f32), matmul (beam correction), and FFT (range compression). Output goes to ROS 2 topics as a point cloud and sonar image via ros_gz_bridge. The Rust library compiles to a static library linked into the C++ Gazebo plugin via C FFI.

## Data Flow

**Pipeline stages:**

1. **Input Buffers** - CPU writes depth, normal maps, reflectivity, window function, beam correction matrix
2. **backscatter.wgsl** - Computes acoustic return per ray using Lambert model, outputs to atomic accumulators
3. **convert.wgsl** - Converts fixed-point i32 results to f32
4. **matmul.wgsl** - Applies beam correction matrix to each beam
5. **fft.wgsl** - Performs in-place FFT with zero-padding to power-of-2 for range compression
6. **Readback** - CPU reads first n_freq bins from staging buffers
7. **Output** - Results published to ROS 2 as point cloud and sonar image

**Buffer details:**

| Buffer | Dimensions | Type | Usage |
|--------|-----------|------|-------|
| depth_buf, normal_buf, refl_buf | n_beams × n_rays | f32 | Input from Gazebo |
| out_re_i32, out_im_i32 | n_beams × n_freq | i32 | Atomic accumulators (zeroed each frame) |
| mm_re_in, mm_im_in | n_beams × n_freq | f32 | After convert pass |
| mm_re_out, mm_im_out | n_beams × n_freq | f32 | After beam correction |
| p_re_buf, p_im_buf | n_beams × fft_len | f32 | FFT input/output (zero-padded) |
| stg_re, stg_im | n_beams × fft_len | f32 | Staging for CPU readback |
174 changes: 102 additions & 72 deletions gazebo/dave_gz_multibeam_sonar/multibeam_sonar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,72 +9,99 @@ set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS TRUE CACHE BOOL

cmake_policy(SET CMP0144 NEW)

project(multibeam_sonar)
set(CUDA_ARCHITECTURE "native" CACHE STRING "Target CUDA SM version(s), e.g. native or 70;80;89")
set(CMAKE_CUDA_ARCHITECTURES "${CUDA_ARCHITECTURE}")

set(CUDA_ARCHITECTURE "60" CACHE STRING "Target CUDA SM version")
Comment thread
naitikpahwa18 marked this conversation as resolved.
project(multibeam_sonar)

find_package(ament_cmake REQUIRED)
find_package(gz-cmake REQUIRED)
find_package(gz-sim REQUIRED)
find_package(gz-sensors REQUIRED)
find_package(gz-rendering REQUIRED OPTIONAL_COMPONENTS ogre ogre2)
find_package(gz-transport REQUIRED)
find_package(gz-msgs REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(OpenCV REQUIRED)
find_package(marine_acoustic_msgs REQUIRED)
find_package(cv_bridge REQUIRED)
find_package(wgpu_vendor REQUIRED)
find_package(CUDAToolkit QUIET)

if(CUDAToolkit_FOUND)

set(CMAKE_CUDA_COMPILER "${CUDAToolkit_NVCC_EXECUTABLE}" CACHE FILEPATH "CUDA compiler" FORCE)
enable_language(CUDA)
find_package(CUDA REQUIRED)
message(STATUS "CUDA found, enabling CUDA support.")
message(STATUS "CUDA ${CUDAToolkit_VERSION} found (SM ${CUDA_ARCHITECTURE}), enabling CUDA support.")
include_directories(${CUDA_INCLUDE_DIRS})
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -arch=sm_${CUDA_ARCHITECTURE}")
find_package(gz-cmake3 REQUIRED)
find_package(gz-sim8 REQUIRED)
find_package(gz-sensors8 REQUIRED)
find_package(gz-rendering8 REQUIRED OPTIONAL_COMPONENTS ogre ogre2)
find_package(gz-transport13 REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(OpenCV REQUIRED)
find_package(marine_acoustic_msgs REQUIRED)
find_package(cv_bridge REQUIRED)

set(GZ_MSGS_VER ${gz-msgs10_VERSION_MAJOR})
set(GZ_RENDERING_VER ${gz-rendering8_VERSION_MAJOR})
set(GZ_SENSORS_VER ${gz-sensors8_VERSION_MAJOR})
set(GZ_TRANSPORT_VER ${gz-transport13_VERSION_MAJOR})
set(GZ_SIM_VER ${gz-sim8_VERSION_MAJOR})

if(TARGET gz-rendering${GZ_RENDERING_VER}::ogre)
set(HAVE_OGRE TRUE)
set(GZ_RENDERING_TARGET gz-rendering${GZ_RENDERING_VER}-ogre)
add_definitions(-DWITH_OGRE)
endif()
endif()

if(TARGET gz-rendering${GZ_RENDERING_VER}::ogre2)
set(HAVE_OGRE2 TRUE)
set(GZ_RENDERING_TARGET gz-rendering${GZ_RENDERING_VER}-ogre2)
add_definitions(-DWITH_OGRE2)
endif()
if(TARGET gz-rendering::ogre)
add_definitions(-DWITH_OGRE)
endif()
if(TARGET gz-rendering::ogre2)
add_definitions(-DWITH_OGRE2)
endif()

add_library(${PROJECT_NAME}
SHARED
MultibeamSonarSensor.cc
sonar_calculation_cuda.cu
)
set(SONAR_SOURCES
MultibeamSonarSensor.cc
sonar_compute_cpu.cc
sonar_compute_wgpu.cc
sonar_compute_cuda.cc
)

if(CUDAToolkit_FOUND)
list(APPEND SONAR_SOURCES sonar_calculation_cuda.cu)
endif()

add_library(${PROJECT_NAME} SHARED ${SONAR_SOURCES})

if(CUDAToolkit_FOUND)
set_target_properties(${PROJECT_NAME}
PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
)
target_compile_definitions(${PROJECT_NAME} PRIVATE DAVE_HAS_CUDA_BACKEND=1)
endif()

target_include_directories(${PROJECT_NAME}
PUBLIC
${gz-sensors${GZ_SENSORS_VER}_INCLUDE_DIRS}
${gz-rendering${GZ_RENDERING_VER}_INCLUDE_DIRS}
${gz-msgs${GZ_MSGS_VER}_INCLUDE_DIRS}
${CUDA_INCLUDE_DIRS}
${gz-transport${GZ_TRANSPORT_VER}_INCLUDE_DIRS}
${gz-sim${GZ_SIM_VER}_INCLUDE_DIRS}
)
target_include_directories(${PROJECT_NAME} PUBLIC
${gz-sensors_INCLUDE_DIRS}
${gz-rendering_INCLUDE_DIRS}
${gz-msgs_INCLUDE_DIRS}
${gz-transport_INCLUDE_DIRS}
${gz-sim_INCLUDE_DIRS}
${rclcpp_INCLUDE_DIRS}
${sensor_msgs_INCLUDE_DIRS}
${geometry_msgs_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${marine_acoustic_msgs_INCLUDE_DIRS}
${cv_bridge_INCLUDE_DIRS}
)

target_link_libraries(${PROJECT_NAME}
gz-sim::gz-sim
gz-sensors::gz-sensors
gz-msgs::gz-msgs
gz-transport::gz-transport
gz-rendering::gz-rendering
${rclcpp_LIBRARIES}
${sensor_msgs_LIBRARIES}
${geometry_msgs_LIBRARIES}
${OpenCV_LIBS}
${marine_acoustic_msgs_LIBRARIES}
)

if(TARGET cv_bridge::cv_bridge)
target_link_libraries(${PROJECT_NAME} cv_bridge::cv_bridge)
elseif(TARGET cv_bridge)
target_link_libraries(${PROJECT_NAME} cv_bridge)
elseif(cv_bridge_LIBRARIES)
target_link_libraries(${PROJECT_NAME} ${cv_bridge_LIBRARIES})
endif()

if(CUDAToolkit_FOUND)
find_library(CUBLAS_LIB cublas
HINTS
${CUDAToolkit_LIBRARY_DIR}
Expand All @@ -85,39 +112,42 @@ if(CUDAToolkit_FOUND)
if(NOT CUBLAS_LIB)
message(FATAL_ERROR "cuBLAS not found")
endif()

target_link_libraries(${PROJECT_NAME}
${CUDA_LIBRARIES}
${CUDA_CUFFT_LIBRARIES}
${CUBLAS_LIB}
)
endif()

install(TARGETS ${PROJECT_NAME}
DESTINATION lib/${PROJECT_NAME}
)

ament_target_dependencies(${PROJECT_NAME}
gz-sensors${GZ_SENSORS_VER}
${GZ_RENDERING_TARGET}
gz-msgs${GZ_MSGS_VER}
gz-transport${GZ_TRANSPORT_VER}
gz-sim${GZ_SIM_VER}
rclcpp
sensor_msgs
rosidl_default_generators
OpenCV
marine_acoustic_msgs
geometry_msgs
cv_bridge
)
if(TARGET wgpu::wgpu_vendor)
target_link_libraries(${PROJECT_NAME} wgpu::wgpu_vendor)
elseif(TARGET wgpu_vendor)
target_link_libraries(${PROJECT_NAME} wgpu_vendor)
endif()

ament_environment_hooks(
"${CMAKE_CURRENT_SOURCE_DIR}/hooks/${PROJECT_NAME}.dsv.in"
)
# Ensure the Rust static archive is linked into this shared library.
# The exported interface target may not always propagate non-installed imported
# targets across package boundaries in overlay builds.
if(DEFINED wgpu_vendor_DIR)
get_filename_component(_wgpu_vendor_prefix "${wgpu_vendor_DIR}/../../.." ABSOLUTE)
set(_sonar_wgpu_static "${_wgpu_vendor_prefix}/lib/libsonar_wgpu.a")
if(EXISTS "${_sonar_wgpu_static}")
target_link_libraries(${PROJECT_NAME} "${_sonar_wgpu_static}")
endif()
endif()

if(TARGET gz-sensors::gz-sensors-rendering)
target_link_libraries(${PROJECT_NAME} gz-sensors::gz-sensors-rendering)
else()
message(STATUS "CUDA Toolkit not found or disabled: "
"Skipping CUDA-specific targets")
find_library(GZ_SENSORS_RENDERING_LIB gz-sensors-rendering)
if(GZ_SENSORS_RENDERING_LIB)
target_link_libraries(${PROJECT_NAME} ${GZ_SENSORS_RENDERING_LIB})
endif()
endif()

install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

ament_environment_hooks(
"${CMAKE_CURRENT_SOURCE_DIR}/hooks/${PROJECT_NAME}.dsv.in")

ament_package()
Loading