360° LiDAR Rangefinder Digital Twin

The 360° LiDAR Rangefinder Digital Twin (VectorizedLiDAR) provides high-speed, GPU-accelerated ray-marching simulations for multi-rotor UAV obstacle detection and collision avoidance in 3D urban topographies.

Overview & Sensor Geometry

Autonomous UAV navigation in complex urban canyons requires real-time sensing of building facades and vertical structures. The VectorizedLiDAR digital twin equips each UAV with a horizontal radial array of rangefinding beams spanning a full \(360^\circ\) azimuth.

\[\theta_k = \frac{2\pi k}{K}, \quad k \in \{0, 1, \dots, K-1\}\]

where \(K\) is the number of azimuth beams (typically 8, 16, or 32).

Ray-Marching Over ITU-R P.1410 3D Heightmaps

Unlike mesh-based ray-tracing which is computationally intensive on CPU, VectorizedLiDAR implements a tensorized ray-marching algorithm directly against VectorizedUrbanMap 2.5D/3D building elevation matrices:

  1. Radial Sample Points: For each beam \(k\) extending from UAV position \((x_i, y_i, z_i)\), sample coordinates are evaluated at \(S\) discrete radial step fractions:

\[x_s = x_i + s \cdot d_{\max} \cos(\theta_k), \quad y_s = y_i + s \cdot d_{\max} \sin(\theta_k), \quad s \in \left\{\frac{1}{S}, \frac{2}{S}, \dots, 1.0\right\}\]
  1. Heightmap Collision Condition: Obstacle intersection occurs whenever the UAV altitude \(z_i\) falls at or below the local building height:

\[\text{Hit}(s) = \mathbb{I}\left( z_i \le H_{\text{map}}\left(\lfloor x_s \rfloor, \lfloor y_s \rfloor\right) \right)\]
  1. Range Normalization: The normalized distance reading \(d_k \in [0.0, 1.0]\) is determined by the nearest hit distance:

\[d_k = \min \left\{ s \mid \text{Hit}(s) = 1 \right\}\]

If no building is intersected within maximum range \(d_{\max}\), \(d_k = 1.0\) (unobstructed clearance).

Sensor Configuration Parameters

Parameter

Description

Default

Unit

num_beams

Number of radial azimuth beams

8

integer

max_range

Maximum sensor detection range

60.0

meters

n_steps

Ray-marching discretization intervals

15

integer

device

PyTorch execution device (CPU / CUDA)

cpu

device

Observation Space Integration

In the uav_lidar_navigation scenario and POMDP control architectures, the LiDAR vector \(\mathbf{d}_i \in \mathbb{R}^K\) is directly concatenated into the decentralized observation vector:

\[\mathbf{o}_i = \big[ \mathbf{p}_i, \; \mathbf{v}_i, \; \mathbf{p}_{\text{target}} - \mathbf{p}_i, \; \mathbf{d}_i \big]^T \in \mathbb{R}^{9 + K}\]

This provides reinforcement learning agents with local geometric awareness without requiring centralized global heightmap knowledge.

Python Usage Example

import torch
from urbanmarl.models.urban_map import VectorizedUrbanMap
from urbanmarl.models.lidar import VectorizedLiDAR

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 1. Create procedural 3D urban terrain
urban_map = VectorizedUrbanMap(
    batch_size=32,
    volume_size=(500, 500, 50),
    device=device,
)

# 2. Initialize 8-beam LiDAR sensor with 60m maximum range
lidar = VectorizedLiDAR(
    num_beams=8,
    max_range=60.0,
    n_steps=15,
    device=device,
)

# 3. UAV coordinates: shape (batch_size=32, num_uavs=5, 3)
uav_pos = torch.zeros(32, 5, 3, device=device)
uav_pos[..., 2] = 25.0  # flying at altitude 25m

# 4. Perform parallel ray-marching scans
# Output shape: (32, 5, 8) with values in [0.0, 1.0]
lidar_readings = lidar.scan(uav_pos, urban_map)

print(f"LiDAR scan tensor shape: {lidar_readings.shape}")
print(f"UAV 0 Beam Clearances: {lidar_readings[0, 0].cpu().numpy()}")