Mujoco KDL Wrapper  0.2.2
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
ex_vel_ctrl.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Joint velocity-control example ported from src/examples/ex_vel_ctrl.cpp.
3
4gen3.xml has POSITION actuators, so velocity control integrates a clamped
5velocity command into the position setpoint each step. An Env on_reset hook
6re-homes the arm and restarts the motion so the simulate-UI reset replays it.
7"""
8
9from __future__ import annotations
10
11import argparse
12
13import mj_kdl_wrapper as mjk
14
15HOME_POSE = [0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708]
16TARGET_POSE = [0.3, 0.5, 2.9, -2.0, 0.3, 1.2, 1.3]
17KV = 2.0
18MAX_VEL = 0.6
19TOL = 0.01
20
21
22def clamp(value: float, low: float, high: float) -> float:
23 return max(low, min(high, value))
24
25
26def build_env(model_path: str) -> tuple[mjk.Env, mjk.Robot]:
27 spec = mjk.SceneSpec()
28 spec.timestep = 0.002
29 spec.add_floor = True
30 spec.add_skybox = True
31 robot_spec = mjk.RobotSpec()
32 robot_spec.path = model_path
33 spec.robots = [robot_spec]
34 env = mjk.Env.build(spec)
35 robot = env.create_robot("base_link", "bracelet_link")
36 robot.ctrl_mode = mjk.CtrlMode.POSITION
37 return env, robot
38
39
40def main() -> int:
41 parser = argparse.ArgumentParser()
42 parser.add_argument("--gui", action="store_true", help="Open the custom Simulate UI.")
43 args = parser.parse_args()
44
45 model_path = mjk.menagerie.model_path("kinova_gen3", env_var="MJ_KDL_MODEL")
46 env, robot = build_env(model_path)
47 try:
48 dt = env.timestep()
49 state = {"arrived": False}
50
51 def on_reset(ctx):
52 robot.set_joint_pos(HOME_POSE, call_forward=False)
53 robot.jnt_pos_cmd = HOME_POSE[:]
54 state["arrived"] = False
55
56 env.on_reset = on_reset
57 env.reset()
58
59 def control_step() -> None:
60 robot.update()
61 if state["arrived"]:
62 return
63 pos_cmd = robot.jnt_pos_cmd
64 max_err = 0.0
65 for i in range(robot.n_joints):
66 err = TARGET_POSE[i] - robot.jnt_pos_msr[i]
67 max_err = max(max_err, abs(err))
68 pos_cmd[i] += clamp(KV * err, -MAX_VEL, MAX_VEL) * dt
69 if max_err < TOL:
70 robot.jnt_pos_cmd = robot.jnt_pos_msr
71 state["arrived"] = True
72 else:
73 robot.jnt_pos_cmd = pos_cmd
74
75 if args.gui:
76 viewer = mjk.SimulateViewer.open(robot, "ex_vel_ctrl.py")
77 prev = env.time()
78 try:
79 while viewer.is_running():
80 if env.time() < prev - 1e-6:
81 env.reset()
82 prev = env.time()
83 control_step()
84 if not viewer.step():
85 break
86 finally:
87 viewer.close()
88 else:
89 end = env.time() + 5.0
90 while env.time() < end and not state["arrived"]:
91 control_step()
92 robot.step()
93 max_err = max(abs(TARGET_POSE[i] - robot.jnt_pos_msr[i]) for i in range(robot.n_joints))
94 status = "converged" if state["arrived"] else "timeout"
95 print(f"max joint error: {max_err:.4f} rad ({status})")
96 finally:
97 env.close()
98
99 return 0
100
101
102if __name__ == "__main__":
103 raise SystemExit(main())
float clamp(float value, float low, float high)
tuple[mjk.Env, mjk.Robot] build_env(str model_path)