parse

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 29, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PACKET_SIZE_STANDARD = 1262                                                                          // Standard UDP packet size in bytes (without UDP sequence)
	PACKET_SIZE_SEQUENCE = 1266                                                                          // UDP packet size with 4-byte sequence number
	BLOCKS_PER_PACKET    = 10                                                                            // Number of data blocks per packet (each contains measurements from all 40 channels)
	CHANNELS_PER_BLOCK   = 40                                                                            // Number of laser channels per data block (Pandar40P has 40 channels total)
	BYTES_PER_CHANNEL    = 3                                                                             // Channel data size: 2 bytes distance + 1 byte reflectivity
	HEADER_SIZE          = 6                                                                             // Legacy constant - not used (blocks start at offset 0)
	TAIL_START           = 1240                                                                          // Fixed tail start offset after 10 × 124-byte blocks
	TAIL_SIZE            = 22                                                                            // Actual LiDAR data tail size in bytes
	SEQUENCE_SIZE        = 4                                                                             // UDP sequence number size (when enabled)
	BLOCK_PREAMBLE_SIZE  = 2                                                                             // Block preamble size (0xFFEE marker)
	AZIMUTH_SIZE         = 2                                                                             // Azimuth field size in each data block (2 bytes, little-endian)
	BLOCK_SIZE           = BLOCK_PREAMBLE_SIZE + AZIMUTH_SIZE + (CHANNELS_PER_BLOCK * BYTES_PER_CHANNEL) // 124 bytes total with preamble
	RANGING_DATA_SIZE    = BLOCKS_PER_PACKET * BLOCK_SIZE                                                // 1240 bytes total for all blocks

	// Physical measurement conversion constants
	DISTANCE_RESOLUTION = 0.004 // Distance unit: 4mm per LSB (converts raw values to meters)
	AZIMUTH_RESOLUTION  = 0.01  // Azimuth unit: 0.01 degrees per LSB (converts raw values to degrees)
	ROTATION_MAX_UNITS  = 36000 // Maximum azimuth value representing 360.00 degrees

	// Static timestamp detection threshold for PTP/GPS mode fallback
	STATIC_TIMESTAMP_THRESHOLD = 10 // Number of consecutive static timestamps before fallback to system time

	// Debug logging control constants for development and troubleshooting
	DEBUG_LOG_INTERVAL = 100 // Debug log every Nth packet after initial packets (reduces log volume)
)

Pandar40P LiDAR packet structure constants These define the fixed format of UDP packets sent by Hesai Pandar40P sensors

Variables

This section is empty.

Functions

func ConfigureTimestampMode

func ConfigureTimestampMode(parser *Pandar40PParser)

ConfigureTimestampMode configures the parser's timestamp mode based on environment variable LIDAR_TIMESTAMP_MODE. Valid values are: "system", "gps", "internal". If not set or invalid, defaults to "system" mode.

func ElevationsFromConfig

func ElevationsFromConfig(cfg *Pandar40PConfig) []float64

ElevationsFromConfig extracts per-channel elevation angles (degrees) from a Pandar40PConfig. Returns nil if config is nil. Length equals CHANNELS_PER_BLOCK.

Types

type AngleCorrection

type AngleCorrection struct {
	Channel   int     // Laser channel number (1-40) for identification
	Elevation float64 // Vertical angle correction in degrees (relative to horizontal plane, typically ±15°)
	Azimuth   float64 // Horizontal angle correction in degrees (relative to sensor front, small corrections ~±1°)
}

AngleCorrection contains the angular calibration parameters for each laser channel These corrections account for mechanical tolerances in the sensor assembly and ensure that each laser channel's measurements are properly aligned in 3D space

type ChannelData

type ChannelData struct {
	Distance     uint16 // Raw distance measurement in 4mm units (0 = no return, max ~262m)
	Reflectivity uint8  // Laser return intensity/reflectivity value (0-255, higher = more reflective surface)
}

ChannelData represents the raw measurement from a single laser channel Contains the fundamental distance and intensity measurements that form the basis of the 3D point cloud data after calibration and coordinate transformation

