CM_DOG/Utils/Kinematics.m
2025-06-26 05:11:10 +08:00

221 lines
7.6 KiB
Matlab
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function quadruped_leg_visualization()
% 四足机器人单腿运动学可视化
% 清除之前的图形
close all;
clc;
% 定义腿部参数 (单位: 米)
leg_params.upper_leg_length = 0.15;
leg_params.lower_leg_length = 0.15;
leg_params.hip_offset_x = 0.05;
leg_params.hip_offset_z = -0.02;
leg_params.hip_yaw_offset = 0.01;
leg_params.knee_sign = 1; % 1或-1取决于机械设计
% 目标位置 (在髋关节坐标系中)
target_pos = [0.2, 0.1, -0.25]; % x, y, z
% 计算逆运动学 (右腿hip_yaw_sign=1左腿=-1)
joint_angles = leg_inverse_kinematics(target_pos, leg_params, 1);
% 显示计算结果
disp('关节角度 (弧度):');
disp(['髋关节偏航 (hip yaw): ', num2str(joint_angles(1)), ' rad']);
disp(['髋关节滚动 (hip roll): ', num2str(joint_angles(2)), ' rad']);
disp(['髋关节俯仰 (hip pitch): ', num2str(joint_angles(3)), ' rad']);
disp(['膝关节 (knee): ', num2str(joint_angles(4)), ' rad']);
disp('关节角度 (度):');
disp(['髋关节偏航 (hip yaw): ', num2str(rad2deg(joint_angles(1))), '°']);
disp(['髋关节滚动 (hip roll): ', num2str(rad2deg(joint_angles(2))), '°']);
disp(['髋关节俯仰 (hip pitch): ', num2str(rad2deg(joint_angles(3))), '°']);
disp(['膝关节 (knee): ', num2str(rad2deg(joint_angles(4))), '°']);
% 可视化腿部
visualize_leg(joint_angles, leg_params, target_pos);
end
function joint_angles = leg_inverse_kinematics(target_pos, leg_params, hip_yaw_sign)
% 逆运动学计算函数
% 从参数字典中提取参数
L1 = leg_params.upper_leg_length;
L2 = leg_params.lower_leg_length;
offset_x = leg_params.hip_offset_x;
offset_z = leg_params.hip_offset_z;
yaw_offset = leg_params.hip_yaw_offset;
knee_sign = leg_params.knee_sign;
% 第一步:计算髋关节偏航角 (hip yaw)
x = target_pos(1);
y = target_pos(2);
z = target_pos(3);
x = x - offset_x;
z = z - offset_z;
% 使用迭代法处理yaw offset
theta_yaw = atan2(hip_yaw_sign * y, x);
for i = 1:3
% 计算yaw旋转后的位置
x_rot = x * cos(theta_yaw) + hip_yaw_sign * y * sin(theta_yaw);
y_rot = -x * sin(theta_yaw) + hip_yaw_sign * y * cos(theta_yaw);
% 考虑yaw offset
x_rot = x_rot - yaw_offset * (1 - cos(theta_yaw));
y_rot = y_rot + yaw_offset * sin(theta_yaw);
theta_yaw = atan2(hip_yaw_sign * y_rot, x_rot);
end
% 第二步:计算髋关节滚转角 (hip roll) 和俯仰角 (hip pitch)
x_rot = x * cos(theta_yaw) + hip_yaw_sign * y * sin(theta_yaw) - yaw_offset;
z_rot = z;
% 计算髋关节滚转角
L = sqrt(x_rot^2 + z_rot^2);
theta_roll = atan2(z_rot, x_rot);
% 计算髋关节俯仰角和膝关节角度
D = (L^2 - L1^2 - L2^2) / (2 * L1 * L2);
D = max(min(D, 1.0), -1.0); % 确保数值在有效范围内
theta_knee = knee_sign * acos(D);
alpha = atan2(L2 * sin(theta_knee), L1 + L2 * cos(theta_knee));
theta_pitch = alpha + theta_roll;
% 返回关节角度 (hip_yaw, hip_roll, hip_pitch, knee)
joint_angles = [theta_yaw, theta_roll, theta_pitch, theta_knee];
end
function visualize_leg(joint_angles, leg_params, target_pos)
% 可视化腿部运动学
% 提取参数
L1 = leg_params.upper_leg_length;
L2 = leg_params.lower_leg_length;
offset_x = leg_params.hip_offset_x;
offset_z = leg_params.hip_offset_z;
yaw_offset = leg_params.hip_yaw_offset;
% 提取关节角度
theta_yaw = joint_angles(1);
theta_roll = joint_angles(2);
theta_pitch = joint_angles(3);
theta_knee = joint_angles(4);
% 创建图形窗口
figure('Name', '四足机器人单腿运动学可视化', 'NumberTitle', 'off', 'Position', [100, 100, 1200, 800]);
% 1. 3D视图
subplot(2,2,[1,3]);
hold on;
grid on;
axis equal;
view(3);
xlabel('X (m)');
ylabel('Y (m)');
zlabel('Z (m)');
title('3D视图');
% 绘制坐标系
plot3([0, 0.1], [0, 0], [0, 0], 'r', 'LineWidth', 2); % X轴
plot3([0, 0], [0, 0.1], [0, 0], 'g', 'LineWidth', 2); % Y轴
plot3([0, 0], [0, 0], [0, 0.1], 'b', 'LineWidth', 2); % Z轴
% 计算关节位置
% 髋关节位置 (考虑了offset)
hip_pos = [offset_x, 0, offset_z];
% 应用yaw旋转
R_yaw = [cos(theta_yaw), -sin(theta_yaw), 0;
sin(theta_yaw), cos(theta_yaw), 0;
0, 0, 1];
% 应用roll旋转 (在yaw旋转后的坐标系中)
R_roll = [cos(theta_roll), 0, sin(theta_roll);
0, 1, 0;
-sin(theta_roll), 0, cos(theta_roll)];
% 应用pitch旋转
R_pitch = [1, 0, 0;
0, cos(theta_pitch), -sin(theta_pitch);
0, sin(theta_pitch), cos(theta_pitch)];
% 计算大腿末端位置
upper_leg_end = hip_pos + (R_yaw * R_roll * R_pitch * [L1; 0; 0])';
% 计算小腿末端位置
R_knee = [1, 0, 0;
0, cos(theta_knee), -sin(theta_knee);
0, sin(theta_knee), cos(theta_knee)];
lower_leg_end = upper_leg_end + (R_yaw * R_roll * R_pitch * R_knee * [L2; 0; 0])';
% 绘制连杆
plot3([hip_pos(1), upper_leg_end(1)], ...
[hip_pos(2), upper_leg_end(2)], ...
[hip_pos(3), upper_leg_end(3)], 'b-o', 'LineWidth', 3, 'MarkerSize', 8);
plot3([upper_leg_end(1), lower_leg_end(1)], ...
[upper_leg_end(2), lower_leg_end(2)], ...
[upper_leg_end(3), lower_leg_end(3)], 'r-o', 'LineWidth', 3, 'MarkerSize', 8);
% 绘制目标位置
plot3(target_pos(1), target_pos(2), target_pos(3), 'g*', 'MarkerSize', 15);
% 绘制yaw offset
plot3([hip_pos(1), hip_pos(1)+yaw_offset*sin(theta_yaw)], ...
[0, yaw_offset*cos(theta_yaw)], ...
[hip_pos(3), hip_pos(3)], 'm--', 'LineWidth', 2);
% 设置视图范围
axis_range = max([L1+L2, abs(offset_x)+0.1, abs(offset_z)+0.1]);
xlim([-axis_range, axis_range]);
ylim([-axis_range, axis_range]);
zlim([-axis_range, axis_range]);
% 2. X-Y平面视图
subplot(2,2,2);
hold on;
grid on;
axis equal;
xlabel('X (m)');
ylabel('Y (m)');
title('X-Y平面视图');
plot([0, 0.1], [0, 0], 'r', 'LineWidth', 2); % X轴
plot([0, 0], [0, 0.1], 'g', 'LineWidth', 2); % Y轴
plot([hip_pos(1), upper_leg_end(1)], [hip_pos(2), upper_leg_end(2)], 'b-o', 'LineWidth', 3, 'MarkerSize', 8);
plot([upper_leg_end(1), lower_leg_end(1)], [upper_leg_end(2), lower_leg_end(2)], 'r-o', 'LineWidth', 3, 'MarkerSize', 8);
plot(target_pos(1), target_pos(2), 'g*', 'MarkerSize', 15);
plot([hip_pos(1), hip_pos(1)+yaw_offset*sin(theta_yaw)], [0, yaw_offset*cos(theta_yaw)], 'm--', 'LineWidth', 2);
xlim([-axis_range, axis_range]);
ylim([-axis_range, axis_range]);
% 3. X-Z平面视图
subplot(2,2,4);
hold on;
grid on;
axis equal;
xlabel('X (m)');
ylabel('Z (m)');
title('X-Z平面视图');
plot([0, 0.1], [0, 0], 'r', 'LineWidth', 2); % X轴
plot([0, 0], [0, 0.1], 'b', 'LineWidth', 2); % Z轴
plot([hip_pos(1), upper_leg_end(1)], [hip_pos(3), upper_leg_end(3)], 'b-o', 'LineWidth', 3, 'MarkerSize', 8);
plot([upper_leg_end(1), lower_leg_end(1)], [upper_leg_end(3), lower_leg_end(3)], 'r-o', 'LineWidth', 3, 'MarkerSize', 8);
plot(target_pos(1), target_pos(3), 'g*', 'MarkerSize', 15);
xlim([-axis_range, axis_range]);
ylim([-axis_range, axis_range]);
% 添加图例
legend({'大腿', '小腿', '目标位置', 'Yaw偏移'}, 'Location', 'best');
end