SLAM Engineer

๐ŸŒˆ [SymForce Tutorial 1ํŽธ] Nonlinear ICP ๋ฐ‘๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ


SymForce ๋ž€?

  • ์ตœ๊ทผ RSS 2022 ์—์„œ SymForce ๋ผ๋Š” framework ์ด ๊ณต๊ฐœ๋˜์—ˆ๋‹ค. Skydio ๊ฐ€ ๊ณต๊ฐœํ•˜์˜€๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ 5๋…„๋™์•ˆ ๊ฐœ๋ฐœํ•˜๊ณ  ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด์˜จ ๊ฒƒ์ด๋ผ๊ณ  ํ•œ๋‹ค.
  • Skydio ๋Š” ์ดˆ๊ธฐ์— GTSAM ์ €์ž์ด์‹  + SLAM ์—ญ์‚ฌ์— ํฐ ํš์„ ๊ทธ์€ Frank Dellaert ๊ต์ˆ˜๋‹˜์˜ ์ž๋ฌธ์„ ๋ฐ›์•˜๋‹ค๊ณ  ๋“ค์—ˆ๋‹ค. ์ตœ๊ทผ์—๋Š” ๋ฉ‹์ง„ ๊ฒฐ๊ณผ๋“ค๋„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์–ด์„œ, ์ด๋“ค์˜ ๊ธฐ์ˆ ๋ ฅ์€ ์–ด๋–ค ์ˆ˜์ค€์ผ์ง€ ๊ถ๊ธˆํ–ˆ์—ˆ๋‹ค.
  • SymForce ๋…ผ๋ฌธ์„ ๋ณด๋ฉด robotics (ํŠนํžˆ ๋“œ๋ก  ๋“ฑ)์™€ ๊ฐ™์ด ๋น ๋ฅธ ๊ณ„์‚ฐ์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์š”๊ตฌ๋  ๋•Œ์—๋Š”, (Ceres ๊ฐ™์€) ๊ณ„์‚ฐ๊ทธ๋ž˜ํ”„ ๊ธฐ๋ฐ˜๋ณด๋‹ค symbolic ๊ธฐ๋ฐ˜ ์˜ ๋ฏธ๋ถ„์ด ๋” ์ข‹๋‹ค๊ณ  ์ฃผ์žฅํ•˜๊ณ  ์žˆ๋‹ค. ์›๋ž˜ Robotics ์—์„œ Ceres ๊ฐ€ ๋งŽ์ด ์“ฐ์ด๊ณ  ์žˆ์–ด์„œ ์ƒˆ๋กœ์šด solver ์˜ ํ•„์š”์„ฑ์„ ๋ชป ๋Š๋ผ๊ณ  ์žˆ์—ˆ๋Š”๋ฐ, ์ด ๋…ผ๋ฌธ์˜ ๋ง์„ ๋“ค์–ด๋ณด๋ฉด ์™ ์ง€ ์„ค๋“์ด ๋œ๋‹ค.
  • ํ•œ ๋ฒˆ ๊ณต๋ถ€ํ• ๊ฒธ ์จ๋ณด์•˜๋‹ค.

Nonlinear ICP ๊ตฌํ˜„ํ•˜๊ธฐ

๋ชฉํ‘œ

  • Nonlinear ICP ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž.

๋ฐฐ๊ฒฝ์ง€์‹

