@@ -81,8 +81,12 @@ def command(self) -> torch.Tensor:
81
81
82
82
def _update_metrics (self ):
83
83
# logs data
84
- self .metrics ["error_pos_2d" ] = torch .norm (self .pos_command_w [:, :2 ] - self .robot .data .root_pos_w [:, :2 ], dim = 1 )
85
- self .metrics ["error_heading" ] = torch .abs (wrap_to_pi (self .heading_command_w - self .robot .data .heading_w ))
84
+ self .metrics ["error_pos_2d" ] = torch .norm (
85
+ self .pos_command_w [:, :2 ] - self .robot .data .root_pos_w [:, :2 ], dim = 1
86
+ )
87
+ self .metrics ["error_heading" ] = torch .abs (
88
+ wrap_to_pi (self .heading_command_w - self .robot .data .heading_w )
89
+ )
86
90
87
91
def _resample_command (self , env_ids : Sequence [int ]):
88
92
# obtain env origins for the environments
@@ -102,7 +106,9 @@ def _resample_command(self, env_ids: Sequence[int]):
102
106
# compute errors to find the closest direction to the current heading
103
107
# this is done to avoid the discontinuity at the -pi/pi boundary
104
108
curr_to_target = wrap_to_pi (target_direction - self .robot .data .heading_w [env_ids ]).abs ()
105
- curr_to_flipped_target = wrap_to_pi (flipped_target_direction - self .robot .data .heading_w [env_ids ]).abs ()
109
+ curr_to_flipped_target = wrap_to_pi (
110
+ flipped_target_direction - self .robot .data .heading_w [env_ids ]
111
+ ).abs ()
106
112
107
113
# set the heading command to the closest direction
108
114
self .heading_command_w [env_ids ] = torch .where (
@@ -117,7 +123,9 @@ def _resample_command(self, env_ids: Sequence[int]):
117
123
def _update_command (self ):
118
124
"""Re-target the position command to the current root state."""
119
125
target_vec = self .pos_command_w - self .robot .data .root_pos_w [:, :3 ]
120
- self .pos_command_b [:] = quat_rotate_inverse (yaw_quat (self .robot .data .root_quat_w ), target_vec )
126
+ self .pos_command_b [:] = quat_rotate_inverse (
127
+ yaw_quat (self .robot .data .root_quat_w ), target_vec
128
+ )
121
129
self .heading_command_b [:] = wrap_to_pi (self .heading_command_w - self .robot .data .heading_w )
122
130
123
131
def _set_debug_vis_impl (self , debug_vis : bool ):
@@ -143,6 +151,68 @@ def _debug_vis_callback(self, event):
143
151
)
144
152
145
153
154
+ class ObstaclePose2dCommand (UniformPose2dCommand ):
155
+ """Command generator that generates pose commands based on the obstacle.
156
+
157
+ This command generator determines the command position based on the position of the obstacle.
158
+ The heading commands are either set to point towards the target or are sampled uniformly.
159
+ This can be configured through the :attr:`Pose2dCommandCfg.simple_heading` parameter in
160
+ the configuration.
161
+ """
162
+
163
+ cfg : ObstaclePose2dCommandCfg
164
+ """Configuration for the command generator."""
165
+
166
+ def __init__ (self , cfg : ObstaclePose2dCommandCfg , env : ManagerBasedEnv ):
167
+ """Initialize the command generator class.
168
+
169
+ Args:
170
+ cfg: The configuration parameters for the command generator.
171
+ env: The environment object.
172
+ """
173
+ # initialize the base class
174
+ super ().__init__ (cfg , env )
175
+
176
+ # obtain the obstacle object
177
+ self .object : RigidObject = env .scene [cfg .object_name ]
178
+
179
+ def _resample_command (self , env_ids : Sequence [int ]):
180
+ # obtain env origins for the environments
181
+ self .pos_command_w [env_ids ] = self ._env .scene .env_origins [env_ids ]
182
+ r = torch .empty (len (env_ids ), device = self .device )
183
+ # offset the position command by the current root position
184
+ self .pos_command_w [env_ids , 0 ] = (
185
+ 2 * self .object .data .root_pos_w [env_ids , 0 ] - self .robot .data .root_pos_w [env_ids , 0 ]
186
+ )
187
+ self .pos_command_w [env_ids , 1 ] = (
188
+ 2 * self .object .data .root_pos_w [env_ids , 1 ] - self .robot .data .root_pos_w [env_ids , 1 ]
189
+ )
190
+ self .pos_command_w [env_ids , 2 ] = self .robot .data .default_root_state [env_ids , 2 ]
191
+
192
+ if self .cfg .simple_heading :
193
+ # set heading command to point towards target
194
+ target_vec = self .pos_command_w [env_ids ] - self .robot .data .root_pos_w [env_ids ]
195
+ target_direction = torch .atan2 (target_vec [:, 1 ], target_vec [:, 0 ])
196
+ flipped_target_direction = wrap_to_pi (target_direction + torch .pi )
197
+
198
+ # compute errors to find the closest direction to the current heading
199
+ # this is done to avoid the discontinuity at the -pi/pi boundary
200
+ curr_to_target = wrap_to_pi (target_direction - self .robot .data .heading_w [env_ids ]).abs ()
201
+ curr_to_flipped_target = wrap_to_pi (
202
+ flipped_target_direction - self .robot .data .heading_w [env_ids ]
203
+ ).abs ()
204
+
205
+ # set the heading command to the closest direction
206
+ self .heading_command_w [env_ids ] = torch .where (
207
+ curr_to_target < curr_to_flipped_target ,
208
+ target_direction ,
209
+ flipped_target_direction ,
210
+ )
211
+ else :
212
+ # random heading command
213
+ self .heading_command_w [env_ids ] = r .uniform_ (* self .cfg .ranges .heading )
214
+
215
+
146
216
class TerrainBasedPose2dCommand (UniformPose2dCommand ):
147
217
"""Command generator that generates pose commands based on the terrain.
148
218
@@ -173,7 +243,9 @@ def __init__(self, cfg: TerrainBasedPose2dCommandCfg, env: ManagerBasedEnv):
173
243
174
244
def _resample_command (self , env_ids : Sequence [int ]):
175
245
# sample new position targets from the terrain
176
- ids = torch .randint (0 , self .valid_targets .shape [2 ], size = (len (env_ids ),), device = self .device )
246
+ ids = torch .randint (
247
+ 0 , self .valid_targets .shape [2 ], size = (len (env_ids ),), device = self .device
248
+ )
177
249
self .pos_command_w [env_ids ] = self .valid_targets [
178
250
self .terrain .terrain_levels [env_ids ], self .terrain .terrain_types [env_ids ], ids
179
251
]
@@ -189,7 +261,9 @@ def _resample_command(self, env_ids: Sequence[int]):
189
261
# compute errors to find the closest direction to the current heading
190
262
# this is done to avoid the discontinuity at the -pi/pi boundary
191
263
curr_to_target = wrap_to_pi (target_direction - self .robot .data .heading_w [env_ids ]).abs ()
192
- curr_to_flipped_target = wrap_to_pi (flipped_target_direction - self .robot .data .heading_w [env_ids ]).abs ()
264
+ curr_to_flipped_target = wrap_to_pi (
265
+ flipped_target_direction - self .robot .data .heading_w [env_ids ]
266
+ ).abs ()
193
267
194
268
# set the heading command to the closest direction
195
269
self .heading_command_w [env_ids ] = torch .where (
0 commit comments