Ebook Robotics · RL–UAV
MODULE 3 — Estimation, Localization, Mapping, SLAM (Lecture 11–16)
Bản ôn nhanh theo module
Chế độ Slide · phím ← → · F toàn màn · Esc về đọc · S mở slide
Bản ôn nhanh theo module
📚 Học sâu:
Lectures/Lec11–16. File này = ôn nhanh.
z ≠ x │ ▼ belief ──predict──► phình ──update──► co │ ├── KF (1 Gauss) / PF (nhiều đỉnh) ├── Localization | Mapping | SLAM └── đô thị GPS kém: clearance phải theo bất định
Mục tiêu module.
Từ Module 1–2, hầu hết suy luận đều giả định ta biết state \(x\). Module này gỡ giả định đó: cảm biến chỉ cho observation \(z\) (nhiễu, thiếu), nên robot phải duy trì belief \(bel(x)\) — phân phối về “mình đang ở trạng thái nào”.
Đây là module then chốt nếu bạn làm RL–UAV muốn sim-to-real: nhiều môi trường huấn luyện “cheat” bằng cách đưa thẳng \(x\) cho policy. Máy thật không làm vậy.
Luồng module:
Lec 11 Ý tưởng filter (predict–update)
↓
Lec 12 Bayes filter (công thức chuẩn)
↓
Lec 13 Hai cách xấp xỉ: Kalman Filter & Particle Filter
↓
Lec 14 Localization (biết map → tìm pose)
Lec 15 Mapping (biết pose → xây map)
Lec 16 SLAM (không biết cả hai → giải đồng thời)
Hiểu vì sao phải dùng tập hợp / phân phối thay vì một điểm ước lượng; phân biệt hai bước predict và update.
Khi động học và đo lường đều không chắc chắn, ta “giữ kiến thức” về state như thế nào?
Bạn đi trong phòng tối. Mỗi bước chân, vị trí có thể lệch vài chục centimet. Mỗi lần sờ tường: “à, khoảng khu vực này”. Bạn không chốt một điểm tọa độ, mà giữ một vùng nghi ngờ, rồi thu hẹp dần khi có thêm bằng chứng.
Đó chính là tinh thần của mọi bộ lọc trạng thái (state filter).
bel(x_{t-1}) ──(u_t)──► bel⁻(x_t) ──(z_t)──► bel(x_t) ──► …
◯◯◯ ◯◯◯◯◯◯ ◯◯
(gọn) (phình) (co lại)
Nếu chỉ predict mãi mà không update: uncertainty tăng không Bound → robot “quên” mình đang ở đâu.
Nếu chỉ update mà không predict: bỏ qua thông tin chuyển động, phản ứng chậm và dễ mâu thuẫn giữa các phép đo.
# Vùng nghi ngờ là đoạn [lo, hi]. Bước đi + đo khoảng cách tới tường tại 0.
lo, hi = 2.0, 2.0 # biết khá chắc đang ở x=2
u, process_slack = 1.0, 0.3 # muốn đi +1, nhưng lệch tới ±0.3
lo, hi = lo + u - process_slack, hi + u + process_slack # predict: phình
print("Sau predict:", lo, hi)
# Đo: "cách tường 3.0 ± 0.4" → x ∈ [2.6, 3.4]
z_lo, z_hi = 2.6, 3.4
lo, hi = max(lo, z_lo), min(hi, z_hi) # update: giao
print("Sau update :", lo, hi)
Viết và giải thích được hai phương trình Bayes filter; phân biệt motion model và sensor model.
Vòng predict–update viết chính xác bằng xác suất như thế nào?
Bayes nói: niềm tin mới tỷ lệ với (độ khớp của phép đo) nhân với (niềm tin trước đó).
Ví dụ tìm remote: bạn nghĩ “hay để ở sofa”. Nhìn sofa không thấy → giảm tin sofa, tăng tin bàn/kệ. Mỗi quan sát chỉnh lại phân phối niềm tin — không phải nhảy cóc sang một kết luận duy nhất ngay lập tức.
Predict (Chapman–Kolmogorov):
\[
\overline{bel}(x_t)
=
\int p(x_t \mid x_{t-1}, u_t)\, bel(x_{t-1})\, dx_{t-1}
\]
Update (Bayes):
\[
bel(x_t)
=
\eta\, p(z_t \mid x_t)\, \overline{bel}(x_t)
\]
Trong đó:
- \(p(x_t \mid x_{t-1}, u_t)\): motion model — state tiến hóa thế nào khi có lệnh \(u_t\) (và nhiễu quá trình).
- \(p(z_t \mid x_t)\): sensor model / likelihood — nếu state là \(x_t\) thì xác suất thấy đo \(z_t\) là bao nhiêu.
- \(\eta\): hằng số chuẩn hóa để \(bel\) tổng/tích phân bằng 1.
Điểm then chốt: Kalman Filter, Extended KF, Unscented KF, Particle Filter… chỉ là các cách xấp xỉ hai tích phân/phép nhân trên khi không gian liên tục và mô hình phức tạp.
bel(x_{t-1})
│ nhân với motion model p(x_t | x_{t-1}, u_t), rồi tích phân
▼
bel̄(x_t) ← còn gọi bel⁻ hoặc prior belief tại t
│ nhân với likelihood p(z_t | x_t), rồi chuẩn hóa η
▼
bel(x_t) ← posterior belief tại t
import numpy as np
# Ba ô A,B,C. Prior đều.
bel = np.array([1/3, 1/3, 1/3])
# Motion: có xu hướng sang phải (cột = từ, hàng = đến; đã đơn giản hóa biên)
T = np.array([[0.2, 0.0, 0.0],
[0.8, 0.2, 0.0],
[0.0, 0.8, 1.0]])
bel_bar = T @ bel
# Đo kiểu "gần tường": A và C khớp mạnh hơn B
lik = np.array([0.9, 0.1, 0.9])
bel = lik * bel_bar
bel /= bel.sum()
print("bel sau 1 chu kỳ:", np.round(bel, 3))
Hãy chạy thêm vài chu kỳ: nếu cứ đo “tường” và chuyển động sang phải, khối tin sẽ dồn về đâu? Đó là cảm giác “filter đang hội tụ”.
Biết khi nào dùng KF/EKF, khi nào cần PF; đọc được ý nghĩa Kalman gain; nắm 3 bước PF.
Hai cách xấp xỉ \(bel(x)\) phổ biến nhất — Gaussian (KF) và đám hạt (PF) — khác nhau thế nào?
KF: ─────╱╲───── một đỉnh, elip bất định
PF: · · ● · · ● · · đám mây; resample giữ các ● nặng
\[
x_t = A x_{t-1} + B u_t + w_t, \qquad
z_t = C x_t + v_t
\]
với \(w_t \sim \mathcal{N}(0,Q)\), \(v_t \sim \mathcal{N}(0,R)\).
Predict:
\[
\hat{x}^- = A\hat{x} + Bu, \qquad
P^- = A P A^\top + Q
\]
Update:
\[
K = P^- C^\top (C P^- C^\top + R)^{-1}
\]
\[
\hat{x} = \hat{x}^- + K(z - C\hat{x}^-), \qquad
P = (I - K C) P^-
\]
Kalman gain \(K\):
- Tin đo nhiều / model kém (\(R\) nhỏ hơn tương đối) → \(K\) lớn → sửa mạnh theo \(z\).
- Tin model nhiều / đo xấu (\(R\) lớn) → \(K\) nhỏ → bám dự đoán.
Nhược điểm PF: số hạt tăng nhanh theo chiều state; dễ degeneracy (một hạt chiếm gần hết trọng số) nếu không resample / không đủ hạt.
import numpy as np
A, C, Q, R = 1.0, 1.0, 0.5, 4.0
x_true, x_hat, P = 0.0, 0.0, 10.0
rng = np.random.default_rng(0)
for t in range(8):
x_true += 1.0 + rng.normal()*0.1
z = x_true + rng.normal()*2.0
# predict
x_hat = A * x_hat
P = A * P * A + Q
# update
K = P * C / (C * P * C + R)
x_hat = x_hat + K * (z - C * x_hat)
P = (1 - K * C) * P
print(f"t={t} true={x_true:5.2f} z={z:5.2f} hat={x_hat:5.2f} P={P:4.2f}")
Quan sát: \(P\) thường giảm sau vài bước nếu cảm biến thực sự chứa thông tin; \(\hat{x}\) mượt hơn \(z\) thô.
Phát biểu bài toán localization; phân biệt tracking / global localization / kidnapped robot; hiểu MCL.
Đã có bản đồ — làm sao biết “tôi đang ở đâu trên map”?
Vào trung tâm thương mại: nhìn biển hiệu cửa hàng, đối chiếu sơ đồ, chốt “mình đang ở tầng 2 gần cầu thang”.
Localization = ước lượng pose trên map đã biết.
MCL (Monte Carlo Localization) = Particle Filter trên pose \((x,y,\theta)\) (hoặc pose 3D), với map cố định.
Ba chế độ khó tăng dần:
| Chế độ | Tình huống | Công cụ điển hình |
|---|---|---|
| Tracking | Đã biết gần đúng pose | EKF / ít hạt PF |
| Global localization | Không biết gì lúc bắt đầu | PF nhiều hạt, belief đa đỉnh |
| Kidnapped robot | Bị “teleport” / mất tracking | Cần thêm hạt ngẫu nhiên để phục hồi |
Thành phần cần có:
- Motion model: odometry / lệnh điều khiển + nhiễu.
- Sensor model: laser beam model, likelihood field, hoặc khớp đặc trưng ảnh.
- Resampling mỗi chu kỳ; thường chèn ~1% hạt ngẫu nhiên chống kidnap.
map cố định + u (odometry) + z (laser/camera)
│
▼
Particle Filter trên pose
│
▼
ước lượng (x, y, θ)
Tưởng tượng hành lang có hai chỗ giống hệt nhau: belief PF có thể có hai chùm hạt. Chỉ khi đi thêm và thấy chi tiết khác biệt, một chùm chết dần.
KF chỉ giữ một Gauss → dễ bám nhầm từ đầu. Đây là lý do global localization thích PF.
Hiểu occupancy grid và cập nhật log-odds; biết map dùng vào planning/reward thế nào.
Đã biết (gần đúng) mình đang ở đâu — làm sao xây bản đồ thế giới?
Robot hút bụi lần đầu chạy quanh nhà: vừa đi vừa tô tường, ghế, cửa. Lần sau nó đi khôn hơn vì đã có map.
Mapping = ước lượng bản đồ \(m\) khi pose được xem là biết (hoặc đủ tốt).
....####.... . free
..##....##.. # occupied
##........## (ô chưa quan sát: prior / unknown)
Map còn có dạng khác: đám landmark thưa, mesh, semantic map… — occupancy grid là điểm vào chuẩn mực.
import numpy as np
def prob_to_logodds(p):
return np.log(p / (1 - p))
def logodds_to_prob(l):
return 1 - 1 / (1 + np.exp(l))
l = prob_to_logodds(0.5) # chưa biết
for evidence in [0.7, 0.8, 0.75]: # vài lần “thấy occupied”
l += prob_to_logodds(evidence) - prob_to_logodds(0.5)
print("p(occupied) ≈", round(logodds_to_prob(l), 3))
Phát biểu bài toán SLAM; hiểu vòng lặp gà–trứng và vai trò loop closure; nắm các họ thuật toán ở mức “đủ để đọc paper”.
Không biết pose và cũng không biết map — giải đồng thời thế nào?
Lạc trong rừng không GPS: bạn vừa đánh dấu cây lạ, vừa đoán mình đã đi bao xa.
Pose sai → map vẽ sai → dùng map sai lại làm pose sai hơn. Đó là vòng gà–trứng.
SLAM (Simultaneous Localization and Mapping) siết hai thứ cùng lúc.
Khi loop closure (nhận ra “chỗ này mình đã từng qua”): có ràng buộc mạnh để sửa cả một đoạn quỹ đạo quá khứ — map hết bị trôi một phía.
Không có loop: quỹ đạo và map trôi theo nhiễu odometry tích lũy
Có loop: khép vòng ●═══● → tối ưu lại cả chuỗi pose
Họ thuật toán (chỉ cần nhớ ý tưởng):
| Họ | Ý tưởng | Điểm mạnh / yếu |
|---|---|---|
| EKF-SLAM | State = pose + toàn bộ landmark | Cổ điển; nặng \(O(n^2)\) theo số landmark |
| FastSLAM | PF trên quỹ đạo; mỗi hạt một map riêng | Xử lý đa giả thuyết tốt hơn EKF thuần |
| Graph-SLAM / pose-graph | Nút = pose; cạnh = odometry / loop; tối ưu least-squares | Chuẩn thực tế; rõ ràng khi có loop closure |
| Visual SLAM / VIO | Ảnh (+ IMU): ORB-SLAM, VINS, … | Chuẩn UAV trong nhà / GPS-denied |
Với UAV: VIO (visual–inertial odometry) thường là lớp nền; “full SLAM có map tái sử dụng” là tầng trên khi cần quay lại vùng cũ.
IMU + camera
│
▼
VIO / Visual SLAM → pose ĥ(t), map/local map
│
├──────────────► controller / tracker
└──────────────► planner hoặc obs cho RL policy
Bayes filter là xương sống. KF/PF là hai cách xấp xỉ chính.
Localization = ước lượng pose khi đã có map. Mapping = ước lượng map khi đã có pose.
SLAM = làm đồng thời cả hai, và sống nhờ loop closure.
Với RL–UAV: đừng giả vờ \(z = x\) nếu máy thật không cho phép — hãy đưa assumption này vào MDP và vào phần thí nghiệm.
Bài tiếp: 04_Vision_Learning.md — khi observation chính là ảnh.