Mujoco KDL Wrapper  0.2.2
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
ex_record.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Headless recording example ported from src/examples/ex_record.cpp.
3
4Records the Kinova GEN3 arm holding the home pose via KDL gravity compensation
5(TORQUE mode) for 5 s at 60 fps, with the camera slowly orbiting the arm. No
6display or GLFW window is needed.
7"""
8
9from __future__ import annotations
10
11import math
12import sys
13
14import mj_kdl_wrapper as mjk
15
16HOME_POSE = [0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708]
17FPS = 60
18DURATION = 5.0 # seconds
19GRAVITY_Z = -9.81
20
21RESOLUTIONS = {
22 "360p": mjk.VideoResolution.R360p,
23 "480p": mjk.VideoResolution.R480p,
24 "720p": mjk.VideoResolution.R720p,
25 "1080p": mjk.VideoResolution.R1080p,
26 "2k": mjk.VideoResolution.R2K,
27 "4k": mjk.VideoResolution.R4K,
28}
29
30
31def build_scene(model_path: str) -> tuple[mjk.Scene, mjk.Robot]:
32 spec = mjk.SceneSpec()
33 spec.timestep = 0.002
34 spec.add_floor = True
35 spec.add_skybox = True
36 robot_spec = mjk.RobotSpec()
37 robot_spec.path = model_path
38 spec.robots = [robot_spec]
39 scene = mjk.Scene.build(spec)
40 robot = mjk.Robot.from_scene(scene, "base_link", "bracelet_link")
41 return scene, robot
42
43
44def main() -> int:
45 out_path = "sim.mp4"
46 resolution = mjk.VideoResolution.R1080p
47 for arg in sys.argv[1:]:
48 if arg.endswith(".mp4"):
49 out_path = arg
50 elif arg in RESOLUTIONS:
51 resolution = RESOLUTIONS[arg]
52 else:
53 print(f"Unknown argument '{arg}'; using 1080p", file=sys.stderr)
54
55 model_path = mjk.menagerie.model_path("kinova_gen3", env_var="MJ_KDL_MODEL")
56 scene, robot = build_scene(model_path)
57 recorder = None
58 try:
59 # Hold the home pose with KDL gravity compensation in TORQUE mode.
60 robot.ctrl_mode = mjk.CtrlMode.TORQUE
61 robot.set_joint_pos(HOME_POSE, call_forward=True)
62 # Prime gravity torques so the first step is compensated.
63 robot.jnt_trq_cmd = list(robot.gravity_torques(GRAVITY_Z))
64
65 recorder = mjk.VideoRecorder.open_preset(scene, out_path, resolution, FPS)
66 # Orbit camera slowly around the arm for a nicer recording.
67 recorder.set_free_camera(distance=1.8, azimuth=0.0, elevation=-20.0, lookat=(0.0, 0.0, 0.5))
68
69 total_steps = int(DURATION / scene.timestep())
70 steps_per_frame = max(1, int(1.0 / (FPS * scene.timestep())))
71 step_per_deg = 360.0 / total_steps # full orbit over DURATION
72
73 print(f"Recording {DURATION} s to {out_path} ({total_steps} steps, {FPS} fps)...")
74 for step in range(total_steps):
75 robot.update()
76 robot.jnt_trq_cmd = list(robot.gravity_torques(GRAVITY_Z))
77 robot.step()
78 if step % steps_per_frame == 0:
79 recorder.set_free_camera(
80 distance=1.8,
81 azimuth=math.fmod(step * step_per_deg, 360.0),
82 elevation=-20.0,
83 lookat=(0.0, 0.0, 0.5),
84 )
85 if not recorder.record_frame():
86 print(f"record_frame() failed at step {step}", file=sys.stderr)
87 break
88 print(f"Saved: {out_path}")
89 finally:
90 if recorder is not None:
91 recorder.close()
92 scene.close()
93 return 0
94
95
96if __name__ == "__main__":
97 raise SystemExit(main())
int main()
Definition ex_record.py:44
tuple[mjk.Scene, mjk.Robot] build_scene(str model_path)
Definition ex_record.py:31