racecar-neo-libraryNEORACER DOCS
NEORACER DOCS
These docs are public and open source.Edit on GitHub
SOFTWARE / RACECAR-NEO-LIBRARY

THE PYTHON LIBRARY.

racecar-neo-library is the Python module every student writes against. Five modules under an rc.* namespace, with identical signatures in the NeoRacer Playground browser simulator and on the physical car. The same file works in both places.

Sim ↔ car portable0 modulesset_start_update + goPyodide-compatible
0 Hz
LiDAR scan rate
0
get_samples() length
0 Hz
IMU sample rate
0
× 480, colour + depth
Camera frame width
FIG. A / SIM TO CAR, ONE TRUNK
//Playground (sim)
Three.js
WebGL physics + render
Web Worker
postMessage sensor data
Pyodide
CPython, WASM-compiled
Playground Sim
simulated LiDAR · camera · IMU
//Your Python
ONE API
rc.*
lidar · camera · imu
drive · controller
in browser
on car
The same student script runs in both runtimes unchanged.
//NeoRacer (car)
racecar-neo-library
Python shim, ROS 2 client
ROS 2 Humble
topics · services · params
Jetson Orin Nano
Ubuntu · 67 TOPS
Hardware
LiDAR · camera · IMU · motors
The red trunk is the rc.* API you write against. Whichever side you run on, the API contract is identical: same names, same shapes, same units.
01 / MODULES AT A GLANCE

THE FIVE MODULES.

Click any module to see the methods it exposes. Every behaviour you'll ever ship (, wall follow, gap follower, end-to-end RL) is some combination of these five.

rc.lidar
The 270° world map you steer by.
rc.lidar.get_samples()The latest 720-float scan, centimetres, 0.5° apart. Index 0 is dead ahead.
rc_utils.get_lidar_average_distance(scan, angle)In racecar_utils. Mean range over a small angle window, for noise-robust gap finding.
rc_utils.get_lidar_closest_point(scan)In racecar_utils. The (angle, distance) of the nearest return.
02 / WHAT THE SCAN LOOKS LIKE

THE LIDAR SCAN.

0° FORWARDlidar_link000° · 30 Hz

The sweep on the left is what the scanner is doing while you read this. Each tick mark is one of the 720 samples get_samples() hands you. The full coordinate frame and array layout live on the LiDAR hardware page.

  • Index 0 is dead ahead. Index 360 is directly behind. The array sweeps clockwise.
  • Samples come back in centimetres. A 0 means no return inside the range gate.
  • One scan arrives every ~33 ms. Reading it inside update() is fast enough for any you'll write.
FIG. B / THE LIFECYCLE
start()update()EVERY FRAMEPER-TICKget_delta_time()READ rc.lidar / camera / imu / controllerWRITE rc.drive.set_speed_angle(...)
start() runs once when the script loads. update() runs every frame after that. You wire both in with rc.set_start_update(start, update), then call rc.go() at the bottom of the file and the runtime handles the rest.
03 / HELLO WORLD, DRIVE A SQUARE

DRIVE A SQUARE.

The smallest interesting program. The Python tab is the file you save. The other two tabs show how to run it in the Playground or on the car.

python
import racecar_core

rc = racecar_core.create_racecar()

SIDE_TIME = 1.0   # seconds per straight leg
TURN_TIME = 0.7   # seconds per 90-degree turn
SPEED = 0.25      # 25% throttle
TURN = 1.0        # full lock

timer = 0.0
leg = 0           # 8 legs: even legs drive straight, odd legs turn

def start():
    global timer, leg
    timer, leg = 0.0, 0
    rc.drive.stop()

def update():
    global timer, leg
    if leg >= 8:                     # four straights + four turns
        rc.drive.stop()
        return
    timer += rc.get_delta_time()     # seconds since the last frame
    if leg % 2 == 0:
        rc.drive.set_speed_angle(SPEED, 0)
        if timer > SIDE_TIME:
            leg, timer = leg + 1, 0.0
    else:
        rc.drive.set_speed_angle(SPEED, TURN)
        if timer > TURN_TIME:
            leg, timer = leg + 1, 0.0

rc.set_start_update(start, update)
rc.go()
FIG. C / EXPECTED PATH
START1 m1 m1 m1 mHELLOrc.drive4 EDGES
Floor view. Square sides are about 1 m at the suggested speed. If your room is smaller, lowering SIDE_TIME shrinks the square to fit.
04 / TWO WAYS TO SHIP

TWO WAYS TO SHIP.

The Playground is the comfortable place to iterate until you trust the behaviour, and the same file then runs on the car without a single change. The runtime swaps the Pyodide-backed sensor sources for the ones for you.

  • In the sim: the flow is to open NeoRacer Playground, paste the script into the editor, and press Run. Pyodide spins up a Web Worker, and your code executes inside it.
  • On the car: SSH in, the file lands in ~/scripts/, and python3 ~/scripts/drive_square.py runs it.