소스 정보
- 저장소
- MIUAV/vibe-coding-ros2
- 최근 소스 활동
- 2026년 4월 3일 16:42
- 감지된 SKILL.md 언어
- 중국어
- 스타
- 26
- 포크
- 2
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/MIUAV/vibe-coding-ros2 --skill soft-body-simulation명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | soft-body-simulation |
| description | 软体仿真技能 - MuJoCo/Isaac Gym 软体物理、绳索/布料/软体抓取、仿真训练迁移 |
| argument-hint | 软体仿真 OR soft body OR 绳索仿真 OR 布料仿真 OR MuJoCo |
| user-invocable | true |
用于实现软体物理仿真,涵盖绳索、布料、软体抓取和仿真-现实迁移(Sim2Real)
当需要以下帮助时使用此技能:
软体仿真:
├── 绳索 (Rope/Cable) → 1D柔性,细长物体
├── 布料 (Cloth/Sheet) → 2D柔性,平坦软体
├── 颗粒 (Granular) → 沙子、粉末
├── 体积软体 (Volumetric) → 果冻、海绵
└── 混合刚软 (Hybrid) → 刚体+软体组合
# MuJoCo(最推荐)
pip install mujoco
# Isaac Gym(GPU加速)
pip install isaacgymenvs
# PyBullet
pip install pybullet
import mujoco
import mujoco.viewer as viewer
import numpy as np
class RopeSimulator:
"""MuJoCo 绳索仿真"""
def __init__(self, num_segments: int = 20, rope_length: float = 1.0):
self.n = num_segments
self.dt = 0.002
# 创建模型
self.model = self._build_model(num_segments, rope_length)
self.data = mujoco.MjData(self.model)
# 渲染器
self.viewer = None
def _build_model(self, n: int, length: float) -> mujoco.Model:
"""构建绳索 MuJoCo 模型"""
segment_length = length / n
# 球体几何体
geom_radius = 0.01
xml = f"""
<mujoco model="rope">
<option timestep="{self.dt}" iterations="50" tolerance="1e-10">
<flag contact="enable" energy="enable"/>
</option>
<worldbody>
<!-- 固定端(世界坐标) -->
<light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>
<!-- 绳索段 -->
<body name="seg0" pos="0 0 2">
<freejoint/>
<geom type="sphere" size="{geom_radius}" friction="0.5"/>
</body>
"""
# 添加剩余段
for i in range(1, n):
xml += f"""
<body name="seg{i}" pos="{i * segment_length} 0 2">
<freejoint/>
<geom type="sphere" size="{geom_radius}" friction="0.5"/>
</body>
"""
# 使用 weld 约束连接相邻段
for i in range(n - 1):
xml += f"""
<tendon>
<fixed name="tendon{i}" stiffness="1000" damping="1">
<joint joint="seg{i}_freejoint" coef1="1.0" coef2="-1.0"/>
</fixed>
</tendon>
"""
xml += """
</worldbody>
</mujoco>
"""
return mujoco.from_xml_string(xml)
def simulate(self, num_steps: int = 1000):
"""运行仿真"""
with viewer.launch_passive(self.model, self.data) as v:
for _ in range(num_steps):
mujoco.mj_step(self.model, self.data)
v.sync()
def apply_force(self, segment_id: int, force: np.ndarray):
"""对指定段施加力"""
self.data.xfrc_applied[segment_id + 1, :3] = force
def get_end_effector_position(self) -> np.ndarray:
"""获取末端位置"""
return self.data.body('seg{}'.format(self.n - 1)).xpos.copy()
class RopeManipulator:
"""绳索操作控制器"""
def __init__(self, rope_sim: RopeSimulator):
self.rope = rope_sim
self.Kp = 5.0
self.Kd = 2.0
def position_control(
self,
target: np.ndarray,
max_segments_to_move: int = 5
) -> np.ndarray:
"""
末端位置控制
Returns: 各段控制力
"""
current_end = self.rope.get_end_effector_position()
error = target - current_end
# 计算控制力
desired_velocity = self.Kp * error
current_velocity = self.rope.data.qvel[-3:]
# 只对前 max_segments_to_move 个段施加控制
forces = np.zeros(self.rope.n * 6)
for i in range(max_segments_to_move):
forces[i * 6:(i + 1) * 6] = (
self.Kp * error - self.Kd * current_velocity
) / max_segments_to_move
return forces
class CableRoutingEnv:
"""电缆布线环境"""
def __init__(self):
self.rope = RopeSimulator(num_segments=30, rope_length=1.5)
self.obstacles = [] # [(position, radius)]
# 奖励参数
self.reach_threshold = 0.02
self.collision_penalty = -1.0
self.success_reward = 10.0
def reset(self) -> np.ndarray:
"""重置环境"""
mujoco.mj_resetModel(self.rope.model, self.rope.data)
return self.rope.data.qpos.copy()
def step(self, action: np.ndarray) -> tuple:
"""
执行动作
Args:
action: 控制命令
Returns:
(next_state, reward, done, info)
"""
# 应用动作
for i in range(len(action)):
self.rope.data.ctrl[i] = action[i]
# 仿真一步
mujoco.mj_step(self.rope.model, self.rope.data)
# 计算奖励
end_pos = self.rope.get_end_effector_position()
goal_pos = np.array([0.5, 0.0, 1.0])
dist_to_goal = np.linalg.norm(end_pos - goal_pos)
reward = -dist_to_goal
# 检查是否成功
done = dist_to_goal < self.reach_threshold
if done:
reward += self.success_reward
return self.rope.data.qpos.copy(), reward, done, {}
def render(self):
"""渲染"""
with viewer.launch_passive(self.rope.model, self.rope.data) as v:
v.sync()
class ClothSimulator:
"""布料仿真"""
def __init__(self, width: int = 10, height: int = 10, cloth_size: float = 0.5):
self.width = width
self.height = height
self.size = cloth_size
self.cell_size = cloth_size / width
self.model = self._build_model(width, height, cloth_size)
self.data = mujoco.MjData(self.model)
def _build_model(self, w: int, h: int, size: float) -> mujoco.Model:
"""构建布料 MuJoCo 模型"""
cell = size / w
h = size / h
# 生成格子顶点
n = (w + 1) * (h + 1)
points = []
faces = []
for i in range(h + 1):
for j in range(w + 1):
points.append([j * cell, i * h, 2.0])
# 生成三角形面
for i in range(h):
for j in range(w):
v0 = i * (w + 1) + j
v1 = v0 +
v2 = v0 + w +
v3 = v2 +
faces.extend([v0, v1, v2, v1, v3, v2])
geom_ids = ((n))
xml =
mujoco.from_xml_string(xml)
:
():
.cloth = ClothSimulator(width=, height=, cloth_size=)
.grasper_pos = np.array([, , ])
.grasp_closed =
() -> :
delta = action[:] *
grasp = action[]
.grasper_pos += delta
grasp > .grasp_closed:
._execute_grasp()
mujoco.mj_step(.cloth.model, .cloth.data)
cloth_center = .cloth.data.geom_xpos[]
reward = -np.linalg.norm(.grasper_pos[:] - cloth_center[:])
done =
._get_obs(), reward, done, {}
():
closest_vert = ._find_closest_vert(.grasper_pos)
.grasp_closed =
() -> :
() -> np.ndarray:
np.concatenate([
.grasper_pos,
.cloth.data.qpos.copy(),
])
import isaacgym
import isaacgym.gymapi as gym_api
import isaacgym.gymutil as gymutil
class IsaacGymSoftBody:
"""Isaac Gym 软体环境"""
def __init__(self, num_envs: int = 256):
self.gym = gym_api.acquire_gym()
self.num_envs = num_envs
# 创建仿真
sim_params = gym_api.SimParams()
sim_params.dt = 1.0 / 60.0
sim_params.substeps = 2
sim_params.up_axis = gym_api.UP_AXIS_Z
sim_params.gravity = gym_api.Vec3(0.0, 0.0, -9.81)
self.sim = self.gym.create_sim(
compute_device=0,
graphics_device=0,
type=gym_api.SIM_PHY_SIM,
params=sim_params
)
# 创建环境
self.envs = []
self.actors = []
for i in range(num_envs):
env = self.gym.create_env(
self.sim,
lower=gym_api.Vec3(-0.5, -0.5, 0),
upper=gym_api.Vec3(0.5, 0.5, 1.0)
)
self.envs.append(env)
# 创建软体
._create_soft_body(env, i)
():
actor = .gym.create_actor(
env,
._get_soft_body_asset(),
gym_api.Transform(),
.(idx),
idx
)
props = .gym.get_actor_shape_properties(env, actor)
props[].compliance =
props[].friction =
.gym.set_actor_shape_properties(env, actor, props)
.actors.append(actor)
():
():
env .envs:
.gym.reset_actor_states(env)
():
i, env (.envs):
.gym.set_actor_dof_actuation(env, .actors[i], actions[i])
.gym.simulate(.sim)
.gym.fetch_results(.sim, )
import numpy as np
class DomainRandomizer:
"""Sim2Real 域随机化"""
def __init__(self):
# 可随机化的参数范围
self.param_ranges = {
# 物理参数
'gravity': (-10.0, -9.81), # 重力加速度
'friction': (0.3, 0.8), # 摩擦系数
'softness': (0.8, 1.2), # 软体刚度
# 视觉参数
'light_intensity': (0.7, 1.3), # 光照强度
'camera_noise': (0.0, 0.05), # 相机噪声
# 控制器参数
'Kp': (0.8, 1.2), # 增益随机化
'Kd': (0.8, 1.2),
}
def randomize(self) -> dict:
"""随机采样参数"""
params = {}
for name, (low, high) in self.param_ranges.items():
params[name] = np.random.uniform(low, high)
return params
():
params:
sim.params.gravity.z = params[]
params:
geom sim.model.geom_friction:
geom[:] = params[]
:
():
.sim = sim_model
.real = real_model
.error_history = []
.max_history =
() -> np.ndarray:
error = real_state - sim_state
.error_history.append(np.linalg.norm(error))
(.error_history) > .max_history:
.error_history.pop()
recent_error = np.mean(.error_history[-:])
recent_error > :
K_adapted = K *
:
K_adapted = K
K_adapted
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 绳索断裂/不稳定 | 子步长太大 | 减小 timestep,增加 iterations |
| 布料穿透自身 | 碰撞参数不当 | 减小 geom size,增加 solimp |
| 仿真太慢 | 粒子数太多 | 减少段数/顶点数 |
| 抓取滑落 | 摩擦力不足 | 增加 friction,或改用夹爪 |
| Sim2Real 迁移失败 | sim 太理想化 | 添加 domain randomization |
# MuJoCo 可视化
python -m mujoco.viewer --model=rope.xml
# Isaac Gym 测试
python -m isaacgym.gymutil --help
# 导出仿真数据
python export_sim_data.py --output=cloth_trajectory.npz
simulator/mujoco/mujoco-modeling — MuJoCo 模型创建manipulator/grasp-planning — 抓取规划manipulator/impedance-control — 柔顺控制simulator/isaaclab/rl-training — RL 训练robotics-learning/transfer-learning — 迁移学习