Mujoco KDL Wrapper  0.2.2
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
test_mjcf_vel_ctrl.cpp
Go to the documentation of this file.
1/* test_mjcf_vel_ctrl.cpp
2 * Joint velocity control on the Kinova GEN3 (MJCF).
3 *
4 * gen3.xml has high-gain position actuators (kp=2000, kv=100).
5 * Velocity control is implemented in POSITION mode by integrating the
6 * desired velocity into a position setpoint each step:
7 *
8 * vel_des[i] = clamp(Kv * (target[i] - q[i]), -maxVel, maxVel)
9 * pos_cmd[i] += vel_des[i] * dt
10 *
11 * The position servo tracks the advancing setpoint, making the joint
12 * follow the commanded velocity profile. */
13
15#include "example_paths.hpp"
16
17#include <gtest/gtest.h>
18
19#include <algorithm>
20#include <cmath>
21#include <filesystem>
22#include <string>
23
24static constexpr double kHomePose[7] = { 0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708 };
25static constexpr double kTargetPose[7] = { 0.3, 0.5, 2.9, -2.0, 0.3, 1.2, 1.3 };
26static constexpr double kKv = 2.0; // P gain [rad/s per rad error]
27static constexpr double kMaxVel = 0.6; // velocity clamp [rad/s]
28static constexpr double kTol = 0.02; // convergence tolerance [rad]
29static constexpr double kTimeout = 5.0; // max simulation time [s]
30
31namespace fs = std::filesystem;
32class MjcfVelCtrlTest : public testing::Test
33{
34 protected:
35 fs::path root_;
36 mjModel *model_ = nullptr;
37 mjData *data_ = nullptr;
39 unsigned n_ = 0;
40
41 void SetUp() override
42 {
43 std::string arm_mjcf = mj_kdl_examples::find_menagerie_model("kinova_gen3/gen3.xml");
44 if (!fs::exists(arm_mjcf)) {
45 GTEST_SKIP() << arm_mjcf << " not found";
46 return;
47 }
48
50 sc.timestep = 0.002;
51 sc.add_floor = true;
52 sc.add_skybox = true;
53 sc.robots.push_back(mj_kdl::RobotSpec{ .path = arm_mjcf.c_str(), .attachments = {} });
54
55 ASSERT_TRUE(mj_kdl::build_scene(&model_, &data_, &sc));
56 ASSERT_TRUE(mj_kdl::init_robot_from_mjcf(&s_, model_, data_, "base_link", "bracelet_link"));
57
58 n_ = static_cast<unsigned>(s_.n_joints);
59
60 KDL::JntArray q_home(n_);
61 for (unsigned i = 0; i < n_; ++i) q_home(i) = kHomePose[i];
62 mj_kdl::set_joint_pos(&s_, q_home);
63
64 // POSITION mode: initialise pos_cmd to home so the servo starts settled.
66 for (unsigned i = 0; i < n_; ++i) { s_.jnt_pos_cmd[i] = kHomePose[i]; }
68 }
69
70 void TearDown() override
71 {
72 if (model_) {
75 }
76 }
77};
78
80{
81 const double dt = model_->opt.timestep;
82 bool arrived = false;
83
84 while (data_->time < kTimeout && !arrived) {
85 mj_kdl::update(&s_); // reads sensors, applies prev pos_cmd to servo
86
87 double max_err = 0.0;
88 for (unsigned i = 0; i < n_; ++i) {
89 double err = kTargetPose[i] - s_.jnt_pos_msr[i];
90 max_err = std::max(max_err, std::abs(err));
91 double vel = std::clamp(kKv * err, -kMaxVel, kMaxVel);
92 s_.jnt_pos_cmd[i] += vel * dt; // integrate velocity into position setpoint
93 }
94
95 if (max_err < kTol) {
96 arrived = true;
97 // Freeze setpoint at current position to avoid overshoot.
98 for (unsigned i = 0; i < n_; ++i) s_.jnt_pos_cmd[i] = s_.jnt_pos_msr[i];
99 }
100
101 mj_kdl::step(&s_);
102 }
103
104 double max_err = 0.0;
105 for (unsigned i = 0; i < n_; ++i)
106 max_err = std::max(max_err, std::abs(kTargetPose[i] - s_.jnt_pos_msr[i]));
107
108 EXPECT_TRUE(arrived) << "velocity controller did not converge within " << kTimeout << " s";
109 EXPECT_LE(max_err, kTol * 2);
110}
111
112int main(int argc, char *argv[])
113{
114 testing::InitGoogleTest(&argc, argv);
115 return RUN_ALL_TESTS();
116}
void TearDown() override
void SetUp() override
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)
std::string find_menagerie_model(const fs::path &relative)
std::vector< RobotSpec > robots
int main(int argc, char *argv[])
TEST_F(MjcfVelCtrlTest, Convergence)