Skip to content

Commit 2ba2b05

Browse files
author
ipuch
committed
feat(model-graph): ellipsoid
1 parent 82f56b2 commit 2ba2b05

File tree

7 files changed

+115
-41
lines changed

7 files changed

+115
-41
lines changed

bindings/python/parsers/graph/expose-edges.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ namespace pinocchio
111111
.def_readonly("nq", &JointSphericalZYX::nq, "Number of configuration variables.")
112112
.def_readonly("nv", &JointSphericalZYX::nv, "Number of tangent variables.");
113113

114+
bp::class_<JointEllipsoid>(
115+
"JointEllipsoid", "Represents an ellipsoidal joint.",
116+
bp::init<>(bp::args("self"), "Default constructor."))
117+
.def_readonly("nq", &JointEllipsoid::nq, "Number of configuration variables.")
118+
.def_readonly("nv", &JointEllipsoid::nv, "Number of tangent variables.");
119+
114120
bp::class_<JointTranslation>(
115121
"JointTranslation", "Represents a translation joint.",
116122
bp::init<>(bp::args("self"), "Default constructor."))

include/pinocchio/parsers/graph/graph-visitor.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ namespace pinocchio
113113
return joint_calc(JointModelSphericalZYX());
114114
}
115115

116+
SE3 operator()(const JointEllipsoid &) const
117+
{
118+
return joint_calc(JointModelEllipsoid());
119+
}
120+
116121
SE3 operator()(const JointPlanar &) const
117122
{
118123
return joint_calc(JointModelPlanar());

include/pinocchio/parsers/graph/joints.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,29 @@ namespace pinocchio
161161
}
162162
};
163163

