Skip to content

Commit 88e46f1

Browse files
committed
Friction compensation
1 parent 9a6f223 commit 88e46f1

File tree

9 files changed

+188
-4
lines changed

9 files changed

+188
-4
lines changed

bindings/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set(
1313
expose-centroidal.cpp
1414
expose-fulldynamics.cpp
1515
expose-kinodynamics.cpp
16+
expose-friction-compensation.cpp
1617
)
1718

1819
Python3_add_library(${PY_NAME}_pywrap MODULE WITH_SOABI ${${PY_NAME}_SOURCES})
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// BSD 2-Clause License
3+
//
4+
// Copyright (C) 2025, INRIA
5+
// Copyright note valid unless otherwise stated in individual files.
6+
// All rights reserved.
7+
///////////////////////////////////////////////////////////////////////////////
8+
9+
#include <eigenpy/eigenpy.hpp>
10+
#include <pinocchio/multibody/fwd.hpp>
11+
12+
#include "simple-mpc/friction-compensation.hpp"
13+
14+
namespace simple_mpc
15+
{
16+
namespace python
17+
{
18+
namespace bp = boost::python;
19+
20+
void exposeFrictionCompensation()
21+
{
22+
bp::class_<FrictionCompensation>(
23+
"FrictionCompensation", bp::init<const Model &, const long>(bp::args("self", "model", "actuation_size")))
24+
.def("computeFriction", &FrictionCompensation::computeFriction)
25+
.add_property("corrected_torque", &FrictionCompensation::corrected_torque_)
26+
.add_property("dry_friction", &FrictionCompensation::dry_friction_)
27+
.add_property("viscuous_friction", &FrictionCompensation::viscuous_friction_);
28+
}
29+
30+
} // namespace python
31+
} // namespace simple_mpc

bindings/module.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace simple_mpc::python
1717
void exposeMPC();
1818
void exposeIDSolver();
1919
void exposeIKIDSolver();
20+
void exposeFrictionCompensation();
2021

2122
/* PYTHON MODULE */
2223
BOOST_PYTHON_MODULE(simple_mpc_pywrap)
@@ -35,6 +36,7 @@ namespace simple_mpc::python
3536
exposeMPC();
3637
exposeIDSolver();
3738
exposeIKIDSolver();
39+
exposeFrictionCompensation();
3840
}
3941

4042
} // namespace simple_mpc::python

examples/go2_fulldynamics.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import numpy as np
22
from bullet_robot import BulletRobot
3-
from simple_mpc import RobotModelHandler, RobotDataHandler, FullDynamicsOCP, MPC, IDSolver
3+
from simple_mpc import RobotModelHandler, RobotDataHandler, FullDynamicsOCP, MPC, IDSolver, FrictionCompensation
44
import example_robot_data as erd
55
import pinocchio as pin
66
import time
@@ -21,6 +21,9 @@
2121
model_handler.addFoot("RR_foot", base_joint_name, pin.XYZQUATToSE3(np.array([-0.24,-0.15, 0.0, 0,0,0,1])))
2222
data_handler = RobotDataHandler(model_handler)
2323

24+
nq = model_handler.getModel().nq
25+
nv = model_handler.getModel().nv
26+
nu = nv - 6
2427
force_size = 3
2528
nk = len(model_handler.getFeetNames())
2629
gravity = np.array([0, 0, -9.81])
@@ -140,6 +143,9 @@
140143

141144
qp = IDSolver(id_conf, model_handler.getModel())
142145

146+
""" Friction """
147+
fcompensation = FrictionCompensation(model_handler.getModel(), nu)
148+
143149
""" Initialize simulation"""
144150
device = BulletRobot(
145151
model_handler.getModel().names,
@@ -270,9 +276,10 @@
270276
mpc.getDataHandler().getData().M,
271277
)
272278

273-
device.execute(qp.solved_torque)
279+
fcompensation.computeFriction(x_interp[nq + 6:], qp.solved_torque)
280+
device.execute(fcompensation.corrected_torque)
274281

275-
u_multibody.append(copy.deepcopy(qp.solved_torque))
282+
u_multibody.append(copy.deepcopy(fcompensation.corrected_torque))
276283
x_multibody.append(x_measured)
277284