Nonlinear optimization

  • Nonlinear optimization ์–ด์ฉŒ๊ตฌ ํ•˜๋ฉด == Gauss-Newton์œผ๋กœ iterative ํ•˜๊ฒŒ ํ‘ผ๋‹ค ๋ผ๊ณ  ์ดํ•ดํ•ด๋„ ๊ฑฐ์˜ ๋ฌด๋ฐฉํ•˜๋‹ค.
  • ์ด ๋•Œ update step ์˜ ๋ฐฉํ–ฅ๊ณผ ํฌ๊ธฐ๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด cost function ์˜ ๋ฏธ๋ถ„๊ฐ’์ด ํ•„์š”ํ•˜๊ณ  ์ด๊ฒƒ์„ Jacobian์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
    • ์ด ๋•Œ cost function output dimension ์ด $n$์ด๊ณ , cost function ์„ ๊ตฌ์„ฑํ•˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ฐพ๊ณ ์‹ถ์€ ์ตœ์ ๊ฐ’์— ๋Œ€ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ณ€์ˆ˜์˜ dimension ์ด $m$์ด๋ผ๊ณ  ํ•˜๋ฉด Jacobian์˜ shape ์€ $n \times m$์ด ๋˜๊ฒŒ ๋œ๋‹ค.

Auto diff

  • ๊ทธ๋Ÿฐ๋ฐ nonlinearํ•œ(์ฆ‰ $a_0 x_0 + a_1 x_ 1 + โ€ฆ$ ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ ๋ชจ๋“  ํฌ๋งท) ๋ณต์žกํ•œ cost function ์˜ Jacobian ์„ ์‚ฌ๋žŒ์ด ์†์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ˆ˜ํ•  ์œ„ํ—˜์ด ํฌ๊ธฐ ๋•Œ๋ฌธ์—, ๋ณ€์ˆ˜๋“ค์„ ๊ณ„์‚ฐ๊ทธ๋ž˜ํ”„๋กœ ์—ฐ๊ฒฐํ•˜๊ณ , ์ž๋™์œผ๋กœ ๋ฏธ๋ถ„๊ฐ’์ด ๊ด€๋ฆฌ๋˜๋„๋ก (์ „ํŒŒ๋˜๋„๋ก) ํ•˜๋Š” ๊ตฌํ˜„์„ ์ฑ„ํƒํ•˜๋Š” ๋ฐฉ์‹์ด ๋„๋ฆฌ ์“ฐ์ด๊ณ  ์žˆ๋‹ค (e.g., Ceres, Pytorch)
    • ์ด ๊ฒฝ์šฐ, forward ์ „ํŒŒ๋  ๋•Œ ํ•˜๋‚˜์˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•ด value์™€ gradient ์˜ ๋‘ ๊ฐ’์„ ๋™์‹œ์— ํ•จ๊ป˜ ์ €์žฅํ•ด์•ผ ๋˜๊ฒŒ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Ceres ์—์„œ๋Š” jet์ด๋ผ๋Š” ํ˜•ํƒœ๋กœ ๊ด€๋ฆฌ๋˜๊ณ , autodiff ์—์„œ๋Š” dual ์ด๋ผ๋Š” ์ด๋ฆ„์ด ์“ฐ์ด๊ณ  ์žˆ๋‹ค.

