Current version:
Version | Date | Changes |
---|---|---|
0.9.5 | 05/13/2025 | Update INFO and Point Data packet format |
0.9.4 | 09/19/2024 | Update Panic timestamp meaning |
0.9.3 | 07/09/2024 | Correct INFO V1 common header order |
0.9.2 | 05/29/2024 | Update to the PANIC packet offsets |
0.9.1 | 01/19/2024 | Update INFO and PANIC packet format |
0.9 | 07/19/2023 | Define frame aggregation behavior |
0.8.3 | 08/27/2022 | Define blooming and blocked bits |
0.8.2 | 03/02/2022 | Functional safety clarifications |
0.8.1 | 01/27/2022 | Add noise bit in point flag |
0.8 | 01/11/2022 | Clarify SDK reserved bits |
0.7.1 | 01/10/2022 | Draft document, add v2 point header |
0.7 | 08/21/2021 | Draft document, add v1 point data |
0.6 | 07/14/2021 | Draft document, not finalized |
This document outlines the data communication protocol for Nova series of lidars produced by Cepton.
There are three general type of communications supported by Cepton's lidar sensors:
Point data is accumulated as the lidar measurements happen. Once a full packet is filled the data will be sent out.
Point data is a stream of measurements following strict order:
0
.SecondReturn
flag will be set and relative timestamp is always 0
.In the payload of the UDP packet, after the 24 bytes header, each point is contiguously placed based on the point size. There are up to 144 points of 10 bytes each.
Offset | Block | Size | Description |
---|---|---|---|
0 | Header | 24 | Point Data Packet Header |
24 | Point0 | Point #0 | |
Point1 | Point #1 | ||
... | ... | ... | ... |
PointN | Point #N |
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | Signature | 4 | STDV | 4 byte signature to identify packet type |
4 | HeaderVersion | 1 | Header type | |
5 | HeaderSize | 1 | Header size | |
6 | Flags | 2 | 0 | Flags |
8 | Timestamp | 8 | Reference timestamp | |
16 | PointVersion | 1 | 0/1 | Point structure type |
17 | PointSize | 1 | Point structure size | |
18 | PointCount | 2 | 144 | Number of points in this packet |
20 | SequenceId | 4 | Version 2+: Sequencing ID for packet stream |
(*When there aren't enough points to fill all 144 possible points in the UDP Packet, this number can be smaller, and the remaining space is filled with empty points (all values equal to 0). )
Corresponding C structure:
struct CeptonPointDataHeader {
uint32_t signature;
uint8_t header_version;
uint8_t header_size;
uint16_t flags;
int64_t reference_system_time_usec;;
uint8_t point_version;
uint8_t point_size;
uint16_t point_count;
uint32_t sequence_id;
};
Reference timestamp holds the reference time for the first point. This is the number of microseconds (us) since the sensor boot up time. To convert this timestamp to universal time, please reference INFO packet description.
Flags: There is no packet level flags defined. This byte has to be 0 at all time.
Offset | Field | Size | Unit | Range | Description |
---|---|---|---|---|---|
0 | X | 2 | 0.5cm | -163.840m to 163.835m | X coordinate |
2 | Y | 2 | 0.5cm | 0 to 327.68m | Y coordinate |
4 | Z | 2 | 0.5cm | -163.840m to 163.835m | Z coordinate |
6 | Reflectivity | 1 | % | 0 to 255 | Reflectivity |
7 | Timestamp | 1 | us | 0 to 255 | Time difference from the point before |
8 | LaserId | 1 | 0 to 63 | Laser ID | |
9 | Flags | 1 | Flags | ||
10+ | Internal | When PointSize > 10, these are internal data |
Corresponding C structure:
struct CeptonPointData {
int16_t x;
uint16_t y;
int16_t z;
uint8_t reflectivity;
uint8_t timestamp_offset_usec;
uint8_t laser_id;
uint8_t flags;
};
Coordinates: Looking from the sensor bore-sight,
Coordinates X and Z are signed short, while Y is unsigned. The reference point (0,0,0) is located at the geometric center of the sensor, which is at the mid-point of all 3 primary dimensions of the sensor enclosure.
Reflectivity: 0-100% reflectivity are measured by assuming Lambertian reflection model. Non-Lambertian materials, such as retro-reflective surfaces commonly found in road signs and warning cones, can produce higher than 100% reflectivity. For reflectivity less than 127%, intensity is equal to reflectivity. For reflectivity greater than or equal to 127%, we convert to intensity exponentially using quantize_table[reflectivity-127]
:
private static float[] quantize_table = {
127.0f, 130.7f, 134.5f, 138.4f, 142.4f, 146.6f, 150.9f, 155.3f,
159.8f, 164.4f, 169.2f, 174.1f, 179.2f, 184.4f, 189.8f, 195.3f,
201.0f, 206.9f, 212.9f, 219.1f, 225.4f, 232.0f, 238.8f, 245.7f,
252.9f, 260.2f, 267.8f, 275.6f, 283.6f, 291.9f, 300.4f, 309.1f,
318.1f, 327.4f, 336.9f, 346.7f, 356.8f, 367.2f, 377.9f, 388.9f,
400.2f, 411.9f, 423.9f, 436.2f, 448.9f, 462.0f, 475.4f, 489.2f,
503.5f, 518.1f, 533.2f, 548.8f, 564.7f, 581.2f, 598.1f, 615.5f,
633.4f, 651.9f, 670.8f, 690.4f, 710.5f, 731.1f, 752.4f, 774.3f,
796.9f, 820.1f, 843.9f, 868.5f, 893.8f, 919.8f, 946.6f, 974.1f,
1002.5f, 1031.7f, 1061.7f, 1092.6f, 1124.4f, 1157.2f, 1190.9f, 1225.5f,
1261.2f, 1297.9f, 1335.7f, 1374.6f, 1414.6f, 1455.8f, 1498.2f, 1541.8f,
1586.6f, 1632.8f, 1680.4f, 1729.3f, 1779.6f, 1831.4f, 1884.8f, 1939.6f,
1996.1f, 2054.2f, 2114.0f, 2175.5f, 2238.9f, 2304.0f, 2371.1f, 2440.1f,
2511.2f, 2584.3f, 2659.5f, 2736.9f, 2816.6f, 2898.6f, 2983.0f, 3069.8f,
3159.2f, 3251.1f, 3345.8f, 3443.2f, 3543.4f, 3646.6f, 3752.7f, 3862.0f,
3974.4f, 4090.1f, 4209.2f, 4331.7f, 4457.8f, 4587.6f, 4721.1f, 4858.6f,
5000.0f};
Timestamp: This value is the relative value from the time since last point in the packet. For the very first point, it is time since the packet header's reference time. Notice that 0
value is possible for dual firing mode or dual return's second return. The timestamp represents the time of firing, for the time accuracy afforded (> 1us, ~300m traveled), it is OK to use directly as target point time (time when target is hit by laser).
Channel ID: Reports the channel ID, which usually indicate a distinct laser->APD pathway. Each channel correspond to a unique set of laser/APD pair.
Flags: per-point flags are defined in the table below
Bit | Value | Name | Description |
---|---|---|---|
0 | 1 | Saturated | Set if the point is saturated |
1 | 2 | Reserved | Reserved |
2 | 4 | FrameParity | Frame parity bit |
3 | 8 | Reserved | Reserved |
4 | 16 | SecondReturn | Set for second return |
5 | 32 | NoReturn | Set if this point has no return |
6 | 64 | Noise | Set if this point is a noise |
7 | 128 | Blocked | Set if this point is blocked |
(*The reserved bit#3 is defined in SDK as frame boundary. This is a software flag created by SDK and is not part of the communication protocol. Refer to Cepton SDK documentation for details)
Corresponding flags and enumerations
enum {
CEPTON_POINT_SATURATED = 1 << 0,
CEPTON_POINT_FRAME_PARITY = 1 << 2,
CEPTON_POINT_SECOND_RETURN = 1 << 4,
CEPTON_POINT_NO_RETURN = 1 << 5,
CEPTON_POINT_NOISE = 1 << 6,
CEPTON_POINT_BLOCKED = 1 << 7,
};
Saturated flag: Set if the signal received is too strong to be correctly measured. This usually happen when measuring retro-reflective targets. When this flag is set, the reflectivity is not trust worthy, and the distance accuracy is slightly reduced.
There are also some unspecified conditions that can be derived from the data stream itself:
FrameParity: Cleared for even frames and set for odd frames. This ensures the frame boundary as identified by the sensor is always communicated even when one of the data packet is lost.
Dual return case: If two consecutive points have same ChannelID
and second point has Timestamp
set to 0
. The second point is the second return of the same laser firing. Second return signifies that the fired laser was somehow split up (e.g. hitting a corner of a near wall, then hitting a wall farther down). In this case, the strongest is always the first and farthest return can be determined by comparing Y
value.
Blocked points: Some Cepton lidar products can detect blockage and report them. When blockage happens, there might still be a valid return. The distance of the return can be trusted but the reflectivity should be considered incorrect.
Point data packets can be turned off completely.
For sensors that support turning on or off the second return feature, point data structure will not change. The second return, when present, will just be a repeat of the same laser channel, with time offset 0
and SecondReturn
flag set.
Offset | Block | Size | Description |
---|---|---|---|
0 | Header | 96 | INFO packet header |
96 | DiagnosisApm | 312 | Application processing microcontroller diagnostic |
408 | DiagnosisKomodo | 22 | Komodo microcontroller diagnostic |
430 | DiagnosisFault | 38 | Fault diagnostic |
468 | DiagnosisGecko | 12 | Gecko diagnostic |
INFO packet header is universal data for all Cepton sensors
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | Signature | 4 | INFZ | 4 byte signature to identify packet type |
4 | HeaderMagic | 2 | 2 bytes for future compatibility | |
6 | Reserved | 1 | Reserved | |
7 | SKU | 1 | SKU number | |
8 | Model | 2 | Model number | |
10 | ModelReserved | 2 | Reserved | |
12 | SerialNumber | 4 | Sensor serial number | |
16 | FirmwareVersion | 4 | Firmware release version number | |
20 | ModelName | 28 | UTF-8 string for model name | |
48 | PartNumber | 4 | Part Number | |
52 | ApmVersion | 4 | Application Processor version | |
56 | IoxVersion | 4 | IOX firmware version | |
60 | IguanaVersion | 4 | Iguana firmware version | |
64 | PowerUpTime | 8 | Microseconds since power up | |
72 | TimeOffsetFromMaster | 8 | FSM-Master time offset in microseconds | |
80 | TimeDriftCorrection | 4 | Clock drift correction | |
84 | TimeSyncStatus | 1 | Time synchronization details | |
85 | ReturnMode | 1 | Dual return mode | |
86 | ThermalDerateState | 1 | Thermal derating | |
87 | RangeEstimation | 1 | Single value range estimation for how far the sensor can see in meters | |
88 | Temperature | 2 | Significant temperature | |
90 | ChannelCount | 2 | Channel count number | |
92 | FaultSummary | 4 | Fault cases summarization |
HeaderMagic: The value of HeaderMagic
is 0x0860
. The total header size is 96 bytes, as indicated by the first 10 bits of the INFZ Magic Number. Bits 11 to 13 represent the INFZ version 1.
FirmwareVersion: The version fields for the sensor firmware, APM, IOX, and Iguana share the same structure defined in the table below:
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | Major | 1 | Major version number | |
1 | Minor | 1 | Minor version number | |
2 | Build | 1 | Build number | |
3 | Revision | 1 | Revision number |
FaultSummary: Per-point flags indicating various error conditions are defined as follows:
Bit | Value | Name | Description |
---|---|---|---|
0 | 1 | Lidar data rationality check error | Any data rationality check error |
1 | 2 | Internal communication error | Any checksum mechanism failure |
2 | 4 | Temperature out of range | Any chip's temperature out of range |
3 | 8 | Voltage out of range | Any ADC measured voltage out of range |
4 | 16 | Boot failure | Any subsystem (iguana, gecko) boot failure |
5 | 32 | Ethernet communication | Any server/client or ethernet sync error |
6 | 64 | Lidar image irregularity | Partial/full laser blockage or distance |
7 | 128 | Micro-Motion Technology | Any mmt-related error |
8 | 256 | Security Error | Any unauthorized access or key provision |
9 | 512 | Session Error | Any incorrect session action |
10-31 | Reserved | Reserved |
Corresponding c structure:
struct CeptonInfoHeader {
uint8_t padding0;
uint8_t sku;
uint16_t model_enum;
uint8_t model_enum_reserved[2];
uint32_t serial_number;
typedef struct {
uint8_t major;
uint8_t minor;
uint8_t build;
uint8_t revision;
} release_version, apm_version, iox_version, iguana_version;
int64_t time_since_powerup;
int64_t time_offset_from_master;
int32_t time_drift_correction;
uint8_t time_status;
uint8_t return_mode;
uint8_t thermal_derate_state;
uint8_t range_estimation;
uint16_t temperature;
uint16_t channel_count;
uint32_t fault_summary;
};
The LiDAR diagnostic system includes four diagnostic payloads.
Offset | Field | Size | Value | Description |
---|---|---|---|---|
96 | DiagType | 2 | Diagnostic structure type | |
98 | DiagSize | 2 | Diagnostic structure size | |
100 | SkuSoftware | 2 | SKU for software | |
102 | MmtStatus | 24 | MMT status | |
126 | TempApm | 2 | Komodo temperature | |
128 | TempIOX | 2 | IOX temperature | |
130 | TempOptic | 2 | Optic temperature | |
132 | TempIguana | 32 | IGUANA temperature | |
164 | ImuReadings | 24 | IMU rotation and acceleration reading | |
188 | Reserved | 2 | Reserved | |
190 | FaultApmLastError | 2 | Last APM error | |
192 | FaultApmLastTs | 8 | Last APM error timestamp | |
200 | Reserved | 6 | Reserved | |
206 | FaultIoxLastError | 2 | Last IOX error | |
208 | FaultIoxLastTsc | 8 | Last IOX error timestamp | |
216 | IguanaRangeEstValues | 16 | Last IGUANA error enum | |
232 | FaultIguanaLastError | 16 | Raw range estimation enum values from each IGUANA | |
248 | FaultIguanaLastTs | 128 | Last IGUANA error timestamp | |
376 | PtpPdelay | 8 | PTP link delay | |
384 | PtpOffset | 8 | PTP master-slave offset | |
392 | PtpStat | 1 | PTP status | |
393 | Reserved | 7 | Reserved | |
400 | LifeCount | 8 | Clock counter |
MmtStatus: Describes the status of the MMT Monitor for both the X-axis (horizontal) and Z-axis (vertical). Each axis contains an identical set of fields as detailed in the table below.
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | Amplitude | 2 | Center-to-peak amplitude in encoder counts | |
2 | DriveAmplitude | 2 | Driving Amplitude | |
4 | Frequency | 2 | MMT frequency | |
6 | PhaseError | 2 | MMT phase error | |
8 | Reserved | 4 | Reserved |
Corresponding c structure:
struct DiagnosticApm {
uint16_t diag_type;
uint16_t diag_size;
uint16_t sku_software;
typedef struct {
typedef struct {
uint16_t amplitude;
int16_t drive_amplitude;
uint16_t frequency;
int16_t phase_error;
uint8_t reserved[4];
} z, x;
} mmt_status
uint16_t temp_apm;
uint16_t temp_iox;
uint16_t temp_optic;
uint16_t temp_iguana[16];
int16_t imu_readings[2][6];
uint16_t padding0[1];
uint16_t fault_apm_last_error;
uint64_t fault_apm_last_ts_usec;
uint16_t padding1[3];
uint16_t fault_iox_last_error;
uint64_t fault_iox_last_ts_usec;
uint8_t iguana_range_est_values[16];
uint8_t fault_iguana_last_error[16];
uint64_t fault_iguana_last_ts_usec[16];
uint64_t ptp_pdelay_nsec;
uint64_t ptp_ms_offset_nsec;
uint8_t ptp_stat;
uint8_t reserved[7];
uint64_t life_counter;
};
Offset | Field | Size | Value | Description |
---|---|---|---|---|
408 | DiagType | 2 | Diagnostic structure type | |
410 | DiagSize | 2 | Diagnostic structure size | |
412 | SkuSoftware | 2 | SKU for Software | |
414 | VoltageAdcOut | 16 | Komodo ADC Voltage |
VoltageAdcOut
Offset | Field | Size | Value | Description |
---|---|---|---|---|
414 | VoltageAdcOut | 2 | Komodo 0.8V | |
416 | VoltageAdcOut | 2 | Komodo 1.0V | |
418 | VoltageAdcOut | 2 | Komodo 1.8V | |
420 | VoltageAdcOut | 2 | Komodo 3.3V | |
422 | VoltageAdcOut | 2 | Komodo 5.3V | |
424 | VoltageAdcOut | 2 | Optical Module 5.3V | |
426 | VoltageAdcOut | 2 | Laser 32V | |
428 | Reserved | 2 | Reserved |
Corresponding c structure:
struct DiagnosticKomodo {
uint16_t diag_type;
uint16_t diag_size;
uint16_t sku_software;
uint16_t voltage_adc_out[8];
};
Offset | Field | Size | Value | Description |
---|---|---|---|---|
430 | DiagType | 2 | Diagnostic structure type | |
432 | DiagSize | 2 | Diagnostic structure size | |
434 | SkuSoftware | 2 | SKU for Software | |
436 | FaultEntries | 32 | Fault entries |
FaultEntries: In the FaultEntried structure, each field corresponds to a specific diagnostic fault condition detected by the system:
Offset | Field | Size | Value | Description |
---|---|---|---|---|
436 | VoltageOutOfRange | 8 | Volate out of range | |
444 | TemperatureOutRangeKomodo | 1 | Komodo temperature error | |
445 | TemperatureOutRangeIox | 1 | IOX temperature error | |
446 | TemperatureOutRangeIguana | 1 | Iguana temperature error | |
447 | TemperatureOutRangeGecko | 1 | Gecko temperature error | |
448 | IguanaIoxCommError | 1 | Iguana and IOX communication error | |
449 | IoxGeckoCommError | 1 | IOX and Gecko communication error | |
450 | GeckoKomodoCommError | 1 | Gecko and Komodo communication error | |
451 | IguanaBootFailure | 1 | Iguana boot failure | |
452 | ChipFailure | 1 | Chip failure | |
453 | EthLnkDown | 1 | Ethernet link down | |
454 | PtpExpiration | 1 | PTP expiration | |
455 | ThermalShutDown | 1 | Thermal shut down | |
456 | LasersPartialBlock | 1 | Lasers partial blockage | |
457 | LasersFullBlock | 1 | Lasers full blockage | |
458 | MmtInterlock | 1 | MMT interlock failure | |
459 | IguanaFailure | 1 | Iguana bootup failure | |
460 | FpgaRuntimeFail | 1 | FPGA runtime failure | |
461 | MmtTimeout | 1 | MMT encoder timeout | |
462 | GeckoBootFailure | 1 | Gecko boot failure | |
463 | InvalidChannels | 1 | Missing or invalid channels | |
464 | Reserved | 4 | Reserved |
VoltageOutOfRange:
Offset | Field | Size | Value | Description |
---|---|---|---|---|
436 | VoltageOutOfRange | 1 | Komodo 0.8V | |
437 | VoltageOutOfRange | 1 | Komodo 1.0V | |
438 | VoltageOutOfRange | 1 | Komodo 1.8V | |
439 | VoltageOutOfRange | 1 | Komodo 3.3V | |
440 | VoltageOutOfRange | 1 | Motor 5.3V | |
441 | VoltageOutOfRange | 1 | OM 5.3V | |
442 | VoltageOutOfRange | 1 | Laser 32V | |
443 | VoltageOutOfRange | 1 | Reserved |
Corresponding c structure:
struct DiagnosticFault {
uint16_t diag_type;
uint16_t diag_size;
uint16_t sku_software;
union {
struct {
uint8_t voltage_out_range[8];
uint8_t temperature_out_range_komodo;
uint8_t temperature_out_range_iox;
uint8_t temperature_out_range_iguana;
uint8_t temperature_out_range_gecko;
uint8_t iguana_iox_comm_crc_error;
uint8_t iox_gecko_comm_crc_error;
uint8_t gecko_komodo_comm_crc_error;
uint8_t iguana_boot_failure;
uint8_t phy_sync_failure;
uint8_t eth_link_down;
uint8_t ptp_expiration;
uint8_t thermal_shut_down;
uint8_t lasers_partial_block;
uint8_t lasers_full_block;
uint8_t mmt_interlock;
uint8_t iguana_failure;
uint8_t fpga_runtime_fail;
uint8_t mmt_timeout;
uint8_t gecko_boot_failure;
uint8_t invalid_channels;
uint8_t rsv[4];
};
uint8_t fault_entries[32];
};
};
Offset | Field | Size | Value | Description |
---|---|---|---|---|
468 | DiagType | 2 | Diagnostic structure type | |
470 | DiagSize | 2 | Diagnostic structure size | |
472 | GeckoStatus | 8 | Gecko Status |
Corresponding c structure:
struct DiagnosticGecko {
uint16_t diag_type;
uint16_t diag_size;
uint8_t gecko_status[8];
};
SDK provides a few methods to aggregate points such that the point cloud creates a frame. Two types of aggregation are available:
The lidar has a built-in notion of when a frame starts and ends. This is signified by the parity on points (shown in the CEPTON_POINT_FRAME_PARITY
bit from the point flag). When the parity changes, the frame aggregator would then note to finish off the frame and start a new one.
Frame aggregation utilizes this mode as the default.
When point packets are dropped, this mode will robustly still detect a frame change. In the unlikely event that a whole frame of the opposite parity is dropped, the aggregator will produce two frames of the same parity with variable results on what the frame looks like visually, but then resume normal operation.
Users of the SDK can specify the period of time a frame should last before switching to a new frame by specifying it in microseconds (minimum 1000).
This should be passed when listening to frames via the CeptonListenFrames
function call.
At a given start timestamp, the internal frame aggregator would increment its time by adding on each point's relative timestamp value. When the starting timestamp reaches the fixed frame duration (or reach an internal buffer limit), it then takes the most recent point cloud packet's start time, adds on the aggregate time elapsed from the points taken in the packet, and restarts the time and frame aggregation from that point.
Note that based on this implementation, if any point packets get lost, the next incoming points will assume a timestamp earlier compared to its presumed ground truth timestamp until the current frame finishes. When the frame is complete, then the next frame will adjust accordingly to the current timestamp again.
There are several built-in mechanisms to ensure the data sanity of the point cloud stream coming out of the lidar:
In addition, when any faults happen inside the sensor, the sensor will send out a "panic message" to inform the host as soon as possible.
Panic packet format:
Offset | Field | Size | Description |
---|---|---|---|
0 | Header | 12 | PANIC packet header |
12 | Active Fault | 24 | Active fault detailed information |
Panic packet header format:
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | Magic | 4 | PANC | 8 bytes header magic signature |
4 | Serial Number | 4 | Sensor serial number | |
8 | Sequence Id | 2 | Continuous increasing sequence id | |
10 | Reserved | 2 | Reserve for future use |
Panic packet active fault format:
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | Fault Identity | 4 | 4 bytes field for unique fault case identification | |
8 | Life Counter | 4 | Count of how many of this panic have been sent | |
12 | Lidar Timestamp | 8 | Microseconds since power on. Matches point data header | |
14 | Reserved | 8 | Reserve for future use |
packet structure:
struct panic_packet {
uint32_t signature;
uint32_t serial_number;
uint16_t sequence_id;
uint16_t reserved;
struct {
uint32_t fault_identity;
uint32_t life_counter;
uint64_t ptp_timestamp;
uint64_t reserved;
} active_fault;
};