type DataBlock

type DataBlock struct {
	Azimuth  uint16                          // Raw azimuth angle in 0.01-degree units (0-35999 = 0-359.99°)
	Channels [CHANNELS_PER_BLOCK]ChannelData // Measurement data for all 40 channels at this azimuth
}

DataBlock represents one of 10 data blocks within a packet Each block contains measurements from all 40 channels at a specific azimuth angle. The Pandar40P captures data in discrete angular steps as the sensor rotates, with each block representing approximately 3.6° of rotation (360° / 100 blocks typical). Block structure: 2-byte preamble (0xFFEE) + 2-byte azimuth + 40 × 3-byte channel data

type FiretimeCorrection

type FiretimeCorrection struct {
	Channel  int     // Laser channel number (1-40) for identification
	FireTime float64 // Time offset in microseconds when this channel fires relative to block start (can be negative)
}

FiretimeCorrection contains timing calibration for each laser channel Different channels fire at slightly different times to avoid interference and ensure proper laser pulse separation. This timing affects the precise azimuth calculation.

type PacketHeader

type PacketHeader struct {
	SOB              uint16 // Start of Block identifier (packet format marker) - UNUSED
	ChLaserNum       uint8  // Channel and laser configuration number - UNUSED
	ChBlockNum       uint8  // Channel and block configuration number - UNUSED
	FirstBlockReturn uint8  // Return mode for first block (single/dual return) - UNUSED
	DisUnit          uint8  // Distance measurement unit identifier - UNUSED
}

PacketHeader represents the theoretical 6-byte header at the start of UDP packets Contains metadata about the packet format and sensor configuration NOTE: This structure is DEPRECATED - analysis shows data blocks start at offset 0 Kept for reference only; actual parsing begins immediately with block preambles

type PacketTail

type PacketTail struct {
	// Reserved fields for future protocol extensions
	Reserved1 [5]uint8 // Reserved (bytes 0-4) - available for future features
	Reserved2 [2]uint8 // Reserved (bytes 6-7) - available for future features

	// Sensor thermal management
	HighTempFlag uint8 // High temperature shutdown flag: 0x01=High temp warning, 0x00=Normal operation

	// Motor control and speed monitoring - CRITICAL for frame timing
	MotorSpeed uint16 // Current motor speed in RPM (typically 600-1200, used for time-based frame detection)

	// Timing information for precise timestamp calculation
	Timestamp uint32 // Microsecond part of UTC timestamp, Range: 0 to 999,999 μs

	// Return mode configuration for dual-return LiDAR operation
	ReturnMode uint8 // Return mode: 0x37=Strongest, 0x38=Last, 0x39=Last+Strongest

	// Sensor identification and configuration
	FactoryInfo uint8 // Factory configuration identifier (typically 0x42 or 0x43)

	// Accurate UTC date and time information
	DateTime [6]uint8 // Whole second UTC timestamp: [year-2000, month, day, hour, minute, second]

	// Computed high-precision timestamp combining DateTime + Timestamp
	CombinedTimestamp time.Time // Accurate UTC timestamp (DateTime + Timestamp) for precise timing

	// Optional packet sequencing for completeness tracking
	UDPSequence uint32 // Sequence number of this data packet (when UDP sequencing enabled)
}

PacketTail represents the 22-byte data tail at the end of each LiDAR UDP packet Structure based on verified Hesai Pandar40P documentation and packet analysis: Reserved(5) + HighTempFlag(1) + Reserved(2) + MotorSpeed(2) + Timestamp(4) + ReturnMode(1) + FactoryInfo(1) + DateTime(6) + [UDPSequence(4) when enabled] This tail contains critical sensor state and timing information used for accurate 3D point generation, frame timing, and sensor health monitoring.

type Pandar40PConfig

type Pandar40PConfig struct {
	AngleCorrections    [CHANNELS_PER_BLOCK]AngleCorrection    // Per-channel angular calibration data (elevation & azimuth offsets)
	FiretimeCorrections [CHANNELS_PER_BLOCK]FiretimeCorrection // Per-channel timing calibration data (microsecond firing delays)
}

Pandar40P configuration containing calibration data embedded in the binary This configuration is essential for accurate point cloud generation as it contains sensor-specific calibration parameters that correct for manufacturing tolerances. Each sensor has unique calibration values that must be applied to achieve millimeter precision.

func DefaultPandar40PConfig

func DefaultPandar40PConfig() *Pandar40PConfig

DefaultPandar40PConfig returns a default configuration using embedded CSV files

func LoadEmbeddedPandar40PConfig

func LoadEmbeddedPandar40PConfig() (*Pandar40PConfig, error)

LoadEmbeddedPandar40PConfig loads configuration from embedded CSV files only

func LoadPandar40PConfig

func LoadPandar40PConfig() (*Pandar40PConfig, error)

LoadPandar40PConfig loads configuration from embedded CSV files

func (*Pandar40PConfig) Validate

func (config *Pandar40PConfig) Validate() error

ValidateConfig validates that the configuration is complete

type Pandar40PParser

type Pandar40PParser struct {
	// contains filtered or unexported fields
}

The parser uses calibration data to convert raw measurements into accurate 3D coordinates and provides multiple timestamp modes for different synchronization requirements. Motor speed tracking enables real-time frame timing adaptation for variable RPM operation.

func NewPandar40PParser

func NewPandar40PParser(config Pandar40PConfig) *Pandar40PParser

NewPandar40PParser creates a new parser instance with the provided calibration configuration The configuration must contain valid angle and firetime corrections for all 40 channels. Parser initializes with system time mode for reliability and configurable debug packet count.

func (*Pandar40PParser) GetLastMotorSpeed

func (p *Pandar40PParser) GetLastMotorSpeed() uint16

GetLastMotorSpeed returns the motor speed from the last parsed packet Used by frame builder for real-time motor speed-based frame timing calculations

func (*Pandar40PParser) ParsePacket

func (p *Pandar40PParser) ParsePacket(data []byte) ([]lidar.PointPolar, error)

ParsePacket parses a complete UDP packet from Pandar40P sensor into a slice of 3D points Supports both standard 1262-byte packets and sequence-enabled 1266-byte packets. The packet must contain valid data blocks and timestamp information. Returns up to 400 points (10 blocks × 40 channels, excluding invalid measurements). Motor speed from packet tail is cached for frame builder time-based detection.

func (*Pandar40PParser) SetDebug

func (p *Pandar40PParser) SetDebug(enabled bool)

SetDebug enables or disables debug logging for development and troubleshooting

func (*Pandar40PParser) SetDebugPackets

func (p *Pandar40PParser) SetDebugPackets(count int)

SetDebugPackets sets the number of initial packets to debug log (prevents log spam) Only affects logging when debug mode is enabled

func (*Pandar40PParser) SetPacketTime

func (p *Pandar40PParser) SetPacketTime(ts time.Time)

SetPacketTime overrides the packet timestamp (used for PCAP replay capture times)

func (*Pandar40PParser) SetTimestampMode

func (p *Pandar40PParser) SetTimestampMode(mode TimestampMode)

SetTimestampMode configures how the parser interprets LiDAR timestamps This affects frame timing accuracy and synchronization with external systems

type TimestampMode

type TimestampMode int

Pandar40PParser handles parsing of Pandar40P LiDAR UDP packets into 3D point clouds TimestampMode defines how LiDAR timestamps should be interpreted for accurate timing

const (
	TimestampModeSystemTime TimestampMode = iota // Use system reception time (reliable, default for street analytics)
	TimestampModePTP                             // PTP synchronized microseconds with static detection and fallback
	TimestampModeGPS                             // GPS synchronized microseconds with static detection and fallback
	TimestampModeInternal                        // Microseconds since device boot with bootTime offset alignment
	TimestampModeLiDAR                           // Use LiDAR's native DateTime + Timestamp fields (most accurate)
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL