tinyrobotics
Loading...
Searching...
No Matches
Kinematics.hpp
Go to the documentation of this file.
1#ifndef TR_FORWARDKINEMATICS_HPP
2#define TR_FORWARDKINEMATICS_HPP
3
4#include <Eigen/Core>
5#include <Eigen/Geometry>
6
7#include "Math.hpp"
8#include "Model.hpp"
9
13namespace tinyrobotics {
14
25 template <typename Scalar, int nq, typename TargetLink>
26 const int get_link_idx(const Model<Scalar, nq>& model, const TargetLink& target_link) {
27 if constexpr (std::is_integral<TargetLink>::value) {
28 return static_cast<int>(target_link);
29 }
30 else if constexpr (std::is_same<TargetLink, std::string>::value) {
31 return model.get_link(target_link).idx;
32 }
33 else {
34 throw std::invalid_argument("Invalid target_link type. Must be int or std::string.");
35 }
36 }
37
46 template <typename Scalar, int nq>
47 std::vector<Eigen::Transform<Scalar, 3, Eigen::Isometry>> forward_kinematics(
48 Model<Scalar, nq>& model,
49 const Eigen::Matrix<Scalar, nq, 1>& q) {
50 model.data.forward_kinematics.resize(model.n_links, Eigen::Transform<Scalar, 3, Eigen::Isometry>::Identity());
51 for (auto const link : model.links) {
52 model.data.forward_kinematics[link.idx] = link.joint.parent_transform;
53 if (link.joint.idx != -1) {
54 model.data.forward_kinematics[link.idx] =
55 model.data.forward_kinematics[link.idx] * link.joint.get_joint_transform(q[link.joint.idx]);
56 }
57 if (link.parent != -1) {
58 model.data.forward_kinematics[link.idx] =
59 model.data.forward_kinematics[link.parent] * model.data.forward_kinematics[link.idx];
60 }
61 }
62 return model.data.forward_kinematics;
63 }
64
75 template <typename Scalar, int nq, typename TargetLink>
76 Eigen::Transform<Scalar, 3, Eigen::Isometry> forward_kinematics(const Model<Scalar, nq>& model,
77 const Eigen::Matrix<Scalar, nq, 1>& q,
78 const TargetLink& target_link) {
79 // Get the target link
80 const int target_link_idx = get_link_idx(model, target_link);
81 Link<Scalar> current_link = model.links[target_link_idx];
82
83 // Build kinematic tree from target_link {t} to base {b}
84 Eigen::Transform<Scalar, 3, Eigen::Isometry> Htb = Eigen::Transform<Scalar, 3, Eigen::Isometry>::Identity();
85 while (current_link.idx != model.base_link_idx) {
86 Eigen::Transform<Scalar, 3, Eigen::Isometry> H = Eigen::Transform<Scalar, 3, Eigen::Isometry>::Identity();
87 if (current_link.joint.idx != -1) {
88 // Transform the joint frame by joint value (Hpt)
89 H = current_link.joint.get_joint_transform(q[current_link.joint.idx]);
90 }
91 Htb = Htb * H.inverse();
92 // Apply inverse joint transform as we are going back up tree
93 Htb = Htb * current_link.joint.parent_transform.inverse();
94 // Move up the tree to parent link
95 current_link = model.links[current_link.parent];
96 }
97 // Return transform Hbt, which is transform from base {b} to target {t}
98 return Htb.inverse();
99 }
100
113 template <typename Scalar, int nq, typename TargetLink, typename SourceLink>
114 Eigen::Transform<Scalar, 3, Eigen::Isometry> forward_kinematics(const Model<Scalar, nq>& model,
115 const Eigen::Matrix<Scalar, nq, 1>& q,
116 const TargetLink& target_link,
117 const SourceLink& source_link) {
118 const int target_link_idx = get_link_idx(model, target_link);
119 const int source_link_idx = get_link_idx(model, source_link);
120
121 // Build kinematic tree from source {s} to base {b} frame
122 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hbs = forward_kinematics(model, q, source_link_idx);
123 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hsb = Hbs.inverse();
124 // Build kinematic tree from base {b} to target {t} frame
125 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hbt = forward_kinematics(model, q, target_link_idx);
126 // Compute transform between source {s} and target {t} frames
127 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hst = Hsb * Hbt;
128 return Hst;
129 }
130
139 template <typename Scalar, int nq>
140 std::vector<Eigen::Transform<Scalar, 3, Eigen::Isometry>> forward_kinematics_com(
141 Model<Scalar, nq>& model,
142 const Eigen::Matrix<Scalar, nq, 1>& q) {
143 // Compute forward kinematics for all the links
144 forward_kinematics(model, q);
145 // Compute transform to centre of mass of all the forward kinematics results
146 for (auto const link : model.links) {
147 model.data.forward_kinematics_com[link.idx] =
148 model.data.forward_kinematics[link.idx] * model.links[link.idx].centre_of_mass;
149 }
150 return model.data.forward_kinematics_com;
151 }
152
165 template <typename Scalar, int nq, typename TargetLink, typename SourceLink = int>
166 Eigen::Transform<Scalar, 3, Eigen::Isometry> forward_kinematics_com(const Model<Scalar, nq>& model,
167 const Eigen::Matrix<Scalar, nq, 1>& q,
168 const TargetLink& target_link,
169 const SourceLink& source_link = 0) {
170 const int target_link_idx = get_link_idx(model, target_link);
171 const int source_link_idx = get_link_idx(model, source_link);
172
173 // Compute forward kinematics from source {b} to target {t}
174 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hst =
175 forward_kinematics(model, q, target_link_idx, source_link_idx);
176 // Compute forward kinematics from source {s} to CoM {c}
177 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hsc = Hst * model.links[target_link_idx].centre_of_mass;
178 // Return transform from source {s} to CoM {c}
179 return Hsc;
180 }
181
194 template <typename Scalar, int nq, typename TargetLink, typename SourceLink = int>
195 Eigen::Matrix<Scalar, 3, 1> translation(const Model<Scalar, nq>& model,
196 const Eigen::Matrix<Scalar, nq, 1>& q,
197 const TargetLink& target_link,
198 const SourceLink& source_link = 0) {
199 const int source_link_idx = get_link_idx(model, source_link);
200 const int target_link_idx = get_link_idx(model, target_link);
201
202 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hst =
203 forward_kinematics(model, q, target_link_idx, source_link_idx);
204 Eigen::Matrix<Scalar, 3, 1> rTSs(Hst.translation());
205 return rTSs;
206 }
207
220 template <typename Scalar, int nq, typename TargetLink, typename SourceLink = int>
221 Eigen::Matrix<Scalar, 3, 3> rotation(const Model<Scalar, nq>& model,
222 const Eigen::Matrix<Scalar, nq, 1>& q,
223 const TargetLink& target_link,
224 const SourceLink& source_link = 0) {
225 int source_link_idx = get_link_idx(model, source_link);
226 int target_link_idx = get_link_idx(model, target_link);
227
228 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hst =
229 forward_kinematics(model, q, target_link_idx, source_link_idx);
230 return Hst.linear();
231 }
232
243 template <typename Scalar, int nq, typename TargetLink>
244 Eigen::Matrix<Scalar, 6, nq> geometric_jacobian(const Model<Scalar, nq>& model,
245 const Eigen::Matrix<Scalar, nq, 1>& q,
246 const TargetLink& target_link) {
247 // Get the target link from the model
248 const int target_link_idx = get_link_idx(model, target_link);
249 Link<Scalar> current_link = model.links[target_link_idx];
250
251 // Get the base link from the model
252 auto base_link = model.links[model.base_link_idx];
253
254 // Compute the displacement of the target link {t} in the base link frame {b}
255 Eigen::Matrix<Scalar, 3, 1> rTBb = translation(model, q, current_link.idx, base_link.idx);
256
257 // Initialize the geometric jabobian matrix with zeros
258 Eigen::Matrix<Scalar, 6, nq> J = Eigen::Matrix<Scalar, 6, nq>::Zero();
259 while (current_link.idx != model.base_link_idx) {
260 auto current_joint = current_link.joint;
261 if (current_joint.idx != -1) {
262 // Compute the transform between base {b} and the current link {i}
263 auto Hbi = forward_kinematics(model, q, current_link.idx, base_link.idx);
264 // Axis of the current joint rotated into the base frame {b}
265 auto zIBb = Hbi.linear() * current_joint.axis;
266 // Compute the displacement of the current link {i} from the base link frame {b}
267 auto rIBb = Hbi.translation();
268 if (current_joint.type == JointType::PRISMATIC) {
269 J.block(0, current_joint.idx, 3, 1) = zIBb;
270 J.block(3, current_joint.idx, 3, 1) = Eigen::Matrix<Scalar, 3, 1>::Zero();
271 }
272 else if (current_joint.type == JointType::REVOLUTE) {
273 J.block(0, current_joint.idx, 3, 1) = (zIBb).cross(rTBb - rIBb);
274 J.block(3, current_joint.idx, 3, 1) = zIBb;
275 }
276 }
277 // Move up the tree to parent towards the base
278 current_link = model.links[current_link.parent];
279 }
280 return J;
281 }
282
293 template <typename Scalar, int nq, typename TargetLink>
294 Eigen::Matrix<Scalar, 6, nq> geometric_jacobian_com(const Model<Scalar, nq>& model,
295 const Eigen::Matrix<Scalar, nq, 1>& q,
296 const TargetLink& target_link) {
297 // Get the target link from the model
298 const int target_link_idx = get_link_idx(model, target_link);
299 Link<Scalar> current_link = model.links[target_link_idx];
300
301 // Get the base link from the model
302 auto base_link = model.links[model.base_link_idx];
303
304 // Compute the displacement of the target link {t} in the base link frame {b}
305 Eigen::Matrix<Scalar, 3, 1> rTcBb = forward_kinematics_com(model, q, target_link, base_link.name).translation();
306
307 // Initialize the geometric jabobian matrix with zeros
308 Eigen::Matrix<Scalar, 6, nq> J = Eigen::Matrix<Scalar, 6, nq>::Zero();
309 while (current_link.idx != model.base_link_idx) {
310 auto current_joint = current_link.joint;
311 if (current_joint.idx != -1) {
312 // Compute the transform between base {b} and the current link {i}
313 auto Hbi = forward_kinematics(model, q, current_link.name, base_link.name);
314 // Axis of the current joint rotated into the base frame {b}
315 auto zIBb = Hbi.linear() * current_joint.axis;
316 // Compute the displacement of the current link {i} from the base link frame {b}
317 auto rIBb = Hbi.translation();
318 if (current_joint.type == JointType::PRISMATIC) {
319 J.block(0, current_joint.idx, 3, 1) = zIBb;
320 J.block(3, current_joint.idx, 3, 1) = Eigen::Matrix<Scalar, 3, 1>::Zero();
321 }
322 else if (current_joint.type == JointType::REVOLUTE) {
323 J.block(0, current_joint.idx, 3, 1) = (zIBb).cross(rTcBb - rIBb);
324 J.block(3, current_joint.idx, 3, 1) = zIBb;
325 }
326 }
327 // Move up the tree to parent towards the base
328 current_link = model.links[current_link.parent];
329 }
330 return J;
331 }
332
344 template <typename Scalar, int nq, typename SourceLink = int>
345 Eigen::Matrix<Scalar, 3, 1> centre_of_mass(const Model<Scalar, nq>& model,
346 const Eigen::Matrix<Scalar, nq, 1>& q,
347 const SourceLink& source_link = 0) {
348 // Initialize the centre of mass as zero
349 Eigen::Matrix<Scalar, 3, 1> rCSs = Eigen::Matrix<Scalar, 3, 1>::Zero();
350 for (auto link : model.links) {
351 // Compute the transform from the source link to the CoM of the link
352 Eigen::Transform<Scalar, 3, Eigen::Isometry> Hsc = forward_kinematics_com(model, q, link.name, source_link);
353 // Compute the centre of mass of the link
354 rCSs = rCSs + Hsc.translation() * link.mass;
355 }
356 // Compute the centre of mass from the source link
357 return rCSs / model.mass;
358 }
359
360} // namespace tinyrobotics
361
362#endif
Eigen::Matrix< Scalar, 6, nq > geometric_jacobian(const Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q, const TargetLink &target_link)
Computes the geometric jacobian of the target link from the base link in the base link frame.
Definition: Kinematics.hpp:244
Eigen::Matrix< Scalar, 6, nq > geometric_jacobian_com(const Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q, const TargetLink &target_link)
Computes the geometric jacobian relative to the base for the specified target link's center of mass.
Definition: Kinematics.hpp:294
std::vector< Eigen::Transform< Scalar, 3, Eigen::Isometry > > forward_kinematics_com(Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q)
Computes the transform to centre of mass of all the links in the tinyrobotics model.
Definition: Kinematics.hpp:140
Eigen::Matrix< Scalar, 3, 3 > rotation(const Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q, const TargetLink &target_link, const SourceLink &source_link=0)
Computes the rotation matrix between the target link and the source link in the source link frame.
Definition: Kinematics.hpp:221
const int get_link_idx(const Model< Scalar, nq > &model, const TargetLink &target_link)
Retrieves the index of the target link in the tinyrobotics model.
Definition: Kinematics.hpp:26
std::vector< Eigen::Transform< Scalar, 3, Eigen::Isometry > > forward_kinematics(Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q)
Computes the transform to all the links in the tinyrobotics model.
Definition: Kinematics.hpp:47
Eigen::Matrix< Scalar, 3, 1 > centre_of_mass(const Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q, const SourceLink &source_link=0)
Computes the centre of mass expressed in source link frame.
Definition: Kinematics.hpp:345
Eigen::Matrix< Scalar, 3, 1 > translation(const Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q, const TargetLink &target_link, const SourceLink &source_link=0)
Computes the translation of the target link from the source link in the source link frame.
Definition: Kinematics.hpp:195
Contains various math related functions.
Contains struct for representing a tinyrobotics model.
A tinyrobotics model.
Definition: Model.hpp:30
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
Scalar mass
Total mass of the model.
Definition: Model.hpp:62
Link< Scalar > get_link(const std::string &name) const
Get a link in the model by name.
Definition: Model.hpp:72
std::string name
Name of the model.
Definition: Model.hpp:32
int base_link_idx
Index of the base link in the models links vector.
Definition: Model.hpp:50
std::vector< Link< Scalar > > links
Vector of links in the model.
Definition: Model.hpp:44