Symbolic diff

  • ์ด๋ ‡๊ฒŒ jet, dual ๋“ฑ์˜ ๊ตฌ์กฐ์ฒด๋กœ ๋‘ ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋ฉด์„œ ๊ณ„์‚ฐ๊ทธ๋ž˜ํ”„๋ฅผ ํ˜•์„ฑํ•˜๋Š” ์‹์˜ autodiff ๊ฐ€ robotics ์™€ deep learning ๋ถ„์•ผ ๋ชจ๋‘์— ๋Œ€ํ•ด์„œ ๋„๋ฆฌ ์“ฐ์ด๊ณ  ์žˆ๋Š” (Ceres, autodiff, tinyAD, jax, pytorch, tensorflow ๋“ฑ๋“ฑ๋“ฑ) ์š”์ฆ˜์ด์ง€๋งŒ โ€ฆ
  • SymForce ๋Š” Symbolic ๊ธฐ๋ฐ˜์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ฆ‰, ์ž„์˜์˜ cost function ์ด ์ฃผ์–ด์งˆ ๋•Œ, ์ด๊ฒƒ์˜ ์ž์ฝ”๋น„์•ˆ์„ ๋ช…์‹œ์ ์œผ๋กœ ์‹์œผ๋กœ ๋”ฑ ๊ณ„์‚ฐํ•ด์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๊ณ„์‚ฐ์ด ์ตœ์ ํ™”๋˜๋„๋ก ํ•ด์ค€๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ICP์—์„œ cost function ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. 3D point $p_0$ ๊ณผ point $p_1$์ด ์ฃผ์–ด์งˆ ๋•Œ, loss $= ||\left( R \{ \theta \}*p_0 + t \right) - p_1 || _2$ ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” transformation parameter $\theta$ ์™€ $t$ ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์ด๋‹ค.
    • ์ด ๋•Œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ทธ๋Ÿฌ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์งˆ๋ฌธ(๋ฉ˜๋ถ•)์— ๋น ์ง€๊ฒŒ ๋œ๋‹ค. $\frac{\partial\text{loss}}{\partial\bf{\theta}}$ ์™€ $\frac{\partial\text{loss}}{\partial{t}}$๋ฅผ ์–ด๋–ป๊ฒŒ ๊ณ„์‚ฐํ•˜์ง€ ..???!?
    • ์ด ๋•Œ ์ด๊ฑธ ๊ณ„์‚ฐ๊ทธ๋ž˜ํ”„๋กœ ๋ฌถ์–ด์„œ ๊ฐ’์„ ์ฃผ๋ฉด autodiff ์ด๊ณ .. ๋ช…์‹œ์ ์œผ๋กœ (์ˆ˜์ž‘์—… ๊ธฐ์ค€)๋ณต์žกํ•œ ์ˆ˜์‹์„ ์ฐพ์•„์ฃผ๋Š” ๊ฒŒ symbolic ์ด๋ผ๊ณ  ์ผ๋‹จ ์ดํ•ดํ•˜๊ณ  ์žˆ๋‹ค (๋” ๊ณต๋ถ€ ํ•„์š”)
    • ์ฆ‰, SymForce ์—๊ฒŒ ์ด ์ž‘์—…์„ ๋งก๊ธฐ๋ฉด $\frac{\partial\text{loss}}{\partial\bf{\theta}}$์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์•„๋ž˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋‚˜์˜จ๋‹ค (๋„ˆ๋ฌด ๊ธธ์–ด์„œ ๋‹ค ์˜ฎ๊ธธ ์ˆ˜๊ฐ€ ์—†์–ด์„œ ์บก์ฒ˜๋กœ ๋Œ€์‹ ํ•œ๋‹ค. ์ „์ฒด ์‹์€ ์—ฌ๊ธฐ jupyter notebook๋ฅผ ์ฐธ๊ณ ).

    • ์ด ๋•Œ $\theta$๋Š” rotation ์„ minimal ํ•˜๊ฒŒ parametrize ํ•˜๋Š” angle-axis ๊ฐ€ ๋œ๋‹ค. ์ด๋ฅผ tangent space ์—์„œ ์ตœ์ ํ™”ํ•œ๋‹ค๋ผ๊ณ ๋„ ํ‘œํ˜„ํ•˜๊ณ , ์ดํ›„์— ์ด ๊ฐ’์„ ์›๋ž˜ ๊ณต๊ฐ„ (e.g., rotation์— ๋Œ€ํ•ด์„œ๋Š” $\text{SO(3)}$) ์œผ๋กœ ๋ณด๋‚ด์ฃผ๋Š” ์ž‘์—…์„ retract ๋ผ๊ณ  ๋ถ€๋ฅด๊ธฐ๋„ ํ•˜๊ณ  โ€ฆ ์ด์— ๋Œ€ํ•ด์„œ๋Š” ๋ณ„๋„์˜ rotation ๊ด€๋ จ ์ž๋ฃŒ(A micro Lie theory for state estimation in robotics, Quaternion kinematics for the error-state Kalman filter )๋ฅผ ์ฐธ๊ณ ํ•˜๋„๋ก ํ•˜์ž.
  • ์•„๋ฌดํŠผ ์š”์•ฝํ•˜์ž๋ฉด Jacobain matrix ์˜ ๊ฐ’์„ ์•Œ๋ฉด iterative update ํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ์‰ฌ์šด๋ฐ, ์ด ๋•Œ ์•„๋ฌด๋ฆฌ ๋ณต์žกํ•œ ํ•จ์ˆ˜์—ฌ๋„ SymForce ๊ฐ€ ์ž์ฝ”๋น„์•ˆ์„ ์•Œ์•„์„œ ์ž˜ ๊ตฌํ•ด์ค€๋‹ค๋Š” ๊ฒƒ. ํŠนํžˆ robotics ์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” parameter ๋“ค (camera projection, rotation ๋“ฑ) ์— ๋Œ€ํ•œ ์ง€์›์„ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— SymPy ๋“ฑ์˜ ๊ธฐ์กด Symbolic solver ๋“ค์„ ์‚ฌ์šฉํ•  ๋•Œ๋ณด๋‹ค robotics ๋ฌธ์ œ๋ฅผ ๋” ํ’€๊ธฐ ํŽธ๋ฆฌํ•ด์กŒ๋‹ค๋Š” ์  ๋“ฑ์ด ์žฅ์ ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค.