278285
force_FL = np.array(force_FL)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// BSD 2-Clause License
3+
//
4+
// Copyright (C) 2025, INRIA
5+
// Copyright note valid unless otherwise stated in individual files.
6+
// All rights reserved.
7+
///////////////////////////////////////////////////////////////////////////////
8+
#pragma once
9+
10+
#include <pinocchio/fwd.hpp>
11+
// Include pinocchio first
12+
#include <Eigen/Dense>
13+
14+
#include "simple-mpc/fwd.hpp"
15+
#include <pinocchio/multibody/model.hpp>
16+
17+
namespace simple_mpc
18+
{
19+
using namespace pinocchio;
20+
21+
/**
22+
* @brief Class managing the friction compensation for torque
23+
*
24+
* It applies a compensation term to a torque depending on dry and
25+
* viscuous frictions.
26+
*/
27+
class FrictionCompensation
28+
{
29+
public:
30+
/**
31+
* @brief Construct a new Friction Compensation object
32+
*
33+
* @param actuation_size Dimension of torque
34+
*/
35+
FrictionCompensation(const Model & model, const long actuation_size);
36+
37+
/**
38+
* @brief Compute the torque correction due to friction and store it internally.
39+
*
40+
* @param[in] velocity Joint velocity
41+
* @param[in] torque Joint torque
42+
*/
43+
void computeFriction(const Eigen::VectorXd & velocity, const Eigen::VectorXd & torque);
44+
45+
// Sign function for internal computation
46+
static double signFunction(double x);
47+
48+
// Internal torque with friction compensation
49+
Eigen::VectorXd corrected_torque_;
50+
51+
// Friction coefficients
52+
Eigen::VectorXd dry_friction_;
53+
Eigen::VectorXd viscuous_friction_;
54+
};
55+
56+
} // namespace simple_mpc

include/simple-mpc/fwd.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace simple_mpc
3838
class OCPHandler;
3939
class IDSolver;
4040
class IKIDSolver;
41+
class FrictionCompensation;
4142

4243
/// EIGEN TYPEDEFS
4344

src/friction-compensation.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "simple-mpc/friction-compensation.hpp"
2+
3+
namespace simple_mpc
4+
{
5+
6+
FrictionCompensation::FrictionCompensation(const Model & model, const long actuation_size)
7+
{
8+
corrected_torque_.resize(actuation_size);
9+
dry_friction_ = model.lowerDryFrictionLimit;
10+
viscuous_friction_ = model.damping;
11+
}
12+
13+
void FrictionCompensation::computeFriction(const Eigen::VectorXd & velocity, const Eigen::VectorXd & torque)
14+
{
15+
if (velocity.size() != corrected_torque_.size())
16+
{
17+
throw std::runtime_error("Velocity has wrong size");
18+
}
19+
if (torque.size() != corrected_torque_.size())
20+
{
21+
throw std::runtime_error("Torque has wrong size");
22+
}
23+
corrected_torque_ = torque + viscuous_friction_.cwiseProduct(velocity)
24+
+ dry_friction_.cwiseProduct(velocity.unaryExpr(std::function(signFunction)));
25+
}
26+
27+
double FrictionCompensation::signFunction(double x)
28+
{
29+
if (x > 0)
30+
return 1.0;
31+
else if (x == 0)
32+
return 0.0;
33+
else
34+
return -1.0;
35+
}
36+
37+
} // namespace simple_mpc

tests/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,14 @@ function(add_aligator_test name)
4949
_add_test_prototype(${name} "" ${PROJECT_NAME})
5050
endfunction()
5151

52-
set(TEST_NAMES robot_handler problem mpc lowlevel)
52+
set(
53+
TEST_NAMES
54+
robot_handler
55+
problem
56+
mpc
57+
lowlevel
58+
friction
59+
)
5360

5461
foreach(test_name ${TEST_NAMES})
5562
add_aligator_test(${test_name})

tests/friction.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
#include <boost/test/unit_test.hpp>
3+
4+
#include "simple-mpc/friction-compensation.hpp"
5+
#include "test_utils.cpp"
6+
7+
BOOST_AUTO_TEST_SUITE(friction)
8+
9+
using namespace simple_mpc;
10+
11+
BOOST_AUTO_TEST_CASE(dry_viscuous_friction)
12+
{
13+
Model model;
14+
15+
const std::string urdf_path = EXAMPLE_ROBOT_DATA_MODEL_DIR "/solo_description/robots/solo12.urdf";
16+
17+
pinocchio::urdf::buildModel(urdf_path, JointModelFreeFlyer(), model);
18+
long nu = 12;
19+
model.lowerDryFrictionLimit = Eigen::VectorXd::Constant(nu, .5);
20+
model.damping = Eigen::VectorXd::Constant(nu, .05);
21+
22+
FrictionCompensation friction = FrictionCompensation(model, nu);
23+
24+
BOOST_CHECK_EQUAL(model.lowerDryFrictionLimit, friction.dry_friction_);
25+
BOOST_CHECK_EQUAL(model.damping, friction.viscuous_friction_);
26+
27+
Eigen::VectorXd velocity = Eigen::VectorXd::Random(nu);
28+
Eigen::VectorXd torque = Eigen::VectorXd::Random(nu);
29+
30+
friction.computeFriction(velocity, torque);
31+
32+
Eigen::VectorXd ctorque(nu);
33+
for (long i = 0; i < nu; i++)
34+
{
35+
double sgn = (velocity[i] > 0) - (velocity[i] < 0);
36+
ctorque[i] = torque[i] + model.lowerDryFrictionLimit[i] * sgn + model.damping[i] * velocity[i];
37+
}
38+
39+
BOOST_CHECK(friction.corrected_torque_.isApprox(ctorque));
40+
}
41+
42+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)