SLAM Engineer

๐ŸŒˆ IMU์™€ LiDAR๋ฅผ ํ“จ์ „ํ•ด์•ผ ํ•˜๋Š” ์ด์œ  2 (Feat. PyPose and Open3D)


Loosely-coupled Lidar-Inertial odometry ์‹ค์Šต

  • ์ €๋ฒˆ ๋ธ”๋กœ๊ทธ ๊ธ€ ์—์„œ IMU๋งŒ์œผ๋กœ odometry (์ฆ‰, relative motion ์ถ”์ •) ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” global attidue๊ฐ€ ์ค‘์š”ํ•จ์„ ์•Œ์•„๋ณด์•˜๋‹ค.
    • ๋ฌผ๋ก  PVA (position, velocity, attitude) ๊ฐ€ ๋ชจ๋‘ ์ค‘์š”ํ•˜๋‹ค.
  • ํ•˜์ง€๋งŒ ๊ฐ’๋น„์‹ผ GPS+INS ์—†์ด๋„, LiDAR ์„ผ์„œ๋ฅผ ์ด์šฉํ•ด์„œ ์ด๋Ÿฌํ•œ ๋ณด์ •์„ ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.
  • Python๋งŒ ์ด์šฉํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ loosely-coupled lidar-inertial odometry (a.k.a mini-pyllio) ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž.

๊ฐœ์š”

  • ์ €๋ฒˆ ๋ธ”๋กœ๊ทธ ๊ธ€ ์—์„œ IMU๋งŒ์œผ๋กœ odometry (์ฆ‰, relative motion ์ถ”์ •) ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” global attidue๊ฐ€ ์ค‘์š”ํ•จ์„ ์•Œ์•„๋ณด์•˜๋‹ค.
  • KITTI dataset ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฐ’๋น„์‹ผ GPS+INS ์„ผ์„œ (== oxts) ๊ฐ€ ์ œ๊ณตํ•˜๋Š” Global rotation ์„ ๊ณต๊ธ‰ํ•œ ๊ฒฝ์šฐ, ์ด ๊ฐ’์œผ๋กœ ์ค‘๋ ฅ์„ ์ž˜ ๋ณด์ƒํ•ด์ค„ ์ˆ˜ ์žˆ์—ˆ๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ ์œ ํšจํ•œ ๊ฐ€์†๋„๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๊ณ , ์ด๋Š” velocity ์™€ position ์˜ˆ์ธก์„ ๋” ์ž˜ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ๊ฐ’๋น„์‹ผ GPS+INS ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ? ํ˜น์€ ์‹ค๋‚ด์—์„œ GPS ์‹ ํ˜ธ๊ฐ€ ๊ณต๊ธ‰๋˜์ง€ ์•Š์„ ๋•Œ์—๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?
  • LiDAR ๋ฅผ ์ด์šฉํ•ด์„œ ์ด ์—ญํ• ์„ ๋Œ€์‹ ํ•ด๋ณด์ž.

๊ตฌํ˜„

๋ชฉ์ 

  • Python ๋งŒ์„ ์ด์šฉํ•ด์„œ ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ด์—ˆ๋‹ค.
    • IMU propagation ์€ Pypose ๋ฅผ ์‚ฌ์šฉํ•˜์˜€๊ณ , LiDAR scan-to-scan registration ์€ Open3D ๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๊ตฌํ˜„์ฒด