๊ตฌํ˜„

Iterative update

  • ์ž์ฝ”๋น„์•ˆ์„ ๊ตฌํ•œ๋‹ค์Œ, ์ด๊ฒƒ์„ ์ด์šฉํ•ด์„œ iterative ํ•˜๊ฒŒ ์ตœ์ ์˜ $d[\theta, t]$ ๋ฅผ ๊ตฌํ•˜๊ณ , ์กฐ๊ธˆ์”ฉ ์ด ๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•ด๋‚˜๊ฐ€๋Š” ๋ฃจํ‹ด์€ ๋„ˆ๋ฌด๋‚˜ ์ž๋ช…ํ•˜๋‹ค. ์ด์— ๋Œ€ํ•ด์„œ๋Š” Grisetti ๊ต์ˆ˜๋‹˜์˜ 2016๋…„ ICRA tutorial ์ž๋ฃŒ ๋ฅผ ์ถ”์ฒœํ•œ๋‹ค. ์—ฌ๊ธฐ์— ๋ณด๋ฉด ์ด๋Ÿฐ ์‹์ด ์žˆ๋‹ค. Octave (Matlab) ๊ตฌํ˜„์ฒด์ด๋‹ค.

  • ์œ„์˜ ๊ตฌ์กฐ๋ฅผ python์œผ๋กœ ์˜ฎ๊ธฐ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋œ๋‹ค. (์ „์ฒด ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ symforce-tutorials ์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค).
    def icp(src, tgt, tf_init, max_iter=5, verbose=False):
    
      tf = tf_init # 6 dim
      num_pts = src.shape[0]
    
      for _iter in range(max_iter):
          # reset for each iter
          H = np.zeros((6, 6))
          b = np.zeros((6, 1))
    
          # gathering measurements
          for pt_idx in range(num_pts):
    
              src_pt = src[pt_idx, :]
              tgt_pt = tgt[pt_idx, :]
    
              e, Je_rot, Je_trans \
                  = evaluate_error_and_jacobian(src_pt, tgt_pt, tf)
    
              J = np.hstack((Je_rot, Je_trans)) # thus, 3x6
    
              H = H + J.T @ J # H: 6x3 * 3x6 => thus H is 6x6
              b = b + J.T @ e # b: 6x3 * 3x1 => thus b is 6x1
    
          dtf = -np.linalg.solve(H, b).squeeze() # note the step direction is minus
          tf = tf + dtf # updated within the tangent space
    
      return tf
    
    • note: ์ด ๋•Œ src_pt์™€ tgt_pt ๋Š” ์‹ค์ œ๋กœ ๊ฐ™์€ ์ง€์ ์˜ ํฌ์ธํŠธ์—ฌ์•ผ ํ•œ๋‹ค. ์ฆ‰, correspondence ์—ฌ์•ผ ํ•œ๋‹ค.
      • ps. ์ด๋ฒˆ ํŠœํ† ๋ฆฌ์–ผ์€ ๊ต์œก์šฉ์œผ๋กœ ์ž‘์„ฑํ•ด๋ณธ ๊ฒƒ (1. SymForce๋ฅผ ์ด์šฉํ•ด์„œ ์ž๋™์œผ๋กœ Jacobian์„ ์‹ฌ๋ณผ๋ฆญ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ณ„์‚ฐํ•ด๋ณด๊ธฐ 2. ์ด๋ฅผ ์ด์šฉํ•ด์„œ nonlinear optimization ์˜ update ๋ถ€๋ถ„ from scratch๋กœ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ) ์ด๊ธฐ ๋•Œ๋ฌธ์—โ€ฆ point cloud $\text{pcd}_0$(์œ„์˜ ๋ฆฌํฌ์—์„œ data/251371071.pcd๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์ž„์˜์˜ $\text{SE(3)}$ transformation ์„ ๊ฐ€ํ•ด์ฃผ์–ด์„œ $\text{pcd}_1$ ์„ ์ƒ์„ฑํ•˜๊ณ  ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ point ์˜ ์ˆœ์„œ๊ฐ€ ๋ณด์กด๋˜๋ฏ€๋กœ src_pt์™€ tgt_pt ๋ชจ๋‘ ๋™์ผํ•œ ์ธ๋ฑ์Šค pt_idx ๋กœ ๊ฐ€์ ธ์˜ค๋ฉด correspondence ๊ฐ€ ์„ฑ๋ฆฝ๋œ๋‹ค. ์‹ค์ œ ์„ธ๊ณ„ ๋ฌธ์ œ์—์„œ๋Š” FPFH local feature ๋“ฑ์˜ ๋ฐฉ๋ฒ•์œผ๋กœ correspondence ๋ฅผ ๋จผ์ € ์ฐพ๊ณ , ์ž˜ associate ๋œ pair ๋ฅผ ์œ„์˜ icp ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋„ฃ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
    • ์œ„์˜ ๋ฃจํ‹ด์€ ํŠน๋ณ„ํžˆ ์–ด๋ ค์šธ ๊ฒƒ์€ ์—†๋‹ค. Robotics ๋ฌธ์ œ์—์„œ ICP๋ฟ ์•„๋‹ˆ๋ผ ์–ด๋–ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋˜๋”๋ผ๋„ ๊ฒฐ๊ตญ ์œ„์˜ ๋ชจ์Šต์„ ํ•˜๊ฒŒ ๋œ๋‹ค.
    • ์ด ๋•Œ ๊ทธ๋Ÿฌ๋ฉด ์œ„์˜ ๋ฃจํ‹ด์—์„œ Jacobian์„ ๊ณ„์‚ฐํ•ด์ฃผ๋Š” evaluate_error_and_jacobian ํ•จ์ˆ˜๋ฅผ ๋””์ž์ธํ•˜๋Š” ๊ฒƒ์ด ๋กœ๋ณดํ‹ฑ์Šค ์—”์ง€๋‹ˆ์–ด์˜ ์—ญํ• ์ด ๋œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ๊ฒƒ์„ ์ด์ œ SymForce๊ฐ€ ์ˆ˜ํ–‰ํ•ด์ค€๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ •์˜๋œ ๋ชจ๋ธ์— ํ•ด๋‹น ๋ฐ์ดํ„ฐํฌ์ธํŠธ์—์„œ์˜ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด๋œ๋‹ค. ์ด ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด SymForce ์—์„œ .subs method ์ธ๋ฐ substitution ์„ ์˜๋ฏธํ•œ๋‹ค.
        def evaluate_error_and_jacobian(src_pt: np.ndarray, tag_pt: np.ndarray, transformation):
        # note: transformation is 6dim vector on the tangent space (i.e., [rotvec, trans])
      
            def inject_values(model):
                model_evaluated = \
                    model.subs(rotvec, sf.V3(transformation[:3])) \
                         .subs(transvec, sf.V3(transformation[3:])) \
                         .subs(p_src, sf.V3(src_pt)) \
                         .subs(p_tgt, sf.V3(tag_pt))
                return model_evaluated
      
            error = inject_values(error_model)
            Je_rot = inject_values(Je_rot_model)
            Je_trans = inject_values(Je_trans_model)
      
        return error.to_numpy(), Je_rot.to_numpy(), Je_trans.to_numpy()
      
    • ์ฐธ๊ณ ๋กœ ์—ฌ๊ธฐ์— ์“ฐ์ด๋Š” error_model, Je_rot_model, Je_trans_model ๋“ฑ์€ ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ํŽธํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
        # Model parameters (as symbolic)
        transvec = sf.V3.symbolic("t")
        rotvec   = sf.V3.symbolic("Theta") # i.e., angle-axis parametrization
        rotmat   = LieGroupOps.from_tangent(sf.Rot3, rotvec) # for debug, display(rotmat.to_rotation_matrix())
      
        # Redisual (loss function)
        #  note: the rotation 'matrix' is used to formulate the below constraint,
        #        but it was parametrized as a 3-dim vector 'rotvec'!
        p_src        = sf.V3.symbolic("p_src")     # p means a single 3D point
        p_tgt        = sf.V3.symbolic("p_tgt")
        p_tgt_est    = (rotmat * p_src) + transvec # The constraint: R*p + t == p'
      
        error_val = p_tgt_est - p_tgt
      
        def loss(error_V3):
            for i in range(3):
                error_V3[i] = sf.sqrt(error_V3[i]*error_V3[i])
            return error_V3
      
        error_model = loss(error_val)
      
        # residual jacobian
        #  this is the powerful moment of symforce. It automatically generate the Jacobian equations explicitly.
        Je_trans_model = error_model.jacobian(transvec)
        Je_rot_model = error_model.jacobian(rotvec)
      
      • V3๋“ฑ์€ 3 dimension vector ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ด๋ ‡๋“ฏ SymForce ์—์„œ ์ง€์›ํ•˜๋Š” symbolic class ๋กœ ๋ณ€์ˆ˜๋ฅผ ์ž˜ ์ด์–ด๋ถ™์—ฌ์„œ error function ์„ ์ •์˜ํ•ด์ฃผ๊ณ , ์—ฌ๊ธฐ์— .jacobian(w.r.t what) ๋ผ๊ณ ๋งŒ ํ•ด์ฃผ๋ฉด ์ค€๋น„ ๋.

๊ฒฐ๊ณผ

  • ๊ทธ๋ž˜์„œ icp ํ•จ์ˆ˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด, ๋‹ค์Œ ๊ฒฐ๊ณผ(์บก์ฒ˜)์™€ ๊ฐ™์ด ์ž„์˜๋กœ ์ฒ˜์Œ์— ๊ฐ€ํ–ˆ๋˜ transformation๊ณผ ์ตœ์ ํ™”ํ•ด์„œ ์ฐพ์€ ์˜ˆ์ธก๊ฐ’์ด ๋™์ผํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    • diff_SE3 ๊ฐ’์„ ๋‹ฌ๋ฆฌํ•ด๊ฐ€๋ฉด์„œ ์ฒดํ—˜ํ•ด๋ณด๊ธธ ๋ฐ”๋ž€๋‹ค! ๊ทธ๋ž˜๋„ ๋Š˜ ๊ฐ™์€ ๊ฐ’์„ ์ž˜ ์˜ˆ์ธกํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๊ฒฐ๋ก 

์š”์•ฝ

  1. SymForce ๋Š” ๋กœ๋ณดํ‹ฑ์Šค ๋ฌธ์ œ๋ฅผ ํ’€ ๋•Œ ํ•„์š”ํ•œ ์ž์ฝ”๋น„์•ˆ์„ ์ž˜ ์ƒ์„ฑํ•ด์ค€๋‹ค.
  2. Gauss-Newton pipeline ์„ ๊ตฌ์„ฑํ•ด๋ณผ ๋•Œ ๊ฐ€์žฅ ์• ๋จน๋Š” ๋ถ€๋ถ„์ด Jacobian ์„ ๊ตฌํ•˜๋Š” ๋ถ€๋ถ„์ธ๋ฐ, ์ด ๋ถ€๋ถ„์„ ์บก์Šํ™”ํ•˜๊ณ  ๋‚˜๋‹ˆ, nonliear update pipeline ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์ข€ ๋” ์ง‘์ค‘ํ•˜์—ฌ ์ตœ์ ํ™” ๊ณผ์ •์„ ๋” ์ž˜ ํŒŒ์•…ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.
    • ์ „์ฒด ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ (link) ์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค
    • ps. ๋ณต์žกํ•œ nonlinear cost ์˜ Jacobian ๊ตฌํ•˜๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์‹ ๊ฒฝ์“ฐ๊ฒŒ ๋˜๋Š” ๊ฒƒ์€ ์ž…๋ฌธ์ž ์ž…์žฅ์—์„œ (์ˆ˜ํ•™์ ์œผ๋กœ) ์–ด๋ ต๋‹ค. ๊ทธ๋ ‡๋‹ค๊ณ  ์ด๋ฅผ ํšŒํ”ผํ•˜๋‹ค ๋ณด๋ฉด, ๋งค๋ฒˆ ๋„ˆ๋ฌด ์‰ฌ์šด ์˜ˆ์ œ๋งŒ์„ ๋‹ค๋ฃจ๊ฒŒ ๋œ๋‹ค. ์ฆ‰ ๋กœ๋ณดํ‹ฑ์Šค ์‹ค์ „ ๋ฌธ์ œ ์ค‘ ํ•ญ์ƒ ์ผ๋ถ€๋งŒ ๋‹ค๋ฃจ๊ฒŒ ๋˜๊ฑฐ๋‚˜ 2D space ์— ํ•œ์ •๋˜๋ฏ€๋กœ ์•„์‰ฝ๋‹ค.. (e.g., 2D์—์„œ์˜ differential wheel motion ๋“ฑ).

TODO

  • ๊ณต๋ถ€์‚ผ์•„ Gauss-Newton update ๊ณผ์ •์„ ๊ตฌ์„ฑํ•ด๋ณด์•˜์ง€๋งŒ, ์•„๋งˆ optimizer ๋ผ๋Š” class ๋กœ ์ด๋Ÿฐ ๊ณผ์ •๋“ค์ด ์ด๋ฏธ wrapping ๋˜์–ด์žˆ๋Š” ๋“ฏ ํ•˜๋‹ค. SymForce ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์กฐ๊ธˆ ๋” high-level์—์„œ์˜ optim API๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž
  • Cauchy kernel ์„ ์”Œ์›Œ์„œ loss function ์„ from scratch๋กœ ๊ตฌํ˜„ํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  noisy ํ•œ correspondences pairs ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ robust kernel ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ๊ฐ•๊ฑด์„ฑ ์ฐจ์ด๋ฅผ ์‹ค์Šตํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  GncOptimizer๋„ ์‚ฌ์šฉํ•ด๋ณด์ž.
  • Automatically generated C++ code ๊ธฐ์ค€ Ceres ์™€์˜ ์†๋„์ฐจ์ด๋ฅผ ์‹ค์ œ๋กœ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž.