当前位置:   article > 正文

Isaac Gym 3. 基础总结_class sim: dt = 0.005 # 环境step时间为5ms substeps = 1

class sim: dt = 0.005 # 环境step时间为5ms substeps = 1 # 模拟的子步数,暂不确

近期使用isaac gym,所以对一些使用进行汇总。

1. ISAAC GYM

在isaac gym中,存在几个基础且常见的概念:gym, sim, env, actor, rigid

  1. Gym: 在Isaac Gym中,“Gym”通常指的是整个仿真平台或框架本身。它提供了创建和管理多个仿真环境的接口。

  2. Sim: “Sim”是指模拟器(simulator),是仿真的核心组件。它负责处理物理计算和仿真的所有细节,如动力学、碰撞检测和其他物理交互。Isaac Gym使用NVIDIA PhysX作为其后端物理引擎,可以高效地在GPU上运行。在代码中的体现是,调用sim可以完成对模拟器的step。

  3. Env: “Env”是指环境(environment),是智能体(agent)进行学习和互动的场所。每个环境包含了特定的任务或场景设置,智能体需要在这些环境中执行操作以获取奖励并学习策略。

  4. Actor: “Actor”是在仿真中表示具有物理属性的对象,如机器人、物体等。每个Actor包括了用于描述其形状、质量、动力学属性等的各种参数。Actors是智能体与环境互动的主体,例如一个机器人的手臂或车辆。

  5. Rigid: “Rigid”,刚体,是一种物理对象,其形状在仿真过程中不会发生变化。在Isaac Gym中,刚体用来表示那些不需要弹性或变形特性的实体。刚体动力学是计算这些对象如何在力和碰撞作用下移动和反应的基础。

  6. Index / indcies: 这是一个很容易混淆的概念,特别是在多env多actor,每个actor拥有1个以上rigid时。理解index的索引获取和它代表的对象非常重要。

由此,可以得到isaac gym仿真环境的基本框架,即基于gym,使用sim进行仿真,在sim中可以生成多个env,每个env中可以生成多个actor作为交互对象。对于每个actor,可以由rigid或其他非刚体关系组成。

2. 仿真环境

2.1. 基础环境搭建

 基础环境包括gym和sim,viewer的初始化,以下是添加ground plane和设置sim参数的代码:

  1. # initialize gym
  2. gym = gymapi.acquire_gym()
  3. # parse arguments
  4. args = gymutil.parse_arguments(description="Joint control Methods Example")
  5. # create a simulator
  6. sim_params = gymapi.SimParams()
  7. sim_params.substeps = 1
  8. sim_params.dt = opt.dt
  9. sim_params.physx.solver_type = 1
  10. sim_params.physx.num_position_iterations = 4
  11. sim_params.physx.num_velocity_iterations = 1
  12. sim_params.physx.num_threads = args.num_threads
  13. sim_params.physx.use_gpu = args.use_gpu
  14. sim_params.use_gpu_pipeline = args.use_gpu_pipeline
  15. if args.sim_device_type == 'cuda' and sim_params.use_gpu_pipeline:
  16. device = args.sim_device
  17. else:
  18. device = 'cpu'
  19. sim = gym.create_sim(args.compute_device_id, args.graphics_device_id, args.physics_engine, sim_params)
  20. if sim is None:
  21. print("*** Failed to create sim")
  22. quit()
  23. # create viewer using the default camera properties
  24. viewer = gym.create_viewer(sim, gymapi.CameraProperties())
  25. if viewer is None:
  26. raise ValueError('*** Failed to create viewer')
  27. # add ground plane
  28. plane_params = gymapi.PlaneParams()
  29. gym.add_ground(sim, gymapi.PlaneParams())

 sim搭建好后就是声明env或envs。

使用gym.create_env声明env并获得env_handle,如果使用多个环境可添加handle到envs。

如:

  1. num_envs = 16
  2. num_per_row = int(np.sqrt(num_envs))
  3. spacing = 1.5 # actor 之间的间隔
  4. env_lower = gymapi.Vec3(-spacing, 0.0, -spacing)
  5. env_upper = gymapi.Vec3(spacing, 0.0, spacing)
  6. envs = []
  7. for i in range(num_envs):
  8. # create env
  9. env_handle = gym.create_env(sim, env_lower, env_upper, int(np.sqrt(num_envs)))
  10. envs.append(env_handle)

创建完成env后可以创建viewer:

  1. # create viewer
  2. mid = 0.5 * spacing * (num_per_row - 1)
  3. cam_pos = gymapi.Vec3(0, spacing, 0)
  4. cam_target = gymapi.Vec3(mid, 0, mid)
  5. gym.viewer_camera_look_at(viewer, None, cam_pos, cam_target)

2.2. 环境参数

这里的环境参数是以上内容中设定环境时可能使用的参数,调用gymutil和gymapi。

# parse arguments 这个函数句柄没有在handbook中找到,待议
args = gymutil.parse_arguments(description="Joint control Methods Example")

其中gymapi.SimParams()返回一个Gym Simulation Parameters的类,其中会包括FlexParams和PhysXParams两个子类用于设定详细参数。

sim_params.dt = 0.01         # 环境step时间为10ms
sim_params.substeps = 2      # 模拟的子步数,暂不确定有什么用
sim_params.gravity = [0., 0., -9.81]

sim_params.enable_actor_creation_warning
sim_params.num_client_threads
sim_params.flex              # 更详细的仿真设置,参考FlexParams
sim_params.up_axis = 1       # 设定坐标系的垂直坐标轴,0为y,1为z

sim_params.use_gpu_pipeline

sim_params.stress_visualization
sim_params.stress_visualization_min
sim_params.stress_visualization_max

sim_params.physx.solver_type = 1                # 
sim_params.physx.num_position_iterations = 4    # 
sim_params.physx.num_velocity_iterations = 1    # 

sim_params.physx.num_threads = args.num_threads
sim_params.physx.use_gpu = args.use_gpu

3.1. 模型导入

请参考https://github.com/leggedrobotics/legged_gym

3.2. 模型生成

举例,生成一个球体,需要用到代码获得球体预设,并将球体句柄加入到actor中。(此时为多环境)

  1. sphere_asset = self.gym.create_sphere(self.sim, radius, asset_options)
  2. # (self: Gym, env: Env, asset: Asset, pose: Transform, name: str = None, group: int = - 1, filter: int = - 1, segmentationId: int = 0)
  3. sphere_handle = self.gym.create_actor(env, sphere_asset, pos, "sphere", filter, 1) # in filter i
  4. actor_handles.append(sphere_handle)

 其中,使用gymapi.AssetOptions(),对球体的部分参数进行设定,如:

  1. # Create the sphere asset with specific physical properties
  2. asset_options = gymapi.AssetOptions()
  3. asset_options.density = 530 # Set the density for the tennis ball

以及,使用gymapi.Transform(),对球体的位姿进行设定,如:

  1. initial_pose = np.random.uniform(-1, 1, size=3)
  2. initial_pose = torch.tensor(initial_pose, device=device)
  3. pos = gymapi.Transform()
  4. pos.p = gymapi.Vec3(*initial_pose)
  5. pos.r = gymapi.Quat(-0.707107, 0.0, 0.0, 0.707107)

以及,使用gymapi.RigidShapeProperties(),对于部分刚体参数的设置,如:

  1. # Set the restitution using RigidShapeProperties
  2. properties = gymapi.RigidShapeProperties() # 具有filter参数
  3. properties.restitution = 0.85 # Set the restitution for the tennis ball
  4. properties.filter = 0
  5. gym.set_actor_rigid_shape_properties(env, sphere_handle, [properties])

注意,以上的几个参数相互存在互补和重复,正确设定即可。

也可以调整球体的颜色:

  1. color = gymapi.Vec3(random.random(), random.random(), random.random())
  2. gym.set_rigid_body_color(env, actor_handle, 0, gymapi.MESH_VISUAL_AND_COLLISION, color)

在导入模型时,我们需要对模型的handle和index进行记录,以便于后续的数据索引,并避免重复检查索引,加速程序运算。

  1. self.actor_handles = []
  2. self.actor_idxs = []
  3. self.rigid_body_idxs = []
  4. self.envs = []

 使用以下api获取index和handle。如果发现返回的idx或handle为-1,则代表未检索到对象。

  1. actor_handle = self.gym.create_actor(env_handle, robot_asset, start_pose, self.cfg.asset.name, i,self.cfg.asset.self_collisions, 0)
  2. self.envs.append(env_handle)
  3. self.actor_handles.append(actor_handle)
  4. actor_idx = self.gym.find_actor_index(env_handle, self.cfg.asset.name, gymapi.DOMAIN_SIM)
  5. self.actor_idxs.append(actor_idx)

 Isaac gym手册中有大量的句柄搜索方法,此处我只列举了当前选出的较为合适的方法。由于这些概念较为抽象,请实际debug时进行查看以理解。

4. 信息读取

4.1. ISAAC GYM运行流程

sim声明后的运行主要为以下流程:

  1. # after init and before loop
  2. gym.prepare_sim(sim)
  3. # start loop
  4. while not gym.query_viewer_has_closed(viewer):
  5. # step the physics
  6. gym.simulate(sim)
  7. gym.fetch_results(sim, True)
  8. # refresh tensors
  9. # take actions
  10. # update viewer
  11. gym.step_graphics(sim)
  12. gym.draw_viewer(viewer, sim, True)
  13. gym.sync_frame_time(sim)
  14. # end and clean up
  15. gym.destroy_viewer(viewer)
  16. gym.destroy_sim(myball.sim)

sim中的信息以isaac gym自有的tensor类型存储,不同于pytorch。为了确保获取实时的信息,使用以下句柄在读取tensor前对tensor进行刷新和维护:

  1. # refresh tensors
  2. gym.refresh_rigid_body_state_tensor(sim)
  3. gym.refresh_dof_state_tensor(sim)
  4. gym.refresh_jacobian_tensors(sim)
  5. gym.refresh_mass_matrix_tensors(sim)

4.1. 基本信息

Isaac gym中的状态tensor大致有几类:_root_tensor, rigid_body_tensor, contact_force_tensor. dof_tensor暂时不提及。

以上的tensor可以通过以下api获取:

  1. self._root_tensor = self.gym.acquire_actor_root_state_tensor(self.sim)
  2. _rb_states = self.gym.acquire_rigid_body_state_tensor(self.sim)
  3. _net_cf = self.gym.acquire_net_contact_force_tensor(self.sim)

获取tensor后,需要通过wrap_tensor操作来将isaac gym类型的tensor转化为torch类型的tensor。

  1. self.root_states = gymtorch.wrap_tensor(self._root_tensor)
  2. self.rb_states = gymtorch.wrap_tensor(_rb_states)
  3. self.contact_forces = gymtorch.wrap_tensor(_net_cf).view(self.num_envs, -1, 3)

从调用的sim句柄可以看出,此处获取的tensor索引(index)应该是sim的全局索引。

由于一次获取的是全部环境的rigid tensor,所以可以按照需要使用env对rigid进行数据切片:

  1. positions = []
  2. velocities = []
  3. for i, (env, ball_handle) in enumerate(zip(envs, actor_handles)):
  4. num_bodies = gym.get_actor_rigid_body_count(env, ball_handle)
  5. if num_bodies == 0:
  6. raise ValueError("The specified ball handle has no rigid bodies.")
  7. # body_index = gym.get_actor_rigid_body_handle(env, ball_handle, 0)
  8. pos = rb_states[i, 0:3].cpu().numpy()
  9. vel = rb_states[i, 7:10].cpu().numpy()
  10. positions.append(pos)
  11. velocities.append(vel)

