Wiki
small_gicp_relocalization(先验点云地图重定位)
Existing English translations were reused. 16 current source blocks remain in Simplified Chinese, without triggering paid translation.
1.small_gicp_relocalization(先验点云地图重定位)
1.1.实车先看:地图、起点和云台零位
This node operates inexisting-map navigation mode slam:=False , aligning the current registered point cloud with a prior PCD map and outputting position and orientation corrections for map → odom . It does not directly control wheels or the gimbal, nor does it recreate terrain obstacles. The complete slam:=True launch does not run it.
| Hardware problem | Check first | Plain-language explanation |
|---|---|---|
| Localization is wrong after startup, or the map cannot be found | prior_pcd_file, map provenance and coordinates |
Provide a three-dimensional PCD for the current site. The Nav2 two-dimensional map and PCD must also use corresponding positions and orientations |
| The robot is stationary at a known map location but does not align initially | init_pose |
This parameter directly gives map→odom an initial guess; it is not universally the chassis position in the map |
| The initial position clicked in RViz has a heading offset by a gimbal angle | robot_base_frame |
The current message is treated as the map pose of gimbal_yaw . Its arrow should represent the yaw-gimbal layer’s heading, rather than always the chassis’s front |
| The same map starts with a different overall orientation after changing gimbal zero position | base_frame、lidar_frame and the reference used during PCD mapping |
At startup, the code transforms the entire map using the then-current chassis←LiDAR transform. Since the LiDAR rotates with yaw, verify that mapping and current zero positions correspond |
| Localization jumps to a similar wall, pillar or another corridor | Initial guess, max_dist_sq and visible site structure |
An overly loose matching distance may admit incorrect correspondences. However, initial guesses, repetitive structures and coordinate errors also cannot be fixed solely by tightening distance |
| Localization is slow or lacks detail | Both leaf_size、num_neighbors、num_threads |
First ensure the point cloud is correct and sufficient, then balance detail against computation. Denser points do not guarantee greater accuracy |
There is currently no physical unit, nor any valid relocalization test for this node. The following separately explains "how the code interprets these values" and "whether they apply to a real vehicle," and does not treat the source code flow as an already-verified localization result.
1.2.参数
1.2.1.ros__parameters (ROS node parameters)
1.2.1.1.Parameter table
The first 12 items correspond to the current physical YAML;prior_pcd_file although they are commented out, they are passed in separately by launch;input_cloud_topic they are not written in this YAML and still use the source code default values. These two items are also listed to facilitate a complete understanding of the input sources.
small_gicp_relocalization:
ros__parameters:
use_sim_time: False
num_threads: 4
num_neighbors: 20
global_leaf_size: 0.1
registered_leaf_size: 0.05
max_dist_sq: 3.0
map_frame: "map"
odom_frame: "odom"
base_frame: "base_footprint"
robot_base_frame: "gimbal_yaw"
lidar_frame: "front_mid360"
init_pose: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # [x, y, z, roll, pitch, yaw]
# The prior_pcd_file does not need to be specified since it going to be set by defaults in launch.
# prior_pcd_file: ""
| Parameter | Current value | Units | Hardware guidance | Purpose | Effect of increasing | Effect of decreasing | Activation conditions / notes |
|---|---|---|---|---|---|---|---|
use_sim_time |
False; in simulation, True |
Not applicable; boolean | Verify and configure correctly before running on hardware | Control the ROS clock for the node and TF buffer | Not applicable | Not applicable | Map initialization queries TF at the current node time; matching and publication timers use wall time. True does not make them run at the simulation rate |
num_threads |
4 |
Threads; count | Usually keep the current value; not a priority for tuning | Set parallel thread counts for neighborhood estimation, tree construction and matching | May be faster with sufficient CPU resources, but may compete with Point-LIO and other processes | Lower parallelism; potentially slower computation | Must be positive; not matching frequency. The downsampling call does not receive this value and currently uses the library default of four threads |
num_neighbors |
20 |
Neighboring points; count | Observe closely on hardware; adjust only for a specific problem | Describe local wall, ground and other shapes using each point’s neighbors | Usually a larger descriptive region and more computation; may combine distinct structures such as both sides of a corner | More local and faster, but potentially more sensitive to sparse points and noise | Used for both map and live point clouds; not 20 frames or 20 matching candidates. The current library cannot form a normal local estimate with fewer than five neighbors |
global_leaf_size |
0.1 |
m; three-dimensional voxel side length | Observe closely on hardware; adjust only for a specific problem | Downsample the prior PCD at startup for matching | Usually fewer map points and lower cost, with less detail | Usually more map points and greater startup and matching costs | Does not modify the PCD file or two-dimensional map resolution. Must be positive; the target map is processed only at startup |
registered_leaf_size |
0.05 |
m; three-dimensional voxel side length | Observe closely on hardware; adjust only for a specific problem | Downsample accumulated input point clouds before each matching round | Usually fewer input points and less computation, potentially losing small structures | Usually more input points and greater cost; may also retain more noise and dynamic points | Does not modify Point-LIO downsampling settings. Must be positive; people, opposing robots and other dynamic points are not separately removed |
max_dist_sq |
3.0 |
m²; squared correspondence distance | Observe closely on hardware; adjust only for a specific problem | Reject point pairs too far apart under the current estimate | Allow more distant pairs, increasing the chance of confusing similar structures | Stricter pairing; poor initial guesses may leave too few pairs | The current distance threshold is approximately √3=1.73 m; not 3 m, localization accuracy or permitted total position error |
map_frame |
"map" |
Not applicable; frame name | Verify and configure correctly before running on hardware | Specify the output TF parent, conventionally the target map frame | Not applicable | Not applicable | Renaming does not automatically transform PCD coordinates; must match the two-dimensional map and global-localization convention |
odom_frame |
"odom" |
Not applicable; frame name | Verify and configure correctly before running on hardware | Specify the output TF child, conventionally the input registered point cloud frame | Not applicable | Not applicable | Current input should use odom coordinates. The node does not transform input points by this name or validate that the message frame_id matches it |
base_frame |
"base_footprint" |
Not applicable; frame name | Verify and configure correctly before running on hardware | Query this frame←LiDAR at startup to transform the prior PCD | Not applicable | Not applicable | Currently the chassis reference layer. Takes only the first successful query and does not rerotate the map as the gimbal subsequently moves. Applicability depends on PCD provenance |
robot_base_frame |
"gimbal_yaw" |
Not applicable; frame name | Verify and configure correctly before running on hardware | Specify which robot component the initialpose message represents and use it in conversion | Not applicable | Not applicable | Used only in the manual initial-pose callback, not as the target frame for every match, and does not modify input point coordinates. Here it is the actual yaw layer |
lidar_frame |
"front_mid360" |
Not applicable; frame name | Verify and configure correctly before running on hardware | Together with base_frame, determine the startup PCD transformation | Not applicable | Not applicable | Used for TF queries only during map loading; does not establish that live input is in the LiDAR’s own frame. MID360 rotates with yaw, not pitch |
init_pose |
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0] |
First three values in m, last three in rad | Verify and configure correctly before running on hardware | Initialize the matching transform: under the current convention, an initial map←odom estimate | Not applicable; set each component according to its reference frame | Not applicable; set each component according to its reference frame | Order is x/y/z/roll/pitch/yaw, with rotation Rz×Ry×Rx. All zeros give the identity transform, without guaranteeing that the robot is at the map origin |
prior_pcd_file |
Absent from YAML; supplied by the launch’s prior_pcd_file argument |
Not applicable; file path | Verify and configure correctly before running on hardware | Load the current site’s three-dimensional prior map | Not applicable | Not applicable | The complete launch supplies the path in a later parameter dictionary. The current default hardware path does not exist; the default simulation PCD does. An empty path is not a substitute |
input_cloud_topic |
"registered_scan"; source-code default, absent from YAML |
Not applicable; topic name | Verify and configure correctly before running on hardware | Receive registered point clouds for matching | Not applicable | Not applicable | Currently should come from loam_interface in odom coordinates; not sensor_scan, terrain_map or a raw LiDAR-local cloud. Type is PointCloud2 |
This block has no custom parameters that are currently completely unused:robot_base_frameparticipates only when a manual initial pose is received,init_poseinitial values are set only at startup; they are not continuously adjusted items. Topics, coordinate frames, and paths cannot be tuned by numerical values.
1.2.1.2.Parameter Details
1.2.1.2.1.Input and Output: Which two point clouds are being matched
| Direction | Data | Actual code purpose |
|---|---|---|
| Read file | prior_pcd_file |
Load PCD, transform at startup, downsample, build fixed target map |
| Subscribe | registered_scan,renamable by input_cloud_topic |
Copy XYZ coordinates and accumulate multiple frames as the matching point cloud for this round; do not use reflection intensity or per-point time |
| Subscribe | initialpose,PoseWithCovarianceStamped |
Reset the initial matching value using a manually given pose; the topic name is hardcoded as a relative name |
| Broadcast | map → odom |
Publish the reference frame correction obtained from point cloud matching; do not publish independent pose or matching point cloud topics |
The real-time point cloud has already been registered by Point-LIO and the interface node to odom. This node directly accumulates coordinates, no longer converting to the radar frame frame by frame, nor additionally rotating these points by the gimbal yaw. When the gimbal rotates, the static environment should still be aligned under the common odom coordinates; this conclusion depends on the correctness of the upstream pose, installation extrinsics, and time interface, and there is currently no independent yaw verification.
The callback only saves the most recent input frame_id and timestamp, does not check whether multiple frames belong to the same system, and does not clear the accumulated points when frame_id changes. PCD does not have a frame_id like ROS messages, and this node processes based on its own source assumptions; the filename and coordinate frame string cannot prove that the map already corresponds.
Every 500 ms of real time, one matching attempt is made, and processing is performed only if there are points; each round involves downsampling, estimating the local shape, and searching for corresponding points in the map, with at most 10 optimization iterations. The matching report updates the result only upon convergence; if it does not converge, the old result is retained, but the points accumulated in this round are still cleared. Convergence means the algorithm's stopping condition is satisfied, and does not prove that the correct location in the field was matched; the source code no longer checks credibility based on matching error, valid correspondence ratio, etc.
1.2.1.2.2.prior_pcd_file: First, confirm that you are using your own venue map
The default path for the entire startup is in the shared directory after installation: pb2025_nav_bringup shared directory:
| Startup method | Default PCD path rule | Current default file check |
|---|---|---|
| Physical | pcd/reality/<world>.pcd; world default rmul_2024 |
rmul_2024.pcd does not exist |
| Simulation | pcd/simulation/<world>.pcd; world default rmuc_2025 |
rmuc_2025.pcd exists |
The corresponding default hardware two-dimensional map map/reality/rmul_2024.yaml also does not exist, while the default simulation map does. This only checks current default files; running-node parameters were not read, and users may supply other world, PCD or two-dimensional map paths. Prepare corresponding maps for the actual site before running on hardware. An existing simulation PCD does not establish hardware-map readiness.
localization_launch.py After the parameter file, additionally pass in {"prior_pcd_file": prior_pcd_file}. Therefore, commenting out this line does not mean the node does not use the prior PCD. It is a different function from whether Point-LIO is enabled prior_pcd_en: Point-LIO may not load the prior, but the relocalization node still requires the prior PCD.
If file loading fails, only the error is logged and the function returns; the constructor still continues to prepare the matching target, and there is no explicit prevention of an empty target from entering subsequent matching; the fact that "the node started up" cannot be regarded as successful map loading. The source code will not re-read the PCD at runtime, nor will it verify for you whether it is consistent with the Nav2 2D map in position, orientation, metric scale, or site version.
1.2.1.2.3.base_frame and lidar_frame: at startup, the entire map is rotated
After the PCD is read in, the source code queries base_footprint ← front_mid360, then left-multiplies this matrix onto every point of the entire map. It queries based on the node's current time, and after a failure retries every second, continuing once it succeeds; there is no upper limit on the number of queries, nor does it update the target map during subsequent gimbal rotation.
This corresponds to a source assumption in the code: the PCD baseline is the initial lidar_odom, and the map is transformed into the desired reference using the initial chassis-to-lidar relationship. However, the current Point-LIO actually stores registered world points under camera_init and its pose origin involves the internal IMU; it is not the lidar's own coordinate frame for each frame. Whether treating such PCDs as the initial lidar frame and directly applying the mechanical transform is consistent with the actual mapping baseline must be re-verified; one must not assume the conversion is correct solely based on the README naming.
With the LiDAR on the gimbal, this step particularly depends on the zero position. If relative gimbal yaw differs between creating the PCD and restarting with it, the current base←lidar contains a different angle. According to the code, a different matrix may rotate the target map, while the independently loaded two-dimensional map does not adjust automatically. Whether this actually causes misalignment depends on the PCD generation start pose, gimbal zero position, chassis heading and map origin; no test conclusion is available yet.
This query is related to the one-time benchmark conversion intent of loam_interface, but the two nodes query separately, so it is not guaranteed that the gimbal angles are obtained at the same instant. The mechanical relationship here is always preserved: the MID360 is mounted on gimbal_yaw; only the actual yaw drives it, while the actual pitch is located in a subsequent layer; the two odom joints are fixed. Errors in the gravity reference, the internal IMU-to-lidar relationship, or the map source cannot be masked by increasing the matching distance.
The README in the package also stated that "an empty transform is used when unset," but the current implementation has no corresponding identity-transform bypass: if the PCD can be read but frame is empty or the TF is missing, it enters retry. The current source code should be taken as authoritative, and no changes will be made to the node or map transform in this round.
1.2.1.2.4.init_pose and robot_base_frame: The two initial poses are not the same object
YAML's init_pose is directly written into the matching matrix. Under the convention that the current input is odom and the target is map, it is the map←odom initial value, that is, "the position and orientation of the odom origin in the map".
[0,0,0,0,0,0] indicates an initial guess that the two frames are fully coincident; this is appropriate only when the initial reference relationship matches, and it does not mean the algorithm already knows the robot's true position in the map. Position units are m, angle units are rad; a yaw of 90° should be approximately 1.5708, not 90. Rotation is composed in the order yaw, pitch, roll Rz×Ry×Rx.
For example: if the odom origin happens to coincide with the described robot origin and has the same orientation, then the robot's initial map pose might be map←odom; if there is a height or mounting offset between the odom origin and the gimbal, or if the robot has already moved within odom, you cannot directly copy the robot position. Currently the chassis, gimbal, and lidar origins are different, so the calculation must be based on the actual reference relationships.
topic initialpose is treated as robot_base_frame=gimbal_yaw the pose in the map. callback then queries the latest gimbal_yaw←输入扫描系. The current scan frame should be odom, and multiplying the two yields map←odom:
map←odom = 人工给定的 map←gimbal_yaw × TF中的 gimbal_yaw←odom
Therefore, if you interpret the RViz arrow as the chassis front, while the current gimbal is turned 90° left relative to the chassis, you may miss a gimbal angle. The position also corresponds to the gimbal origin: if the manual message gives z=0, the source code treats it as the gimbal origin being at z=0 in the map, not as "the chassis ground height being 0"; the height should be checked against this map's datum. Changing only the name of robot_base_frame also requires rechecking the entire relationship; the three characters "robot" cannot automatically be equated with the chassis. This parameter is only used in this callback and is not deducted as a mechanical angle during each point cloud matching.
The callback does not transform the pose according to the message header.frame_id, does not use its covariance, and does not look up TF by message time; instead, it takes the latest transform. Before the first scan is received, the scan frame_id is still empty, so the query may fail. Manually setting the initial value only changes the current and next matching guesses; it does not re-transform the PCD, nor does it clear the accumulated points. When the gimbal rotates rapidly, it is also necessary to verify whether the orientation corresponding to the manual pose and the latest TF are at the same time.
1.2.1.2.5.max_dist_sq: 1.73 m is a pairing threshold, not a positioning error metric
The small_gicp code used by the current build directly checks whether squared correspondence distance exceeds max_dist_sq and rejects the pair if it does. Source points are first transformed into the map using the current estimate, then paired with their nearest map points before this check. With metric point clouds, the units are therefore m²:
max_dist_sq = 3.0 m² → 最大对应点距离约 sqrt(3) = 1.73 m
希望门槛为0.5 m → 平方值为0.25 m²
The second line only explains unit conversion and is not a recommendation to modify the current value. It does not limit the robot's total travel distance, does not mean that a positioning deviation of 1.73 m is allowed, and is even less a scanning range. Under an incorrect initial value, the source point may still happen to be close to another wall and pass the threshold.
On hardware, relaxing this threshold retains more point pairs, but repetitive pillars, similar corridors and dynamic objects may also create incorrect matches. Tightening it reduces distant mismatches but may leave too few pairs when the true initial error is somewhat larger. First verify the map, initial estimate and reference frames, then tune using evidence of correct and incorrect matches. Smaller alone does not mean more accurate.
This unit was verified against the currently built cached library source code; the library commit is fa0cfc983417c044b6036f71dfa448038bb9c820. CMake references master; after re-fetching dependencies, the version should be re-verified, and the current cached behavior should not be treated as a fixed commitment for all versions.
1.2.1.2.6.Two leaf_size, num_neighbors, and num_threads (point cloud simplification, number of neighbors, and computation threads)
global_leaf_size=0.1 m Process the prior map;registered_leaf_size=0.05 m Process the accumulated real-time point cloud for each round. The two are not required to be the same, nor are they equal to the terrain analysis grid, Nav2 map resolution, or localization accuracy. Map processing will not modify the original PCD, and real-time processing will not change the output of Point-LIO itself.
Reducing the setting usually retains more details, at the cost of increased computation; details absent from the raw data will not appear merely because the setting is reduced. Whether distant sparse points, wall corners, or small pillars can be described stably depends on the actual data; dynamic points such as personnel and enemy vehicles are not specifically filtered out at this node, and more real-time points may also introduce more interference.
num_neighbors=20It refers to the number of neighboring points used at each point to describe the local shape, and it is used for both the map and real-time points. It is not 20 matching candidates or an accumulation of 20 frames. If the range is too large, it may mix in different structures such as two sides of a wall corner, a slope surface, and an obstacle; if it is too small, it may be affected by noise. When the current library actually finds fewer than 5 neighboring points, it is set to the default value for an invalid local feature, so sparse regions and the downsampling scale should be considered together.
num_threads=4Control parallel computation for neighborhood estimation, tree building, and matching. The downsampling call does not pass this parameter, and in the current library this function defaults to 4 threads; increasing the parameter does not mean that all steps will increase their thread count accordingly. It is not the node frequency, nor does it guarantee that doubling the threads will double the speed; for now, continue using the current value.
1.2.1.2.7.map_frame, odom_frame, use_sim_time and output boundaries (map, odometry reference frame, and time base)
The map matching result is the transformation from "target map ← input accumulated point cloud"; the output is directly named map→odom. To make this name correct, the target PCD and the input actual coordinates must first conform to the convention; this node does not separately transform into the frames specified by these two names.
Output repeats the current result at approximately 20 Hz real time; point cloud matching attempts once at approximately 2 Hz real time; 20 Hz does not mean a new localization is obtained every time. The TF time takes the last received scan time plus 0.1 seconds, fixed in the source code, not a parameter of this block; there is also no output protection for "has already been successfully matched," and the startup initial value can likewise be published. Here only the output interface is recorded; the previously shelved troubleshooting of navigation start-stop or TF timeliness faults is still not expanded.
use_sim_time should be consistent with the input, mechanical TF, and startup mode. True affects the node's current time and TF cache; it will not cause two wall timers to automatically adjust with the simulation speed multiplier, nor will it fix the previous Point-LIO point time unit or internal pose transformation issues.
1.2.1.2.8.Startup source and current verification scope
| Startup method | Parameter and map sources | Current differences |
|---|---|---|
| Full reality navigation set, slam=False | Physical nav2_params.yaml, passed in via localization_launch; PCD is passed separately via the launch parameter dictionary | Values in this table; the physical map file corresponding to the default world is missing, and a map of the current site needs to be prepared |
| Full simulation navigation set, slam=False | Simulated nav2_params.yaml, likewise with PCD passed separately | Except for use_sim_time=True, the 12 items in this block are the same; the default simulation map exists |
| Full set slam=True | Enters slam_launch, does not enter localization_launch | This node does not run; the mapping output cannot be used to show that this block has been verified |
| Independent launch within the package | Self-written parameter dictionary, does not read the full YAML set | num_neighbors=10, both types of leaf_size are 0.25, max_dist_sq=1.0, input cloud_registered, frame and PCD default to empty; cannot be used directly as the full entry point |
All 13 custom parameters are declared and read at construction time; there is no dynamic parameter update callback;init_pose is used for startup, and manual initial values go through the initialpose message. ROS standard use_sim_time beyond the 13 items are handled by the node clock and cannot be conflated with dynamic updates of algorithm parameters.
- The source code can confirm: Parameter reading, one-time map conversion, cumulative registration point cloud, squared distance threshold, the difference between the startup initial value and the manual initial value, the update rule after matching convergence, and the output interface.
- The simulation has observed: 2026-10-08 only verified independent Point-LIO stationary and approximately 20 cm round trip; did not verify this node, prior map matching, independent gimbal yaw, manual initial value, or global localization.
- Must be verified by physical measurement / file sources: The common reference of the PCD and the 2D map, the gimbal zero position for mapping and startup, the lidar / internal IMU / chassis extrinsics, the map metric scale and actual starting point, visible structures and dynamic interference, and matching stability at the correct position. The current gravity direction and point timing issues remain pending verification.
1.3.开发问题
1.3.1.关掉small_gicp
| 原模板 | 对应静态版本 |
|---|---|
localization_launch.py |
localization_static_launch.py |
rm_navigation_reality_launch.py |
rm_navigation_reality_static_launch.py |
rm_navigation_simulation_launch.py |
rm_navigation_simulation_static_launch.py |
主要调整是关闭 small_gicp、增加静态 map → odom;导航节点继续复用原来的 navigation_launch.py
1.3.2.日志某些报错
| 日志原文 | 含义 |
|---|---|
GICP did not converge. |
本次点云配准没有收敛 |
No accumulated points to process. |
没收到可处理的实时点云 |
TF lookup failed... |
初始化需要的 TF 查询失败 |
Couldn't read PCD file... |
先验 PCD 读取失败 |
1.3.2.1.GICP did not converge.
点云对不上,要自己跑一边slam建出来PCD,然后再使用这个PCD进行匹配。
1.3.2.2.No accumulated points to process.
这条提示表示 small_gicp 的实时点云缓存为空,发生在匹配之前。现在先查数据有没有送到,暂时不用调匹配参数或初始位姿。
它默认订阅的是 /registered_scan,数据链是:
MID360 → Point-LIO → /cloud_registered
↓ loam_interface
/registered_scan → small_gicp