資料
ダウンロード
Technology > 床の模様だけで、地図と自己位置を ― 下向きカメラ1台のSLAM「slam_tenchi」

床の模様だけで、地図と自己位置を ― 下向きカメラ1台のSLAM「slam_tenchi」

ロボットが「いま自分がどこにいるか」を知る方法はいくつもありますが、多くは専用センサや、床・天井にマーカを敷き詰める準備を必要とします。

slam_tenchi は、そうした準備なしに、床の“模様”そのものを手がかりにします。下向きカメラ1台で床を撮り、同じ座標系で地図(MAPPING)と自己位置(LOCALIZATION)を出す ― それが「床SLAM」です。尺度はカメラ高さ(0.35m)が既知なので、得られるのは実寸の SE2 姿勢(x, y, yaw)です。

紹介映像

※ Gazebo での床SLAM(地図作成と自己位置推定)の様子をまとめた技術紹介映像です。

何をするか

対象は、屋内の有限な床です。下向きカメラが床を捉え、その模様(タイル・傷・テクスチャ)を特徴として使います。尺度(実寸)はカメラの取り付け高さ 0.35m が既知であることから確定するので、ピクセルではなくメートル単位の位置が出せます。

出力は SE2 姿勢、すなわち平面上の x, y, yaw の3自由度です。地図も自己位置も同じ座標系で表されるため、「作った地図の上で、いま自分がどこにいるか」を一貫して扱えます。

処理の流れ

床の画像から姿勢を得るまでは、一続きのパイプラインです。

処理の流れ。床画像(640x480 BGR)→ SuperPoint(特徴+記述子)→ LightGlue(対応付け)→ MAPPING(ホモグラフィVO+キーフレーム地図)/LOCALIZE(毎フレーム地図照合)→ SE2姿勢(x, y, yaw)
床画像 → SuperPoint(特徴点と記述子)→ LightGlue(対応付け)→ MAPPING / LOCALIZE → SE2 姿勢。フレーム間の対応からホモグラフィを推定して動きを求める、ビジュアルオドメトリ(VO)が土台です。(クリックで拡大)

床は平面なので、2枚の画像の対応関係はホモグラフィで表せます。ここから移動量を復元し、キーフレーム(画像+特徴+SE2姿勢)をつないで地図を作っていきます。

2つのモード ― 地図作成と自己位置

slam_tenchi は、役割の違う2つのモードを持ちます。

  • MAPPING(地図作成) ― フレーム間VOで動きを積み、一定の移動(0.3m / 12°)ごとにキーフレームを追加。ループ検出とマーカ制約で pose graph を最適化し、地図として保存します。
  • LOCALIZATION(自己位置) ― 大域探索で初期化し、以降は近傍キーフレームで追跡。複数キーフレームを最小二乗で照合します。

ここが要点です。自己位置は「一度合わせて積算する」のではなく、毎フレーム地図に照合します。 だからオドメトリのようなドリフトが積み上がりません。うまく解けないフレームは無理に推測せず、未解決として扱います。

カメラが見ているもの

実際の入力は、下向きカメラに写る床です。

Gazeboの下向きカメラが捉えた床模様。MAPPING入力・LOCALIZATION入力・走行中(Ground Truthと推定の重畳)の3例。床模様がパース付きで写っている
Gazebo の下向きカメラ。床の模様がパース付きで写ります。左から MAPPING 入力・LOCALIZATION 入力・走行中(真値と推定の重畳)。特別なランドマークではなく、床そのものの模様が手がかりです。(クリックで拡大)

軌跡の読み方

評価では、地図作成時の軌跡と自己位置推定時の軌跡を並べて見ます。

軌跡の読み方。左が地図作成(MAPPING)の軌跡、右が自己位置(LOCALIZATION)の軌跡。内側と外側のずれは、評価軌道を+0.125mずらしているため(失敗ではない)
左が地図作成、右が自己位置の軌跡。内側と外側がずれているのは失敗ではありません ― 評価用の走行軌道を、地図作成時から +0.125m 平行移動させているためです(別の経路でも地図の上で正しく自己位置が出るか、を確かめる意図)。(クリックで拡大)

マーカとのハイブリッド

床模様だけでも動きますが、より高い絶対精度が要るときのために、マーカとのハイブリッドも用意しています。

  • レイアウトがあるときだけ ― マーカ配置図(markers.yaml:ID / family / x, y, yaw)を渡したときに有効化。
  • 検出フレームは絶対姿勢を優先 ― マーカが見えたフレームは、その絶対姿勢を優先して使います。地図作成時は見えたマーカを記録し(found_markers.json)、自己位置推定時は姿勢と見えているIDを同時に返します。
  • 無ければ床模様だけ ― マーカが無い環境では、これまで通り床の模様だけで動きます。
  • 推測しない設計 ― マーカを検出したのに誤差(RMSE)が閾値を超えた場合は、無理に値を返さず例外で停止します。「それらしい嘘」を出さないための安全側の設計です。

合成マーカでの絶対姿勢は 0.18mm で PASS しています。

数字で見る正しさ

精度は、閾値がcmオーダーのところ、実測はmmで収まっています。

数字で見る正しさ。Gazebo地図 4.5mm(vs GT PASS)、Gazebo自己位置 6.1mm(未解決0% PASS)、処理時間 62ms(CUDA・自己位置中央値)。実測は閾値(50-100mm)より1桁小さい
Gazebo 評価。地図 4.5mm(対 真値)、自己位置 6.1mm(未解決 0%)、処理時間 62ms/frame(CUDA・中央値)。実測は許容閾値(50〜100mm)より1桁小さい水準です。(クリックで拡大)
指標 実測 判定
Gazebo 地図(対 真値) 4.5mm PASS
Gazebo 自己位置 6.1mm(未解決 0%) PASS
合成マーカ 絶対姿勢 0.18mm PASS
処理時間(CUDA・中央値) 62ms/frame ―

Python から呼ぶ

導入はエディタブルインストール、呼び出しは数行です。

pip install -e .

from floor_slam import FloorSlam, list_image_paths
import cv2

# 地図をつくる
with FloorSlam.mapping(config_path="config/default.yaml") as slam:
    for p in list_image_paths("frames"):
        fr = slam.process(cv2.imread(str(p)))
        print(fr.pose.x, fr.pose.y, fr.pose.yaw, fr.source)
    slam.finalize_map("datasets/maps/my_scene")

# 作った地図で自己位置を出す
slam = FloorSlam.load_map("datasets/maps/gazebo_floor_v1")
fr, ms = slam.process_with_timing(bgr)   # SE2姿勢 + 処理時間(ms)

マーカ配置図を使うときは、FloorSlam.mapping(marker_layout="markers.yaml") のように渡すだけです。

まとめ

  • 床模様 1枚で、地図と自己位置 ― 下向きカメラ1台。専用マーカの敷設は不要。
  • MAPPING ― ホモグラフィ VO でキーフレーム地図を作る。
  • LOCALIZATION ― 毎フレーム地図に照合。積算しないからドリフトが溜まらない。
  • マーカがあれば絶対姿勢を優先、無ければ模様だけ。推測せず、危ういときは止まる。
  • Gazebo で 地図 4.5mm / 自己位置 6.1mm、CUDA 62ms/frame。Pythonから数行で。

床SLAM「slam_tenchi」について、デモやご相談を承っています。

この技術や導入について、お気軽にご相談ください。

お問い合わせ・ご相談はこちら
一覧に戻る

Contact

自社のロボット、現場、データにどう使えるか。まずは相談から

既存ロボットへの知性付与、ローカルAI導入、移動AI、ヒューマノイド制御、行動ログの記録まで。製品選定とPoCの組み立てを、Forcesteed Robotics が支援します。