Skip to content

Commit af4d74d

Browse files
committed
State and linear interpolators
1 parent 983e6f7 commit af4d74d

File tree

5 files changed

+158
-80
lines changed

5 files changed

+158
-80
lines changed

bindings/expose-interpolate.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,34 @@ namespace simple_mpc
1717
{
1818
namespace bp = boost::python;
1919

20-
void exposeInterpolator()
20+
Eigen::VectorXd stateInterpolateProxy(
21+
StateInterpolator & self, const double delay, const double timestep, const std::vector<Eigen::VectorXd> xs)
2122
{
22-
bp::class_<Interpolator>(
23-
"Interpolator", bp::init<const long, const long, const long, const long, const double>(
24-
bp::args("self", "nx", "nv", "nu", "nu", "MPC_timestep")))
25-
.def("interpolate", &Interpolator::interpolate)
26-
.add_property("MPC_timestep", &Interpolator::MPC_timestep_)
27-
.add_property("x_interpolated", &Interpolator::x_interpolated_)
28-
.add_property("u_interpolated", &Interpolator::u_interpolated_)
29-
.add_property("a_interpolated", &Interpolator::a_interpolated_)
30-
.add_property("forces_interpolated", &Interpolator::forces_interpolated_)
31-
.add_property("step_nb", &Interpolator::step_nb_)
32-
.add_property("step_progress", &Interpolator::step_progress_);
23+
Eigen::VectorXd x_interp(xs[0].size());
24+
self.interpolate(delay, timestep, xs, x_interp);
25+
26+
return x_interp;
27+
}
28+
29+
Eigen::VectorXd linearInterpolateProxy(
30+
LinearInterpolator & self, const double delay, const double timestep, const std::vector<Eigen::VectorXd> xs)
31+
{
32+
Eigen::VectorXd x_interp(xs[0].size());
33+
self.interpolate(delay, timestep, xs, x_interp);
34+
35+
return x_interp;
36+
}
37+
38+
void exposeStateInterpolator()
39+
{
40+
bp::class_<StateInterpolator>("StateInterpolator", bp::init<const Model &>(bp::args("self", "model")))
41+
.def("interpolate", &stateInterpolateProxy);
42+
}
43+
44+
void exposeLinearInterpolator()
45+
{
46+
bp::class_<LinearInterpolator>("LinearInterpolator", bp::init<const size_t>(bp::args("self", "vec_size")))
47+
.def("interpolate", &linearInterpolateProxy);
3348
}
3449

3550
} // namespace python

examples/go2_fulldynamics.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import numpy as np
22
from bullet_robot import BulletRobot
3-
from simple_mpc import RobotModelHandler, RobotDataHandler, FullDynamicsOCP, MPC, IDSolver, Interpolator
3+
from simple_mpc import (
4+
RobotModelHandler,
5+
RobotDataHandler,
6+
FullDynamicsOCP,
7+
MPC,
8+
IDSolver,
9+
StateInterpolator,
10+
LinearInterpolator
11+
)
412
import example_robot_data as erd
513
import pinocchio as pin
614
import time
@@ -146,7 +154,10 @@
146154
qp = IDSolver(id_conf, model_handler.getModel())
147155

148156
""" Interpolation """
149-
interpolator = Interpolator(nq + nv, nv, nu, nf, dt)
157+
state_interpolator = StateInterpolator(model_handler.getModel())
158+
acc_interpolator = LinearInterpolator(model_handler.getModel().nv)
159+
u_interpolator = LinearInterpolator(nu)
160+
force_interpolator = LinearInterpolator(nf)
150161