164+
struct JointEllipsoid
165+
{
166+
double radius_a = 0.01;
167+
double radius_b = 0.01;
168+
double radius_c = 0.01;
169+
170+
static constexpr int nq = 3;
171+
static constexpr int nv = 3;
172+
173+
JointEllipsoid() = default;
174+
JointEllipsoid(const double r_a, const double r_b, const double r_c)
175+
: radius_a(r_a)
176+
, radius_b(r_b)
177+
, radius_c(r_c)
178+
{
179+
}
180+
181+
bool operator==(const JointEllipsoid & other) const
182+
{
183+
return radius_a == other.radius_a && radius_b == other.radius_b && radius_c == other.radius_c;
184+
}
185+
};
186+
164187
struct JointTranslation
165188
{
166189
static constexpr int nq = 3;
@@ -241,6 +264,7 @@ namespace pinocchio
241264
JointFreeFlyer,
242265
JointSpherical,
243266
JointSphericalZYX,
267+
JointEllipsoid,
244268
JointTranslation,
245269
JointPlanar,
246270
JointHelical,

src/parsers/graph/model-graph-algo.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ namespace pinocchio
9090
// Joint Spherical ZYX
9191
typedef typename JointCollectionDefault::JointModelSphericalZYX JointModelSphericalZYX;
9292

93+
// Joint Ellipsoid
94+
typedef typename JointCollectionDefault::JointModelEllipsoid JointModelEllipsoid;
95+
9396
// Joint Translation
9497
typedef typename JointCollectionDefault::JointModelTranslation JointModelTranslation;
9598

@@ -221,6 +224,10 @@ namespace pinocchio
221224
{
222225
return JointModelSphericalZYX();
223226
}
227+
ReturnType operator()(const JointEllipsoid & joint) const
228+
{
229+
return JointModelEllipsoid(joint.radius_a, joint.radius_b, joint.radius_c);
230+
}
224231
ReturnType operator()(const JointUniversal & joint) const
225232
{
226233
return JointModelUniversal(joint.axis1, joint.axis2);
@@ -338,6 +345,29 @@ namespace pinocchio
338345
model.addBodyFrame(target_vertex.name, j_id, body_pose);
339346
}
340347

348+
void operator()(const JointEllipsoid & joint, const BodyFrame & b_f)
349+
{
350+
if (!edge.forward)
351+
PINOCCHIO_THROW_PRETTY(std::invalid_argument, "Graph - JointEllipsoid cannot be reversed yet.");
352+
353+
if (boost::get<BodyFrame>(&source_vertex.frame) == nullptr)
354+
PINOCCHIO_THROW_PRETTY(
355+
std::invalid_argument, "Graph - Invalid joint between a body and a non body frame.");
356+
357+
const SE3 & joint_pose = edge.source_to_joint;
358+
const SE3 & body_pose = edge.joint_to_target;
359+
360+
const Frame previous_body = model.frames[model.getFrameId(source_vertex.name, BODY)];
361+
JointIndex j_id = model.addJoint(
362+
previous_body.parentJoint,
363+
cjm(joint),
364+
previous_body.placement * joint_pose, edge.name);
365+
366+
model.addJointFrame(j_id);
367+
model.appendBodyToJoint(j_id, b_f.inertia); // check this
368+
model.addBodyFrame(target_vertex.name, j_id, body_pose);
369+
}
370+
341371
void operator()(const JointFixed & joint, const BodyFrame & b_f)
342372
{
343373
// Need to check what's vertex the edge is coming from. If it's a body, then we add

src/parsers/graph/model-graph.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ namespace pinocchio
6565
{
6666
return {JointSphericalZYX(), SE3::Identity()};
6767
}
68+
ReturnType operator()(const JointEllipsoid &) const
69+
{
70+
return {JointEllipsoid(), SE3::Identity()};
71+
}
6872
ReturnType operator()(const JointTranslation &) const
6973
{
7074
return {JointTranslation(), SE3::Identity()};

unittest/joint-ellipsoid.cpp

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,14 @@ BOOST_AUTO_TEST_CASE(vsSphericalZYX)
277277

278278
// Get the motion subspace matrices (which give us the Jacobians)
279279
JointModelSphericalZYX jmodel_s;
280-
jmodel_s.setIndexes(0, 0, 0); // Set indices for standalone joint
280+
jmodel_s.setIndexes(0, 0, 0);
281281

282282
JointDataSphericalZYX jdata_s = jmodel_s.createData();
283283
jmodel_s.calc(jdata_s, q_s);
284284

285285
JointModelEllipsoid jmodel_e(0, 0, 0);
286-
jmodel_e.setIndexes(0, 0, 0); // Set indices for standalone joint
287-
286+
jmodel_e.setIndexes(0, 0, 0);
287+
288288
JointDataEllipsoid jdata_e = jmodel_e.createData();
289289
jmodel_e.calc(jdata_e, q_e);
290290

@@ -317,56 +317,35 @@ BOOST_AUTO_TEST_CASE(vsSphericalZYX)
317317
forwardKinematics(modelEllipsoid, dataEllipsoid, q_e, qd_e);
318318

319319
// Getting S with q_e from the three calcs
320-
// Note: jmodel_e already has indices set from earlier
321-
JointDataEllipsoid jdata_e_fk = jmodel_e.createData();
322-
JointDataEllipsoid jdata_e_fk2 = jmodel_e.createData();
323-
JointDataEllipsoid jdata_e_fk3 = jmodel_e.createData();
324-
325-
jmodel_e.calc(jdata_e_fk, q_e, qd_e);
320+
JointDataEllipsoid jDataEllipsoidFK = jmodel_e.createData();
321+
JointDataEllipsoid jDataEllipsoidFK2 = jmodel_e.createData();
322+
JointDataEllipsoid jDataEllipsoidFK3 = jmodel_e.createData();
326323

327-
jmodel_e.calc(jdata_e_fk2, q_e);
324+
jmodel_e.calc(jDataEllipsoidFK, q_e, qd_e);
325+
jmodel_e.calc(jDataEllipsoidFK2, q_e);
326+
jmodel_e.calc(jDataEllipsoidFK3, q_e);
327+
jmodel_e.calc(jDataEllipsoidFK3, Blank(), qd_e);
328328

329-
jmodel_e.calc(jdata_e_fk3, q_e);
330-
jmodel_e.calc(jdata_e_fk3, Blank(), qd_e);
331-
332-
BOOST_CHECK(jdata_e_fk.S.matrix().isApprox(jdata_e_fk2.S.matrix()));
333-
BOOST_CHECK(jdata_e_fk.S.matrix().isApprox(jdata_e_fk3.S.matrix()));
329+
BOOST_CHECK(jDataEllipsoidFK.S.matrix().isApprox(jDataEllipsoidFK2.S.matrix()));
330+
BOOST_CHECK(jDataEllipsoidFK.S.matrix().isApprox(jDataEllipsoidFK3.S.matrix()));
334331
std::cout << "✓ Motion subspace matrices match for the three calc(...) methods" << std::endl;
335332

336-
JointDataSphericalZYX jdata_s_fk = jmodel_s.createData();
337-
jmodel_s.calc(jdata_s_fk, q_s, qd_s);
333+
JointDataSphericalZYX jDataSphereFK = jmodel_s.createData();
334+
jmodel_s.calc(jDataSphereFK, q_s, qd_s);
338335

339336
std::cout << "\n=== Joint-frame velocities (S * v) ===" << std::endl;
340-
std::cout << "idx_v() for standalone joint: " << jmodel_e.idx_v() << std::endl;
341-
std::cout << "qd_e: " << qd_e.transpose() << std::endl;
342-
std::cout << "jdata_e_fk.joint_v: " << jdata_e_fk.joint_v.transpose() << std::endl;
343-
Eigen::Matrix<double, 6, 1> joint_vel_e = jdata_e_fk.S.matrix() * qd_e;
344-
std::cout << "joint_vel_e (S * qd_e): " << joint_vel_e.transpose() << std::endl;
345-
std::cout << "jdata_e_fk.v (computed): " << jdata_e_fk.v.toVector().transpose() << std::endl;
346-
Eigen::Matrix<double, 6, 1> manual_vel = jdata_e_fk.S.matrix() * jdata_e_fk.joint_v;
347-
std::cout << "S * jdata_e_fk.joint_v: " << manual_vel.transpose() << std::endl;
348-
349-
Eigen::Matrix<double, 6, 1> joint_vel_s = jdata_s_fk.S.matrix() * qd_s;
350-
std::cout << "Ellipsoid (S_xyz * qd_e): " << joint_vel_e.transpose() << std::endl;
351-
std::cout << "SphericalZYX (S_zyx * qd_s): " << joint_vel_s.transpose() << std::endl;
352-
353-
std::cout << "\n=== Rotation Matrices ===" << std::endl;
354-
std::cout << "Ellipsoid rotation:\n" << dataEllipsoid.oMi[1].rotation() << std::endl;
355-
std::cout << "\nSphericalZYX rotation:\n" << dataSphericalZYX.oMi[1].rotation() << std::endl;
356-
357-
std::cout << "\n=== Translations ===" << std::endl;
358-
std::cout << "Ellipsoid translation: " << dataEllipsoid.oMi[1].translation().transpose() << std::endl;
359-
std::cout << "SphericalZYX translation: " << dataSphericalZYX.oMi[1].translation().transpose() << std::endl;
360-
361-
std::cout << "\n=== Spatial Velocities ===" << std::endl;
362-
std::cout << "Ellipsoid v:\n" << dataEllipsoid.v[1].toVector().transpose() << std::endl;
363-
std::cout << "SphericalZYX v:\n" << dataSphericalZYX.v[1].toVector().transpose() << std::endl;
337+
Eigen::Matrix<double, 6, 1> joint_vel_e = jDataEllipsoidFK.S.matrix() * qd_e;
338+
Eigen::Matrix<double, 6, 1> manual_vel = jDataEllipsoidFK.S.matrix() * jDataEllipsoidFK.joint_v;
339+
Eigen::Matrix<double, 6, 1> joint_vel_s = jDataSphereFK.S.matrix() * qd_s;
364340

365341
BOOST_CHECK(dataEllipsoid.v[1].toVector().isApprox(dataSphericalZYX.v[1].toVector()));
366342
std::cout << "✓ Spatial velocities match" << std::endl;
367343

368344
BOOST_CHECK(dataEllipsoid.oMi[1].isApprox(dataSphericalZYX.oMi[1]));
369345
std::cout << "✓ Full oMi[1] matches" << std::endl;
346+
347+
// TODO ACCELERATION
348+
370349
}
371350

372351
BOOST_AUTO_TEST_SUITE_END()

unittest/model-graph.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,32 @@ BOOST_AUTO_TEST_CASE(test_reverse_spherical_zyx)
617617
d_f.oMf[m_forward.getFrameId("body1", pinocchio::BODY)]));
618618
}
619619

