Omniverse Lidar Extension#
Introduction#
The Lidar extension consists of simulation model plugins (currently only one), several utility plugins and different Omnigraph Nodes, where the simulation plugin is a configurable generic lidar model.
The Lidar extension uses the GenericModelOutput as its output format. See the documentation of the Generic Model Output
package for more information on the GenericModelOutput.
The Lidar model is instantiated in the scene as an OmniLidar
prim, with schema attributes and their default values. It uses the following API-Schemas:
OmniSensorGenericLidarCoreAPI
: Defines the core attributes of the Lidar model.OmniSensorGenericLidarCoreEmitterStateAPI:s#
: Defines the emitter state attributes of the Lidar model (default: s001).
Example usage:
def OmniLidar "generic_lidar" (
doc = """Defines an instance of a lidar that uses generic lidar model Core"""
prepend apiSchemas = ["OmniSensorGenericLidarCoreAPI", "OmniSensorGenericLidarCoreEmitterStateAPI:s002"] # s002 only needed for Lidars with second emitter state array
)
{
# ... changing attributes ...
# ... potentially change values of first emitter state array values ...
float[] omni:sensor:Core:emitterState:s001:azimuthDeg = [...] # has to have numberOfEmitters elements
...
# ... adding second emitter state array values ...
# Overwriting second emitter state attributes with prefix "s002".
float[] omni:sensor:Core:emitterState:s002:azimuthDeg = [...] # has to have numberOfEmitters elements
...
def RenderProduct "RenderedOutputs"
{
uniform int2 resolution = (1280, 720)
rel camera = <../../generic_lidar>
rel orderedVars = [
<SupportedOutputs/RtxSensorGmo>,
<SupportedOutputs/RtxSensorMetadata>,
]
def Scope "SupportedOutputs"
{
def RenderVar "RtxSensorGmo"
{
uniform string sourceName = "GenericModelOutput"
}
def RenderVar "RtxSensorMetadata"
{
string sourceName = "RtxSensorMetadata"
}
}
}
}
Setting Lidar Attributes#
There are multiple steps and attributes to set so that the configured Lidar behaves in a specific way. For ease of understanding, this part will omit the preceding omni:sensor:Core:
for every attribute. Additionally, this guideline will only explain the most basic attributes.
Defining Output#
Lidar output is provided as a GenericModelOutput
struct. The following Lidar attributes define that output:
Attribute |
Type |
Description |
---|---|---|
auxOutputType |
token |
Sets the desired level of detail of the output auxiliary data. Allowed tokens: “NONE”, “BASIC”, “EXTRA”, “FULL”. Runtime changes not supported, yet. |
elementsCoordsType |
token |
Sets the desired coordinate system for the output basic elements (not auxiliary data). Allowed tokens: “CARTESIAN”, “SPHERICAL”. Runtime changes not supported, yet. |
outputMotionCompensationState |
token |
Sets the desired motion compensation state for all outputs (including auxiliary data). Allowed tokens: “NONCOMPENSATED”, “COMPENSATED”. Runtime changes not supported, yet. |
outputFrameOfReference |
token |
Sets the desired frame of reference for all outputs (including auxiliary data). Allowed tokens: “SENSOR”, “WORLD”, “CUSTOM”. Runtime changes not supported, yet. |
customFrameOfReferenceTrafo |
float[] |
Used only if outputFrameOfReference = CUSTOM. Defines the transformation for the custom frame of reference. Structured as [x,y,z,roll,pitch,yaw]. Runtime changes not supported, yet. |
Scanning Principle#
The first attribute to set corresponds to the scanning principle of the sensor.
token omni:sensor:Core:scanType
The two allowed tokens and supported scanning principles are: ROTARY
(a rotating Lidar) and SOLID_STATE
(a solid state Lidar, including flash Lidars).
There exist common and exclusive attributes between the two scanning principles. Every attribute explained is a common attribute if not indicated otherwise.
Configuring a Full Firing Pattern#
The second step to configure a Lidar sensor is to set up the firing pattern related attributes. The following attributes are corresponding to the application of the individual emitter state(s) (fixed firing pattern).
Attribute |
Type |
Description |
---|---|---|
scanRateBaseHz |
uint |
Number of full point clouds per second. |
reportRateBaseHz
|
uint
|
Number of times the emitter array (firing pattern) is
applied per second (at different rotation points for
rotary Lidars). For solid state Lidar this should be the
same as the scanRateBaseHz.
|
maxReturns
|
uint
|
Maximum number of returns/detections (correspond to
individual points) per channel.
|
numberOfEmitters
|
uint
|
Number of emitters per emitter state (individual firing
patterns). Corresponds to the length of the arrays in the
emitter states.
|
numberOfChannels
|
uint
|
Number of channels/detectors. Corresponds to the
individual number of detectors (can be different to
numberOfEmitters).
|
emitterStateCount
|
uint
|
Number of different emitter states (firing patterns).
Only needs to be changed for multiple emitter states.
|
stateResolutionStep
|
uint
|
Number of times same firing pattern will be applied until
the state is changed. Only needs to be changed for multiple
emitter states.
|
numLines
|
uint
|
Number of lines in solid state firing pattern. Only needed
for solid state Lidar.
|
numRaysPerLine
|
uint[]
|
Number of points per line. Only needed for solid state
Lidar.
|
For rotary Lidars the reportRateBaseHz
and scanRateBaseHz
correspond to the individual rotation points where the emitter states are applied (referred to as “ticks” here onwards).
For instance, a scanRateBaseHz
of 10 and reportRateBaseHz
of 36000 will result in a tick at every 0.1° (azimuth) for a rotary Lidar.
The following attributes define the individual emitter state (firing pattern applied at every rotation point). “#” is a placeholder for the number of the emitter state starting with a “001” (emitterState:s001:…
)
Attribute |
Type |
Description |
---|---|---|
emitterState:s#:azimuthDeg |
float[] |
Azimuth of the emitter relative to the tick position of the emitter in degrees. |
emitterState:s#:elevationDeg |
float[] |
Elevation of the emitter in degrees. |
emitterState:s#:fireTimeNs |
uint[] |
Delta fire time to the current tick time in nanoseconds |
emitterState:s#:channelId |
uint[] |
Mapping to the corresponding channel/detector |
emitterState:s#:bank |
uint[] |
Line of the emitter (only needed for solid state Lidar) |
emitterState:s#:rangeId |
uint[] |
Corresponding range id of the emitters. Has numberOfEmitters elements or empty. |
emitterState:s#:vertOffsetM |
float[] |
Vertical offset of the emitters in meters. Has numberOfEmitters elements or empty. |
emitterState:s#:horOffsetM |
float[] |
Horizontal offset of the emitters in meters. Has numberOfEmitters elements or empty. |
emitterState:s#:distanceCorrectionM |
float[] |
Distance correction of the emitters in meters. Has numberOfEmitters elements or empty. |
emitterState:s#:focalDistM |
float[] |
Focal distance of the emitters in meters. Has numberOfEmitters elements or empty. |
emitterState:s#:focalSlope |
float[] |
Focal slope of the emitters. Has numberOfEmitters elements or empty. |
emitterState:s#:reportRateDiv |
float[] |
Report rate divisor of the emitters. Has numberOfEmitters elements or empty. DEPRECATED |
emitterState:s#:roi |
bool[] |
Is the emitter part of the ROI. Has numberOfEmitters elements or empty. (ROI - Region of Interest) |
emitterState:s#:isROIState |
bool |
Is the emitter state a ROI state. |
Constraining Field of View#
Attribute |
Type |
Description |
---|---|---|
nearRangeM |
float |
Minimum range to be a valid return in meters. |
farRangeM |
float |
Maximum range to be a valid return in meters. |
validStartAzimuthDeg |
float |
Valid start azimuth in degrees. Only for rotary sensors. Default is 0°. |
validEndAzimuthDeg |
float |
Valid end azimuth in degrees. Only for rotary sensors. Default is 360°. |
Intensity-Defining Attributes#
The following attributes are responsible for generating a sensible intensity measurement. The Lidar model
calculates an intensity value between 0 and 1. Additionally, one can set the omni:sensor:Core:intensityScalePercent
attribute to map this value to a sensor-specific reflectivity value, with default value 255.
Moreover, there also exists the ability to encode a non-linear mapping to emphasize on specific regions of
intensity values (not discussed here).
Attributes which affect the main intensity computation can be grouped into the following three categories:
Point Drops Sensitivity#
The Lidar model calculates the point drops sensitivity (what is seen as a valid point/measurement) based on the two attributes:
Attribute |
Type |
Description |
---|---|---|
minReflectance |
float |
Minimum reflectance value (in %) to get a return at a specified distance. |
minReflectionRangeM |
float |
Range in meters corresponding to the |
Beam Properties#
Attribute |
Type |
Description |
---|---|---|
avgPowerW |
float |
Average power per emitter in watts. |
waveLengthNm |
float |
Wavelength in nanometers. Will also affect the material processing. |
pulseTimeNs |
uint |
Pulse time of the beam in nanoseconds. |
focusDistM |
float |
Focus distance of the beam in meters. |
Msquared |
float |
Msquared value of the beam. Often called the beam quality value. |
divergenceHorDeg |
float |
Horizontal beam divergence angle in degrees. Alternatively one could set the beamWaistHorM value. |
divergenceVerDeg |
float |
Vertical beam divergence angle in degrees. Alternatively one could set the beamWaistVerM value. |
Detector Properties#
Attribute |
Type |
Description |
---|---|---|
aspectRatio |
float |
Aspect ratio of the detector (“squareness of the detector”) |
effectiveApertureSizeM |
float |
Effective aperture size of the sensor in meters. |
quantumEfficiency |
float |
Quantum efficiency of the detector. |
pixelPitch |
float |
Pixel pitch of the detector in microns. |
calibrationGain |
float |
Calibration gain of the detector. |
bitDepthResolution |
float |
Bit depth resolution of the detector. |
Mechanical noise#
Attribute |
Type |
Description |
---|---|---|
azimuthErrorMean |
float |
Mean value of the emitter’s azimuth noise in degrees. |
azimuthErrorStd |
float |
Standard deviation of the emitter’s azimuth noise in degrees. |
elevationErrorMean |
float |
Mean value of the emitter’s elevation noise in degrees. |
elevationErrorStd |
float |
Standard deviation of the emitter’s elevation noise in degrees. |
originErrorMean |
float |
Mean value of the emitter’s origin error in meters. Can be used to model vibrations. |
originErrorStd |
float |
Standard deviation of the emitter’s origin error in meters. Can be used to model vibrations. |
Additional attributes#
As mentioned before there are additional attributes not listed in this section. Some examples are:
Attribute |
Type |
Description |
---|---|---|
beamWaistHorM |
float |
Beam waist horizontal of the sensor in meters. |
beamWaistVerM |
float |
Beam waist vertical of the sensor in meters. |
emitterStatesFile |
string |
File containing the emitter states of the sensor. Not supported, yet. |
intensityMappingDecoding |
float[] |
Intensity mapping decoding. Changing the number of elements at runtime is not supported. |
intensityMappingEncoding |
float[] |
Intensity mapping encoding. Changing the number of elements at runtime is not supported. |
intensityMappingType |
token |
Intensity mapping type. Allowed tokens: “LINEAR”, “NONLINEAR”, “NONLINEAR_ENCODING_ONLY”, “NONLINEAR_DECODING_ONLY”. |
maxAzimuthROI |
float |
End azimuth point of the ROI part of the pattern – in sensor market model frame. |
minAzimuthROI |
float |
Start azimuth point of the ROI part of the pattern – in sensor market model frame. |
minDistBetweenEchosM |
float |
Minimum distance between two echos in meters. |
rangeAccuracyM |
float |
Range accuracy of the sensor in meters. |
rangeCount |
uint |
Number of range regions of the emitters. |
rangeOffsetM |
float |
Range for which objects are invisible – useful for sensors inside objects. |
rangeResolutionM |
float |
Range resolution of the sensor in meters. |
rangesMaxM |
float[] |
Maximum ranges of the emitters in meters. Has rangeCount elements. For per-emitter ranges |
rangesMinM |
float[] |
Minimum ranges of the emitters in meters. Has rangeCount elements. For per-emitter ranges |
reflectionPowerFraction |
float |
Fraction of the reflection power for multiple returns. |
skipDroppingInvalidPoints |
bool |
When false the model will drop invalid (dropped) points. Runtime changes not supported, yet. |
startAzimuthOffsetDeg |
float |
Start azimuth offset angle of the sensor in degrees – in sensor market model frame. |
transmissionPowerFraction |
float |
Fraction of the transmission power for multiple returns. |
marketName |
string |
Market name of the sensor. |
modelName |
string |
Model name of the sensor. |
modelVendor |
string |
Vendor of the sensor model. |
modelVersion |
string |
Version of the sensor model. |
tickRate |
float |
Tick rate of the sensor. |
Atmospheric Modeling#
The Lidar model includes a Mie scattering based atmospheric simulation model, which currently supports rain. It is planned to add fog, haze and snow at a later time.
Besides the wavelength dependency, the rain model has one basic parameter: the rain rate in mm/h (configurable as a carb
setting, /app/sensors/nv/atmospherics/rainRate
).
For instance, a rain rate of 0.25mm/h is light rain, whereas a rain rate of 25mm/h corresponds to a very heavy rain.
Every other parameter for the Mie scattering (e.g., rain drop size distribution) is derived from the rain rate.
Additionally, the rain model provides the possibility to simulate rain drop hits as false positive.
The amount of false positives can be set via a rain drop hit threshold (configurable as a carb
setting: /app/sensors/nv/atmospherics/rainDropHitThresh
).
This threshold is related to the Mie back scattering efficiency parameter and a distance dependent rain drop hit probability distribution.
Both parameters can be set via command line and dynamically via the script editor, as both parameter are defined as carb
settings.
For example, you can start the simulation with a rain rate of 25mm/h by adding --/app/sensors/nv/atmospherics/rainRate=25
to the startup command of kit.
It is important to activate the material framework to get accurate readings from wet roads (point drops) and false positives due to back scattering (under the ground).
LidarPCConverter#
The LidarPCConverter converts the Lidar data stream to an easily usable point cloud (GenericModelOutput format). The interface is defined in the header file ILidarPCConverter.h.
Users can create objects that implement this interface by acquiring the ILidarPCConverterFactory (ILidarPCConverterFactory.h) carbonite interface and using the createInstance() method.
Instantiation#
To instantiate the LidarPCConverter the user needs to acquire the carbonite ILidarPCConverterFactory interface, and use the create instance method:
ILidarPCConverterPtr m_pcConverter = carb::getFramework()->acquireInterface<omni::sensors::lidar::ILidarPCConverterFactory>()->createInstance();
Initialization#
The user has to initialize the converter, with the corresponding converter cfg (omni::sensors::lidar::LidarPCConverterCfg) like this:
m_pcConverter->init(cfg);
Conversion#
The conversion of the buffer differs with the conversion buffer type (PACKETS, GENERIC_FILE (HDF5) or live sensor buffer). In the live sensor buffer the user calls the following function
m_pcConverter->convertBuffer(sensorBuffer, dataSize, numPoints, scanComplete, cudaStream);
Next he can get the point cloud:
LidarPointCloud pc = m_pcConverter->getPointCloud(cudaStream);
The user has to keep in mind, that in live CPU mode the getPointCloud function has to be called in a cudaLaunchHostFunc with the appropriate cudaStream, as every work is scheduled asynchronously.
Omnigraph Nodes#
TranscoderLidar#
Introduction
The Transcoder node encodes the Lidar data stream into vendor specific packets and records them via binary file writing.
Omnigraph Node Name
omni.sensors.nv.lidar.TranscoderLidar
Parameters & Attributes
Parameter Name |
Description |
Value Type |
Value Range |
Default Value |
Example |
---|---|---|---|---|---|
sensorProfileName |
Filename of sensor profile (excluding directory and .json) |
string |
“GENERIC” |
||
returnType |
Desired return type (0 - First, 1 - last, 2 - Strongest, 3 - MultipleReturns) |
int |
3 |
||
dumpPackets |
Dump packets as file |
bool |
false |
||
decoderPath |
Optional path to ndas decoder |
string |
“” |
||
fileName |
Filename of the dumped bin file |
string |
“lidar.h5” |
||
groupName |
Sensor name to be put inside hdf5 file |
string |
“Lidar” |
||
encoderType |
Encoder Type – needed if there are different versions of the sensor (e.g., NCD) |
int |
7 |
||
simTime |
Simulation time given from PostProcessEntryNode |
double |
0 |
||
src |
Sensor buffer id |
uint64 |
0 |
||
srcMeta |
Lidar Meta Data |
uint64 |
0 |
||
cudaStream |
Cuda Stream Input |
uint64 |
0 |
The next node is the LidarPointAccumulator, which accumulates the Lidar data stream and converts it to a point cloud.
LidarPointAccumulator#
Introduction
The LidarPointAccumulator node accumulates the Lidar data stream and converts it to a point cloud.
Omnigraph Node Name
omni.sensors.nv.lidar.LidarPointAccumulator
Parameters & Attributes
Parameter Name |
Description |
Value Type |
Value Range |
Default Value |
Example |
---|---|---|---|---|---|
src |
Input buffer |
uint64 |
0 |
||
cudaStream |
Cuda Stream Input |
uint64 |
0 |
||
srcMeta |
Input meta data buffer |
uint64 |
0 |
||
targetPID |
Target process ID to send data stream to |
uint64 |
0 |
||
exportBytePoints |
Export lidar points |
bool |
false |
||
publishVizPoints |
Export viz points |
bool |
true |
||
desiredCoordsType |
Desired output coords type |
token |
CARTESIAN, SPHERICAL |
“CARTESIAN” |
|
outputOnGPU |
Output on GPU |
bool |
false |
||
sensorMount6DPose |
[x,y,z,r,p,y] |
float[] |
|||
colorCode |
0 - constant, 1 - intensity, 2 - height, 3 - range, 4 - objectId, 5 - echoId, 6 - materialId |
int |
1 |
||
sendDataId |
Send data id to distinguish point clouds on the receiver side |
int |
0 |
Outputs
Output Name |
Description |
Value Type |
Value Range |
Default Value |
Example |
---|---|---|---|---|---|
dest |
Output buffer of accumulated GenericModelOutput |
uint64 |
0 |
||
newData |
True if new data is published |
bool |
false |
||
cudaStream |
Cuda Stream Input |
uint64 |
0 |
Python Bindings and Scripts#
The Lidar extension offers a variety of python bindings and scripts for the Lidar. These can be used for easy post-processing of the simulated Lidar point cloud.
Python Bindings#
The python bindings make it possible to use the Lidar utilities and specific classes in python code. For instance, the user can import the Lidar python bindings in the following way
import omni.sensors.nv.lidar._lidar as lidar
Furthermore, there exist the LidarUtilities script, containing some helper functions for ease of use of the Lidar bindings. The script can be imported, e.g., the following way:
import omni.sensors.nv.lidar.scripts.LidarUtilities as lutil
There are binding definitions for all basic classes and structs of the Lidar and Lidar Tools extension. Furthermore, there are bindings for the utilities like the LidarPCConverter. There is a mode to accumulate and convert udp packets to a Lidar point cloud, but not every sensor is supported. To get a LidarPCConverter object the user can call the following helper function of the LidarUtilities script
cfg = lutil.PCGeneratorConfig(bin_file) # or (bin_file,"",sensor_name) for reading a HDF5 file (only supported in linux for now)
converter = lutil.get_pc_converter(cfg)
For more options of the PCGeneratorConfig see the LidarUtilities script.
Currently, only host side conversion of the buffer is supported, but GPU accelerated conversion will be added in the near future. An example conversion is as follows
# convert buffer
# File is specified in the cfg
converter.convertBuffer()
# or this for a GenericModelOutput binary buffer
# converter.convertBuffer(buffer,data_size, num_points, scan_complete)
pc = converter.getPointCloud()