見出し画像

Isaac Simで学ぶ、いちばん簡単なロボットのピッキング — 座標既知&自作IKで動かす

🤖 はじめに:この記事で作るもの

固定した場所に置いた赤いキューブを、ロボットアームがつかんで別の場所へ置く——それを延々と往復し続けるデモを、Isaac Sim 上で作ります。

ポイントは「カメラも機械学習も使わない」こと。キューブの位置は最初から座標で分かっている(既知)前提にして、ロボットを動かす一番の土台=逆運動学(IK)と状態機械だけに絞ります。派手さはありませんが、「アームを狙った座標へ動かす」という物理AIの最初の一歩を、ブラックボックスなしで自分の手で書けるようになります。

使うもの:

  • FANUC CRX-20iA/L(協働ロボットアーム)

  • Robotiq 2F-85(2本指グリッパー)

  • NVIDIA Isaac Sim 6.0.1

🎯 全体設計:7つの「フェーズ」で考える

ピッキングは、要するに手順の連続です。
人間なら無意識にやる動きを、
ロボットには段階(フェーズ)に分けて教えます。

この「今どのフェーズか」を管理する仕組みが 状態機械(ステートマシン) です。各フェーズには「表示名・グリッパーを閉じるか・タイムアウト」を持たせ、目標に到達したら次のフェーズへ進みます。

class Phase(IntEnum):
    APPROACH_ABOVE = 0  # 上空へ移動
    DESCEND = 1         # 下降して接近
    GRASP = 2           # 把持
    LIFT = 3            # 持ち上げ
    TRANSPORT = 4       # 置き先へ搬送
    PLACE_DOWN = 5      # 下降して設置(保持したまま)
    RELEASE = 6         # 離す

✍️ 設計のコツ:「下降」と「離す」を分けているのがミソ。ひとつのフェーズで“降ろしながら開く”にすると、着地前に手を離してキューブを落とします。降ろしきってから離す——現実と同じ順番にするのが安定の秘訣です。


🧮 心臓部:逆運動学(IK)をどう解くか

「手先を座標 (x, y, z) へ動かしたい」。でもロボットが直接コントロールできるのは各関節の角度です。この「行きたい場所 → 関節角度」の変換が逆運動学(IK)

この記事では、Isaac Sim の便利機能に頼らず、
ヤコビアン+減衰最小二乗法(DLS)
という王道アルゴリズムを自分で書きます。
中身は4ステップ:

① 誤差を作る … 今の手先位置と目標の差(位置3+姿勢3の6次元)
② ヤコビアンを取る … 「関節を動かすと手先がどう動くか」の対応表 J
③ 逆算する … dq = Jᵀ (J Jᵀ + λ²I)⁻¹ e で「誤差を減らす関節変化」を求める ④ 安全に丸める … 1ステップで動きすぎないよう上限でクリップ

λ²I(ダンピング項)を足すのがポイントで、これがあるおかげで特異点(腕が伸びきった姿勢など)でも計算が発散せず、なめらかに動きます。

# 減衰最小二乗解 dq = Jᵀ (J Jᵀ + λ²I)⁻¹ e
damping = np.eye(6) * (cfg.damping ** 2)
dq = task_jac.T @ np.linalg.solve(task_jac @ task_jac.T + damping, task_err)

この式そのものを「なぜこうなるのか」まで理解するには線形代数とロボット工学の知識が要ります。まずは「誤差を入れると関節の動かし方が返ってくる魔法の関数」と捉えてOK。動かしながら少しずつ中身に踏み込むのがおすすめです。

地味だけど効く工夫:ヤコビアンの「基準点ずらし」

ヤコビアンが得られるリンク(ik_link)と、実際につかみたい点(grip_frame、指の付け根)は少しズレています。剛体の運動 v_grip = v_link + ω × r を使い、そのズレ r の分だけ基準点を補正しています(コード中の skew 補正)。ここを省くと、狙いが微妙にズレます。


