tinyrobotics
Loading...
Searching...
No Matches
Dynamics.hpp
Go to the documentation of this file.
1#ifndef TR_DYNAMICS_HPP
2#define TR_DYNAMICS_HPP
3
4#include <Eigen/Core>
5#include <Eigen/Dense>
6#include <Eigen/Geometry>
7
8#include "Kinematics.hpp"
9#include "Model.hpp"
10
14namespace tinyrobotics {
15
23 template <typename Scalar, int nq>
24 Eigen::Matrix<Scalar, nq, nq> mass_matrix(Model<Scalar, nq>& m, const Eigen::Matrix<Scalar, nq, 1>& q) {
25 // First pass
26 for (int i = 0; i < nq; i++) {
27 // Get transform from body to parent
28 Eigen::Transform<Scalar, 3, Eigen::Isometry> T =
29 m.links[m.q_idx[i]].joint.get_parent_to_child_transform(q(i));
30 // Compute the spatial transform from the parent to the current body
31 m.data.Xup[i] = homogeneous_to_spatial(T.inverse());
32 m.data.IC[i] = m.links[m.q_idx[i]].I;
33 }
34
35 // Second pass
36 for (int i = nq - 1; i >= 0; i--) {
37 if (m.parent[i] != -1) {
38 m.data.IC[m.parent[i]] =
39 m.data.IC[m.parent[i]] + m.data.Xup[i].transpose() * m.data.IC[i] * m.data.Xup[i];
40 }
41 }
42
43 // Third pass
44 m.data.mass_matrix.setZero();
45 for (int i = 0; i < nq; i++) {
46 m.data.fh = m.data.IC[i] * m.links[m.q_idx[i]].joint.S;
47 m.data.mass_matrix(i, i) = m.links[m.q_idx[i]].joint.S.transpose() * m.data.fh;
48 int j = i;
49 while (m.parent[j] > -1) {
50 m.data.fh = m.data.Xup[j].transpose() * m.data.fh;
51 j = m.parent[j];
52 m.data.mass_matrix(i, j) = m.links[m.q_idx[j]].joint.S.transpose() * m.data.fh;
53 m.data.mass_matrix(j, i) = m.data.mass_matrix(i, j);
54 }
55 }
56
57 return m.data.mass_matrix;
58 }
59
66 template <typename Scalar, int nq>
68 const Eigen::Matrix<Scalar, nq, 1>& q,
69 const Eigen::Matrix<Scalar, nq, 1>& dq) {
70
71 // Compute the mass matrix
72 mass_matrix<Scalar, nq>(m, q);
73 // Compute the kinetic energy
74 m.data.kinetic_energy = 0.5 * dq.transpose() * m.data.mass_matrix * dq;
75 return m.data.kinetic_energy;
76 }
77
85 template <typename Scalar, int nq>
86 Scalar potential_energy(Model<Scalar, nq>& m, const Eigen::Matrix<Scalar, nq, 1>& q) {
87 // Reset the potential energy
88 m.data.potential_energy = 0;
89 // Compute the potential energy
90 for (int i = 0; i < m.n_links; i++) {
91 // Compute the contribution to the potential energy of the link
92 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hbi_c =
93 forward_kinematics_com<Scalar, nq>(m, q, m.base_link_idx, m.links[i].idx);
94 Eigen::Matrix<Scalar, 3, 1> rMIi_c = Hbi_c.translation();
95 m.data.potential_energy += -m.links[i].mass * m.gravity.transpose() * rMIi_c;
96 }
97 return m.data.potential_energy;
98 }
99
108 template <typename Scalar, int nq>
110 const Eigen::Matrix<Scalar, nq, 1>& q,
111 const Eigen::Matrix<Scalar, nq, 1>& dq) {
112 // Compute the kinetic energy
113 kinetic_energy(m, q, dq);
114
115 // Compute the potential energy
116 potential_energy(m, q);
117
118 // Compute and return the total energy (kinetic + potential)
119 return m.data.kinetic_energy + m.data.potential_energy;
120 }
121
130 template <typename Scalar, int nq>
131 std::vector<Eigen::Matrix<Scalar, 6, 1>> apply_external_forces(
132 const Model<Scalar, nq>& m,
133 const std::vector<Eigen::Matrix<Scalar, 6, 6>>& Xup,
134 const std::vector<Eigen::Matrix<Scalar, 6, 1>>& f_in,
135 const std::vector<Eigen::Matrix<Scalar, 6, 1>>& f_ext) {
136 std::vector<Eigen::Matrix<Scalar, 6, 1>> f_out(nq, Eigen::Matrix<Scalar, 6, 1>::Zero());
137 std::vector<Eigen::Matrix<Scalar, 6, 6>> Xa(nq, Eigen::Matrix<Scalar, 6, 6>::Zero());
138
139 f_out = f_in;
140 for (int i = 0; i < nq; i++) {
141 const auto link = m.links[m.q_idx[i]];
142 if (m.parent[i] == -1) {
143 Xa[i] = Xup[i];
144 }
145 else {
146 Xa[i] = Xup[i] * Xa[m.parent[i]];
147 }
148 f_out[i] += Xa[i].transpose().inverse() * f_ext[i];
149 }
150 return f_out;
151 }
152
162 template <typename Scalar, int nq>
163 Eigen::Matrix<Scalar, nq, 1> forward_dynamics(Model<Scalar, nq>& m,
164 const Eigen::Matrix<Scalar, nq, 1>& q,
165 const Eigen::Matrix<Scalar, nq, 1>& qd,
166 const Eigen::Matrix<Scalar, nq, 1>& tau,
167 const std::vector<Eigen::Matrix<Scalar, 6, 1>>& f_ext = {}) {
168
169 // First pass: compute the spatial acceleration of each body
170 for (int i = 0; i < nq; i++) {
171 // Compute the joint transform and motion subspace matrices
172 m.links[m.q_idx[i]].joint.S = m.links[m.q_idx[i]].joint.S;
173 Eigen::Matrix<Scalar, 6, 1> vJ = m.links[m.q_idx[i]].joint.S * qd(i);
174 // Get transform from body to parent
175 m.data.T = m.links[m.q_idx[i]].joint.get_parent_to_child_transform(q(i));
176 // Compute the spatial transform from the parent to the current body
177 m.data.Xup[i] = homogeneous_to_spatial(m.data.T.inverse());
178 // Check if the m.parent link is the base link
179 if (m.parent[i] == -1) {
180 m.data.v[i] = vJ;
181 m.data.c[i] = Eigen::Matrix<Scalar, 6, 1>::Zero();
182 }
183 else {
184 m.data.v[i] = m.data.Xup[i] * m.data.v[m.parent[i]] + vJ;
185 m.data.c[i] = cross_spatial(m.data.v[i]) * vJ;
186 }
187 m.data.IA[i] = m.links[m.q_idx[i]].I;
188 m.data.pA[i] = cross_motion(m.data.v[i]) * m.data.IA[i] * m.data.v[i];
189 }
190
191 // Apply external forces if non-zero
192 if (f_ext.size() != 0) {
193 m.data.pA = apply_external_forces(m, m.data.Xup, m.data.pA, f_ext);
194 }
195
196 // Second pass: compute the spatial force acting on each body
197 for (int i = nq - 1; i >= 0; i--) {
198 m.data.U[i] = m.data.IA[i] * m.links[m.q_idx[i]].joint.S;
199 m.data.d[i] = m.links[m.q_idx[i]].joint.S.transpose() * m.data.U[i];
200 m.data.u[i] = Scalar(tau(i) - m.links[m.q_idx[i]].joint.S.transpose() * m.data.pA[i]);
201 if (m.parent[i] != -1) {
202 Eigen::Matrix<Scalar, 6, 6> Ia = m.data.IA[i] - (m.data.U[i] / m.data.d[i]) * m.data.U[i].transpose();
203 Eigen::Matrix<Scalar, 6, 1> pa =
204 m.data.pA[i] + Ia * m.data.c[i] + m.data.U[i] * (m.data.u[i] / m.data.d[i]);
205 m.data.IA[m.parent[i]] += m.data.Xup[i].transpose() * Ia * m.data.Xup[i];
206 m.data.pA[m.parent[i]] += m.data.Xup[i].transpose() * pa;
207 }
208 }
209
210 // Third pass: compute the joint accelerations
211 for (int i = 0; i < nq; i++) {
212 if (m.parent[i] == -1) {
213 m.data.a[i] = m.data.Xup[i] * -m.data.spatial_gravity + m.data.c[i];
214 }
215 else {
216 m.data.a[i] = m.data.Xup[i] * m.data.a[m.parent[i]] + m.data.c[i];
217 }
218 m.data.ddq(i) = (m.data.u[i] - m.data.U[i].transpose() * m.data.a[i]) / m.data.d[i];
219 m.data.a[i] = m.data.a[i] + m.links[m.q_idx[i]].joint.S * m.data.ddq(i);
220 }
221 return m.data.ddq;
222 }
223
233 template <typename Scalar, int nq>
234 Eigen::Matrix<Scalar, nq, 1> forward_dynamics_crb(Model<Scalar, nq>& m,
235 const Eigen::Matrix<Scalar, nq, 1>& q,
236 const Eigen::Matrix<Scalar, nq, 1>& qd,
237 const Eigen::Matrix<Scalar, nq, 1>& tau,
238 const std::vector<Eigen::Matrix<Scalar, 6, 1>>& f_ext = {}) {
239 // First pass
240 for (int i = 0; i < nq; i++) {
241 // Compute the joint transform and motion subspace matrices
242 Eigen::Matrix<Scalar, 6, 1> vJ = m.links[m.q_idx[i]].joint.S * qd(i);
243 // Get transform from body to parent
244 Eigen::Transform<Scalar, 3, Eigen::Isometry> T =
245 m.links[m.q_idx[i]].joint.get_parent_to_child_transform(q(i));
246 // Compute the spatial transform from the parent to the current body
247 m.data.Xup[i] = homogeneous_to_spatial(T.inverse());
248 // Check if the m.parent link is the base link
249 if (m.parent[i] == -1) {
250 m.data.v[i] = vJ;
251 m.data.avp[i] = m.data.Xup[i] * -m.data.spatial_gravity;
252 }
253 else {
254 m.data.v[i] = m.data.Xup[i] * m.data.v[m.parent[i]] + vJ;
255 m.data.avp[i] = m.data.Xup[i] * m.data.avp[m.parent[i]] + cross_spatial(m.data.v[i]) * vJ;
256 }
257 m.data.fvp[i] =
258 m.links[m.q_idx[i]].I * m.data.avp[i] + cross_motion(m.data.v[i]) * m.links[m.q_idx[i]].I * m.data.v[i];
259 m.data.IC[i] = m.links[m.q_idx[i]].I;
260 }
261
262 // Apply external forces if non-zero
263 if (f_ext.size() != 0) {
264 m.data.fvp = apply_external_forces(m, m.data.Xup, m.data.pA, f_ext);
265 }
266
267 // Second pass
268 for (int i = nq - 1; i >= 0; i--) {
269 m.data.C(i, 0) = m.links[m.q_idx[i]].joint.S.transpose() * m.data.fvp[i];
270 if (m.parent[i] != -1) {
271 m.data.fvp[m.parent[i]] = m.data.fvp[m.parent[i]] + m.data.Xup[i].transpose() * m.data.fvp[i];
272 }
273 }
274
275 // Third pass
276 for (int i = nq - 1; i >= 0; i--) {
277 if (m.parent[i] != -1) {
278 m.data.IC[m.parent[i]] =
279 m.data.IC[m.parent[i]] + m.data.Xup[i].transpose() * m.data.IC[i] * m.data.Xup[i];
280 }
281 }
282
283 for (int i = 0; i < nq; i++) {
284 m.data.fh = m.data.IC[i] * m.links[m.q_idx[i]].joint.S;
285 m.data.mass_matrix(i, i) = m.links[m.q_idx[i]].joint.S.transpose() * m.data.fh;
286 int j = i;
287 while (m.parent[j] != -1) {
288 m.data.fh = m.data.Xup[j].transpose() * m.data.fh;
289 j = m.parent[j];
290 m.data.mass_matrix(i, j) = m.links[m.q_idx[j]].joint.S.transpose() * m.data.fh;
291 m.data.mass_matrix(j, i) = m.data.mass_matrix(i, j);
292 }
293 }
294
295 // Compute qdd with inverse mass using LDLT
296 Eigen::Matrix<Scalar, nq, 1> qdd = m.data.mass_matrix.ldlt().solve(tau - m.data.C);
297
298 return qdd;
299 }
300
309 template <typename Scalar, int nq>
310 Eigen::Matrix<Scalar, nq, 1> inverse_dynamics(Model<Scalar, nq>& m,
311 const Eigen::Matrix<Scalar, nq, 1>& q,
312 const Eigen::Matrix<Scalar, nq, 1>& qd,
313 const Eigen::Matrix<Scalar, nq, 1>& qdd,
314 const std::vector<Eigen::Matrix<Scalar, 6, 1>>& f_ext = {}) {
315 // First pass
316 for (int i = 0; i < nq; i++) {
317 // Compute the joint transform and motion subspace matrices
318 m.links[m.q_idx[i]].joint.S = m.links[m.q_idx[i]].joint.S;
319 Eigen::Matrix<Scalar, 6, 1> vJ = m.links[m.q_idx[i]].joint.S * qd(i);
320 // Get transform from body to parent
321 Eigen::Transform<Scalar, 3, Eigen::Isometry> T =
322 m.links[m.q_idx[i]].joint.get_parent_to_child_transform(q(i));
323 // Compute the spatial transform from the parent to the current body
324 m.data.Xup[i] = homogeneous_to_spatial(T.inverse());
325 // Check if the m.parent link is the base link
326 if (m.parent[i] == -1) {
327 m.data.v[i] = vJ;
328 m.data.a[i] = m.data.Xup[i] * -m.data.spatial_gravity + m.links[m.q_idx[i]].joint.S * qdd(i);
329 }
330 else {
331 m.data.v[i] = m.data.Xup[i] * m.data.v[m.parent[i]] + vJ;
332 m.data.a[i] = m.data.Xup[i] * m.data.a[m.parent[i]] + m.links[m.q_idx[i]].joint.S * qdd(i)
333 + cross_spatial(m.data.v[i]) * vJ;
334 }
335 m.data.fvp[i] =
336 m.links[m.q_idx[i]].I * m.data.a[i] + cross_motion(m.data.v[i]) * m.links[m.q_idx[i]].I * m.data.v[i];
337 }
338
339 // Apply external forces if non-zero
340 if (f_ext.size() != 0) {
341 m.data.fvp = apply_external_forces(m, m.data.Xup, m.data.pA, f_ext);
342 }
343
344 // Second pass
345 for (int i = nq - 1; i >= 0; i--) {
346 m.data.tau(i, 0) = m.links[m.q_idx[i]].joint.S.transpose() * m.data.fvp[i];
347 if (m.parent[i] != -1) {
348 m.data.fvp[m.parent[i]] = m.data.fvp[m.parent[i]] + m.data.Xup[i].transpose() * m.data.fvp[i];
349 }
350 }
351 return m.data.tau;
352 }
353
354} // namespace tinyrobotics
355
356#endif
Eigen::Matrix< Scalar, nq, 1 > forward_dynamics(Model< Scalar, nq > &m, const Eigen::Matrix< Scalar, nq, 1 > &q, const Eigen::Matrix< Scalar, nq, 1 > &qd, const Eigen::Matrix< Scalar, nq, 1 > &tau, const std::vector< Eigen::Matrix< Scalar, 6, 1 > > &f_ext={})
Compute the forward dynamics of the tinyrobotics model via Articulated-Body Algorithm.
Definition: Dynamics.hpp:163
Scalar total_energy(Model< Scalar, nq > &m, const Eigen::Matrix< Scalar, nq, 1 > &q, const Eigen::Matrix< Scalar, nq, 1 > &dq)
Compute the total energy of the tinyrobotics model.
Definition: Dynamics.hpp:109
Scalar kinetic_energy(Model< Scalar, nq > &m, const Eigen::Matrix< Scalar, nq, 1 > &q, const Eigen::Matrix< Scalar, nq, 1 > &dq)
Compute the kinetic_energy of the tinyrobotics model.
Definition: Dynamics.hpp:67
Scalar potential_energy(Model< Scalar, nq > &m, const Eigen::Matrix< Scalar, nq, 1 > &q)
Compute the potential_energy of the tinyrobotics model.
Definition: Dynamics.hpp:86
Eigen::Matrix< Scalar, nq, 1 > forward_dynamics_crb(Model< Scalar, nq > &m, const Eigen::Matrix< Scalar, nq, 1 > &q, const Eigen::Matrix< Scalar, nq, 1 > &qd, const Eigen::Matrix< Scalar, nq, 1 > &tau, const std::vector< Eigen::Matrix< Scalar, 6, 1 > > &f_ext={})
Compute the forward dynamics of the tinyrobotics model via Composite-Rigid-Body Algorithm.
Definition: Dynamics.hpp:234
Eigen::Matrix< Scalar, nq, nq > mass_matrix(Model< Scalar, nq > &m, const Eigen::Matrix< Scalar, nq, 1 > &q)
Compute the mass matrix of the tinyrobotics model.
Definition: Dynamics.hpp:24
std::vector< Eigen::Matrix< Scalar, 6, 1 > > apply_external_forces(const Model< Scalar, nq > &m, const std::vector< Eigen::Matrix< Scalar, 6, 6 > > &Xup, const std::vector< Eigen::Matrix< Scalar, 6, 1 > > &f_in, const std::vector< Eigen::Matrix< Scalar, 6, 1 > > &f_ext)
Apply external forces to the tinyrobotics model.
Definition: Dynamics.hpp:131
Eigen::Matrix< Scalar, nq, 1 > inverse_dynamics(Model< Scalar, nq > &m, const Eigen::Matrix< Scalar, nq, 1 > &q, const Eigen::Matrix< Scalar, nq, 1 > &qd, const Eigen::Matrix< Scalar, nq, 1 > &qdd, const std::vector< Eigen::Matrix< Scalar, 6, 1 > > &f_ext={})
Compute the inverse dynamics of a tinyrobotics model.
Definition: Dynamics.hpp:310
Contains functions for computing various kinematic quantities of a tinyrobotics model.
Eigen::Matrix< Scalar, 6, 6 > homogeneous_to_spatial(const Eigen::Transform< Scalar, 3, Eigen::Isometry > &H)
Spatial coordinate transform from homogeneous transformation matrix.
Definition: Math.hpp:110
Eigen::Matrix< Scalar, 6, 6 > cross_motion(const Eigen::Matrix< Scalar, 6, 1 > &v)
Computes the 6x6 cross-product matrix for a motion vector and a force vector.
Definition: Math.hpp:70
Eigen::Matrix< Scalar, 6, 6 > cross_spatial(const Eigen::Matrix< Scalar, 6, 1 > &v)
Computes the 6x6 cross-product matrix for a 6D spatial vector.
Definition: Math.hpp:56
Contains struct for representing a tinyrobotics model.
A tinyrobotics model.
Definition: Model.hpp:30
std::vector< int > parent
Vector of parent link indices of the links which are non-fixed.
Definition: Model.hpp:56
int n_links
Number of links in the model.
Definition: Model.hpp:35
Data< Scalar, nq > data
Stores the results of the models algorithms.
Definition: Model.hpp:65
Eigen::Matrix< Scalar, 3, 1 > gravity
Gravitational acceleration experienced by model.
Definition: Model.hpp:59
int base_link_idx
Index of the base link in the models links vector.
Definition: Model.hpp:50
std::vector< int > q_idx
Vector of indices of links in the models link vector that have a non-fixed joint.
Definition: Model.hpp:53
std::vector< Link< Scalar > > links
Vector of links in the model.
Definition: Model.hpp:44