620+
/// @brief test if reversing of a composite joint is correct.
621+
BOOST_AUTO_TEST_CASE(test_reverse_ellipsoid)
622+
{
623+
using namespace pinocchio::graph;
624+
625+
ModelGraph g = buildReversableModelGraph(JointEllipsoid());
626+
///////////////// Model
627+
BOOST_CHECK_THROW(buildModel(g, "body2", pinocchio::SE3::Identity()), std::invalid_argument);
628+
629+
//////////////////////////////////// Forward model
630+
pinocchio::Model m_forward = buildModel(g, "body1", pinocchio::SE3::Identity());
631+
pinocchio::Data d_f(m_forward);
632+
// config vector forward model Ellipsoid
633+
Eigen::Vector3d q(m_forward.nq);
634+
q << M_PI / 4, M_PI, M_PI / 2;
635+
pinocchio::framesForwardKinematics(m_forward, d_f, q);
636+
637+
cout << "Forward Ellipsoid oMf body2: \n"
638+
<< d_f.oMf[m_forward.getFrameId("body2", pinocchio::BODY)].matrix() << endl;
639+
BOOST_CHECK(d_f.oMf[m_forward.getFrameId("body2", pinocchio::BODY)].isApprox(
640+
// trouver une valeur à mettre dedans.
641+
// todo après manger :)
642+
));
643+
}
644+
645+
620646
/// @brief test if reversing of a composite joint is correct.
621647
BOOST_AUTO_TEST_CASE(test_reverse_composite)
622648
{

0 commit comments

Comments
 (0)