Mujoco KDL Wrapper  0.2.2
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
ex_vel_ctrl.cpp
Go to the documentation of this file.
1/* ex_vel_ctrl.cpp
2 * Joint velocity control: drive the Kinova GEN3 from the home pose to a target
3 * pose using a proportional velocity controller, then hold.
4 *
5 * gen3.xml has POSITION actuators, so velocity is implemented by integrating
6 * a clamped velocity command into the position setpoint each step:
7 *
8 * vel[i] = clamp(Kv * (target[i] - q[i]), -maxVel, maxVel)
9 * jnt_pos_cmd[i] += vel[i] * dt
10 *
11 * Requires MuJoCo Menagerie in cache.
12 *
13 * Usage:
14 * ex_vel_ctrl [--headless]
15 *
16 * With --headless runs until convergence (or 5 s timeout) and prints
17 * final max joint error. */
18
20#include "example_paths.hpp"
21
22#include <algorithm>
23#include <cmath>
24#include <iomanip>
25#include <iostream>
26#include <string>
27
28static constexpr double kHomePose[7] = { 0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708 };
29static constexpr double kTargetPose[7] = { 0.3, 0.5, 2.9, -2.0, 0.3, 1.2, 1.3 };
30
31static constexpr double kKv = 2.0; // proportional gain [rad/s per rad error]
32static constexpr double kMaxVel = 0.6; // max joint velocity [rad/s]
33static constexpr double kTol = 0.01; // convergence tolerance [rad]
34
35int main(int argc, char *argv[])
36{
37 bool headless = false;
38 for (int i = 1; i < argc; ++i)
39 if (std::string(argv[i]) == "--headless") headless = true;
40
41 const std::string mjcf = mj_kdl_examples::menagerie_model("kinova_gen3/gen3.xml");
42
44 sc.timestep = 0.002;
45 sc.add_floor = true;
46 sc.add_skybox = true;
48 r.path = mjcf.c_str();
49 sc.robots.push_back(r);
50
51 mjModel *model = nullptr;
52 mjData *data = nullptr;
53 if (!mj_kdl::build_scene(&model, &data, &sc)) {
54 std::cerr << "build_scene() failed\n";
55 return 1;
56 }
57
58 mj_kdl::Robot robot;
59 if (!mj_kdl::init_robot_from_mjcf(&robot, model, data, "base_link", "bracelet_link")) {
60 std::cerr << "init_robot_from_mjcf() failed\n";
61 mj_kdl::destroy_scene(model, data);
62 return 1;
63 }
64
65 unsigned n = static_cast<unsigned>(robot.n_joints);
66
67 KDL::JntArray q_home(n);
68 for (unsigned i = 0; i < n; ++i) q_home(i) = kHomePose[i];
69
71
72 mj_kdl::Env env;
73 env.spec = sc;
74 env.model = model;
75 env.data = data;
76 mj_kdl::env_add_robot(&env, &robot);
77
78 const double dt = model->opt.timestep;
79 bool arrived = false;
80
81 env.on_reset = [&](mj_kdl::ResetContext *) {
82 mj_kdl::set_joint_pos(&robot, q_home, false);
83 arrived = false;
84 };
85
86 mj_kdl::reset(&env);
87
88 auto ctrl_step = [&]() {
89 mj_kdl::update(&robot);
90
91 if (arrived) return;
92
93 double max_err = 0.0;
94 for (unsigned i = 0; i < n; ++i) {
95 double err = kTargetPose[i] - robot.jnt_pos_msr[i];
96 max_err = std::max(max_err, std::abs(err));
97 double vel = std::clamp(kKv * err, -kMaxVel, kMaxVel);
98 robot.jnt_pos_cmd[i] += vel * dt;
99 }
100
101 if (max_err < kTol) {
102 arrived = true;
103 for (unsigned i = 0; i < n; ++i) robot.jnt_pos_cmd[i] = robot.jnt_pos_msr[i];
104 }
105 };
106
107 if (headless) {
108 const double timeout = 5.0;
109 while (data->time < timeout && !arrived) {
110 ctrl_step();
111 mj_kdl::step(&robot);
112 }
113
114 double max_err = 0.0;
115 for (unsigned i = 0; i < n; ++i)
116 max_err = std::max(max_err, std::abs(kTargetPose[i] - robot.jnt_pos_msr[i]));
117 std::cout << "max joint error: " << std::fixed << std::setprecision(4) << max_err
118 << " rad (" << (arrived ? "converged" : "timeout") << ")\n";
119 } else {
120 mj_kdl::Viewer viewer;
121 if (!mj_kdl::init_window_sim(&viewer, &robot)) {
122 std::cerr << "init_window_sim() failed\n";
123 mj_kdl::cleanup(&robot);
124 mj_kdl::destroy_scene(model, data);
125 return 1;
126 }
127
128 double prev_sim_time = data->time;
129 while (true) {
130 if (data->time < prev_sim_time - 1e-6) mj_kdl::reset(&env);
131 prev_sim_time = data->time;
132 ctrl_step();
133 if (!mj_kdl::step(&robot)) break;
134 }
135
136 mj_kdl::cleanup(&viewer);
137 }
138
139 mj_kdl::cleanup(&robot);
140 mj_kdl::destroy_scene(model, data);
141 return 0;
142}
int main(int argc, char *argv[])
void env_add_robot(Env *env, Robot *robot)
ResetInfo reset(Env *env, const ResetOptions *options=nullptr)
bool step(Robot *s)
void cleanup(Robot *r)
bool init_robot_from_mjcf(Robot *r, mjModel *model, mjData *data, const char *base_body, const char *tip_body, const char *prefix="", const ToolFrameSpec *tool=nullptr)
void set_joint_pos(Robot *r, const KDL::JntArray &q, bool call_forward=true)
void update(Robot *r)
bool build_scene(mjModel **out_model, mjData **out_data, const SceneSpec *spec)
void destroy_scene(mjModel *model, mjData *data)
bool init_window_sim(Viewer *v, Robot *r, const char *title="MuJoCo")
std::string menagerie_model(const fs::path &relative)
ResetHook on_reset
std::vector< double > jnt_pos_msr
std::vector< double > jnt_pos_cmd
std::vector< RobotSpec > robots