はじめに
PyBullet (Python上で動く物理シミュレータ) を使用して,ロボットアームを可視化して,動かしたい.
前記事では,エージェントの学習方法として "モンテカルロ法" を採用して,PyBullet 内の2軸ロボットアームの強化学習を実装した.
前記事の問題点は,モンテカルロ法が "1エピソード完了後にのみQ値を更新" するため,学習が遅い点である.
本記事では,エージェントの学習方法として "SARSA (TD学習)" を採用する.SARSAは "1ステップごとにQ値を更新" するため,モンテカルロ法よりも学習が速くなる.
グリッパー付きの2軸ロボットアームを使用して,干渉物が存在しない環境下にて,複数のカメラから把持物体の位置を取得して,物体を把持する(下図はPyBullet上のグリッパー付き2軸ロボットアームである).赤枠がグリッパー,緑枠が把持したい物体,青枠がカメラ,青色の球が初期位置である.

本記事を実施してできる最終的なものは下記動画の通りである.エージェントの学習方法は "SARSA" である.
下記は,学習中の強化学習による経路生成の動画である.
下記は,学習後の強化学習による経路生成の動画である.
本記事で実装すること
- エージェントの学習方法は"SARSA"
本記事では実装できないこと (将来実装したい内容)
エージェントの学習手法
- Q学習
- DQN
- Actor-Critic
動作環境
- macOS Sequoia (バージョン15.5)
- Python3 (3.13.3)
- PyBullet (3.25) (物理シミュレータ)
- Numpy (2.3.0) (数値計算用ライブラリ)
PyBullet のインストール方法
PyBullet のインストール方法については下記にて,説明したため,割愛する.
PyBulletの使用方法
Pythonの物理シミュレータであるPyBulletの使用方法について説明する.
下記リンクのPyBullet公式で調べながら,PyBulletを使用している.
上記リンクを開くと,下図のようなサイトに飛ぶ.使用方法を調べるときは,下図の赤枠内の「PYBULLET QUICKSTART GUIDE」タグをクリックする.

「PYBULLET QUICKSTART GUIDE」タグをクリックすると,下図のようなドキュメントを見ることができる.基本的には,ドキュメントに記載されている関数の使用方法を見て,ソースコードを作成している.

