๐ก Raycaster Sensors#
The Raycaster family measures distance by casting rays into the scene and detecting intersections with geometry. Concrete sensors are Lidar (returns the full ray hit set) and DepthCamera (returns the hits formatted as a depth image). The number of rays and their directions are controlled by a RaycastPattern.
Lidar and DepthCamera#
lidar = scene.add_sensor(
gs.sensors.Lidar(
pattern=gs.sensors.SphericalPattern(),
entity_idx=robot.idx, # attach to a rigid entity
pos_offset=(0.3, 0.0, 0.1), # offset from attached entity
return_world_frame=True, # return points in world frame (else local frame)
)
)
depth_camera = scene.add_sensor(
gs.sensors.DepthCamera(
pattern=gs.sensors.DepthCameraPattern(
res=(480, 360), # image resolution (width, height)
fov_horizontal=90, # field of view in degrees
fov_vertical=40,
),
)
)
scene.build()
scene.step()
lidar.read() # NamedTuple(points=..., distances=...)
depth_camera.read_image() # tensor (height, width) of distances
The example script at examples/sensors/lidar_teleop.py demonstrates a raycaster sensor mounted on a robot. Set --pattern to spherical for a Lidar-like pattern, grid for a planar grid pattern, or depth for a depth camera.
Running python examples/sensors/lidar_teleop.py --pattern depth:
Common options#
gs.sensors.Lidar(
pattern=pattern,
entity_idx=robot.idx,
pos_offset=(0.0, 0.0, 0.15),
euler_offset=(0.0, 0.0, 0.0),
max_range=100.0,
min_range=0.1,
return_world_frame=True,
draw_debug=True,
)
Patterns#
Pattern |
Use case |
|---|---|
|
3D LiDAR (Velodyne, Ouster) |
|
Depth cameras (RealSense, Kinect) |
|
Planar sensing, height maps |
SphericalPattern (LiDAR)#
# 360ยฐ horizontal, 60ยฐ vertical FOV
pattern = gs.sensors.SphericalPattern(
fov=(360.0, 60.0),
n_points=(128, 32),
)
lidar = scene.add_sensor(
gs.sensors.Lidar(
pattern=pattern,
entity_idx=robot.idx,
pos_offset=(0.0, 0.0, 0.15),
max_range=100.0,
min_range=0.1,
draw_debug=True,
)
)
Parameters:
gs.sensors.SphericalPattern(
fov=(360.0, 60.0), # (horizontal, vertical) degrees
n_points=(128, 64), # (horizontal, vertical) rays
angular_resolution=(0.25, 0.5), # alternative: degrees per ray
angles=(h_angles, v_angles), # custom angle arrays
)
Real-world LiDAR configurations:
# Velodyne VLP-16
velodyne = gs.sensors.SphericalPattern(fov=(360.0, 30.0), n_points=(1800, 16))
# Front-facing 120ยฐ FOV
front_lidar = gs.sensors.SphericalPattern(fov=((-60, 60), 30.0), n_points=(128, 32))
DepthCameraPattern#
pattern = gs.sensors.DepthCameraPattern(
res=(640, 480),
fov_horizontal=87.0,
)
depth_cam = scene.add_sensor(
gs.sensors.DepthCamera(
pattern=pattern,
entity_idx=robot.idx,
pos_offset=(0.0, 0.0, 0.05),
max_range=5.0,
)
)
Parameters:
gs.sensors.DepthCameraPattern(
res=(640, 480), # resolution (width, height)
fov_horizontal=90.0, # horizontal FOV degrees
fov_vertical=None, # auto-computed from aspect ratio
fx=None, fy=None, # focal lengths (override FOV)
cx=None, cy=None, # principal point
)
GridPattern#
Planar grid of parallel rays:
pattern = gs.sensors.GridPattern(
resolution=0.1, # 10 cm spacing
size=(2.0, 2.0), # 2 m x 2 m grid
direction=(0.0, 0.0, -1.0), # pointing down
)
Reading data#
data = lidar.read()
points = data.points # shape: (n_h, n_v, 3)
distances = data.distances # shape: (n_h, n_v)
depth_image = depth_cam.read_image() # shape: (H, W)
Multi-environment#
scene.build(n_envs=4)
data = lidar.read()
print(data.points.shape) # (4, n_h, n_v, 3)