151162
""" Initialize simulation"""
152163
device = BulletRobot(
@@ -257,24 +268,28 @@
257268

258269
for j in range(N_simu):
259270
# time.sleep(0.01)
260-
interpolator.interpolate(j / float(N_simu), xss, uss, ddqs, forces)
271+
delay = j / float(N_simu)
272+
x_interp = state_interpolator.interpolate(delay, dt, xss)
273+
u_interp = u_interpolator.interpolate(delay, dt, uss)
274+
acc_interp = acc_interpolator.interpolate(delay, dt, ddqs)
275+
force_interp = force_interpolator.interpolate(delay, dt, forces)
261276

262277
q_meas, v_meas = device.measureState()
263278
x_measured = np.concatenate([q_meas, v_meas])
264279

265280
mpc.getDataHandler().updateInternalData(x_measured, True)
266281

267-
current_torque = interpolator.u_interpolated - 1. * mpc.Ks[0] @ model_handler.difference(
268-
x_measured, interpolator.x_interpolated
282+
current_torque = u_interp - 1. * mpc.Ks[0] @ model_handler.difference(
283+
x_measured, x_interp
269284
)
270285

271286
qp.solveQP(
272287
mpc.getDataHandler().getData(),
273288
contact_states,
274289
x_measured[nq:],
275-
interpolator.a_interpolated,
290+
acc_interp,
276291
current_torque,
277-
interpolator.forces_interpolated,
292+
force_interp,
278293
mpc.getDataHandler().getData().M,
279294
)
280295

include/simple-mpc/interpolator.hpp

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,40 @@
1414
#define SIMPLE_MPC_INTERPOLATOR_HPP_
1515

1616
#include "simple-mpc/fwd.hpp"
17+
#include "simple-mpc/model-utils.hpp"
1718

1819
namespace simple_mpc
1920
{
20-
class Interpolator
21+
class StateInterpolator
2122
{
2223
public:
23-
explicit Interpolator(const long nx, const long nv, const long nu, const long nf, const double MPC_timestep);
24+
explicit StateInterpolator(const Model & model);
2425

2526
void interpolate(
2627
const double delay,
27-
std::vector<Eigen::VectorXd> xs,
28-
std::vector<Eigen::VectorXd> us,
29-
std::vector<Eigen::VectorXd> ddqs,
30-
std::vector<Eigen::VectorXd> forces);
28+
const double timestep,
29+
const std::vector<Eigen::VectorXd> xs,
30+
Eigen::Ref<Eigen::VectorXd> x_interp);
3131

32-
// Interpolated trajectories
33-
Eigen::VectorXd x_interpolated_;
34-
Eigen::VectorXd u_interpolated_;
35-
Eigen::VectorXd a_interpolated_;
36-
Eigen::VectorXd forces_interpolated_;
32+
// Intermediate differential configuration
33+
Eigen::VectorXd diff_q_;
3734

38-
// Timestep of trajectories
39-
double MPC_timestep_;
35+
// Pinocchio model
36+
Model model_;
37+
};
38+
39+
class LinearInterpolator
40+
{
41+
public:
42+
explicit LinearInterpolator(const size_t vec_size);
4043

41-
// Time knot associated with current delay
42-
size_t step_nb_;
44+
void interpolate(
45+
const double delay,
46+
const double timestep,
47+
const std::vector<Eigen::VectorXd> vecs,
48+
Eigen::Ref<Eigen::VectorXd> vec_interp);
4349

44-
// Interpolation time between two knots
45-
double step_progress_;
50+
size_t vec_size_;
4651
};
4752
} // namespace simple_mpc
4853

src/interpolator.cpp

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,59 @@
1010
namespace simple_mpc
1111
{
1212

13-
Interpolator::Interpolator(const long nx, const long nv, const long nu, const long nf, const double MPC_timestep)
14-
: MPC_timestep_(MPC_timestep)
13+
StateInterpolator::StateInterpolator(const Model & model)
1514
{
16-
x_interpolated_.resize(nx);
17-
u_interpolated_.resize(nu);
18-
a_interpolated_.resize(nv);
19-
forces_interpolated_.resize(nf);
15+
model_ = model;
16+
diff_q_.resize(model_.nv);
2017
}
2118

22-
void Interpolator::interpolate(
19+
void StateInterpolator::interpolate(
2320
const double delay,
24-
std::vector<Eigen::VectorXd> xs,
25-
std::vector<Eigen::VectorXd> us,
26-
std::vector<Eigen::VectorXd> ddqs,
27-
std::vector<Eigen::VectorXd> forces)
21+
const double timestep,
22+
const std::vector<Eigen::VectorXd> xs,
23+
Eigen::Ref<Eigen::VectorXd> x_interp)
2824
{
2925
// Compute the time knot corresponding to the current delay
30-
step_nb_ = static_cast<size_t>(delay / MPC_timestep_);
31-
step_progress_ = (delay - (double)step_nb_ * MPC_timestep_) / MPC_timestep_;
26+
size_t step_nb = static_cast<size_t>(delay / timestep);
27+
double step_progress = (delay - (double)step_nb * timestep) / timestep;
3228

3329
// Interpolate state and command trajectories
34-
if (step_nb_ >= xs.size() - 1)
30+
if (step_nb >= xs.size() - 1)
31+
x_interp = xs[step_nb];
32+
else
3533
{
36-
step_nb_ = xs.size() - 1;
37-
step_progress_ = 0.0;
38-
x_interpolated_ = xs[step_nb_];
39-
u_interpolated_ = us[step_nb_];
40-
a_interpolated_ = ddqs[step_nb_];
41-
forces_interpolated_ = forces[step_nb_];
34+
// Compute the differential between configuration
35+
diff_q_ = pinocchio::difference(model_, xs[step_nb].head(model_.nq), xs[step_nb + 1].head(model_.nq));
36+
37+
pinocchio::integrate(model_, xs[step_nb].head(model_.nq), diff_q_ * step_progress, x_interp.head(model_.nq));
38+
39+
// Compute velocity interpolation
40+
x_interp.tail(model_.nv) =
41+
xs[step_nb + 1].tail(model_.nv) * step_progress + xs[step_nb].tail(model_.nv) * (1. - step_progress);
4242
}
43+
}
44+
45+
LinearInterpolator::LinearInterpolator(const size_t vec_size)
46+
{
47+
vec_size_ = vec_size;
48+
}
49+
50+
void LinearInterpolator::interpolate(
51+
const double delay,
52+
const double timestep,
53+
const std::vector<Eigen::VectorXd> vecs,
54+
Eigen::Ref<Eigen::VectorXd> vec_interp)
55+
{
56+
// Compute the time knot corresponding to the current delay
57+
size_t step_nb = static_cast<size_t>(delay / timestep);
58+
double step_progress = (delay - (double)step_nb * timestep) / timestep;
59+
60+
// Interpolate state and command trajectories
61+
if (step_nb >= vecs.size() - 1)
62+
vec_interp = vecs[step_nb];
4363
else
4464
{
45-
x_interpolated_ = xs[step_nb_ + 1] * step_progress_ + xs[step_nb_] * (1. - step_progress_);
46-
u_interpolated_ = us[step_nb_ + 1] * step_progress_ + us[step_nb_] * (1. - step_progress_);
47-
a_interpolated_ = ddqs[step_nb_ + 1] * step_progress_ + ddqs[step_nb_] * (1. - step_progress_);
48-
forces_interpolated_ = forces[step_nb_ + 1] * step_progress_ + forces[step_nb_] * (1. - step_progress_);
65+
vec_interp = vecs[step_nb + 1] * step_progress + vecs[step_nb] * (1. - step_progress);
4966
}
5067
}
5168

tests/interpolator.cpp

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,60 @@ using namespace simple_mpc;
1010

1111
BOOST_AUTO_TEST_CASE(interpolate)
1212
{
13-
long nx = 27;
14-
long nu = 12;
15-
long nv = 18;
16-
long nf = 12;
17-
double MPC_timestep = 0.01;
18-
Interpolator interpolator = Interpolator(nx, nv, nu, nf, MPC_timestep);
13+
Model model;
14+
// Load pinocchio model from example robot data
15+
const std::string urdf_path = EXAMPLE_ROBOT_DATA_MODEL_DIR "/solo_description/robots/solo12.urdf";
16+
const std::string srdf_path = EXAMPLE_ROBOT_DATA_MODEL_DIR "/solo_description/srdf/solo.srdf";
17+
18+
pinocchio::urdf::buildModel(urdf_path, JointModelFreeFlyer(), model);
19+
double timestep = 0.01;
20+
StateInterpolator interpolator = StateInterpolator(model);
1921

2022
std::vector<Eigen::VectorXd> xs;
21-
std::vector<Eigen::VectorXd> us;
22-
std::vector<Eigen::VectorXd> ddqs;
23-
std::vector<Eigen::VectorXd> forces;
2423
for (std::size_t i = 0; i < 4; i++)
2524
{
26-
xs.push_back(Eigen::Vector<double, 27>::Random());
27-
us.push_back(Eigen::Vector<double, 12>::Random());
28-
ddqs.push_back(Eigen::Vector<double, 18>::Random());
29-
forces.push_back(Eigen::Vector<double, 12>::Random());
25+
Eigen::VectorXd x0(model.nq + model.nv);
26+
x0.tail(model.nv).setRandom();
27+
x0.head(model.nq) = pinocchio::neutral(model);
28+
Eigen::VectorXd dq(model.nv);
29+
dq.setRandom();
30+
pinocchio::integrate(model, x0.head(model.nq), dq, x0.head(model.nq));
31+
32+
xs.push_back(x0);
33+
}
34+
double delay = 0.02;
35+
36+
Eigen::VectorXd x_interp(model.nq + model.nv);
37+
interpolator.interpolate(delay, timestep, xs, x_interp);
38+
39+
BOOST_CHECK(xs[2].isApprox(x_interp));
40+
}
41+
42+
BOOST_AUTO_TEST_CASE(linear_interpolate)
43+
{
44+
Model model;
45+
// Load pinocchio model from example robot data
46+
const std::string urdf_path = EXAMPLE_ROBOT_DATA_MODEL_DIR "/solo_description/robots/solo12.urdf";
47+
const std::string srdf_path = EXAMPLE_ROBOT_DATA_MODEL_DIR "/solo_description/srdf/solo.srdf";
48+
49+
pinocchio::urdf::buildModel(urdf_path, JointModelFreeFlyer(), model);
50+
double timestep = 0.01;
51+
LinearInterpolator interpolator = LinearInterpolator((size_t)model.nv);
52+
53+
std::vector<Eigen::VectorXd> vs;
54+
for (std::size_t i = 0; i < 4; i++)
55+
{
56+
Eigen::VectorXd v0(model.nv);
57+
v0.setRandom();
58+
59+
vs.push_back(v0);
3060
}
3161
double delay = 0.02;
3262

33-
interpolator.interpolate(delay, xs, us, ddqs, forces);
63+
Eigen::VectorXd v_interp(model.nv);
64+
interpolator.interpolate(delay, timestep, vs, v_interp);
3465

35-
BOOST_CHECK(xs[2].isApprox(interpolator.x_interpolated_));
36-
BOOST_CHECK(us[2].isApprox(interpolator.u_interpolated_));
37-
BOOST_CHECK(ddqs[2].isApprox(interpolator.a_interpolated_));
38-
BOOST_CHECK(forces[2].isApprox(interpolator.forces_interpolated_));
39-
BOOST_CHECK(interpolator.step_nb_ == 2);
40-
BOOST_CHECK(interpolator.step_progress_ == 0.);
66+
BOOST_CHECK(vs[2].isApprox(v_interp));
4167
}
4268

4369
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)