環境設定パラメータ(velocity_env_cfg.py)
ファイルパス: source/unitree_rl_lab/unitree_rl_lab/tasks/locomotion/robots/{robot_name}/velocity_env_cfg.py
ロボットの速度追従タスクの環境設定を定義します。このファイルでは、シミュレーション環境、地形、報酬関数、観測、イベントなど、強化学習に必要な全ての要素を設定します。
シーン設定 (RobotSceneCfg)
並列シミュレーション環境の数と配置を設定します。
| scene: RobotSceneCfg = RobotSceneCfg(
num_envs=4096, # 並列環境数(GPUメモリに応じて調整)
env_spacing=2.5 # 環境間の間隔 [m]
)
|
調整のポイント:
num_envs: GPUメモリに応じて調整。多いほど学習が高速化されるが、メモリ不足に注意。
- 2の累乗でないと、「FPSが10〜30%程度低下」「端数処理が入りwarp効率が落ちる」といった問題が起こるため、2の累乗で与えるのが良い。
num_envsの値が小さいほど速いわけではなく、総合的には4096が最速になることが多い。
- ただし、「GPUメモリが足りない」「学習が重い」などの場合は2の累乗で値を小さくするのが良い。
- RTX 3060 (12GB): 2048-4096
- RTX 4090 (24GB): 8192-16384
地形設定 (COBBLESTONE_ROAD_CFG)
トレーニング用の地形を生成します。
1
2
3
4
5
6
7
8
9
10
11
12 | COBBLESTONE_ROAD_CFG = terrain_gen.TerrainGeneratorCfg(
size=(8.0, 8.0), # 地形のサイズ [m]
num_rows=10, # 地形の行数
num_cols=20, # 地形の列数
horizontal_scale=0.1, # 水平方向のスケール
vertical_scale=0.005, # 垂直方向のスケール(地形の起伏)
difficulty_range=(0.0, 1.0), # 難易度の範囲
sub_terrains={ # サブ地形の定義
"flat": terrain_gen.MeshPlaneTerrainCfg(proportion=0.1),
# コメントアウトされた地形を有効化することで、階段、ボックス、傾斜などを追加可能
}
)
|
サブ地形のオプション:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | # ランダムな凹凸
"random_rough": terrain_gen.HfRandomUniformTerrainCfg(
proportion=0.1,
noise_range=(0.01, 0.06),
noise_step=0.01,
border_width=0.25
),
# ピラミッド型の傾斜
"hf_pyramid_slope": terrain_gen.HfPyramidSlopedTerrainCfg(
proportion=0.1,
slope_range=(0.0, 0.4),
platform_width=2.0,
border_width=0.25
),
# ランダムボックス
"boxes": terrain_gen.MeshRandomGridTerrainCfg(
proportion=0.2,
grid_width=0.45,
grid_height_range=(0.05, 0.2),
platform_width=2.0
),
# 階段
"pyramid_stairs": terrain_gen.MeshPyramidStairsTerrainCfg(
proportion=0.2,
step_height_range=(0.05, 0.23),
step_width=0.3,
platform_width=3.0,
border_width=1.0,
holes=False,
),
|
物理マテリアル設定
地形との接触時の物理特性を設定します。
| physics_material=sim_utils.RigidBodyMaterialCfg(
friction_combine_mode="multiply", # 摩擦の結合モード
restitution_combine_mode="multiply", # 反発係数の結合モード
static_friction=1.0, # 静止摩擦係数
dynamic_friction=1.0, # 動摩擦係数
)
|
コマンド設定 (CommandsCfg)
ロボットに与える速度コマンドの範囲を設定します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | base_velocity = mdp.UniformLevelVelocityCommandCfg(
resampling_time_range=(10.0, 10.0), # コマンドの再サンプリング時間 [s]
rel_standing_envs=0.1, # 静止環境の割合
ranges=mdp.UniformLevelVelocityCommandCfg.Ranges(
lin_vel_x=(-0.1, 0.1), # 初期の前後方向の速度範囲 [m/s]
lin_vel_y=(-0.1, 0.1), # 初期の左右方向の速度範囲 [m/s]
ang_vel_z=(-1, 1) # 初期の回転速度範囲 [rad/s]
),
limit_ranges=mdp.UniformLevelVelocityCommandCfg.Ranges(
lin_vel_x=(-1.0, 1.0), # 最終的な前後方向の速度範囲
lin_vel_y=(-0.4, 0.4), # 最終的な左右方向の速度範囲
ang_vel_z=(-1.0, 1.0) # 最終的な回転速度範囲
),
)
|
パラメータの意味:
ranges: カリキュラム学習の初期段階での速度範囲
limit_ranges: カリキュラム学習の最終段階での速度範囲
rel_standing_envs: 静止コマンド(速度0)を与える環境の割合
アクション設定 (ActionsCfg)
ポリシーネットワークの出力をロボットの制御に変換する設定です。
| JointPositionAction = mdp.JointPositionActionCfg(
asset_name="robot",
joint_names=[".*"], # 対象となる関節(正規表現)
scale=0.25, # アクションのスケール
use_default_offset=True, # デフォルトオフセットを使用
clip={".*": (-100.0, 100.0)} # アクションのクリッピング範囲
)
|
調整のポイント:
scale: 値が大きいほど、ポリシーの出力が大きな関節角度変化を引き起こす
観測設定 (ObservationsCfg)
PolicyCfg - ポリシーネットワーク用の観測
実機でも取得可能な観測値のみを使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | base_ang_vel = ObsTerm(
func=mdp.base_ang_vel,
scale=0.2, # スケール係数
clip=(-100, 100), # クリッピング範囲
noise=Unoise(n_min=-0.2, n_max=0.2) # ノイズ範囲
)
projected_gravity = ObsTerm(
func=mdp.projected_gravity,
clip=(-100, 100),
noise=Unoise(n_min=-0.05, n_max=0.05)
)
velocity_commands = ObsTerm(
func=mdp.generated_commands,
clip=(-100, 100),
params={"command_name": "base_velocity"}
)
joint_pos_rel = ObsTerm(
func=mdp.joint_pos_rel,
clip=(-100, 100),
noise=Unoise(n_min=-0.01, n_max=0.01)
)
joint_vel_rel = ObsTerm(
func=mdp.joint_vel_rel,
scale=0.05,
clip=(-100, 100),
noise=Unoise(n_min=-1.5, n_max=1.5)
)
last_action = ObsTerm(
func=mdp.last_action,
clip=(-100, 100)
)
|
観測項目の説明:
base_ang_vel: 胴体の角速度(IMUから取得)
projected_gravity: 投影された重力ベクトル(IMUから計算)
velocity_commands: 速度コマンド
joint_pos_rel: 関節位置(デフォルト位置からの相対値)
joint_vel_rel: 関節速度
last_action: 前ステップのアクション
CriticCfg - Criticネットワーク用の観測(特権情報)
シミュレーションでのみ利用可能な情報を含みます。
1
2
3
4
5
6
7
8
9
10
11
12 | base_lin_vel = ObsTerm(func=mdp.base_lin_vel, clip=(-100, 100))
base_ang_vel = ObsTerm(func=mdp.base_ang_vel, scale=0.2, clip=(-100, 100))
projected_gravity = ObsTerm(func=mdp.projected_gravity, clip=(-100, 100))
velocity_commands = ObsTerm(
func=mdp.generated_commands,
clip=(-100, 100),
params={"command_name": "base_velocity"}
)
joint_pos_rel = ObsTerm(func=mdp.joint_pos_rel, clip=(-100, 100))
joint_vel_rel = ObsTerm(func=mdp.joint_vel_rel, scale=0.05, clip=(-100, 100))
joint_effort = ObsTerm(func=mdp.joint_effort, scale=0.01, clip=(-100, 100))
last_action = ObsTerm(func=mdp.last_action, clip=(-100, 100))
|
追加の観測:
base_lin_vel: 胴体の並進速度(実機では直接測定困難)
joint_effort: 関節トルク
報酬設定 (RewardsCfg)
報酬関数は学習の成否を決定する最も重要な要素です。
タスク報酬
| track_lin_vel_xy = RewTerm(
func=mdp.track_lin_vel_xy_exp,
weight=1.5, # 重み係数
params={"command_name": "base_velocity", "std": math.sqrt(0.25)}
)
track_ang_vel_z = RewTerm(
func=mdp.track_ang_vel_z_exp,
weight=0.75,
params={"command_name": "base_velocity", "std": math.sqrt(0.25)}
)
|
ペナルティ項目
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 | base_linear_velocity = RewTerm(
func=mdp.lin_vel_z_l2,
weight=-2.0
) # Z軸方向の並進速度ペナルティ
base_angular_velocity = RewTerm(
func=mdp.ang_vel_xy_l2,
weight=-0.05
) # XY軸周りの角速度ペナルティ
joint_vel = RewTerm(
func=mdp.joint_vel_l2,
weight=-0.001
) # 関節速度ペナルティ
joint_acc = RewTerm(
func=mdp.joint_acc_l2,
weight=-2.5e-7
) # 関節加速度ペナルティ
joint_torques = RewTerm(
func=mdp.joint_torques_l2,
weight=-2e-4
) # 関節トルクペナルティ
action_rate = RewTerm(
func=mdp.action_rate_l2,
weight=-0.1
) # アクション変化率ペナルティ
dof_pos_limits = RewTerm(
func=mdp.joint_pos_limits,
weight=-10.0
) # 関節角度制限ペナルティ
energy = RewTerm(
func=mdp.energy,
weight=-2e-5
) # エネルギー消費ペナルティ
flat_orientation_l2 = RewTerm(
func=mdp.flat_orientation_l2,
weight=-2.5
) # 姿勢維持ペナルティ
|
足の接触報酬
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | feet_air_time = RewTerm(
func=mdp.feet_air_time,
weight=0.1,
params={
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=".*_foot"),
"command_name": "base_velocity",
"threshold": 0.5
}
)
air_time_variance = RewTerm(
func=mdp.air_time_variance_penalty,
weight=-1.0,
params={"sensor_cfg": SceneEntityCfg("contact_forces", body_names=".*_foot")}
)
feet_slide = RewTerm(
func=mdp.feet_slide,
weight=-0.1,
params={
"asset_cfg": SceneEntityCfg("robot", body_names=".*_foot"),
"sensor_cfg": SceneEntityCfg("contact_forces", body_names=".*_foot")
}
)
|
望ましくない接触のペナルティ
| undesired_contacts = RewTerm(
func=mdp.undesired_contacts,
weight=-1,
params={
"threshold": 1,
"sensor_cfg": SceneEntityCfg(
"contact_forces",
body_names=["Head_.*", ".*_hip", ".*_thigh", ".*_calf"]
)
}
)
|
イベント設定 (EventCfg)
ドメインランダマイゼーションと環境のリセット処理を設定します。
起動時のランダム化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | physics_material = EventTerm(
func=mdp.randomize_rigid_body_material,
mode="startup",
params={
"asset_cfg": SceneEntityCfg("robot", body_names=".*"),
"static_friction_range": (0.3, 1.2), # 静止摩擦係数の範囲
"dynamic_friction_range": (0.3, 1.2), # 動摩擦係数の範囲
"restitution_range": (0.0, 0.15), # 反発係数の範囲
"num_buckets": 64 # バケット数
}
)
add_base_mass = EventTerm(
func=mdp.randomize_rigid_body_mass,
mode="startup",
params={
"asset_cfg": SceneEntityCfg("robot", body_names="base"),
"mass_distribution_params": (-1.0, 3.0), # 質量の変動範囲 [kg]
"operation": "add"
}
)
|
リセット時の設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | reset_base = EventTerm(
func=mdp.reset_root_state_uniform,
mode="reset",
params={
"pose_range": {
"x": (-0.5, 0.5),
"y": (-0.5, 0.5),
"yaw": (-3.14, 3.14)
},
"velocity_range": {
"x": (0.0, 0.0),
"y": (0.0, 0.0),
"z": (0.0, 0.0),
"roll": (0.0, 0.0),
"pitch": (0.0, 0.0),
"yaw": (0.0, 0.0)
}
}
)
reset_robot_joints = EventTerm(
func=mdp.reset_joints_by_scale,
mode="reset",
params={
"position_range": (1.0, 1.0), # 関節位置の範囲
"velocity_range": (-1.0, 1.0) # 関節速度の範囲
}
)
|
定期的なイベント
| push_robot = EventTerm(
func=mdp.push_by_setting_velocity,
mode="interval",
interval_range_s=(5.0, 10.0), # イベント発生間隔 [s]
params={
"velocity_range": {
"x": (-0.5, 0.5),
"y": (-0.5, 0.5)
}
}
)
|
終了条件 (TerminationsCfg)
エピソードを終了させる条件を設定します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | time_out = DoneTerm(func=mdp.time_out, time_out=True)
base_contact = DoneTerm(
func=mdp.illegal_contact,
params={
"sensor_cfg": SceneEntityCfg("contact_forces", body_names="base"),
"threshold": 1.0
}
)
bad_orientation = DoneTerm(
func=mdp.bad_orientation,
params={"limit_angle": 0.8} # 姿勢の許容角度 [rad]
)
|
カリキュラム学習 (CurriculumCfg)
学習の進行に応じて難易度を調整します。
| terrain_levels = CurrTerm(func=mdp.terrain_levels_vel) # 地形の難易度を段階的に上昇
lin_vel_cmd_levels = CurrTerm(mdp.lin_vel_cmd_levels) # 速度コマンドの範囲を段階的に拡大
|
全体設定 (RobotEnvCfg)
| decimation = 4 # 制御周期のデシメーション(4 × 0.005s = 0.02s = 50Hz)
episode_length_s = 20.0 # エピソード長 [s]
sim.dt = 0.005 # シミュレーションのタイムステップ [s]
sim.render_interval = decimation # レンダリング間隔
|
パラメータの説明:
decimation: シミュレーションステップごとに何回に1回制御を実行するか
episode_length_s: 1エピソードの長さ(秒)
sim.dt: 物理シミュレーションのタイムステップ
- 制御周波数 = 1 / (decimation × sim.dt) = 1 / (4 × 0.005) = 50 Hz