LiDARNEORACER DOCS
These docs are public and open source.Edit on GitHub
HARDWARE / SENSORS

THE PLANAR LIDAR.

A Richbeam LakiBeam1 planar laser scanner on top of the car. Your code reads it as ~1440 distances in centimetres, 0.25° apart, index 0 straight ahead. The array covers the full circle; the sensor's live window is 270°, so the rear wedge reads 0.

Same degrees in Playground (sim)0 Hz0 m range~0 samples270° live windowframe_id: laser
FIG. A / COORDINATE FRAME
135°225°0° forward · idx 090° right · idx 360rear wedge 135°–225° · blind, reads 0270° left · idx 108016 m8 m25 m max
The scan array starts at index 0 (forward) and rotates clockwise. The rear arc (around 180°) is occluded by the chassis and returns 0.
01 / SAMPLE LAYOUT

THE SCAN LAYOUT.

The full scan is one flat list. Index 0 is forward; the list wraps clockwise. To look at a direction, convert your angle to an index with one of the helpers below, or use rc_utils.get_lidar_average_distance(scan, angle, window_angle) and let it do the maths for you.

python
scan = rc.lidar.get_samples() # ~1440 floats on the car, 720 in the sim print(len(scan)) # use this, never a hardcoded count print(scan[0]) # cm, straight forward print(scan[len(scan) // 4]) # cm, 90° right on any platform # For any other direction, let the helper do the index math: left = rc_utils.get_lidar_average_distance(scan, 270, window_angle=8) # 90° left front = rc_utils.get_lidar_average_distance(scan, 0, window_angle=4)
02 / WHAT TRIPS PEOPLE UP

COMMON PITFALLS.

01

The rear is blind

Samples roughly 135° to 225° (around the back) return zero.
The chassis occludes the scanner there, so any control loop that divides by a sample without checking it will blow up at the rear. The helpers already skip the zero samples for you, which is the easy way to stay clear of this.
02

Centimetres, not metres

The same as racecar-neo-library on the real car.
Picking cm or m once at the top of your script and staying with it keeps things honest. Switching units mid-loop is a common way for the gains to drift, and then the wobble is hard to trace back to the cause.
03

Sample rate ≠ control rate

The scanner runs at 30 Hz. Your loop probably runs faster.
Reading get_samples() twice in the same frame returns the same list, which is fine. Just keep in mind that the loop's deltas aren't 30 Hz samples, so averaging them as if they were will give you the wrong picture.
03 / PYTHON API

THE PYTHON API.

  • rc.lidar.get_samples() → NDArray[Float] · the raw scan in cm, ~1440 samples on the car.
  • rc_utils.get_lidar_average_distance(scan, angle, window_angle=4) · average over a degree window. Skips blind-arc zeros for you.
  • rc_utils.get_lidar_closest_point(scan, window=(0, 360)) · returns (angle_deg, distance_cm).
04 / ROS 2

THE /scan TOPIC.

// ros2 topic info /scan
Type:   sensor_msgs/msg/LaserScan
Rate:   30 Hz
Frame:  laser
QoS:    Reliable, Volatile, depth 10
05 / THE SCANNER ITSELF

RICHBEAM LAKIBEAM1.

The scanner is an off-the-shelf Richbeam LakiBeam1. If you ever want the raw datasheet numbers straight from the source, the Richbeam LakiBeam product page is the place to go. These are the sensor's native numbers: it spins at 0.25° resolution, ~1440 samples per revolution, and the library hands you that scan as-is. Nothing is resampled; the 270° live window is a sensor setting, and the rear wedge outside it reads 0.

Live window
270° (rear wedge reads 0)
Angular resolution
0.25° native
Samples per scan
~1440 per revolution
Scan rate
30 Hz
Range
≥25 m @ 90%, ≥15 m @ 10%
Range accuracy
±2 cm
Laser wavelength
940 nm (Class 1, eye-safe)
Interface
USB-C bridge (UDP/IP, sensor at 192.168.8.2)