Survey point-cloud merger
Merge recorded survey clouds into a binary PLY file using TF or URDF transforms, range filtering, and voxel averaging. Processing is offline but requires ROS Python dependencies.
scripts.survey_mapping.merge_survey_bag · Source
Perception and mapping · Guide · Symbol index
How it is used
Use main() to turn a recorded survey bag into a PLY point cloud for the Isaac Sim workflow. Run the script after sourcing ROS and the workspace; it reads files and needs no running ROS graph. The helpers below handle cloud extraction, coordinate transforms, and voxel averaging.
Recorded TF is the default alignment source. Supplying --urdf replaces TF lookup with forward kinematics using the latest preceding joint-state message. Neither mode refines the camera calibration or performs ICP alignment.
Start here
Callable |
Purpose |
|---|---|
Merge the bag’s clouds into one PLY file. Range-filter points in the incoming camera frame, transform them using recorded TF or joint states with the URDF, then voxel-average them. If any included cloud lacks color, omit color from the final map. |
|
Return the transform from |
|
Group floor(xyz/leaf) cells and average coordinates and optional RGB per cell. Color means are clipped and truncated to uint8. |
|
Serialize point coordinates as little-endian float32 vertices with optional unsigned-byte red/green/blue fields. |
Example
From the repository root, merge an existing survey bag:
python3 scripts/survey_mapping/merge_survey_bag.py \
--bag survey_session --out survey_map.ply --voxel 0.005
The voxel size is 5 mm. Use a new output filename to keep an earlier map; an existing PLY file is overwritten.
Functions
main()
Merge the bag’s clouds into one PLY file. Range-filter points in the incoming camera frame, transform them using recorded TF or joint states with the URDF, then voxel-average them. If any included cloud lacks color, omit color from the final map.
Entry point · Source
main()
Returns: Integer exit code: 0 after PLY/self-check, 1 for missing inputs or no mergeable clouds.
Errors: Argparse exits for missing –bag or negative range/voxel; known URDF load errors return 1; transform failures skip clouds with warnings. Bag deserialization, extraction and PLY write errors can propagate.
Side effects: Reads bag/optional URDF, prints progress/warnings and overwrites –out (default survey_map.ply); no robot movement.
voxel_downsample()
Group floor(xyz/leaf) cells and average coordinates and optional RGB per cell. Color means are clipped and truncated to uint8.
Function · Source
voxel_downsample(xyz, rgb, leaf)
Parameter |
Meaning |
|---|---|
|
N×3 coordinate array, normally metres. |
|
Matching N×3 colors, or None to omit color. |
|
Voxel edge in the same units as xyz; zero or negative disables sampling. |
Returns: (sampled_xyz, sampled_rgb); returns original objects for leaf <= 0 or empty input, otherwise one centroid per lexicographically ordered occupied cell.
Errors: Shape, nonfinite coordinate and incompatible dtype errors are not caught.
Side effects: Allocates aggregate arrays; does not mutate supplied arrays.
Example
xyz, rgb = voxel_downsample(np.array([[0., 0, 0], [0.4, 0, 0], [1.1, 0, 0]]), None, 1.0)
assert np.allclose(xyz, [[0.2, 0, 0], [1.1, 0, 0]])
assert rgb is None
Referenced in source (2)
main— scripts.survey_mapping.merge_survey_bagself_check— scripts.survey_mapping.merge_survey_bag
write_ply()
Serialize point coordinates as little-endian float32 vertices with optional unsigned-byte red/green/blue fields.
Function · Source
write_ply(path, xyz, rgb)
Parameter |
Meaning |
|---|---|
|
Destination file; opened in wb mode, overwriting an existing file. Parent directories must exist. |
|
N×3 coordinates; cast to float32 for storage. |
|
N×3 colors cast to uint8, or None for XYZ-only PLY. |
Returns: None.
Errors: I/O and incompatible array-shape errors propagate; writes are not atomic.
Side effects: Creates or truncates a binary PLY file.
Referenced in source (1)
main— scripts.survey_mapping.merge_survey_bag
xyz_rpy_matrix()
Build a homogeneous transform from fixed-axis XYZ Euler rotation and translation.
Function · Source
xyz_rpy_matrix(xyz, rpy)
Parameter |
Meaning |
|---|---|
|
Three translation components, conventionally metres. |
|
Roll, pitch, yaw in radians, applied with tf_transformations axes=”sxyz”. |
Returns: NumPy 4×4 homogeneous matrix with xyz in its translation column.
Errors: Invalid vector shape or numeric values are not caught.
Side effects: Allocates a matrix only.
Example
m = xyz_rpy_matrix([1, 2, 3], [0, 0, 0])
assert np.allclose(m[:3, 3], [1, 2, 3])
Referenced in source (2)
UrdfFkSolver.__init__— scripts.survey_mapping.merge_survey_bagself_check— scripts.survey_mapping.merge_survey_bag
Internal callbacks and helpers
open_bag()
Open a rosbag2 sequential reader using auto-selected storage and CDR-to-CDR conversion.
Internal helper · Source
open_bag(path)
Parameter |
Meaning |
|---|---|
|
Bag directory/path accepted by rosbag2; converted to string. |
Returns: (reader, topic_types), where topic_types maps topic names to ROS type strings.
Errors: rosbag2 open/storage/metadata errors propagate.
Side effects: Opens and reads bag metadata; returned reader retains the bag resource.
Referenced in source (1)
main— scripts.survey_mapping.merge_survey_bag
transform_matrix()
Convert the translation and quaternion in a TransformStamped into a homogeneous matrix.
Internal helper · Source
transform_matrix(transform)
Parameter |
Meaning |
|---|---|
|
TransformStamped-like object whose transform contains translation xyz and quaternion xyzw. |
Returns: NumPy 4×4 source-to-target matrix in the message’s coordinate units.
Errors: Malformed attributes/numeric data are not caught.
Side effects: Allocates a matrix only.
Referenced in source (1)
main— scripts.survey_mapping.merge_survey_bag
extract_points()
Read XYZ and optional packed color from PointCloud2, preferring rgba over rgb and skipping NaN records. Unpack the lower RGB bytes and discard alpha.
Internal helper · Source
extract_points(cloud)
Parameter |
Meaning |
|---|---|
|
sensor_msgs.msg.PointCloud2 with x/y/z fields and optional rgb or rgba packed 32-bit field. |
Returns: (xyz, rgb): xyz is N×3 float64; rgb is N×3 uint8, or None for missing color or an empty cloud. Coordinates keep the cloud units/frame.
Errors: Missing/malformed fields and point_cloud2/NumPy errors propagate; infinities are not explicitly filtered.
Side effects: Reads message buffers and allocates arrays.
Referenced in source (1)
main— scripts.survey_mapping.merge_survey_bag
self_check()
Assert voxel centroid/color averaging and translation-column behavior using small in-memory arrays.
Internal helper · Source
self_check()
Returns: None if assertions pass.
Errors: AssertionError on incorrect expected results; module imports still require ROS and NumPy dependencies.
Side effects: Prints self-check passed; no bag or hardware access.
Referenced in source (1)
main— scripts.survey_mapping.merge_survey_bag
UrdfFkSolver
Compute frame transforms from an expanded URDF and a joint-position mapping. This is the merger’s optional alternative to recorded TF; it does not model mimic joints.
UrdfFkSolver.lookup()
Return the transform from source to target using the URDF and supplied joint positions. Both frames must exist; disconnected URDF roots are not explicitly rejected.
Method · Source
lookup(self, target, source, angles)
Parameter |
Meaning |
|---|---|
|
Destination link frame. |
|
Source link frame. |
|
Mapping of movable joint positions, radians for rotation and metres for translation. |
Returns: 4×4 transform taking points from source to target.
Errors: ValueError for absent frames, cycles or missing positions; inversion errors propagate. No explicit check ensures target and source share one root.
Side effects: Computes transforms without publishing TF.
UrdfFkSolver.__init__()
Parse each URDF joint into a child-link-to-joint table containing name, type, parent, origin transform and axis. Missing origin defaults to zero and missing axis to +X; mimic behavior is not modeled.
Lifecycle · Source
__init__(self, path)
Parameter |
Meaning |
|---|---|
|
Filesystem path to a parsed URDF XML document, not a xacro command. |
Returns: None; initializes parent_joint.
Errors: File/XML errors, missing parent or child elements and malformed numeric fields propagate.
Side effects: Reads the URDF file and populates memory.
Referenced in source (1)
main— scripts.survey_mapping.merge_survey_bag
UrdfFkSolver.chain_to_root()
Walk parent joints from a link and return them in root-to-link multiplication order.
Method · Source
chain_to_root(self, link)
Parameter |
Meaning |
|---|---|
|
Child link name from the parsed URDF; an unknown name produces an empty chain here. |
Returns: Reverse iterator over joint dictionaries from root toward link.
Errors: Raises ValueError on a repeated link/cycle.
Side effects: None outside local allocations.
Referenced in source (1)
UrdfFkSolver.world_matrix— scripts.survey_mapping.merge_survey_bag
UrdfFkSolver.joint_matrix()
Compose a joint origin with its revolute/continuous rotation or prismatic translation. Other joint types return the stored origin unchanged.
Method · Source
joint_matrix(self, joint, angles)
Parameter |
Meaning |
|---|---|
|
Joint dictionary from parent_joint, including type, name, origin and axis. |
|
Mapping from movable joint names to positions: radians for rotation, metres for prismatic motion. |
Returns: 4×4 origin @ motion matrix; fixed/unsupported types return the origin array itself.
Errors: ValueError if a supported movable joint lacks a position; numeric/shape errors propagate.
Side effects: No external effects; fixed results alias stored origin.
Referenced in source (1)
UrdfFkSolver.world_matrix— scripts.survey_mapping.merge_survey_bag
UrdfFkSolver.world_matrix()
Multiply the root-to-link chain of origin and motion transforms.
Method · Source
world_matrix(self, link, angles)
Parameter |
Meaning |
|---|---|
|
URDF link name; this helper alone treats an unknown link as the identity. |
|
Joint-name-to-position mapping in radians or metres according to joint type. |
Returns: 4×4 transform mapping link coordinates into its root coordinates.
Errors: Propagates cycle and missing-joint ValueError from chain/joint helpers.
Side effects: Allocates matrices only.
Referenced in source (1)
UrdfFkSolver.lookup— scripts.survey_mapping.merge_survey_bag