| // Shared sim constants, lifted verbatim from the pre-React rl.js. | |
| export const POLICY_DIR = "./policies"; | |
| export const POLICIES = { | |
| walk: `${POLICY_DIR}/BEST_alpha_walking.onnx`, | |
| sitstand: `${POLICY_DIR}/BEST_alpha_sitstand.onnx`, | |
| roll: `${POLICY_DIR}/roulade.onnx`, | |
| // Blind one-shot kicks (the operator aims the robot, no ball in obs): | |
| // the runtime swaps these in for a 0.5 s window, commands zeroed. | |
| kickL: `${POLICY_DIR}/ball_kick_left.onnx`, | |
| kickR: `${POLICY_DIR}/ball_kick_right.onnx`, | |
| // One-shot ground pick (runtime A button): peck the ground and stand | |
| // back up, phase-driven via [cos, sin, 0] in the command vel slots. | |
| groundpick: `${POLICY_DIR}/alpha_ground_pick.onnx`, | |
| // Get-up policy for the automatic fall recovery (runtime --fall-detect): | |
| // same 61D obs layout as the other alpha policies, commands all zeroed. | |
| stand: `${POLICY_DIR}/BEST_alpha_stand.onnx`, | |
| // Roller variant (lazy-loaded on first switch, never at boot): | |
| // drive = velocity-tracking skating, crouch = one-shot crouch-glide | |
| // driven by a phase encoding in the command slots (ground-pick style). | |
| drive: `${POLICY_DIR}/BEST_roller.onnx`, | |
| crouch: `${POLICY_DIR}/BEST_roller_crouch.onnx`, | |
| }; | |
| // From the ONNX metadata (identical for all alpha policies) and the STAND | |
| // keyframe in mjlab's scene_walk.xml. Order matches the actuators in | |
| // the MJCF. | |
| export const JOINT_NAMES = [ | |
| "left_hip_yaw", "left_hip_roll", "left_hip_pitch", "left_knee", "left_ankle", | |
| "neck_pitch", "head_pitch", "head_yaw", "head_roll", | |
| "right_hip_yaw", "right_hip_roll", "right_hip_pitch", "right_knee", "right_ankle", | |
| ]; | |
| export const DEFAULT_POSE = new Float32Array([ | |
| 0, -0.08726646259971647, -0.457924, -0.004940, 0.452984, | |
| 0.3490658503988659, 0.3490658503988659, 0, 0, | |
| 0, 0.08726646259971647, 0.457924, 0.004940, -0.452984, | |
| ]); | |
| export const NUM_JOINTS = 14; | |
| export const OBS_SIZE = 61; | |
| export const CMD_SIZE = 13; | |
| export const ACTION_SCALE = 1.0; | |
| export const TIMESTEP = 0.005; | |
| export const DECIMATION = 4; | |
| export const CTRL_DT = TIMESTEP * DECIMATION; // 50 Hz | |
| // Velocity command limits, same as infer_policy.py's keyboard mapping. | |
| // No strafe input anymore: the lateral cmd slot stays zeroed for the obs. | |
| export const VEL_FWD = 0.25, VEL_BACK = -0.2, VEL_ANG = 1.0; | |
| // Roller mode limits, from the runtime's roller branch: asymmetric vx | |
| // (0.6 push / 0.5 brake), no lateral. The real runtime launches rollers | |
| // with --max-angular-vel 0.3: faster commanded turns tip the robot over, | |
| // so the playground clamps wz the same way. | |
| export const RVEL_FWD = 0.6, RVEL_BACK = -0.5, RVEL_ANG = 0.3; | |
| // Crouch-glide one-shot: command = [cos(2pi*phase), sin(2pi*phase), 0], | |
| // phase advancing at 1/CROUCH_PERIOD_S per second and the cycle exiting | |
| // at 0.7 - exactly the runtime's ground-pick slot the policy was trained | |
| // against (mjlab CROUCH_PERIOD = 5.0, cycle end 0.7 => 3.5 s gesture). | |
| export const CROUCH_PERIOD_S = 5.0; | |
| export const CROUCH_END_PHASE = 0.7; | |
| // Ground-pick one-shot (legs): same phase encoding, from the runtime's | |
| // defaults (--ground-pick-period 4.0, cycle exiting at 0.7 => ~2.8 s | |
| // gesture, action scale and kP untouched at their 1.0 defaults). | |
| export const GROUND_PICK_PERIOD_S = 4.0; | |
| export const GROUND_PICK_END_PHASE = 0.7; | |
| // Kickable ball: radius and parking spot (far away = hidden by default). | |
| export const BALL_RADIUS = 0.05; | |
| export const BALL_PARK_POS = "50 0 0.05"; | |
| // Square arena boxing the play area: static walls at +-ARENA_HALF keep | |
| // the ball (and the duck) inside. Tall enough that neither steps over. | |
| export const ARENA_HALF = 1.5; // inner half-size, m | |
| export const ARENA_WALL_H = 0.25; | |
| export const ARENA_WALL_T = 0.05; | |
| // Section grid: 5 cells across the 3 m arena (ODD, so a true middle | |
| // column/row of cells exists; the lattice is shifted half a cell in the | |
| // shaders so the walls land exactly on section lines). | |
| export const GRID_SECTION = (2 * ARENA_HALF) / 5; // 0.6 m | |
| // Arcade cabinet row: three cabinets side by side against the front (+X) | |
| // wall, screens facing the arena. Consumed by the prop library (props.js | |
| // "arcade" def - currently benched, enabled: false) for both the clone | |
| // placements and the row's single static collision box. Proportions | |
| // measured from the GLB's natural size (0.524 x 0.587 x 1.0 m, w x d x h). | |
| // Slightly surreal scale: ~2.8x the 0.25 m duck (a real 1.73 m cabinet | |
| // felt overwhelming in the 3 m arena). Big enough to read as oversized | |
| // furniture, small enough that the row (~1.15 m wide, 0.41 m deep) | |
| // leaves the play area open. | |
| export const ARCADE_H = 0.7; // target height, m | |
| export const ARCADE_W = ARCADE_H * 0.524; // footprint width, ~0.22 m | |
| export const ARCADE_D = ARCADE_H * 0.5876; // footprint depth, ~0.247 m | |
| export const ARCADE_GAP = 0.02; // gap between neighbouring cabinets | |
| export const ARCADE_WALL_GAP = 0.01; // clearance between backs and the wall | |
| // Relief (prototype): gentle cosine bumps baked into the level itself. | |
| // One shared analytic height function drives BOTH the physics (a MuJoCo | |
| // heightfield covering the arena) and the visuals (vertex displacement | |
| // of the grid floor shader), so the grid genuinely deforms instead of | |
| // boxes popping out of it. Entries are [cx, cy, height, radius] in MJCF | |
| // coords; slopes stay mild (max grade ~20%) so the blind walking policy | |
| // has a chance, and the spawn cell + arcade row stay flat. | |
| export const RELIEF_BUMPS = [ | |
| [0.3, -0.9, 0.06, 0.55], | |
| [-0.9, 0.75, 0.05, 0.5], | |
| [0.6, 0.9, 0.07, 0.55], | |
| ]; | |
| export const RELIEF_HMAX = 0.07; // tallest bump, scales the hfield z-size | |
| export const RELIEF_GRID = 65; // hfield rows/cols over the 3x3 m arena | |
| export const RELIEF_SINK = 0.003; // hfield geom buried below the floor | |
| export const RELIEF_RATE = 0.6; // raise/sink rate, scale units per second | |
| // Spawn: center of the middle section cell in the SECOND ROW FROM THE | |
| // BACK wall. The duck faces +X (identity freejoint quat, walks toward | |
| // local +X), so "back" is the -X wall: row centers sit at x = -1.2, | |
| // -0.6, 0, 0.6, 1.2 -> second row is -0.6; middle column is y = 0. | |
| // MJCF coordinates (three.js: x -> x, y -> -z). | |
| export const SPAWN_X = -ARENA_HALF + 1.5 * GRID_SECTION; // -0.6 | |
| export const SPAWN_Y = 0; | |