ORB-SLAM2๋ ์ค์๊ฐ Visual SLAM์ ์ํ ์คํ์์ค ํ๋ ์์ํฌ๋ก, ๋จ์ผ ์นด๋ฉ๋ผ, ์คํ ๋ ์ค ์นด๋ฉ๋ผ, RGB-D ์นด๋ฉ๋ผ๋ฅผ ๋ชจ๋ ์ง์ํ๋ฉฐ ๋ค์๊ณผ ๊ฐ์ ์ธ ๊ฐ์ง ํต์ฌ ๋ชจ๋๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
๐ง 1. Tracking (์ถ์ )
์ค์๊ฐ์ผ๋ก ์นด๋ฉ๋ผ ์์น๋ฅผ ์ถ์ ํ๋ ๋ชจ๋
- ์ ๋ ฅ: ์ด๋ฏธ์ง ํ๋ ์
- ORB ํน์ง์ ์ถ์ถ
- ์ด์ ํ๋ ์๊ณผ์ ํน์ง์ ๋งค์นญ
- PnP or ICP ๋ฐฉ์์ผ๋ก ์นด๋ฉ๋ผ ํฌ์ฆ(6DoF) ์ถ์
- KeyFrame ์ฌ๋ถ ํ๋จ
- Relocalization ๊ธฐ๋ฅ ํฌํจ (์์น ์ถ์ ์คํจ ์ ์ฌ์ธ์ ์๋)
๐บ๏ธ 2. Local Mapping (๋ก์ปฌ ์ง๋ ์์ฑ)
ํ์ฌ KeyFrame ์ฃผ๋ณ์ ๊ตญ์์ ์ธ 3D ๋งต ์ ๋ฐ์ดํธ
- KeyFrame์ ORB ํน์ง์ ์ผ๋ก ์๋ก์ด ๋งต ํฌ์ธํธ ์์ฑ
- ๊ธฐ์กด ํฌ์ธํธ์ ์ฐ๊ฒฐํด์ Local Bundle Adjustment ์ํ
- ์ฃผ๋ณ KeyFrame๋ค๊ณผ์ ์ฐ๊ฒฐ ๊ด๊ณ(์ฝ๋น์ ๊ทธ๋ํ)๋ฅผ ์ ๋ฐ์ดํธ
โป๏ธ 3. Loop Closing (๋ฃจํ ํด๋ก์ )
๋๋ฆฌํํธ ๋์ ์ ์ค์ด๊ธฐ ์ํ ์์น ์ฌ์ธ์ ๋ฐ ์ ์ญ ๋ณด์
- ์ KeyFrame์ด ๊ณผ๊ฑฐ์ ๋ณธ ์ฅ์์ ๊ฒน์น๋์ง ํ์
- BoW (Bag of Words) ๋ฐฉ์์ผ๋ก ์ ์ฌ๋ ํ๋จ
- ๋ฃจํ๋ฅผ ๊ฐ์งํ๋ฉด Pose Graph Optimization ์ํ
- ์ ์ญ์ ์ธ Bundle Adjustment๋ก ์ ์ฒด ์ง๋ ์ ํฉ
๐งฉ ๋ฐ์ดํฐ ํ๋ฆ ์์ฝ
[์ด๋ฏธ์ง ์
๋ ฅ]
โ
[Tracking] โ KeyFrame ๊ฒฐ์ โ [Local Mapping] โ [Loop Closing]
โ
[์ค์๊ฐ ์นด๋ฉ๋ผ ์์น ์ถ์ (Pose)]
๐ Sensor Fusion (์ ํ์ฌํญ)
- ORB-SLAM2 ์์ฒด๋ IMU ๋ฏธ์ง์์ด์ง๋ง,
- ํ์ฅํ์ธ ORB-SLAM3์์๋ Visual-Inertial SLAM ์ง์๋จ (IMU + vSLAM ์ตํฉ)
๐ก ํน์ง ์์ฝ
ํญ๋ชฉ | ๋ด์ฉ |
---|---|
ํน์ง์ ๋ฐฉ์ | ORB (FAST + BRIEF) ๊ธฐ๋ฐ |
์ง๋ ๋ฐฉ์ | Sparse point map (์ ๊ธฐ๋ฐ ์ง๋) |
์นด๋ฉ๋ผ ์ง์ | Mono, Stereo, RGB-D ๋ชจ๋ ๊ฐ๋ฅ |
์ฝ๋ ๊ตฌ์กฐ | C++ + OpenCV + Pangolin (์๊ฐํ) |
์ฑ๋ฅ | ์ค์๊ฐ ๋์ ๊ฐ๋ฅ, ์ ํ๋ ๋งค์ฐ ๋์ |
๋จ์ | ์ ์กฐ๋, ๋ฐ์ฌ, ํ ์ค์ฒ ๋ถ์กฑ ํ๊ฒฝ์ ์ฝํจ |
๐งฉ A. ORB-SLAM2 + ROS ์ฐ๋
๐ฆ 1. ROS ํจํค์ง ์ค์น
cd ~/catkin_ws/src
git clone https://github.com/raulmur/ORB_SLAM2.git ORB_SLAM2
cd ORB_SLAM2
chmod +x build.sh
./build.sh
build.sh
์คํ ์ Pangolin, OpenCV ๋ฑ ์๋ ๋น๋๋ฉ๋๋ค.catkin_make
๋ก ROS ํจํค์ง ๋น๋
๐ก 2. ROS ํ ํฝ ์ฐ๊ฒฐ
ORB-SLAM2๋ sensor_msgs/Image
์ sensor_msgs/CameraInfo
๋ฅผ ๊ตฌ๋
ํฉ๋๋ค.
rosrun ORB_SLAM2 Mono PATH_TO_VOC PATH_TO_CONFIG.yaml
์์:
rosrun ORB_SLAM2 Mono Vocabulary/ORBvoc.txt Examples/Monocular/TUM1.yaml
/camera/image_raw
๋ฑ์ ํ ํฝ์์ ์ค์๊ฐ ์ด๋ฏธ์ง ์์- ORB-SLAM2๋ ๋ด๋ถ์์
geometry_msgs/PoseStamped
ํํ๋ก ์ถ์ ์์น๋ฅผ ํผ๋ธ๋ฆฌ์ํ๊ฑฐ๋, TF ๋ธ๋ก๋์บ์คํธ๋ ๊ฐ๋ฅ
๐งญ 3. ์ฐ๋๋๋ ํ ํฝ
ํ ํฝ ์ด๋ฆ | ๋ฉ์์ง ํ์ | ์ค๋ช |
---|---|---|
/camera/image_raw | sensor_msgs/Image | ์นด๋ฉ๋ผ ์์ ์ ๋ ฅ |
/camera/camera_info | sensor_msgs/CameraInfo | ์นด๋ฉ๋ผ ๋ด์ญ (์ด์ ๊ฑฐ๋ฆฌ ๋ฑ) |
/orbslam2/pose | geometry_msgs/PoseStamped | ์ถ์ ๋ ์นด๋ฉ๋ผ ์์น ์ถ๋ ฅ |
/tf | TF ๋ณํ | ์ธ๋ฆฌ์ผ ํน์ RViz์์ ์๊ฐํ |
๐ฎ B. ORB-SLAM2 + Unreal Engine ์ฐ๋
Unreal์ ROS์ ์ง์ ํต์ ํ ์๋ ์์ง๋ง, ์ค๊ฐ ๋ธ๋ฆฟ์ง๋ฅผ ํตํด ์ธ๋ถ ์์น ๋ฐ์ดํฐ๋ฅผ ์ธ๋ฆฌ์ผ์ Actor ์์น๋ก ์ ๋ฌํ ์ ์์ต๋๋ค.
๋ฐฉ๋ฒ 1: ROS โ UDP/Socket โ Unreal
๐ก 1. ORB-SLAM2 โ Pose ๋ฐ์ดํฐ๋ฅผ ์์ผ์ผ๋ก ์ ์ก (Python ์์)
import socket
import rospy
from geometry_msgs.msg import PoseStamped
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
unreal_ip = '127.0.0.1'
unreal_port = 9876
def callback(pose_msg):
x = pose_msg.pose.position.x
y = pose_msg.pose.position.y
z = pose_msg.pose.position.z
data = f"{x},{y},{z}"
sock.sendto(data.encode(), (unreal_ip, unreal_port))
rospy.init_node('orbslam2_udp_sender')
rospy.Subscriber('/orbslam2/pose', PoseStamped, callback)
rospy.spin()
๐ฎ 2. ์ธ๋ฆฌ์ผ์์ ์์ (C++ or Blueprint via UDP)
- Unreal Engine์์ UDP ๋ฆฌ์ค๋๋ฅผ ํตํด
x, y, z
๋ฐ์ดํฐ๋ฅผ ๋ฐ์ Actor ์์น ๊ฐฑ์ - ๋ธ๋ฃจํ๋ฆฐํธ ํ๋ฌ๊ทธ์ธ: UE4 UDP Receiver Plugin
๋ฐฉ๋ฒ 2: ROS Integration Plugin for Unreal
- ROSIntegration Plugin ์ฌ์ฉ
- ROS ๋ฉ์์ง๋ฅผ ์ง์ ์ธ๋ฆฌ์ผ์์ ๊ตฌ๋ ๊ฐ๋ฅ
- ์ธ๋ฆฌ์ผ Actor์ TF ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ก ๋ฐ์
โ ๏ธ ์ค์ ์ด ๋ณต์กํ๊ณ ROS ๋ฒ์ , Unreal ๋ฒ์ ํธํ์ฑ์ด ๊น๋ค๋ก์
๐ ๊ฒฐ๋ก
- ROS ์ฐ๋์ ์์ ์ ์ด๊ณ RViz ์๊ฐํ๊น์ง ๊ฐ๋ฅ โ ์ฐ๊ตฌ ๋ฐ ์ค์ฆ ํ๊ฒฝ์ ์ ํฉ
- Unreal ์ฐ๋์ UDP ๋๋ ROS ๋ธ๋ฆฌ์ง ๋ฐฉ์์ผ๋ก ๊ฐ๋ฅํ๋ฉฐ, ์ค์๊ฐ XR/AR ์์ฉ์ ์ ํฉ
- ์ค์ XR ๊ธฐ๋ฐ ์์น ์ถ์ ์ด๋ VR ๊ฒ์์์ ORB-SLAM2 ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํํ๋ ๋ฐ ์ ํฉํ ๊ตฌ์กฐ
๐ ์์ฝ ๋จผ์ : PnP vs ICP
ํญ๋ชฉ | PnP (Perspective-n-Point) | ICP (Iterative Closest Point) |
---|---|---|
์ฃผ๋ก ์ฐ๋ ๋ฐ์ดํฐ | 3D ํฌ์ธํธ โ 2D ์ด๋ฏธ์ง ์ขํ | ๋ ๊ฐ์ 3D ํฌ์ธํธ ํด๋ผ์ฐ๋ |
ํต์ฌ ๋ชฉ์ | ์นด๋ฉ๋ผ ์์น ์ถ์ (PnP + RANSAC์ผ๋ก ์ถ์ robust) | ํฌ์ธํธ ํด๋ผ์ฐ๋ ๊ฐ ์ ํฉ (๋ฑ๋ก/์ ๋ ฌ) |
๋ํ ์ฌ์ฉ์ฒ | ๋น์ฃผ์ผ SLAM (ORB-SLAM, ARKit ๋ฑ) | ๋ผ์ด๋ค ๊ธฐ๋ฐ SLAM, 3D ์ค์บ ์ ํฉ |
์ฐ์ฐ๋ | ์๋์ ์ผ๋ก ์์ | ์๋์ ์ผ๋ก ํผ |
์๊ตฌ ์กฐ๊ฑด | 3D ๋งตํฌ์ธํธ์ ์ด๋ฏธ์ง์ ํน์ง์ ๋งค์นญ ํ์ | ์ ๋ฐํ 3D ํฌ์ธํธ ํด๋ผ์ฐ๋ ํ์ |
๐ 1. PnP (Perspective-n-Point)
โ๏ธ ๋ชฉ์ :
3D ํฌ์ธํธ + 2D ์ด๋ฏธ์ง์ ๋์์ ์ด ์์ ๋,
์นด๋ฉ๋ผ์ 6DoF ํฌ์ฆ (์์น + ํ์ )๋ฅผ ์ถ์ ํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค.
โ๏ธ ์ ๋ ฅ:
- 3D ์ ๋ค (์๋ ์ขํ๊ณ ์์ ๋งตํฌ์ธํธ๋ค)
- ํด๋น ์ ์ด ์นด๋ฉ๋ผ ์ด๋ฏธ์ง์ ์ฐํ 2D ์ขํ๋ค
- ์นด๋ฉ๋ผ ๋ด๋ถ ํ๋ผ๋ฏธํฐ (์ด์ ๊ฑฐ๋ฆฌ ๋ฑ)
โ๏ธ ๋์ ๋ฐฉ์:
- ์ฌ๋ฌ ๊ฐ์ 3Dโ2D ์์ด ์์ผ๋ฉด, ์ํ์ ์ผ๋ก ์ด๋ฅผ ๋ง์กฑํ๋ ์นด๋ฉ๋ผ ์์น์ ๋ฐฉํฅ(R, t) ์ ์ญ์ผ๋ก ๊ณ์ฐ
- ๋ณดํต EPnP, RPnP, RANSAC PnP ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด์ ๋ ธ์ด์ฆ๋ ์ค๋ฅ๋ฅผ ๊ฒฌ๋ ์ ์๊ฒ ๊ฐ์
โ๏ธ ์์:
cv2.solvePnP(points_3d, points_2d, K, distCoeffs)
๐ 2. ICP (Iterative Closest Point)
โ๏ธ ๋ชฉ์ :
๋ ๊ฐ์ 3D ํฌ์ธํธ ํด๋ผ์ฐ๋๊ฐ ์์ ๋,
์๋ก ์ด๋ป๊ฒ ๊ฒน์ณ์ผ ๊ฐ์ฅ ์ ๋ง๋์ง(๋ณํํ๋ ฌ R, t)๋ฅผ ์ถ์ ํ๋ ์๊ณ ๋ฆฌ์ฆ
โ๏ธ ์ ๋ ฅ:
- ํฌ์ธํธ ํด๋ผ์ฐ๋ A (๊ธฐ์ค)
- ํฌ์ธํธ ํด๋ผ์ฐ๋ B (์ด๋ ๋์)
โ๏ธ ๋์ ๋ฐฉ์:
- B์ ๊ฐ ํฌ์ธํธ์ ๋ํด A์์ ๊ฐ์ฅ ๊ฐ๊น์ด ํฌ์ธํธ ์ฐพ๊ธฐ
- ๋์์ ์ ๊ธฐ์ค์ผ๋ก ์ต์ ์ ๋ณํ(R, t)์ ๊ณ์ฐ
- B์ ์ ์ฉํ๊ณ , ์ค์ฐจ๊ฐ ์ค์ด๋ค ๋๊น์ง ๋ฐ๋ณต
โ๏ธ ์์:
- LiDAR SLAM
- 3D ์ค์บ๋ ๋ชจ๋ธ ์ ํฉ
pcl::IterativeClosestPoint<PointT, PointT> icp;
icp.setInputSource(cloud_source);
icp.setInputTarget(cloud_target);
icp.align(cloud_aligned);
๐ฏ ์ค์ SLAM ์์คํ ์์๋ ์ด๋ป๊ฒ ์ฐ์ด๋?
์ํฉ | ์ฌ์ฉ ๋ฐฉ์ |
---|---|
ORB-SLAM, ARKit ๋ฑ ๋น์ฃผ์ผ SLAM | PnP ์ฌ์ฉ |
LiDAR ๊ธฐ๋ฐ SLAM (e.g., Cartographer, LOAM) | ICP ์ฌ์ฉ |
RGB-D SLAM | PnP + Depth or ICP ํผ์ฉ ๊ฐ๋ฅ |
โ ํ์ค ์ ๋ฆฌ
- PnP๋ “2D ์ด๋ฏธ์ง์์ ๋ณด๊ณ ์๋ 3D ํฌ์ธํธ๋ก๋ถํฐ ์นด๋ฉ๋ผ ์์น๋ฅผ ์ ์ถ”
- ICP๋ “๋ ๊ฐ์ 3D ์ ๊ตฌ๋ฆ์ ์ ๋ ฌํด์ ์๋ ์์น๋ฅผ ๊ณ์ฐ”
๋ ๋ค SLAM, AR, 3D ์ฌ๊ตฌ์ฑ์์ ํต์ฌ์ ์ธ ์์น ์ถ์ ๋๊ตฌ์ ๋๋ค.
์ด์ PnP (Perspective-n-Point) ์๊ณ ๋ฆฌ์ฆ์ ์ํ์ ์ ๋๋ฅผ ์ฐจ๊ทผ์ฐจ๊ทผ ์ค๋ช
๋๋ฆด๊ฒ์.
๋ค์ ์ํ์ ์ธ ๋ด์ฉ์ด์ง๋ง, ํต์ฌ์ 2D ์ด๋ฏธ์ง์ ๋ณด์ด๋ ์ ์ด ์ค์ 3D ๊ณต๊ฐ์ ์ด๋ ์์น์ ๋์ํ๋์ง๋ฅผ ํตํด ์นด๋ฉ๋ผ์ ์์น์ ์์ธ(R, t)๋ฅผ ์ถ์ ํ๋ ๊ฒ์
๋๋ค.
๐ ๋ฌธ์ ์ ์: PnP๋?
N๊ฐ์ 3D ํฌ์ธํธ XiโR3\mathbf{X}_i \in \mathbb{R}^3 ์
๊ทธ์ ๋์ํ๋ ์ด๋ฏธ์ง ๋ด 2D ํฌ์ธํธ xiโR2\mathbf{x}_i \in \mathbb{R}^2 ๊ฐ ์ฃผ์ด์ก์ ๋,
์นด๋ฉ๋ผ์ ํ์ ํ๋ ฌ RโSO(3)\mathbf{R} \in SO(3) ๊ณผ ์ด๋ ๋ฒกํฐ tโR3\mathbf{t} \in \mathbb{R}^3 ๋ฅผ ๊ตฌํ๋ ๋ฌธ์
๐ง 1. ์นด๋ฉ๋ผ ํฌ์ ๋ชจ๋ธ
๐ ์๋์ขํ โ ์นด๋ฉ๋ผ์ขํ
Xc=Rโ Xw+t\mathbf{X}_c = \mathbf{R} \cdot \mathbf{X}_w + \mathbf{t}
๐ ์นด๋ฉ๋ผ์ขํ โ ์ด๋ฏธ์ง์ขํ
xi=Kโ [Rโฃt]โ [Xw1]\mathbf{x}_i = \mathbf{K} \cdot [\mathbf{R} | \mathbf{t}] \cdot \begin{bmatrix} \mathbf{X}_w \\ 1 \end{bmatrix}
์ฌ๊ธฐ์:
- xi=(ui,vi,1)T\mathbf{x}_i = (u_i, v_i, 1)^T: ์ด๋ฏธ์ง์ homogeneous ์ขํ
- K\mathbf{K}: ์นด๋ฉ๋ผ ๋ด๋ถ ํ๋ผ๋ฏธํฐ ํ๋ ฌ
K=[fx0cx0fycy001]\mathbf{K} = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix}
๐ฏ 2. ์ต์ ์กฐ๊ฑด
- ์ต์ 3์ ์ด์ ํ์ (Perspective-3-Point)
- ์ค์ ๋ก๋ 4์ ์ด์์ผ๋ก ๊ณผ์ ๊ฒฐ์ (overdetermined) โ ์ต์์์น๋ฒ (Least Squares) ์ฌ์ฉ
๐ 3. ๋น์ ํ ์ต์ ํ ๋ฌธ์ ๋ก ์ ์
minโกR,tโi=1Nโฅxiโฯ(Rโ Xi+t)โฅ2\min_{\mathbf{R}, \mathbf{t}} \sum_{i=1}^{N} \left\| \mathbf{x}_i – \pi(\mathbf{R} \cdot \mathbf{X}_i + \mathbf{t}) \right\|^2
- ฯ(โ )\pi(\cdot): 3D โ 2D ํ๋ก์ ์ ํจ์ (์นด๋ฉ๋ผ ๋ด๋ถ ํ๋ผ๋ฏธํฐ ํฌํจ)
ฯ(Xc)=[fxโ XcZc+cxfyโ YcZc+cy]\pi(\mathbf{X}_c) = \begin{bmatrix} f_x \cdot \frac{X_c}{Z_c} + c_x \\ f_y \cdot \frac{Y_c}{Z_c} + c_y \end{bmatrix}
- ์ด ์์ ๋น์ ํ์ด๋ฏ๋ก Levenberg-Marquardt ์ต์ ํ ๋๋ EPnP ์๊ณ ๋ฆฌ์ฆ ๊ฐ์ ๊ทผ์ฌ ๊ธฐ๋ฒ ์ฌ์ฉ
๐ง 4. RANSAC PnP
์ค์ ํ๊ฒฝ์์๋ ๋งค์นญ๋ ์ ์ค ์ผ๋ถ๊ฐ **์ค๋ฅ(outlier)**์ผ ์ ์๊ธฐ ๋๋ฌธ์,
PnP๋ ๋ณดํต RANSAC๊ณผ ํจ๊ป ์ฌ์ฉํฉ๋๋ค:
- 4~6๊ฐ์ ๋๋ค ๋์์ ์ ํ
- PnP๋ก R, t ๊ณ์ฐ
- ๋๋จธ์ง ์ ์ ๋ํด reprojection error ๊ณ์ฐ
- ์ค์ฐจ๊ฐ ์์ ์ ๋ค(inliers)์ ๊ฐ์๋ก ๋ชจ๋ธ ํ๊ฐ
- ์ฌ๋ฌ ๋ฐ๋ณต ์ค ๊ฐ์ฅ ์ข์ ๋ชจ๋ธ ์ ํ
โ ์์ฝ ์ ๋ฆฌ
๋จ๊ณ | ์ค๋ช |
---|---|
1. | 3D โ 2D ๋์์ ํ๋ณด |
2. | ํฌ์ ๋ชจ๋ธ ์์์ผ๋ก ์์น(R, t) ์ถ์ |
3. | ๋น์ ํ ์ต์ ํ๋ก ์ค์ฐจ ์ต์ํ |
4. | RANSAC๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด outlier์ ๊ฐ์ธํจ |
๋ต๊ธ ๋จ๊ธฐ๊ธฐ