Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

LiDAR

factors::lidar — scan registration. Correspondences are established upstream: these factors evaluate one already-matched pair, so the data association is the front end’s job.

Two graph topologies coexist deliberately. The two-pose family (distance_field, edge, and the LidarPlaneFactor alias) registers a scan against a reference frame with the query point baked into the factor. The pose-and-point family (plane, point_to_point, gicp) treats the body-frame point as a variable. Pick the one matching how your front end parameterizes the scan.

The derivative every pose-and-point factor needs is SE3::act’s:


IcpFactor<F> — point-to-field

Aligns a query point against a distance or occupancy field defined in another frame. Generic over F: DistanceField, which returns the field value and its gradient at a query point.

Blocks — residual 1, Jacobian . Whitens internally with .

Error

Dividing by converts the field value into an approximate metric distance to the surface, so one is meaningful across fields of different scaling.

Jacobian

The residual and Jacobian are zeroed where the field query fails or — an undefined gradient carries no information, and a huge one is numerical noise.


LidarPlaneFactor — LOAM point-to-plane, two-pose

Not a distinct residual: it is the type alias IcpFactor<PrecomputedPlane>, where the field is a plane through with unit normal :

so and the Jacobian above specializes exactly. Build one with lidar_plane_factor_isotropic.


LidarEdgeFactor — LOAM point-to-line

The only genuinely distinct LiDAR residual here.

Blocks — residual 3, Jacobian . Whitens internally.

Error

With a matched edge line through with unit direction ,

the vector rejection of the offset onto the line’s orthogonal complement. The scalar cross-product form would measure the same distance but is non-differentiable at its own zero, which is precisely where the optimizer converges.

Jacobian

The projector is constant, so , chained with the same blocks as IcpFactor.


PointToPlaneFactor — plane as a measurement

Blocks — residual 1, Jacobian . Takes an external NoiseModel.

for a target plane with .

One constraint per correspondence, along the normal only — which is why three non-parallel planes are needed to fix a translation.


PoseToPointFactor

Blocks — residual 3, Jacobian .

The plain point-to-point correspondence, and the special case of GICP.


GicpFactor — plane-to-plane

Generalized ICP: the same point-to-point residual, but Mahalanobis-whitened by the combined surface covariance, so tangential directions (flat in both clouds) contribute almost nothing and the normal direction dominates. Plane-to-plane registration emerges from point-to-point with the right metric.

Blocks — residual 3, Jacobian . Whitens internally.

Error

is the symmetric inverse square root, with eigenvalues below clamped to zero so a rank-deficient covariance yields a pseudo-inverse root rather than non-finite entries.

Jacobian

is evaluated once at construction from a caller-supplied rotation hint and then held fixed, so the rotation-dependence of is dropped from the Jacobian. That is deliberate: callers rebuild correspondences (and these factors) every scan-matching iteration, so the frozen covariance never goes stale, and freezing it keeps the residual/Jacobian pair exactly consistent.