diff --git a/sensor_calibration_manager/launch/x2_gen2/ground_plane_calibrator.launch.xml b/sensor_calibration_manager/launch/x2_gen2/ground_plane_calibrator.launch.xml new file mode 100644 index 00000000..b4a6dda2 --- /dev/null +++ b/sensor_calibration_manager/launch/x2_gen2/ground_plane_calibrator.launch.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sensor_calibration_manager/launch/x2_gen2/mapping_based_lidar_lidar_calibrator.launch.xml b/sensor_calibration_manager/launch/x2_gen2/mapping_based_lidar_lidar_calibrator.launch.xml new file mode 100644 index 00000000..1e458e46 --- /dev/null +++ b/sensor_calibration_manager/launch/x2_gen2/mapping_based_lidar_lidar_calibrator.launch.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sensor_calibration_manager/launch/x2_gen2/marker_radar_lidar_calibrator.launch.xml b/sensor_calibration_manager/launch/x2_gen2/marker_radar_lidar_calibrator.launch.xml new file mode 100644 index 00000000..204e506c --- /dev/null +++ b/sensor_calibration_manager/launch/x2_gen2/marker_radar_lidar_calibrator.launch.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sensor_calibration_manager/launch/x2_gen2/tag_based_pnp_calibrator.launch.xml b/sensor_calibration_manager/launch/x2_gen2/tag_based_pnp_calibrator.launch.xml new file mode 100644 index 00000000..ee1bca44 --- /dev/null +++ b/sensor_calibration_manager/launch/x2_gen2/tag_based_pnp_calibrator.launch.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sensor_calibration_manager/launch/x2_gen2/tag_based_sfm_base_lidar_calibrator.launch.xml b/sensor_calibration_manager/launch/x2_gen2/tag_based_sfm_base_lidar_calibrator.launch.xml new file mode 100644 index 00000000..1e59083d --- /dev/null +++ b/sensor_calibration_manager/launch/x2_gen2/tag_based_sfm_base_lidar_calibrator.launch.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sensor_calibration_manager/sensor_calibration_manager/calibrators/__init__.py b/sensor_calibration_manager/sensor_calibration_manager/calibrators/__init__.py index 0d7af762..3c8926d7 100644 --- a/sensor_calibration_manager/sensor_calibration_manager/calibrators/__init__.py +++ b/sensor_calibration_manager/sensor_calibration_manager/calibrators/__init__.py @@ -2,5 +2,6 @@ from .rdv import * # noqa: F401, F403 from .x1 import * # noqa: F401, F403 from .x2 import * # noqa: F401, F403 +from .x2_gen2 import * # noqa: F401, F403 from .xx1 import * # noqa: F401, F403 from .xx1_15 import * # noqa: F401, F403 diff --git a/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/__init__.py b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/__init__.py new file mode 100644 index 00000000..8548af73 --- /dev/null +++ b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/__init__.py @@ -0,0 +1,13 @@ +from .ground_plane_calibrator import GroundPlaneCalibrator +from .mapping_based_lidar_lidar_calibrator import MappingBasedLidarLidarCalibrator +from .marker_radar_lidar_calibrator import MarkerRadarLidarCalibrator +from .tag_based_pnp_calibrator import TagBasedPNPCalibrator +from .tag_based_sfm_base_lidar_calibrator import TagBasedSfmBaseLidarCalibrator + +__all__ = [ + "TagBasedSfmBaseLidarCalibrator", + "GroundPlaneCalibrator", + "MappingBasedLidarLidarCalibrator", + "MarkerRadarLidarCalibrator", + "TagBasedPNPCalibrator", +] diff --git a/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/ground_plane_calibrator.py b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/ground_plane_calibrator.py new file mode 100644 index 00000000..8834113d --- /dev/null +++ b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/ground_plane_calibrator.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Tier IV, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict + +import numpy as np + +from sensor_calibration_manager.calibrator_base import CalibratorBase +from sensor_calibration_manager.calibrator_registry import CalibratorRegistry +from sensor_calibration_manager.ros_interface import RosInterface +from sensor_calibration_manager.types import FramePair + + +@CalibratorRegistry.register_calibrator( + project_name="x2_gen2", calibrator_name="ground_plane_calibrator" +) +class GroundPlaneCalibrator(CalibratorBase): + required_frames = [] + + def __init__(self, ros_interface: RosInterface, **kwargs): + super().__init__(ros_interface) + + self.base_frame = "base_link" + self.sensor_kit_frame = "sensor_kit_base_link" + self.lidar_frame = "left_upper/lidar" + + self.required_frames.extend([self.base_frame, self.sensor_kit_frame, self.lidar_frame]) + + self.add_calibrator( + service_name="calibrate_base_lidar", + expected_calibration_frames=[ + FramePair(parent=self.base_frame, child=self.lidar_frame), + ], + ) + + def post_process(self, calibration_transforms: Dict[str, Dict[str, np.array]]): + base_to_lidar_transform = calibration_transforms[self.base_frame][self.lidar_frame] + + sensor_kit_to_lidar_transform = self.get_transform_matrix( + self.sensor_kit_frame, self.lidar_frame + ) + + base_to_sensor_kit_transform = base_to_lidar_transform @ np.linalg.inv( + sensor_kit_to_lidar_transform + ) + + result = {self.base_frame: {self.sensor_kit_frame: base_to_sensor_kit_transform}} + + return result diff --git a/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/mapping_based_lidar_lidar_calibrator.py b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/mapping_based_lidar_lidar_calibrator.py new file mode 100644 index 00000000..9f83bf73 --- /dev/null +++ b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/mapping_based_lidar_lidar_calibrator.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Tier IV, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict + +import numpy as np + +from sensor_calibration_manager.calibrator_base import CalibratorBase +from sensor_calibration_manager.calibrator_registry import CalibratorRegistry +from sensor_calibration_manager.ros_interface import RosInterface +from sensor_calibration_manager.types import FramePair + + +@CalibratorRegistry.register_calibrator( + project_name="x2_gen2", calibrator_name="mapping_based_lidar_lidar_calibrator" +) +class MappingBasedLidarLidarCalibrator(CalibratorBase): + required_frames = [] + + def __init__(self, ros_interface: RosInterface, **kwargs): + super().__init__(ros_interface) + + self.sensor_kit_frame = "sensor_kit_base_link" + + self.mapping_lidar_frame = "left_upper/lidar" + self.calibration_lidar_frames = [ + "left_lower/lidar", + "right_upper/lidar", + "right_lower/lidar", + "front_upper/lidar", + "front_lower/lidar", + "rear_upper/lidar", + "rear_lower/lidar", + ] + + self.calibration_base_lidar_frames = [ + "left_lower/lidar_base_link", + "right_upper/lidar_base_link", + "right_lower/lidar_base_link", + "front_upper/lidar_base_link", + "front_lower/lidar_base_link", + "rear_upper/lidar_base_link", + "rear_lower/lidar_base_link", + ] + + self.required_frames.extend( + [ + self.sensor_kit_frame, + self.mapping_lidar_frame, + *self.calibration_lidar_frames, + *self.calibration_base_lidar_frames, + ] + ) + + self.add_calibrator( + service_name="calibrate_lidar_lidar", + expected_calibration_frames=[ + FramePair(parent=self.mapping_lidar_frame, child=calibration_lidar_frame) + for calibration_lidar_frame in self.calibration_lidar_frames + ], + ) + + def post_process(self, calibration_transforms: Dict[str, Dict[str, np.array]]): + sensor_kit_to_lidar_transform = self.get_transform_matrix( + self.sensor_kit_frame, self.mapping_lidar_frame + ) + + calibration_lidar_to_base_lidar_transforms = [ + self.get_transform_matrix(calibration_lidar_frame, calibration_base_lidar_frame) + for calibration_lidar_frame, calibration_base_lidar_frame in zip( + self.calibration_lidar_frames, self.calibration_base_lidar_frames + ) + ] + + sensor_kit_to_calibration_lidar_transforms = [ + sensor_kit_to_lidar_transform + @ calibration_transforms[self.mapping_lidar_frame][calibration_lidar_frame] + @ calibration_lidar_to_base_lidar_transform + for calibration_lidar_frame, calibration_lidar_to_base_lidar_transform in zip( + self.calibration_lidar_frames, calibration_lidar_to_base_lidar_transforms + ) + ] + + result = { + self.sensor_kit_frame: { + calibration_base_lidar_frame: transform + for calibration_base_lidar_frame, transform in zip( + self.calibration_base_lidar_frames, sensor_kit_to_calibration_lidar_transforms + ) + } + } + + return result diff --git a/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/marker_radar_lidar_calibrator.py b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/marker_radar_lidar_calibrator.py new file mode 100644 index 00000000..21bfe419 --- /dev/null +++ b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/marker_radar_lidar_calibrator.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 + +# Copyright 2024 TIER IV, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict + +import numpy as np + +from sensor_calibration_manager.calibrator_base import CalibratorBase +from sensor_calibration_manager.calibrator_registry import CalibratorRegistry +from sensor_calibration_manager.ros_interface import RosInterface +from sensor_calibration_manager.types import FramePair + + +@CalibratorRegistry.register_calibrator( + project_name="x2_gen2", calibrator_name="marker_radar_lidar_calibrator" +) +class MarkerRadarLidarCalibrator(CalibratorBase): + required_frames = [] + + def __init__(self, ros_interface: RosInterface, **kwargs): + super().__init__(ros_interface) + + self.radar_optimization_frame = kwargs["radar_optimization_frame"] + self.radar_parent_frame = kwargs["radar_parent_frame"] + self.radar_frame = kwargs["radar_frame"] + self.lidar_frame = kwargs["lidar_frame"] + + if self.radar_optimization_frame == self.radar_parent_frame: + self.required_frames.extend( + [self.radar_optimization_frame, self.radar_frame, self.lidar_frame] + ) + else: + self.required_frames.extend( + [ + self.radar_optimization_frame, + self.radar_parent_frame, + self.radar_frame, + self.lidar_frame, + ] + ) + + self.add_calibrator( + service_name="calibrate_radar_lidar", + expected_calibration_frames=[ + FramePair(parent=self.radar_frame, child=self.lidar_frame) + ], + ) + + def post_process(self, calibration_transforms: Dict[str, Dict[str, np.array]]): + lidar_to_radar_optimization_transform = self.get_transform_matrix( + self.lidar_frame, self.radar_optimization_frame + ) + + radar_optimization_to_radar_transform = np.linalg.inv( + calibration_transforms[self.radar_frame][self.lidar_frame] + @ lidar_to_radar_optimization_transform + ) + + if self.radar_optimization_frame == self.radar_parent_frame: + results = { + self.radar_optimization_frame: { + self.radar_frame: radar_optimization_to_radar_transform + } + } + else: + radar_parent_to_radar_optimization_transform = self.get_transform_matrix( + self.radar_parent_frame, self.radar_optimization_frame + ) + + radar_parent_to_radar_transform = ( + radar_parent_to_radar_optimization_transform @ radar_optimization_to_radar_transform + ) + results = {self.radar_parent_frame: {self.radar_frame: radar_parent_to_radar_transform}} + + return results diff --git a/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/tag_based_pnp_calibrator.py b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/tag_based_pnp_calibrator.py new file mode 100644 index 00000000..60076c36 --- /dev/null +++ b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/tag_based_pnp_calibrator.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Tier IV, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict + +import numpy as np + +from sensor_calibration_manager.calibrator_base import CalibratorBase +from sensor_calibration_manager.calibrator_registry import CalibratorRegistry +from sensor_calibration_manager.ros_interface import RosInterface +from sensor_calibration_manager.types import FramePair + + +@CalibratorRegistry.register_calibrator( + project_name="x2_gen2", calibrator_name="tag_based_pnp_calibrator" +) +class TagBasedPNPCalibrator(CalibratorBase): + required_frames = [] + + def __init__(self, ros_interface: RosInterface, **kwargs): + super().__init__(ros_interface) + + self.camera_name = kwargs["camera_name"] + self.lidar_frame = kwargs["lidar_frame"] + + camera_name_to_sensor_kit_frame = { + "camera0": "sensor_kit_base_link", + "camera1": "sensor_kit_base_link", + "camera2": "sensor_kit_base_link", + "camera3": "sensor_kit_base_link", + "camera4": "sensor_kit_base_link", + "camera5": "sensor_kit_base_link", + "camera6": "sensor_kit_base_link", + "camera7": "sensor_kit_base_link", + } + + camera_name_to_frame = { + "camera0": "top_rear_center", + "camera1": "left_center", + "camera2": "right_center", + "camera3": "top_front_right", + "camera4": "top_front_center_right", + "camera5": "top_front_left", + "camera6": "left_front", + "camera7": "right_front", + } + + self.sensor_kit_frame = camera_name_to_sensor_kit_frame[self.camera_name] + self.camera_frame = camera_name_to_frame[self.camera_name] + + self.required_frames.extend( + [ + self.lidar_frame, + self.sensor_kit_frame, + f"{self.camera_frame}/camera_link", + f"{self.camera_frame}/camera_optical_link", + ] + ) + + self.add_calibrator( + service_name="calibrate_camera_lidar", + expected_calibration_frames=[ + FramePair( + parent=f"{self.camera_frame}/camera_optical_link", child=self.lidar_frame + ), + ], + ) + + def post_process(self, calibration_transforms: Dict[str, Dict[str, np.array]]): + optical_link_to_lidar_transform = calibration_transforms[ + f"{self.camera_frame}/camera_optical_link" + ][self.lidar_frame] + + sensor_kit_to_lidar_transform = self.get_transform_matrix( + self.sensor_kit_frame, self.lidar_frame + ) + + camera_to_optical_link_transform = self.get_transform_matrix( + f"{self.camera_frame}/camera_link", f"{self.camera_frame}/camera_optical_link" + ) + + sensor_kit_camera_link_transform = np.linalg.inv( + camera_to_optical_link_transform + @ optical_link_to_lidar_transform + @ np.linalg.inv(sensor_kit_to_lidar_transform) + ) + + result = { + self.sensor_kit_frame: { + f"{self.camera_frame}/camera_link": sensor_kit_camera_link_transform + } + } + return result diff --git a/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/tag_based_sfm_base_lidar_calibrator.py b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/tag_based_sfm_base_lidar_calibrator.py new file mode 100644 index 00000000..1b502c42 --- /dev/null +++ b/sensor_calibration_manager/sensor_calibration_manager/calibrators/x2_gen2/tag_based_sfm_base_lidar_calibrator.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +# Copyright 2024 TIER IV, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Dict + +import numpy as np + +from sensor_calibration_manager.calibrator_base import CalibratorBase +from sensor_calibration_manager.calibrator_registry import CalibratorRegistry +from sensor_calibration_manager.ros_interface import RosInterface +from sensor_calibration_manager.types import FramePair + + +@CalibratorRegistry.register_calibrator( + project_name="x2_gen2", calibrator_name="tag_based_sfm_base_lidar_calibrator" +) +class TagBasedSfmBaseLidarCalibrator(CalibratorBase): + required_frames = [] + + def __init__(self, ros_interface: RosInterface, **kwargs): + super().__init__(ros_interface) + + self.base_frame = kwargs["base_frame"] + self.top_unit_frame = "sensor_kit_base_link" + + self.main_sensor_frame = kwargs["main_calibration_sensor_frame"] + + self.required_frames.extend([self.base_frame, self.top_unit_frame, self.main_sensor_frame]) + + self.add_calibrator( + service_name="calibrate_base_lidar", + expected_calibration_frames=[ + FramePair(parent=self.main_sensor_frame, child=self.base_frame) + ], + ) + + def post_process(self, calibration_transforms: Dict[str, Dict[str, np.array]]): + sensor_kit_to_mapping_lidar_transform = self.get_transform_matrix( + self.top_unit_frame, self.main_sensor_frame + ) + + base_to_top_sensor_kit_transform = np.linalg.inv( + sensor_kit_to_mapping_lidar_transform + @ calibration_transforms[self.main_sensor_frame][self.base_frame] + ) + results = {self.base_frame: {self.top_unit_frame: base_to_top_sensor_kit_transform}} + + return results