Mujoco KDL Wrapper  0.2.2
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
ex_impedance.cpp
Go to the documentation of this file.
1/* ex_impedance.cpp
2 * Cartesian-impedance-like joint-space controller on Kinova GEN3 + Robotiq 2F-85.
3 *
4 * Control law (per joint):
5 * tau[i] = Kp[i]*(q_home[i] - q[i]) - Kd[i]*qdot[i] + g_kdl[i]
6 * where g_kdl is computed via KDL::ChainDynParam::JntToGravity (includes gripper inertia).
7 * Applied via TORQUE mode (qfrc_applied). The gripper cycles open and closed every 3 s.
8 *
9 * Requires MuJoCo Menagerie in cache.
10 *
11 * Usage:
12 * ex_impedance [--headless]
13 *
14 * With --headless runs 200 steps and prints EE drift. */
15
17#include "example_paths.hpp"
18
19#include <kdl/chaindynparam.hpp>
20#include <kdl/chainfksolverpos_recursive.hpp>
21
22#include <cmath>
23#include <iomanip>
24#include <iostream>
25#include <string>
26
27static constexpr double kHomePose[7] = { 0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708 };
28
29// Impedance gains - tuned for Gen3 joint sizes.
30static constexpr double kKp[7] = { 100, 200, 100, 200, 100, 200, 100 };
31static constexpr double kKd[7] = { 10, 20, 10, 20, 10, 20, 10 };
32
33
34int main(int argc, char *argv[])
35{
36 bool headless = false;
37 for (int i = 1; i < argc; ++i)
38 if (std::string(argv[i]) == "--headless") headless = true;
39
40 const std::string arm_mjcf = mj_kdl_examples::menagerie_model("kinova_gen3/gen3.xml");
41 const std::string grp_mjcf = mj_kdl_examples::asset("robotiq_2f85/2f85.xml");
42
44 gs.mjcf_path = grp_mjcf.c_str();
45 gs.attach_to = { mj_kdl::AttachKind::Site, "pinch_site" };
46 gs.prefix = "g_";
47
49 rs.path = arm_mjcf.c_str();
50 rs.attachments.push_back(gs);
51
53 sc.timestep = 0.002;
54 sc.add_floor = true;
55 sc.add_skybox = true;
56 sc.robots.push_back(rs);
57
58 mjModel *model = nullptr;
59 mjData *data = nullptr;
60 if (!mj_kdl::build_scene(&model, &data, &sc)) {
61 std::cerr << "build_scene() failed\n";
62 return 1;
63 }
64
66 tool.tool_body = "g_base";
67 tool.tcp_site = "g_pinch";
68
69 mj_kdl::Robot robot;
71 &robot, model, data, "base_link", "bracelet_link", "", &tool
72 )) {
73 std::cerr << "init_robot_from_mjcf() failed\n";
74 mj_kdl::destroy_scene(model, data);
75 return 1;
76 }
77
78 unsigned n = robot.chain.getNrOfJoints();
79 int fingers_act = mj_name2id(model, mjOBJ_ACTUATOR, "g_fingers_actuator");
80 int key_id = mj_name2id(model, mjOBJ_KEY, "home");
81
82 KDL::ChainDynParam dyn(robot.chain, KDL::Vector(0.0, 0.0, -9.81));
83 KDL::JntArray q_home(n), q(n), g(n);
84 for (unsigned i = 0; i < n; ++i) q_home(i) = kHomePose[i];
85
87
88 mj_kdl::Env env;
89 env.spec = sc;
90 env.model = model;
91 env.data = data;
92 mj_kdl::env_add_robot(&env, &robot);
93
94 mj_kdl::ResetOptions reset_opts;
95 reset_opts.use_keyframe = key_id >= 0;
96 reset_opts.keyframe = key_id >= 0 ? key_id : 0;
97
98 env.on_reset = [&](mj_kdl::ResetContext *ctx) {
99 if (key_id < 0) mj_kdl::set_joint_pos(&robot, q_home, false);
100 mjData *d = ctx->data;
101 if (fingers_act >= 0) d->ctrl[fingers_act] = 0.8;
102 };
103
104 mj_kdl::reset(&env, &reset_opts);
105
106 double prev_sim_time = data->time;
107
108 /*
109 * Per-step sequence:
110 * 1. update() -- refresh *_msr from current state and apply the previous command
111 * 2. Reset check -- if sim time went backward, zero torques and return
112 * 3. Compute jnt_trq_cmd from fresh *_msr
113 * 4. Set gripper ctrl
114 * 5. The next update() call applies the freshly computed jnt_trq_cmd.
115 */
116 auto step_impedance = [&]() {
117 mj_kdl::update(&robot); // refresh *_msr; previous jnt_trq_cmd is applied this step
118
119 if (data->time < prev_sim_time - 1e-6) {
120 // Simulation was reset: restore the home state and re-seed commands.
121 mj_kdl::reset(&env, &reset_opts);
122 prev_sim_time = data->time;
123 return;
124 }
125 prev_sim_time = data->time;
126
127 for (unsigned i = 0; i < n; ++i) q(i) = robot.jnt_pos_msr[i];
128 dyn.JntToGravity(q, g);
129 for (unsigned i = 0; i < n; ++i) {
130 robot.jnt_trq_cmd[i] =
131 kKp[i] * (kHomePose[i] - robot.jnt_pos_msr[i]) - kKd[i] * robot.jnt_vel_msr[i] + g(i);
132 }
133 data->ctrl[fingers_act] = (std::fmod(data->time, 6.0) < 3.0) ? 0.8 : 0.0;
134 };
135
136 if (headless) {
137 KDL::ChainFkSolverPos_recursive fk(robot.chain);
138 KDL::JntArray q0(n);
139 for (unsigned i = 0; i < n; ++i) q0(i) = robot.jnt_pos_cmd[i];
140 KDL::Frame ee_start;
141 fk.JntToCart(q0, ee_start);
142
143 for (int step = 0; step < 200; ++step) {
144 step_impedance();
145 mj_kdl::step(&robot);
146 }
147
148 KDL::JntArray q_end(n);
149 for (unsigned i = 0; i < n; ++i) q_end(i) = robot.jnt_pos_msr[i];
150 KDL::Frame ee_end;
151 fk.JntToCart(q_end, ee_end);
152 double drift = (ee_start.p - ee_end.p).Norm();
153 std::cout << "EE drift after 200 steps: " << std::fixed << std::setprecision(3)
154 << drift * 1000.0 << " mm\n";
155 } else {
156 mj_kdl::Viewer viewer;
157 if (!mj_kdl::init_window_sim(&viewer, &robot)) {
158 std::cerr << "init_window_sim() failed\n";
159 mj_kdl::cleanup(&robot);
160 mj_kdl::destroy_scene(model, data);
161 return 1;
162 }
163
164 while (true) {
165 step_impedance();
166 if (!mj_kdl::step(&robot)) break;
167 }
168
169 mj_kdl::cleanup(&viewer);
170 }
171
172 mj_kdl::cleanup(&robot);
173 mj_kdl::destroy_scene(model, data);
174 return 0;
175}
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 asset(const fs::path &relative)
std::string menagerie_model(const fs::path &relative)
ResetHook on_reset
std::vector< AttachmentSpec > attachments
std::vector< double > jnt_pos_msr
std::vector< double > jnt_pos_cmd
std::vector< double > jnt_vel_msr
std::vector< double > jnt_trq_cmd
std::vector< RobotSpec > robots