PyBulletの関数の引数や戻り値をもっと知りたいのでしたら,上記ドキュメントを見た方がわかりやすいです.
2軸ロボットアームの定義
2軸ロボットアームの定義については下記にて,説明したため,割愛する.
グリッパーの定義
グリッパーの定義については下記にて,説明したため,割愛する.
グリッパー付き2軸ロボットアームのURDF作成
グリッパー付き2軸ロボットアームのURDF作成については下記にて,説明したため,割愛する.
URDFに関しては,下記にて説明したため,割愛する.
カメラによる把持物体の2次元位置を取得
PyBulletでカメラ情報を取得する方法については下記にて,説明したため,割愛する.
強化学習に関して
強化学習は機械学習の一つの種類である.強化学習とは,自分で試行錯誤をしてデータを集め,詰めたデータから良い行動を学習することである.
強化学習のイメージは下図の通りである.
1:「環境」から「エージェント」に対して,「状態」を渡す
2:「エージェント」が「状態」より,「行動」を選択する
3:「エージェント」から「環境」に対して,「行動」を実行する
4:「環境」が「行動」より,「状態」を更新する
5:「環境」から「エージェント」に対して,「報酬」を渡す
6:「エージェント」が「報酬」より,「学習」する
ここで,用語の定義をする.
| 用語 | 用語の定義 |
|---|---|
| エージェント | 行動の主体者 |
| 環境 | エージェントと相互作用を行う対象 |
| 状態 | エージェントの行動によって置かれるエージェントの状況 |
| 行動 | エージェントが起こすアクション |
| 報酬 | エージェントの行動に対する環境からのフィードバック |
本記事での "環境" は "PuBullet上のロボットと環境" である."エージェント" は "ロボットを動かすための頭脳" である.
以下では,本記事で使用する "環境" と "エージェント" を説明していく.
強化学習の環境に関して
強化学習の環境に関しては下記にて,説明したため本記事では割愛する.
強化学習のエージェントに関して
強化学習のエージェントに関して説明する.強化学習の全体像の中で,下図の赤枠で囲んだ「エージェント」を説明する.
エージェントは,環境から「状態」を受け取り,「行動」を行い,「報酬」を得て,次の「状態」へ遷移する.下記のように1エピソードが完了するまで,「状態(S)」,「行動(A)」,「報酬(R)」,「状態(S)」のループとなる.
$S_{0}, A_{0}, R_{0}, S_{1}, A_{1}, R_{1}, ...$
行動価値関数に関して
行動価値関数については下記にて,説明したため本記事では割愛する.
SARSA (TD学習) に関して
エージェントの学習方法の一種である "SARSA" に関して説明する.
SARSAとは,"State-Action-Reward-State-Action" の頭文字を取った名称である.Q値の更新に使用する5つの要素 $(s_t, a_t, r_t, s_{t+1}, a_{t+1})$ から名付けられており,更新式は以下の通りである.
\displaylines{
Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_t + \gamma Q(s_{t+1}, a_{t+1}) - Q(s_t, a_t) \right] \\
\\
文字の意味は以下の通り.\\
Q ... \text{行動価値関数},\; \alpha ... \text{学習率},\; \gamma ... \text{割引率} \\
s_t ... \text{時刻}t\text{の状態},\; a_t ... \text{時刻}t\text{の行動},\; r_t ... \text{時刻}t\text{の報酬} \\
s_{t+1} ... \text{次の状態},\; a_{t+1} ... \text{次の行動}
}
SARSAは "TD学習 (Temporal Difference Learning)" の一種である.TD学習とは,"1ステップ後の情報を使って価値関数をブートストラップ更新する手法" の総称である.
モンテカルロ法では,更新に収益 $G_t = R_t + \gamma R_{t+1} + \gamma^2 R_{t+2} + \cdots$ (エピソード全体の報酬列) が必要なため,1エピソードが完了するまで更新できない.
SARSAでは,収益 $G_t$ の代わりに "次のQ値" $Q(s_{t+1}, a_{t+1})$ を使うことで,エピソード完了を待たずに1ステップごとにQ値を更新できる.
モンテカルロ法とSARSAの比較を下表にまとめた.
| 比較項目 | モンテカルロ法 | SARSA |
|---|---|---|
| 更新タイミング | 1エピソード完了後 | 1ステップごと |
| 更新に必要な情報 | エピソード全体の報酬列 | $(s_t, a_t, r_t, s_{t+1}, a_{t+1})$ |
| 収束速度 | 遅い | 速い |
| 方策の種類 | on-policy | on-policy |
| エピソード終了条件 | 必須 | 不要 |
SARSAは "on-policy" の学習手法である.on-policyとは,"行動の選択に使う方策と,Q値の更新に使う方策が同一である" ことを意味する.具体的には,次の行動 $a_{t+1}$ が "同じ ε-greedy 方策" によって選択されるため,on-policyとなる.
SARSAの学習フローを以下に示す.
1:初期状態 $s_0$ を取得して,ε-greedy方策で最初の行動 $a_0$ を選択する
2:行動 $a_t$ を実行して,報酬 $r_t$ と次の状態 $s_{t+1}$ を得る
3:同じ ε-greedy方策で次の行動 $a_{t+1}$ を選択する
4:$Q(s_t, a_t)$ を更新式で更新する
5:$s_t \leftarrow s_{t+1}$,$a_t \leftarrow a_{t+1}$ として2に戻る
ポイントは,"ループ前に最初の行動を選択する" 点である.モンテカルロ法では,ループ内で行動を選択した後にステップを実行していたが,SARSAでは次の行動 $a_{t+1}$ もループ内で選択する必要があるため,最初の行動 $a_0$ はループ開始前に選択する必要がある.
SARSAの更新式の意味を分解すると下式の通りとなる.
\displaylines{
Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_t + \gamma Q(s_{t+1}, a_{t+1}) - Q(s_t, a_t) \right] \\
\\
\underbrace{r_t + \gamma Q(s_{t+1}, a_{t+1})}_{\text{TD目標値 (1ステップ先の見積もり)}} - \underbrace{Q(s_t, a_t)}_{\text{現在の推定値}} = \underbrace{\delta_t}_{\text{TD誤差}} \\
\\
Q値の更新 = Q値 + \alpha * TD誤差 \\
TD誤差が正なら Q値を増やす(現在の推定より良い状態だった)\\
TD誤差が負なら Q値を減らす(現在の推定より悪い状態だった)
}
このTD誤差 $\delta_t$ を使って,Q値を少しずつ更新することで,学習が進む仕組みである.
行動の選択方法 (ε-greedy法)
行動の選択方法 (ε-greedy法) に関しては下記にて,説明したため本記事では割愛する.
ソースコード一覧
本記事で使用する全ソースコードの一覧を下表にまとめる.フォルダ名が記載されているものは,そのフォルダを作成して,フォルダ内にファイルを保存してください.
URDFファイル
| ファイル名 | 概要 |
|---|---|
camera_back_to_front.urdf |
手前方向(-Y方向)を向いているカメラの定義 |
camera_front_to_back.urdf |
奥行き方向(+Y方向)を向いているカメラの定義 |
camera_left_to_right.urdf |
右方向(+X方向)を向いているカメラの定義 |
camera_right_to_left.urdf |
左方向(-X方向)を向いているカメラの定義 |
camera_up_to_down.urdf |
下方向(-Z方向)を向いているカメラの定義 |
grasp_object.urdf |
把持物体の定義 |
robot_2dof.urdf |
グリッパーなし2軸ロボットアームの定義 |
environment_2dof.urdf |
2軸ロボットアームの環境を定義 |
robot_2dof_hand.urdf |
グリッパー付き2軸ロボットアームの定義 |
Pythonファイル
| ファイル名 | 概要 |
|---|---|
constant.py |
定数の定義 (SARSA追加) |
main.py |
全体的なメイン処理 |
pybullet_grasp.py |
PyBulletの把持物体 |
pybullet_gripper.py |
PyBulletのグリッパー |
pybullet_robot.py |
PyBulletのロボット |
pybullet_camera.py |
PyBulletのカメラ |
pybullet_agent_controller.py |
PyBulletのエージェント制御 (SARSA対応) |
BaseAgent.py |
PyBulletのエージェントの抽象クラス |
RandomAgent.py |
PyBulletのランダムに動くエージェント |
MonteCarloAgent.py |
PyBulletのモンテカルロ法で学習するエージェント |
SarsaAgent.py |
PyBulletのSARSAで学習するエージェント |
pybullet_environment_controller.py |
PyBulletの強化学習用の環境制御 |
BaseEnvironment.py |
PyBulletの強化学習用の環境の抽象クラス |
DiscretizeEnvironment.py |
PyBulletの強化学習用の離散値環境 |
pybullet_main.py |
PyBulletのメイン処理 (SARSAループ) |
pybullet_main.py の変更点に関して
pybullet_main.py の __learning() メソッドをSARSA用に変更した点について説明する.
モンテカルロ法とSARSAの学習ループの違いを下表にまとめた.
| 比較項目 | モンテカルロ法 (part2) | SARSA (part3) |
|---|---|---|
| 最初の行動選択 | whileループ内 | ループ前に選択 |
add() の呼び出し |
add(s, a, r) |
add(s, a, r, s', a') |
| Q値の更新タイミング | エピソード終了後の update()
|
ステップごとの add() 内 |
update() の役割 |
Q値更新 + ε更新 | ε更新のみ |
最初の行動をループ前に選択する理由は,SARSAでは "1ステップの実行前後で必ず行動が必要" なためである.具体的には,step(action) の前後に行動が必要となる.step() を呼ぶ前に $a_t$,step() を呼んだ後に $a_{t+1}$ が必要であり,ループ内で step() を最初に呼ぶためには,最初の $a_0$ はループ前に選択しておく必要がある.
SARSAの __learning() の主要部分を抜粋すると以下の通りとなる.
# SARSAは最初の行動をループ前に選択する (s, a, r, s', a' の a に相当)
action = self.__agent.get_action(state)
while not done:
# 1ステップ実行: (s, a) → (s', r, done)
next_state, reward, done = self.__env.step(action)
# 次の行動を選択 (on-policy: 同じε-greedy方策で選択)
next_action = self.__agent.get_action(next_state)
# Q値を即時更新: Q(s,a) ← Q(s,a) + α[r + γQ(s',a') - Q(s,a)]
self.__agent.add(state, action, reward, next_state, next_action)
# 状態と行動の更新 (s ← s', a ← a')
state = next_state
action = next_action
# エピソード終了: 探索確率 ε の更新 (Q値更新はadd()内で完了済み)
self.__agent.update()
SarsaAgent.py の実装に関して
SarsaAgent.py では,モンテカルロ法 (MonteCarloAgent.py) と比較して,以下の点が異なる.
add() メソッドの引数変更
モンテカルロ法では add(state, action, reward) だったが,SARSAでは (s, a, r, s', a') の5要素が必要なため,add(state, action, reward, next_state, next_action) に変更した.また,モンテカルロ法では add() でメモリにデータを蓄積してエピソード終了後にまとめて更新するのに対して,SARSAでは add() の中でQ値を即時更新する.
\displaylines{
Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ \underbrace{r_t + \gamma Q(s_{t+1}, a_{t+1})}_{\text{TD目標値}} - Q(s_t, a_t) \right]
}
update() メソッドの役割変更
モンテカルロ法では update() がQ値の更新と ε 更新の両方を担っていたが,SARSAでは update() は ε 更新のみである (Q値更新は add() で完了済み).
パラメータファイル
モンテカルロ法は montecarlo_param.json,SARSAは sarsa_param.json にそれぞれQ値を保存する.学習パラメータ (γ, α, ε など) はモンテカルロ法と同一の値とした.
| パラメータ | 値 |
|---|---|
| 割引率 γ | 0.9 |
| 学習率 α | 0.1 |
| 探索確率の最小値 ε_min | 0.1 |
| 探索確率の最大値 ε_max | 0.9 |
| 探索確率の減衰率 | 0.9999 |
PyBulletのメイン処理 (pybullet_main.py)
p.connect() 関数の引数である p.DIRECT と p.GUI に関しては下記にて,説明したため本記事では割愛する.
PyBulletでロボットを動かす
上記にて,ソースコードを説明した.
main.py ファイルを実施することによって,PyBullet上のロボットを動かしていく.
経路生成の動画
SARSAに動くエージェントによる経路生成の動画を載せる.
動画1:学習時の経路生成の動画
動画2:学習完了後の経路生成の動画
SARSAはモンテカルロ法と比較して,1ステップごとにQ値を更新するため,収束が速くなることが期待される.ただし,学習終了後であっても行動が最適とは限らない.
そのため,次回はSARSAではなく,Q学習を採用することで,行動がより最適となるようにする.
おわりに
本記事では,Pythonを使用して,下記内容を実装しました
- エージェントの学習方法としてSARSAを採用して,PyBullet 内の2軸ロボットアームの強化学習
次記事では,下記内容を実装していきます.
参考文献
本記事を作成する上で参考にした内容を記載する.
参考記事
参考書籍
- ゼロから作るDeep Learning ❹ ―強化学習編



