Wiki
Point_LIO(激光与IMU融合里程计,建图与定位算法)
Existing English translations were reused. 6 current source blocks remain in Simplified Chinese, without triggering paid translation.
1.Point_LIO(激光与IMU融合里程计,建图与定位算法)
| YAML level | Main contents |
|---|---|
Parameters placed directly under ros__parameters in YAML |
Estimation model, propagation method, saturation checks, map initialization, downsampling and logging switches |
common |
Input topics, frame merging, frame splitting and time offsets |
prior_pcd |
Prior map and initial position |
preprocess |
LiDAR format, scan lines, per-point time units and near-range filtering |
mapping |
IMU, gravity, extrinsics, noise and matching parameters |
odometry |
Odometry publication mode |
publish |
Trajectory, point cloud and TF publication switches |
pcd_save |
Point cloud saving switch and interval |
1.1.参数
1.1.1.ros__parameters (ROS node parameters)
1.1.1.1.Parameter table
point_lio:
ros__parameters:
use_imu_as_input: False # Change to True to use IMU as input of Point-LIO
prop_at_freq_of_imu: True
check_satu: True
init_map_size: 10
point_filter_num: 8 # Options: 4, 3
space_down_sample: True
filter_size_surf: 0.2 # Options: 0.5, 0.3, 0.2, 0.15, 0.1
filter_size_map: 0.2 # Options: 0.5, 0.3, 0.15, 0.1
ivox_nearby_type: 18 # Options: 0, 6, 18, 26
runtime_pos_log_enable: False # Option: True
| Parameter | Current value | Units | Hardware guidance | Purpose | Effect of increasing | Effect of decreasing | Activation conditions / notes |
|---|---|---|---|---|---|---|---|
use_imu_as_input |
False |
Not applicable; boolean | Usually keep the current value; not a priority for tuning | Select the IMU input or observation model | Not applicable | Not applicable | False: use the IMU as observations to correct the filter state; True: use the IMU as input for motion prediction. False still uses the IMU |
prop_at_freq_of_imu |
True |
Not applicable; boolean | Usually keep the current value; not a priority for tuning | Select covariance prediction timing | Not applicable | Not applicable | True: predict covariance mainly at IMU timestamps; False: also predict at individual LiDAR point timestamps. This does not set the hardware sampling frequency |
check_satu |
True |
Not applicable; boolean | Usually keep the current value; not a priority for tuning | Check whether each IMU axis is near saturation and exclude saturated axes from observation updates | Not applicable | Not applicable | Currently use_imu_as_input=False branch uses this; thresholds come from mapping.satu_acc/satu_gyro |
init_map_size |
10 |
Points; count | Usually keep the current value; not a priority for tuning | Minimum accumulated point count for initial map creation | Accumulate more initial points; may delay matching if the threshold exceeds one frame’s point count | Reach the threshold earlier, potentially with a smaller initial map | Not a frame count or an IMU initialization count; the initial point cloud comes from preprocessing |
point_filter_num |
8 |
Dimensionless; point sampling interval | Observe closely on hardware; adjust only for a specific problem | Select one in every N Livox points after initial line/tag filtering | Retain fewer points, usually reducing computation but potentially losing useful structure | Retain more points, usually increasing computation and preserving more structure | Used in the current Livox branch; must be a positive integer. The commented values 4 and 3 do not define the full allowed range |
space_down_sample |
True |
Not applicable; boolean | Usually keep the current value; not a priority for tuning | Whether to spatially voxel-downsample the current scan | Not applicable | Not applicable | True uses filter_size_surf; False skips this stage, but the preceding interval sampling still runs |
filter_size_surf |
0.2 |
m; voxel side length | Observe closely on hardware; adjust only for a specific problem | Reduce spatially redundant points in the current scan | Usually fewer scan points and faster computation, with less small-scale structure preserved | Usually more scan points and detail, with greater computation | space_down_sample=True activates this; 0.2 m is not the localization accuracy |
filter_size_map |
0.2 |
m; map filtering scale | Observe closely on hardware; adjust only for a specific problem | Suppress insertion of new points into voxels already containing map points during map updates | Usually a sparser map, slower growth and less detail | Usually a denser map and faster growth, with greater memory and search costs | Used during map insertion, independently of the scan downsampling switch |
ivox_nearby_type |
18 |
Not applicable; enum | Usually keep the current value; not a priority for tuning | Select neighboring grid cells for nearest-neighbor map searches | Not applicable | Not applicable | Supports 0/6/18/26; more neighbors broaden the candidate region and usually increase search cost |
runtime_pos_log_enable |
False |
Not applicable; boolean | Enable or configure as needed | Enable detailed state recording and timing statistics | Not applicable | Not applicable | True adds state writes and terminal output; with False, the code still opens some log files |
1.1.1.2.Parameter Details
1.1.1.2.1.use_imu_as_input (the way the IMU participates in motion estimation)
use_imu_as_input determines how the IMU participates in filtering.
The current handling of False is as follows: the filter internally estimates states such as angular velocity and acceleration; after receiving IMU data, it corrects these states using measurements, and then performs motion prediction and laser matching.
When set to True, acceleration and angular velocity are used as prediction inputs, and after unit scaling and bias processing, they drive the motion state. Switching the model also changes the noise parameters used, so for the first round, keep the current False.
Disabling the IMU corresponds to another parameter, mapping.imu_en.
1.1.1.2.2.prop_at_freq_of_imu (update the estimation uncertainty at IMU timestamps)
prop_at_freq_of_imu Mainly affects covariance propagation.
Covariance can be understood as the degree of uncertainty of the filter about the current estimate. When true, the code propagates it at the IMU instants; the state still advances to the sampling instants of the laser points.
After changing it to False, the code will still add covariance prediction at each laser point time, which usually results in a larger computational load. It is not a switch for "setting the Point-LIO output frequency to the IMU frequency," nor can it guarantee higher accuracy after switching.
1.1.1.2.3.check_satu (IMU reading range protection)
check_satu is processed axis by axis.
The current code compares three acceleration axes and three angular velocity axes separately:abs(原始轴值) ≥ 0.99 × 对应饱和阈值
The flagged axis stops participating in this IMU observation update, while the other axes continue to be used. Therefore, it needs to work with satu_acc/satu_gyro in the correct units and range. This check takes effect in the current output model.
1.1.1.2.4.init_map_size (minimum number of points to initialize the map)
init_map_size=10 is just a point threshold.
The code determines:init_feats_world->size() >= init_map_size
If a single preprocessed frame already contains several thousand points, setting it to 10 or 100 may both satisfy the condition within the same frame. Therefore, increasing it does not necessarily increase initialization time, nor can it replace static IMU initialization.
The map initialization uses the preprocessed point cloud, and does not directly use the point cloud that has undergone filter_size_surf voxel downsampling.
Three point-count control parameters act on different stages.
The routine processing after initialization is roughly as follows:
原始点云
→ line/tag 初筛
→ point_filter_num:按间隔取点
→ 距离等过滤
→ filter_size_surf:扫描空间降采样
→ 逐点匹配
→ filter_size_map:地图插入筛选
For example, about 10,000 points pass the line/tag initial screening:
- point_filter_num=8: First select about 1,250, subsequent filtering may continue to reduce.
- Change to 4: First select about 2,500.
- Subsequent voxel downsampling will further compress spatially dense points.
Therefore, using more interval sample points does not necessarily increase the final number of matched points proportionally; it also depends on the scanning voxel, occlusion, and matching conditions.
1.1.1.2.5.ivox_nearby_type (map neighboring cell search range)
ivox_nearby_type=18 indicates the adjacency grid type.
The number of grids where the local implementation actually performs the search includes the center grid:
| Configuration value | Search range | Total number of grids |
|---|---|---|
0 |
Center grid only | 1 |
6 |
Center + face-adjacent grids | 7 |
18 |
Then add edge-adjacent grids | 19 |
26 |
Then add corner-adjacent grids | 27 |
It does not mean "find 18 points" or "search for 18 meters".
The actual spatial scale also depends on mapping.ivox_grid_resolution, currently 0.5 m; during matching, there are also nearest-neighbor and residual conditions.
When tuning this parameter group in the future, mainly compare output latency, effective environmental structure, point cloud ghosting, and trajectory continuity. First use the current values to establish a baseline, then change one parameter for the specific behavior in order to determine where the improvement comes from.
1.1.2.common (input topic and point cloud time processing)
1.1.2.1.Parameter table
common:
lid_topic: "livox/lidar"
imu_topic: "livox/imu"
con_frame: False # True: if you need to combine several LiDAR frames into one
con_frame_num: 1 # the number of frames combined
cut_frame: False # True: if you need to cut one LiDAR frame into several subframes
cut_frame_time_interval: 0.05 # should be integral fraction of 1 / LiDAR frequency
time_diff_lidar_to_imu: 0.0 # Time offset between LiDAR and IMU calibrated by other algorithms, e.g., LI-Init (find in Readme)
| Parameter | Current value | Units | Hardware guidance | Purpose | Effect of increasing | Effect of decreasing | Activation conditions / notes |
|---|---|---|---|---|---|---|---|
common.lid_topic |
"livox/lidar" |
Not applicable; topic name | Verify and configure correctly before running on hardware | Specify the point cloud subscription topic | Not applicable | Not applicable | Currently lidar_type=1; this topic must publish Livox CustomMsg, and the namespace must also match |
common.imu_topic |
"livox/imu" |
Not applicable; topic name | Verify and configure correctly before running on hardware | Specify the IMU subscription topic | Not applicable | Not applicable | Currently connected to the internal MID360 IMU; reads acceleration, angular velocity and timestamps |
common.con_frame |
False |
Not applicable; boolean | Usually keep the current value; not a priority for tuning | Whether to merge multiple point cloud frames before subsequent processing | Not applicable | Not applicable | True enters the frame-merging branch, but the count is hardcoded to 10; the implementation also fails to include the next frame |
common.con_frame_num |
1 |
Frames; count | Unused in the current execution path; leave unchanged for now | Commented intent: specify the number of frames to merge | No change in the current implementation | No change in the current implementation | The parameter is read, but the merge code uses the fixed number 10 instead |
common.cut_frame |
False |
Not applicable; boolean | Unused in the current execution path; leave unchanged for now | Commented intent: enable point cloud frame splitting | Not applicable | Not applicable | The actual branch checks a different variable, cut_frame_init; no connection between them was found |
common.cut_frame_time_interval |
0.05 |
s | Unused in the current execution path; leave unchanged for now | Commented intent: specify the split time interval | No change in the current implementation | No change in the current implementation | The parameter is read, but no use in frame-splitting calculations was found |
common.time_diff_lidar_to_imu |
0.0 |
s; time offset | Unused in the current execution path; leave unchanged for now | Commented intent: compensate for the LiDAR and IMU time difference | No change in the current implementation | No change in the current implementation | The parameter is read, but IMU timestamp correction does not use it |
1.1.2.2.Parameter Details
1.1.2.2.1.lid_topic and imu_topic (Radar and IMU input topics)
The two topic parameters—name, message type, and namespace—must all correspond at the same time.
Current real vehicle drive settings xfer_format=4, multi_topic=0, source code release:
livox/lidar → Livox CustomMsg
livox/lidar/pointcloud → PointCloud2
livox/imu → sensor_msgs/Imu
Point-LIO Currently, lidar_type=1, and CustomMsg is subscribed, so livox/lidar in the configuration matches the driver.
Both of these configurations are relative topic names:
| Node namespace | livox/lidar actually resolves to |
|---|---|
| empty namespace | /livox/lidar |
/red_standard_robot1 |
/red_standard_robot1/livox/lidar |
The namespace or topic remapping of the driver and Point-LIO must be consistent. The topic name is responsible for selecting the input source, and the frame_id in the message indicates the coordinate frame name; selecting a topic does not automatically perform coordinate transformation.
1.1.2.2.2.con_frame and con_frame_num (multi-frame point cloud merging)
The actual behavior of con_frame is not entirely consistent with the annotation.
The current Livox frame-merging branch executes:
- Receive the first 10 frames and accumulate their points.
- Adjust the per-point time of each frame to the start time of the first frame.
- On the 11th callback, place the accumulated point cloud into the processing queue.
- The 11th frame received in this callback is not added to the accumulated point cloud, and then the count is reset to zero.
So even if we set:
con_frame: True
con_frame_num: 1
nor will it execute as "merge 1 frame." The code still accumulates 10 frames, and then the next callback triggers the output.
Assuming a stable drive at 20 Hz, this logic theoretically outputs one merged packet about every 11 callbacks, i.e., about 1.82 Hz, with the accumulated point cloud covering about 0.5 seconds. This increases the waiting time and the number of points processed at once, so the first round keeps False.
1.1.2.2.3.cut_frame and cut_frame_time_interval (point cloud frame splitting settings)
The frame splitting function exists, but the YAML switch is not connected to it.
Actual code check:
if (cut_frame_init)
{
process_cut_frame_livox(..., cut_frame_num, ...);
}
Where cut_frame_init defaults to False. Currently, no assignment of common.cut_frame to it has been found, nor has any use of cut_frame_time_interval been found. Additionally, this internal function segments by point count, using cut_frame_num, rather than directly splitting according to the 0.05 seconds in the YAML. Therefore, modifying these two YAML parameters alone will not achieve the frame splitting behavior described in the comments.
1.1.2.2.4.time_diff_lidar_to_imu (radar and IMU time offset)
The time difference parameter is not connected, which does not mean the system does not need synchronization.
The expression by which the IMU callback actually corrects the timestamp is:
修正后时间 = 原始时间
− timediff_imu_wrt_lidar
− time_lag_IMU_wtr_lidar
It uses two other variables, currently initialized to zero; common.time_diff_lidar_to_imu is not used.
Point-LIO It still waits for the IMU to cover the end of the point cloud scan based on timestamps. However, this only organizes the data by timestamp; it does not prove that the physical sampling times of the two sensors have been aligned.
In the future, the actual vehicle will need to measure the real synchronization state; if an offset is found, the correction method and its sign must first be confirmed before handling the corresponding code or driver configuration. Currently, setting time_diff_lidar_to_imu to a nonzero value will not complete the correction.
1.1.3.prior_pcd (prior point cloud map)
1.1.3.1.Parameter table
prior_pcd:
enable: False
# NOTE: `prior_pcd_map_path` will be provided in the launch file
# prior_pcd_map_path: ""
init_pose: [ 0.0, 0.0, 0.0 ]
| Parameter | Current value | Units | Hardware guidance | Purpose | Effect of increasing | Effect of decreasing | Activation conditions / notes |
|---|---|---|---|---|---|---|---|
prior_pcd.enable |
False |
Not applicable; boolean | Enable or configure as needed | Select the initial map source: the current scan or an existing PCD | Not applicable | Not applicable | False: build the initial map from the current scan; True: load a prior PCD. The integrated mapping slam_launch.py forces False; configure according to the intended mode after switching |
prior_pcd.prior_pcd_map_path |
Absent from YAML; the program defaults to "" |
Not applicable; file path | Enable or configure as needed | Specify the prior PCD file | Not applicable | Not applicable | Prior-map mode is currently disabled, so this need not be set. It is read only when prior-map mode is enabled. The localization launch supplies the path; running the node directly does not obtain it automatically |
prior_pcd.init_pose |
[0.0,0.0,0.0] |
m; respectively x/y/z | Unused in the current execution path; leave unchanged for now | Set the initial position of the internal IMU position state | Increasing a component shifts the position along that coordinate axis’s positive direction | Decreasing a component shifts the position along that coordinate axis’s negative direction | Used only when enable=True and use_imu_as_input=False; the assignment occurs when the first pose is output |
1.1.3.2.Parameter Details
1.1.3.2.1.enable (prior map loading switch)
enable changes the source of the initial match map.
The current process when False is:
IMU 初始化
→ 累计当前扫描点
→ 达到 init_map_size 门槛
→ 用这些点建立地图
→ 后续匹配并更新地图
When enabled, upon reaching the same initialization threshold, the code switches to reading the PCD and adds its points into the map search structure.
Loading a prior map does not automatically accomplish global relocalization, nor does it automatically determine the robot's position within the entire map. The initial position, pose, and map coordinates must be sufficiently consistent so that subsequent local matching has a basis.
In addition, after enabling the prior, the code delays the insertion of new points; after the relevant valid processing count exceeds 200, it will still continue to update the map. Therefore, this switch does not mean that the map is permanently frozen either.
When loading the prior PCD, coordinate rotation or unit scaling is not automatically performed; the map must also be consistent with the current Point-LIO reference frame. The source code does not check at the call site the null pointer returned when PCD reading fails, so the file must be confirmed to be valid before enabling it.
1.1.3.2.2.prior_pcd_map_path (prior point cloud map path)
Path annotations only hold for the corresponding boot chain.
localization_launch.py will pass the boot parameter prior_pcd_file to: prior_pcd.prior_pcd_map_path
However, it does not automatically change prior_pcd.enable to True because of this. With the current configuration, even if the path is obtained, Point-LIO still does not load it.
And slam_launch.py explicitly overrides: prior_pcd.enable: False
This is consistent with the purpose of mapping from the current scan.
small_gicp in the same positioning startup chain also receives the prior file, but it is another node. Point-LIO closing the prior does not mean that small_gicp did not use the map.
1.1.3.2.3.init_pose (initial position of the internal IMU)
init_pose There are three easily misunderstood points:
- It is [x,y,z], with all three values in meters. The third value is not yaw, and the vector contains no roll/pitch/yaw.
- It specifies the position of the internal IMU origin in camera_init. It does not directly set the navigation position of base_footprint.
- The assignment timing in the local code is unusual. It directly modifies kf_output.x_.pos when the first pose is output, rather than completing initialization before loading the prior map and beginning matching.
Especially under your current setting of “high-frequency odometry enabled, path disabled,” this assignment occurs in the odometry output after the first successful match. Therefore, when enabling the prior in the future, you cannot simply fill in a position and assume that the first round of matching has already started from that position; this initialization sequence needs to be reviewed separately.
1.1.4.preprocess (radar format and point cloud preprocessing)
1.1.4.1.Parameter table
preprocess:
lidar_type: 1 # 1 for Livox serials LiDAR, 2 for Velodyne LiDAR, 3 for ouster LiDAR
scan_line: 4
timestamp_unit: 3 # the unit of time/t field in the PointCloud2 rostopic: 0-second, 1-milisecond, 2-microsecond, 3-nanosecond.
blind: 0.5
Currently lidar_type=1 and scan_line=4 are consistent with the local MID360 driver implementation; blind=0.5 can be used as a baseline first. timestamp_unit=3 does not participate in the conversion in the current Livox CustomMsg branch, but the per-point time is still correctly handled in ns.
| Parameter | Current value | Units | Hardware guidance | Purpose | Effect of increasing | Effect of decreasing | Activation conditions / notes |
|---|---|---|---|---|---|---|---|
preprocess.lidar_type |
1 |
Not applicable; enum | Check against the device model and driver; usually retain the current value | Select the point cloud message type and field parser | Not applicable | Not applicable | Currently uses the Livox CustomMsg branch; must match the input message format |
preprocess.scan_line |
4 |
Lines; count | Check against the device model and driver; usually retain the current value | Specify the accepted scan-line index range | Raise the allowed index limit; does not add points if input indices remain 0–3 | Discard points above the index limit, reducing valid data | The local driver assigns four line indices to MID360; Point-LIO checks line < scan_line |
preprocess.timestamp_unit |
3 |
Not applicable; unit-selection enum | Unused in the current execution path; leave unchanged for now | Specify the units of the PointCloud2 per-point time field | Not applicable | Not applicable | The current CustomMsg path converts offset_time directly from ns to ms, bypassing this switch |
preprocess.blind |
0.5 |
m; distance | Observe closely on hardware; adjust only for a specific problem | Exclude points too close to the point cloud coordinate origin | Expand the excluded region, reducing nearby interference but also losing more useful structure | Retain more nearby structure, potentially also retaining more robot-body or close-range interference points | Used by the current Livox preprocessing path; filters by three-dimensional distance |
1.1.4.2.Parameter Details
1.1.4.2.1.lidar_type (radar type and input format)
lidar_type: Select message format and parse branch. Locally supported values are:
| Value | Processing path |
|---|---|
1 |
Livox CustomMsg, internally named AVIA; the current MID360 also uses this path |
2 |
Velodyne style PointCloud2 with time and ring fields |
3 |
Ouster style PointCloud2 with t and ring fields |
4 |
Hesai XT32 style PointCloud2; this option is absent from the original YAML comments |
It not only determines how fields are parsed, but also determines whether to subscribe to CustomMsg or PointCloud2. The current real-vehicle driver publishes CustomMsg at livox/lidar, so it is set to 1.
The simulation uses 2 because the converter generated Velodyne-style fields, and it does not mean that a Velodyne LiDAR was swapped in the simulation.
1.1.4.2.2.scan_line (number of valid scan lines)
scan_line: Limit the accepted line numbers. The current judgment condition is:msg->points[i].line < N_SCANS
N_SCANS comes from scan_line, so it is allowed when set to 4:line = 0、1、2、3
The local driver defines kLineNumberMid360=4 for MID360, and generates the line field as follows:point.line = i % pkt.line_num;Therefore, the current value of 4 has a basis in the driver code.
For example:
- Change to 2: accept only lines 0 and 1, discard lines 2 and 3.
- Change to 8: if the input still has only 0–3, no new points will be generated. It is mainly a parameter for matching the input format. To adjust point density, first look at point_filter_num and the voxel size discussed earlier.
1.1.4.2.3.timestamp_unit (time unit within a point)
timestamp_unit: explains the unit of the point-by-point time field. The local enumeration and conversion relationships are:
| Value | Input field unit | Multiplier to convert to internal ms |
|---|---|---|
0 |
Seconds, s | ×1000 |
1 |
Milliseconds, ms | ×1 |
2 |
Microseconds, μs | ×0.001 |
3 |
Nanoseconds, ns | ×0.000001 |
This selection is used in the normal PointCloud2 branch. For example, Velodyne's time and Ouster's t undergo the corresponding conversion.
However, your current Livox CustomMsg path directly executes:curvature = offset_time / 1000000.0;That is, it always converts from ns to ms. Therefore, the current modification of timestamp_unit will not change the time interpretation of this input path.
Let’s give a purely numerical example:
offset_time = 25,000,000 ns
= 25 ms
= 0.025 s
The processing time for this point is:
点云 header.stamp + 0.025 s
Point-by-point time participates in motion prediction and point cloud matching, and cannot be arbitrarily discarded during input conversion; time unit conversion also does not accomplish the time offset calibration between the radar and IMU.
1.1.4.2.4.blind (close-range blind zone filtering)
blind: Close-range exclusion radius. The current code calculates:
When:
discard that point. Therefore, blind=0.5 means excluding points less than 0.5 m from the origin of the radar point cloud coordinate system; the region is a spherical volume.
For example:
- Points at a distance of 0.3 m: excluded by this filter.
- Points at a distance of 0.6 m: pass the lower distance limit check, but may still be excluded by other conditions.
The distance here is a three-dimensional distance, which differs from the height of the point and the distance from the robot center. This filtering acts on both robot points and environment points, so when it is increased, valid points from nearby walls, the ground, and obstacles will also be lost.
After the real vehicle is in place, first observe whether there is still obvious vehicle body interference after 0.5 m filtering and whether nearby valid structures are insufficient, then decide whether to adjust. Currently there is no such measured evidence, so keep 0.5 for now.
1.1.5.mapping (motion state estimation and point cloud matching)
1.1.5.1.Which issues should be checked first on the actual vehicle?
This section is responsible first for making Point-LIO align position, motion, and map estimation; whether the ramp is passable is then determined by terrain analysis and the costmap. When issues occur on the real vehicle, first find the parameters according to the phenomena below; there is no need to read the noise formulas first.
| Observed on hardware | Parameters or relationships to check first | Specific checks |
|---|---|---|
| The robot is stationary, but the estimated position changes noticeably | acc_norm、gravity; then check data timing and installation relationships |
Verify acceleration units and whether the system’s up and down direction matches the navigation reference frame. Drift alone does not prove a noise value is wrong |
| Level ground appears tilted, or ramp elevation directions are wrong | gravity and the complete coordinate transformation chain |
Stationary IMU readings, LiDAR installation orientation and the relationship from the Point-LIO frame to odom must agree; do not simply substitute an array pointing downward |
| The entire MID360 is tilted or rotates with gimbal yaw | extrinsic_T/R and the robot mounting TF |
Distinguish the internal LiDAR and IMU relationship from the entire sensor’s installation on the robot; rotating the unit does not change its internal origin positions |
| Localization jumps when crossing seams or bumps | satu_acc、imu_meas_acc_cov、acc_cov_output |
First check bracket rigidity, acceleration units and peaks, and timing interfaces. Then assess how the algorithm should distinguish vibration from actual motion |
| Walls ghost or heading jumps when the chassis or gimbal rotates rapidly | satu_gyro、imu_meas_omg_cov、gyr_cov_output and the per-point timing interface |
Check whether angular velocity approaches the measurement-range limit and whether data arrives promptly; noise tuning alone cannot solve these symptoms |
| Few usable matched points at wall corners, on the ground or on slopes | plane_thr、match_s、ivox_grid_resolution |
Check for enough reliable neighboring map points. A slope can also be planar; these three parameters do not define a maximum climbing angle |
Currently using the MID360 internal IMU, keep imu_en=True and use_imu_as_input=False. The MCU world pose cannot replace the mechanical joint angles; the actual yaw is at gimbal_yaw_joint; the actual pitch is at gimbal_pitch_joint; the two odom joints are fixed, and the MID360 rotates with yaw but not with independent pitch.
The following noise parameters mainly determine whether the system trusts the measurements more or trusts the original motion trend more. First confirm the units, timing, and installation relationships, then discuss the noise; they will not make a loose bracket stable, nor are they vehicle speed or slope limits. There is no physical object in this round, so no new tuning values are specified based on these phenomena.
1.1.5.2.Parameter table
The output model currently uses use_imu_as_input=False; the following explanation is based on this operating branch; the "current value" comes from the physical configuration, not the runtime node value read in this round. g₀ in the table is the gravity vector in the YAML above, with a current magnitude of approximately 9.81 m/s².
The units of the noise parameters are derived according to the local equations of motion and covariance formulas; they are not all equivalent to the noise densities in the sensor datasheets.
mapping:
imu_en: True
extrinsic_est_en: False # for aggressive motion, set this variable False
imu_time_inte: 0.005 # = 1 / frequency of IMU
lidar_time_inte: 0.1
satu_acc: 4.0 # the saturation value of IMU's acceleration. not related to the units
satu_gyro: 35.0 # the saturation value of IMU's angular velocity. not related to the units
acc_norm: 1.0 # 1.0 for g as unit, 9.81 for m/s^2 as unit of the IMU's acceleration
lidar_meas_cov: 0.01 # 0.001
acc_cov_output: 500.0
gyr_cov_output: 1000.0
b_acc_cov: 0.0001
b_gyr_cov: 0.0001
imu_meas_acc_cov: 0.1
imu_meas_omg_cov: 0.1
gyr_cov_input: 0.1 # for IMU as input model
acc_cov_input: 0.1 # for IMU as input model
plane_thr: 0.1 # 0.05, the threshold for plane criteria, the smaller, the flatter a plane
match_s: 81.0
ivox_grid_resolution: 0.5
# 测量平均值是[0.00423894,0.71588876,0.69592434]经过公式计算得出[-0.04166067, -7.03407005, -6.83785222]
gravity: [-0.04166067, -7.03407005, -6.83785222] # gravity to be aligned # rpy = [0, pi/6, 0]
gravity_init: [-0.04166067, -7.03407005, -6.83785222] # preknown gravity in the first IMU body frame, use when imu_en is False or start from a non-stationary state
extrinsic_T: [ -0.011, -0.02329, 0.04412 ]
extrinsic_R: [ 1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0 ]
| Parameter | Current value | Units | Hardware guidance | Purpose | Effect of increasing | Effect of decreasing | Activation conditions / notes |
|---|---|---|---|---|---|---|---|
mapping.imu_en |
True |
Not applicable; boolean | Usually keep the current value; not a priority for tuning | Use the internal MID360 IMU to help estimate rotation and acceleration | Not applicable | Not applicable | Keep True for now; disabling it removes this inertial information and is not a routine way to reduce vibration |
mapping.extrinsic_est_en |
False |
Not applicable; boolean | Usually keep the current value; not a priority for tuning | Whether to refine the internal LiDAR and IMU position and orientation relationship during operation | Not applicable | Not applicable | Current False uses fixed extrinsics; tilting the entire MID360 or rotating gimbal yaw does not require enabling this |
mapping.imu_time_inte |
0.005 |
s | Unused in the current execution path; leave unchanged for now | Record the nominal IMU time interval; currently not used in calculations | No change in the current implementation | No change in the current implementation | 0.005 s corresponds to a nominal 200 Hz period; actual timing comes from message timestamps. Changing this cannot change the hardware frequency |
mapping.lidar_time_inte |
0.1 |
s | Usually keep the current value; not a priority for tuning | Fallback time window used in the abnormal point cloud branch | Longer fallback window | Shorter fallback window | Normal scans use per-point times to calculate the scan end; this does not set the LiDAR frequency |
mapping.satu_acc |
4.0 |
g; current raw input units | Check against the device model and driver; usually retain the current value | Temporarily exclude an axis from updates when its acceleration approaches the range limit | Exclude less data, potentially accepting clipped readings | Exclude more data, potentially rejecting normal bumps | The current effective threshold is 3.96 g. Check input units, device range and actual peaks; this is not the permitted vehicle acceleration |
mapping.satu_gyro |
35.0 |
rad/s | Check against the device model and driver; usually retain the current value | Temporarily exclude an axis from updates when its angular velocity approaches the range limit | Exclude less data | Exclude more data | The current effective threshold is 34.65 rad/s, approximately 1985°/s; this is not a vehicle or gimbal speed limit |
mapping.acc_norm |
1.0 |
g; current raw input units | Verify and configure correctly before running on hardware | Convert raw IMU acceleration into the metric units used by the algorithm | Smaller converted acceleration | Larger converted acceleration | Raw input currently uses g, hence 1.0. The combined stationary reading across three axes is about 1 g; no individual axis must read 1 |
mapping.lidar_meas_cov |
0.01 |
Intended as m²; the implementation is inconsistent | Usually keep the current value; not a priority for tuning | Control the influence of LiDAR matching on the pose, but usage is inconsistent in the local code | Opposite effects in different solver branches | Opposite effects in different solver branches | Retain 0.01 for now; verify the code inconsistency separately. It cannot be treated as a universal LiDAR trust control |
mapping.acc_cov_output |
500.0 |
m²/s⁶; derived from the local formula | Observe closely on hardware; adjust only for a specific problem | Allow the estimated acceleration to change at a given rate | Follow observations more readily, potentially also following jitter | Favor the previous trend; may respond slowly to sudden acceleration or deceleration | Used by the current output model; interpret together with acceleration measurement noise |
mapping.gyr_cov_output |
1000.0 |
rad²/s⁴; derived from the local formula | Observe closely on hardware; adjust only for a specific problem | Allow the estimated angular velocity to change at a given rate | Follow observations more readily, potentially also following jitter | Favor the previous trend; may respond slowly to sudden rotation | Used by the current output model; not an angular-velocity value or actual gyroscope noise measurement |
mapping.b_acc_cov |
0.0001 |
m²/s⁶; derived from the local formula | Usually keep the current value; not a priority for tuning | Allow the estimated accelerometer bias to change at a given rate | Bias changes more readily; too high may mistake actual movement for bias | More stable bias, potentially adapting more slowly to gradual drift | Used by both models; retain the current value first. Do not use it to hide unit or direction errors |
mapping.b_gyr_cov |
0.0001 |
rad²/s⁴; derived from the local formula | Usually keep the current value; not a priority for tuning | Allow the estimated gyroscope bias to change at a given rate | Bias changes more readily | More stable bias, potentially adapting more slowly to drift | Used by both models; nonzero stationary angular velocity should first prompt checks of the actual data and bias source |
mapping.imu_meas_acc_cov |
0.1 |
m²/s⁴ | Observe closely on hardware; adjust only for a specific problem | Determine how much the algorithm trusts this acceleration reading | Trust acceleration measurements less, reducing their influence | Trust acceleration measurements more, potentially following noise more readily | Used by the current output model on converted acceleration; not the variance of the raw g-valued readings |
mapping.imu_meas_omg_cov |
0.1 |
rad²/s² | Observe closely on hardware; adjust only for a specific problem | Determine how much the algorithm trusts this angular-velocity reading | Trust angular-velocity measurements less | Trust angular-velocity measurements more, potentially following noise more readily | Used by the current output model; consider together with angular-velocity change parameters during vibration and rapid rotation |
mapping.gyr_cov_input |
0.1 |
rad²/s² | Unused in the current execution path; leave unchanged for now | Angular-velocity input noise used by the other estimation model | No current effect; increases prediction uncertainty after switching to the input model | No current effect; decreases prediction uncertainty after switching to the input model | Currently use_imu_as_input=False, so it does not participate in this round’s prediction |
mapping.acc_cov_input |
0.1 |
m²/s⁴ | Unused in the current execution path; leave unchanged for now | Acceleration input noise used by the other estimation model | No current effect; increases prediction uncertainty after switching to the input model | No current effect; decreases prediction uncertainty after switching to the input model | Currently use_imu_as_input=False, so it does not participate in this round’s prediction |
mapping.plane_thr |
0.1 |
m | Observe closely on hardware; adjust only for a specific problem | Determine whether a small patch of map points is planar enough for matching | Accept less planar point groups, potentially including edges and curved surfaces | Require greater planarity, potentially reducing usable matches | Check deviations of five neighboring map points from the fitted plane. The plane may be inclined; this is not a slope or traversable-height threshold |
mapping.match_s |
81.0 |
Implicit m⁻¹; empirical coefficient | Observe closely on hardware; adjust only for a specific problem | Determine whether the current LiDAR point is close enough to the matched map plane | Stricter acceptance; fewer matches | Looser acceptance; more matches, potentially including incorrect matches | Check the distance residual between the current point and map plane; not map accuracy or the permitted vehicle-to-obstacle distance |
mapping.ivox_grid_resolution |
0.5 |
m; grid side length | Observe closely on hardware; adjust only for a specific problem | Partition the map to find nearby points suitable for matching | Fixed neighboring cells cover a larger region; searches may take longer | Smaller coverage; may fail to find enough neighbors | Does not directly remove map points; not a parameter specifying detectable obstacle size |
mapping.gravity |
g₀ |
m/s² | Verify and configure correctly before running on hardware | Set gravity direction and conversion magnitude in the Point-LIO reference frame | Increase magnitude in the same direction: increase gravity and acceleration conversion together | Decrease magnitude in the same direction: decrease both together | Magnitude is already approximately 9.81; do not change it again. Distinguish initial gravity in the IMU frame from gravity in the target frame; direction still needs verification |
mapping.gravity_init |
g₀ |
m/s² | Unused in the current execution path; leave unchanged for now | Initial gravity preset used when the IMU is disabled | No current effect | No current effect | Currently imu_en=True, so initialization uses mean IMU acceleration. Changing this cannot adjust the current up and down direction |
mapping.extrinsic_T |
[-0.011,-0.02329,0.04412] |
m; three-dimensional translation | Check against the device model and driver; usually retain the current value | Describe the LiDAR origin relative to the internal IMU | Increase the conversion offset along the corresponding coordinate axis | Decrease the conversion offset along the corresponding coordinate axis | Units are meters; in millimeters: -11, -23.29, +44.12. This is not the LiDAR mounting position relative to the chassis or gimbal |
mapping.extrinsic_R |
3×3 identity matrix | Dimensionless; rotation matrix | Check against the device model and driver; usually retain the current value | Describe how the LiDAR and internal IMU axes correspond | Not applicable; do not arbitrarily increase individual elements | Not applicable; do not arbitrarily decrease individual elements | The identity matrix means the input frames’ axes align. Tilting the entire MID360 belongs in the robot TF; also check whether the driver applies an additional data rotation |
1.1.5.3.Parameter Details
1.1.5.3.1.imu_en (Enable radar internal IMU)
Currently, True indicates that the MID360 internal IMU is used. During continuous LiDAR scanning, the IMU helps the algorithm determine how the sensor is rotating and accelerating or decelerating, and it also participates in initial orientation determination.
It is not in conflict with use_imu_as_input=False: the IMU is still in use, only the algorithm uses it in a different way. When the real vehicle has vibration, check the installation and data first; "disabling the IMU" should not be treated as an ordinary anti-vibration measure.
1.1.5.3.2.extrinsic_est_en (Online Estimation of Radar and IMU Extrinsics)
This decision determines "whether the position and orientation relationship between the radar and the internal IMU is fixed or estimated by the algorithm during operation". Currently False uses the configuration's extrinsic_T/R.
The MID360's lidar and internal IMU are housed in the same device; tilting the entire unit, rotating the chassis, and rotating the gimbal yaw will not change the fixed relationship between the two. How the entire lidar is mounted on the vehicle and which joint it rotates with are described by the robot TF and cannot be replaced by enabling this option.
1.1.5.3.3.imu_time_inte (IMU nominal time interval)
0.005 seconds corresponds to a nominal period of 200 Hz, but the current source code only reads this value and does not use it for calculation. Changing it to a smaller number will not make the physical IMU output faster; the actual data interval depends on the message timestamp. No adjustment will be made for now.
1.1.5.3.4.lidar_time_inte (fallback time window for abnormal point clouds)
It mainly provides a time window for fallback branches such as lost point cloud or no valid points. The end time of a normal scan is calculated from the time of each point, not mandatorily determined by this 0.1 second.
Therefore, one cannot simply see that the driver publishes at 20 Hz and change it to 0.05 according to 1/20. The actual frequency, per-point timing, and fallback window are different matters; for now, keep them as they are.
1.1.5.3.5.satu_acc (acceleration reading saturation threshold)
It can be understood as "when the acceleration reading is close to the edge of the range, the algorithm should not fully trust this axis yet." The current code compares the raw readings axis by axis, and when it reaches 0.99×4.0=3.96 g it masks this IMU update for that axis.
On the real robot, this relates to bumps, sudden acceleration or deceleration, and vibration. However, 4.0 does not mean that the hardware range has been confirmed as 4 g, nor does it specify the vehicle’s maximum permitted acceleration. First verify the model, actual range settings, input units and peaks during normal movement. A threshold that is too low may reject normal bump data; one that is too high may continue accepting clipped readings.
The original note "unit-independent" does not hold. The current input is g; if it is changed to m/s² and 4.0 is still used as is, then under normal stationary conditions the reading on a given axis may exceed the threshold. When the unit changes, this item must be reviewed together.
1.1.5.3.6.satu_gyro (angular velocity reading saturation threshold)
This provides the same kind of protection for angular velocity. The current effective threshold is 0.99×35.0=34.65 rad/s, approximately 1985°/s or 5.51 revolutions per second. It compares the IMU readings on each axis, rather than the spinning velocity commanded to the chassis.
When rotating the chassis or gimbal quickly, check whether the actual peak value approaches the device range and whether limiting occurs; currently only check_satu=True executes this protection. Increasing it will not allow the vehicle to rotate faster, nor can it directly solve heading drift.
1.1.5.3.7.acc_norm (acceleration unit conversion reference)
The most important role of this parameter is unit conversion. The current local driver publishes MID360 acceleration in g, while Point-LIO calculates internally in m/s². Thus, acc_norm=1.0 converts a raw reading of 1 g to approximately 9.81 m/s². Data unit definitions in the Livox driver
When the physical object is stationary, the combined magnitude of the three axes should be close to 1 g. After the radar is installed at an angle, gravity will be distributed across multiple axes; it is not required that any one axis must equal 1, nor that the other two axes must both be 0. Here, acc_norm and gravity having a length of approximately 9.81 do not conflict: one corresponds to the raw reading unit, and the other corresponds to the internal metric calculation.
If it is still a g input but is changed to 9.81, the original 1 g will be replaced with approximately 1 m/s², and the ratio will be off by nearly a factor of 10. Currently keep it at 1.0; this item cannot be used to "suppress drift" or eliminate vibration. Only after changing the driver, performing a unit conversion, or changing the sensor should it be reconfirmed according to the actual input.
1.1.5.3.8.lidar_meas_cov (Effect of laser matching on pose)
This affects "how much the laser matching result contributes to the pose." However, the two solving branches in the local code have inconsistent directions, so it cannot be simply recorded as "increasing it makes the radar less trusted."
When a single update currently has fewer than 30 valid matched points, increasing this value generally reduces the LiDAR’s influence. Once it reaches 30 points, the other formula has the opposite effect. The count applies to one per-point or time-group update, rather than a complete frame. The source-code inconsistency is confirmed, but its actual activation and effects have not been tested. The value remains 0.01 for now.
The following IMU noise can first be understood in two sentences:Measurement noisegoverns "how much to trust this reading";Process noise of the motion stategoverns "how quickly the original motion estimate is allowed to change." They serve different roles and should not be increased together just because their names both contain cov. The units in the table are derived from local formulas and also cannot be directly compared with manufacturer noise density or raw g readings.
1.1.5.3.9.acc_cov_output (uncertainty in the variation of the acceleration estimate)
It governs "whether the acceleration in the estimate is easy to change." When the vehicle accelerates hard, brakes, or hits bumps, increasing it usually allows the measurement to correct the previous estimate more quickly, while decreasing it tends to maintain the original trend; if the readings are mainly vibration, allowing it to change too quickly may also cause the estimate to jitter along with them.
Currently, 500 is an uncertainty coefficient internal to the program; it is not adding an acceleration of 500 to the vehicle, nor is it measured sensor noise. It should be understood together with imu_meas_acc_cov and unit, time, and installation errors should be ruled out first.
1.1.5.3.10.gyr_cov_output (uncertainty in speed estimation variation)
It is similar to the previous item and controls "whether the estimated rotational speed is easy to change". When the chassis or gimbal is suddenly rotated, increasing it usually allows faster tracking of observations, while decreasing it trusts the original rotational trend more.
Currently, 1000 is not the upper limit of the vehicle speed, nor is it a measurement result of the actual gyroscope noise. It needs to be checked together with imu_meas_omg_cov and the angular velocity peak value and time interface; one cannot conclude that this item should be increased merely based on ghosting during rotation.
1.1.5.3.11.b_acc_cov (noise of accelerometer bias variation)
"Zero bias" is a persistent small offset in the sensor readings. It controls how quickly the algorithm's estimated acceleration zero bias can change: a larger value makes changes easier, while a smaller value is more stable but adapts to drift more slowly. If it is too large, real motion may be interpreted as bias. For now, keep it at 0.0001.
1.1.5.3.12.b_gyr_cov (noise of gyroscope bias variation)
It controls the rate of change of the gyroscope bias estimate. If the angular velocity continuously deviates from zero when the physical unit is stationary, first verify the real data and the source of the deviation; increasing this does not guarantee elimination of heading drift. For now, keep it at 0.0001.
1.1.5.3.13.imu_meas_acc_cov (confidence of acceleration readings)
It governs “how much to trust this acceleration reading.” Increasing it means trusting the reading less, reducing its corrective effect; decreasing it means trusting the reading more, and also being more susceptible to vibration effects.
Currently, 0.1 is the noise assumption adopted by the algorithm, not the sensor accuracy that has already been measured; it acts on the converted m/s² data. When combined with acc_cov_output, it is necessary to distinguish between two things: "whether the readings are credible or not" and "whether the estimate can keep up with real changes."
1.1.5.3.14.imu_meas_omg_cov (speed reading reliability)
It controls "how much to trust this rotational speed reading". Increasing it reduces the influence of angular velocity measurement; decreasing it trusts it more. When the physical object rotates or vibrates, you should simultaneously observe whether the reading is clean and whether the motion estimation keeps up, then combine with gyr_cov_output to judge. The current 0.1 is also not the manufacturer's accuracy commitment.
1.1.5.3.15.gyr_cov_input (speed noise of the IMU prediction model)
Current use_imu_as_input=False. This item does not participate in the prediction of the current model. Changing it cannot improve the rotation performance of this round, so it will not be adjusted for now. It will only be reinterpreted and verified after switching to another model.
1.1.5.3.16.acc_cov_input (acceleration noise of the IMU prediction model)
It also belongs to another model and is not currently used for prediction. Do not change this item just because the acceleration has jitter; at this point you should check the actually effective acceleration noise term, its units, and its installation.
1.1.5.3.17.plane_thr (flatness threshold for map neighbors)
It determines “whether these 5 nearby map points can be considered a relatively flat surface.” Currently, 0.1 m means each neighboring point should not deviate from the fitted plane by more than 10 cm.
The slope may also be a flat inclined plane. The source code does not use this to constrain the inclination angle of the surface, so it is neither a maximum slope nor the obstacle threshold of "prohibiting passage when 10 cm above the ground"; the latter belongs to the judgment of the terrain and costmap.
Check it when matching is insufficient near wall corners, curved surfaces, cluttered points, or sparse points in real vehicles. Increasing it accepts more uneven point clusters and may also accept erroneous surfaces; decreasing it makes it stricter, and available matches may decrease.
1.1.5.3.18.match_s (matching threshold between new points and the map plane)
After the map neighboring points have already formed a face, it then determines “whether the current radar point is too far from this face.” This analysis is only combined when there is map wall ghosting, incorrect matching, or very few valid matches.
The larger the current 81, the stricter the condition. The distance error allowed by the code also varies with the distance from the point to the radar, for example about 11.1 cm at 1 m and about 22.2 cm at 4 m; these are matching thresholds, not positioning accuracy or how far the vehicle must stay from the wall.
plane_thr Check whether the neighboring map point itself is flat;match_s Check whether the new point can align with this plane. The two criteria cannot both be relaxed simply because the map looks bad; timing and extrinsic calibration errors can also produce similar phenomena.
1.1.5.3.19.ivox_grid_resolution (map search grid size)
It divides the map into blocks to facilitate finding nearby matching points. The current grid side length is 0.5 m, which, together with the neighboring grid search method, determines the coverage range of each search.
Increasing it covers a larger range but may search more points; decreasing it shrinks the range and may fail to find enough neighboring points. It does not directly delete obstacles smaller than 0.5 m, nor is it the downsampling size of the current scan; first observe it together with the number of matched points and the computational load.
1.1.5.3.20.gravity and gravity_init (the gravity of the target reference frame and the initialization gravity)
gravityThe most important physical meaning is:Point-LIO When establishing one's own reference frame, which side should be understood as "downward," and by how much the magnitude of gravity should be calculated. It affects the initial attitude and acceleration conversion; if the direction is wrong, the ground, height, and subsequent slope recognition may all be affected, and this cannot first be masked by loosening the terrain height range.
The current vector length is already approximately 9.81 m/s², so there is no need to change the magnitude again. When the radar is tilted as a whole, gravity components will be seen simultaneously on several axes of the IMU itself; after the vehicle goes uphill, the components on each axis will also change. This does not mean that the gravity in the configuration should be changed every time according to the readings; it describes the relationship of the selected target reference frame.
Two things need to be distinguished:
- The gravity direction initially observed by the IMU itself: With the current
imu_en=True, the code normalizes and negates the mean of an initial sequence of acceleration readings, then scales it by 9.81. This is still a direction in the IMU’s own coordinate frame. - The desired gravity direction in the Point-LIO reference frame: This is provided by
mapping.gravity. The code calculates the initial rotation between these two directions, and downstream interfaces must correctly connect the result to theodomframe used for navigation.
Negating stationary readings therefore tells us where gravity points in the initial IMU frame, but without checking the coordinate frames, it cannot be equated directly with mapping.gravity. Likewise, the fact that navigation usually uses an upward z axis does not justify changing it to [0,0,-9.81] without further checks. Verify the Point-LIO reference frame, the sensor installation and how downstream interfaces connect. The direction and values remain unchanged pending verification.
gravity_initis the initial gravity preset provided when the IMU is not used. Although the current parameter is read in, the initialization uses the real IMU average acceleration,gravity_initand does not participate in this branch; changing it cannot correct the up-down direction of the current system.
The installation theory and measurement records from the original logs are retained below as clues. No commands from them were executed in this round, and no new physical measurements were added; the equipment, installation orientation, and driver configuration used in these records still need to be verified.
The current model sets the installation roll of the entire MID360 to -π/4, i.e., -45°; whether the model settings are consistent with the actual axial direction recorded for the old physical unit still needs to be verified.
Method 1: Theoretical calculation under consistent axis conventions, an initially horizontal vehicle body, and only the aforementioned roll present
When the robot is stationary, the IMU's linear_acceleration essentially measures the "specific force" opposite to gravity. If it only rolls around the X-axis by an angle r, then when stationary, approximately:
ax = 0
ay = g·sin(r)
az = g·cos(r)
g = 9.81 m/s²
r = -45°
ax = 0
ay = 9.81 × sin(-45°)
≈ -6.9367
az = 9.81 × cos(-45°)
≈ +6.9367
Simulation
Method 2: Measurement method
IMU measurement in simulation environment:
ros2 topic echo /red_standard_robot1/livox/imu --once
linear_acceleration:
x: 1.877548187489191e-05
y: -6.929646440459081
z: 6.929646470797371
For this set of old simulation records, Y-negative and Z-positive are consistent with the calculations under the above theoretical conditions; it did not verify physical installation, nor can it alone prove that the up-down direction of the navigation reference frame is correct.
Then negate it to obtain the gravity in the initial IMU's own coordinates. The gravity label in the old code snippet below should be understood with this meaning, rather than being required to be filled directly into mapping.gravity:
gravity
≈ [0, +6.93, -6.93]
Static measurements help verify the IMU's actual axes, but the measured initial IMU orientation must still be distinguished from the target reference frame; measurement results alone cannot replace the entire coordinate relationship check.
Legacy physical record (installation and data source pending verification)
Method 2: Measurement method
source install/setup.bash
ros2 launch livox_ros_driver2 msg_MID360_launch.py
ros2 topic echo /livox/imu --once
平均 linear_acceleration ≈
x = 0.00424
y = 0.71589
z = 0.69592
For this set of old records, Y is positive, whereas the Y in the above -45° theoretical and simulation records is negative.atan2(0.716, 0.696) ≈ 45.8° This cannot be explained merely as a small machining error of 0.8°: there is also a sign difference in direction. The physical installation at the time, coordinate axes, startup configuration, and whether the drive had any additional rotation should first be checked, and only then can it be determined whether the records can be directly compared; in this round, there is no physical evidence to explain their origin.
Below isPoint-LIOthe code:
tmp_gravity =
-mean_acc / mean_acc.norm() * G_m_s2;
It is just three steps: first compute the average acceleration → compute the magnitude of this vector → after normalization, take the negative.
First calculate the mean acceleration: mean_acc = [0.00423894,0.71588876,0.69592434] Then calculate the magnitude of mean_acc: mean_acc.norm() =sqrt(0.00423894²+ 0.71588876²+ 0.69592434²) ≈ 0.99841142 ≈ 1.0 The combined raw reading across the three axes is approximately 1 g. The code uses G_m_s2≈9.81 m/s² internally for conversion. The values 1 and 9.81 here correspond to different units. Substitution into the formula gives [0.04166067, 7.03407005, 6.83785222]. The formula has a minus sign, so negating it gives [-0.04166067, -7.03407005, -6.83785222]
This yields the initial IMU self gravity vector corresponding to the old record. The current YAML does indeed use the same set of numbers, but whether it conforms to the selected Point-LIO / navigation reference frame still needs to be verified; a magnitude of approximately 9.81 being correct does not mean the directional relationship has also been verified. This round does not change the direction.
Source code supplement: when the two initial gravity directions happen to be exactly opposite,Set_init one branch of returns -Eye3d, and this matrix is not a valid three-dimensional rotation matrix. This extreme branch needs to be verified separately; this round did not prove that the existing configuration triggers it, nor was the source code modified.
1.1.5.3.21.extrinsic_T (positional relationship between the radar and the internal IMU)
This describes the position of the LiDAR origin relative to the internal MID360 IMU origin. The current code uses p_I=R_IL·p_L+t_IL. The vector [-0.011,-0.02329,+0.04412] m corresponds to [-11,-23.29,+44.12] mm.
This internal relationship is separate from where the LiDAR is mounted on the chassis or gimbal. Changing the bracket, tilting the entire sensor or rotating the gimbal does not change the distance between its two internal origins. Describe the sensor’s installation in the robot TF. Incorrect values or directions may cause position errors and ghosting during rotation, but the same symptoms can also result from timing or downstream interfaces.
For the physical setup, it is necessary to verify the device model, the definitions of the point cloud and IMU origins, and whether there is any additional transformation before the data enters Point-LIO; the installation distance from the gimbal to the LiDAR must not be entered here. The existing values are retained and are not treated as conclusions of a new calibration in this round.
1.1.5.3.22.extrinsic_R (axial relationship between the radar and the internal IMU)
It describeshow the radar coordinate axes correspond to the internal IMU coordinate axes。The current identity matrix indicates that the two input channels are used with consistent axial directions. When the entire MID360 is mounted at an angle, the radar and the internal IMU tilt together, so the -45° mounting angle of the whole unit must not be filled into this item because of that.
Also verify whether the driver has already rotated the data: the local driver contains code that rotates the IMU, and currently the three rotation items read from the MID360 configuration are all 0. When switching configurations later, check whether the point cloud and IMU still correspond as expected; do not rely solely on their message names.
The overall installation angle belongs to the robot TF, and the internal axial correspondence belongs to extrinsic_R. The rotation matrix must be given by an explicit coordinate relationship; individual numbers must not be arbitrarily increased or decreased.
1.1.5.3.23.vel_cov (Uncertainty in the variation of velocity estimates)
This parameter is absent from the current YAML and defaults to 20 in the source code. The current output model uses it to describe uncertainty in the velocity state. It does not specify the vehicle’s maximum speed: increasing it lets observations change the estimated velocity more easily, while decreasing it favors retaining the existing estimate. Keep the default for now. If acceleration or deceleration responses are abnormal, first rule out problems with units, timing and pose transformations.
1.1.5.4.Physical verification and validation scope of this block
Once the hardware is available and a separate inspection is authorized, prioritize these checks: whether the combined stationary acceleration across all three axes is about 1 g; whether angular-velocity readings are near zero and use the correct units; whether point clouds and IMU data use the expected axes; whether sensor installation and internal extrinsics have been confused; and whether readings clip, or the estimated pose and walls fail to keep up, when the chassis or gimbal rotates or encounters bumps.
At present, no single symptom such as tilted ground, ghosted walls or stationary drift is sufficient evidence that a particular parameter must change. Raw units, timing, installation and downstream IMU or LiDAR pose interfaces all affect the result. Source-code gaps require separate fixes; blindly tuning noise cannot guarantee a solution.
- Confirmed from the source code: The current IMU input units, acceleration conversion, saturation thresholds, activation branches for each parameter, internal extrinsic usage, and the recorded solver and initialization concerns. Only the provenance of installed packages and the current hardware YAML was checked in the container; running-node parameters were not read.
- Observed in simulation: On 2026-10-08, Point-LIO pose and registered point cloud output were observed while stationary and during roughly 20 cm of back-and-forth motion. Slopes, long distances, rapid rotation, independent gimbal yaw and actual vibration were not verified. Earlier commands and readings in this block remain as historical records; they do not expand this round’s verification scope.
- Requires hardware verification: The actual installation, axis and origin definitions, range settings, stationary readings and movement peaks. Gravity magnitude is already about 9.81, while its direction and target reference frame still require checks. No new measurements were taken, and no source code, configuration or parameter values were changed.
1.1.6.odometry (odometry publishing settings)
1.1.6.1.Parameter table
odometry:
publish_odometry_without_downsample: True
| Parameter name | Current value | Unit | Recommended action for real vehicle tuning | Function | Effect of increasing | Effect of decreasing | Activation conditions / Notes |
|---|---|---|---|---|---|---|---|
publish_odometry_without_downsample |
True |
Not applicable, boolean | Usually keep the current value; not used as a priority tuning item | Publish odometry after point-by-point update or after each frame processing | Not applicable | Not applicable | True: publish after successful match update; False: publish once per frame; point cloud downsampling is still performed |
1.1.6.2.Parameter Details
1.1.6.2.1.publish_odometry_without_downsample (odometry publish tick)
This switch controls the timing of the odometer output:
- True: Publish after every successful per-point or time-group match, using the current sampling time as the timestamp. Output is more frequent, with the actual frequency determined by the number of successful updates.
- False: Publish once after each frame is processed, using the end of the scan as the timestamp. With 20 Hz input and normal processing of every frame, output is usually about 20 Hz.
For now, keep it as True. Later, if the output and received load becomes too high, consider False again; what changes is the output cadence, while per-point estimation and point cloud downsampling are still performed.
1.1.7.publish (trajectory, point cloud, and TF output switch)
1.1.7.1.Parameter table
publish:
path_en: False # False: close the path output
scan_publish_en: True # False: close all the point cloud output
scan_bodyframe_pub_en: False # True: output the point cloud scans in IMU-body-frame
tf_send_en: False # True: send transform from 'camera_init' to 'aft_mapped'
| Parameter name | Current value | Unit | Vehicle processing suggestion | Function | Effect of increasing | Effect of decreasing | Effective conditions / notes |
|---|---|---|---|---|---|---|---|
path_en |
False |
Not applicable, Boolean | Enable or set according to actual functional requirements | Whether to publish the accumulated runtime trajectory | Not applicable | Not applicable | When True, publish path, with coordinate frame camera_init; trajectory continuously accumulates |
scan_publish_en |
True |
Not applicable, Boolean | Usually keep the current value; not a priority debugging item | Whether to publish the registered scan point cloud in the reference frame | Not applicable | Not applicable | Publish cloud_registered, with coordinate frame camera_init; local PCD point cloud accumulation also depends on this switch |
scan_bodyframe_pub_en |
False |
Not applicable, Boolean | Enable or set according to actual functional requirements | Whether to additionally publish the point cloud in the internal IMU coordinate frame | Not applicable | Not applicable | Requires scan_publish_en to also be True; the topic is cloud_registered_body, and the coordinate frame is body |
tf_send_en |
False |
Not applicable, Boolean | Usually keep the current value; not a priority debugging item | Whether Point-LIO publishes its own pose TF | Not applicable | Not applicable | The current integration chain keeps False; True publishes camera_init → aft_mapped, and the values correspond to the internal IMU pose; when enabled for standalone debugging, the TF organization must be checked, and it is not the chassis pose TF |
1.1.7.2.Parameter Details
1.1.7.2.1.path_en (odometry trajectory publication)
When True, publish the accumulated path trajectory to conveniently observe the motion route of the robot sensors in RViz; when False, disable this trajectory output, while odometry is still published as usual.
It can be enabled as needed when observing SLAM trajectories. There is no fixed upper limit on trajectory length; long-term accumulation will increase memory and display load.
1.1.7.2.2.scan_publish_en (publishing the registered point cloud in the reference frame)
Currently keep True, publish cloud_registered registration scan for use by RViz and subsequent interfaces.
When False, the current registration scan and the body point cloud output that depends on it are disabled; internal estimation and mapping continue. The original comment "disable all point cloud output" is not entirely accurate: the initialized Laser_map can still be published. In addition, the point cloud accumulation required for local PCD saving is also placed in this branch; when saving is subsequently enabled, it should be kept True.
1.1.7.2.3.scan_bodyframe_pub_en (point cloud published in the internal IMU's own frame)
When True, additionally publish cloud_registered_body, transforming the preprocessed point cloud into the IMU coordinate system via the internal extrinsics, mainly used to assist in checking the point cloud and extrinsics; scan_publish_en must also be True.
Here, body refers to the MID360 internal IMU coordinate system. There is currently no debugging need for this, so keep it False for now.
1.1.7.2.4.tf_send_en (Point-LIO pose TF publishing)
When True, publish the TF from camera_init → aft_mapped along with the odometry; when False, disable this TF, while odometry and registered scans can still continue to be output.
For now, keep the integration chain as False; the chassis TF is published by other interface nodes. Only consider enabling it when you need to display Point-LIO's own pose TF during standalone debugging; this TF represents the internal IMU pose, not odom → base_footprint.
1.1.8.pcd_save (point cloud map saving)
1.1.8.1.Parameter table
pcd_save:
pcd_save_en: False
interval: -1 # how many LiDAR frames saved in each pcd file;
# -1 : all frames will be saved in ONE pcd file, may lead to memory crash when having too much frames.
| Parameter | Current value | Units | Hardware guidance | Purpose | Effect of increasing | Effect of decreasing | Activation conditions / notes |
|---|---|---|---|---|---|---|---|
pcd_save_en |
False |
Not applicable; boolean | Enable or configure as needed | Whether to accumulate and save registered scans as PCD files | Not applicable | Not applicable | Local point cloud accumulation requires scan_publish_en=True; the integrated SLAM launch overrides it to True |
interval |
-1 |
Scan-processing count; -1 is a special value | Enable or configure as needed | Control how many processed scans accumulate before saving a file | For positive values: longer intervals, usually larger files and more buffered data | For positive values: more frequent saving, usually smaller files and more disk writes | -1: accumulate until normal exit, then save. Greater than 0: save in batches and clear the accumulated buffer. Not seconds; applies only when saving is enabled, as it is by the integrated SLAM launch |
1.1.8.2.Parameter Details
1.1.8.2.1.pcd_save_en (Point cloud map saving switch)
When False, PCD saving is disabled, while estimation and mapping continue; when True, registered scans in the camera_init coordinate system are accumulated and saved as binary PCD.
Currently keep it False; enable it only when archiving is needed, and keep publish.scan_publish_en=True. Note: slam_launch.py will override this parameter to True, so whether saving actually occurs still depends on the actual startup method.
1.1.8.2.2.interval (frame interval for point cloud saving)
- -1: Continuously accumulate the point cloud and save it to scans.pcd upon normal exit. Long-running operation increases memory usage, and the program must be terminated normally for the exit save to occur.
- Greater than 0: After each specified number of scan processes accumulated, save as scans_1.pcd, scans_2.pcd, etc., and clear the accumulation buffer; upon normal exit, the remaining points are still saved to scans.pcd.
This count increases according to the number of scan processing times that enter the save branch. For example, at a stable 20 Hz with normal processing per frame, 100 times is about 5 seconds, but interval itself is not a time parameter. Locally, saving is performed in batches only when interval > 0; 0 and other negative values also do not trigger periodic saving, and using the default special value -1 is clearer.
保存目录由编译时ROOT_DIR确定:CMake使用当时的Point-LIO源码目录,保存代码再拼接PCD/。当前安装程序的输出目录为:
/src/pb2025_sentry_nav/point_lio/PCD/
这不是相对于运行目录的路径;在其他目录重新编译后需重新核对安装产物。
The saved content is the cumulative point cloud of multi-frame registration scans; the file will not automatically be placed in the navigation prior map directory. The output filename is fixed, so when results from different rounds need to be retained, existing files should be archived first.