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

THE PLANAR LIDAR.

A Richbeam LakiBeam1 planar laser scanner mounted in front of the chassis. Your code reads it as 720 distances in centimetres, 0.5° apart, index 0 straight ahead. The same 720-float buffer the racecar-neo-library hands you in the Playground sim and on the car.

Runs unchanged in Playground (sim)0 Hz0 m range0 samples270° FOVframe_id: lidar_link
FIG. A / COORDINATE FRAME
0° forward · idx 090° right · idx 180180° blind · returns 0270° left · idx 54016 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() # NDArray[720, Float], len == 720 print(len(scan)) # 720 print(scan[0]) # cm, straight forward print(scan[180]) # cm, 90° right (0.5° per index) # 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 160° to 200° (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[720, Float] · the raw 720-sample scan in cm.
  • 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:  lidar_link
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, about 1080 points across the arc. The racecar-neo-library resamples that to the fixed 720-float, 0.5° scan your code actually reads, which is why every example above says 720.

Field of view
270°
Angular resolution
0.25° native
Samples per scan
1080 raw / 720 API
Scan rate
30 Hz
Range
≥25 m @ 90%, ≥15 m @ 10%
Range accuracy
±2 cm
Laser wavelength
940 nm (Class 1, eye-safe)
Interface
100 Mbps Ethernet (UDP)