Lidar

Rays cast from the car on every sample, with the same point cast the car’s own physics uses, so they see what the car would: the track and the items on it, never the car itself. The cast is read-only: a gym with a lidar drives exactly as one without.

Pass a Lidar to Session.connect() and read the result as Telemetry.lidar, a LidarScan. For a one-off cast, call Gym.raycast() with the same Ray objects a lidar is made of.

from tickgym import Lidar, TelemetryGroup

# 32 rays over 270 degrees, level, up to 200 m.
lidar = Lidar.fan(rays=32, fov_degrees=270, range_m=200)
with session.connect(TelemetryGroup.RACE | TelemetryGroup.VEHICLE, lidar) as gym:
    t = gym.reset()
    print(t.lidar.distance, t.lidar.hit)

A ray is given in the car frame by default, X right, Y up, Z forward, and rides with the car; a world-frame ray stays where it is. The factories and Ray.at() take a direction as an azimuth, 0 forward and positive left, and an elevation, positive up, in degrees.

class Lidar(rays: tuple[Ray, ...])

The rays a gym casts on every sample; the scan is Telemetry.lidar, one entry per ray in this order. Build one with fan(), grid() or directions(), or give the rays yourself. The car frame is X right, Y up, Z forward.

rays: tuple[Ray, ...]

The rays, in the order the scan reports them.

property ray_count: int

How many rays.

static fan(
rays: int,
fov_degrees: float = 270.0,
range_m: float = 200.0,
elevation_degrees: float = 0.0,
origin: tuple[float, float, float] = (0.0, 0.5, 0.0),
) → Lidar

A horizontal fan.

Parameters:
  • rays – How many rays, spread evenly over the field of view.

  • fov_degrees – The field of view, centred on forward.

  • range_m – How far a ray reaches, in metres.

  • elevation_degrees – The fan’s elevation; 0 is level.

  • origin – Where the rays start, in metres in the car frame.

static grid(
azimuths: int,
elevations: int,
fov_degrees: float = 270.0,
elevation_span_degrees: float = 30.0,
range_m: float = 200.0,
origin: tuple[float, float, float] = (0.0, 0.5, 0.0),
) → Lidar

Several fans stacked at evenly spaced elevations.

Parameters:
  • azimuths – Rays per fan.

  • elevations – How many fans.

  • fov_degrees – Each fan’s field of view, centred on forward.

  • elevation_span_degrees – The elevations run from minus half of this to plus half.

  • range_m – How far a ray reaches, in metres.

  • origin – Where the rays start, in metres in the car frame.

static directions(
azimuth_degrees: Sequence[float],
elevation_degrees: Sequence[float] | float = 0.0,
range_m: float = 200.0,
origin: tuple[float, float, float] = (0.0, 0.5, 0.0),
) → Lidar

Rays in the directions given.

Parameters:
  • azimuth_degrees – One azimuth per ray.

  • elevation_degrees – One elevation per ray, or one for all.

  • range_m – How far a ray reaches, in metres.

  • origin – Where the rays start, in metres in the car frame.

class Ray(
origin: tuple[float, float, float],
direction: tuple[float, float, float],
range_m: float = 200.0,
frame: RayFrame = RayFrame.CAR,
)

One ray: where it starts, which way it points, how far it reaches, and the frame it is given in. A car-frame ray rides with the car; a world-frame ray stays where it is.

origin: tuple[float, float, float]

Where the ray starts, in metres.

direction: tuple[float, float, float]

The unit direction it travels.

range_m: float = 200.0

How far it reaches, in metres.

frame: RayFrame = 0

the car’s, or the world’s.

Type:

The frame origin and direction are in

static at(
azimuth_degrees: float,
elevation_degrees: float = 0.0,
range_m: float = 200.0,
origin: tuple[float, float, float] = (0.0, 0.5, 0.0),
) → Ray

A car-frame ray by direction: azimuth 0 is forward and positive turns left; elevation is positive up.

Parameters:
  • azimuth_degrees – The turn from forward, in degrees.

  • elevation_degrees – The rise from level, in degrees.

  • range_m – How far the ray reaches, in metres.

  • origin – Where it starts, in metres in the car frame.

class RayFrame(value)
CAR = 0
WORLD = 1