Dear,
I find the meaning of model.nq confusing in my c++ version of Pinocchio. I think that for a given robot model, the number of configurations should equal to the number of velocity variables. However, there exists discrepancies between these two numbers. For example, when I import a HRP2 robot model with pinocchio::urdf::buildModel method, ideally the DOFs should be (30 + 6 = 36). When I print the them, model.nq = 60 and model.nv = 30. The velocity seems to be understandable but I am not sure about what is the meaning of 60 in model.nq. Why this configuration number is twice the velocity number? Can you give me a hint about how to understand it?
Thanks,
Same ask.
This comes from complex joint, like 3d spherical joints and 6d free
flyer joints. These cases are the easier to understand. Part of the
joint configuration is a rotation, that is conveniently represented by a
quaternion (dimension 4) but only has 3 degrees of freedom. The velocity
of this joint is not represented by the derivative of the quaternion but
by the angular velocity (dimension 3). Then nq which contains a
quaternion has 1 more dimension dimension compared to nv which contains
an angular velocity.
For manipulator with simple revolute joints, nq=nv. In general, we have
nq>=nv. For the humanoid robot, we often have nq=nv+1 because we only
have the quaternion for the free flyer.
In addition to the increased dimension, the quaternion is also subject
to the constraint that it should be normalized. So randomly sampling a
configuration vector q does not work: you must also normalized q[3:7]
where the quaternion is stored. The method
pinocchio.randomConfiguration(model) does that for you, more generically.
We also cannot integrate q+=v or differentiate v=q1-q0.
pinocchio.integrate and pinocchio.differentiate are there for that.
N
Dear @ShihaoWang,
The question is indeed important. The idea is that you have Configuration vector of dimension nq, typically denoted by q and the Tangent vector of dimension nv, usually denoted by v and corresponds to velocity or acceleration vectors.
Then, in the context of spherical joint for instance, the idea in Pinocchio is to parametrize it using a Quaternion (a vector of dimension 4 having a norm of value 1) while then angular velocity is represented by a classic vector of dimension 3. You can see through this example that the configuration vector and the velocity vector do not have the same dimension.
We use quaternion to avoid singularities in the representation of the orientation.
So in the context of the free-flyer, it will be the same: the configuration vector will be represented by (x,y,z,quaternion) of dimension 7 and the spatial velocity will be represented by a vector of dimension.
In your precise context of HRP-2 (which is different from the model of LAAS), it seems that you have continuous joint representation for the revolute joints, while in our model of HRP-2 we are using classic revolute with bounds. Please see the URDF convention for that.
Woo, I've just seen that @nmansard also replies. So the two answers are related and complementary on some points.
Dear Justin and Nicolas,
Thank you very much your detailed explanations. It makes sense to me now why for an imported ATLAS robot, its model.nq is 30 and model.nv is 29, and for an imported TALOS robot, its model.nq is 32 so is its model.nv. After I manually change the joint type from continuous to revolute, my HRP2 model reports consistent numbers from model.nq and model.nv. Just to confirm that q[3:7] saves the information of the rotation, so does it mean that q[0:3] denotes the translation positions of the base link? (q[0]: x coordinate, q[1]: y coordinate, q[2]: z coordinate)?
Yes indeed. If you, there are some helpers functions in Python that you can replicate in C++ too.
pin.utils.XYZQUATToSe3 and pin.utils.se3ToXYZQUAT to transform one config vector into a SE3 element and vis-versa.
Hi @ShihaoWang, I have a small recommendation.
When you do
pinocchio::urdf::buildModel(filename, model);
the obtained model will NOT have the floating-base joint, as it is not in the URDF.
Instead, the robot will be considered as fixed-base, i.e. the base of the robot will be attached to the universe.
In other words, the configuration q will NOT contain the position and orientation of the base.
For a humanoid robot, normally what you want to do is
pinocchio::JointModelFreeFlyer root_joint;
pinocchio::urdf::buildModel(filename, root_joint, model);
which will add a JointModelFreeFlyer to represent the floating base.
The examples are in C++, but in Python the concept is the same.
I am saying this because you mentioned Talos having model.nq = model.nv = 32. From Talos, I expect model.nq = 39 and model.nv = 38. You can see the difference for nq is +7, while for nv it is +6.
Hi @gabrielebndn,
Yes, thanks for pointing this out clearly. With the introduction of the FreeFlyer into the humanoid model using the provided command pinocchio::JointModelFreeFlyer root_joint;, I got the same number of model.nq=39 and model.nv=38. This also matches my expectation.
Shihao
I will close now this issue. @ShihaoWang Feel free to reopen it if needed.
Most helpful comment
Hi @ShihaoWang, I have a small recommendation.
When you do
the obtained model will NOT have the floating-base joint, as it is not in the URDF.
Instead, the robot will be considered as fixed-base, i.e. the base of the robot will be attached to the universe.
In other words, the configuration
qwill NOT contain the position and orientation of the base.For a humanoid robot, normally what you want to do is
which will add a
JointModelFreeFlyerto represent the floating base.The examples are in C++, but in Python the concept is the same.
I am saying this because you mentioned Talos having
model.nq = model.nv = 32. From Talos, I expectmodel.nq = 39andmodel.nv = 38. You can see the difference fornqis +7, while fornvit is +6.