Skip to content

Commit 6d0638c

Browse files
authored
Merge pull request #206 from ManifoldFR/topic/restore-pin3-python-tests
[tests/python] Restore Pinocchio 3 tests, add check for Pinocchio features from Python
2 parents 92f171d + a644ea4 commit 6d0638c

File tree

7 files changed

+79
-45
lines changed

7 files changed

+79
-45
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Templated getters `getCost<U>()` and `getDynamics<U>()` in the StageModel class, and another `getDynamics<U>()` for integrator classes, to get the concrete types ([##205](https://github.com/Simple-Robotics/aligator/pull/205))
13+
- python: Add helper `aligator.has_pinocchio_features()` ([#206](https://github.com/Simple-Robotics/aligator/pull/206))
1314

1415
### Changed
1516

1617
- All map types are now `boost::unordered_map` ([#203](https://github.com/Simple-Robotics/aligator/pull/203))
1718

19+
### Fixed
20+
21+
- Restore Pinocchio 3 Python tests ([#206](https://github.com/Simple-Robotics/aligator/pull/206))
22+
1823
## [0.8.0] - 2024-09-18
1924

2025
### Added

bindings/python/src/module.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ BOOST_PYTHON_MODULE(MODULE_NAME) {
8181
bp::import("warnings");
8282
bp::import("proxsuite_nlp");
8383

84+
bp::def(
85+
"has_pinocchio_features",
86+
+[]() constexpr -> bool {
87+
return
88+
#ifdef ALIGATOR_WITH_PINOCCHIO
89+
true;
90+
#else
91+
false;
92+
#endif
93+
},
94+
"Whether Aligator (and its Python bindings) were compiled with support "
95+
"for Pinocchio.");
96+
8497
exposeContainers();
8598
exposeGAR();
8699
exposeEnums();

tests/python/CMakeLists.txt

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,20 @@ file(
1010
if(NOT BUILD_CROCODDYL_COMPAT)
1111
list(REMOVE_ITEM PYTHON_TESTS test_compat_croc.py)
1212
endif()
13-
if(NOT BUILD_WITH_PINOCCHIO_PYTHON_BINDINGS)
14-
list(REMOVE_ITEM PYTHON_TESTS test_constrained_dynamics.py)
13+
if(NOT BUILD_WITH_PINOCCHIO_SUPPORT)
14+
list(REMOVE_ITEM PYTHON_TESTS test_center_of_mass.py)
1515
list(REMOVE_ITEM PYTHON_TESTS test_frames.py)
16+
list(REMOVE_ITEM PYTHON_TESTS test_rollout.py)
17+
endif()
18+
if(NOT PINOCCHIO_V3)
19+
list(REMOVE_ITEM PYTHON_TESTS test_constrained_dynamics.py)
1620
endif()
17-
# TODO Add tests when Pinocchio 3 is released
18-
list(REMOVE_ITEM PYTHON_TESTS test_center_of_mass.py)
19-
list(REMOVE_ITEM PYTHON_TESTS test_constrained_dynamics.py)
20-
list(REMOVE_ITEM PYTHON_TESTS test_finite_diff.py)
21-
list(REMOVE_ITEM PYTHON_TESTS test_frames.py)
22-
list(REMOVE_ITEM PYTHON_TESTS test_rollout.py)
2321
make_directory(${CMAKE_CURRENT_BINARY_DIR})
2422

2523
foreach(pyfile ${PYTHON_TESTS})
2624
get_filename_component(test_name ${pyfile} NAME_WE)
2725
string(REGEX REPLACE "^test_" "${PROJECT_NAME}-test-py-" test_name ${test_name})
28-
string(REGEX REPLACE "_" "-" test_name ${test_name})
26+
string(REPLACE "_" "-" test_name ${test_name})
2927
execute_process(
3028
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${pyfile}
3129
${CMAKE_CURRENT_BINARY_DIR}/${pyfile}

tests/python/test_center_of_mass.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
model = pin.buildSampleModelHumanoid()
1313
rdata: pin.Data = model.createData()
1414
np.random.seed(0)
15-
FD_EPS = 1e-8
16-
THRESH = 2 * FD_EPS**0.5
15+
EPS = 1e-7
16+
ATOL = 2 * EPS**0.5
1717

1818
nq = model.nq
1919
nv = model.nv
@@ -55,7 +55,7 @@ def test_com_placement():
5555
assert J.shape == realJ.shape
5656
assert np.allclose(fdata.Jx[:, :nv], realJ)
5757

58-
fun_fd = aligator.FiniteDifferenceHelper(space, fun, FD_EPS)
58+
fun_fd = aligator.FiniteDifferenceHelper(space, fun, EPS)
5959
fdata2 = fun_fd.createData()
6060
fun_fd.evaluate(x0, u0, x0, fdata2)
6161
assert np.allclose(fdata.value, fdata2.value)
@@ -70,7 +70,7 @@ def test_com_placement():
7070
fun.computeJacobians(x0, u0, x0, fdata)
7171
fun_fd.evaluate(x0, u0, x0, fdata2)
7272
fun_fd.computeJacobians(x0, u0, x0, fdata2)
73-
assert np.allclose(fdata.Jx, fdata2.Jx, THRESH)
73+
assert np.allclose(fdata.Jx, fdata2.Jx, ATOL)
7474

7575

7676
def test_frame_velocity():
@@ -94,7 +94,7 @@ def test_frame_velocity():
9494

9595
fun.computeJacobians(x0, fdata)
9696

97-
fun_fd = aligator.FiniteDifferenceHelper(space, fun, FD_EPS)
97+
fun_fd = aligator.FiniteDifferenceHelper(space, fun, EPS)
9898
fdata2 = fun_fd.createData()
9999
fun_fd.evaluate(x0, u0, x0, fdata2)
100100
fun_fd.computeJacobians(x0, u0, x0, fdata2)
@@ -110,7 +110,7 @@ def test_frame_velocity():
110110
print(fdata.Jx)
111111
print(fdata2.Jx)
112112
print(fdata.Jx)
113-
assert np.allclose(fdata.Jx, fdata2.Jx, THRESH)
113+
assert np.allclose(fdata.Jx, fdata2.Jx, ATOL)
114114

115115

116116
if __name__ == "__main__":

tests/python/test_continuous_dynamics.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
import numpy as np
77
import aligator
88
from aligator import dynamics, manifolds
9-
from pinocchio import Quaternion
9+
from eigenpy import Quaternion
1010
from utils import finite_diff, infNorm, create_multibody_ode
1111

1212
epsilon = 1e-6
1313
aligator.seed(42)
1414
np.random.seed(42)
15+
HAS_PINOCCHIO = aligator.has_pinocchio_features()
1516

1617

1718
class MyODE(dynamics.ODEAbstract):
@@ -71,6 +72,9 @@ def test_custom_ode():
7172
assert len(xs) == 11
7273

7374

75+
@pytest.mark.skipif(
76+
not HAS_PINOCCHIO, reason="Aligator was compiled without Pinocchio."
77+
)
7478
def test_multibody_free():
7579
ode = create_multibody_ode(True)
7680
if ode is None:
@@ -304,6 +308,9 @@ def test_continuous_centroidal_diff():
304308
assert np.allclose(Judiff, Ju0, epsilon), "err={}".format(infNorm(Judiff - Ju0))
305309

306310

311+
@pytest.mark.skipif(
312+
not HAS_PINOCCHIO, reason="Aligator was compiled without Pinocchio."
313+
)
307314
def test_kinodynamics():
308315
import pinocchio as pin
309316

@@ -337,6 +344,9 @@ def test_kinodynamics():
337344
ode.dForward(x0, u0, data)
338345

339346

347+
@pytest.mark.skipif(
348+
not HAS_PINOCCHIO, reason="Aligator was compiled without Pinocchio."
349+
)
340350
def test_kinodynamics_diff():
341351
import pinocchio as pin
342352

tests/python/test_finite_diff.py

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,19 @@
55
ControlBoxFunction,
66
StateErrorResidual,
77
manifolds,
8+
has_pinocchio_features,
89
)
910
import numpy as np
11+
import pytest
12+
13+
# Attempt importing Pinocchio at least. Then, check if the Python module
14+
# has Pinocchio features.
15+
try:
16+
import pinocchio as pin
17+
18+
HAS_PINOCCHIO = has_pinocchio_features()
19+
except ImportError:
20+
HAS_PINOCCHIO = False
1021

1122

1223
def test_compute_jac_vs():
@@ -31,32 +42,30 @@ def test_compute_jac_vs():
3142
assert np.allclose(fdata1.Jy, fdata1b.Jy, 1e-2)
3243

3344

45+
@pytest.mark.skipif(
46+
not HAS_PINOCCHIO, reason="Aligator was compiled without Pinocchio."
47+
)
3448
def test_compute_jac_multibody():
35-
try:
36-
import pinocchio as pin
37-
38-
model = pin.buildSampleModelHumanoid()
39-
space = manifolds.MultibodyConfiguration(model)
40-
nu = 3
41-
x_tar = space.neutral()
42-
fun2 = StateErrorResidual(space, nu, x_tar)
43-
fdata2 = fun2.createData()
44-
fun2_fd = FiniteDifferenceHelper(space, fun2, 1e-6)
45-
fdata2b = fun2_fd.createData()
46-
for i in range(1000):
47-
x0 = pin.randomConfiguration(model, -np.ones(model.nq), np.ones(model.nq))
48-
u0 = 0.6 * np.ones(nu)
49-
fun2.evaluate(x0, u0, x0, fdata2)
50-
fun2_fd.evaluate(x0, u0, x0, fdata2b)
51-
assert np.allclose(fdata2.value, fdata2b.value, 1e-2)
52-
fun2.computeJacobians(x0, u0, x0, fdata2)
53-
fun2_fd.computeJacobians(x0, u0, x0, fdata2b)
54-
assert np.allclose(fdata2.Jx, fdata2b.Jx, 1e-2)
55-
assert np.allclose(fdata2.Ju, fdata2b.Ju, 1e-2)
56-
assert np.allclose(fdata2.Jy, fdata2b.Jy, 1e-2)
57-
return
58-
except ImportError:
59-
pass
49+
model = pin.buildSampleModelHumanoid()
50+
space = manifolds.MultibodyConfiguration(model)
51+
nu = 3
52+
x_tar = space.neutral()
53+
fun2 = StateErrorResidual(space, nu, x_tar)
54+
fdata2 = fun2.createData()
55+
fun2_fd = FiniteDifferenceHelper(space, fun2, 1e-6)
56+
fdata2b = fun2_fd.createData()
57+
for i in range(1000):
58+
x0 = pin.randomConfiguration(model, -np.ones(model.nq), np.ones(model.nq))
59+
u0 = 0.6 * np.ones(nu)
60+
fun2.evaluate(x0, u0, x0, fdata2)
61+
fun2_fd.evaluate(x0, u0, x0, fdata2b)
62+
assert np.allclose(fdata2.value, fdata2b.value, 1e-2)
63+
fun2.computeJacobians(x0, u0, x0, fdata2)
64+
fun2_fd.computeJacobians(x0, u0, x0, fdata2b)
65+
assert np.allclose(fdata2.Jx, fdata2b.Jx, 1e-2)
66+
assert np.allclose(fdata2.Ju, fdata2b.Ju, 1e-2)
67+
assert np.allclose(fdata2.Jy, fdata2b.Jy, 1e-2)
68+
return
6069

6170

6271
def test_compute_cost_se3():
@@ -80,7 +89,6 @@ def test_compute_cost_se3():
8089

8190

8291
if __name__ == "__main__":
83-
import pytest
8492
import sys
8593

8694
sys.exit(pytest.main(sys.argv))

tests/python/test_frames.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""
2-
Test function related to frames.
2+
Test function related to Pinocchio frames.
3+
This test is not added to CTest when CMake does not detect Pinocchio.
34
"""
45

56
import aligator
@@ -165,7 +166,7 @@ def test_fly_high():
165166
fr_name1 = "larm_shoulder2_body"
166167
fr_id1 = model.getFrameId(fr_name1)
167168
space = manifolds.MultibodyPhaseSpace(model)
168-
fun = aligator.FlyHighResidual(space, fr_id1, 0.1, nu)
169+
fun = aligator.FlyHighResidual(space.ndx, model, fr_id1, 0.1, nu)
169170
data = fun.createData()
170171
data2 = fun.createData()
171172
Jx_nd = data.Jx.copy()
@@ -194,4 +195,3 @@ def test_fly_high():
194195
import pytest
195196

196197
sys.exit(pytest.main(sys.argv))
197-
# test_frame_placement()

0 commit comments

Comments
 (0)