ํ†บ์•„๋ณด๊ธฐ

  • ๋ฉ”์ธ๋ถ€๋ถ„๋งŒ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๋‹ค.
      # state estimation for a KITTI dataset raw data sequence (e.g., 2011_09_30_0018)
      llio = LLIO("cfg.yml")
      llio.init_integrator()
    
      for idx, data in enumerate(llio.dataloader):
          state = llio.propogate(data)
          state = llio.correct(data, llio.cfg["use_lidar_correction"])
    
          llio.append_log(data, state)
    
      llio.visualize_traj()
    
    • ์ œ์ผ ๋งˆ์ง€๋ง‰์— ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋ฆฌ๋„๋ก ํ•˜์˜€๋‹ค (visualize_traj()).
  • ๋‹จ๊ณ„๋ณ„๋กœ ์š”์•ฝํ•ด๋ณด์ž๋ฉด:
    1. ์ค€๋น„ ๋‹จ๊ณ„
      • LLIO (Loosely-coupled LiDAR Inertial Odometry) ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด dataset์„ load ํ•œ๋‹ค.
         def load_dataset(self):
             self.dataset = KittiDataloader(
                 self.cfg["input"]["dataroot"],
                 self.cfg["input"]["dataname"],
                 self.cfg["input"]["datadrive"],
                 duration=self.cfg["step_size"],
                 step_size=self.cfg["step_size"],
             )
        
      • ๊ต์œก์šฉ ๋ชฉ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— lidar scan ์„ ํ•œ๋ฒˆ์— ๋‹ค ์ฝ์–ด์„œ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ๋„๋ก ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. ๊ทธ๋ž˜์„œ ์ˆ˜ ์ดˆ๊ฐ€ ์†Œ์š”๋˜๊ณ  (๋ฐ์ดํ„ฐ์…‹์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ) ์ˆ˜G ์ •๋„์˜ ์—ฌ๋ถ„์˜ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค (ps. 2011_09_30_0020 ๊ฐ€ frame์ด 1000๊ฐœ ์ •๋„๋˜๋Š” ๊ฝค ์งง์€ ์‹œํ€€์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฑธ๋กœ ์‹ค์Šตํ•˜๋ฉด ํŽธ๋ฆฌํ•  ๊ฒƒ์ด๋‹ค).
      • ์œ„์˜ configuration์—์„œ step_size ๋Š” lidar aiding ์„ ๋ฐ›์„ ๊ฐ„๊ฒฉ์„ ์˜๋ฏธํ•œ๋‹ค.
        • ์˜ˆ๋ฅผ ๋“ค์–ด 5๋กœ ์„ค์ •ํ•˜๋ฉด, LiDAR ๋Š” 5 frame ๋งˆ๋‹ค ํ•œ๋ฒˆ์”ฉ๋งŒ ๋ณด์ •์„ ํ•œ๋‹ค. ๋ณด์ •ํ•˜์ง€ ์•Š๋Š” ๋‚˜๋จธ์ง€ 4 ํ”„๋ ˆ์ž„ ๊ฐ„๊ฒฉ์— ๋Œ€ํ•ด์„œ๋Š” ๋ณด์ •์—†์ด, imu only๋กœ propagation ์„ ํ•œ๋‹ค๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
        • ์‹ค์ œ๋กœ๋„, IMU (๋ณดํ†ต 100hz ์ด์ƒ) ๋ณด๋‹ค LiDAR ์„ผ์„œ (10hz) ์˜ frame ์ด ๋” sparse ํ•˜๊ฒŒ ๋“ค์–ด์˜ค๊ธฐ ๋•Œ๋ฌธ์—, correction ์€ sparse ํ•˜๊ฒŒ ์ผ์–ด๋‚˜๊ณ , propagation ์€ ๋” ์ž์ฃผ ์ผ์–ด๋‚˜๋Š” ์ƒํ™ฉ์ด ์ผ๋ฐ˜์ ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋ณดํ†ต์€ ๋ชจ๋“  lidar frame ์— ๋Œ€ํ•ด์„œ correction์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค (๊ทธ๊ฒƒ๋ณด๋‹ค ์ด๋ฏธ imu hz๊ฐ€ ๋” ๋†’๊ธฐ ๋•Œ๋ฌธ์—).
        • ๋‹ค๋งŒ ์ด ์‹ค์Šต์˜ˆ์ œ์—์„œ๋Š” KITTI dataset ์˜ raw data ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์—์„œ๋Š” imu data (in the oxts directory) ๊ฐ€ lidar frame ์— ๋™๊ธฐํ™”๋˜์–ด ์žˆ๋‹ค (๋ฏธ๋ฆฌ relative frame ์‚ฌ์ด์˜ angular velocity ์™€ linear acceleration์„ preintegrationํ•ด๋‘” ๊ฐ’์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค ๋ผ๊ณ  ๋ณด๋ฉด ๋˜๊ฒ ๋‹ค). ๋”ฐ๋ผ์„œ ๊ฐ™์€ ๊ฐœ์ˆ˜์˜ ํŒŒ์ผ์ด ์กด์žฌํ•œ๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ step_size ๋ฅผ 5๋กœ ์„ค์ •ํ•œ๋‹ค๋ฉด, ์•ž์„œ ๋งํ–ˆ๋“ฏ, LiDAR ๋Š” 5 frame ๋งˆ๋‹ค ํ•œ๋ฒˆ์”ฉ๋งŒ ๋ณด์ •์„ ํ•œ๋‹ค. ๋ณด์ •ํ•˜์ง€ ์•Š๋Š” ๋‚˜๋จธ์ง€ 4 ํ”„๋ ˆ์ž„ ๊ฐ„๊ฒฉ์— ๋Œ€ํ•ด์„œ๋Š” ๋ณด์ •์—†์ด, imu only๋กœ propagation ์„ ํ•œ๋‹ค๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. 10hz lidar ์ธ ๊ฒฝ์šฐ, 0.5์ดˆ ๋™์•ˆ imu๋กœ๋งŒ odometry๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค. ๊ทธ๋ ‡๊ฒŒ ์—๋Ÿฌ๊ฐ€ ๋ˆ„์ ๋  ๋•Œ์ฏค, lidar scan-to-scan matching ์„ ์ˆ˜ํ–‰ํ•ด์„œ IMU state ์˜ PVA (position, velocity, attitude) ๋ฅผ ๋ณด์ •ํ•ด์ค€๋‹ค. ๊ทธ๋Ÿฌ๋ฉด IMU๋Š” ๋‹ค์‹œ ์ข‹์€ ์ƒํƒœ๋ฅผ ๊ฐ–๊ฒŒ ๋˜๊ณ , ๋‹ค์‹œ ํ•œ๋™์•ˆ (๋ฌผ๋ก  0.5์ดˆ์™€ ๊ฐ™์ด ์—ฌ์ „ํžˆ ์งง์€ ์‹œ๊ฐ„ (IMU์ž…์žฅ์—์„œ๋Š” ๋‹ค์†Œ ๊ธด์‹œ๊ฐ„์ผ์ง€๋„) ๋‚ด์—์„œ ๋ง์ด๋‹ค) lidar (๊ฐ€ ๋“ค์–ด์˜ค์ง€ ์•Š๊ฑฐ๋‚˜) ๋ณด์ •์„ ๋ฐ›์ง€ ๋ชปํ•˜๋”๋ผ๋„ ์–ด๋Š์ •๋„ ์ž˜ egomotion estimation ์„ ํ•ด์ค„ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์šฐ๋ฆฌ๋Š” ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    2. Main
      1. Propagation
        • Propagation ์„ ์œ„ํ•ด์„œ๋Š” Pypose์˜ IMUPreintegrator ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
           def propogate(self, data):
              propagated_state = self.integrator(  # == forward()
                  dt=data["dt"],
                  gyro=data["gyro"],
                  acc=data["acc"],
                  rot=self.get_rotation(data)
              )
          
          • ๋” ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„ ๋””ํ…Œ์ผ์€ ์ด ๋ผ์ธ์„ ์ฐธ๊ณ .
      2. Correction
        • Correction ๋‹จ๊ณ„์—์„œ๋Š” ๋จผ์ € scan-to-scan matching ์„ ํ†ตํ•ด์„œ (imu propagation only๋ณด๋‹ค ์ •๋ฐ€ํ•ด์ง„) relative motion ์„ ๊ณ„์‚ฐ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ์ง์ „ pose ์— compose ํ•ด์„œ global pose ๋ฅผ correctํ•ด์ค€๋‹ค.
            # registration and get a more precise relative motion
            pcd = utils.downsample_points(data["velodyne"][0], self.cfg)
            dx_imu = self.registration(source=pcd, target=self.pcd_previous)
          
            # correct the current global pose
            pose_corrected_prev = self.pose_corrected
            pose_corrected = pose_corrected_prev @ dx_imu
          
            # update the state of the estimator
            dt_batch = data["dt"][..., -1, :] * self.cfg["step_size"]  # sec
            corrected_state = self.update_state(dt_batch, pose_corrected)
          
        • ์ด ๊ณผ์ •์—์„œ ์–ด์งœํ”ผ ICPํ•ด์„œ relative motion ์„ ๊ตฌํ• ๊ฑฐ๋ฉด IMU๊ฐ€ ์™œ ํ•„์š”ํ•œ๊ฐ€? ๋ผ๋Š” ์งˆ๋ฌธ์„ ํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค.
          • ํ•˜์ง€๋งŒ ICP๋Š” initial guess ๊ฐ€ ์ข‹์„ ๋•Œ์—๋งŒ ์ •๋‹ต์œผ๋กœ์˜ ์ˆ˜๋ ด์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.
          • ๋งŒ์•ฝ ๋กœ๋ด‡์ด ๊ณ ์†์œผ๋กœ ์ฃผํ–‰ํ•˜๊ณ  ์žˆ๊ฑฐ๋‚˜, ํ˜น์€ ํšŒ์ „ํ•˜๊ณ  ์žˆ๊ฑฐ๋‚˜, ํ˜น์€ ๋™์ ๋ฌผ์ฒด๊ฐ€ ๋„ˆ๋ฌด ๋งŽ๊ฑฐ๋‚˜ ๋“ฑ ๋‹ค์–‘ํ•œ ์ด์œ ๋กœ ์ธํ•ด ์ฃผ๋ณ€ ํ™˜๊ฒฝ์˜ structure ๊ฐ€ locally converge ํ•  ์œ„ํ—˜์ด ๋งŽ๋‹ค.
          • ํŠนํžˆ ์œ„์˜ ์˜ˆ์‹œ์—์„œ step_size ๋ฅผ 5๋กœ ์„ค์ •ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ฆ‰ 0.5์ดˆ ์ „ํ›„์˜ ์Šค์บ”์„ ์ •ํ•ฉํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. KITTI dataset์—์„œ์˜ ์ž๋™์ฐจ์˜ ๊ฒฝ์šฐ 0.5์ดˆ ๋งŒ์— ์ˆ˜ meter ๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ˆ˜ meter ์ •๋„์˜ translation ์ด ์žˆ์„ ๋•Œ initial guess ์—†์ด (== using identity) ICP ๊ฐ€ ์ˆ˜๋ ดํ•˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•˜๊ธฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์–ด๋ ต๋‹ค (์•„๋ž˜ ์‹คํ—˜๊ฒฐ๊ณผ์—์„œ ์ •๋Ÿ‰์ ์œผ๋กœ ์•Œ์•„๋ณด์•˜๋‹ค).
          • ๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์ด IMU ๊ฐ€ propagate ํ•œ relative motion ์„ ์ด์šฉํ•ด์„œ initial guess ๋ฅผ ๊ณต๊ธ‰ํ•ด์ฃผ๋ฉด ICP๊ฐ€ ๋” ์ž˜ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, IMU๊ฐ€ LiDAR์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์ด๋‹ค.
              dx_imu_initial = self.relative_pose_propagated
              dx_lidar_initial = i2v @ dx_imu_initial @ v2i # important!
              icplib = o3d.pipelines.registration
              dx_lidar = icplib.registration_generalized_icp(
                  source,
                  target,
                  self.cfg["icp_inlier_threshold"],
                  dx_lidar_initial,
                  icplib.TransformationEstimationForGeneralizedICP(),
              ).transformation
            
            • Tip: ์ด ๋•Œ error = np.linalg.inv(dx_lidar) @ dx_lidar_initial ์™€ ๊ฐ™์ด initial guess ์™€ ICP๋กœ ๋ถ€ํ„ฐ ์–ป์€ transform ์‚ฌ์ด์˜ ์ฐจ์ด๋ฅผ ๊ณ„์‚ฐํ•ด๋ณด๋ฉด, IMU๊ฐ€ ์–ผ๋งˆ๋‚˜ ์ข‹์€ initial ์„ ๊ณต๊ธ‰ํ•ด์ฃผ๋Š” ์ง€ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค. step size ๋ฅผ 1์ด๋‚˜ 2๋กœ ์„ค์ •ํ•  ๊ฒฝ์šฐ ๊ฑฐ์˜ ์ˆ˜ cm ์ˆ˜์ค€๋งŒ์˜ ์ฐจ์ด๋ฅผ ๋ณด์ด๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
            • PS: ๋ฌผ๋ก  IMU์—†์ด LiDAR ๋งŒ์œผ๋กœ๋„ robust ํ•œ local keypoint matching ์„ ํ†ตํ•ด ์ข‹์€ registration initial ์„ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜๋„ ์žˆ๋‹ค (์˜ˆ์‹œ: Open3Dโ€™s global registration, or Quatro ICRA22). ํ•˜์ง€๋งŒ IMU ๊ฐ€ ๊ฐ–๋Š” ์žฅ์ ์€, ์ด๋Ÿฐ ๋ฐฉ์‹๋“ค์— ๋น„ํ•ด (propagationํ•˜๋Š” ๊ฒƒ์€) ์ถ”๊ฐ€์ ์ธ ๋น„์šฉ์ด ๊ฑฐ์˜ ๋“ค์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค! ๋ฌผ๋ก  ์–ด๋Š์ชฝ์ด ํ•ญ์ƒ ๋” ๋‚ซ๋‹ค ๋ผ๊ณ  ๋งํ•  ์ˆ˜๋Š” ์—†๋Š” ๊ฒƒ์ด๊ณ , point cloud ์„ผ์„œ ๋ฐ์ดํ„ฐ๋งŒ ๋ฉ๊ทธ๋Ÿฌ๋‹ˆ ์ฃผ์–ด์ง€๋Š” ์ƒํ™ฉ์ธ๊ฐ€, ํ˜น์€ a robot ์ด real-time ์œผ๋กœ recursively state ๋ฅผ ์˜ˆ์ธกํ•ด๋‚˜๊ฐ€๋Š” ์ƒํ™ฉ์ธ๊ฐ€, ์— ๋”ฐ๋ผ ์—”์ง€๋‹ˆ์–ด๊ฐ€ ์ž์›๊ณผ ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•ด์„œ ์ ์ ˆํ•˜๊ฒŒ ์„ ํƒํ•ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.
        • ์ด๋ ‡๊ฒŒ ๊ณ„์‚ฐํ•œ ๋ณด์ •๋œ relative motion ์„ ์ด์šฉํ•ด์„œ global pose ๋ฅผ correction ํ•ด์ค€๋‹ค.
          def update_state(self, dt_batch, pose_corrected):
              # prepare
              global_pos = torch.tensor(pose_corrected[:3, -1]).unsqueeze(0)
          
              pose_corrected_prev = self.pose_corrected
              global_delta_pos = torch.tensor(
                  pose_corrected[:3, -1] - pose_corrected_prev[:3, -1]).unsqueeze(0)
              global_vel = global_delta_pos / dt_batch
          
              global_rot = pp.SO3(R.from_matrix(pose_corrected[:3, :3]).as_quat())
          
              # update (loosely coupled, thus do explicit replacement) the engine state
              self.integrator.pos = global_pos
              self.integrator.vel = global_vel
              self.integrator.rot = global_rot
          
          • ์ด ๊ณผ์ •์—์„œ integrator ๋‚ด๋ถ€์˜ state ๋ฅผ ๊ทธ๋ƒฅ ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•˜๋Š” ์…ˆ์ด๋ฏ€๋กœ loosely coupled lidar-inertial odometry system ์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋‹ค. correction ๊ณผ์ •์—์„œ IMU๋Š” LiDAR์—๊ฒŒ initial ์„ ๋…๋ฆฝ์ ์œผ๋กœ ์ œ๊ณตํ•˜๊ณ , ์‹ค์ œ๋กœ ๋ณด์ •์น˜๋Š” LiDAR registration ๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์‹คํ—˜ ๊ฒฐ๊ณผ

  • ์„ธํŒ…
    • LiDAR registrationํ•  ๋•Œ point cloud ๋Š” 0.5m ๋กœ voxel downsampling ํ•˜์˜€๋‹ค.
    • 2011_09_30_0018 ์‹œํ€€์Šค์— ๋Œ€ํ•ด ์‹คํ—˜ํ•˜์˜€๋‹ค.
  • Ablations for each comparison methods

  • Z ๋น„๊ต

  • ์š”์•ฝ
    • LiDAR only ๋Š” scan๊ณผ scan ์‚ฌ์ด ๊ฐ„๊ฒฉ์ด ๋ฉ€์–ด์งˆ ์ˆ˜๋ก initial guess ์—†์ด๋Š” failํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
    • GT rotation ์„ ๊ณต๊ธ‰ํ•œ ๊ฒƒ๋ณด๋‹ค, sparse ํ•˜๋”๋ผ๋„ lidar ๋กœ ๋ณด์ •ํ•œ ๊ฒƒ์ด ๋” ์•ˆ์ •์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๊ฒฐ๋ก 

  • IMU only odometry ๋Š” ์™ธ๋ถ€ ๋„์›€ ์—†์ด๋Š” ๊ธˆ๋ฐฉ ๋ฐœ์‚ฐํ•œ๋‹ค.
  • Python ๋งŒ ์ด์šฉํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ Loosely-coupled LiDAR + IMU ๊ธฐ๋ฐ˜ Odometry system์„ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค.
  • LiDAR๊ฐ€ rough ํ•˜๊ฒŒ๋งŒ ์“ฐ์—ฌ๋„ (i.e., 0.5m resolution, 0.5sec ๋งˆ๋‹ค ํ•œ ๋ฒˆ๋งŒ ๋ณด์ •), IMU state ๋ฅผ ์ž˜ ๋ณด์ •ํ•  ์ˆ˜ ์žˆ์Œ์„ ์‹คํ—˜์ ์œผ๋กœ ์•Œ์•„๋ณด์•˜๋‹ค.
  • ์ด๋ ‡๊ฒŒ PVA๊ฐ€ ์ž˜ ๋ณด์ •๋œ IMU๋Š” ๊ทธ ๋‹ค์Œํ„ด์˜ LiDAR registration ์„ ์œ„ํ•œ ์ข‹์€ initial guess ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ ์„ ์ˆœํ™˜์ด ๋ฐ˜๋ณต๋œ๋‹ค.