注:以上代码仅适用与多环境单actor单rigid的情况。后续更新

对于gym.acquire_rigid_body_state_tensor的参数定义如下:

Retrieves buffer for Rigid body states.

The buffer has shape (num_rigid_bodies, 13).

State for each rigid body contains position([0:3]), rotation([3:7]), linear velocity([7:10]), and angular velocity([10:13]).

4.1.1. 获取具体刚体的信息

参考isaac gym的例程franka_ cube_ik_osc.py

其中,涉及使用函数

gym.get_actor_rigid_body_index,DOMAIN_SIM表示返回sim中的句柄,DOMAIN_ENV则是返回env中的句柄。

  1. box_idx = gym.get_actor_rigid_body_index(env, box_handle, 0, gymapi.DOMAIN_SIM)
  2. box_idxs.append(box_idx)

gym.find_actor_rigid_body_handle,查找给定名称的actor刚体句柄。

  1. hand_handle = gym.find_actor_rigid_body_handle(env, franka_handle, "panda_hand")
  2. hand_pose = gym.get_rigid_transform(env, hand_handle)

gym.find_actor_rigid_body_index,使用此函数可查找状态缓冲区中刚体的索引。

  1. hand_idx = gym.find_actor_rigid_body_index(env, franka_handle, "panda_hand", gymapi.DOMAIN_SIM)
  2. hand_idxs.append(hand_idx)

以上带有DOMAIN_SIM一类参数函数是部分查找函数的集合,所以有更多不同名称的调用方法,具体见handbook。

获取index后即可切片读取信息:

  1. box_pos = rb_states[box_idxs, :3]
  2. box_rot = rb_states[box_idxs, 3:7]
  3. hand_pos = rb_states[hand_idxs, :3]
  4. hand_rot = rb_states[hand_idxs, 3:7]
  5. hand_vel = rb_states[hand_idxs, 7:]

4.2. 碰撞检测

这里提及的碰撞检测使用

  1. net_contact_forces = self.gym.acquire_net_contact_force_tensor(self.sim)
  2. self.contact_forces = gymtorch.wrap_tensor(net_contact_forces).view(self.num_envs, -1, 3) # shape: num_envs, num_bodies, xyz axis

刷新使用

self.gym.refresh_net_contact_force_tensor(self.sim)

刷新后可以检测

base_force = torch.norm(self.contact_forces[:, self.termination_contact_indices, :], dim=-1)

 

5. 设定状态

在这里提一个很恶心的问题,文档的说明不多。

在CPU状态下,我们可以通过以下方法来设定全局的刚体状态,比如需要重置状态的时候。

  1. # Unwrap the tensor before setting it
  2. rb_states = gymtorch.unwrap_tensor(rb_states)
  3. ii = self.gym.set_rigid_body_state_tensor(self.sim, rb_states)
  4. print("vel", ii)

 但是该方法不能在GPU环境下生效,(会返回false,但是程序运行不会报错)需要改为另一个方法:

  1. indices = torch.tensor(actor_idxs, device=self.device, dtype=torch.int32)
  2. self.gym.set_actor_root_state_tensor_indexed(self.sim,
  3. gymtorch.unwrap_tensor(rb_states),
  4. gymtorch.unwrap_tensor(indices), len(indices))

以上代码可以设定特定index的root_state状态,以下代码设定全部的状态:

self.gym.set_actor_root_state_tensor(self.sim, gymtorch.unwrap_tensor(self.rb_states))

在设定状态时,可能在gpu pipline遇见以下问题。

CUDA error: an illegal memory access was encountered - #2 by vamshikurva - Isaac Gym - NVIDIA Developer Forums

部分错误请详细阅读用户文档的:NVIDIA_Omniverse/ISAAC_Gym/isaacgym/docs/programming/tensors.html?highlight=set_dof_state_tensor_indexed

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/827908
推荐阅读
相关标签
  

闽ICP备14008679号