🌀 なめらかに動かす:追従点をちょっとずつ進める

IK にいきなり最終目標を渡すと、腕が急発進してカクつきます。そこで setpoint(追従点) を用意し、毎フレーム目標へ少しずつ近づけながら IK を解きます。人が指で目標をなぞるように動かすイメージです。

to = target - self.setpoint
dist = np.linalg.norm(to)
if dist > speed:
    self.setpoint = self.setpoint + to / dist * speed  # 少しだけ前進
else:
    self.setpoint = target.copy()
self.ik.solve(self.setpoint)

♻️ 無限ループさせる:置き場所を入れ替える

1回置いて終わりだと寂しいので、ずっと往復し続けるようにします。

ここで一工夫。単純に最初のフェーズへ戻すだけだと、「置いた場所からまた拾って、同じ場所に置く=動かない」になってしまいます。そこで拾い先と置き先を毎サイクル入れ替えて、A地点→B地点→A地点…と往復させます。拾う位置はキューブの実座標を毎回読むので、置いた場所を自動で拾いに行きます。

self._place_idx ^= 1   # 0↔1 を交互にトグル
self.phase = Phase.APPROACH_ABOVE

🛠️ 設定を一箇所にまとめる

つかむ場所・置く場所・IKのゲインなどは、dataclass で種類ごとにまとめています。「この数字を変えると挙動が変わる」が一目で分かるのが狙いです。

@dataclass(frozen=True)
class SceneConfig:
    cube_size: float = 0.06
    cube_position = np.array([0.72, 0.0, 0.03])   # つかむ場所
    place_position = np.array([0.50, 0.32, 0.03]) # 置く場所
    above_height: float = 0.30                    # 上空へ逃がす高さ

まず遊ぶなら cube_position / place_position を書き換えるのが一番わかりやすいです。


▶️ 動かし方

# Windows
C:\isaacsim\python.bat ".\simple_picking.py"
# Linux
/home/dev/isaacsim/python.sh "./simple_picking.py"

🚀 つまずきポイント & 次の一歩

うまくいかない時のチェック

  • 腕が目標に届かない → above_height を下げる、cube_position をロボットに近づける

  • つかむ前に落とす → フェーズ5と6が分かれているか確認

  • 動きがカクつく → setpoint_speed を小さく

  • 急に暴れる → max_joint_delta(1ステップの関節変化上限)を小さく

発展のアイデア

  • 📷 カメラを足して、座標既知 → 物体検出でつかむ

  • 🧠 IK を強化学習ポリシーに置き換える

  • 📦 キューブを増やして順番にピッキング


おわりに

「アームを狙った座標へ動かす」——物理AIの一番の土台を、ライブラリのブラックボックスに頼らず自分で書けました。ここが分かると、カメラや学習を足したときに「どこがどう効いているか」が見えるようになります。

コード全文はこちら 👉コードはこちら


フィジカルAI・工場向けAI開発のご相談

私は製造業向けのAIシステム開発を行っています。
こんなお悩みはありませんか?

* 外観検査を自動化したい
* 作業監視をAI化したい
* PPE(保護具)着用チェックを導入したい
* ロボットアームへAIを組み込みたい
* ROS2・Isaac Simを活用したい
* フィジカルAIのPoCを進めたい
* 社内向けAIツールを開発したい
* Isaac simを使ってロボット操作したい

要件整理からPoC、実装まで対応可能です。
まずはお気軽にご相談ください。

お問い合わせ
https://forms.gle/qTxgVfBF622eiBWA6

技術ポートフォリオ
GitHub

Hugging Face

note


いいなと思ったら応援しよう!

FCTX 無料で気軽に使えるアプリを個人で開発しています! いただいたチップは、アプリの改善や開発環境の維持に大切に使わせていただきます。 応援していただけると、とても励みになります!