| name | kinematics |
| description | 运动学技能 - 正逆运动学、雅可比矩阵、轨迹运动学、奇异姿态 |
| argument-hint | 运动学 OR kinematics OR 逆运动学 OR 雅可比 OR IK |
| user-invocable | true |
运动学技能
机器人运动学:正运动学、逆运动学、雅可比矩阵、奇异姿态分析
何时使用
- 求解机械臂末端位姿(正运动学)
- 已知末端位姿,求关节角度(逆运动学)
- 速度级逆运动学(雅可比矩阵)
- 奇异姿态检测与处理
- 冗余机械臂求解
正运动学(Forward Kinematics)
DH 参数法(标准机械臂)
#include <Eigen/Dense>
struct DHParams {
double a;
double alpha;
double d;
double theta;
};
class ForwardKinematics {
public:
Eigen::Matrix4d dh_to_transform(const DHParams& dh) {
double ct = std::cos(dh.theta);
double st = std::sin(dh.theta);
double ca = std::cos(dh.alpha);
double sa = std::sin(dh.alpha);
Eigen::Matrix4d T;
T << ct, -st*ca, st*sa, dh.a*ct,
st, ct*ca, -ct*sa, dh.a*st,
0.0, sa, ca, dh.d,
0.0, 0.0, 0.0, 1.0;
return T;
}
Eigen::Matrix4d compute_pose(const std::vector<DHParams>& dh_chain) {
Eigen::Matrix4d T = Eigen::Matrix4d::Identity();
for (const auto& dh : dh_chain) {
T = T * dh_to_transform(dh);
}
return T;
}
};
通用(已知 URDF)
#include <kdl_parser/kdl_parser.hpp>
#include <kdl/chainfksolverpos_recursive.hpp>
class UrdfKinematics : public rclcpp::Node {
public:
UrdfKinematics() : Node("urdf_kinematics") {
this->declare_parameter("robot_description", "");
std::string robot_desc;
this->get_parameter("robot_description", robot_desc);
KDL::Tree tree;
if (!kdl_parser::treeFromString(robot_desc, tree)) {
RCLCPP_ERROR(this->get_logger(), "Failed to parse URDF");
return;
}
tree.getChain("base_link", "tool0", kdl_chain_);
fk_solver_ = std::make_unique<KDL::ChainFkSolverPos_recursive>(kdl_chain_);
RCLCPP_INFO(this->get_logger(), "FK solver initialized for %zu joints", kdl_chain_.getNrOfJoints());
}
KDL::Frame compute_fk(const std::vector<double>& q) {
KDL::JntArray jnt_pos;
( i = ; i < q.(); ++i) (i) = q[i];
KDL::Frame pose;
fk_solver_->(jnt_pos, pose);
pose;
}
:
KDL::Chain kdl_chain_;
std::unique_ptr<KDL::ChainFkSolverPos_recursive> fk_solver_;
};
逆运动学(Inverse Kinematics)
解析法(6DOF 机械臂)
class AnalyticalIK {
public:
std::vector<std::array<double, 6>> solve(const Eigen::Matrix4d& T) {
std::vector<std::array<double, 6>> solutions;
Eigen::Vector3d p = T.block<3,1>(0,3);
Eigen::Matrix3d R = T.block<3,3>(0,0);
double j1 = std::atan2(p(1), p(0));
solutions.push_back({j1, j2, j3, j4, j5, j6});
return solutions;
}
std::array<double, 6> choose_nearest(const std::vector<std::array<double,6>>& sols,
const std::array<double,6>& q_current) {
double min_dist = INFINITY;
std::array<double,6> best;
for (const auto& sol : sols) {
double dist = 0;
( i = ; i < ; ++i) dist += std::(sol[i] - q_current[i]);
(dist < min_dist) { min_dist = dist; best = sol; }
}
best;
}
};
数值法(KDL)
#include <kdl/chainiksolverpos_lma.hpp>
class NumericalIK : public rclcpp::Node {
public:
NumericalIK() : Node("numerical_ik") {
ik_solver_ = std::make_unique<KDL::ChainIkSolverPos_LMA>(kdl_chain_);
}
std::vector<double> solve(const Eigen::Matrix4d& target_pose) {
KDL::Frame frame;
frame.p = {target_pose(0,3), target_pose(1,3), target_pose(2,3)};
frame.M = KDL::Rotation(target_pose(0,0), target_pose(1,0), target_pose(2,0),
target_pose(0,1), target_pose(1,1), target_pose(2,1),
target_pose(0,2), target_pose(1,2), (,));
;
;
ret = ik_solver_->(q_init, frame, q_out);
(ret >= ) {
std::vector<> result;
( i = ; i < q_out.(); ++i) result.((i));
result;
}
{};
}
:
std::unique_ptr<KDL::ChainIkSolverPos_LMA> ik_solver_;
};
雅可比矩阵(Jacobian)
class JacobianCalculator {
public:
Eigen::MatrixXd compute_jacobian(const KDL::Chain& chain,
const KDL::JntArray& q) {
int nj = chain.getNrOfJoints();
Eigen::MatrixXd J(6, nj);
KDL::Frame T_end;
KDL::ChainFkSolverPos_recursive fk(chain);
fk.JntToCart(q, T_end);
Eigen::Vector3d p_end = {T_end.p.x(), T_end.p.y(), T_end.p.z()};
for (int i = 0; i < nj; ++i) {
KDL::Vector axis = chain.getSegment(i).getSegment().Joint().JointAxis();
if (chain.getSegment(i).getSegment().Joint().getType() == KDL::Joint::RotAxis) {
J.block<3,1>(0,i) = axis.Cross(p_end - chain.getSegment(i).getSegment().pose(q).p);
J.block<,>(,i) = axis;
} {
J.<,>(,i) = axis;
J.<,>(,i) = Eigen::Vector3d::();
}
}
J;
}
{
lambda = ;
Eigen::MatrixXd J_inv = J.() * (J * J.() + lambda*lambda * Eigen::Matrix6d::()).();
J_inv * twist;
}
};
奇异姿态检测
class SingularityHandler {
public:
double manipulability(const Eigen::MatrixXd& J) {
return std::sqrt((J * J.transpose()).determinant());
}
bool is_near_singularity(const Eigen::MatrixXd& J, double threshold = 0.01) {
double m = manipulability(J);
return m < threshold;
}
Eigen::VectorXd damped_ik(const Eigen::MatrixXd& J,
const Eigen::Vector6d& desired_twist,
double lambda = 0.05) {
Eigen::MatrixXd JJT = J * J.transpose();
Eigen::MatrixXd J_damped = JJT + lambda * lambda * Eigen::Matrix6d::Identity();
return J.transpose() * J_damped.inverse() * desired_twist;
}
};
关节限位检查
struct JointLimits {
std::vector<double> min;
std::vector<double> max;
std::vector<double> max_velocity;
std::vector<double> max_acceleration;
};
bool check_limits(std::vector<double>& q,
const JointLimits& limits) {
bool valid = true;
for (size_t i = 0; i < q.size(); ++i) {
if (i < limits.min.size()) {
if (q[i] < limits.min[i]) { q[i] = limits.min[i]; valid = false; }
if (q[i] > limits.max[i]) { q[i] = limits.max[i]; valid = false; }
}
}
return valid;
}
性能指标
| 指标 | 目标 | 说明 |
|---|
| FK 求解时间 | < 1ms | 实时控制需要 |
| IK 求解时间(解析) | < 5ms | 6DOF 工业机械臂 |
| IK 求解时间(数值) | < 20ms | 冗余机械臂 |
| 奇异值阈值 | > 0.01 | manipulability |
| 关节限位余量 | > 5° | 避免物理限位 |