"""Build a SPIDER task directory from a kinematic reference directory and apply the validated physics settings. Env: SPIDER_SRC (reference dir with datasets/.../boxes, reference_video_rate.npz, config.json), SPIDER_TASK_OUT (target). Settings follow output/spider_dynamics_fix_20260915/physics_parameters.json (simulation assumptions, not hardware).""" import os, json, shutil, xml.etree.ElementTree as E from pathlib import Path ROOT = Path(__file__).resolve().parents[1]; SRC = Path(os.environ['SPIDER_SRC']); OUT = Path(os.environ['SPIDER_TASK_OUT']) T = OUT / 'datasets/processed/current/l20/bimanual/boxes'; (T / '0').mkdir(parents=True, exist_ok=True) for rel in ['datasets/processed/current/l20/bimanual/boxes/scene_act.xml', 'datasets/processed/current/l20/bimanual/boxes/task_info.json', 'datasets/processed/current/l20/bimanual/boxes/0/trajectory_kinematic_act.npz', 'reference_video_rate.npz']: shutil.copy2(SRC / rel, OUT / rel) cfg = json.loads((SRC / 'config.json').read_text()); cfg['dataset_dir'] = str(OUT / 'datasets'); cfg.update(json.loads(os.environ.get('SPIDER_CONFIG_OVERRIDES', '{}'))); (OUT / 'config.json').write_text(json.dumps(cfg, indent=2)) for name in ['collision_v2', 'hand_collision']: if not (OUT / name).exists(): os.symlink(os.path.relpath(ROOT / 'output/collision_fix_20260915' / name, OUT), OUT / name) p = T / 'scene_act.xml'; tree = E.parse(p); r = tree.getroot() r.find('option').set('iterations', '80'); r.find('option').set('ls_iterations', '50') for g in r.findall('.//geom'): g.set('solimp', '.9 .95 .001 .5 2'); g.set('solref', '.02 1') if g.get('contype') in ['1', '2', '4']: g.set('margin', '.004'); g.set('gap', '.002') for a in r.findall('actuator/position'): n = a.get('name') if '_object_' in n: continue if '_hand_pos_' in n: kp, kv, limit = 500, 30, 20 elif '_hand_rot_' in n: kp, kv, limit = 15, 2, 2 else: kp, kv, limit = float(os.environ.get('HF_FINGER_KP', '4')), float(os.environ.get('HF_FINGER_KV', '.15')), float(os.environ.get('HF_FINGER_TORQUE', '.1')) a.attrib.update(kp=str(kp), kv=str(kv), forcerange=f'{-limit} {limit}') tree.write(p) settings = {'solver_iterations': 80, 'ls_iterations': 50, 'wrist_position_kp': 500, 'wrist_position_kv': 30, 'wrist_force_cap_N': 20, 'wrist_rotation_kp': 15, 'wrist_rotation_kv': 2, 'wrist_torque_cap_Nm': 2, 'finger_kp': float(os.environ.get('HF_FINGER_KP', '4')), 'finger_kv': float(os.environ.get('HF_FINGER_KV', '.15')), 'finger_torque_cap_Nm': float(os.environ.get('HF_FINGER_TORQUE', '.1')), 'contact_solimp': [.9, .95, .001, .5, 2], 'contact_solref': [.02, 1], 'contact_activation_distance_m': .002, 'table_collides_with_hands': True, 'note': 'Same contact regularization and 2 mm activation as spider_dynamics_fix_20260915 (selected by GPU/CPU short replay); table now a hand collider. Simulation parameters, not measured hardware.', 'source_reference': str(SRC)} (OUT / 'physics_parameters.json').write_text(json.dumps(settings, indent=2)); print('configured', OUT)