Overview
BeamNG.tech ships with a simulated Lidar sensor which extracts point clouds from the BeamNG.tech virtual environment. Various control parameters are available to customise the sensor, and it can be positioned on or relative to a vehicle or to a fixed point on the map.
Usage
This sensor runs in various modes, which are chosen using the two flag arguments ‘isRotate’ and ‘is360’:
MODE I: Full 360 Degrees Mode: The LiDAR will return a point cloud covering the full 360 degree sector around the provided ‘up’ vector, with the chosen parameters. This mode should be used if fast, 360 degree updates are required. For fastest results, use shared memory or see the ‘stream()’ functions. Note: There is no need to provide a horizontal angle for this mode, since it will be fixed upon instantiation. Likewise, the direction vector is meaningless when using this mode, since the full 360 degrees will be scanned with every reading. [For this mode, leave the flags as default or switch is360=true, isRotate=false].
MODE II: LFO Mode: The LiDAR will operate in a low-frequency rotating mode and provide readings local to the sector at which it currently points. For best results, the frequency should be in the range [1Hz, 8Hz]. Faster frequencies (on this mode) may cause undersampling in some sectors, so beware! The horizontal angle defines the aperture of the returns in the currently-facing direction, as the LiDAR spins. The direction vector will specify the starting direction only, for this mode. [For this mode, set the flags as follows: is360=false, isRotate=true].
MODE III: Static Mode: The LiDAR will operate in a fixed static pose relative to the vehicle (ie it doesn’t rotate). You can set the horizontal angle and direction and this will remain so for the lifetime of the sensor. The horizontal angle is supported in the range [1, 179] degrees (the full hemisphere, basically). [For this mode, set the flags as follows: is360=false, isRotate=false].
All three LiDAR modes also support the return of semantic annotations (segmentations). This can be switched on with the similarly-named flag (see below).
We can create the Lidar either with shared memory or without, using either of the following commands:
sensorId = extensions.tech_sensors.createLidar(vehicleId, args)
sensorId = extensions.tech_sensors.createLidarWithSharedMemory(vehicleId, args)
This sensor can be attached to a vehicle, or can be fixed to a position in space. The dir and up parameters are used to set the local coordinate system. A requested update rate can be provided, to tell the simulator how often to read measurements for this sensor. If a negative value is provided, the sensor will not update automatically at all. However, ad-hoc polling requests can be sent at any time, even for non-updating sensors.
Args:
vehicleID(int): The vehicle ID. This can be nil if the Lidar is not to be attached to any vehicle.
The args parameter is a Lua table containing as many of the following properties as required. If any property is not set manually then a default value is used, so it is entirely possible to create the Lidar with args being an empty table. What follows is a complete list of these arguments:
isRotate(bool): Runs the LiDAR sensor in ‘LFO rotate’ mode. Should be used with frequencies in the range [1Hz - 10Hz, or so, for best results].
is360(bool): Runs the LiDAR sensor in ‘Full 360 Degrees’ mode. Note: there is no need to provide a horizontal angle for this mode.
updateTime(float): How often the Lidar sensor should update its readings in the simulator (in seconds).
updatePriority(float): A scheduling priority value for this Lidar sensor, in range 0 to 1. 0 is highest priority, 1 is least.
pos(Point3F): The position of the Lidar sensor either in vehicle space (if attached to vehicle) or in world space (if fixed to the map).
dir(Point3F): The forward direction in which the Lidar sensor points.
up(Point3F): The up direction of the Lidar sensor.
verticalResolution(int): The vertical resolution of the Lidar sensor.
verticalAngle(float): The vertical angle (field of view), in radians.
frequency(float): The frequency (refresh rate).
horizontalAngle(float): The horizontal angle (field of view), in radians.
maxDistance(float): The maximum distance at which the Lidar sensor can detect, in metres.
isVisualised(bool): A flag which indicates if the Lidar sensor should be visualised.
isAnnotated(bool): A flag which indicates if the Lidar sensor should be annotated (uses Annotation Mode if true, otherwise uses Depth Mode).
isStatic(bool): True if the Lidar sensor is fixed to a point on the map, false if it is attached to a vehicle.
isSnappingDesired(bool): True if the Lidar sensor position should be forced onto the surface of the vehicle, at its closest vehicle point. This is useful if finding it hard to have the Lidar on the vehicle itself. False, otherwise, eg if the Lidar should be suspended at a fixed point relative to the vehicle.
isForceInsideTriangle(bool): Used with isSnappingDesired. True, if the Lidar should be forced to be inside its nearest vehicle triangle. Otherwise false.
The following extra parameters are used if the Lidar sensor should be configured to use shared memory (if the command createLidarWithSharedMemory() is used):
pointCloudShmemName(string): The name of the shared memory handle used for sending the Lidar point cloud data.
pointCloudShmemSize(int): The size of the shared memory block used for sending the Lidar point cloud data.
colourShmemName(string): The name of the shared memory handle used for sending the Lidar colour data.
colourShmemSize(int): The size of the shared memory block used for sending the Lidar colour data.
Returns: sensorId(int): The unique Id number of this sensor, in order to refer to it later eg when closing it.
points = extensions.tech_sensors.getLidarPointCloud(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: table(Point3F): The most-recent point cloud data from the Lidar sensor.
sensorPosition = extensions.tech_sensors.getLidarSensorPosition(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: sensorPosition(Point3F): The current world-space position of the Lidar sensor.
sensorDirection = extensions.tech_sensors.getLidarSensorDirection(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: sensorDirection(Point3F): The current direction of the Lidar sensor.
verticalResolution = extensions.tech_sensors.getLidarVerticalResolution(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: verticalResolution(int): The vertical resolution of the Lidar.
frequency = extensions.tech_sensors.getLidarFrequency(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: frequency(float): The frequency (refresh rate) of the Lidar.
isVisualised = extensions.tech_sensors.getLidarIsVisualised(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: isVisualised(bool): A flag which indicates if the Lidar is being visualised or not.
isAnnotated = extensions.tech_sensors.getLidarIsAnnotated(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: isAnnotated(bool): A flag which indicates if the Lidar has annotations switched on or not.
maxPendingGpuRequests = extensions.tech_sensors.getLidarMaxPendingGpuRequests(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: maxPendingGpuRequests(int): The maximum number of pending GPU requests for this Lidar sensor.
requestedUpdateTime = extensions.tech_sensors.getLidarRequestedUpdateTime(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: requestedUpdateTime(float): The current requested update time used by this Lidar sensor.
updatePriority = extensions.tech_sensors.getLidarUpdatePriority(sensorId)
Args:
sensorId(int): The Id number of the Lidarsensor.
Returns: updatePriority(float): The current update priority used by this Lidar sensor.
extensions.tech_sensors.setLidarVerticalResolution(sensorId, verticalResolution)
Args:
sensorId(int): The Id number of the Lidar sensor.
verticalResolution(int): The new vertical resolution of the Lidar.
Returns: nil.
extensions.tech_sensors.setLidarFrequency(sensorId, frequency)
Args:
sensorId(int): The Id number of the Lidar sensor.
frequency(float): The new frequency of the Lidar.
Returns: nil.
extensions.tech_sensors.setLidarMaxDistance(sensorId, maxDistance)
Args:
sensorId(int): The Id number of the Lidar sensor.
maxDistance(float): The new maximum distance at which the Lidar can detect.
Returns: nil.
extensions.tech_sensors.setLidarIsVisualised(sensorId, isVisualised)
Args:
sensorId(int): The Id number of the Lidar sensor.
isVisualised(bool): True if the Lidar should be visualised, otherwise false.
Returns: nil.
extensions.tech_sensors.setLidarIsAnnotated(sensorId, isAnnotated)
Args:
sensorId(int): The Id number of the Lidar sensor.
isAnnotated(bool): True if the Lidar should be annotated, otherwise false.
Returns: nil.
extensions.tech_sensors.setLidarMaxPendingGpuRequests(sensorId, maxPendingGpuRequests)
Args:
sensorId(int): The Id number of the Lidar sensor.
maxPendingGpuRequests(int): The new maximum number of pending GPU requests for this Lidar sensor.
extensions.tech_sensors.setLidarRequestedUpdateTime(sensorId, requestedUpdateTime)
Args:
sensorId(int): The Id number of the Lidar sensor.
requestedUpdateTime(float): The new requested update time for this Lidar sensor.
extensions.tech_sensors.setLidarUpdatePriority(sensorId, updatePriority)
Args:
sensorId(int): The Id number of the Lidar sensor.
updatePriority(float): The new update priority for this Lidar sensor.
The following three functions can be used to send ad-hoc polling requests to a Lidar sensor. This is when we just want an occasional reading. We need to first send a request using sendLidarRequest
, then wait for it. We can check it is complete using isRequestComplete
(see below), then retrieve it using collectLidarRequest
.
requestId = extensions.tech_sensors.sendLidarRequest(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor.
Returns: The unique Id number of the ad-hoc sensor polling request which is being sent.
isComplete = extensions.tech_sensors.isRequestComplete(requestId)
Args:
requestId(int): The Id number of the ad-hoc sensor polling request to check on.
Returns: isComplete(bool): True if the ad-hoc polling request has been completed, otherwise false.
data = extensions.tech_sensors.collectLidarRequest(requestId)
Args:
requestId(int): The Id number of the ad-hoc sensor polling request.
Returns: data(table): The Lidar readings.
extensions.tech_sensors.removeSensor(sensorId)
Args:
sensorId(int): The Id number of the Lidar sensor to remove.
Returns: nil.