12#include "rby1-sdk/dynamics/inertial.h"
13#include "rby1-sdk/dynamics/joint.h"
14#include "rby1-sdk/dynamics/link.h"
15#include "rby1-sdk/dynamics/state.h"
16#include "rby1-sdk/export.h"
17#include "rby1-sdk/math/liegroup.h"
35enum class MobileBaseType {
42 MobileBaseType type{MobileBaseType::kNone};
44 rb::math::SE3::MatrixType T;
45 std::vector<std::string> joints;
46 std::vector<double> params;
50 unsigned int right_wheel_idx{};
51 unsigned int left_wheel_idx{};
53 double wheel_base{0.};
54 double wheel_radius{0.};
58 unsigned int fr_wheel_idx{};
59 unsigned int fl_wheel_idx{};
60 unsigned int rr_wheel_idx{};
61 unsigned int rl_wheel_idx{};
65 double wheel_radius{0.};
74 std::shared_ptr<Link> base_link;
75 std::shared_ptr<MobileBase> mobile_base;
81 template <
typename T,
int N>
82 using ContainerType =
typename std::conditional_t<(N > 0), std::array<T, (
unsigned int)N>, std::vector<T>>;
86 std::shared_ptr<Link> link;
87 Inertial::MatrixType J_wrt_p;
88 math::SE3::MatrixType M_wrt_p;
89 math::SE3::MatrixType M_wrt_base;
92 std::vector<SubLink_> links;
93 Inertial::MatrixType J{Inertial::MatrixType::Zero()};
94 math::SE3::MatrixType M{math::SE3::Identity()};
96 Inertial::MatrixType I{Inertial::MatrixType::Zero()};
99 int parent_joint_idx{-1};
100 std::vector<int> child_joint_idx{};
102 void SetBaseLink(
const std::shared_ptr<Link>& link,
const math::SE3::MatrixType& T) {
106 J = Inertial::MatrixType::Zero();
109 AddLink(link, math::SE3::Identity());
112 int AddLink(
const std::shared_ptr<Link>& link,
const math::SE3::MatrixType& M_wrt_p) {
113 Inertial::MatrixType J_wrt_p = Inertial::Transform(M_wrt_p, link->I_);
114 int idx = links.size();
119 l.M_wrt_base = M * M_wrt_p;
122 J += Inertial::Transform(M, J_wrt_p);
128 std::shared_ptr<Joint> joint{
nullptr};
129 math::se3v::MatrixType S{math::se3v::MatrixType::Zero()};
131 int parent_link_idx{};
132 int child_link_idx{};
142 std::shared_ptr<const Link> GetBase()
const {
return links_[0].links[0].link; }
144 std::shared_ptr<Link> GetBase() {
return links_[0].links[0].link; }
146 std::vector<std::string> GetLinkNames()
const {
147 std::vector<std::string> names;
148 for (
const auto& [n, idx] : link_idx_) {
154 std::vector<std::string> GetJointNames()
const {
155 std::vector<std::string> names;
156 for (
const auto& [n, idx] : joint_idx_) {
162 std::shared_ptr<Link> GetLink(
const std::string& name)
const {
163 if (link_idx_.find(name) == link_idx_.end()) {
166 const auto& idx = link_idx_.at(name);
167 return links_[idx.link_idx].links[idx.sub_link_idx].link;
170 std::shared_ptr<Link> GetLink(std::shared_ptr<State<DOF>> state,
int index)
const {
171 if (index >= (
int)state->utr_link_map.size()) {
174 const auto& idx = state->utr_link_map[index];
175 return links_[idx.link_idx].links[idx.sub_link_idx].link;
178 template <
typename LinkContainer = std::vector<std::
string>,
typename Jo
intContainer = std::vector<std::
string>>
179 std::shared_ptr<State<DOF>> MakeState(
const LinkContainer& link_names,
const JointContainer& joint_names) {
180 static_assert(std::is_same_v<typename LinkContainer::value_type, std::string> ||
181 std::is_same_v<typename LinkContainer::value_type, std::string_view>,
182 "LinkContainer value_type must be std::string");
183 static_assert(std::is_same_v<typename JointContainer::value_type, std::string> ||
184 std::is_same_v<typename JointContainer::value_type, std::string_view>,
185 "JointContainer value_type must be std::string");
187 std::vector<bool> flag;
188 flag.resize(n_joints_);
189 std::fill(flag.begin(), flag.end(),
false);
191 auto state = std::shared_ptr<State<DOF>>(
new State<DOF>(n_joints_));
192 for (
int i = 0; i < (int)joint_names.size(); i++) {
193 const auto& name = joint_names[i];
195 auto it = std::find_if(joints_.begin(), joints_.end(), [name](
const auto& j) { return j.joint->name_ == name; });
196 if (it == joints_.end()) {
197 throw std::runtime_error(
"Cannot find the joint with name");
199 state->utr_joint_map[i] = it - joints_.begin();
200 state->joint_names[i] = it->joint->name_;
201 flag[state->utr_joint_map[i]] =
true;
203 for (
unsigned int i = joint_names.size(); i < n_joints_; i++) {
204 auto it = std::find(flag.begin(), flag.end(),
false);
205 state->utr_joint_map[i] = it - flag.begin();
206 state->joint_names[i] = (joints_.begin() + (it - flag.begin()))->joint->name_;
209 for (
int i = 0; i < state->utr_joint_map.size(); i++) {
210 state->rtu_joint_map[state->utr_joint_map[i]] = i;
213 std::unordered_map<std::string, bool> name_flag;
214 state->link_names.clear();
215 state->utr_link_map.clear();
216 for (
const auto& name : link_names) {
217 auto it = link_idx_.find(name);
218 if (it == link_idx_.end()) {
219 throw std::runtime_error(
"The link with the given name does not exist");
221 state->utr_link_map.push_back(it->second);
222 state->link_names.push_back(name);
223 name_flag[name] =
true;
225 for (
const auto& [k, v] : link_idx_) {
226 if (name_flag.find(k) == name_flag.end()) {
227 state->utr_link_map.push_back(v);
228 state->link_names.push_back(k);
231 for (
int i = 0; i < (int)state->link_names.size(); i++) {
232 const auto& n = state->link_names[i];
233 auto it = link_idx_.find(n);
234 if (it == link_idx_.end()) {
235 throw std::runtime_error(
"Fatal error; link names in state should be found in link idx");
237 if (it->second.link_idx == 0 && it->second.sub_link_idx == 0) {
238 state->base_link_user_idx = i;
245 int GetDOF()
const {
return n_joints_; }
247 int GetNumberOfJoints()
const {
return n_joints_; }
249 void ComputeForwardKinematics(std::shared_ptr<State<DOF>> state) {
250 for (
int i = 0; i < (int)n_joints_; i++) {
251 state->E[i] = math::SE3::Exp(joints_[i].S, state->q(i));
253 int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
254 state->T[i] = GetJointT(state, parent_joint_idx) * state->E[i];
256 state->S.col(i) = math::SE3::Ad(GetJointT(state, parent_joint_idx), joints_[i].S);
260 void ComputeDiffForwardKinematics(std::shared_ptr<State<DOF>> state) {
261 for (
int i = 0; i < (int)n_joints_; i++) {
262 state->V.col(i) = joints_[i].S * state->qdot(i);
264 int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
265 state->V.col(i) += math::SE3::InvAd(state->E[i], GetJointV(state, parent_joint_idx));
269 void Compute2ndDiffForwardKinematics(std::shared_ptr<State<DOF>> state) {
270 for (
int i = 0; i < (int)n_joints_; i++) {
271 state->Vdot.col(i) = joints_[i].S * state->qddot(i);
273 int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
274 state->Vdot.col(i) += math::SE3::InvAd(state->E[i], GetJointVdot(state, parent_joint_idx)) +
275 math::SE3::ad(state->V.col(i), joints_[i].S * state->qdot(i));
279 void ComputeInverseDynamics(std::shared_ptr<State<DOF>> state) {
280 for (
int i = n_joints_ - 1; i >= 0; i--) {
281 Eigen::Vector<double, 6> F;
284 for (
const auto& child_joint_idx : links_[joints_[i].child_link_idx].child_joint_idx) {
285 F += math::SE3::InvAd(state->E[child_joint_idx]).transpose() * state->F.col(child_joint_idx);
287 F += links_[joints_[i].child_link_idx].J * state->Vdot.col(i) -
288 math::SE3::adTranspose(state->V.col(i), links_[joints_[i].child_link_idx].J * state->V.col(i));
291 state->tau(i) = joints_[i].S.dot(F);
295 Eigen::Vector<double, DOF> ComputeGravityTerm(std::shared_ptr<State<DOF>> state) {
296 Eigen::Vector<double, DOF> gravity_term;
297 gravity_term.resize(n_joints_);
298 std::vector<Eigen::Vector<double, 6>> Vdot{}, Fs{};
299 Vdot.resize(n_joints_);
300 Fs.resize(n_joints_);
303 for (
int i = 0; i < (int)n_joints_; i++) {
304 int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
305 if (parent_joint_idx < 0) {
306 Vdot[i] = math::SE3::InvAd(state->E[i], state->Vdot0);
308 Vdot[i] = math::SE3::InvAd(state->E[i], Vdot[parent_joint_idx]);
313 for (
int i = n_joints_ - 1; i >= 0; i--) {
314 Eigen::Vector<double, 6> F;
317 for (
const auto& child_joint_idx : links_[joints_[i].child_link_idx].child_joint_idx) {
318 F += math::SE3::InvAd(state->E[child_joint_idx]).transpose() * Fs[child_joint_idx];
320 F += links_[joints_[i].child_link_idx].J * Vdot[i];
323 gravity_term(state->rtu_joint_map[i]) = joints_[i].S.dot(F);
329 Eigen::Matrix<double, DOF, DOF> ComputeMassMatrix(std::shared_ptr<State<DOF>> state) {
330 Eigen::Matrix<double, DOF, DOF> M(n_joints_, n_joints_);
333 std::vector<Eigen::Matrix<double, 6, DOF>> J;
336 for (
int i = 0; i < (int)n_joints_; i++) {
337 int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
338 if (parent_joint_idx < 0) {
340 J[i].col(state->rtu_joint_map[i]) = joints_[i].S;
342 J[i] = math::SE3::Ad(state->E[i].inverse()) * J[parent_joint_idx];
343 J[i].col(state->rtu_joint_map[i]) = joints_[i].S;
347 for (
int i = 0; i < (int)n_joints_; i++) {
348 M += J[i].transpose() * links_[joints_[i].child_link_idx].J * J[i];
354 Eigen::Matrix<double, 6, 6> ComputeReflectiveInertia(std::shared_ptr<State<DOF>> state,
unsigned int from,
356 if (from >= state->utr_link_map.size() || to >= state->utr_link_map.size()) {
357 throw std::runtime_error(
"Out of range state link");
359 const auto& J = ComputeBodyJacobian(state, from, to);
360 Eigen::Matrix<double, DOF, DOF> m_inv = ComputeMassMatrix(state).completeOrthogonalDecomposition().pseudoInverse();
361 return (J * m_inv * J.transpose()).completeOrthogonalDecomposition().pseudoInverse();
364 math::SE3::MatrixType ComputeTransformation(std::shared_ptr<State<DOF>> state,
unsigned int from,
unsigned int to) {
365 if (from >= state->utr_link_map.size() || to >= state->utr_link_map.size()) {
366 throw std::runtime_error(
"Out of range state link");
368 return GetTransformation(state, state->utr_link_map[from], state->utr_link_map[to]);
371 math::se3v::MatrixType ComputeBodyVelocity(std::shared_ptr<State<DOF>> state,
unsigned int from,
unsigned int to) {
372 if (from >= state->utr_link_map.size() || to >= state->utr_link_map.size()) {
373 throw std::runtime_error(
"Out of range state link");
375 math::SE3::MatrixType T_from_to = ComputeTransformation(state, from, to);
376 math::se3v::MatrixType V_from = GetLinkV(state, state->utr_link_map[from]);
377 math::se3v::MatrixType V_to = GetLinkV(state, state->utr_link_map[to]);
378 return V_to - math::SE3::InvAd(T_from_to, V_from);
381 Eigen::Matrix<double, 6, DOF> ComputeSpaceJacobian(std::shared_ptr<State<DOF>> state,
unsigned int from,
383 return GetSpaceJacobian(state, state->utr_link_map[from], state->utr_link_map[to]);
386 Eigen::Matrix<double, 6, DOF> ComputeBodyJacobian(std::shared_ptr<State<DOF>> state,
unsigned int from,
388 math::SE3::MatrixType T = ComputeTransformation(state, from, to);
389 return math::SE3::InvAd(T) * ComputeSpaceJacobian(state, from, to);
392 double ComputeMass(std::shared_ptr<State<DOF>> state,
unsigned int target_link) {
393 const auto& idx = state->utr_link_map[target_link];
394 return Inertial::GetMass(links_[idx.link_idx].links[idx.sub_link_idx].link->I_);
397 Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr<State<DOF>> state,
unsigned int ref_link,
398 unsigned int target_link) {
399 const auto& idx = state->utr_link_map[target_link];
400 return math::SE3::Multiply(ComputeTransformation(state, ref_link, target_link),
401 Inertial::GetCOM(links_[idx.link_idx].links[idx.sub_link_idx].link->I_));
404 Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr<State<DOF>> state,
unsigned int ref_link,
405 const std::vector<unsigned int>& target_links) {
406 Eigen::Vector3d com{Eigen::Vector3d ::Zero()};
408 for (
auto target_link : target_links) {
409 const auto& idx = state->utr_link_map[target_link];
410 const auto& p = Inertial::GetCOM(links_[idx.link_idx].links[idx.sub_link_idx].link->I_);
411 double m = Inertial::GetMass(links_[idx.link_idx].links[idx.sub_link_idx].link->I_);
412 com += math::SE3::Multiply(ComputeTransformation(state, ref_link, target_link), p) * m;
418 Eigen::Matrix<double, 3, DOF> ComputeCenterOfMassJacobian(std::shared_ptr<State<DOF>> state,
unsigned int ref_link,
419 unsigned int target_link) {
420 using namespace math;
422 const auto& idx = state->utr_link_map[target_link];
423 return SE3::GetRotation(ComputeTransformation(state, ref_link, target_link)) *
424 (SE3::InvAd(SE3::T(Inertial::GetCOM(links_[idx.link_idx].links[idx.sub_link_idx].link->I_))) *
425 ComputeBodyJacobian(state, ref_link, target_link))
426 .block(3, 0, 3, n_joints_);
436 Inertial::MatrixType I{Inertial::MatrixType::Zero()};
437 for (
const auto& link : links_) {
438 I += Inertial::Transform(GetJointT(state, link.parent_joint_idx), link.J);
441 return Inertial::Transform(math::SE3::Inverse(GetLinkT(state, state->utr_link_map[ref_link])), I);
444 Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr<
State<DOF>> state,
unsigned int ref_link) {
445 Eigen::Vector3d sum{Eigen::Vector3d::Zero()};
448 for (
const auto& link : links_) {
449 sum += Inertial::GetMass(link.J) *
450 math::SE3::Multiply(GetJointT(state, link.parent_joint_idx), Inertial::GetCOM(link.J));
451 mass += Inertial::GetMass(link.J);
454 return math::SE3::Multiply(math::SE3::Inverse(GetLinkT(state, state->utr_link_map[ref_link])), sum / mass);
457 Eigen::Matrix<double, 3, DOF> ComputeCenterOfMassJacobian(std::shared_ptr<State<DOF>> state,
unsigned int ref_link) {
458 using namespace math;
459 Eigen::Matrix<double, 3, DOF> J;
460 J.resize(3, n_joints_);
463 for (
int i = 0; i < (int)links_.size(); i++) {
465 double m = Inertial::GetMass(links_[i].I);
466 J += m * SE3::GetRotation(GetTransformation(state, state->utr_link_map[ref_link], {i, 0})) *
467 (SE3::InvAd(SE3::T(Inertial::GetCOM(links_[i].I))) *
468 GetBodyJacobian(state, state->utr_link_map[ref_link], {i, 0}))
469 .block(3, 0, 3, n_joints_);
475 std::vector<CollisionResult> DetectCollisionsOrNearestLinks(std::shared_ptr<State<DOF>> state,
476 int collision_threshold = 0) {
477 std::vector<CollisionResult> dis;
479 int n = state->GetLinkNames().size();
480 for (
int i = 0; i < n; i++) {
481 auto link1 = GetLink(state, i);
483 throw std::runtime_error(
"Index error");
485 auto link1_T = ComputeTransformation(state, 0, i);
486 for (
int j = i + 1; j < n; j++) {
487 auto link2 = GetLink(state, j);
489 throw std::runtime_error(
"Index error");
491 auto link2_T = ComputeTransformation(state, 0, j);
493 for (
auto link1_col : link1->GetCollisions()) {
494 for (
auto link2_col : link2->GetCollisions()) {
496 for (
auto link1_geom : link1_col->GetGeoms()) {
497 for (
auto link2_geom : link2_col->GetGeoms()) {
499 if (link1_geom->GetType() == GeomType::kCapsule &&
500 link2_geom->GetType() == GeomType::kCapsule &&
501 link1_geom->Filter(*link2_geom)) {
502 auto collision_result =
503 link1_geom->ComputeMinimumDistance(link1_T * link1_col->GetOrigin(), *link2_geom,
504 link2_T * link2_col->GetOrigin());
505 if (collision_result.has_value()) {
506 auto v = collision_result.value();
507 v.link1 = link1->GetName();
508 v.link2 = link2->GetName();
519 std::sort(dis.begin(), dis.end(),
520 [](
const CollisionResult& r1,
const CollisionResult& r2) { return r1.distance < r2.distance; });
522 std::vector<CollisionResult> rv;
523 for (
const auto& d : dis) {
524 if (d.distance > 0 && (
int)rv.size() >= collision_threshold) {
536 Eigen::Vector<double, DOF> GetLimitQLower(
const std::shared_ptr<State<DOF>>& state) {
537 return GetJointProperty(state, [](
auto j) {
return j->GetLimitQLower(); });
540 Eigen::Vector<double, DOF> GetLimitQUpper(
const std::shared_ptr<State<DOF>>& state) {
541 return GetJointProperty(state, [](
auto j) {
return j->GetLimitQUpper(); });
544 Eigen::Vector<double, DOF> GetLimitQdotLower(
const std::shared_ptr<State<DOF>>& state) {
545 return GetJointProperty(state, [](
auto j) {
return j->GetLimitQdotLower(); });
548 Eigen::Vector<double, DOF> GetLimitQdotUpper(
const std::shared_ptr<State<DOF>>& state) {
549 return GetJointProperty(state, [](
auto j) {
return j->GetLimitQdotUpper(); });
552 Eigen::Vector<double, DOF> GetLimitQddotLower(
const std::shared_ptr<State<DOF>>& state) {
553 return GetJointProperty(state, [](
auto j) {
return j->GetLimitQddotLower(); });
556 Eigen::Vector<double, DOF> GetLimitQddotUpper(
const std::shared_ptr<State<DOF>>& state) {
557 return GetJointProperty(state, [](
auto j) {
return j->GetLimitQddotUpper(); });
560 Eigen::Vector<double, DOF> GetLimitTorque(
const std::shared_ptr<State<DOF>>& state) {
561 return GetJointProperty(state, [](
auto j) {
return j->GetLimitTorque(); });
564 Eigen::Vector<double, DOF> GetJointProperty(
const std::shared_ptr<State<DOF>>& state,
565 const std::function<
double(std::shared_ptr<Joint>)>& getter) {
566 Eigen::Vector<double, DOF> prop;
567 prop.resize(n_joints_);
568 for (
int i = 0; i < (int)n_joints_; i++) {
569 prop(state->rtu_joint_map[i]) = getter(joints_[i].joint);
574 void ComputeMobilityInverseDiffKinematics(std::shared_ptr<State<DOF>> state,
575 const Eigen::Vector2d& linear_velocity,
576 double angular_velocity
578 math::se2v::MatrixType S;
579 S(0) = angular_velocity;
580 S.tail<2>() = linear_velocity;
582 ComputeMobilityInverseDiffKinematics(state, S);
585 void ComputeMobilityInverseDiffKinematics(std::shared_ptr<State<DOF>> state,
586 const math::se2v::MatrixType& body_velocity
588 math::se3v::MatrixType S{math::se3v::MatrixType::Zero()};
589 S.block<3, 1>(2, 0) = body_velocity;
591 S = math::SE3::InvAd(mobile_base_->T, S);
593 switch (mobile_base_->type) {
594 case MobileBaseType::kNone: {
597 case MobileBaseType::kDifferential: {
598 auto mb = std::static_pointer_cast<MobileBaseDifferential>(mobile_base_);
599 double v_right = S(3) + mb->wheel_base / 2 * S(2);
600 double v_left = S(3) - mb->wheel_base / 2 * S(2);
601 state->qdot(mb->right_wheel_idx) = -v_right / mb->wheel_radius;
602 state->qdot(mb->left_wheel_idx) = -v_left / mb->wheel_radius;
605 case MobileBaseType::kMecanum: {
613 auto mb = std::static_pointer_cast<MobileBaseMecanum>(mobile_base_);
614 double w_1 = 1 / mb->wheel_radius * (v_x - v_y - (mb->L_x + mb->L_y) * w);
615 double w_2 = 1 / mb->wheel_radius * (v_x + v_y + (mb->L_x + mb->L_y) * w);
616 double w_3 = 1 / mb->wheel_radius * (v_x + v_y - (mb->L_x + mb->L_y) * w);
617 double w_4 = 1 / mb->wheel_radius * (v_x - v_y + (mb->L_x + mb->L_y) * w);
618 state->qdot(mb->fl_wheel_idx) = w_1;
619 state->qdot(mb->fr_wheel_idx) = w_2;
620 state->qdot(mb->rl_wheel_idx) = w_3;
621 state->qdot(mb->rr_wheel_idx) = w_4;
633 math::se2v::MatrixType ComputeMobilityDiffKinematics(
634 std::shared_ptr<State<DOF>> state
636 math::se3v::MatrixType S{math::se3v::MatrixType::Zero()};
638 switch (mobile_base_->type) {
639 case MobileBaseType::kNone: {
642 case MobileBaseType::kDifferential: {
643 auto mb = std::static_pointer_cast<MobileBaseDifferential>(mobile_base_);
644 double w_r = -state->qdot(mb->right_wheel_idx);
645 double w_l = -state->qdot(mb->left_wheel_idx);
646 S.block<3, 1>(2, 0) = math::se2v::MatrixType{(w_r - w_l) * mb->wheel_radius / mb->wheel_base,
647 (w_r + w_l) * mb->wheel_radius / 2, 0};
650 case MobileBaseType::kMecanum: {
651 auto mb = std::static_pointer_cast<MobileBaseMecanum>(mobile_base_);
652 double w_1 = state->qdot(mb->fl_wheel_idx);
653 double w_2 = state->qdot(mb->fr_wheel_idx);
654 double w_3 = state->qdot(mb->rl_wheel_idx);
655 double w_4 = state->qdot(mb->rr_wheel_idx);
656 double v_x = mb->wheel_radius / 4 * (w_1 + w_2 + w_3 + w_4);
657 double v_y = mb->wheel_radius / 4 * (-w_1 + w_2 + w_3 - w_4);
658 double w = mb->wheel_radius / (4 * (mb->L_x + mb->L_y)) * (-w_1 + w_2 - w_3 + w_4);
659 S.block<3, 1>(2, 0) = math::se2v::MatrixType{w, v_x, v_y};
664 S = math::SE3::Ad(mobile_base_->T, S);
666 return S.block<3, 1>(2, 0);
669 static int CountJoints(
const std::shared_ptr<Link>& base_link,
bool include_fixed =
false) {
672 std::queue<std::shared_ptr<Link>> que;
674 while (!que.empty()) {
675 std::shared_ptr<Link> link = que.front();
678 for (
const auto& joint : link->GetChildJointList()) {
679 que.push(joint->GetChildLink());
681 if (joint->IsFixed() && !include_fixed)
694 void Build(
const RobotConfiguration& rc) {
695 const auto& base = rc.base_link;
697 int n_joints = CountJoints(base);
699 if constexpr (DOF < 0) {
700 n_links_ = n_joints + 1;
701 n_joints_ = n_joints;
703 links_.resize(n_links_);
704 joints_.resize(n_joints_);
706 if (n_joints != DOF) {
707 throw std::runtime_error(
"DOF does not match the number of joints");
714 int parent_joint_idx{};
715 int parent_link_idx{};
716 std::shared_ptr<Link> link;
718 bool merge_parent_link{};
719 math::SE3::MatrixType M_wrt_base;
720 math::SE3::MatrixType M_wrt_p;
723 std::queue<QueueItem> que;
729 item.parent_joint_idx = -1;
730 item.parent_link_idx = link_idx++;
733 item.merge_parent_link =
false;
734 item.M_wrt_base = math::SE3::Identity();
735 item.M_wrt_p = math::SE3::Identity();
739 while (!que.empty()) {
740 auto e = que.front();
743 if (!e.merge_parent_link) {
744 links_[e.parent_link_idx].SetBaseLink(e.link, e.M_wrt_base);
745 links_[e.parent_link_idx].depth = e.depth;
746 links_[e.parent_link_idx].parent_joint_idx = e.parent_joint_idx;
747 link_idx_[e.link->name_] = {e.parent_link_idx, 0};
749 int sub_link_idx = links_[e.parent_link_idx].AddLink(e.link, e.M_wrt_p);
750 link_idx_[e.link->name_] = {e.parent_link_idx, sub_link_idx};
753 for (
const auto& joint : e.link->child_joints_) {
754 if (!joint->fixed_) {
755 math::SE3::MatrixType M_wrt_base = e.M_wrt_base * joint->T_pj_;
759 j.S = math::SE3::Ad(M_wrt_base, joint->S_);
760 j.parent_link_idx = e.parent_link_idx;
761 j.child_link_idx = link_idx;
762 joints_[joint_idx] = j;
764 joint_idx_[joint->name_] = joint_idx;
765 links_[e.parent_link_idx].child_joint_idx.push_back(joint_idx);
768 item.parent_joint_idx = joint_idx++;
769 item.parent_link_idx = link_idx++;
770 item.link = joint->child_link_;
771 item.depth = e.depth + 1;
772 item.merge_parent_link =
false;
773 item.M_wrt_base = M_wrt_base;
774 item.M_wrt_p = math::SE3::Identity();
779 item.parent_joint_idx = e.parent_joint_idx;
780 item.parent_link_idx = e.parent_link_idx;
781 item.link = joint->child_link_;
782 item.depth = e.depth;
783 item.merge_parent_link =
true;
784 item.M_wrt_base = e.M_wrt_base * joint->T_pj_ * joint->T_jc_;
785 item.M_wrt_p = e.M_wrt_p * joint->T_pj_ * joint->T_jc_;
792 if (rc.mobile_base) {
793 switch (rc.mobile_base->type) {
794 case MobileBaseType::kNone: {
795 auto mb = std::make_shared<MobileBase>();
796 *std::static_pointer_cast<MobileBase>(mb) = *rc.mobile_base;
800 case MobileBaseType::kDifferential: {
801 auto mb = std::make_shared<MobileBaseDifferential>();
802 *std::static_pointer_cast<MobileBase>(mb) = *rc.mobile_base;
803 if (rc.mobile_base->joints.size() != 2) {
804 throw std::runtime_error(
"Differential type mobile should have two joints.");
806 if (joint_idx_.find(rc.mobile_base->joints[0]) == joint_idx_.end()) {
807 throw std::runtime_error(
"Right wheel has invalid parameter.");
809 if (joint_idx_.find(rc.mobile_base->joints[1]) == joint_idx_.end()) {
810 throw std::runtime_error(
"Left wheel has invalid parameter.");
812 if (rc.mobile_base->params.size() != 2) {
813 throw std::runtime_error(
"Differential type mobile should have two parameters.");
815 mb->right_wheel_idx = joint_idx_[rc.mobile_base->joints[0]];
816 mb->left_wheel_idx = joint_idx_[rc.mobile_base->joints[1]];
817 mb->wheel_base = rc.mobile_base->params[0];
818 mb->wheel_radius = rc.mobile_base->params[1];
822 case MobileBaseType::kMecanum:
823 auto mb = std::make_shared<MobileBaseMecanum>();
824 *std::static_pointer_cast<MobileBase>(mb) = *rc.mobile_base;
825 if (rc.mobile_base->joints.size() != 4) {
826 throw std::runtime_error(
827 "Mecanum type mobile should have four joints. (front-right, front-left, rear-right, rear-left)");
829 if (joint_idx_.find(rc.mobile_base->joints[0]) == joint_idx_.end()) {
830 throw std::runtime_error(
"Front-right wheel has invalid parameter.");
832 if (joint_idx_.find(rc.mobile_base->joints[1]) == joint_idx_.end()) {
833 throw std::runtime_error(
"Front-left wheel has invalid parameter.");
835 if (joint_idx_.find(rc.mobile_base->joints[2]) == joint_idx_.end()) {
836 throw std::runtime_error(
"Rear-right wheel has invalid parameter.");
838 if (joint_idx_.find(rc.mobile_base->joints[3]) == joint_idx_.end()) {
839 throw std::runtime_error(
"Rear-left wheel has invalid parameter.");
841 if (rc.mobile_base->params.size() != 3) {
842 throw std::runtime_error(
"Mecanum type mobile should have three parameters. (Lx, Ly, wheel radius)");
844 mb->fr_wheel_idx = joint_idx_[rc.mobile_base->joints[0]];
845 mb->fl_wheel_idx = joint_idx_[rc.mobile_base->joints[1]];
846 mb->rr_wheel_idx = joint_idx_[rc.mobile_base->joints[2]];
847 mb->rl_wheel_idx = joint_idx_[rc.mobile_base->joints[3]];
848 mb->L_x = rc.mobile_base->params[0];
849 mb->L_y = rc.mobile_base->params[1];
850 mb->wheel_radius = rc.mobile_base->params[2];
857 math::SE3::MatrixType GetLinkT(std::shared_ptr<State<DOF>> state,
const LinkIdx_& idx) {
858 return GetJointT(state, links_[idx.link_idx].parent_joint_idx) *
859 links_[idx.link_idx].links[idx.sub_link_idx].M_wrt_base;
862 math::se3v::MatrixType GetLinkV(std::shared_ptr<State<DOF>> state,
const LinkIdx_& idx) {
863 return math::SE3::InvAd(links_[idx.link_idx].links[idx.sub_link_idx].M_wrt_base,
864 GetJointV(state, links_[idx.link_idx].parent_joint_idx));
867 math::SE3::MatrixType GetJointT(std::shared_ptr<State<DOF>> state,
int joint_idx) {
869 return math::SE3::Identity();
870 return state->T[joint_idx];
873 math::se3v::MatrixType GetJointV(std::shared_ptr<State<DOF>> state,
int joint_idx) {
876 return state->V.col(joint_idx);
879 math::se3v::MatrixType GetJointVdot(std::shared_ptr<State<DOF>> state,
int joint_idx) {
882 return state->Vdot.col(joint_idx);
885 math::SE3::MatrixType GetTransformation(std::shared_ptr<State<DOF>> state,
const LinkIdx_& from,
const LinkIdx_& to) {
886 return math::SE3::Inverse(GetLinkT(state, from)) * GetLinkT(state, to);
889 Eigen::Matrix<double, 6, DOF> GetSpaceJacobian(std::shared_ptr<State<DOF>> state,
const LinkIdx_& from,
890 const LinkIdx_& to) {
891 Eigen::Matrix<double, 6, DOF> J;
892 J.resize(6, n_joints_);
897 int from_link_idx = from.link_idx;
898 int to_link_idx = to.link_idx;
899 while (from_link_idx != to_link_idx) {
900 if (links_[from_link_idx].depth > links_[to_link_idx].depth) {
901 int pj = links_[from_link_idx].parent_joint_idx;
902 J.col(state->rtu_joint_map[pj]) = -state->S.col(pj);
903 from_link_idx = joints_[pj].parent_link_idx;
905 int pj = links_[to_link_idx].parent_joint_idx;
906 J.col(state->rtu_joint_map[pj]) = state->S.col(pj);
907 to_link_idx = joints_[pj].parent_link_idx;
911 return math::SE3::InvAd(GetLinkT(state, from)) * J;
914 Eigen::Matrix<double, 6, DOF> GetBodyJacobian(std::shared_ptr<State<DOF>> state,
const LinkIdx_& from,
915 const LinkIdx_& to) {
916 math::SE3::MatrixType T = GetTransformation(state, from, to);
917 return math::SE3::InvAd(T) * GetSpaceJacobian(state, from, to);
921 ContainerType<Link_, DOF + 1> links_;
922 ContainerType<Joint_, DOF> joints_;
924 std::unordered_map<std::string, LinkIdx_> link_idx_;
925 std::unordered_map<std::string, unsigned int> joint_idx_;
933 std::shared_ptr<MobileBase> mobile_base_;
936RBY1_SDK_API RobotConfiguration LoadRobotFromURDFData(
const std::string& model,
const std::string& base_link_name);
938RBY1_SDK_API RobotConfiguration LoadRobotFromURDF(
const std::string& path,
const std::string& base_link_name);
940RBY1_SDK_API
inline std::string to_string(GeomType type) {
942 case GeomType::kCapsule:
Inertial::MatrixType ComputeTotalInertial(std::shared_ptr< State< DOF > > state, unsigned int ref_link)
Definition robot.h:435